import QtQuick 2.2

Component
{
    Image
    {
        id: cameraImage
        property bool proportionalHeight:
        {
            if(sourceSize.height == 0 || maximumHeight == 0)
            {
                return true;
            }
            return (sourceSize.width / sourceSize.height) > (maximumWidth / maximumHeight);
        }
        property real _width: Math.min(maximumWidth, sourceSize.width)
        property real _height: Math.min(maximumHeight, sourceSize.height)
        width: proportionalHeight ? _width : sourceSize.width * _height / sourceSize.height
        height: !proportionalHeight ? _height : sourceSize.height * _width / sourceSize.width
        anchors.horizontalCenter: parent.horizontalCenter

        onVisibleChanged:
        {
            if(visible)
            {
                OutputDevice.startCamera()
            } else
            {
                OutputDevice.stopCamera()
            }
        }
        source:
        {
            if(OutputDevice.cameraImage)
            {
                return OutputDevice.cameraImage;
            }
            return "";
        }

        rotation: OutputDevice.cameraOrientation.rotation
        mirror: OutputDevice.cameraOrientation.mirror
    }
}

Fix rotated camera image overlapping parts of the UI

import QtQuick 2.2

Component
{
    Image
    {
        id: cameraImage
        property bool rotatedImage: (OutputDevice.cameraOrientation.rotation / 90) % 2
        property bool proportionalHeight:
        {
            if(sourceSize.height == 0 || maximumHeight == 0)
            {
                return true;
            }
            if(!rotatedImage)
            {
                return (sourceSize.width / sourceSize.height) > (maximumWidth / maximumHeight);
            }
            else
            {
                return (sourceSize.width / sourceSize.height) > (maximumHeight / maximumWidth);
            }
        }
        property real _width:
        {
            if(!rotatedImage)
            {
                return Math.min(maximumWidth, sourceSize.width);
            }
            else
            {
                return Math.min(maximumHeight, sourceSize.width);
            }
        }
        property real _height:
        {
            if(!rotatedImage)
            {
                return Math.min(maximumHeight, sourceSize.height);
            }
            else
            {
                return Math.min(maximumWidth, sourceSize.height);
            }
        }
        width: proportionalHeight ? _width : sourceSize.width * _height / sourceSize.height
        height: !proportionalHeight ? _height : sourceSize.height * _width / sourceSize.width
        anchors.horizontalCenter: parent.horizontalCenter

        onVisibleChanged:
        {
            if(visible)
            {
                OutputDevice.startCamera()
            } else
            {
                OutputDevice.stopCamera()
            }
        }
        source:
        {
            if(OutputDevice.cameraImage)
            {
                return OutputDevice.cameraImage;
            }
            return "";
        }

        rotation: OutputDevice.cameraOrientation.rotation
        mirror: OutputDevice.cameraOrientation.mirror
    }
}


import qbs 1.0

import cutehmi

cutehmi.Tool {
	name: "cutehmi_view"

	major: 1

	minor: 0

	micro: 0

	vendor: "CuteHMI"

	friendlyName: "View"

	description: "Client, GUI application, which allows one to run CuteHMI project in a window."

	author: "Michal Policht"

	copyright: "Michal Policht"

	license: "Mozilla Public License, v. 2.0"

	files: [
        "resources.qrc",
        "resources.rc",
        "src/main.cpp",
    ]

	Depends { name: "cutehmi_1" }
	cutehmi_1.reqMinor: 0

	Depends { name: "cutehmi_xml_1" }
	cutehmi_xml_1.reqMinor: 0

	Depends { name: "cutehmi_app_1" }
	cutehmi_app_1.reqMinor: 0

	Depends { name: "cutehmi.doxygen" }
}

//(c)MP: Copyright © 2018, Michal Policht. All rights reserved.
//(c)MP: This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

Add 'README.md' to file list.

import qbs 1.0

import cutehmi

cutehmi.Tool {
	name: "cutehmi_view"

	major: 1

	minor: 0

	micro: 0

	vendor: "CuteHMI"

	friendlyName: "View"

	description: "Client, GUI application, which allows one to run CuteHMI project in a window."

	author: "Michal Policht"

	copyright: "Michal Policht"

	license: "Mozilla Public License, v. 2.0"

	files: [
        "README.md",
        "resources.qrc",
        "resources.rc",
        "src/main.cpp",
    ]

	Depends { name: "cutehmi_1" }
	cutehmi_1.reqMinor: 0

	Depends { name: "cutehmi_xml_1" }
	cutehmi_xml_1.reqMinor: 0

	Depends { name: "cutehmi_app_1" }
	cutehmi_app_1.reqMinor: 0

	Depends { name: "cutehmi.doxygen" }
}

//(c)MP: Copyright © 2018, Michal Policht. All rights reserved.
//(c)MP: This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.


/// is the same thing as usual Image but fill it's parent instead of placing it inside
Image {
	width: 100%;	///< @private
	height: 100%;	///< @private

	///@private
	function _createElement(tag) {
		this.element = this.parent.element;
	}
}

Remove imagemixin size setting in prototype

/// is the same thing as usual Image but fill it's parent instead of placing it inside
Image {
	///@private
	function _createElement(tag) {
		this.element = this.parent.element;
	}
}


import qbs

CppApplication {
    name: "the app"
    consoleApplication: true
    files: "main.cpp"
    qbs.installPrefix: "/usr/local"
    Group {
        fileTagsFilter: "application"
        qbs.install: true
        qbs.installDir: "bin"
    }
}

Fix makefileGenerator() autotest on macOS

import qbs

CppApplication {
    name: "the app"
    consoleApplication: true

    cpp.separateDebugInformation: false
    Properties {
        condition: qbs.targetOS.contains("macos")
        bundle.embedInfoPlist: false
    }

    files: "main.cpp"
    qbs.installPrefix: "/usr/local"
    Group {
        fileTagsFilter: "application"
        qbs.install: true
        qbs.installDir: "bin"
    }
}


import QtQuick 2.0
import QtTest 1.0
import Spark.sys 1.0
import QUIKit 1.0
import Spark.views.components 1.0
import "../sample/rectanlges"

TestCase {
    name: "QmlFileListModel"
    when: windowShown

    TestUtils {
        id: utils
    }

    Component {
        id: creator
        QmlFileListModel {

        }
    }

    function test_options() {
        var model = creator.createObject();

        model.folder = Qt.resolvedUrl("../sample/rectanlges/");
        model.options = {
            "Blue100x50": {
                color: "green"
            }
        }

        utils.waitUntil(function() {
            return model.count > 0;
        }, 1000)

        var item = model.get(0);
        compare(item.title, "Blue100x50");
        compare(item.properties.color, "green");

    }

}

Fix test case time out issue

import QtQuick 2.0
import QtTest 1.0
import Spark.sys 1.0
import QUIKit 1.0
import Spark.views.components 1.0
import "../sample/rectanlges"

TestCase {
    name: "QmlFileListModel"

    TestUtils {
        id: utils
    }

    Component {
        id: creator
        QmlFileListModel {

        }
    }

    function test_options() {
        console.log("test_options");
        var model = creator.createObject();

        model.folder = Qt.resolvedUrl("../sample/rectanlges/");
        model.options = {
            "Blue100x50": {
                color: "green"
            }
        }

        utils.waitUntil(function() {
            return model.count > 0;
        }, 1000)

        var item = model.get(0);
        compare(item.title, "Blue100x50");
        compare(item.properties.color, "green");

    }

}


Item {
	property string name;
	property Item manager: parent;
	visible: false;

	signal started;
	signal stopped;

	init(intent): { }
	pop: { this.manager.pop() }
	push(name, intent, state): { this.manager.push(name, intent, state) }
	replaceTopActivity(name, intent, state): { this.manager.replaceTopActivity(name, intent, state) }
	setState(state, name): { this.manager.setState(state, name) }
	setIntent(state, name): { this.manager.setIntent(state, name) }
	clear: { this.manager.clear() }

	onBackPressed: { this.manager.pop(); return true }
}

Fix 'init' signature: add lost argument

Item {
	property string name;
	property Item manager: parent;
	visible: false;

	signal started;
	signal stopped;

	init(intent, state): { }
	pop: { this.manager.pop() }
	push(name, intent, state): { this.manager.push(name, intent, state) }
	replaceTopActivity(name, intent, state): { this.manager.replaceTopActivity(name, intent, state) }
	setState(state, name): { this.manager.setState(state, name) }
	setIntent(state, name): { this.manager.setIntent(state, name) }
	clear: { this.manager.clear() }

	onBackPressed: { this.manager.pop(); return true }
}


import qbs
import qbs.Environment
import qbs.Utilities

import "functions.js" as Functions

/**
  This module generates 'plugins.qmltypes' artifact.
  */
Module {
	additionalProductTypes: ["qmltypes"]

	condition: qbs.targetOS.contains("windows")

	Depends { name: "Qt.core" }

	Rule {
		multiplex: true
		inputs: ["qml", "dynamiclibrary"]

		prepare: {
			var dumpCmd = new Command(product.Qt.core.binPath + "/qmlplugindump", ["-nonrelocatable", product.name, product.major + "." + product.minor, "QML"]);
			dumpCmd.workingDirectory = product.qbs.installRoot
			dumpCmd.description = "invoking 'qmlplugindump' program to generate " + product.sourceDirectory + "/plugins.qmltypes";
			dumpCmd.highlight = "codegen"
			dumpCmd.stdoutFilePath = product.sourceDirectory + "/plugins.qmltypes"
			return [dumpCmd]
		}

		Artifact {
			filePath: product.sourceDirectory + "/plugins.qmltypes"
			fileTags: ["qmltypes"]
		}
	}
}

Move condition to `Rule` item.

import qbs
import qbs.Environment
import qbs.Utilities

import "functions.js" as Functions

/**
  This module generates 'plugins.qmltypes' artifact.
  */
Module {
	additionalProductTypes: ["qmltypes"]

	Depends { name: "Qt.core" }

	Rule {
		condition: qbs.targetOS.contains("windows")

		multiplex: true
		inputs: ["qml", "dynamiclibrary"]

		prepare: {
			var dumpCmd = new Command(product.Qt.core.binPath + "/qmlplugindump", ["-nonrelocatable", product.name, product.major + "." + product.minor, "QML"]);
			dumpCmd.workingDirectory = product.qbs.installRoot
			dumpCmd.description = "invoking 'qmlplugindump' program to generate " + product.sourceDirectory + "/plugins.qmltypes";
			dumpCmd.highlight = "codegen"
			dumpCmd.stdoutFilePath = product.sourceDirectory + "/plugins.qmltypes"
			return [dumpCmd]
		}

		Artifact {
			filePath: product.sourceDirectory + "/plugins.qmltypes"
			fileTags: ["qmltypes"]
		}
	}
}


import QtQuick 2.7

ListModel {

    ListElement {
        dish_name: 'blue'
    }

    ListElement {
        dish_name: 'black'
    }

    ListElement {
        dish_name: 'green'
    }

    ListElement {
        dish_name: 'red'
    }
}


import QtQuick 2.0
import Sailfish.Silica 1.0
import "../components"

