import QtQuick 2.4
import QtQuick.Controls.Private 1.0

// TooltipArea.qml
// This file contains private Qt Quick modules that might change in future versions of Qt
// Tested on: Qt 5.4.1
// Based on https://www.kullo.net/blog/tooltiparea-the-missing-tooltip-component-of-qt-quick/

MouseArea {
    id: _root
    property string text: ""

    hoverEnabled: _root.enabled

    onExited: Tooltip.hideText()
    onCanceled: Tooltip.hideText()

    Timer {
        interval: 1000
        running: _root.enabled && _root.containsMouse && _root.text.length
        onTriggered: Tooltip.showText(_root, Qt.point(_root.mouseX, _root.mouseY), wrapText(_root.text, 80))
    }

    /**
     * Manually wrap a line of text to a certain maximum line length.
     *
     * This method will introduce newlines so that the length of each string
     * will be equal or less than a certain maximum line length.
     *
     * \param text The text to wrap.
     * \param line_length The maximum line length to wrap to.
     */
    function wrapText(text, line_length)
    {
        var words = text.split(" ");
        var lines = [];
        var line = "";
        var word = "";

        for(var i = 0; i < words.length; i++)
        {
            word = words[i];
            if((line.length + word.length + 1) > line_length)
            {
                lines.push(line);
                line = "";
            }
            line += " "
            line += word
        }
        lines.push(line);
        return lines.join("\n");
    }
}

Use built-in wrapping functionality for tooltips

import QtQuick 2.4
import QtQuick.Controls.Private 1.0

// TooltipArea.qml
// This file contains private Qt Quick modules that might change in future versions of Qt
// Tested on: Qt 5.4.1
// Based on https://www.kullo.net/blog/tooltiparea-the-missing-tooltip-component-of-qt-quick/

MouseArea {
    id: _root
    property string text: ""

    hoverEnabled: _root.enabled

    onExited: Tooltip.hideText()
    onCanceled: Tooltip.hideText()

    Timer {
        interval: 1000
        running: _root.enabled && _root.containsMouse && _root.text.length
        onTriggered: Tooltip.showText(_root, Qt.point(_root.mouseX, _root.mouseY), wrapText(_root.text))
    }

    /**
     * Wrap a line of text automatically to a readable width.
     *
     * This automatically wraps the line around if it is too wide.
     *
     * \param text The text to wrap.
     */
    function wrapText(text)
    {
        /* The divider automatically adapts to 100% of the parent width and
        wraps properly, so this causes the tooltips to be wrapped to the width
        of the tooltip as set by the operating system. */
        return "<div>" + text + "</div>"
    }
}


import QtQuick 2.8
import QtQuick.XmlListModel 2.0

BaseXml {
    query: "/MPL/Item"
    mcwsFields: "name,artist,album,genre,duration,media type"

    onHostUrlChanged: source = ""

    function loadPlayingNow(zoneid)
    {
        source = ""
        load("Playback/Playlist?Zone=" + zoneid)
    }

    function loadSearch(search)
    {
        source = ""
        load("Files/Search?Shuffle=1&query=" + search)
    }

    // Filekey (mcws: Key) will always be the first field returned
    XmlRole { name: "filekey";  query: "Field[1]/string()" }

}

Add playlist tracks query method

import QtQuick 2.8
import QtQuick.XmlListModel 2.0

BaseXml {
    query: "/MPL/Item"
    mcwsFields: "name,artist,album,genre,duration,media type"

    onHostUrlChanged: source = ""

    function loadPlayingNow(zoneid)
    {
        source = ""
        load("Playback/Playlist?Zone=" + zoneid)
    }

    function loadSearch(search)
    {
        source = ""
        load("Files/Search?Shuffle=1&query=" + search)
    }

    function loadPlaylistFiles(search)
    {
        source = ""
        load("Playlist/Files?" + search)
    }

    // Filekey (mcws: Key) will always be the first field returned
    XmlRole { name: "filekey";  query: "Field[1]/string()" }

}


import QtQuick 2.5
import QtQuick.Window 2.2

Window {
    visible: true
    width: 600
    height: 400

    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }

    Image {
        source: "qrc:/delete.svg"
        sourceSize.width: 400
        sourceSize.height: 400
        anchors.centerIn: parent
    }

    Text {
        text: qsTr("Hello World") + magicNumber
        anchors.centerIn: parent
        color: "#ffffff"
    }
}

Test app to exit on timeout

import QtQuick 2.5
import QtQuick.Window 2.2

Window {
    visible: true
    width: 600
    height: 400

    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }

    Image {
        source: "qrc:/delete.svg"
        sourceSize.width: 400
        sourceSize.height: 400
        anchors.centerIn: parent
    }

    Text {
        text: qsTr("Hello World") + magicNumber
        anchors.centerIn: parent
        color: "#ffffff"
    }

    Timer {
        interval: 2000
        repeat: false
        onTriggered: Qt.quit()
        running: true
    }
}


import QtQuick 2.0
import FluidCore 1.0 as FluidCore
import FluidUi 1.0 as FluidUi

Rectangle {
	width: 300
	height: 300
	color: "gainsboro"

	Column {
		id: column
		spacing: 30
		width: 100

		FluidUi.Label { text: "This is a label" }
		FluidUi.Button { enabled: false; text: "Disabled Button" }
	}
}

Add radio buttons to the little demo.

import QtQuick 2.0
import FluidCore 1.0 as FluidCore
import FluidUi 1.0 as FluidUi

Rectangle {
	width: 300
	height: 300
	color: "gainsboro"

	Column {
		id: column
		spacing: 30
		width: 100

		FluidUi.Label { text: "This is a label" }
		FluidUi.Button { enabled: true; text: "Enabled Button" }
		FluidUi.Button { enabled: false; text: "Disabled Button" }
		FluidUi.RadioButton { text: "Radio 1" }
		FluidUi.RadioButton { text: "Radio 2" }
	}
}


import QtQuick 2.9
import QtQuick.Layouts 1.2

RowLayout {

    property var items
    property var root: ({
                            text: qsTr("Home")
                        })

    BreadCrumb {
        text: root.text
        action: items.length > 0 && function () {
            popToDepth(0)
        }
    }

    Repeater {
        model: items

        RowLayout {
            BreadCrumbSeparator {
            }
            BreadCrumb {
                text: items[index].text
                action: !active && function () {
                    popToDepth(index + 1)
                }
                active: index === items.length - 1
            }
        }
    }
}

Enable breadcrumb items to override the action

import QtQuick 2.9
import QtQuick.Layouts 1.2

RowLayout {

    property var items
    property var root: ({
                            text: qsTr("Home")
                        })

    BreadCrumb {
        text: root.text
        action: root.action || (items.length > 0 && function () {
            popToDepth(0)
        })
    }

    Repeater {
        model: items

        RowLayout {
            BreadCrumbSeparator {
            }
            BreadCrumb {
                text: items[index].text
                action: items[index].action || (index < items.length - 1
                                                && function () {
                                                    popToDepth(index + 1)
                                                })
                active: !!action
            }
        }
    }
}


import QtQuick 2.0

Rectangle {
    id: tile
    state: "open"
    width: 40
    height: 40
    border.width: 5
    border.color: "black"
    color: "white"

    property int count: 0
    property int index: 0

    states: [
        State {
            name: "open"
            PropertyChanges { target: tile; color: "white" }
        },
        State {
            name: "closed"
            PropertyChanges { target: tile; color: "black" }
        }
    ]

    transitions: Transition {
        ColorAnimation {  properties: "color"; duration: 150 }
    }

    Text {
        anchors.centerIn: parent
        font.pixelSize: 12
        color: "black"
        visible: count > 0
        text: count
    }

    MouseArea {
        id: mouseArea
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        onClicked: {
            if (count > 0) return
            tile.state = tile.state == "open" ? "closed" : "open"
            window.tileChecked(index);
        }
    }
}

Scale grid font size with width

import QtQuick 2.0

Rectangle {
    id: tile
    state: "open"
    width: 40
    height: 40
    border.width: 5
    border.color: "black"
    color: "white"

    property int count: 0
    property int index: 0

    states: [
        State {
            name: "open"
            PropertyChanges { target: tile; color: "white" }
        },
        State {
            name: "closed"
            PropertyChanges { target: tile; color: "black" }
        }
    ]

    transitions: Transition {
        ColorAnimation {  properties: "color"; duration: 150 }
    }

    Text {
        anchors.centerIn: parent
        font.pixelSize: parent.width / 3
        color: "black"
        visible: count > 0
        text: count
    }

    MouseArea {
        id: mouseArea
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        onClicked: {
            if (count > 0) return
            tile.state = tile.state == "open" ? "closed" : "open"
            window.tileChecked(index);
        }
    }
}


import qbs

DynamicLibrary {
    name: "tee"
    Depends { name: "cpp" }
    cpp.includePaths: ["include"]
    cpp.dynamicLibraries: ["uuid", "rt", "crypt"]

    Export {
        Depends { name: "cpp" }
        cpp.includePaths: "include"
    }

    files: ["include/tee_client_api.h", "include/tee_emu_client_api.h",
        'src/open_emu_ipc/tee_client_api_emu_ipc.c',
        'src/open_emu_ipc/list.h', 'src/open_emu_ipc/list.c',
        'src/open_emu_ipc/utils.h', 'src/open_emu_ipc/utils.c'
    ]
}

Change product destination directory to build root

import qbs

DynamicLibrary {
    name: "tee"
    Depends { name: "cpp" }
    cpp.includePaths: ["include"]
    cpp.dynamicLibraries: ["uuid", "rt", "crypt"]

    destinationDirectory: '.'

    Export {
        Depends { name: "cpp" }
        cpp.includePaths: "include"
    }

    files: ["include/tee_client_api.h", "include/tee_emu_client_api.h",
        'src/open_emu_ipc/tee_client_api_emu_ipc.c',
        'src/open_emu_ipc/list.h', 'src/open_emu_ipc/list.c',
        'src/open_emu_ipc/utils.h', 'src/open_emu_ipc/utils.c'
    ]
}