Dialog {
    property string path: ""

    // return value
    property string errorMessage: ""

    id: dialog
    allowedOrientations: Orientation.All
    canAccept: folderName.text !== ""

    onAccepted: errorMessage = engine.mkdir(path, folderName.text);

    SilicaFlickable {
        id: flickable
        anchors.fill: parent
        contentHeight: column.height
        VerticalScrollDecorator { flickable: flickable }

        Column {
            id: column
            anchors.left: parent.left
            anchors.right: parent.right

            DialogHeader {
                id: dialogHeader
                title: qsTr("Create Folder")
                acceptText: qsTr("Create")
            }

            Label {
                x: Theme.horizontalPageMargin
                width: parent.width - 2*x
                text: qsTr("Create a new folder under") + "\n" + path
                color: Theme.highlightColor
                wrapMode: Text.Wrap
            }

            Spacer {
                height: Theme.paddingLarge
            }

            TextField {
                id: folderName
                width: parent.width
                placeholderText: qsTr("Folder name")
                label: qsTr("Folder name")
                focus: true

                // return key on virtual keyboard accepts the dialog
                EnterKey.enabled: folderName.text.length > 0
                EnterKey.iconSource: "image://theme/icon-m-enter-accept"
                EnterKey.onClicked: dialog.accept()
            }
        }
    }
}

Add a slash to the end of path string in create folder dialog

import QtQuick 2.0
import Sailfish.Silica 1.0
import "../components"

Dialog {
    property string path: ""

    // return value
    property string errorMessage: ""

    id: dialog
    allowedOrientations: Orientation.All
    canAccept: folderName.text !== ""

    onAccepted: errorMessage = engine.mkdir(path, folderName.text);

    SilicaFlickable {
        id: flickable
        anchors.fill: parent
        contentHeight: column.height
        VerticalScrollDecorator { flickable: flickable }

        Column {
            id: column
            anchors.left: parent.left
            anchors.right: parent.right

            DialogHeader {
                id: dialogHeader
                title: qsTr("Create Folder")
                acceptText: qsTr("Create")
            }

            Label {
                x: Theme.horizontalPageMargin
                width: parent.width - 2*x
                text: qsTr("Create a new folder under") + "\n" + path + (path != "/" ? "/" : "");
                color: Theme.highlightColor
                wrapMode: Text.Wrap
            }

            Spacer {
                height: Theme.paddingLarge
            }

            TextField {
                id: folderName
                width: parent.width
                placeholderText: qsTr("Folder name")
                label: qsTr("Folder name")
                focus: true

                // return key on virtual keyboard accepts the dialog
                EnterKey.enabled: folderName.text.length > 0
                EnterKey.iconSource: "image://theme/icon-m-enter-accept"
                EnterKey.onClicked: dialog.accept()
            }
        }
    }
}


import qbs
import qbs.FileInfo

QbsProduct {
    property bool isForDarwin: qbs.targetOS.contains("darwin")
    Depends { name: "cpp" }
    Depends { name: "bundle"; condition: isForDarwin }
    Depends { name: "Qt.core" }
    Depends { name: "qbsbuildconfig" }
    Depends { name: "qbscore"; condition: !Qt.core.staticBuild }
    type: (Qt.core.staticBuild ? ["staticlibrary"]
                               : [isForDarwin ? "loadablemodule" : "dynamiclibrary"])
        .concat(["qbsplugin"])
    Properties {
        condition: Qt.core.staticBuild
        cpp.defines: ["QBS_STATIC_LIB"]
    }
    cpp.cxxLanguageVersion: "c++11"
    cpp.includePaths: base.concat(["../../../lib/corelib"])
    cpp.visibility: "hidden"
    destinationDirectory: FileInfo.joinPaths(project.buildDirectory,
                                             qbsbuildconfig.libDirName + "/qbs/plugins")
    Group {
        fileTagsFilter: [isForDarwin ? "loadablemodule" : "dynamiclibrary"]
            .concat(qbs.buildVariant === "debug"
        ? [isForDarwin ? "debuginfo_loadablemodule" : "debuginfo_dll"] : [])
        qbs.install: true
        qbs.installDir: qbsbuildconfig.pluginsInstallDir + "/qbs/plugins"
        qbs.installSourceBase: destinationDirectory
    }
    Properties {
        condition: isForDarwin
        bundle.isBundle: false
    }
}

Use minimal visibility for plugins as well as libraries

import qbs
import qbs.FileInfo

QbsProduct {
    property bool isForDarwin: qbs.targetOS.contains("darwin")
    Depends { name: "cpp" }
    Depends { name: "bundle"; condition: isForDarwin }
    Depends { name: "Qt.core" }
    Depends { name: "qbsbuildconfig" }
    Depends { name: "qbscore"; condition: !Qt.core.staticBuild }
    type: (Qt.core.staticBuild ? ["staticlibrary"]
                               : [isForDarwin ? "loadablemodule" : "dynamiclibrary"])
        .concat(["qbsplugin"])
    Properties {
        condition: Qt.core.staticBuild
        cpp.defines: ["QBS_STATIC_LIB"]
    }
    cpp.cxxLanguageVersion: "c++11"
    cpp.includePaths: base.concat(["../../../lib/corelib"])
    cpp.visibility: "minimal"
    destinationDirectory: FileInfo.joinPaths(project.buildDirectory,
                                             qbsbuildconfig.libDirName + "/qbs/plugins")
    Group {
        fileTagsFilter: [isForDarwin ? "loadablemodule" : "dynamiclibrary"]
            .concat(qbs.buildVariant === "debug"
        ? [isForDarwin ? "debuginfo_loadablemodule" : "debuginfo_dll"] : [])
        qbs.install: true
        qbs.installDir: qbsbuildconfig.pluginsInstallDir + "/qbs/plugins"
        qbs.installSourceBase: destinationDirectory
    }
    Properties {
        condition: isForDarwin
        bundle.isBundle: false
    }
}


import QtQuick 2.0
import QtDesktop 0.1

ApplicationWindow {
    width: 400
    height: 400

    Rectangle {
        id: back
        anchors.fill: parent
        color: enabled ? "red" : "blue"
    }

    Column {
        spacing: 8
        anchors.centerIn: parent

        Row {
            Button {
                id: button1
                focus: true
                text: "Button 1"
                activeFocusOnPress: true
                KeyNavigation.tab: button2
                onClicked: back.enabled = !back.enabled
            }
            Button {
                id: button2
                text: "Button 2"
                activeFocusOnPress: true
                KeyNavigation.tab: button3
                KeyNavigation.backtab: button1
                onClicked: back.enabled = !back.enabled
            }
            Button {
                id: button3
                text: "Button 3"
                activeFocusOnPress: true
                KeyNavigation.tab: checkbox1
                KeyNavigation.backtab: button2
                onClicked: back.enabled = !back.enabled
            }
        }

        Row {
            CheckBox {
                id: checkbox1
                text: "Checkbox 1"
                activeFocusOnPress: true
                KeyNavigation.tab: checkbox2
                KeyNavigation.backtab: button3
                onClicked: back.enabled = !back.enabled
            }
            CheckBox {
                id: checkbox2
                text: "Checkbox 2"
                activeFocusOnPress: true
                KeyNavigation.tab: checkbox3
                KeyNavigation.backtab: checkbox1
                onClicked: back.enabled = !back.enabled
            }
            CheckBox {
                id: checkbox3
                text: "Checkbox 3"
                activeFocusOnPress: true
                KeyNavigation.tab: radioButton1
                KeyNavigation.backtab: checkbox2
                onClicked: back.enabled = !back.enabled
            }
        }

        ButtonRow {
            exclusive: true
            RadioButton {
                id: radioButton1
                text: "RadioButton 1"
                activeFocusOnPress: true
                KeyNavigation.tab: radioButton2
                KeyNavigation.backtab: checkbox3
                onClicked: back.enabled = !back.enabled
            }
            RadioButton {
                id: radioButton2
                text: "RadioButton 2"
                activeFocusOnPress: true
                KeyNavigation.tab: radioButton3
                KeyNavigation.backtab: radioButton1
                onClicked: back.enabled = !back.enabled
            }
            RadioButton {
                id: radioButton3
                text: "RadioButton 3"
                activeFocusOnPress: true
                KeyNavigation.backtab: radioButton2
                onClicked: back.enabled = !back.enabled
            }
        }
    }
}


import qbs

Project {
    Product {
        name: "dep"
        Export {
            Depends { name: "cpp" }
            Group { files: ["main.cpp"] }
        }
    }

    Application {
        name: "app"
        Depends { name: "dep" }
    }
}

Fix autotest for OS X.

import qbs

Project {
    Product {
        name: "dep"
        Export {
            Depends { name: "cpp" }
            Group { files: ["main.cpp"] }
        }
    }

    Application {
        name: "app"
        bundle.isBundle: false
        Depends { name: "dep" }
    }
}


import QtQuick 2.2
import Protobuf 1.0 as PB

PB.ServerUnaryMethodHolder {
  id: root
  property var handler
  property var readType
  property var writeType

  readDescriptor: readType && readType.descriptor
  writeDescriptor: writeType && writeType.descriptor

  onData: {
    'use strict';
    if (typeof handler !== 'function') {
      console.warn('Service method not available: ' + root.methodName);
      return;
    }
    handler(new root.readType(data), function(err, response) {
      sayHelloMethod.respond(tag, new root.writeType(response)._raw);
    });
  }
}

Fix bug where server unary method only worked for test code

import QtQuick 2.2
import Protobuf 1.0 as PB

PB.ServerUnaryMethodHolder {
  id: root
  property var handler
  property var readType
  property var writeType

  readDescriptor: readType && readType.descriptor
  writeDescriptor: writeType && writeType.descriptor

  onData: {
    'use strict';
    if (typeof handler !== 'function') {
      console.warn('Service method not available: ' + root.methodName);
      return;
    }
    handler(new root.readType(data), function(err, response) {
      root.respond(tag, new root.writeType(response)._raw);
    });
  }
}


import QtQuick 1.0
import AbstractMediaPlayer 1.0

QMHMediaBackend {
//    property variant source

    //state
//    property variant playing
//    property variant hasAudio
//    property variant hasVideo
//    property variant volume
//    property variant position
//    property variant seekable
//    property variant status
//    property variant paused
//    property variant playbackRate
    playing: false
    hasAudio: true
    hasVideo: false
    volume: 0.5
    position: 0
    seekable: true
    status: AbstractMediaPlayer.NoMedia
    paused: false
    playbackRate: 1.0

    onSourceChanged: {
        runtime.mediaPlayer.source = source
        //Benefit of the doubt!
        status = AbstractMediaPlayer.Buffered
        hasAudio = true
        playing = true
    }

    onPausedChanged:
        //Why are these discrete functions again girish?
        if (paused)
            runtime.mediaPlayer.pause()
        else
            runtime.mediaPlayer.resume()

    //Having a hard time deciding what to maintain
    //As (setable) property and what to keep as function
    function play() { runtime.mediaPlayer.play() }
    function stop() { runtime.mediaPlayer.stop() }
}

Add bindings for hasVideo and statusChanged

import QtQuick 1.0
import AbstractMediaPlayer 1.0
import QtMediaHub.components 1.0

QMHMediaBackend {
    id: root
//    property variant source

    //state
//    property variant playing
//    property variant hasAudio
//    property variant hasVideo
//    property variant volume
//    property variant position
//    property variant seekable
//    property variant status
//    property variant paused
//    property variant playbackRate
    playing: false
    hasAudio: true
    hasVideo: false
    volume: 0.5
    position: 0
    seekable: true
    status: AbstractMediaPlayer.NoMedia
    paused: false
    playbackRate: 1.0

    onSourceChanged: {
        runtime.mediaPlayer.source = source
        //Benefit of the doubt!
        status = AbstractMediaPlayer.Buffered
        hasAudio = true
        playing = true
    }

    onPausedChanged:
        //Why are these discrete functions again girish?
        if (paused)
            runtime.mediaPlayer.pause()
        else
            runtime.mediaPlayer.resume()

    //Having a hard time deciding what to maintain
    //As (setable) property and what to keep as function
    function play() { runtime.mediaPlayer.play() }
    function stop() { runtime.mediaPlayer.stop() }

    QMHUtil {
       id: util
    }

    Component.onCompleted: {
        util.createBinding("root", "hasVideo", "runtime.mediaPlayer.hasVideo", root)
        util.createBinding("root", "status", "runtime.mediaPlayer.status", root)
    }
}


import QtQuick 2.0

Item {
    Component {
        id: compCaller
        Timer {}
    }

    function queueCall() {
        if (!arguments)
            return

        // first param fn, then just run it with args if any
        if (typeof arguments[0] === 'function') {
            var fn = arguments[0]
            var delay = 0
            if (arguments.length > 1)
                var copyargs = [].splice.call(arguments,1)
        }
        // NOP
        else if (arguments.length < 2)
            return
        // first arg delay, second fn, run with args if any
        else {
            delay = arguments[0]
            fn = arguments[1]
            if (arguments.length > 2)
                 copyargs = [].splice.call(arguments,2)
        }

        var caller = compCaller.createObject(null, { interval: delay, running: true })
        caller.triggered.connect(function()
        {
            fn.apply(null, copyargs || [])
            caller.destroy()
        })
    }

}

Clean up; add warning for invalid call args

import QtQuick 2.0

Item {
    Component {
        id: compCaller
        Timer {}
    }

    function queueCall() {
        if (!arguments)
            return

        const len = arguments.length

        // check first param fn, run it with args if any
        if (typeof arguments[0] === 'function') {
            var delay = 0
            var fn = arguments[0]
            var copyargs = len > 1
                            ? [].splice.call(arguments,1)
                            : []

        // first arg delay, second fn, run with args if any
        } else if (len >= 2) {
            delay = arguments[0]
            fn = arguments[1]
            copyargs = len > 2
                        ? [].splice.call(arguments,2)
                        : []

        // NOP
        } else {
            console.warn('Invalid arg list: ' + arguments)
            return
        }

        var caller = compCaller.createObject(null, {interval: delay, running: true})
        caller.triggered.connect(() => {
            fn.apply(null, copyargs)
            caller.destroy()
        })
    }

}


import QtQuick 2.9
import QtQuick.Controls 2.5

Action {
    property bool shuffle: false
    property string method: ''
    property string defaultIcon: ''
    property string aText: ''
    property bool useAText: false

    text: {
        if (useAText)
            return aText

        switch (method) {
            case 'add'      : return 'Append'
            case 'addNext'  : return 'Add Next'
            case 'show'     : return 'Show'
            case 'play'     : return 'Play'
            case 'remove'   : return 'Remove'
            default         : '<unknown>'
        }
    }

    icon.name: {
        switch (method) {
            case 'add'      : return 'media-playlist-append'
            case 'addNext'  : return 'playlist-queue'
            case 'show'     : return 'search'
            case 'remove'   : return 'list-remove'
            // play is default
            default         : defaultIcon || 'media-playback-start'
        }
    }

    property var call: ({
        play: query => zoneView.currentPlayer.searchAndPlayNow(query, shuffle)
        , add: query => zoneView.currentPlayer.searchAndAdd(query, false, shuffle)
        , addNext: query => zoneView.currentPlayer.searchAndAdd(query, true, shuffle)
        , show: query => event.queueCall(trackView.search, query)
    })
}

Add default text optional bool

import QtQuick 2.9
import QtQuick.Controls 2.5

Action {
    property bool shuffle: false
    property string method: ''
    property string defaultIcon: ''
    property string aText: ''
    property bool useAText: false
    property bool useDefaultText: false

    text: {
        if (useAText)
            return aText

        if (!useDefaultText)
            return ''

        switch (method) {
            case 'add'      : return 'Append'
            case 'addNext'  : return 'Add Next'
            case 'show'     : return 'Show'
            case 'play'     : return 'Play'
            case 'remove'   : return 'Remove'
            default         : '<unknown>'
        }
    }

    icon.name: {
        switch (method) {
            case 'add'      : return 'media-playlist-append'
            case 'addNext'  : return 'playlist-queue'
            case 'show'     : return 'search'
            case 'remove'   : return 'list-remove'
            // play is default
            default         : defaultIcon || 'media-playback-start'
        }
    }

    property var call: ({
        play: query => zoneView.currentPlayer.searchAndPlayNow(query, shuffle)
        , add: query => zoneView.currentPlayer.searchAndAdd(query, false, shuffle)
        , addNext: query => zoneView.currentPlayer.searchAndAdd(query, true, shuffle)
        , show: query => event.queueCall(trackView.search, query)
    })
}


import qbs

CppApplication {
    files: ["emptymain.cpp", "empty.m", "empty.mm"]
}

Fix enableExceptions autotest on Linux.

import qbs

CppApplication {
    files: ["emptymain.cpp"]

    Group {
        condition: qbs.targetOS.contains("darwin")
        files: ["empty.m", "empty.mm"]
    }
}


/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

import Qt 4.7
BorderImage {
    id: tileIcon

    property alias imageSource: fpImage.source
    property bool zoomImage: false
    property alias fillMode: fpImage.fillMode
    property string fallBackImage: ""
    property alias imageChild: imageChildComp.sourceComponent

    Image {
        id: fpImage
        anchors.centerIn: parent
        height: (tileIcon.zoomImage ? parent.height - parent.border.bottom - parent.border.top : sourceSize.height)
        width: (tileIcon.zoomImage ? parent.width - parent.border.right - parent.border.left : sourceSize.width)
        anchors.verticalCenterOffset: parent.border.top - parent.border.bottom
        fillMode: Image.PreserveAspectCrop
        clip: fillMode == Image.PreserveAspectCrop
        asynchronous: true

        Component.onCompleted: {
            if ((fallBackImage != "") && ((fpImage.status == Image.Error))) {
                console.log("Failed to load: " + tileIcon.imageSource)
                tileIcon.imageSource = fallBackImage;
            }
        }
        Loader {
            id: imageChildComp
            anchors.fill: parent
        }
    }
}

Fix 17716 - Icon's larger than 100x100 pixels overlap in the "Top Applications" display

/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

import Qt 4.7
BorderImage {
    id: tileIcon

    property alias imageSource: fpImage.source
    property bool zoomImage: false
    property alias fillMode: fpImage.fillMode
    property string fallBackImage: ""
    property alias imageChild: imageChildComp.sourceComponent

    Image {
        id: fpImage
        property int vspace: parent.height - parent.border.bottom - parent.border.top
        property int hspace: parent.width - parent.border.right - parent.border.left
        anchors.centerIn: parent
        height: (tileIcon.zoomImage ? vspace : Math.min(vspace, sourceSize.height))
        width: (tileIcon.zoomImage ? hspace : Math.min(hspace,sourceSize.width))
        anchors.verticalCenterOffset: parent.border.top - parent.border.bottom
        fillMode: Image.PreserveAspectCrop
        clip: fillMode == Image.PreserveAspectCrop
        smooth: true
        asynchronous: true

        Component.onCompleted: {
            if ((fallBackImage != "") && ((fpImage.status == Image.Error))) {
                console.log("Failed to load: " + tileIcon.imageSource)
                tileIcon.imageSource = fallBackImage;
            }
        }
        Loader {
            id: imageChildComp
            anchors.fill: parent
        }
    }
}


import QtQuick 2.0
import gloperate.base 1.0
import QtQuick.Controls 1.0 as Controls
import QtQuick.Controls.Styles 1.0

/**
*  ComboBox
*
*  Editable Drop-Down ComboBox
*/
Controls.ComboBox
{
    style: ComboBoxStyle {
        font.pixelSize:  Ui.style.ctrlTextSize
    }
}

Fix qml versions, still compatible with Qt5.4

import QtQuick 2.0
import gloperate.base 1.0
import QtQuick.Controls 1.0 as Controls
import QtQuick.Controls.Styles 1.3

/**
*  ComboBox
*
*  Editable Drop-Down ComboBox
*/
Controls.ComboBox
{
    style: ComboBoxStyle {
        font.pixelSize:  Ui.style.ctrlTextSize
    }
}


import QtQuick 2.0
import Sailfish.Silica 1.0
import "pages"

ApplicationWindow
{
    initialPage: Component { MainPage { } }
    cover: Qt.resolvedUrl("cover/CoverPage.qml")
}

Remove import and use Qt.resolvedUrl instead

import QtQuick 2.0
import Sailfish.Silica 1.0

ApplicationWindow
{
    initialPage: Qt.resolvedUrl("pages/MainPage.qml")
    cover: Qt.resolvedUrl("cover/CoverPage.qml")
}


Add testcase for Q.resolved and Q.rejected

import QtQuick 2.0
import QtTest 1.0
import QuickPromise 1.0

TestCase {
    name : "Promise_Resolved_Rejected"

    function test_resolved() {
        var promise = Q.resolved("blue");
        wait(50);
        compare(promise.hasOwnProperty("___promiseSignature___"), true);
        compare(promise.isSettled, true);
        compare(promise.isFulfilled, true);
        compare(promise.isRejected, false);
        compare(promise._result, "blue");
    }

    function test_rejected() {
        var promise = Q.rejected("blue");
        wait(50);
        compare(promise.hasOwnProperty("___promiseSignature___"), true);
        compare(promise.isSettled, true);
        compare(promise.isFulfilled, false);
        compare(promise.isRejected, true);
        compare(promise._result, "blue");
    }

}


import QtQuick 2.0
import QtTest 1.0
import "qrc:///QuickPromise/promise.js"  as Q

TestCase {
    name : "PromiseJS_Minimal"

    function tick() {
        wait(0);
        wait(0);
        wait(0);
    }

    function test_constructor() {
        var callbackResult = {}

        var promise = new Q.Promise(function(resolve, reject) {
           resolve("ready") ;
        });

        tick();

        compare(callbackResult.result, "ready");
    }

    function test_resolve() {
        var promise = Q.Promise.resolve("done");
        var callbackResult = {}
        promise.then(function(result) {
            callbackResult.result = result;
        });

        tick();

        compare(callbackResult.result, "done");
    }

}