import org.webkit 1.0

// Test loading of import libraries
WebView {
    width: 640
    height: 480

    html:"\
        <body bgcolor=white>\
          Hello World\
        </body>"
}


import QtQuick 2.0

Item {
    property int decimals: 3
    property int digits: 4
    property double value: 12.2349
    property color activeColor: "white"
    property color inactiveColor: "#BBBBBB"
    property alias font: digitsText.font

    id: root
    implicitWidth: container.width
    implicitHeight: container.height

    QtObject {
        id: d
        readonly property string restValue: d.clampingFixed(value, decimals)
        readonly property int leftOver: (decimals + digits + 1) - restValue.length
        readonly property string leftOverText: "00000000".slice(-leftOver)

        function clampingFixed(value, decimals) {
            var factor = Math.pow(10, decimals);
            return ((~~(value * factor)) / factor).toFixed(decimals);
        }
    }

    Row {
        id: container
        anchors.centerIn: parent

        Text {
            id: digitsText
            color: root.inactiveColor
            text: d.leftOverText
            font.family: "Monospace"
        }

        Text {
            id: decimalsText
            font: digitsText.font
            color: root.activeColor
            text: d.restValue
        }
    }
}

Fix DRO for more than 3 digits

import QtQuick 2.0

Item {
    property int decimals: 3
    property int digits: 4
    property double value: 12.2349
    property color activeColor: "white"
    property color inactiveColor: "#BBBBBB"
    property alias font: digitsText.font

    id: root
    implicitWidth: container.width
    implicitHeight: container.height

    QtObject {
        id: d
        readonly property string restValue: d.clampingFixed(value, decimals)
        readonly property int leftOver: (decimals + digits + 1) - restValue.length
        readonly property string leftOverText: d.getLeftOverText(leftOver)

        function getLeftOverText(len) {
            if (len > 0)
                return (Array(digits + 1).join('0')).slice(-len);
            return "";
        }

        function clampingFixed(value, decimals) {
            var factor = Math.pow(10, decimals);
            return ((~~(value * factor)) / factor).toFixed(decimals);
        }
    }

    Row {
        id: container
        anchors.centerIn: parent

        Text {
            id: digitsText
            color: root.inactiveColor
            text: d.leftOverText
            font.family: "Monospace"
        }

        Text {
            id: decimalsText
            font: digitsText.font
            color: root.activeColor
            text: d.restValue
        }
    }
}


import qbs

import cutehmi

cutehmi.Test
{
	testNamePrefix: parent.parent.name

	Depends { name: "CuteHMI.Symbols.HVAC.0" }

	Depends { name: "CuteHMI.Test.0" }
}

//(c)C: Copyright © 2020, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI 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 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI 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.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.

Use proper extension as dependency.

import qbs

import cutehmi

cutehmi.Test
{
	testNamePrefix: parent.parent.name

	Depends { name: "CuteHMI.Symbols.HVAC.1" }

	Depends { name: "CuteHMI.Test.0" }
}

//(c)C: Copyright © 2020, Michał Policht <michal@policht.pl>. All rights reserved.
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI 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 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI 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.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.


Object {
	property string browser;
	property string device;
	property string vendor;
	property string os;
	property bool webkit;
	property bool portrait: context.width < context.height;
	property bool landscape: !portrait;

	onCompleted: {
		var browser = ""
		if (navigator.userAgent.indexOf('Chromium') >= 0)
			browser = "Chromium"
		else if (navigator.userAgent.indexOf('Chrome') >= 0)
			browser = "Chrome"
		else if (navigator.userAgent.indexOf('Opera') >= 0)
			browser = "Opera"
		else if (navigator.userAgent.indexOf('Firefox') >= 0)
			browser = "Firefox"
		else if (navigator.userAgent.indexOf('Safari') >= 0)
			browser = "Safari"
		else if (navigator.userAgent.indexOf('MSIE') >= 0)
			browser = "IE"
		else if (navigator.userAgent.indexOf('YaBrowser') >= 0)
			browser = "Yandex"

		this.browser = browser
		this.webkit = navigator.userAgent.toLowerCase().indexOf('webkit') >= 0
		this.device = _globals.core.device
		this.vendor = _globals.core.vendor
		this.os = _globals.core.os
	}
}

Add 'language' property to context.system.

Object {
	property string language;
	property string browser;
	property string device;
	property string vendor;
	property string os;
	property bool webkit;
	property bool portrait: context.width < context.height;
	property bool landscape: !portrait;

	onCompleted: {
		var browser = ""
		if (navigator.userAgent.indexOf('Chromium') >= 0)
			browser = "Chromium"
		else if (navigator.userAgent.indexOf('Chrome') >= 0)
			browser = "Chrome"
		else if (navigator.userAgent.indexOf('Opera') >= 0)
			browser = "Opera"
		else if (navigator.userAgent.indexOf('Firefox') >= 0)
			browser = "Firefox"
		else if (navigator.userAgent.indexOf('Safari') >= 0)
			browser = "Safari"
		else if (navigator.userAgent.indexOf('MSIE') >= 0)
			browser = "IE"
		else if (navigator.userAgent.indexOf('YaBrowser') >= 0)
			browser = "Yandex"

		this.browser = browser
		this.webkit = navigator.userAgent.toLowerCase().indexOf('webkit') >= 0
		this.device = _globals.core.device
		this.vendor = _globals.core.vendor
		this.os = _globals.core.os
		this.language = navigator.language
	}
}


import Qt 4.7

Item {
    height: 300
    width: 400

    Component {
        id: contactsDelegate
        Rectangle {
            border.width: 1
            border.color: "black"
            width: parent.width - 4
            anchors.horizontalCenter: parent.horizontalCenter
            height: childrenRect.height
            Text {
                id: aliasName
                anchors.left: parent.left
                // anchors.verticalCenter: parent.verticalCenter
                anchors.margins: 10
                text: model.aliasName
            }
            Text {
                id: presenceMessage
                anchors.left: aliasName.right
                // anchors.verticalCenter: parent.verticalCenter
                anchors.margins: 10
                text: " - " + model.presenceMessage
            }
            Text {
                id: status
                anchors.left: presenceMessage.right
                text: " - " + model.presenceStatus
            }

        }
    }

    ListView {
        id: contactsList
        anchors.fill: parent

        model: contactsListModel
        delegate: contactsDelegate
    }
}

Add avatars to contact list example.

import Qt 4.7

Item {
    height: 300
    width: 400

    Component {
        id: contactsDelegate
        Rectangle {
            border.width: 1
            border.color: "black"
            width: parent.width - 4
            anchors.horizontalCenter: parent.horizontalCenter
            height: childrenRect.height
            Image {
                id: avatar
                anchors.left: parent.left
                anchors.margins: 10
                height: 30
                width: 30
                source: { console.log("avatar: " + model.avatar); model.avatar }
            }
            Text {
                id: aliasName
                anchors.left: avatar.right
                // anchors.verticalCenter: parent.verticalCenter
                anchors.margins: 10
                text: model.aliasName
            }
            Text {
                id: presenceMessage
                anchors.left: aliasName.right
                // anchors.verticalCenter: parent.verticalCenter
                anchors.margins: 10
                text: " - " + model.presenceMessage
            }
            Text {
                id: status
                anchors.left: presenceMessage.right
                text: " - " + model.presenceStatus
            }

        }
    }

    ListView {
        id: contactsList
        anchors.fill: parent

        model: contactsListModel
        delegate: contactsDelegate
    }
}


import QtQuick 2.8
import QtQuick.XmlListModel 2.0

BaseXml {
    query: "/MPL/Item"
    mcwsFields: "name,artist,album,genre"

    onHostUrlChanged: source = ""

    function loadPlayingNow(zoneid)
    {
        load("Playback/Playlist?Fields=" + mcwsFields + "&Zone=" + zoneid)
    }

    function loadSearch(search)
    {
        load("Files/Search?Fields=" + mcwsFields + "&Shuffle=1&query=" + search)
    }

    // Filekey (mcws: Key) will always be the first field returned
    XmlRole { name: "filekey";  query: "Field[1]/string()" }

}

Fix regression with the model refactor

import QtQuick 2.8
import QtQuick.XmlListModel 2.0

BaseXml {
    query: "/MPL/Item"
    mcwsFields: "name,artist,album,genre"

    onHostUrlChanged: source = ""

    function loadPlayingNow(zoneid)
    {
        source = ""
        load("Playback/Playlist?Fields=" + mcwsFields + "&Zone=" + zoneid)
    }

    function loadSearch(search)
    {
        source = ""
        load("Files/Search?Fields=" + mcwsFields + "&Shuffle=1&query=" + search)
    }

    // Filekey (mcws: Key) will always be the first field returned
    XmlRole { name: "filekey";  query: "Field[1]/string()" }

}


import QtQuick 1.1
import org.kde.people 0.1

ListView {
    width: 100
    height: 100

    model: PersonsModel {}
    delegate: Text { text: display }
}

Make sweet people to puke all the PersonsModel data

import QtQuick 1.1
import org.kde.people 0.1
import org.kde.plasma.components 0.1
import org.kde.plasma.extras 0.1

Rectangle {
    width: 100
    height: 100
    color: "red"

    ListView {
        id: view
        anchors {
            top: parent.top
            bottom: parent.bottom
            left: parent.left
        }
        width: parent.width/2

        model: PersonsModel {}
        delegate:   ListItem {
                        Label {
                            anchors.fill: parent
                            elide: Text.ElideRight
                            text: display
                        }
                        enabled: true
                        onClicked: contactItem.contactData = model
                    }
    }

    Item {
        id: contactItem
        anchors {
            top: parent.top
            right: parent.right
            bottom: parent.bottom
        }
        width: parent.width/2
        property variant contactData
        onContactDataChanged: {
            var text = ""
            for(var a in contactData)
                text += a + ": " + contactData[a]+'\n'
            contactText.text = text
            console.log("contact selected:", text)
        }

        Label {
            id: contactText
            anchors.fill: parent
            text: "select a contact"
        }
    }
}


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