Fix a broken test case

import QtQuick 2.0
import QtTest 1.0
import "qrc:///QuickPromise/promise.js"  as Q

TestCase {
    name : "PromiseJS_Minimal"

    function tick() {
        wait(0);
        wait(0);
        wait(0);
    }

    function test_constructor() {
        var callbackResult = {}

        var promise = new Q.Promise(function(resolve, reject) {
           resolve("ready");
        });

        promise.then(function(result) {
            callbackResult.result = result;
        });

        tick();

        compare(callbackResult.result, "ready");
    }

    function test_resolve() {
        var promise = Q.Promise.resolve("done");
        var callbackResult = {}
        promise.then(function(result) {
            callbackResult.result = result;
        });

        tick();

        compare(callbackResult.result, "done");
    }

}


import QtQuick 2.8
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0

Item {
    height: 32
    width: height

    property bool animateLoad: false
    property string key

    onKeyChanged: img.source = mcws.imageUrl(key, 'medium')

    Image {
        id: img
        sourceSize.height: parent.height
        sourceSize.width: parent.width
        opacity: .8
        layer.enabled: true
        layer.effect: DropShadow {
            transparentBorder: true
            horizontalOffset: 2
            verticalOffset: 2
            color: "#80000000"
        }

        NumberAnimation on opacity {
            id: load
            to: .8
            duration: 400
        }
        onStatusChanged: {
            if (status === Image.Error)
                source = "default.png"
            if (animateLoad)
                if (status === Image.Ready) //source.toString() !== "" &&
                {
                    opacity = 0
                    load.start()
                }
        }
    }

}

Make it fade in and fade out

import QtQuick 2.8
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0

Item {
    height: 32
    width: height

    property bool animateLoad: false
    property string key

    onKeyChanged: img.aSource = mcws.imageUrl(key, 'medium')

    Image {
        id: img

        property var aSource

        sourceSize.height: parent.height
        sourceSize.width: parent.width
        layer.enabled: true
        layer.effect: DropShadow {
            transparentBorder: true
            horizontalOffset: 2
            verticalOffset: 2
            color: "#80000000"
        }

        onASourceChanged: {
            if (animateLoad)
                Qt.callLater(function(){ seq.start() })
            else
                source = aSource
        }
        SequentialAnimation {
            id: seq
            NumberAnimation { target: img; property: "opacity"; to: 0; duration: 500 }
            PropertyAction { target: img; property: "source"; value: img.aSource }
            NumberAnimation { target: img; property: "opacity"; to: .8; duration: 500 }
        }

        onStatusChanged: {
            if (status === Image.Error)
                source = "default.png"
        }
    }
}


///object for handling XML/HTTP requests
Object {
	property bool loading: false;	///< loading flag, is true when request was send and false when answer was recieved or error occured

	/**@param request:Object request object
	send request using 'XMLHttpRequest' object*/
	ajax(request): {
		var url = request.url
		var error = request.error,
			data = request.data,
			headers = request.headers,
			done = request.done,
			settings = request.settings

		var xhr = new XMLHttpRequest()

		var self = this
		if (error)
			xhr.addEventListener('error', function(event) { self.loading = false; log("Error"); error(event) })

		if (done)
			xhr.addEventListener('load', function(event) { self.loading = false; done(event) })

		xhr.open(request.method || 'GET', url);

		for (var i in settings)
			xhr[i] = settings[i]

		for (var i in headers)
			xhr.setRequestHeader(i, headers[i])

		this.loading = true
		if (request.data)
			xhr.send(request.data)
		else
			xhr.send()
	}
}

Fix warning, remove unused variable.

///object for handling XML/HTTP requests
Object {
	property bool loading: false;	///< loading flag, is true when request was send and false when answer was recieved or error occured

	/**@param request:Object request object
	send request using 'XMLHttpRequest' object*/
	ajax(request): {
		var url = request.url
		var error = request.error,
			headers = request.headers,
			done = request.done,
			settings = request.settings

		var xhr = new XMLHttpRequest()

		var self = this
		if (error)
			xhr.addEventListener('error', function(event) { self.loading = false; log("Error"); error(event) })

		if (done)
			xhr.addEventListener('load', function(event) { self.loading = false; done(event) })

		xhr.open(request.method || 'GET', url);

		for (var i in settings)
			xhr[i] = settings[i]

		for (var i in headers)
			xhr.setRequestHeader(i, headers[i])

		this.loading = true
		if (request.data)
			xhr.send(request.data)
		else
			xhr.send()
	}
}


/****************************************************************************
**
** Copyright (C) 2014 Jolla Ltd.
** Contact: Raine Makelainen <raine.makelainen@jolla.com>
**
****************************************************************************/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

import QtQuick 2.1

QtObject {
    property QtObject webView
    property bool videoActive
    property bool audioActive
    property bool background

    signal webViewSuspended

    function calculateStatus() {}

    function resumeView() {}

    function suspendView() {}
}

Add missing property to the ResourceController mock

/****************************************************************************
**
** Copyright (C) 2014 Jolla Ltd.
** Contact: Raine Makelainen <raine.makelainen@jolla.com>
**
****************************************************************************/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

import QtQuick 2.1

QtObject {
    property QtObject webView
    property bool videoActive
    property bool audioActive
    property bool background
    property bool displayOff

    signal webViewSuspended

    function calculateStatus() {}

    function resumeView() {}

    function suspendView() {}
}


// Copyright (c) 2015 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.

import QtQuick 2.1
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1

import UM 1.2 as UM

UM.TooltipArea
{
    x: model.depth * UM.Theme.getSize("default_margin").width;
    text: model.description;

    width: childrenRect.width;
    height: childrenRect.height;

    CheckBox
    {
        id: check

        text: definition.label
        checked: model.visible;
        enabled: !model.prohibited;
        onClicked: definitionsModel.setVisible(model.key, checked);
    }
}

Put a MouseArea over the visibility checkbox so bindings do not break

// Copyright (c) 2015 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.

import QtQuick 2.1
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1

import UM 1.2 as UM

UM.TooltipArea
{
    x: model.depth * UM.Theme.getSize("default_margin").width;
    text: model.description;

    width: childrenRect.width;
    height: childrenRect.height;

    CheckBox
    {
        id: check

        text: definition.label
        checked: model.visible;
        enabled: !model.prohibited;

        MouseArea {
            anchors.fill: parent;
            onClicked: definitionsModel.setVisible(model.key, !check.checked);
        }
    }
}


// Copyright (c) 2015 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.

import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1

import UM 1.0 as UM

Item {
    property alias title: titleLabel.text;
    default property alias contents: contentsItem.children;
    property bool resetEnabled: true;

    function reset()
    {
        UM.Application.log("w", "No reset implemented!")
    }
    function boolCheck(value) //Hack to ensure a good match between python and qml.
    {
        if(value == "True")
        {
            return true
        }else if(value == "False")
        {
            return false
        }
        else
        {
            return value
        }
    }

    Label {
        id: titleLabel;

        anchors {
            top: parent.top;
            left: parent.left;
            right: parent.right;
            margins: 5;
        }

        font.pointSize: 18;
    }

    Item {
        id: contentsItem;

        anchors {
            top: titleLabel.bottom;
            left: parent.left;
            right: parent.right;
            bottom: parent.bottom;
            margins: 5;
            bottomMargin: 0;
        }

        clip: true;
    }
}

Handle undefined values in boolcheck

// Copyright (c) 2015 Ultimaker B.V.
// Uranium is released under the terms of the AGPLv3 or higher.

import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtQuick.Window 2.1

import UM 1.0 as UM

Item {
    property alias title: titleLabel.text;
    default property alias contents: contentsItem.children;
    property bool resetEnabled: true;

    function reset()
    {
        UM.Application.log("w", "No reset implemented!")
    }
    function boolCheck(value) //Hack to ensure a good match between python and qml.
    {
        if(value == "True")
        {
            return true
        }else if(value == "False" || value == undefined)
        {
            return false
        }
        else
        {
            return value
        }
    }

    Label {
        id: titleLabel;

        anchors {
            top: parent.top;
            left: parent.left;
            right: parent.right;
            margins: 5;
        }

        font.pointSize: 18;
    }

    Item {
        id: contentsItem;

        anchors {
            top: titleLabel.bottom;
            left: parent.left;
            right: parent.right;
            bottom: parent.bottom;
            margins: 5;
            bottomMargin: 0;
        }

        clip: true;
    }
}


import QtQuick 2.0
import Sailfish.Silica 1.0
import "../js/logic/channelListPageLogic.js" as Logic

Page {
    id: channelListPage

    SilicaFlickable {
        anchors.fill: parent
        contentHeight: column.height

        ListModel {
            id: channelModel
        }

        WorkerScript {
            id: slackWorker
            source: "../js/services/slackWorker.js"
            onMessage: {
                Logic.workerOnMessage(messageObject);
            }
        }

        Component.onCompleted: {
            Logic.loadChannels();
        }

        // -------------------------

        Column {
            id: column

            width: channelListPage.width
            spacing: Theme.paddingLarge
            PageHeader {
                title: qsTr("Channels")
            }

            SilicaListView {
                id: channelList
                width: parent.width
                height: parent.height
                model: channelModel

                delegate: BackgroundItem {
                    width: parent.width
                    Label {
                        text: '#' + model.name
                        font.pixelSize: Theme.fontSizeLarge
                        height: Theme.itemSizeLarge
                        width: parent.width
                        color: highlighted ? Theme.highlightColor : Theme.primaryColor
                        horizontalAlignment: Text.AlignHCenter
                    }
                }
            }
        }
    }
}

Add transition to channelPage to channelListPage items

import QtQuick 2.0
import Sailfish.Silica 1.0
import "../js/logic/channelListPageLogic.js" as Logic

Page {
    id: channelListPage

    SilicaFlickable {
        anchors.fill: parent
        contentHeight: column.height

        ListModel {
            id: channelModel
        }

        WorkerScript {
            id: slackWorker
            source: "../js/services/slackWorker.js"
            onMessage: {
                Logic.workerOnMessage(messageObject);
            }
        }

        Component.onCompleted: {
            Logic.loadChannels();
        }

        // -------------------------

        Column {
            id: column

            width: channelListPage.width
            spacing: Theme.paddingLarge
            PageHeader {
                title: qsTr("Channels")
            }

            SilicaListView {
                id: channelList
                width: parent.width
                height: parent.height
                model: channelModel

                delegate: BackgroundItem {
                    onClicked: { pageStack.push(Qt.resolvedUrl("ChannelPage.qml"), { name: model.name }) }
                    width: parent.width
                    Label {
                        text: '#' + model.name
                        font.pixelSize: Theme.fontSizeLarge
                        height: Theme.itemSizeLarge
                        width: parent.width
                        color: highlighted ? Theme.highlightColor : Theme.primaryColor
                        horizontalAlignment: Text.AlignHCenter
                    }
                }
            }
        }
    }
}


import QtQuick 2.0

Item {
    id: canvas_root
    objectName: "canvas"
    height: 200
    width: 200

    property bool continuous: false
    onContinuousChanged: mouseArea1.hoverEnabled = continuous

    Rectangle {
        id: canvas_background
        color: "#ffffff"
        anchors.rightMargin: 1
        anchors.leftMargin: 1
        anchors.bottomMargin: 1
        anchors.topMargin: 1
        anchors.fill: parent
        border.width: 0

        property bool rdy: false

        Component.onCompleted: rdy = true

        onHeightChanged: {
            if(rdy)
                management.setCanvasHeight(height)
        }
        onWidthChanged: {
            if(rdy)
                management.setCanvasWidth(width)
        }
    }

    MouseArea {
        id: mouseArea1
        hoverEnabled: true
        anchors.fill: parent

        onClicked: {
            if(!continuous)
                management.setMousePosition(mouseX, mouseY)
        }

        onPositionChanged: {
            if(continuous)
                management.setMousePosition(mouseX, mouseY)
        }

        onExited: {
            if(continuous)
                management.setMousePosition(0, 0)
        }
    }
}

Allow right click to reset goal

import QtQuick 2.0

Item {
    id: canvas_root
    objectName: "canvas"
    height: 200
    width: 200

    property bool continuous: false
    onContinuousChanged: mouseArea1.hoverEnabled = continuous

    Rectangle {
        id: canvas_background
        color: "#ffffff"
        anchors.rightMargin: 1
        anchors.leftMargin: 1
        anchors.bottomMargin: 1
        anchors.topMargin: 1
        anchors.fill: parent
        border.width: 0

        property bool rdy: false

        Component.onCompleted: rdy = true

        onHeightChanged: {
            if(rdy)
                management.setCanvasHeight(height)
        }
        onWidthChanged: {
            if(rdy)
                management.setCanvasWidth(width)
        }
    }

    MouseArea {
        id: mouseArea1
        hoverEnabled: true
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton

        onClicked: {
            if(!continuous){
                if(mouse.button == Qt.LeftButton)
                    management.setMousePosition(mouseX, mouseY)
                else
                    management.setMousePosition(0, 0)
            }
        }

        onPositionChanged: {
            if(continuous)
                management.setMousePosition(mouseX, mouseY)
        }

        onExited: {
            if(continuous)
                management.setMousePosition(0, 0)
        }
    }
}


import QtQuick 2.7

Item {
    id: item1
    property int tile_text_spacing: 20
    property string tile_text: 'Tile'
    property int tile_text_max_size: 72
    property string tile_color: 'grey'

    Text {
        id: main_text
        color: "#d9000000"
        text: qsTr(tile_text)
        fontSizeMode: Text.Fit
        clip: true
        font.weight: Font.Medium
        font.capitalization: Font.AllUppercase
        font.pixelSize: tile_text_max_size
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        anchors.right: parent.right
        anchors.left: parent.left
        anchors.topMargin: tile_text_spacing
        anchors.leftMargin: tile_text_spacing
        anchors.rightMargin: tile_text_spacing
        anchors.bottomMargin: tile_text_spacing
        z: 1
    }

    Rectangle {
        id: background
        anchors.fill: parent
        color: tile_color
        z: 0
    }
}

Add ID to generic tile

import QtQuick 2.7

Item {
    id: generic_tile
    property int tile_text_spacing: 20
    property string tile_text: 'Tile'
    property int tile_text_max_size: 72
    property string tile_color: 'grey'

    Text {
        id: main_text
        color: "#d9000000"
        text: qsTr(tile_text)
        fontSizeMode: Text.Fit
        clip: true
        font.weight: Font.Medium
        font.capitalization: Font.AllUppercase
        font.pixelSize: tile_text_max_size
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
        anchors.top: parent.top
        anchors.bottom: parent.bottom
        anchors.right: parent.right
        anchors.left: parent.left
        anchors.topMargin: tile_text_spacing
        anchors.leftMargin: tile_text_spacing
        anchors.rightMargin: tile_text_spacing
        anchors.bottomMargin: tile_text_spacing
        z: 1
    }

    Rectangle {
        id: background
        anchors.fill: parent
        color: tile_color
        z: 0
    }
}


import QtQuick 2.0
import Sailfish.Silica 1.0

// This component creates a menu item with two lines
MenuItem {
    property string subtext: ""

    Label {
        visible: subtext !== ""
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        text: subtext
        color: Theme.secondaryColor
        font.pixelSize: Theme.fontSizeExtraSmall
    }
}

Make dir popup second row text smaller

import QtQuick 2.0
import Sailfish.Silica 1.0

// This component is a menu item with two lines
MenuItem {
    property string subtext: ""

    Label {
        visible: subtext !== ""
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.bottom: parent.bottom
        text: subtext
        color: Theme.secondaryColor
        font.pixelSize: Theme.fontSizeTiny
    }
}


import QtQuick 2.7

Item {

}

Add background and basic text on generic tile

import QtQuick 2.7

Item {
    id: item1
    property int tile_text_spacing: 20
    property string tile_text: 'Tile'
    property string tile_color: 'grey'

    Text {
        id: main_text
        text: qsTr(tile_text)
        anchors.right: parent.right
        anchors.left: parent.left
        anchors.leftMargin: 0
        anchors.rightMargin: 0
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
        anchors.top: parent.top
        anchors.topMargin: tile_text_spacing
        z: 1
    }

    Rectangle {
        id: background
        anchors.fill: parent
        color: tile_color
        z: 0
    }

}


import qbs 1.0

Project {
    StaticLibrary {
        name: "a"

        Depends { name: "cpp" }

        files: [
            "a.c",
        ]
    }

    StaticLibrary {
        name: "b"

        Depends { name: "a" }
        Depends { name: "cpp" }

        files: [
            "b.c",
        ]
    }

    CppApplication {
        name: "appWithoutSources"
        type: ["application"]
        cpp.entryPoint: "main"

        Depends { name: "a" }
        Depends { name: "b" }
    }
}

Apply workaround to get appWithoutSources autotest passing again.

import qbs 1.0

Project {
    StaticLibrary {
        name: "a"

        Depends { name: "cpp" }

        files: [
            "a.c",
        ]
    }

    StaticLibrary {
        name: "b"

        Depends { name: "a" }
        Depends { name: "cpp" }

        files: [
            "b.c",
        ]
    }

    CppApplication {
        name: "appWithoutSources"
        type: ["application"]

        // HACK: cpp.entryPoint currently not working 100% with gcc
        Properties {
            condition: qbs.toolchain.contains("msvc")
            cpp.entryPoint: "main"
        }

        Depends { name: "a" }
        Depends { name: "b" }
    }
}


import QtQuick 2.1
import Sailfish.Silica 1.0

Page {
    id: root

    property string url

    // work around Silica bug: don't let webview enable forward navigation
    onForwardNavigationChanged: {
        if (forwardNavigation) {
            forwardNavigation = false;
        }
    }

    allowedOrientations: Orientation.All

    Loader {
        anchors.fill: parent
        sourceComponent: parent.status === PageStatus.Active ? webComponent : undefined
    }

    Component {
        id: webComponent

        SilicaWebView {
            id: webview

            header: PageHeader {
                title: webview.title
            }

            PullDownMenu {
                MenuItem {
                    text: qsTr("Close web view")

                    onClicked: {
                        root.backNavigation = true;
                        pageStack.pop(PageStackAction.Animated);
                    }
                }

                MenuItem {
                    text: qsTr("Copy link to clipboard");
                    onClicked: {
                        textArea.text = url; textArea.selectAll(); textArea.copy();
                        infoBanner.showText(qsTr("Link") + " " + textArea.text + " " + qsTr("copied to clipboard."));
                    }
                }

                TextArea {
                    id: textArea;
                    visible: false;
                }

                MenuItem {
                    text: qsTr("Open in browser")

                    onClicked: {
                        Qt.openUrlExternally(root.url);
                    }
                }
            }

            url: root.url
        }
    }

}

Add busyindicator to webview. Change copy clipboard to use Clipboard.

import QtQuick 2.1
import Sailfish.Silica 1.0

Page {
    id: root
    objectName: "WebPage"

    property string url

    // work around Silica bug: don't let webview enable forward navigation
    onForwardNavigationChanged: {
        if (forwardNavigation) {
            forwardNavigation = false;
        }
    }

    allowedOrientations: Orientation.All

    Loader {
        id: loader

        anchors.fill: parent
        sourceComponent: parent.status === PageStatus.Active ? webComponent : undefined
    }

    Component {
        id: webComponent

        SilicaWebView {
            id: webview

            header: PageHeader {
                title: webview.title
            }

            PullDownMenu {
                MenuItem {
                    text: qsTr("Close web view")

                    onClicked: {
                        root.backNavigation = true;
                        pageStack.pop(PageStackAction.Animated);
                    }
                }

                MenuItem {
                    text: qsTr("Copy link to clipboard");
                    onClicked: {
                        Clipboard.text = url;
                        infoBanner.showText(qsTr("Link") + " " + Clipboard.text + " " + qsTr("copied to clipboard."));
                    }
                }

                MenuItem {
                    text: qsTr("Open in browser")

                    onClicked: {
                        Qt.openUrlExternally(root.url);
                    }
                }
            }

            url: root.url
        }
    }

    BusyIndicator {
        running: loader.item ? loader.item.loading : false
        anchors.centerIn: parent
        size: BusyIndicatorSize.Large
    }

}


// CustomButton.qml
//
import QtQuick 2.0

Rectangle {
    property alias text: label.text
    property alias font: label.font
    signal clicked

    width: label.width + 20; height: label.height + 5;
    border { width: 1; color: Qt.darker(activePalette.button) }
    antialiasing: true
    radius: 8
    /// Color the button with a gradient
    gradient: Gradient {
        GradientStop {
            position: 0.0
            color: {
                if (mouseArea.pressed)
                    return activePalette.dark
                else
                    return activePalette.light
            }
        }
        GradientStop {
            position: 1.0
            color: activePalette.button
        }
    }

    Text {
        id: label
        anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter }
        text: "Button"
    }

    MouseArea {
        id: mouseArea
        anchors.fill: parent
        onClicked: parent.clicked()
    }
}

Adjust button rectangle radius to 4

// CustomButton.qml
//
import QtQuick 2.0

Rectangle {
    property alias text: label.text
    property alias font: label.font
    signal clicked

    width: label.width + 20; height: label.height + 5;
    border { width: 1; color: Qt.darker(activePalette.button) }
    antialiasing: true
    radius: 4
    /// Color the button with a gradient
    gradient: Gradient {
        GradientStop {
            position: 0.0
            color: {
                if (mouseArea.pressed)
                    return activePalette.dark
                else
                    return activePalette.light
            }
        }
        GradientStop {
            position: 1.0
            color: activePalette.button
        }
    }

    Text {
        id: label
        anchors { horizontalCenter: parent.horizontalCenter; verticalCenter: parent.verticalCenter }
        text: "Button"
    }

    MouseArea {
        id: mouseArea
        anchors.fill: parent
        onClicked: parent.clicked()
    }
}