import QtQuick 2.2
import QtQuick.Window 2.2
import QtQuick.Controls 1.2

import UM 1.0 as UM

UM.Dialog
{
    id: base;

    width: 500 * Screen.devicePixelRatio;
    height: 100 * Screen.devicePixelRatio;

    visible: true;
    modality: Qt.ApplicationModal;

    Column
    {
        anchors.fill: parent;

        Text
        {
            anchors {
                left: parent.left;
                right: parent.right;
            }

            text: {
                if (manager.progress == 0)
                {
                    //: Firmware update status label
                    return qsTr("Starting firmware update, this may take a while.")
                }
                else if (manager.progress > 99)
                {
                    //: Firmware update status label
                    return qsTr("Firmware update completed.")
                }
                else
                {
                    //: Firmware update status label
                    return qsTr("Updating firmware.")
                }
            }

            wrapMode: Text.Wrap;
        }

        ProgressBar
        {
            id: prog;
            value: manager.progress
            minimumValue: 0;
            maximumValue: 100;
            anchors {
                left: parent.left;
                right: parent.right;
            }

        }

        SystemPalette {
           id: palette;
        }
    }

    rightButtons: Button {
        text: qsTr("Close");

        enabled: true;
    }
}

Remove the close button since it does not work

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

import QtQuick 2.2
import QtQuick.Window 2.2
import QtQuick.Controls 1.2

import UM 1.0 as UM

UM.Dialog
{
    id: base;

    width: 500 * Screen.devicePixelRatio;
    height: 100 * Screen.devicePixelRatio;

    visible: true;
    modality: Qt.ApplicationModal;

    Column
    {
        anchors.fill: parent;

        Text
        {
            anchors {
                left: parent.left;
                right: parent.right;
            }

            text: {
                if (manager.progress == 0)
                {
                    //: Firmware update status label
                    return qsTr("Starting firmware update, this may take a while.")
                }
                else if (manager.progress > 99)
                {
                    //: Firmware update status label
                    return qsTr("Firmware update completed.")
                }
                else
                {
                    //: Firmware update status label
                    return qsTr("Updating firmware.")
                }
            }

            wrapMode: Text.Wrap;
        }

        ProgressBar
        {
            id: prog;
            value: manager.progress
            minimumValue: 0;
            maximumValue: 100;
            anchors {
                left: parent.left;
                right: parent.right;
            }

        }

        SystemPalette {
           id: palette;
        }
    }
}


import qbs

import cutehmi

import "Test.qbs" as Test

Project {
	Test {
		testName: "logging"

		files: [
			"test_logging.cpp",
		]
	}

	Test {
		testName: "Address"

		files: [
			"test_Address.cpp",
		]
	}
}

//(c)MP: Copyright © 2019, 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/.

Modify names of test products.

import qbs

import cutehmi

import "Test.qbs" as Test

Project {
	Test {
		testName: "test_logging"

		files: [
			"test_logging.cpp",
		]
	}

	Test {
		testName: "test_Address"

		files: [
			"test_Address.cpp",
		]
	}
}

//(c)MP: Copyright © 2019, 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/.


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

import QtQuick 2.1

MouseArea
{
    id: base

    hoverEnabled: true;

    property alias color: image.color;
    property alias backgroundColor: background.color;
    property alias iconSource: image.source;

    property alias hovered: base.containsMouse;

    Rectangle {
        id: background;
        anchors.fill: parent;
        color: "transparent";
    }

    RecolorImage {
        id: image;

        anchors.fill: parent;

        sourceSize.width: width
        sourceSize.height: width

        color: "black";

        visible: source != "";
    }
}

Add hoverColor/hoverBackgroundColor to simplify hover state handling everywhere else

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

import QtQuick 2.1

MouseArea
{
    id: base

    hoverEnabled: true;

    property color color: "black";
    property color hoverColor: color;
    property color backgroundColor: "transparent";
    property color hoverBackgroundColor: backgroundColor;
    property alias iconSource: image.source;

    property alias hovered: base.containsMouse;

    Rectangle {
        id: background;
        anchors.fill: parent;
        color: base.containsMouse ? base.hoverBackgroundColor : base.backgroundColor;
    }

    RecolorImage {
        id: image;

        anchors.fill: parent;

        sourceSize.width: width
        sourceSize.height: width

        color: base.containsMouse ? base.hoverColor : base.color;

        visible: source != "";
    }
}


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

import UM 1.0 as UM

PreferencesPage {
    //: General configuration page title
    title: qsTr("General");

    GridLayout {
        columns: 2;

        //: Language selection label
        Label { text: qsTr("Language"); }
        ComboBox {
            model: ListModel {
                ListElement { text: 'English'; code: 'en' }
                ListElement { text: 'x-test'; code: 'x-test' }
            }

            currentIndex: {
                var code = UM.Preferences.getValue('general/language')
                for(i in model.count) {
                    if(model.get(i).code == code) {
                        return i;
                    }
                }
            }
            onCurrentIndexChanged: UM.Preferences.setValue('general/language', model.get(currentIndex).code)
        }

        Label {
            Layout.columnSpan: 2;
            //: Language change warning
            text: qsTr("You will need to restart the application for language changes to have effect.")

            font.italic: true;
        }

        Item { Layout.fillHeight: true; Layout.columnSpan: 2 }
    }
}

Implement reset() for General preferences page

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

import UM 1.0 as UM

PreferencesPage {
    //: General configuration page title
    title: qsTr("General");

    function reset() {
        UM.Preferences.resetPreference('general/language')
    }

    GridLayout {
        columns: 2;

        //: Language selection label
        Label { text: qsTr("Language"); }
        ComboBox {
            model: ListModel {
                ListElement { text: 'English'; code: 'en' }
                ListElement { text: 'x-test'; code: 'x-test' }
            }

            currentIndex: {
                var code = UM.Preferences.getValue('general/language')
                for(i in model.count) {
                    if(model.get(i).code == code) {
                        return i;
                    }
                }
            }
            onCurrentIndexChanged: UM.Preferences.setValue('general/language', model.get(currentIndex).code)
        }

        Label {
            Layout.columnSpan: 2;
            //: Language change warning
            text: qsTr("You will need to restart the application for language changes to have effect.")

            font.italic: true;
        }

        Item { Layout.fillHeight: true; Layout.columnSpan: 2 }
    }
}


BaseActivity {
	start: {
		this.style('display', 'block')
		this.visible = true
		this.started()
	}

	stop: {
		this.style('display', 'none')
		this.visible = false
		this.stopped()
	}

	function getActivity() {
		return this
	}
}

Add flag to handle 'display' style

BaseActivity {
	property bool handleDisplay;

	start: {
		if (this.handleDisplay)
			this.style('display', 'block')
		this.visible = true
		this.started()
	}

	stop: {
		if (this.handleDisplay)
			this.style('display', 'none')
		this.visible = false
		this.stopped()
	}

	function getActivity() {
		return this
	}
}


import Qt 4.7
import "qmlproject01"
import "qmlproject02"

Rectangle {
    width: 200
    height: 200
    color: "#ddddff"

    Text {
        id: title
        text: "main"
    }

    Column {
        anchors.fill: parent
        anchors.margins: title.height + 2

        QmlProject01 {
            anchors.top: parent.top
            height: parent.height / 2
            width: parent.width
        }

        QmlProject02 {
            anchors.bottom: parent.bottom
            height: parent.height / 2
            width: parent.width
        }
    }
}

Remove incorrect (and unneeded) anchoring

import Qt 4.7
import "qmlproject01"
import "qmlproject02"

Rectangle {
    width: 200
    height: 200
    color: "#ddddff"

    Text {
        id: title
        text: "main"
    }

    Column {
        anchors.fill: parent
        anchors.margins: title.height + 2

        QmlProject01 {
            height: parent.height / 2
            width: parent.width
        }

        QmlProject02 {
            height: parent.height / 2
            width: parent.width
        }
    }
}


Project {
	qbsSearchPaths: ["qbs"]

	SubProject {
		filePath: "modules/modules.qbs"
	}

	SubProject {
		filePath: "tools/tools.qbs"
	}

	SubProject {
		filePath: "QML/QML.qbs"
	}

	SubProject {
		filePath: "examples/examples.qbs"
	}
}

Add `buildTests` property and `AutotestRunner` item.

import qbs

Project {
	property bool buildTests: false

	qbsSearchPaths: ["qbs"]

	references: [
		"modules/modules.qbs",
		"tools/tools.qbs",
		"QML/QML.qbs",
		"examples/examples.qbs"
	]

	AutotestRunner {
		environment: {
			var env = base;
			env.push("QML2_IMPORT_PATH=" + qbs.installRoot + "/" + cutehmi.dirs.qmlExtensionInstallDirname);

			env.push("QBS_INSTALL_ROOT=" + qbs.installRoot);

			if (qbs.hostOS.contains("windows") && qbs.targetOS.contains("windows")) {
				var path = "";
				for (var i = 0; i < env.length; ++i) {
					if (env[i].startsWith("PATH=")) {
						path = env[i].substring(5);
						break;
					}
				}
				path = Qt.core.binPath + ";" + path;
				var arrayElem = "PATH=" + path;
				if (i < env.length)
					env[i] = arrayElem;
				else
					env.push(arrayElem);
			}

			if (qbs.hostOS.contains("darwin") && qbs.targetOS.contains("darwin")) {
				env.push("DYLD_FRAMEWORK_PATH=" + Qt.core.libPath);
				env.push("DYLD_LIBRARY_PATH=" + Qt.core.libPath);
			}

			return env;
		}

		Depends { name: "Qt.core" }

		Depends { name: "cutehmi.dirs" }
	}
}


import QtQuick 2.0
import QtQuick.LocalStorage 2.0 as Sql

Item {
    property var db

    Component.onCompleted: {
        db = Sql.LocalStorage.openDatabaseSync("Hangee", "1.0",
                                               "Database for Hangee", 100000)
        db.transaction(function (tx) {
            var query = "CREATE TABLE IF NOT EXISTS Position(AppID TEXT, DesktopID INTEGER, PositionID INTEGER)"
            tx.executeSql(query)
        })
    }

    function appInfo(AppID, DesktopID, PositionID) {
        this.AppID = AppID
        this.DesktopID = DesktopID
        this.PositionID = PositionID
    }

    function insert(AppID, DesktopID, PositionID) {
        db.transaction(function (tx) {
            var query = "INSERT INTO Position VALUES(?, ?, ?)"
            tx.executeSql(query, [AppID, DesktopID, PositionID])
        })
    }

    function select(AppID) {
        var jsondata
        db.transaction(function (tx) {
            var rs = tx.executeSql("SELECT * FROM Position WHERE AppID = ?",
                                   [AppID])

            for (var i = 0; i < rs.rows.length; i++) {
                jsondata = "{\"AppID\":\"" + rs.rows.item(
                            i).AppID + "\", \"DesktopID\":\"" + rs.rows.item(
                            i).DesktopID + "\", \"PositionID\":\"" + rs.rows.item(
                            i).PositionID + "\"}"
            }
        })
        return jsondata
    }
}

Remove the unnecessary AppInfo function

import QtQuick 2.0
import QtQuick.LocalStorage 2.0 as Sql

Item {
    property var db

    Component.onCompleted: {
        db = Sql.LocalStorage.openDatabaseSync("Hangee", "1.0",
                                               "Database for Hangee", 100000)
        db.transaction(function (tx) {
            var query = "CREATE TABLE IF NOT EXISTS Position(AppID TEXT, DesktopID INTEGER, PositionID INTEGER)"
            tx.executeSql(query)
        })
    }

    function insert(AppID, DesktopID, PositionID) {
        db.transaction(function (tx) {
            var query = "INSERT INTO Position VALUES(?, ?, ?)"
            tx.executeSql(query, [AppID, DesktopID, PositionID])
        })
    }

    function select(AppID) {
        var jsondata
        db.transaction(function (tx) {
            var rs = tx.executeSql("SELECT * FROM Position WHERE AppID = ?",
                                   [AppID])

            for (var i = 0; i < rs.rows.length; i++) {
                jsondata = "{\"AppID\":\"" + rs.rows.item(
                            i).AppID + "\", \"DesktopID\":\"" + rs.rows.item(
                            i).DesktopID + "\", \"PositionID\":\"" + rs.rows.item(
                            i).PositionID + "\"}"
            }
        })
        return jsondata
    }
}


Item {
	property color color: "#000";

	property Border border: Border {}
	property Gradient gradient;

	function _mapCSSAttribute(name) {
		var attr = {color: 'background-color'}[name]
		return (attr !== undefined)?
			attr:
			qml.core.Item.prototype._mapCSSAttribute.apply(this, arguments)
	}

	function _update(name, value) {
		switch(name) {
			case 'color': this.style('background-color', qml.core.normalizeColor(value)); break;
			case 'gradient': {
				if (value) {
					var decl = value._getDeclaration()
					this.style({ 'background-color': '', 'background': 'linear-gradient(to ' + decl + ')' })
				} else {
					this.style('background', '')
					this._update('color', qml.core.normalizeColor(this.color)) //restore color
				}
				break;
			}
		}
		qml.core.Item.prototype._update.apply(this, arguments);
	}

}

Change default rectangle's color value.

Item {
	property color color: "#0000";

	property Border border: Border {}
	property Gradient gradient;

	function _mapCSSAttribute(name) {
		var attr = {color: 'background-color'}[name]
		return (attr !== undefined)?
			attr:
			qml.core.Item.prototype._mapCSSAttribute.apply(this, arguments)
	}

	function _update(name, value) {
		switch(name) {
			case 'color': this.style('background-color', qml.core.normalizeColor(value)); break;
			case 'gradient': {
				if (value) {
					var decl = value._getDeclaration()
					this.style({ 'background-color': '', 'background': 'linear-gradient(to ' + decl + ')' })
				} else {
					this.style('background', '')
					this._update('color', qml.core.normalizeColor(this.color)) //restore color
				}
				break;
			}
		}
		qml.core.Item.prototype._update.apply(this, arguments);
	}

}


import QtQuick 2.12
import QtQuick.Controls 2.2
import org.kde.kirigami 2.12 as Kirigami

Item {
    id: root
    implicitWidth: img.width
    implicitHeight: img.height

    property alias color: shadowRectangle.color
    property alias radius: shadowRectangle.radius
    property alias shadow: shadowRectangle.shadow
    property alias border: shadowRectangle.border
    property alias corners: shadowRectangle.corners

    property alias animateLoad: img.animateLoad
    property alias sourceKey: img.sourceKey
    property alias source: img.source
    property alias opacityTo: img.opacityTo
    property alias sourceSize: img.sourceSize
    property alias fillMode: img.fillMode
    property alias duration: img.duration
    property alias cache: img.cache
    property alias mipmap: img.mipmap
    property alias thumbnail: img.thumbnail

    signal statusChanged()
    signal imageError()

    TrackImage {
        id: img
        onStatusChanged: {
            if (img.status === Image.Error)
                root.imageError()
            root.statusChanged()
        }

        onAnimationStart: shadowRectangle.source = null
        onAnimationEnd: shadowRectangle.source = img
    }

    Kirigami.ShadowedTexture {
        id: shadowRectangle
        anchors.fill: parent
        source: img
        radius: 2
        color: 'transparent'
        shadow.xOffset: 1
        shadow.yOffset: 3
        shadow.color: Qt.rgba(0, 0, 0, 0.6)
        shadow.size: Kirigami.Units.largeSpacing

     }
}

Use the shadow texture properly

import QtQuick 2.12
import QtQuick.Controls 2.2
import org.kde.kirigami 2.12 as Kirigami

Item {
    id: root
    implicitWidth: img.width
    implicitHeight: img.height

    property alias color: shadowRectangle.color
    property alias radius: shadowRectangle.radius
    property alias shadow: shadowRectangle.shadow
    property alias border: shadowRectangle.border
    property alias corners: shadowRectangle.corners

    property alias animateLoad: img.animateLoad
    property alias sourceKey: img.sourceKey
    property alias source: img.source
    property alias opacityTo: img.opacityTo
    property alias sourceSize: img.sourceSize
    property alias fillMode: img.fillMode
    property alias duration: img.duration
    property alias cache: img.cache
    property alias mipmap: img.mipmap
    property alias thumbnail: img.thumbnail

    signal statusChanged()
    signal imageError()

    TrackImage {
        id: img
        onStatusChanged: {
            if (img.status === Image.Error)
                root.imageError()
            root.statusChanged()
        }
    }

    Kirigami.ShadowedTexture {
        id: shadowRectangle
        anchors.fill: parent
        radius: 2
        color: 'transparent'
        shadow.xOffset: 1
        shadow.yOffset: 3
        shadow.color: Qt.rgba(0, 0, 0, 0.6)
        shadow.size: Kirigami.Units.largeSpacing
     }
}


// -*- qml -*-
import QtQuick 1.1
import com.nokia.meego 1.1
import QtCamera 1.0

CameraPage {
        id: page

        controlsVisible: recording.visible

        orientationLock: PageOrientation.LockLandscape

        Button {
                id: recording
                anchors.right: parent.right
                anchors.rightMargin: 20
                anchors.verticalCenter: parent.verticalCenter
                iconSource: "/usr/share/themes/blanco/meegotouch/icons/icon-m-camera-video-record.png"
                width: 75
                height: 75
                opacity: 0.5
                onClicked: {
                        if (!videoMode.recording) {
                                videoMode.startRecording("/home/developer/foo.mp4");
                        }
                        else {
                                videoMode.stopRecording();
                        }
                }

                visible: (videoMode.recording || videoMode.canCapture) && !cameraMode.animationRunning && !previewAnimationRunning
        }

        VideoMode {
                id: videoMode
                camera: cam
                onPreviewAvailable: page.setPreview(preview);
        }

        VideoTorchButton {
                id: torch
                visible: controlsVisible
                anchors.top: parent.top
                anchors.left: parent.left
                anchors.topMargin: 20
                anchors.leftMargin: 20
        }

        VideoSceneButton {
                id: scene
                visible: controlsVisible
                anchors.top: torch.bottom
                anchors.left: parent.left
                anchors.topMargin: 10
                anchors.leftMargin: 20
        }
}

Set the opacity for the torch button to 0.5

// -*- qml -*-
import QtQuick 1.1
import com.nokia.meego 1.1
import QtCamera 1.0

CameraPage {
        id: page

        controlsVisible: recording.visible

        orientationLock: PageOrientation.LockLandscape

        Button {
                id: recording
                anchors.right: parent.right
                anchors.rightMargin: 20
                anchors.verticalCenter: parent.verticalCenter
                iconSource: "/usr/share/themes/blanco/meegotouch/icons/icon-m-camera-video-record.png"
                width: 75
                height: 75
                opacity: 0.5
                onClicked: {
                        if (!videoMode.recording) {
                                videoMode.startRecording("/home/developer/foo.mp4");
                        }
                        else {
                                videoMode.stopRecording();
                        }
                }

                visible: (videoMode.recording || videoMode.canCapture) && !cameraMode.animationRunning && !previewAnimationRunning
        }

        VideoMode {
                id: videoMode
                camera: cam
                onPreviewAvailable: page.setPreview(preview);
        }

        VideoTorchButton {
                id: torch
                visible: controlsVisible
                anchors.top: parent.top
                anchors.left: parent.left
                anchors.topMargin: 20
                anchors.leftMargin: 20
                opacity: 0.5
        }

        VideoSceneButton {
                id: scene
                visible: controlsVisible
                anchors.top: torch.bottom
                anchors.left: parent.left
                anchors.topMargin: 10
                anchors.leftMargin: 20
        }
}


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
                    }
                }
            }
        }
    }
}