/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Raine Makelainen <raine.makelainen@jollamobile.com>
**
****************************************************************************/

import QtQuick 2.0
import Sailfish.Silica 1.0

Rectangle {
    color: Theme.highlightBackgroundColor
    height: visible ? Theme.itemSizeLarge : 0
}

Fix toolbar height to not cause rounding problems in chrome mode.

/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Raine Makelainen <raine.makelainen@jollamobile.com>
**
****************************************************************************/

import QtQuick 2.0
import Sailfish.Silica 1.0

Rectangle {
    color: Theme.highlightBackgroundColor
    // Height of toolbar should be such that viewport height is
    // even number both chrome and fullscreen modes. For instance
    // height of 110px for toolbar would result would result 1px rounding
    // error in chrome mode as viewport height would be 850px. This would
    // result in CSS pixels viewport height of 566.66..px -> rounded to 566px.
    // So, check that (device height - toolbar height) / pixel ratio is even number.
    height: visible ? Theme.itemSizeMedium * 1.2 : 0
}


import qbs

Project {
    CppApplication {
        name: "default app"
        consoleApplication: true
        files: "main.cpp"
    }

    CppApplication {
        name: "non-default app"
        consoleApplication: true
        builtByDefault: false
        files: "main.cpp"
    }
}

Update autotest for non-default products.

import qbs

Project {
    CppApplication {
        name: "default app"
        consoleApplication: true
        files: "main.cpp"
    }

    CppApplication {
        name: "non-default app"
        Depends { name: "default app" }
        consoleApplication: true
        builtByDefault: false
        files: "main.cpp"
    }
}


import QtQuick 2.12
import QtQuick.Controls 2.5

import ".."

Item {
    id: root

    property string name
    property Setting setting
    property alias echoMode: textField.echoMode
    property alias inputMethodHints: textField.inputMethodHints

    implicitHeight: item.implicitHeight

    SettingItem {
        id: item

        name: root.name
        subtitle: setting.value
        anchors.fill: parent

        onClicked: dialog.open()

        Dialog {
            id: dialog

            title: root.name
            anchors.centerIn: Overlay.overlay
            modal: true
            standardButtons: Dialog.Ok | Dialog.Cancel

            onAccepted: setting.setValue(textField.text)
            onRejected: textField.text = setting.value

            TextField {
                id: textField
                anchors.fill: parent
                text: setting.value
            }
        }
    }
}

Stop showing raw passwords in QML settings

import QtQuick 2.12
import QtQuick.Controls 2.5

import ".."

Item {
    id: root

    property string name
    property Setting setting
    property alias echoMode: textField.echoMode
    property alias inputMethodHints: textField.inputMethodHints

    implicitHeight: item.implicitHeight

    SettingItem {
        id: item

        name: root.name
        subtitle: textField.echoMode === TextField.Password
            ? "*".repeat(setting.value.length)
            : setting.value
        anchors.fill: parent

        onClicked: dialog.open()

        Dialog {
            id: dialog

            title: root.name
            anchors.centerIn: Overlay.overlay
            modal: true
            standardButtons: Dialog.Ok | Dialog.Cancel

            onAccepted: setting.setValue(textField.text)
            onRejected: textField.text = setting.value

            TextField {
                id: textField
                anchors.fill: parent
                text: setting.value
            }
        }
    }
}


import qbs
import qbs.FileInfo

QbsProduct {
    Depends { name: "qbscore" }
    Depends { name: "cpp" }
    type: "application"
    consoleApplication: true
    destinationDirectory: "bin"
    cpp.includePaths: [
        "../shared",    // for the logger
    ]
    cpp.cxxLanguageVersion: "c++11"
    Group {
        fileTagsFilter: product.type
        qbs.install: true
        qbs.installDir: qbsbuildconfig.appInstallDir
    }
    Group {
        name: "logging"
        prefix: FileInfo.joinPaths(product.sourceDirectory, "../shared/logging") + '/'
        files: [
            "coloredoutput.cpp",
            "coloredoutput.h",
            "consolelogger.cpp",
            "consolelogger.h"
        ]
    }
}

Set the version number for Qbs applications

import qbs
import qbs.FileInfo

QbsProduct {
    Depends { name: "qbscore" }
    Depends { name: "cpp" }
    Depends { name: "qbsversion" }
    type: "application"
    version: qbsversion.version
    consoleApplication: true
    destinationDirectory: "bin"
    cpp.includePaths: [
        "../shared",    // for the logger
    ]
    cpp.cxxLanguageVersion: "c++11"
    Group {
        fileTagsFilter: product.type
        qbs.install: true
        qbs.installDir: qbsbuildconfig.appInstallDir
    }
    Group {
        name: "logging"
        prefix: FileInfo.joinPaths(product.sourceDirectory, "../shared/logging") + '/'
        files: [
            "coloredoutput.cpp",
            "coloredoutput.h",
            "consolelogger.cpp",
            "consolelogger.h"
        ]
    }
}


import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12

ColumnLayout {
    id: root

    signal closed()
    property var fileUrl

    Image {
        Layout.fillWidth: true
        Layout.fillHeight: true
        source: fileUrl
        fillMode: Image.PreserveAspectFit
    }

    DialogButtonBox {
        standardButtons: DialogButtonBox.Close
        Layout.fillWidth: true

        onRejected: root.closed()
    }
}

Add loading bar to image screen

import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12

ColumnLayout {
    id: root

    signal closed()
    property var fileUrl

    Image {
        id: image
        Layout.fillWidth: true
        Layout.fillHeight: true
        source: fileUrl
        fillMode: Image.PreserveAspectFit
    }

    ProgressBar {
        value: image.progress
        visible: image.status != Image.Ready
        Layout.fillWidth: true
    }

    DialogButtonBox {
        standardButtons: DialogButtonBox.Close
        Layout.fillWidth: true

        onRejected: root.closed()
    }
}


import QtQuick 1.0
import "custom" as Components
import "plugin"

Components.Button {
    id:button

    width: 100
    height: Math.max(22, sizehint.height)

    property variant sizehint: backgroundItem.sizeFromContents(80, 6)
    property bool defaultbutton
    property string hint

    background: QStyleItem {
        id: styleitem
        anchors.fill: parent
        elementType: "button"
        sunken: pressed
        raised: !pressed
        hover: containsMouse
        text: iconSource === "" ? "" : button.text
        focus: button.focus
        hint: button.hint

        // If no icon, let the style do the drawing
        activeControl: focus ? "default" : ""
        Connections{
            target: button
            onToolTipTriggered: styleitem.showTip()
        }
        function showTip(){
            showToolTip(tooltip);
        }
    }

    label: Item {
        // Used as a fallback since I can't pass the imageURL
        // directly to the style object
        visible: button.iconSource === ""
        Row {
            id: row
            anchors.centerIn: parent
            spacing: 4
            Image {
                source: iconSource
                anchors.verticalCenter: parent.verticalCenter
                fillMode: Image.Stretch //mm Image should shrink if button is too small, depends on QTBUG-14957
            }
            Text {
                id:text
                color: textColor
                anchors.verticalCenter: parent.verticalCenter
                text: button.text
                horizontalAlignment: Text.Center
            }
        }
    }
    Keys.onSpacePressed:clicked()
}

Support checked state for button

import QtQuick 1.0
import "custom" as Components
import "plugin"

Components.Button {
    id:button

    width: 100
    height: Math.max(22, sizehint.height)

    property variant sizehint: backgroundItem.sizeFromContents(80, 6)
    property bool defaultbutton
    property string hint

    background: QStyleItem {
        id: styleitem
        anchors.fill: parent
        elementType: "button"
        sunken: pressed || checked
        raised: !(pressed || checked)
        hover: containsMouse
        text: iconSource === "" ? "" : button.text
        focus: button.focus
        hint: button.hint

        // If no icon, let the style do the drawing
        activeControl: focus ? "default" : ""
        Connections{
            target: button
            onToolTipTriggered: styleitem.showTip()
        }
        function showTip(){
            showToolTip(tooltip);
        }
    }

    label: Item {
        // Used as a fallback since I can't pass the imageURL
        // directly to the style object
        visible: button.iconSource === ""
        Row {
            id: row
            anchors.centerIn: parent
            spacing: 4
            Image {
                source: iconSource
                anchors.verticalCenter: parent.verticalCenter
                fillMode: Image.Stretch //mm Image should shrink if button is too small, depends on QTBUG-14957
            }
            Text {
                id:text
                color: textColor
                anchors.verticalCenter: parent.verticalCenter
                text: button.text
                horizontalAlignment: Text.Center
            }
        }
    }
    Keys.onSpacePressed:clicked()
}


Layout {
	property int currentIndex: 0;
	property int count: 0;
	clip: true;

	onCurrentIndexChanged: {
		if (this.currentIndex < 0)
			this.currentIndex = 0;
		else if (this.currentIndex >= this.children.length)
			this.currentIndex = this.children.length - 1;

		this._delayedLayout.schedule()
	}

	onActiveFocusChanged: {
		if (value && this.count)
			this.children[this.currentIndex].setFocus()
	}

	function _layout() {
		this.count = this.children.length;
		for (var i = 0; i < this.count; ++i)
			this.children[i].visible = (i == this.currentIndex);

		var c = this.children[this.currentIndex];
		this.contentHeight = c.height;
		this.contentWidth = c.width;
	}

	function addChild(child) {
		qml.core.Item.prototype.addChild.apply(this, arguments)
		var delayedLayout = this._delayedLayout
		child.onChanged('height', delayedLayout.schedule.bind(delayedLayout))
		child.onChanged('recursiveVisible', delayedLayout.schedule.bind(delayedLayout))
	}

}

Check children before size setting.

Layout {
	property int currentIndex: 0;
	property int count: 0;
	clip: true;

	onCurrentIndexChanged: {
		if (this.currentIndex < 0)
			this.currentIndex = 0;
		else if (this.currentIndex >= this.children.length)
			this.currentIndex = this.children.length - 1;

		this._delayedLayout.schedule()
	}

	onActiveFocusChanged: {
		if (value && this.count)
			this.children[this.currentIndex].setFocus()
	}

	function _layout() {
		this.count = this.children.length;
		for (var i = 0; i < this.count; ++i)
			this.children[i].visible = (i == this.currentIndex);

		var c = this.children[this.currentIndex];
		if (!c)
			return

		this.contentHeight = c.height;
		this.contentWidth = c.width;
	}

	function addChild(child) {
		qml.core.Item.prototype.addChild.apply(this, arguments)
		var delayedLayout = this._delayedLayout
		child.onChanged('height', delayedLayout.schedule.bind(delayedLayout))
		child.onChanged('recursiveVisible', delayedLayout.schedule.bind(delayedLayout))
	}

}