Move properties, models, event handlers to top

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

Page {
    id: channelListPage

    ListModel {
        id: channelModel
    }

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

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

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

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

        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
                    }
                }
            }
        }
    }
}


/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Dmitry Rozhkov <dmitry.rozhkov@jollamobile.com>
**
****************************************************************************/

import QtQuick 1.1
import Sailfish.Silica 1.0

Rectangle {
    id: notification

    anchors.centerIn: parent
    width: notificationLabel.width + (2 * theme.paddingMedium)
    height: theme.itemSizeMedium
    color: theme.highlightBackgroundColor
    opacity: notificationTimer.running ? 1.0 : 0.0
    Behavior on opacity { FadeAnimation {} }

    function show(text) {
        notificationLabel.text = text
        notificationTimer.restart()
    }

    Label {
        id: notificationLabel

        anchors.centerIn: parent
        color: theme.primaryColor
    }

    Timer {
        id: notificationTimer
        interval: 2000
    }
}

Move info banner to top

/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Dmitry Rozhkov <dmitry.rozhkov@jollamobile.com>
**
****************************************************************************/

import QtQuick 1.1
import Sailfish.Silica 1.0

Rectangle {
    id: notification

    anchors.horizontalCenter: parent.horizontalCenter
    anchors.top: parent.top
    width: parent.width
    height: theme.itemSizeSmall
    color: theme.highlightBackgroundColor
    opacity: notificationTimer.running ? 1.0 : 0.0
    Behavior on opacity { FadeAnimation {} }

    function show(text) {
        notificationLabel.text = text
        notificationTimer.restart()
    }

    Label {
        id: notificationLabel

        anchors.centerIn: parent
        color: theme.primaryColor
    }

    Timer {
        id: notificationTimer
        interval: 2000
    }
}


// [WriteFile Name=Unique_Value_Renderer, Category=DisplayInformation]
// [Legal]
// Copyright 2016 Esri.

// 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.
// [Legal]

import QtQuick 2.3
import QtQuick.Controls 1.2
import Esri.Samples 1.0
import Esri.ArcGISExtras 1.1

Unique_Value_RendererSample {
    clip: true
    width: 800
    height: 600

    property real scaleFactor: System.displayScaleFactor

    // add a mapView component
    MapView {
        anchors.fill: parent
        objectName: "mapView"
    }

    // neatline rectangle
    Rectangle {
        anchors.fill: parent
        color: "transparent"
        border {
            width: 0.5 * scaleFactor
            color: "black"
        }
    }
}

Correct import values for UniqueValueRenderer Sample

// [WriteFile Name=Unique_Value_Renderer, Category=DisplayInformation]
// [Legal]
// Copyright 2016 Esri.

// 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.
// [Legal]

import QtQuick 2.6
import QtQuick.Controls 1.4
import Esri.Samples 1.0
import Esri.ArcGISExtras 1.1

Unique_Value_RendererSample {
    clip: true
    width: 800
    height: 600

    property real scaleFactor: System.displayScaleFactor

    // add a mapView component
    MapView {
        anchors.fill: parent
        objectName: "mapView"
    }

    // neatline rectangle
    Rectangle {
        anchors.fill: parent
        color: "transparent"
        border {
            width: 0.5 * scaleFactor
            color: "black"
        }
    }
}


import qbs.base 1.0

Project {
    property string app_target: "qio"

    property string install_app_path: "bin"
    property string lib_suffix: ""

    property string install_binary_path: {
        return install_app_path
    }

    property string install_library_path: {
        if (qbs.targetOS.contains("osx"))
            return "lib/" + app_target
        else if (qbs.targetOS.contains("windows"))
            return install_app_path
        else
            return "lib" + lib_suffix + "/" + app_target
    }

    property string install_plugin_path: {
        return install_library_path + "/plugins"
    }

    property stringList includePaths: {
        return [ path + "/include" ]
    }

    property stringList libraryPaths: {
        return []
    }

    property stringList cxxFlags: {
        if (qbs.targetOS.contains("osx"))
            return [ "-std=c++0x", "-stdlib=libc++" ]
        if (qbs.targetOS.contains("linux"))
            return [ "-std=c++0x", "-Werror" ]
        else
            return []
    }

    property stringList linkerFlags: {
        if (qbs.targetOS.contains("osx"))
            return [ "-stdlib=libc++" ]
        else
            return []
    }

    name: "QIO"

    SubProject {
        filePath: "examples/examples.qbs"
    }
    SubProject {
        filePath: "src/src.qbs"
    }
}

Move plugins to specified subfolder

import qbs.base 1.0

Project {
    property string app_target: "qio"

    property string install_app_path: "bin"
    property string lib_suffix: ""

    property string install_binary_path: {
        return install_app_path
    }

    property string install_library_path: {
        if (qbs.targetOS.contains("osx"))
            return "lib/" + app_target
        else if (qbs.targetOS.contains("windows"))
            return install_app_path
        else
            return "lib" + lib_suffix + "/" + app_target
    }

    property string install_plugin_path: {
        return install_library_path + "/plugins/filesystems"
    }

    property stringList includePaths: {
        return [ path + "/include" ]
    }

    property stringList libraryPaths: {
        return []
    }

    property stringList cxxFlags: {
        if (qbs.targetOS.contains("osx"))
            return [ "-std=c++0x", "-stdlib=libc++" ]
        if (qbs.targetOS.contains("linux"))
            return [ "-std=c++0x", "-Werror" ]
        else
            return []
    }

    property stringList linkerFlags: {
        if (qbs.targetOS.contains("osx"))
            return [ "-stdlib=libc++" ]
        else
            return []
    }

    name: "QIO"

    SubProject {
        filePath: "examples/examples.qbs"
    }
    SubProject {
        filePath: "src/src.qbs"
    }
}


import QtQuick 2.9

Item {
    property alias items: lm
    property string configKey: ''
    property string outputStr: ''

    function setEnabled(index, val) {
        lm.setProperty(index, 'enabled', val)
        lm.save()
    }

    BaseListModel {
        id: lm

        onRowsMoved: save()
        onRowsRemoved: save()

        function save() {
            event.queueCall(100, function() {
                var arr = []
                for (var i=0; i<count; ++i)
                    arr.push(get(i))
                outputStr = JSON.stringify(arr)
            })
        }

        function load() {
            lm.rowsInserted.disconnect(lm.save)
            JSON.parse(plasmoid.configuration[configKey]).forEach(function(obj) {
                lm.append(obj)
            })
            lm.rowsInserted.connect(lm.save)
        }

        Component.onCompleted: event.queueCall(0, load)
    }
    SingleShot {
        id: event
    }
}

Support an object defn; add props from defn if not in loaded object (allows forward compatibility with configured objects)

import QtQuick 2.9

Item {
    property alias items: lm
    property string configKey: ''
    property string outputStr: ''
    property var objectDef: []

    function setEnabled(index, val) {
        lm.setProperty(index, 'enabled', val)
        lm.save()
    }

    BaseListModel {
        id: lm

        onRowsMoved: save()
        onRowsRemoved: save()

        function save() {
            event.queueCall(100, function() {
                var arr = []
                for (var i=0; i<count; ++i)
                    arr.push(get(i))
                outputStr = JSON.stringify(arr)
            })
        }

        function load() {
            lm.rowsInserted.disconnect(lm.save)
            JSON.parse(plasmoid.configuration[configKey]).forEach(function(obj) {
                objectDef.forEach(function(prop) {
                    if (!obj.hasOwnProperty(prop))
                        obj[prop] = ''
                })
                lm.append(obj)
            })
            lm.rowsInserted.connect(lm.save)
        }

        Component.onCompleted: event.queueCall(0, load)
    }

    SingleShot { id: event }
}


import QtQuick 2.4
import QtQuick.Controls 1.3

Control {
    id: root

    padding: 10

    background: Rectangle {
        color: "#F5F5F5"
    }

    function updateImplicitSize() {
        if (contentItem.children.length == 1) {
            implicitWidth = contentItem.children[0].implicitWidth + leftPadding + rightPadding;
            implicitHeight = contentItem.children[0].implicitHeight + topPadding + bottomPadding;
        }
    }

    Component.onCompleted: {
        root.contentItem.onChildrenChanged.connect(childrenChanged);
        updateImplicitSize();
    }
}

Fix automatic updating of implicitHeight and implicitWidth

import QtQuick 2.4
import QtQuick.Controls 1.3

Control {
    id: root

    padding: 10

    background: Rectangle {
        color: "#F5F5F5"
    }

    /**
    *  Implements the following specification:
    *  If only a single item is used within a Pane, it will resize to fit the implicit size of its contained item.
    */
    function updateImplicitSize() {
        if (contentItem.children.length == 1) {
            implicitWidth = Qt.binding(function() { return contentItem.children[0].implicitWidth + leftPadding + rightPadding });
            implicitHeight = Qt.binding(function() { return contentItem.children[0].implicitHeight + topPadding + bottomPadding });
        }
    }

    Component.onCompleted: {
        root.contentItem.onChildrenChanged.connect(childrenChanged);
        updateImplicitSize();
    }
}


/****************************************************************************
**
** Copyright (C) 2014 Alexander Rössler
** License: LGPL version 2.1
**
** This file is part of QtQuickVcp.
**
** All rights reserved. This program and the accompanying materials
** are made available under the terms of the GNU Lesser General Public License
** (LGPL) version 2.1 which accompanies this distribution, and is available at
** http://www.gnu.org/licenses/lgpl-2.1.html
**
** This library 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.
**
** Contributors:
** Alexander Rössler @ The Cool Tool GmbH <mail DOT aroessler AT gmail DOT com>
**
****************************************************************************/
import QtQuick 2.0
import QtQuick.Controls 1.1
import Machinekit.Application 1.0
import Machinekit.Application.Controls 1.0
import Machinekit.Service 1.0