Text {
	signal clicked;
	property bool hover;
	property string cursor: "pointer";

	property string href;

	onHrefChanged: {
		this.element.attr("href", this.href)
	}

	constructor: {
		this.element.remove();
		this.element = this.getContext().createElement('a')
		this.parent.element.append(this.element);
		this.style('cursor', this.cursor);
	}

	onCursorChanged: 	{ this.style('cursor', value) }

	_onEnter: {
		if (this.recursiveVisible)
			this.hover = true;
	}

	_onExit: {
		if (this.recursiveVisible)
			this.hover = false;
	}

	_onClick: {
		if (this.recursiveVisible)
			this.clicked()
	}

	onCompleted: {
		var self = this;
		self.element.click(self._onClick.bind(self))
		self.element.hover(self._onEnter.bind(self), self._onExit.bind(self)) //fixme: unsubscribe
	}
}

Use new API for events subscribing.

Text {
	signal clicked;
	property bool hover;
	property string cursor: "pointer";

	property string href;

	onHrefChanged: {
		this.element.attr("href", this.href)
	}

	constructor: {
		this.element.remove();
		this.element = this.getContext().createElement('a')
		this.parent.element.append(this.element);
		this.style('cursor', this.cursor);
	}

	onCursorChanged: 	{ this.style('cursor', value) }

	_onEnter: {
		if (this.recursiveVisible)
			this.hover = true;
	}

	_onExit: {
		if (this.recursiveVisible)
			this.hover = false;
	}

	_onClick: {
		if (this.recursiveVisible)
			this.clicked()
	}

	onCompleted: {
		this.element.on('click', this._onClick.bind(this))
		this.element.on('mouseenter', this._onEnter.bind(this))
		this.element.on('mouseleave', this._onExit.bind(this))
	}
}


/****************************************************************************
 * This file is part of Qt AccountsService Addon.
 *
 * Copyright (C) 2015 Leslie Zhai <xiang.zhai@i-soft.com.cn>
 *
 * Author(s):
 *    Leslie Zhai
 *
 * $BEGIN_LICENSE:LGPL2.1+$
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $END_LICENSE$
 ***************************************************************************/

import QtQuick 2.2
import QtQuick.Window 2.1
import QtAccountsService 1.0

Window {
    width: 300; height: 200
    title: "AccountsService Qt binding"

    UserAccount {
        id: userAccount
        Component.onCompleted: {
            faceIcon.source = iconFileName;
            loginName.text = userName;
            displayName.text = userAccount.displayName;
        }
    }

    Image {
        id: faceIcon
    }

    Text {
        id: loginName
        anchors.left: faceIcon.right
    }

    Text {
        id: displayName
        anchors.top: loginName.bottom
        anchors.left: loginName.left
    }
}


import qbs.base 1.0
import "../../../../qbs/defaults.js" as Defaults

DynamicLibrary {
    name: "styleplugin"

    Depends { name: "cpp" }
    Depends { name: "Qt"; submodules: ["core", "widgets", "declarative", "script"] }

    cpp.defines: Defaults.defines(qbs)

    files: [
        "qdeclarativefolderlistmodel.cpp",
        "qdeclarativefolderlistmodel.h",
        "qrangemodel.cpp",
        "qrangemodel.h",
        "qrangemodel_p.h",
        "qstyleitem.cpp",
        "qstyleitem.h",
        "qstyleplugin.cpp",
        "qstyleplugin.h",
        "qtmenu.cpp",
        "qtmenu.h",
        "qtmenubar.cpp",
        "qtmenubar.h",
        "qtmenuitem.cpp",
        "qtmenuitem.h",
        "qwheelarea.cpp",
        "qwheelarea.h",
    ]

    Group {
        fileTagsFilter: product.type
        qbs.install: true
        qbs.installDir: project.ide_library_path + "/qtcomponents/plugin"
    }
}

Fix install path for styleplugin on Windows

import qbs.base 1.0
import "../../../../qbs/defaults.js" as Defaults

DynamicLibrary {
    name: "styleplugin"

    Depends { name: "cpp" }
    Depends { name: "Qt"; submodules: ["core", "widgets", "declarative", "script"] }

    cpp.defines: Defaults.defines(qbs)

    files: [
        "qdeclarativefolderlistmodel.cpp",
        "qdeclarativefolderlistmodel.h",
        "qrangemodel.cpp",
        "qrangemodel.h",
        "qrangemodel_p.h",
        "qstyleitem.cpp",
        "qstyleitem.h",
        "qstyleplugin.cpp",
        "qstyleplugin.h",
        "qtmenu.cpp",
        "qtmenu.h",
        "qtmenubar.cpp",
        "qtmenubar.h",
        "qtmenuitem.cpp",
        "qtmenuitem.h",
        "qwheelarea.cpp",
        "qwheelarea.h",
    ]

    Group {
        fileTagsFilter: product.type
        qbs.install: true
        qbs.installDir: (qbs.targetOS.contains("windows") ? "lib/qtcreator" : project.ide_library_path)
                        + "/qtcomponents/plugin"
    }
}


import qbs

CppApplication {
    type: "application"
    files: "raw_socket_write/raw_socket.c"
}

Add dummy qbs build configuration

import qbs

CppApplication {
    type: "application"
    name: "test_session"
}


import QtQuick 2.4
import QtQuick.Dialogs 1.0

import QmlToolbox.Base 1.0
import QmlToolbox.Controls 1.0

/**
*  EditorFilename
*
*  Editor for properties of type 'filename'
*/
Editor
{
    id: item

    implicitWidth:  input.implicitWidth
    implicitHeight: input.implicitHeight

    TextField
    {
        id: input

        anchors.top:         parent.top
        anchors.bottom:      parent.bottom
        anchors.left:        parent.left
        anchors.right:       button.left
        anchors.rightMargin: Ui.style.paddingMedium

        onEditingFinished:
        {
            item.properties.setValue(item.path, item.slot, text);
        }
    }

    Button
    {
        id: button

        anchors.top:    parent.top
        anchors.bottom: parent.bottom
        anchors.right:  parent.right
        implicitWidth:  32

        text: '...'

        onClicked:
        {
            fileDialog.open();
        }
    }

    FileDialog
    {
        id: fileDialog

        title:          'Open texture'
        selectExisting: true
        selectFolder:   false
        selectMultiple: false

        onAccepted:
        {
            var path = QmlUtils.urlToLocalFile(fileUrl);

            input.text = path;
            item.properties.setValue(item.path, item.slot, path);
        }
    }

    onStatusChanged:
    {
        input.text = status.value;
    }
}

Make text edit field for filenames read-only

import QtQuick 2.4
import QtQuick.Dialogs 1.0

import QmlToolbox.Base 1.0
import QmlToolbox.Controls 1.0

/**
*  EditorFilename
*
*  Editor for properties of type 'filename'
*/
Editor
{
    id: item

    implicitWidth:  input.implicitWidth
    implicitHeight: input.implicitHeight

    TextField
    {
        id: input

        anchors.top:         parent.top
        anchors.bottom:      parent.bottom
        anchors.left:        parent.left
        anchors.right:       button.left
        anchors.rightMargin: Ui.style.paddingMedium

        readOnly: true

        onEditingFinished:
        {
            item.properties.setValue(item.path, item.slot, text);
        }
    }

    Button
    {
        id: button

        anchors.top:    parent.top
        anchors.bottom: parent.bottom
        anchors.right:  parent.right
        implicitWidth:  32

        text: '...'

        onClicked:
        {
            fileDialog.open();
        }
    }

    FileDialog
    {
        id: fileDialog

        title:          'Open texture'
        selectExisting: true
        selectFolder:   false
        selectMultiple: false

        onAccepted:
        {
            var path = QmlUtils.urlToLocalFile(fileUrl);

            input.text = path;
            item.properties.setValue(item.path, item.slot, path);
        }
    }

    onStatusChanged:
    {
        input.text = status.value;
    }
}


ListModel {
	property Object parentModel;
	property int channelIdx;

	onCompleted: {
		var row = this.parentModel.get(this.channelIdx).schedule;

		var daysBefore = 2;
		var startTime = Math.round(new Date().getTime() / 1000) - daysBefore * 24 * 3600;
		var delta = row[0].start - startTime;
		var newRow;
		if (delta > 0)
			this.append({
				title: "Нет информации",
				start: startTime,
				duration: delta
			});
		this.append({
			title: row[0].title,
			start: row[0].start,
			duration: row[0].duration + delta
		});
		for (var i = 1; i < row.length; ++i)
			this.append(row[i]);
	}
}

Add empty programs after time scope.

ListModel {
	property Object parentModel;
	property int channelIdx;

	onCompleted: {
		var row = this.parentModel.get(this.channelIdx).schedule;

		var daysBefore = 2;
		var startTime = Math.round(new Date().getTime() / 1000) - daysBefore * 24 * 3600;
		var delta = row[0].start - startTime;
		if (delta > 0)
			this.append({
				title: "Нет информации",
				start: startTime,
				duration: delta,
				empty: true
			});
		this.append({
			title: row[0].title,
			start: row[0].start,
			duration: row[0].duration + delta
		});
		for (var i = 1; i < row.length; ++i)
			this.append(row[i]);

		var daysAfter = 5;
		var endTime = Math.round(new Date().getTime() / 1000) - daysAfter * 24 * 3600;
		var delta = row[row.length - 1].start - endTime;
		if (delta > 0)
			this.append({
				title: "Нет информации",
				start: row[row.length - 1].start,
				duration: delta,
				empty: true
			});
	}
}


import qbs

Product {
    property bool isBlubbOS: qbs.targetOS.contains("blubb-OS")
    profiles: isBlubbOS ? ["blubb-profile"] : [project.profile]
    qbs.architecture: "blubb-arch"
}


/*
The MIT License (MIT)

Copyright (c) 2016 Oleg Linkin <maledictusdemagog@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

import QtQuick 2.0
import Sailfish.Silica 1.0

ApplicationWindow {
    id: mainWindow
}


import QtQuick 2.1
import QtQuick.Layouts 1.0
import Plot 1.0

RowLayout {
  Layout.fillHeight: true
  property var xaxis
  property var test

  Rectangle {
    width: 320
    Layout.fillHeight: true

    color: '#444444'
  }

  PhosphorRender {
      Layout.fillHeight: true
      Layout.fillWidth: true

      Rectangle {
        color: 'green'
        opacity: 0.1
        anchors.fill: parent
      }

      id: line
      anchors.margins: 20

      buffer: FloatBuffer{}

      Component.onCompleted: {
          if (test == 'sine') {
            this.buffer.fillSine(1/533/1000, 533, 1);
          } else {
            this.buffer.fillSawtooth(1/533/1000, 333, 1);
          }
          for (var i=0; i<0; i++) {
              this.buffer.jitter(0.01);
          }
      }

      pointSize: 2

      xmin: xaxis.visibleMin
      xmax: xaxis.visibleMax
      ymin: -1.1
      ymax: 1.1
  }
}

Scale the points on zoom

import QtQuick 2.1
import QtQuick.Layouts 1.0
import Plot 1.0

RowLayout {
  Layout.fillHeight: true
  property var xaxis
  property var test

  Rectangle {
    width: 320
    Layout.fillHeight: true

    color: '#444444'
  }

  PhosphorRender {
      Layout.fillHeight: true
      Layout.fillWidth: true

      id: line
      anchors.margins: 20

      buffer: FloatBuffer{}

      Component.onCompleted: {
          if (test == 'sine') {
            this.buffer.fillSine(1/533/1000, 533, 1);
          } else {
            this.buffer.fillSawtooth(1/533/1000, 333, 1);
          }
          for (var i=0; i<0; i++) {
              this.buffer.jitter(0.01);
          }
      }

      pointSize: Math.max(2, Math.min(xaxis.xscale/200000, 20))

      xmin: xaxis.visibleMin
      xmax: xaxis.visibleMax
      ymin: -1.1
      ymax: 1.1
  }
}


import qbs.Environment
import qbs.FileInfo

Project {
    QtApplication {
        name: "app"
        Depends { name: "Qt.scxml"; required: false }

        Properties {
            condition: Qt.scxml.present
            cpp.defines: ["HAS_QTSCXML"]
        }

        Qt.scxml.className: "QbsStateMachine"
        Qt.scxml.namespace: "QbsTest"
        Qt.scxml.generateStateMethods: true

        files: ["main.cpp"]
        Group {
            files: ["dummystatemachine.scxml"]
            fileTags: ["qt.scxml.compilable"]
        }
    }

    Product {
        name: "runner"
        type: ["runner"]
        Depends { name: "app" }
        Rule {
            inputsFromDependencies: ["application"]
            outputFileTags: ["runner"]
            prepare: {
                var cmd = new Command(input.filePath);
                cmd.description = "running " + input.filePath;
                var pathVar;
                var pathValue;
                if (product.qbs.hostOS.contains("windows")) {
                    pathVar = "PATH";
                    pathValue = FileInfo.toWindowsSeparators(input["Qt.core"].binPath);
                } else {
                    pathVar = "LD_LIBRARY_PATH";
                    pathValue = input["Qt.core"].libPath;
                }
                var oldValue = Environment.getEnv(pathVar) || "";
                var newValue = pathValue + product.qbs.pathListSeparator + oldValue;
                cmd.environment = [pathVar + '=' + newValue];
                return [cmd];
            }
        }
    }
}

Work around compression bug in 5.13.0

import qbs.Environment
import qbs.FileInfo
import qbs.Utilities

Project {
    QtApplication {
        name: "app"
        Depends { name: "Qt.scxml"; required: false }

        Properties {
            condition: Qt.scxml.present && Utilities.versionCompare(Qt.core.version, "5.13.0") != 0
            cpp.defines: ["HAS_QTSCXML"]
        }

        Qt.scxml.className: "QbsStateMachine"
        Qt.scxml.namespace: "QbsTest"
        Qt.scxml.generateStateMethods: true

        files: ["main.cpp"]
        Group {
            files: ["dummystatemachine.scxml"]
            fileTags: ["qt.scxml.compilable"]
        }
    }

    Product {
        name: "runner"
        type: ["runner"]
        Depends { name: "app" }
        Rule {
            inputsFromDependencies: ["application"]
            outputFileTags: ["runner"]
            prepare: {
                var cmd = new Command(input.filePath);
                cmd.description = "running " + input.filePath;
                var pathVar;
                var pathValue;
                if (product.qbs.hostOS.contains("windows")) {
                    pathVar = "PATH";
                    pathValue = FileInfo.toWindowsSeparators(input["Qt.core"].binPath);
                } else {
                    pathVar = "LD_LIBRARY_PATH";
                    pathValue = input["Qt.core"].libPath;
                }
                var oldValue = Environment.getEnv(pathVar) || "";
                var newValue = pathValue + product.qbs.pathListSeparator + oldValue;
                cmd.environment = [pathVar + '=' + newValue];
                return [cmd];
            }
        }
    }
}


Object {
	property string name;
	property string value;

	onNameChanged: {
		this.read()
	}

	onValueChanged: {
		this.init()
		//log("localStorage: write", this.name, this.value)
		this._storage.setItem(this.name, this.value)
	}

	read: {
		this.init()
		var value = this.name? this._storage.getItem(this.name): "";
		if (value !== null && value !== undefined)
			this.value = value
		//log("localStorage: read", this.name, this.value)
	}

	init: {
		if (!this._storage) {
			this._storage = window.localStorage;
			if (!this._storage)
				throw new Error("no local storage support")
		}
	}

	onCompleted: {
		this.read()
	}
}

Add comments for doc generation.

Object {
	property string name;		///< stored property key name
	property string value;		///< stored property value

	///@internal
	onNameChanged: {
		this.read()
	}

	///@internal
	onValueChanged: {
		this.init()
		this._storage.setItem(this.name, this.value)
	}

	///@private
	read: {
		this.init()
		var value = this.name? this._storage.getItem(this.name): "";
		if (value !== null && value !== undefined)
			this.value = value
	}

	///@private
	init: {
		if (!this._storage) {
			this._storage = window.localStorage;
			if (!this._storage)
				throw new Error("no local storage support")
		}
	}

	///@private
	onCompleted: {
		this.read()
	}
}


/*
 * Copyright © 2015-2017 Oleksii Aliakin. All rights reserved.
 * Author: Oleksii Aliakin (alex@nls.la)
 * Author: Andrii Shelest
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import qbs
import qbs.FileInfo

Module {
    name: "app_config"

    property string binDir: "bin"
    property string dataDir: "data"
    property string qmlInstallDir: FileInfo.joinPaths(dataDir, "qtquick2")
    property string configInstallDir: FileInfo.joinPaths(dataDir, "config")
    property string pluginsInstallDir: FileInfo.joinPaths(dataDir, "plugins")
    property string libsInstallDir: "lib"
    property string includesInstallDir: FileInfo.joinPaths(dataDir, "include")
}

Set binDir to installRoot by default

/*
 * Copyright © 2015-2017 Oleksii Aliakin. All rights reserved.
 * Author: Oleksii Aliakin (alex@nls.la)
 * Author: Andrii Shelest
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import qbs
import qbs.FileInfo

Module {
    name: "app_config"

    property string binDir: ""
    property string dataDir: "data"
    property string qmlInstallDir: FileInfo.joinPaths(dataDir, "qtquick2")
    property string configInstallDir: FileInfo.joinPaths(dataDir, "config")
    property string pluginsInstallDir: FileInfo.joinPaths(dataDir, "plugins")
    property string libsInstallDir: "lib"
    property string includesInstallDir: FileInfo.joinPaths(dataDir, "include")
}


import QtQuick 2.0

Item {
    id: root;

    width: 400
    height: 400
    function complicate() { count = count + increment; }
    function simplify() { count = Math.max(1, count - increment); }
    property int increment: (count >= 100
                             ? 10
                             : (count >= 50
                                ? 5
                                : count >= 10 ? 2 : 1
                                )
                             )
    property int count: 8;
    property string description: "Rendering "
                                 + count + " opaque texture"
                                 + (count > 1 ? "s" : "");
    Repeater {
        model: root.count;
        Rectangle {
            x: index
            y: index
            width: root.width
            height: root.height
            color: Qt.hsla((index * .271) % 1.0, 0.5, 0.5);
            z: index
            layer.enabled: true
            layer.format: ShaderEffectSource.RGB
        }
    }

}

Use non-blended shader effect instead of a RGB fbo

import QtQuick 2.0

Item {
    id: root;

    width: 400
    height: 400
    function complicate() { count = count + increment; }
    function simplify() { count = Math.max(1, count - increment); }
    property int increment: (count >= 100
                             ? 10
                             : (count >= 50
                                ? 5
                                : count >= 10 ? 2 : 1
                                )
                             )
    property int count: 8;
    property string description: "Rendering "
                                 + count + " opaque texture"
                                 + (count > 1 ? "s" : "");
    Repeater {
        model: root.count;
        Rectangle {
            x: index
            y: index
            width: root.width
            height: root.height
            color: Qt.hsla((index * .271) % 1.0, 0.5, 0.5);
            z: index
            layer.enabled: true
            layer.effect: ShaderEffect {
                blending: false
            }
        }
    }

}


import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12

Page {
    property string log

    header: ToolBar {
        RowLayout {
            anchors.fill: parent

            ToolButton {
                icon.source: "/images/icons/menu.png"
                onClicked: drawer.open()
            }

            Label {
                text: "Log"
                elide: Label.ElideRight
                horizontalAlignment: Qt.AlignHCenter
                verticalAlignment: Qt.AlignVCenter
                Layout.fillWidth: true
            }
        }
    }

    Label {
        anchors.fill: parent
        text: log
        textFormat: Text.RichText
    }
}

Add scrol in log view

import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12

Page {
    property string log

    header: ToolBar {
        RowLayout {
            anchors.fill: parent

            ToolButton {
                icon.source: "/images/icons/menu.png"
                onClicked: drawer.open()
            }

            Label {
                text: "Log"
                elide: Label.ElideRight
                horizontalAlignment: Qt.AlignHCenter
                verticalAlignment: Qt.AlignVCenter
                Layout.fillWidth: true
            }
        }
    }

    ScrollView {
        anchors.fill: parent
        clip: true

        Label {
            anchors.fill: parent
            padding: 6
            lineHeight: 1.1
            text: log
            textFormat: Text.RichText
        }
    }
}


Rectangle {
	property Object target;
	property string updatePositionProperty: "currentIndex";
	width: 100;
	height: 100;
	color: "#fff";

	function _updatePos() {
		var target = this.target
		var item = target.getItemPosition(target[this.updatePositionProperty])
		var horizontal = target.orientation ===  _globals.core.ListView.prototype.Horizontal
		if (horizontal) {
			this.x = target.x + item[0]
			this.width = item[2]
		} else {
			this.y = target.y + item[1]
			this.height = item[3]
		}
	}

	onCompleted: {
		var target = this.target
		this.connectOnChanged(target, this.updatePositionProperty, this._updatePos.bind(this))
		this.connectOnChanged(target, "count", this._updatePos.bind(this))
		this.connectOnChanged(target, "activeFocus", this._updatePos.bind(this))
		this._updatePos()
	}
}

Add some comments for doc generation

Rectangle {
	property Object target;	///< target view for highlighter
	property string updatePositionProperty: "currentIndex";	///< which property must changed to update highlighter position
	width: 100;
	height: 100;
	color: "#fff";

	///@private
	function _updatePos() {
		var target = this.target
		var item = target.getItemPosition(target[this.updatePositionProperty])
		var horizontal = target.orientation ===  _globals.core.ListView.prototype.Horizontal
		if (horizontal) {
			this.x = target.x + item[0]
			this.width = item[2]
		} else {
			this.y = target.y + item[1]
			this.height = item[3]
		}
	}

	onCompleted: {
		var target = this.target
		this.connectOnChanged(target, this.updatePositionProperty, this._updatePos.bind(this))
		this.connectOnChanged(target, "count", this._updatePos.bind(this))
		this.connectOnChanged(target, "activeFocus", this._updatePos.bind(this))
		this._updatePos()
	}
}


import QtQuick 2.2
import QtQuick.Controls 1.4

ApplicationWindow {
    visible: true
    title: "libqmlbind's Example Window"
    width: 600
    height: 400

    Label {
        anchors.centerIn: parent
        id: helloworld
        text: "Hello, World!"
    }
}