ApplicationWindow {
    id: applicationWindow

    visibility: (Qt.platform.os == "android") ? "FullScreen" : "AutomaticVisibility"
    visible: true
    width: 600
    height: 950 // Tablet screen height will be 1024
    title: connectionWindow.title
    toolBar: connectionWindow.toolBar
    statusBar: connectionWindow.statusBar
    menuBar: connectionWindow.menuBar

    Init {
        id: connectionWindow
        anchors.fill: parent
    }
}

Remove hard coded windows size

/****************************************************************************
**
** Copyright (C) 2014 Alexander Rössler
** License: LGPL version 2.1
**
** This file is part of QtQuickVcp.
**
** All rights reserved. This program and the accompanying materials
** are made available under the terms of the GNU Lesser General Public License
** (LGPL) version 2.1 which accompanies this distribution, and is available at
** http://www.gnu.org/licenses/lgpl-2.1.html
**
** This library 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.
**
** Contributors:
** Alexander Rössler @ The Cool Tool GmbH <mail DOT aroessler AT gmail DOT com>
**
****************************************************************************/
import QtQuick 2.0
import QtQuick.Controls 1.1
import Machinekit.Application 1.0
import Machinekit.Application.Controls 1.0
import Machinekit.Service 1.0

ApplicationWindow {
    id: applicationWindow

    visibility: (Qt.platform.os == "android") ? "FullScreen" : "AutomaticVisibility"
    visible: true

    title: connectionWindow.title
    toolBar: connectionWindow.toolBar
    statusBar: connectionWindow.statusBar
    menuBar: connectionWindow.menuBar

    Init {
        id: connectionWindow
        anchors.fill: parent
    }
}


import qbs
import QbsFunctions

Product {
    Depends { name: "Qt.core" }
    property string minimumQtVersion: "5.1.0"
    cpp.defines: {
        var res = ["QT_NO_CAST_FROM_ASCII", "QT_NO_PROCESS_COMBINED_ARGUMENT_START"];
        if (qbs.toolchain.contains("msvc"))
            res.push("_SCL_SECURE_NO_WARNINGS");
        return res;
    }
    condition: QbsFunctions.versionIsAtLeast(Qt.core.version, minimumQtVersion)
}

Enable exceptions in qbs project

import qbs
import QbsFunctions

Product {
    Depends { name: "Qt.core" }
    property string minimumQtVersion: "5.1.0"
    cpp.defines: {
        var res = ["QT_NO_CAST_FROM_ASCII", "QT_NO_PROCESS_COMBINED_ARGUMENT_START"];
        if (qbs.toolchain.contains("msvc"))
            res.push("_SCL_SECURE_NO_WARNINGS");
        return res;
    }
    cpp.enableExceptions: true
    condition: QbsFunctions.versionIsAtLeast(Qt.core.version, minimumQtVersion)
}


// Copyright (c) 2015 Ultimaker B.V.
// Cura 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.1 as UM

UM.Dialog
{
    id: base
    minimumWidth: 400 * Screen.devicePixelRatio
    minimumHeight: 300 * Screen.devicePixelRatio
    width: minimumWidth
    height: minimumHeight
    title: catalog.i18nc("@label", "Changelog")

    ScrollView
    {
        width: parent.width
        height: parent.height - 25
        Label
        {
            text: manager.getChangeLogString()
            width:base.width - 35
            wrapMode: Text.Wrap;
        }
    }
    Button
    {
        UM.I18nCatalog
        {
            id: catalog
            name: "cura"
        }
        anchors.bottom:parent.bottom
        text: catalog.i18nc("@action:button", "Close")
        onClicked: base.hide()
        anchors.horizontalCenter: parent.horizontalCenter
    }
}

Clean up styling of Changelog dialog

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

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

import UM 1.1 as UM

UM.Dialog
{
    id: base
    minimumWidth: UM.Theme.getSize("modal_window_minimum").width * 0.75
    minimumHeight: UM.Theme.getSize("modal_window_minimum").height * 0.75
    width: minimumWidth
    height: minimumHeight
    title: catalog.i18nc("@label", "Changelog")

    TextArea
    {
        anchors.fill: parent
        text: manager.getChangeLogString()
        readOnly: true;
        textFormat: TextEdit.RichText
    }

    rightButtons: [
        Button
        {
            UM.I18nCatalog
            {
                id: catalog
                name: "cura"
            }

            text: catalog.i18nc("@action:button", "Close")
            onClicked: base.hide()
        }
    ]
}


import QtQuick 2.1
import QtQuick.Controls 1.3

import org.kde.kcm 1.0
import org.kde.plasma.core 2.0 as PlasmaCore

import org.kde.plasma.private.volume 0.1

TabView {
    implicitWidth: units.gridUnit * 20
    implicitHeight: units.gridUnit * 20

    ConfigModule.quickHelp: "((UNKNOWN))"

    Tab {
        title: i18nc("@title:tab", "Applications")
        StreamView {
            model: SinkInputModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Recording")
        StreamView {
            model: SourceOutputModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Output Devices")
        DeviceView {
            model: SinkModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Input Devices")
        DeviceView {
            model: SourceModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Configuration")
        CardView {
            model: CardModel {}
        }
    }
}

Move Output and Input devices before Applications and Recording. When no applications play/record audio, they are greeted with blank page.

import QtQuick 2.1
import QtQuick.Controls 1.3

import org.kde.kcm 1.0
import org.kde.plasma.core 2.0 as PlasmaCore

import org.kde.plasma.private.volume 0.1

TabView {
    implicitWidth: units.gridUnit * 20
    implicitHeight: units.gridUnit * 20

    ConfigModule.quickHelp: "((UNKNOWN))"
    Tab {
        title: i18nc("@title:tab", "Output Devices")
        DeviceView {
            model: SinkModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Input Devices")
        DeviceView {
            model: SourceModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Applications")
        StreamView {
            model: SinkInputModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Recording")
        StreamView {
            model: SourceOutputModel {}
        }
    }
    Tab {
        title: i18nc("@title:tab", "Configuration")
        CardView {
            model: CardModel {}
        }
    }
}


Implement 'shaka-player' - first iteration.

///Video paly er based on shaka-player
Item {
	signal error;		///< error occured signal
	signal finished;	///< video finished signal
	property string	source;	///< video source URL
	property Color	backgroundColor: "#000";	///< default background color
	property float	volume: 1.0;		///< video volume value [0:1]
	property bool	loop: false;		///< video loop flag
	property bool	ready: false;		///< read only property becomes 'true' when video is ready to play, 'false' otherwise
	property bool	muted: false;		///< volume mute flag
	property bool	paused: false;		///< video paused flag
	property bool	waiting: false;		///< wating flag while video is seeking and not ready to continue playing
	property bool	seeking: false;		///< seeking flag
	property bool	autoPlay: false;	///< play video immediately after source changed
	property int	duration;			///< content duration in seconds (valid only for not live videos)
	property int	progress;			///< current playback progress in seconds
	property int	buffered;			///< buffered contetnt in seconds

	///@private
	function getTag() { return 'video' }

	///@private
	constructor: {
		var shaka = window.shaka
		if (!shaka) {
			log("shaka is undefined maybe you forget to include 'shaka-player.compiled.js'")
			return
		}
		if (!shaka.Player.isBrowserSupported()) {
			log("shaka player is not supported for this browser")
			return
		}

		this._player = new shaka.Player(this.element.dom)

		var errorCallback = function(event) { log("Error", event) }
		this._player.addEventListener('error', this.error);
	}

	///@private
	onSourceChanged: {
		this._player.load(this.source).then(function() {
			log('The video has now been loaded!');
		}).catch(function(err) {
			log("Error while loading", err)
		});
	}
}


import QtQuick 2.3

FocusScope {
    id: root

    default property alias content: contentItem.data
    property alias titleBar: titleBarContainer.data
    property bool active: false

    signal activated
    signal currentItemChanged

    Component.onCompleted: {
        if (root.parent === null || root.parent.toString().substring(0, 9) !== "StackView") {
            root.activated()
            root.active = true
        }
    }

    Connections {
        target: root.parent !== null && root.parent.toString().substring(0, 9) === "StackView" ? root.parent : root

        onCurrentItemChanged: {
            if (root.parent.currentItem === root) {
                root.active = true
                root.activated()
            } else {
                root.active = false
            }
        }
    }

    FocusScope {
        id: titleBarContainer

        height: childrenRect.height
        width: parent.width
    }

    FocusScope {
        id: contentItem

        anchors {
            top: titleBarContainer.bottom
            bottom: parent.bottom
            left: parent.left
            right: parent.right
        }
    }
}

Set focus true when page is activated

import QtQuick 2.3

FocusScope {
    id: root

    default property alias content: contentItem.data
    property alias titleBar: titleBarContainer.data
    property bool active: false

    signal activated
    signal currentItemChanged

    Component.onCompleted: {
        if (root.parent === null || root.parent.toString().substring(0, 9) !== "StackView") {
            root.activated()
            root.active = true
            root.focus = true
        }
    }

    Connections {
        target: root.parent !== null && root.parent.toString().substring(0, 9) === "StackView" ? root.parent : root

        onCurrentItemChanged: {
            if (root.parent.currentItem === root) {
                root.active = true
                root.activated()
                root.focus = true
            } else {
                root.active = false
            }
        }
    }

    FocusScope {
        id: titleBarContainer

        height: childrenRect.height
        width: parent.width
    }

    FocusScope {
        id: contentItem

        anchors {
            top: titleBarContainer.bottom
            bottom: parent.bottom
            left: parent.left
            right: parent.right
        }
    }
}


/*
 * Copyright (C) 2016 Dan Leinir Turthra Jensen <admin@leinir.dk>
 *
 * This library 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) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * This library 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 library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

import QtQuick 2.1

import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras

Item {
    id: root;
    property alias title: bookTitle.text;
    property string author;
    property string filename;
    property int categoryEntriesCount;
    property string currentPage;
    signal bookSelected(string filename, int currentPage);

    property int neededHeight: bookCover.height + bookTitle.height + units.largeSpacing;
    property int minimumWidth: bookCover.width + units.largeSpacing * 2;
    visible: height > 0;
    enabled: visible;
    clip: true;
    MouseArea {
        anchors.fill: parent;
        onClicked: root.bookSelected(root.filename, root.currentPage);
    }
    Item {
        id: bookCover;
        anchors {
            top: parent.top;
            horizontalCenter: parent.horizontalCenter;
            margins: units.largeSpacing;
        }
        width: units.iconSizes.enormous + units.largeSpacing * 2;
        height: width;
        Rectangle {
            anchors.centerIn: coverImage;
            width: coverImage.paintedWidth + units.smallSpacing * 2;
            height: coverImage.paintedHeight + units.smallSpacing * 2;
            color: theme.viewBackgroundColor;
            border {
                width: 2;
                color: theme.viewTextColor;
            }
            radius: 2;
        }
        Image {
            id: coverImage;
            anchors {
                fill: parent;
                margins: units.largeSpacing;
            }
            source: "image://preview/" + root.filename
            asynchronous: true;
            fillMode: Image.PreserveAspectFit;
        }
    }
    PlasmaComponents.Label {
        id: bookTitle;
        anchors {
            top: bookCover.bottom;
            left: parent.left;
            right: parent.right;
            margins: units.smallSpacing;
            topMargin: 0;
        }
        height: paintedHeight;
        maximumLineCount: 2;
        wrapMode: Text.WrapAtWordBoundaryOrAnywhere;
        elide: Text.ElideMiddle;
        horizontalAlignment: Text.AlignHCenter;
    }
}


/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Vesa-Matti Hartikainen <vesa-matti.hartikainen@jollamobile.com>
** 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.0
import Sailfish.Silica 1.0
import Sailfish.Browser 1.0
import "pages"

ApplicationWindow {
    id: window

    signal newTab

    function setBrowserCover(model) {
        if (model && model.count === 0) {
            cover = Qt.resolvedUrl("cover/NoTabsCover.qml")
        } else {
            cover = null
        }
    }

    allowedOrientations: defaultAllowedOrientations
    _defaultPageOrientations: Orientation.All
    _defaultLabelFormat: Text.PlainText
    cover: null
    initialPage: Component {
        BrowserPage {
            id: browserPage

            Connections {
                target: window
                onNewTab: browserPage.activateNewTabView()
            }
        }
    }
}

Improve no tabs cover condition

/****************************************************************************
**
** Copyright (C) 2013 Jolla Ltd.
** Contact: Vesa-Matti Hartikainen <vesa-matti.hartikainen@jollamobile.com>
** 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.0
import Sailfish.Silica 1.0
import Sailfish.Browser 1.0
import "pages"

ApplicationWindow {
    id: window

    signal newTab

    function setBrowserCover(model) {
        if (!model || model.count === 0) {
            cover = Qt.resolvedUrl("cover/NoTabsCover.qml")
        } else {
            cover = null
        }
    }

    allowedOrientations: defaultAllowedOrientations
    _defaultPageOrientations: Orientation.All
    _defaultLabelFormat: Text.PlainText
    cover: null
    initialPage: Component {
        BrowserPage {
            id: browserPage

            Connections {
                target: window
                onNewTab: browserPage.activateNewTabView()
            }
        }
    }
}


import QtQuick 2.0
import Ubuntu.Components 1.1
import AardDictionary 1.0
/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "aarddictionary.danielbeck"

    /*
     This property enables the application to change orientation
     when the device is rotated. The default is false.
    */
    //automaticOrientation: true

    // Removes the old toolbar and enables new features of the new header.
    useDeprecatedToolbar: false

    width: units.gu(100)
    height: units.gu(75)

    Page {
        title: i18n.tr("aardDictionary")

        MyType {
            id: myType

            Component.onCompleted: {
                myType.helloWorld = i18n.tr("Hello world..")
            }
        }

        Column {
            spacing: units.gu(1)
            anchors {
                margins: units.gu(2)
                fill: parent
            }

            Label {
                id: label
                objectName: "label"

                text: myType.helloWorld
            }

            Button {
                objectName: "button"
                width: parent.width

                text: i18n.tr("Tap me!")

                onClicked: {
                    myType.helloWorld = i18n.tr("..from Cpp Backend")
                }
            }
        }
    }
}

Switch to Ubuntu Components 1.3.

import QtQuick 2.4
import Ubuntu.Components 1.3
import AardDictionary 1.0
/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "aarddictionary.danielbeck"

    /*
     This property enables the application to change orientation
     when the device is rotated. The default is false.
    */
    //automaticOrientation: true

    // Removes the old toolbar and enables new features of the new header.
   // useDeprecatedToolbar: false

    width: units.gu(100)
    height: units.gu(75)

    Page {
        title: i18n.tr("Aard Dictionaries")

        MyType {
            id: myType

            Component.onCompleted: {
                myType.helloWorld = i18n.tr("Hello world..")
            }
        }

        Column {
            spacing: units.gu(1)
            anchors {
                margins: units.gu(2)
                fill: parent
            }

            Label {
                id: label
                objectName: "label"

                text: myType.helloWorld
            }

            Button {
                objectName: "button"
                width: parent.width

                text: i18n.tr("Tap me!")

                onClicked: {
                    myType.helloWorld = i18n.tr("..from Cpp Backend")
                }
            }
        }
    }
}


import Qt 4.7

// These buttons are very ugly
Rectangle {
    id: container

    signal clicked
    property string image: ""
    property string text: ""

    color: activePalette.button; smooth: true
    border.width: 1; border.color: Qt.darker(activePalette.button); radius: 8;

    gradient: Gradient {
        GradientStop {
            id: topGrad; position: 0.0
            color : mr.pressed ?  activePalette.dark : activePalette.light
        }
        GradientStop { position: 1.0; color: activePalette.button }
    }
    width: stuff.width + 4
    height: stuff.height + 4

    Item {
        id: stuff
        width: childrenRect.width;
        height: childrenRect.height;

        Image {
            id: imgItem;
            smooth: true
            width: 16; height: 16;
            source: container.image;
            x: 8
            y: 2;
        }

        Item {
            width: txtItem.width + 12
            height: txtItem.height
            Text {
                x: 6
                id: txtItem; text: container.text; font.pixelSize: 16; color: activePalette.buttonText
            }
        }
    }

    // Don't make mr part of the size determination, since it uses anchors.fill
    MouseArea { id: mr; anchors.fill: parent; onClicked: container.clicked() }

}

Make the button a little less ugly.

import Qt 4.7

// These buttons are very ugly
Rectangle {
    id: container

    signal clicked
    property string image: ""
    property string text: ""
    property int padding: 4

    color: activePalette.button;
    smooth: true
    border.width: 2;
    border.color: Qt.darker(activePalette.button);
    radius: 2;

    gradient: Gradient {
        GradientStop { position: 0.0; color: activePalette.button }
        GradientStop {
            position: 1.0
            color : mr.pressed ?  activePalette.light : activePalette.dark
        }
    }
    width: stuff.width + 4 * padding
    height: stuff.height + 2 * padding

    Item {
        id: stuff
        width: childrenRect.width;
        height: childrenRect.height;
        x: 2 * padding
        y: padding

        Row {
            Image {
                id: imgItem;
                smooth: true
                width: 16; height: 16;
                source: container.image;
                opacity: source == "" ? 0 : 1;
            }

            Text {
                id: txtItem; text: container.text; font.pixelSize: 16; color: activePalette.buttonText
            }
        }
    }

    // Don't make mr part of the size determination, since it uses anchors.fill
    MouseArea { id: mr; anchors.fill: parent; onClicked: container.clicked() }

}


Add basic example for adjusting column width draggable handle

/*
 *   Copyright 2017 Eike Hein <hein@kde.org>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Library General Public License as
 *   published by the Free Software Foundation; either version 2 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 Library General Public License for more details
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this program; if not, write to the
 *   Free Software Foundation, Inc.,
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

import QtQuick 2.1

import org.kde.kirigami 2.0 as Kirigami

Kirigami.ApplicationWindow {
    id: root

    property int defaultColumnWidth: Kirigami.Units.gridUnit * 13
    property int columnWidth: defaultColumnWidth

    pageStack.defaultColumnWidth: columnWidth
    pageStack.initialPage: [firstPageComponent, secondPageComponent]

    MouseArea {
        id: dragHandle

        visible: pageStack.wideMode

        anchors.top: parent.top
        anchors.bottom: parent.bottom

        x: columnWidth - (width / 2)
        width: Kirigami.Units.devicePixelRatio * 2

        property int dragRange: (Kirigami.Units.gridUnit * 5)
        property int _lastX: -1

        cursorShape: Qt.SplitHCursor

        onPressed: _lastX = mouseX

        onPositionChanged: {
            if (mouse.x > _lastX) {
                columnWidth = Math.min((defaultColumnWidth + dragRange),
                    columnWidth + (mouse.x - _lastX));
            } else if (mouse.x < _lastX) {
                columnWidth = Math.max((defaultColumnWidth - dragRange),
                    columnWidth - (_lastX - mouse.x));
            }
        }

        Rectangle {
            anchors.fill: parent

            color: "blue"
        }
    }

    Component {
        id: firstPageComponent

        Kirigami.Page {
            id: firstPage

            background: Rectangle { color: "red" }
        }
    }

    Component {
        id: secondPageComponent

        Kirigami.Page {
            id: secondPage

            background: Rectangle { color: "green" }
        }
    }
}


/*
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

Page {
    id: feedPage

    onStatusChanged: {
        attachPage()
    }

    function attachPage() {
        if (status == PageStatus.Active &&
                pageStack._currentContainer.attachedContainer === null &&
                mnemosyManager.logged) {
            pageStack.pushAttached(Qt.resolvedUrl("ProfilePage.qml"))
            console.log("page attached")
        }
    }

    function load() {
        console.log("load")
    }

    BusyIndicator {
        size: BusyIndicatorSize.Medium
        anchors.centerIn: parent
        running: mnemosyManager.busy
        visible: running
    }

    SilicaListView {
        id: friendsFeedView

        anchors.fill: parent

        header: PageHeader {
            title: qsTr("Friends Feed")
        }

        ViewPlaceholder {
            enabled: !mnemosyManager.busy
            text: qsTr("There are no entries. Pull down to refresh.")
        }

        PullDownMenu {

        }

        VerticalScrollDecorator{}
    }
}


///clickable and hoverable rectangle for mouse supportings applications
Rectangle {
	property Mixin hoverMixin: HoverClickMixin {}		///< hover mixin object proveds common API for mouse properties
	property alias hover: hoverMixin.value;			///< mouse hovered flag
	property alias clickable: hoverMixin.clickable;	///< flag which enables or disables mouse click event handling
	property alias hoverable: hoverMixin.enabled;	///< flag which enables or disables mouse hover event handling
	property alias cursor: hoverMixin.cursor;		///< mouse cursor property
	property alias activeHover: hoverMixin.activeHover;	///< flag which becames 'true' on 'mouseover' event and becames 'false' on 'mouseout' event
	property alias activeHoverEnabled: hoverMixin.activeHoverEnabled;	///< flag which enables or disables 'mouseover' and 'mouseout' event handling
	color: "transparent";				///< background color
	hoverMixin.cursor: "pointer";
	property string position;			///< position mode property
	property string title;				///< title attribute property

	/// @private
	onPositionChanged: { this.style('position', value); }
}

Remove 'title' property it's useless now

///clickable and hoverable rectangle for mouse supportings applications
Rectangle {
	property Mixin hoverMixin: HoverClickMixin {}		///< hover mixin object proveds common API for mouse properties
	property alias hover: hoverMixin.value;			///< mouse hovered flag
	property alias clickable: hoverMixin.clickable;	///< flag which enables or disables mouse click event handling
	property alias hoverable: hoverMixin.enabled;	///< flag which enables or disables mouse hover event handling
	property alias cursor: hoverMixin.cursor;		///< mouse cursor property
	property alias activeHover: hoverMixin.activeHover;	///< flag which becames 'true' on 'mouseover' event and becames 'false' on 'mouseout' event
	property alias activeHoverEnabled: hoverMixin.activeHoverEnabled;	///< flag which enables or disables 'mouseover' and 'mouseout' event handling
	color: "transparent";				///< background color
	hoverMixin.cursor: "pointer";
	property string position;			///< position mode property

	/// @private
	onPositionChanged: { this.style('position', value); }
}


import QtQuick 2.8
import QtQuick.XmlListModel 2.0
import org.kde.plasma.core 2.1 as PlasmaCore

/* HACK: Use of the SortFilterModel::filterCallback.  It doesn't really
  support xmllistmodel filterRole/String, so instead of invalidate(),
  reset the sourceModel to force a reload, using callback to filter.
*/
Item {

    property alias hostUrl: xlm.hostUrl
    readonly property alias model: sf
    property string filterType: ""

    onFilterTypeChanged: {
        sf.sourceModel = null
        xlm.reload()
        sf.sourceModel = xlm
    }

    PlasmaCore.SortFilterModel {
        id: sf
        sourceModel: xlm
        filterCallback: function(i,str)
        {
            return (filterType === "" || filterType.toLowerCase() === "all")
                    ? true
                    : filterType.toLowerCase().indexOf(xlm.get(i).type.toLowerCase()) !== -1
        }
    }

    BaseXml {
        id: xlm
        onHostUrlChanged: load("Playlists/List")

        XmlRole { name: "id";   query: "Field[1]/string()" }
        XmlRole { name: "name"; query: "Field[2]/string()" }
        XmlRole { name: "path"; query: "Field[3]/string()" }
        XmlRole { name: "type"; query: "Field[4]/string()" }

    }
}

Add clear method to reset the model/sf model

import QtQuick 2.8
import QtQuick.XmlListModel 2.0
import org.kde.plasma.core 2.1 as PlasmaCore

/* HACK: Use of the SortFilterModel::filterCallback.  It doesn't really
  support xmllistmodel filterRole/String, so instead of invalidate(),
  reset the sourceModel to force a reload, using callback to filter.
*/
Item {

    property alias hostUrl: xlm.hostUrl
    readonly property alias model: sf
    property string filterType: ""

    function clear() {
        sf.sourceModel = null
        xlm.source = ""
        sf.sourceModel = xlm
    }

    onFilterTypeChanged: {
        sf.sourceModel = null
        xlm.reload()
        sf.sourceModel = xlm
    }

    PlasmaCore.SortFilterModel {
        id: sf
        sourceModel: xlm
        filterCallback: function(i,str)
        {
            return (filterType === "" || filterType.toLowerCase() === "all")
                    ? true
                    : filterType.toLowerCase().indexOf(xlm.get(i).type.toLowerCase()) !== -1
        }
    }

    BaseXml {
        id: xlm
        onHostUrlChanged: load("Playlists/List")

        XmlRole { name: "id";   query: "Field[1]/string()" }
        XmlRole { name: "name"; query: "Field[2]/string()" }
        XmlRole { name: "path"; query: "Field[3]/string()" }
        XmlRole { name: "type"; query: "Field[4]/string()" }

    }
}


// Here, we implement "Scale to Fit" behaviour, using the
// preserveAspect property.
//
Image {
    id: Image
    source: "pics/face.png"
    preserveAspect: true
}

Make identical to non-simple example.

// Here, we implement "Scale to Fit" behaviour, using the
// preserveAspect property.
//
Rect {
    // default size: whole image, unscaled
    width: Image.width
    height: Image.height
    color: "gray"
    clip: true

    Image {
        id: Image
        source: "pics/face.png"
        preserveAspect: true
        anchors.fill: parent
    }
}


import QtQuick 2.8
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0

Item {
    height: 32
    width: height

    property bool animateLoad: false
    property string sourceKey: ''

    Image {
        id: img

        property var aSource: mcws.imageUrl(sourceKey)

        onASourceChanged: {
            if (animateLoad)
                Qt.callLater(function(){ seq.start() })
            else
                source = aSource
        }

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

        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'
                mcws.setImageError(sourceKey)
            }
        }
    }
}

Disable caching of track images

import QtQuick 2.8
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0

Item {
    height: 32
    width: height

    property bool animateLoad: false
    property string sourceKey: ''

    Image {
        id: img
        // Qt caches images based on source string, which is
        // different for every track as it's based on filekey.
        // So, if true, caching stores multiple copies of the same
        // image because filekey is different.
        cache: false

        property var aSource: mcws.imageUrl(sourceKey)

        onASourceChanged: {
            if (animateLoad)
                Qt.callLater(function(){ seq.start() })
            else
                source = aSource
        }

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

        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'
                mcws.setImageError(sourceKey)
            }
        }
    }
}


import QtQuick 6.0

Item
{
    id: canvas
    width: parent.width
    height: parent.height

    property int columns: 0
    property int rows: 0
    property var cellArray: []

    function redraw(biotope)
    {
        const Cell = Qt.createComponent("Cell.qml");
        children = []; // remove all cells from canvas

        columns = biotope.width;
        rows = biotope.height;
        cellArray = new Array(columns * rows); // keep references of cells to modify them later

        const boxWidth = canvas.width / columns;
        const boxHeight = canvas.height / rows;

        for (var y = 0; y < rows; y++)
        {
            for (var x = 0; x < columns; x++)
            {
                var cell = Cell.createObject(canvas);

                cell.move(boxWidth * x, boxHeight * y);
                cell.resize(boxWidth, boxHeight);

                cellArray[offset(x, y)] = cell;
            }
        }

        refreshAll(biotope);
    }

    function refreshAll(biotope)
    {
        canvas.visible = false;

        for (var y = 0; y < rows; y++)
        {
            for (var x = 0; x < columns; x++)
            {
                refreshCell(biotope, x, y);
            }
        }

        canvas.visible = true;
    }

    function refreshCell(biotope, x, y)
    {
        var cell = cellArray[offset(x, y)];
        cell.setAlive(biotope.isAlive(x, y));
    }

    function offset(x, y)
    {
        return y * columns + x;
    }
}

Replace "var" with safer "let" declarations

import QtQuick 6.0

Item
{
    id: canvas
    width: parent.width
    height: parent.height

    property int columns: 0
    property int rows: 0
    property var cellArray: []

    function redraw(biotope)
    {
        const Cell = Qt.createComponent("Cell.qml");
        children = []; // remove all cells from canvas

        columns = biotope.width;
        rows = biotope.height;
        cellArray = new Array(columns * rows); // keep references of cells to modify them later

        const boxWidth = canvas.width / columns;
        const boxHeight = canvas.height / rows;

        for (let y = 0; y < rows; y++)
        {
            for (let x = 0; x < columns; x++)
            {
                let cell = Cell.createObject(canvas);

                cell.move(boxWidth * x, boxHeight * y);
                cell.resize(boxWidth, boxHeight);

                cellArray[offset(x, y)] = cell;
            }
        }

        refreshAll(biotope);
    }

    function refreshAll(biotope)
    {
        canvas.visible = false;

        for (let y = 0; y < rows; y++)
        {
            for (let x = 0; x < columns; x++)
            {
                refreshCell(biotope, x, y);
            }
        }

        canvas.visible = true;
    }

    function refreshCell(biotope, x, y)
    {
        let cell = cellArray[offset(x, y)];
        cell.setAlive(biotope.isAlive(x, y));
    }

    function offset(x, y)
    {
        return y * columns + x;
    }
}


import qbs

DynamicLibrary {
    name: "test_applet"
    Depends { name: "cpp" }
    Depends { name: "InternalApi" }

    cpp.defines: ["TA_PLUGIN"]

    files: ["test_applet.c"]
}

Change product destination directory to build root

import qbs

DynamicLibrary {
    name: "test_applet"
    Depends { name: "cpp" }
    Depends { name: "InternalApi" }

    destinationDirectory: '.'
    cpp.defines: ["TA_PLUGIN"]

    files: ["test_applet.c"]
}