diff --git a/examples/applets/compactrepresentation/contents/ui/main.qml b/examples/applets/compactrepresentation/contents/ui/main.qml index 8a1ef7196..78c81576a 100644 --- a/examples/applets/compactrepresentation/contents/ui/main.qml +++ b/examples/applets/compactrepresentation/contents/ui/main.qml @@ -19,13 +19,14 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents Item { - property int minimumWidth: 200 - property int minimumHeight: 300 - property Component compactRepresentation: Component { + Layout.minimumWidth: 200 + Layout.minimumHeight: 300 + Plasmoid.compactRepresentation: Component { PlasmaComponents.Button { text: i18n("Click me") onClicked: plasmoid.expanded = !plasmoid.expanded diff --git a/examples/applets/conditionalloader/contents/ui/main.qml b/examples/applets/conditionalloader/contents/ui/main.qml index 0f855da24..985868ff4 100644 --- a/examples/applets/conditionalloader/contents/ui/main.qml +++ b/examples/applets/conditionalloader/contents/ui/main.qml @@ -17,6 +17,7 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 import QtQuick.Layouts 1.0 import org.kde.plasma.core 2.0 as PlasmaCore @@ -30,10 +31,10 @@ Rectangle { height: 100 radius: 10 smooth: true - property int minimumWidth: units.gridUnit * 20 - property int minimumHeight: column.implicitHeight + Layout.minimumWidth: units.gridUnit * 20 + Layout.minimumHeight: column.implicitHeight - property Component compactRepresentation: Component { + Plasmoid.compactRepresentation: Component { Rectangle { MouseArea { anchors.fill: parent diff --git a/examples/applets/config/contents/ui/main.qml b/examples/applets/config/contents/ui/main.qml index 15969b0bc..2c0cb62ce 100644 --- a/examples/applets/config/contents/ui/main.qml +++ b/examples/applets/config/contents/ui/main.qml @@ -26,8 +26,8 @@ Item { id: root width: 100 height: 100 - property int minimumWidth: units.gridUnit * 20 - property int minimumHeight: column.implicitHeight + Layout.minimumWidth: units.gridUnit * 20 + Layout.minimumHeight: column.implicitHeight ColumnLayout { diff --git a/examples/applets/dataenginemodel/contents/ui/main.qml b/examples/applets/dataenginemodel/contents/ui/main.qml index d64e71f48..e28741200 100644 --- a/examples/applets/dataenginemodel/contents/ui/main.qml +++ b/examples/applets/dataenginemodel/contents/ui/main.qml @@ -19,6 +19,7 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras @@ -26,8 +27,8 @@ import org.kde.plasma.extras 2.0 as PlasmaExtras Column { width: 500 height: 500 - property int minimumWidth: 200 - property int minimumHeight: 300 + Layout.minimumWidth: 200 + Layout.minimumHeight: 300 PlasmaCore.DataSource { id: source diff --git a/examples/applets/helloworld/contents/ui/main.qml b/examples/applets/helloworld/contents/ui/main.qml index 810d5f8b1..c6746f5b2 100644 --- a/examples/applets/helloworld/contents/ui/main.qml +++ b/examples/applets/helloworld/contents/ui/main.qml @@ -19,12 +19,13 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents Item { - property int minimumWidth: 200 - property int minimumHeight: 300 + Layout.minimumWidth: 200 + Layout.minimumHeight: 300 PlasmaComponents.Label { text: i18n("Hello world") diff --git a/examples/applets/notes/contents/ui/main.qml b/examples/applets/notes/contents/ui/main.qml index d0c5e13fc..b74e15203 100644 --- a/examples/applets/notes/contents/ui/main.qml +++ b/examples/applets/notes/contents/ui/main.qml @@ -18,12 +18,13 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents PlasmaCore.SvgItem { - property int minimumWidth: 150 - property int minimumHeight: 150 + Layout.minimumWidth: 150 + Layout.minimumHeight: 150 svg: PlasmaCore.Svg("widgets/notes") elementId: "yellow-notes" diff --git a/examples/applets/qmltasks/contents/ui/qmltasks.qml b/examples/applets/qmltasks/contents/ui/qmltasks.qml index 91a99106e..e6e538a74 100644 --- a/examples/applets/qmltasks/contents/ui/qmltasks.qml +++ b/examples/applets/qmltasks/contents/ui/qmltasks.qml @@ -27,8 +27,8 @@ Item { width: 400 height: 32 - property bool fillWidth: true - property bool fillHeight: true + Layout.fillWidth: true + Layout.fillHeight: true implicitWidth: tasksModel.count * 50 PlasmaCore.DataSource { diff --git a/examples/applets/testcomponents/contents/ui/testcomponents.qml b/examples/applets/testcomponents/contents/ui/testcomponents.qml index 8b6c3f0d1..19909a95b 100644 --- a/examples/applets/testcomponents/contents/ui/testcomponents.qml +++ b/examples/applets/testcomponents/contents/ui/testcomponents.qml @@ -28,8 +28,8 @@ Item { width: 100 height: 100 clip: true - property int minimumWidth: units.gridUnit * 20 - property int minimumHeight: units.gridUnit * 30 + Layout.minimumWidth: units.gridUnit * 20 + Layout.minimumHeight: units.gridUnit * 30 property int _s: units.iconSizes.small property int _h: units.iconSizes.desktop diff --git a/examples/applets/testshaders/contents/ui/testshaderapplet.qml b/examples/applets/testshaders/contents/ui/testshaderapplet.qml index b6ed67e59..f517383e9 100644 --- a/examples/applets/testshaders/contents/ui/testshaderapplet.qml +++ b/examples/applets/testshaders/contents/ui/testshaderapplet.qml @@ -28,8 +28,8 @@ Item { width: 400 height: 400 - property int minimumWidth: units.gridUnit * 20 - property int minimumHeight: units.gridUnit * 30 + Layout.minimumWidth: units.gridUnit * 20 + Layout.minimumHeight: units.gridUnit * 30 property int _s: units.iconSizes.small property int _h: units.iconSizes.desktop property int _m: 12 diff --git a/examples/applets/testtheme/contents/ui/testtheme.qml b/examples/applets/testtheme/contents/ui/testtheme.qml index 2fcaa02c1..8e4f0c02a 100644 --- a/examples/applets/testtheme/contents/ui/testtheme.qml +++ b/examples/applets/testtheme/contents/ui/testtheme.qml @@ -28,8 +28,8 @@ Item { width: 300 height: 400 clip: true - property int minimumWidth: units.gridUnit * 10 - property int minimumHeight: units.gridUnit * 10 + Layout.minimumWidth: units.gridUnit * 10 + Layout.minimumHeight: units.gridUnit * 10 property int _s: units.iconSizes.small property int _h: units.iconSizes.medium diff --git a/examples/applets/widgetgallery/contents/ui/main.qml b/examples/applets/widgetgallery/contents/ui/main.qml index 723c7240c..68d84089a 100644 --- a/examples/applets/widgetgallery/contents/ui/main.qml +++ b/examples/applets/widgetgallery/contents/ui/main.qml @@ -18,33 +18,40 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 +import QtQuick.Layouts 1.1 import org.kde.plasma.components 2.0 Item { - property int minimumWidth: 300 - property int minimumHeight: 400 + Plasmoid.switchWidth: 300 + Plasmoid.switchHeight: 400 - ToolBar { - id: toolBar - z: 10 - anchors { - top: parent.top - left: parent.left - right: parent.right + Plasmoid.fullRepresentation: Item { + Layout.minimumWidth: 300 + Layout.minimumHeight: 400 + + ToolBar { + id: toolBar + z: 10 + //AppletInterface.title: "bah" + anchors { + top: parent.top + left: parent.left + right: parent.right + } } - } - - PageStack { - id: pageStack - toolBar: toolBar - clip: true - anchors { - top: toolBar.bottom - left: parent.left - right: parent.right - bottom: parent.bottom + PageStack { + id: pageStack + toolBar: toolBar + clip: true + anchors { + top: toolBar.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } + initialPage: Qt.createComponent("Menu.qml") } - initialPage: Qt.createComponent("Menu.qml") } } diff --git a/examples/applets/widgetgallery/platformcontents/application/tablet/ui/main.qml b/examples/applets/widgetgallery/platformcontents/application/tablet/ui/main.qml index fe51e5044..057dd3d99 100644 --- a/examples/applets/widgetgallery/platformcontents/application/tablet/ui/main.qml +++ b/examples/applets/widgetgallery/platformcontents/application/tablet/ui/main.qml @@ -18,11 +18,12 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.components 2.0 Image { - property int minimumWidth: 300 - property int minimumHeight: 400 + Layout.minimumWidth: 300 + Layout.minimumHeight: 400 source: "image://appbackgrounds/standard" fillMode: Image.Tile asynchronous: true diff --git a/examples/applets/windowthumbnails/contents/ui/main.qml b/examples/applets/windowthumbnails/contents/ui/main.qml index 92ec7f282..bf8f01b25 100644 --- a/examples/applets/windowthumbnails/contents/ui/main.qml +++ b/examples/applets/windowthumbnails/contents/ui/main.qml @@ -20,6 +20,7 @@ */ import QtQuick 2.0 +import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.extras 2.0 as PlasmaExtras @@ -28,8 +29,8 @@ Item { width: 400 height: 32 - property bool fillWidth: true - property bool fillHeight: true + Layout.fillWidth: true + Layout.fillHeight: true PlasmaCore.DataSource { id: tasksSource diff --git a/src/declarativeimports/core/dialog.cpp b/src/declarativeimports/core/dialog.cpp index 72737e9b7..d995c19c7 100644 --- a/src/declarativeimports/core/dialog.cpp +++ b/src/declarativeimports/core/dialog.cpp @@ -44,6 +44,10 @@ #include #endif +//Unfortunately QWINDOWSIZE_MAX is not exported +#define DIALOGSIZE_MAX ((1<<24)-1) + + DialogProxy::DialogProxy(QQuickItem *parent) : QQuickWindow(parent ? parent->window() : 0), m_location(Plasma::Types::BottomEdge), @@ -114,6 +118,36 @@ void DialogProxy::setMainItem(QQuickItem *mainItem) }); } requestSyncToMainItemSize(); + + //Extract the representation's Layout, if any + QObject *layout = 0; + + //Search a child that has the needed Layout properties + //HACK: here we are not type safe, but is the only way to access to a pointer of Layout + foreach (QObject *child, mainItem->children()) { + //find for the needed property of Layout: minimum/maximum/preferred sizes and fillWidth/fillHeight + if (child->property("minimumWidth").isValid() && child->property("minimumHeight").isValid() && + child->property("preferredWidth").isValid() && child->property("preferredHeight").isValid() && + child->property("maximumWidth").isValid() && child->property("maximumHeight").isValid() && + child->property("fillWidth").isValid() && child->property("fillHeight").isValid() + ) { + layout = child; + } + } + m_mainItemLayout = layout; + + if (layout) { + connect(layout, SIGNAL(minimumWidthChanged()), this, SLOT(updateMinimumWidth())); + connect(layout, SIGNAL(minimumHeightChanged()), this, SLOT(updateMinimumHeight())); + connect(layout, SIGNAL(maximumWidthChanged()), this, SLOT(updatemaximumWidth())); + connect(layout, SIGNAL(maximumHeightChanged()), this, SLOT(updatemaximumHeight())); + + updateMinimumWidth(); + updateMinimumHeight(); + updateMaximumWidth(); + updateMaximumHeight(); + } + } //if this is called in Component.onCompleted we have to wait a loop the item is added to a scene @@ -604,6 +638,7 @@ void DialogProxy::updateInputShape() #endif } + //find the screen which contains the item QScreen* DialogProxy::screenForItem(QQuickItem* item) const { @@ -616,5 +651,51 @@ QScreen* DialogProxy::screenForItem(QQuickItem* item) const return QGuiApplication::primaryScreen(); } +void DialogProxy::updateMinimumWidth() +{ + if (m_mainItemLayout) { + setMinimumWidth(m_mainItemLayout.data()->property("minimumWidth").toInt()); + } else { + setMinimumWidth(-1); + } +} + +void DialogProxy::updateMinimumHeight() +{ + if (m_mainItemLayout) { + setMinimumHeight(m_mainItemLayout.data()->property("minimumHeight").toInt()); + } else { + setMinimumHeight(-1); + } +} + +void DialogProxy::updateMaximumWidth() +{ + if (m_mainItemLayout) { + const int hint = m_mainItemLayout.data()->property("maximumWidth").toInt(); + if (hint > 0) { + setMaximumWidth(hint); + } else { + setMaximumWidth(DIALOGSIZE_MAX); + } + } else { + setMaximumWidth(DIALOGSIZE_MAX); + } +} + +void DialogProxy::updateMaximumHeight() +{ + if (m_mainItemLayout) { + const int hint = m_mainItemLayout.data()->property("maximumHeight").toInt(); + if (hint > 0) { + setMaximumWidth(hint); + } else { + setMaximumWidth(DIALOGSIZE_MAX); + } + } else { + setMaximumHeight(DIALOGSIZE_MAX); + } +} + #include "dialog.moc" diff --git a/src/declarativeimports/core/dialog.h b/src/declarativeimports/core/dialog.h index a2ea91746..3c0df8b71 100644 --- a/src/declarativeimports/core/dialog.h +++ b/src/declarativeimports/core/dialog.h @@ -172,6 +172,11 @@ private Q_SLOTS: void updateVisibility(bool visible); + void updateMinimumWidth(); + void updateMinimumHeight(); + void updateMaximumWidth(); + void updateMaximumHeight(); + private: QScreen* screenForItem(QQuickItem *item) const; @@ -180,6 +185,9 @@ private: bool m_hideOnWindowDeactivate; bool m_outputOnly; Plasma::Theme m_theme; + + //Attached Layout property of mainItem, if any + QWeakPointer m_mainItemLayout; }; #endif diff --git a/src/plasma/applet.h b/src/plasma/applet.h index c91cb6e3b..7fce564f4 100644 --- a/src/plasma/applet.h +++ b/src/plasma/applet.h @@ -415,6 +415,21 @@ class PLASMA_EXPORT Applet : public QObject public Q_SLOTS: //BOOKKEEPING + /** + * Call this method when the applet fails to launch properly. An + * optional reason can be provided. + * + * Not that all children items will be deleted when this method is + * called. If you have pointers to these items, you will need to + * reset them after calling this method. + * + * @param failed true when the applet failed, false when it succeeded + * @param reason an optional reason to show the user why the applet + * failed to launch + * @since 5.0 + **/ + void setLaunchErrorMessage(const QString &reason = QString()); + /** * Sets the immutability type for this applet (not immutable, * user immutable or system immutable) @@ -488,22 +503,6 @@ class PLASMA_EXPORT Applet : public QObject */ Applet(QObject *parent, const QVariantList &args); -//BOOKEEPING - /** - * Call this method when the applet fails to launch properly. An - * optional reason can be provided. - * - * Not that all children items will be deleted when this method is - * called. If you have pointers to these items, you will need to - * reset them after calling this method. - * - * @param failed true when the applet failed, false when it succeeded - * @param reason an optional reason to show the user why the applet - * failed to launch - * @since 5.0 - **/ - void setLaunchErrorMessage(const QString &reason = QString()); - //CONFIGURATION /** * When called, the Applet should write any information needed as part diff --git a/src/plasma/private/applet_p.cpp b/src/plasma/private/applet_p.cpp index 7afcdd37c..26d48e306 100644 --- a/src/plasma/private/applet_p.cpp +++ b/src/plasma/private/applet_p.cpp @@ -358,12 +358,21 @@ KConfigGroup *AppletPrivate::mainConfigGroup() return mainConfig; } + Containment *c = q->containment(); + Plasma::Applet *parentApplet = 0; + if (c) { + parentApplet = qobject_cast(c->parent()); + } + if (q->isContainment()) { Corona *corona = static_cast(q)->corona(); KConfigGroup containmentConfig; //qDebug() << "got a corona, baby?" << (QObject*)corona << (QObject*)q; - if (corona) { + if (parentApplet) { + containmentConfig = parentApplet->config(); + containmentConfig = KConfigGroup(&containmentConfig, "Containments"); + } else if (corona) { containmentConfig = KConfigGroup(corona->config(), "Containments"); } else { containmentConfig = KConfigGroup(KSharedConfig::openConfig(), "Containments"); @@ -373,14 +382,7 @@ KConfigGroup *AppletPrivate::mainConfigGroup() } else { KConfigGroup appletConfig; - Containment *c = q->containment(); - Applet *parentApplet = qobject_cast(q->parent()); - if (parentApplet && parentApplet != static_cast(c)) { - // this applet is nested inside another applet! use it's config - // as the parent group in the config - appletConfig = parentApplet->config(); - appletConfig = KConfigGroup(&appletConfig, "Applets"); - } else if (c) { + if (c) { // applet directly in a Containment, as usual appletConfig = c->config(); appletConfig = KConfigGroup(&appletConfig, "Applets"); diff --git a/src/plasmaquick/CMakeLists.txt b/src/plasmaquick/CMakeLists.txt index 45260693e..03251bc07 100644 --- a/src/plasmaquick/CMakeLists.txt +++ b/src/plasmaquick/CMakeLists.txt @@ -1,6 +1,7 @@ project(PlasmaQuick) set(plasmaquick_LIB_SRC + appletquickitem.cpp plasmaquickview.cpp configmodel.cpp configview.cpp @@ -36,6 +37,7 @@ generate_export_header(KF5PlasmaQuick BASE_NAME PlasmaQuick) set(plasmaquick_LIB_INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/plasmaquick_export.h + appletquickitem.h plasmaquickview.h configview.h configmodel.h diff --git a/src/plasmaquick/appletquickitem.cpp b/src/plasmaquick/appletquickitem.cpp new file mode 100644 index 000000000..804084a79 --- /dev/null +++ b/src/plasmaquick/appletquickitem.cpp @@ -0,0 +1,648 @@ +/* + * Copyright 2014 Marco Martin + * + * 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 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. + */ + +#include "appletquickitem.h" +#include "private/appletquickitem_p.h" + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +QHash AppletQuickItemPrivate::s_rootObjects = QHash(); + +AppletQuickItemPrivate::AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickItem *item) + : q(item), + switchWidth(-1), + switchHeight(-1), + applet(a), + expanded(false) +{ +} + +void AppletQuickItemPrivate::connectLayoutAttached(QObject *item) +{ + QObject *layout = 0; + + //Extract the representation's Layout, if any + //No Item? + if (!item) { + return; + } + + //Search a child that has the needed Layout properties + //HACK: here we are not type safe, but is the only way to access to a pointer of Layout + foreach (QObject *child, item->children()) { + //find for the needed property of Layout: minimum/maximum/preferred sizes and fillWidth/fillHeight + if (child->property("minimumWidth").isValid() && child->property("minimumHeight").isValid() && + child->property("preferredWidth").isValid() && child->property("preferredHeight").isValid() && + child->property("maximumWidth").isValid() && child->property("maximumHeight").isValid() && + child->property("fillWidth").isValid() && child->property("fillHeight").isValid() + ) { + layout = child; + } + } + + if (!layout) { + return; + } + + //propagate all the size hints + propagateSizeHint("minimumWidth"); + propagateSizeHint("minimumHeight"); + propagateSizeHint("preferredWidth"); + propagateSizeHint("preferredHeight"); + propagateSizeHint("maximumWidth"); + propagateSizeHint("maximumHeight"); + propagateSizeHint("fillWidth"); + propagateSizeHint("fillHeight"); + + //HACK: check the Layout properties we wrote + QQmlProperty p(q, "Layout.minimumWidth", QtQml::qmlContext(qmlObject->rootObject())); + + QObject *ownLayout = 0; + + foreach (QObject *child, q->children()) { + //find for the needed property of Layout: minimum/maximum/preferred sizes and fillWidth/fillHeight + if (child->property("minimumWidth").isValid() && child->property("minimumHeight").isValid() && + child->property("preferredWidth").isValid() && child->property("preferredHeight").isValid() && + child->property("maximumWidth").isValid() && child->property("maximumHeight").isValid() && + child->property("fillWidth").isValid() && child->property("fillHeight").isValid() + ) { + ownLayout = child; + } + } + + //this should never happen, since we ask to create it if doesn't exists + if (!ownLayout) { + return; + } + + //if the representation didn't change, don't do anything + if (representationLayout.data() == layout) { + return; + } + + if (representationLayout) { + QObject::disconnect(representationLayout.data(), 0, q, 0); + } + + //Here we can't use the new connect syntax because we can't link against QtQuick layouts + QObject::connect(layout, SIGNAL(minimumWidthChanged()), + q, SLOT(minimumWidthChanged())); + QObject::connect(layout, SIGNAL(minimumHeightChanged()), + q, SLOT(minimumHeightChanged())); + + QObject::connect(layout, SIGNAL(preferredWidthChanged()), + q, SLOT(preferredWidthChanged())); + QObject::connect(layout, SIGNAL(preferredHeightChanged()), + q, SLOT(preferredHeightChanged())); + + QObject::connect(layout, SIGNAL(maximumWidthChanged()), + q, SLOT(maximumWidthChanged())); + QObject::connect(layout, SIGNAL(maximumHeightChanged()), + q, SLOT(maximumHeightChanged())); + + QObject::connect(layout, SIGNAL(fillWidthChanged()), + q, SLOT(fillWidthChanged())); + QObject::connect(layout, SIGNAL(fillHeightChanged()), + q, SLOT(fillHeightChanged())); + + representationLayout = layout; + AppletQuickItemPrivate::ownLayout = ownLayout; + + propagateSizeHint("minimumWidth"); + propagateSizeHint("minimumHeight"); + propagateSizeHint("preferredWidth"); + propagateSizeHint("preferredHeight"); + propagateSizeHint("maximumWidth"); + propagateSizeHint("maximumHeight"); + propagateSizeHint("fillWidth"); + propagateSizeHint("fillHeight"); +} + +void AppletQuickItemPrivate::propagateSizeHint(const QByteArray &layoutProperty) +{ + if (ownLayout && representationLayout) { + ownLayout.data()->setProperty(layoutProperty, representationLayout.data()->property(layoutProperty)); + } +} + +QObject *AppletQuickItemPrivate::createCompactRepresentationItem() +{ + if (!compactRepresentation) { + return 0; + } + + if (compactRepresentationItem) { + return compactRepresentationItem.data(); + } + + compactRepresentationItem = qmlObject->createObjectFromComponent(compactRepresentation.data(), QtQml::qmlContext(qmlObject->rootObject())); + + emit q->compactRepresentationItemChanged(compactRepresentationItem.data()); + + return compactRepresentationItem.data(); +} + +QObject *AppletQuickItemPrivate::createFullRepresentationItem() +{ + if (fullRepresentationItem) { + return fullRepresentationItem.data(); + } + + if (fullRepresentation) { + fullRepresentationItem = qmlObject->createObjectFromComponent(fullRepresentation.data(), QtQml::qmlContext(qmlObject->rootObject())); + } else { + fullRepresentation = qmlObject->mainComponent(); + fullRepresentationItem = qmlObject->rootObject(); + emit q->fullRepresentationChanged(fullRepresentation.data()); + } + + QQuickItem *graphicsObj = qobject_cast(fullRepresentationItem.data()); + QObject::connect (graphicsObj, &QQuickItem::widthChanged, [=]() { + fullRepresentationResizeTimer.start(); + }); + QObject::connect (graphicsObj, &QQuickItem::heightChanged, [=]() { + fullRepresentationResizeTimer.start(); + }); + + emit q->fullRepresentationItemChanged(fullRepresentationItem.data()); + + return fullRepresentationItem.data(); +} + +QObject *AppletQuickItemPrivate::createCompactRepresentationExpanderItem() +{ + if (!compactRepresentationExpander) { + return 0; + } + + if (compactRepresentationExpanderItem) { + return compactRepresentationExpanderItem.data(); + } + + compactRepresentationExpanderItem = qmlObject->createObjectFromComponent(compactRepresentationExpander.data(), QtQml::qmlContext(qmlObject->rootObject())); + + + compactRepresentationExpanderItem.data()->setProperty("compactRepresentation", QVariant::fromValue(createCompactRepresentationItem())); + compactRepresentationExpanderItem.data()->setProperty("fullRepresentation", QVariant::fromValue(createFullRepresentationItem())); + + return compactRepresentationExpanderItem.data(); +} + +void AppletQuickItemPrivate::compactRepresentationCheck() +{ + //ignore 0,0 sizes; + if (q->width() <= 0 && q->height() <= 0) { + return; + } + + bool full = false; + + if (applet->isContainment()) { + full = true; + + } else { + if (switchWidth > 0 && switchHeight > 0) { + full = q->width() > switchWidth && q->height() > switchHeight; + //if a size to switch wasn't set, determine what representation to always chose + } else { + //preferred representation set? + if (preferredRepresentation) { + full = preferredRepresentation.data() == fullRepresentation.data(); + //Otherwise, base on FormFactor + } else { + full = (applet->formFactor() != Plasma::Types::Horizontal && applet->formFactor() != Plasma::Types::Vertical); + } + } + + if ((full && fullRepresentationItem && fullRepresentationItem.data() == currentRepresentationItem.data()) || + (!full && compactRepresentationItem && compactRepresentationItem.data() == currentRepresentationItem.data()) + ) { + return; + } + } + + //Expanded + if (full) { + QQuickItem *item = qobject_cast(createFullRepresentationItem()); + + if (item) { + item->setParentItem(q); + { + //set anchors + QQmlExpression expr(QtQml::qmlContext(qmlObject->rootObject()), item, "parent"); + QQmlProperty prop(item, "anchors.fill"); + prop.write(expr.evaluate()); + } + if (compactRepresentationItem) { + compactRepresentationItem.data()->setProperty("visible", false); + } + if (compactRepresentationExpanderItem) { + compactRepresentationExpanderItem.data()->setProperty("compactRepresentation", QVariant()); + compactRepresentationExpanderItem.data()->setProperty("fullRepresentation", QVariant()); + } + + currentRepresentationItem = item; + connectLayoutAttached(item); + } + + //Icon + } else { + QQuickItem *compactItem = qobject_cast(createCompactRepresentationItem()); + + if (compactItem) { + //set the root item as the main visible item + compactItem->setParentItem(q); + compactItem->setVisible(true); + { + //set anchors + QQmlExpression expr(QtQml::qmlContext(qmlObject->rootObject()), compactItem, "parent"); + QQmlProperty prop(compactItem, "anchors.fill"); + prop.write(expr.evaluate()); + } + + if (fullRepresentationItem) { + fullRepresentationItem.data()->setProperty("parent", QVariant()); + } + + if (compactRepresentationExpanderItem) { + compactRepresentationExpanderItem.data()->setProperty("compactRepresentation", QVariant::fromValue(compactItem)); + compactRepresentationExpanderItem.data()->setProperty("fullRepresentation", QVariant::fromValue(createFullRepresentationItem())); + } + + currentRepresentationItem = compactItem; + connectLayoutAttached(compactItem); + } + } +} + +void AppletQuickItemPrivate::minimumWidthChanged() +{ + propagateSizeHint("minimumWidth"); +} + +void AppletQuickItemPrivate::minimumHeightChanged() +{ + propagateSizeHint("minimumHeight"); +} + +void AppletQuickItemPrivate::preferredWidthChanged() +{ + propagateSizeHint("preferredWidth"); +} + +void AppletQuickItemPrivate::preferredHeightChanged() +{ + propagateSizeHint("preferredHeight"); +} + +void AppletQuickItemPrivate::maximumWidthChanged() +{ + propagateSizeHint("maximumWidth"); +} + +void AppletQuickItemPrivate::maximumHeightChanged() +{ + propagateSizeHint("maximumHeight"); +} + +void AppletQuickItemPrivate::fillWidthChanged() +{ + propagateSizeHint("fillWidth"); +} + +void AppletQuickItemPrivate::fillHeightChanged() +{ + propagateSizeHint("fillHeight"); +} + + + + +AppletQuickItem::AppletQuickItem(Plasma::Applet *applet, QQuickItem *parent) + : QQuickItem(parent), + d(new AppletQuickItemPrivate(applet, this)) +{ + if (d->applet) { + d->appletPackage = d->applet->package(); + } + if (d->applet && d->applet->containment() && d->applet->containment()->corona()) { + d->coronaPackage = d->applet->containment()->corona()->package(); + } + + d->compactRepresentationCheckTimer.setSingleShot(true); + d->compactRepresentationCheckTimer.setInterval(250); + connect (&d->compactRepresentationCheckTimer, SIGNAL(timeout()), + this, SLOT(compactRepresentationCheck())); + d->compactRepresentationCheckTimer.start(); + + d->fullRepresentationResizeTimer.setSingleShot(true); + d->fullRepresentationResizeTimer.setInterval(250); + connect (&d->fullRepresentationResizeTimer, &QTimer::timeout, + [=]() { + KConfigGroup cg = d->applet->config(); + cg = KConfigGroup(&cg, "PopupApplet"); + cg.writeEntry("DialogWidth", d->fullRepresentationItem.data()->property("width").toInt()); + cg.writeEntry("DialogHeight", d->fullRepresentationItem.data()->property("height").toInt()); + } + ); + + + + d->qmlObject = new KDeclarative::QmlObject(this); + d->qmlObject->setInitializationDelayed(true); + + // set the graphicObject dynamic property on applet + d->applet->setProperty("_plasma_graphicObject", QVariant::fromValue(this)); + setProperty("_plasma_applet", QVariant::fromValue(applet)); +} + +AppletQuickItem::~AppletQuickItem() +{ + //Here the order is important + delete d->compactRepresentationItem.data(); + delete d->fullRepresentationItem.data(); + delete d->compactRepresentationExpanderItem.data(); + + AppletQuickItemPrivate::s_rootObjects.remove(d->qmlObject->engine()); +} + + AppletQuickItem *AppletQuickItem::qmlAttachedProperties(QObject *object) +{ + //at the moment of the attached object creation, the root item is the only one that hasn't a parent + //only way to avoid creation of this attached for everybody but the root item + if (!object->parent() && AppletQuickItemPrivate::s_rootObjects.contains(QtQml::qmlEngine(object))) { + return AppletQuickItemPrivate::s_rootObjects.value(QtQml::qmlEngine(object)); + } else { + return 0; + } +} + +Plasma::Applet *AppletQuickItem::applet() const +{ + return d->applet; +} + +void AppletQuickItem::init() +{ + if (AppletQuickItemPrivate::s_rootObjects.contains(this)) { + return; + } + + AppletQuickItemPrivate::s_rootObjects[d->qmlObject->engine()] = this; + + Q_ASSERT(d->applet); + + //Initialize the main QML file + QQmlEngine *engine = d->qmlObject->engine(); + + PackageUrlInterceptor *interceptor = new PackageUrlInterceptor(engine, d->applet->package()); + interceptor->addAllowedPath(d->coronaPackage.path()); + engine->setUrlInterceptor(interceptor); + + d->qmlObject->setSource(QUrl::fromLocalFile(d->applet->package().filePath("mainscript"))); + + if (!engine || !engine->rootContext() || !engine->rootContext()->isValid() || d->qmlObject->mainComponent()->isError()) { + QString reason; + foreach (QQmlError error, d->qmlObject->mainComponent()->errors()) { + reason += error.toString()+'\n'; + } + reason = i18n("Error loading QML file: %1", reason); + + d->qmlObject->setSource(QUrl::fromLocalFile(d->coronaPackage.filePath("appleterror"))); + d->qmlObject->completeInitialization(); + + + //even the error message QML may fail + if (d->qmlObject->mainComponent()->isError()) { + return; + } else { + d->qmlObject->rootObject()->setProperty("reason", reason); + } + + d->applet->setLaunchErrorMessage(reason); + } + + engine->rootContext()->setContextProperty("plasmoid", this); + + //initialize size, so an useless resize less + QVariantHash initialProperties; + initialProperties["width"] = width(); + initialProperties["height"] = height(); + d->qmlObject->completeInitialization(initialProperties); + + //default fullrepresentation is our root main component, if none specified + if (!d->fullRepresentation) { + d->fullRepresentation = d->qmlObject->mainComponent(); + d->fullRepresentationItem = d->qmlObject->rootObject(); + emit fullRepresentationChanged(d->fullRepresentation.data()); + } + + //default d->compactRepresentation is a simple icon provided by the shell package + if (!d->compactRepresentation) { + d->compactRepresentation = new QQmlComponent(engine, this); + d->compactRepresentation.data()->loadUrl(QUrl::fromLocalFile(d->coronaPackage.filePath("defaultcompactrepresentation"))); + emit compactRepresentationChanged(d->compactRepresentation.data()); + } + + //default d->compactRepresentationExpander is the popup in which fullRepresentation goes + if (!d->compactRepresentationExpander) { + d->compactRepresentationExpander = new QQmlComponent(engine, this); + d->compactRepresentationExpander.data()->loadUrl(QUrl::fromLocalFile(d->coronaPackage.filePath("compactapplet"))); + } + +} + +Plasma::Package AppletQuickItem::appletPackage() const +{ + return d->appletPackage; +} + +void AppletQuickItem::setAppletPackage(const Plasma::Package &package) +{ + d->appletPackage = package; +} + +Plasma::Package AppletQuickItem::coronaPackage() const +{ + return d->coronaPackage; +} + +void AppletQuickItem::setCoronaPackage(const Plasma::Package &package) +{ + d->coronaPackage = package; +} + +int AppletQuickItem::switchWidth() const +{ + return d->switchWidth; +} + +void AppletQuickItem::setSwitchWidth(int width) +{ + if (d->switchWidth == width) { + return; + } + + d->switchWidth = width; + emit switchWidthChanged(width); +} + +int AppletQuickItem::switchHeight() const +{ + return d->switchHeight; +} + +void AppletQuickItem::setSwitchHeight(int width) +{ + if (d->switchHeight == width) { + return; + } + + d->switchHeight = width; + emit switchHeightChanged(width); +} + +QQmlComponent *AppletQuickItem::compactRepresentation() +{ + return d->compactRepresentation.data(); +} + +void AppletQuickItem::setCompactRepresentation(QQmlComponent *component) +{ + if (d->compactRepresentation.data() == component) { + return; + } + + d->compactRepresentation = component; + emit compactRepresentationChanged(component); +} + + +QQmlComponent *AppletQuickItem::fullRepresentation() +{ + return d->fullRepresentation.data(); +} + +void AppletQuickItem::setFullRepresentation(QQmlComponent *component) +{ + if (d->fullRepresentation.data() == component) { + return; + } + + d->fullRepresentation = component; + emit fullRepresentationChanged(component); +} + +QQmlComponent *AppletQuickItem::preferredRepresentation() +{ + return d->preferredRepresentation.data(); +} + +void AppletQuickItem::setPreferredRepresentation(QQmlComponent *component) +{ + if (d->preferredRepresentation.data() == component) { + return; + } + + d->preferredRepresentation = component; + emit preferredRepresentationChanged(component); +} + +bool AppletQuickItem::isExpanded() const +{ + return d->expanded; +} + +void AppletQuickItem::setExpanded(bool expanded) +{ + if (d->applet->isContainment()) { + expanded = true; + } + + //if there is no compact representation it means it's always expanded + //Containnments are always expanded + if (d->expanded == expanded) { + return; + } + + d->createFullRepresentationItem(); + d->createCompactRepresentationExpanderItem(); + + d->expanded = expanded; + emit expandedChanged(expanded); +} + +////////////Internals + + +KDeclarative::QmlObject *AppletQuickItem::qmlObject() +{ + return d->qmlObject; +} + +QObject *AppletQuickItem::compactRepresentationItem() +{ + return d->compactRepresentationItem.data(); +} + +QObject *AppletQuickItem::fullRepresentationItem() +{ + return d->fullRepresentationItem.data(); +} + +void AppletQuickItem::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_UNUSED(oldGeometry) + + QQuickItem::geometryChanged(newGeometry, oldGeometry); + d->compactRepresentationCheckTimer.start(); +} + +void AppletQuickItem::itemChange(ItemChange change, const ItemChangeData &value) +{ + if (change == QQuickItem::ItemSceneChange) { + //we have a window: create the representations if needed + if (value.window) { + init(); + } + } + + QQuickItem::itemChange(change, value); +} + + + +#include "moc_appletquickitem.cpp" + diff --git a/src/plasmaquick/appletquickitem.h b/src/plasmaquick/appletquickitem.h new file mode 100644 index 000000000..28bdab877 --- /dev/null +++ b/src/plasmaquick/appletquickitem.h @@ -0,0 +1,151 @@ +/* + * Copyright 2014 Marco Martin + * + * 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 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. + */ + +#ifndef APPLETQUICKITEM_H +#define APPLETQUICKITEM_H + +#include +#include +#include +#include +#include + +#include + +#include + +namespace Plasma { + class Applet; +} + +namespace KDeclarative { + class QmlObject; +} + + +class AppletQuickItemPrivate; + +class PLASMAQUICK_EXPORT AppletQuickItem : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(int switchWidth READ switchWidth WRITE setSwitchWidth NOTIFY switchWidthChanged) + Q_PROPERTY(int switchHeight READ switchHeight WRITE setSwitchHeight NOTIFY switchHeightChanged) + + Q_PROPERTY(QQmlComponent *compactRepresentation READ compactRepresentation WRITE setCompactRepresentation NOTIFY compactRepresentationChanged) + Q_PROPERTY(QObject *compactRepresentationItem READ compactRepresentationItem NOTIFY compactRepresentationItemChanged) + + Q_PROPERTY(QQmlComponent *fullRepresentation READ fullRepresentation WRITE setFullRepresentation NOTIFY fullRepresentationChanged) + Q_PROPERTY(QObject *fullRepresentationItem READ fullRepresentationItem NOTIFY fullRepresentationItemChanged) + + + /** + * this is supposed to be either one between compactRepresentation or fullRepresentation + */ + Q_PROPERTY(QQmlComponent *preferredRepresentation READ preferredRepresentation WRITE setPreferredRepresentation NOTIFY preferredRepresentationChanged) + + /** + * True when the applet is showing its full representation. either as the main only view, or in a popup. + * Setting it will open or close the popup if the plasmoid is iconified, however it won't have effect if the applet is open + */ + Q_PROPERTY(bool expanded WRITE setExpanded READ isExpanded NOTIFY expandedChanged) + +public: + AppletQuickItem(Plasma::Applet *applet, QQuickItem *parent = 0); + ~AppletQuickItem(); + +////API NOT SUPPOSED TO BE USED BY QML + Plasma::Applet *applet() const; + + //Make the constructor lighter and delay the actual instantiation of the qml in the applet + virtual void init(); + + Plasma::Package appletPackage() const; + void setAppletPackage(const Plasma::Package &package); + + Plasma::Package coronaPackage() const; + void setCoronaPackage(const Plasma::Package &package); + + QObject *compactRepresentationItem(); + QObject *fullRepresentationItem(); + +////PROPERTY ACCESSORS + int switchWidth() const; + void setSwitchWidth(int width); + + int switchHeight() const; + void setSwitchHeight(int width); + + + QQmlComponent *compactRepresentation(); + void setCompactRepresentation(QQmlComponent *component); + + QQmlComponent *fullRepresentation(); + void setFullRepresentation(QQmlComponent *component); + + QQmlComponent *preferredRepresentation(); + void setPreferredRepresentation(QQmlComponent *component); + + bool isExpanded() const; + void setExpanded(bool expanded); + +////NEEDED BY QML TO CREATE ATTACHED PROPERTIES + static AppletQuickItem *qmlAttachedProperties(QObject *object); + + +Q_SIGNALS: +//Property signals + void switchWidthChanged(int width); + void switchHeightChanged(int height); + + void expandedChanged(bool expanded); + + void compactRepresentationChanged(QQmlComponent *compactRepresentation); + void fullRepresentationChanged(QQmlComponent *fullRepresentation); + void preferredRepresentationChanged(QQmlComponent *preferredRepresentation); + + void compactRepresentationItemChanged(QObject *compactRepresentationItem); + void fullRepresentationItemChanged(QObject *fullRepresentationItem); + +protected: + KDeclarative::QmlObject *qmlObject(); + + //Reimplementation + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + virtual void itemChange(ItemChange change, const ItemChangeData &value); + + + +private: + AppletQuickItemPrivate *const d; + + Q_PRIVATE_SLOT(d, void compactRepresentationCheck()) + Q_PRIVATE_SLOT(d, void minimumWidthChanged()) + Q_PRIVATE_SLOT(d, void minimumHeightChanged()) + Q_PRIVATE_SLOT(d, void preferredWidthChanged()) + Q_PRIVATE_SLOT(d, void preferredHeightChanged()) + Q_PRIVATE_SLOT(d, void maximumWidthChanged()) + Q_PRIVATE_SLOT(d, void maximumHeightChanged()) + Q_PRIVATE_SLOT(d, void fillWidthChanged()) + Q_PRIVATE_SLOT(d, void fillHeightChanged()) +}; + +QML_DECLARE_TYPEINFO(AppletQuickItem, QML_HAS_ATTACHED_PROPERTIES) + +#endif diff --git a/src/plasmaquick/configview.cpp b/src/plasmaquick/configview.cpp index cf9c1df19..3fc69973a 100644 --- a/src/plasmaquick/configview.cpp +++ b/src/plasmaquick/configview.cpp @@ -92,7 +92,7 @@ void ConfigViewPrivate::init() delete object; } - q->engine()->rootContext()->setContextProperty("plasmoid", applet->property("graphicObject").value()); + q->engine()->rootContext()->setContextProperty("plasmoid", applet->property("_plasma_graphicObject").value()); q->engine()->rootContext()->setContextProperty("configDialog", q); component->completeCreate(); delete component; diff --git a/src/plasmaquick/plasmaquickview.cpp b/src/plasmaquick/plasmaquickview.cpp index 8485b819d..a7c480a49 100644 --- a/src/plasmaquick/plasmaquickview.cpp +++ b/src/plasmaquick/plasmaquickview.cpp @@ -67,7 +67,7 @@ void PlasmaQuickViewPrivate::setContainment(Plasma::Containment *cont) if (containment) { QObject::disconnect(containment.data(), 0, q, 0); - QObject *oldGraphicObject = containment.data()->property("graphicObject").value(); + QObject *oldGraphicObject = containment.data()->property("_plasma_graphicObject").value(); if (oldGraphicObject) { qDebug() << "Old graphics Object:" << oldGraphicObject << "Old containment" << containment.data(); //make sure the graphic object won't die with us @@ -100,7 +100,7 @@ void PlasmaQuickViewPrivate::setContainment(Plasma::Containment *cont) return; } - QQuickItem *graphicObject = qobject_cast(containment.data()->property("graphicObject").value()); + QQuickItem *graphicObject = qobject_cast(containment.data()->property("_plasma_graphicObject").value()); if (graphicObject) { diff --git a/src/plasmaquick/private/appletquickitem_p.h b/src/plasmaquick/private/appletquickitem_p.h new file mode 100644 index 000000000..7e111136e --- /dev/null +++ b/src/plasmaquick/private/appletquickitem_p.h @@ -0,0 +1,93 @@ +/* + * Copyright 2014 Marco Martin + * + * 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 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. + */ + +#ifndef APPLETQUICKITEM_P_H +#define APPLETQUICKITEM_P_H + +#include + +namespace Plasma { + class Applet; +} + +namespace KDeclarative { + class QmlObject; +} + +class AppletQuickItem; + +class AppletQuickItemPrivate +{ +public: + AppletQuickItemPrivate(Plasma::Applet *a, AppletQuickItem *item); + + QObject *createCompactRepresentationItem(); + QObject *createFullRepresentationItem(); + QObject *createCompactRepresentationExpanderItem(); + + //look into item, and return the Layout attached property, if found + void connectLayoutAttached(QObject *item); + void propagateSizeHint(const QByteArray &layoutProperty); + + //handlers of Layout signals, private slots + void compactRepresentationCheck(); + void minimumWidthChanged(); + void minimumHeightChanged(); + void preferredWidthChanged(); + void preferredHeightChanged(); + void maximumWidthChanged(); + void maximumHeightChanged(); + void fillWidthChanged(); + void fillHeightChanged(); + + + AppletQuickItem *q; + + int switchWidth; + int switchHeight; + + QWeakPointer compactRepresentation; + QWeakPointer fullRepresentation; + QWeakPointer preferredRepresentation; + QWeakPointer compactRepresentationExpander; + + QWeakPointer compactRepresentationItem; + QWeakPointer fullRepresentationItem; + QWeakPointer compactRepresentationExpanderItem; + QWeakPointer currentRepresentationItem; + + //Attached layout objects: own and the representation's one + QWeakPointer representationLayout; + QWeakPointer ownLayout; + + QTimer compactRepresentationCheckTimer; + QTimer fullRepresentationResizeTimer; + + Plasma::Applet *applet; + KDeclarative::QmlObject *qmlObject; + + Plasma::Package appletPackage; + Plasma::Package coronaPackage; + + bool expanded : 1; + + static QHash s_rootObjects; +}; + +#endif diff --git a/src/scriptengines/qml/CMakeLists.txt b/src/scriptengines/qml/CMakeLists.txt index 0a60665ae..b5497b377 100644 --- a/src/scriptengines/qml/CMakeLists.txt +++ b/src/scriptengines/qml/CMakeLists.txt @@ -8,6 +8,8 @@ endif() #DECLARATIVE APPLET set(declarative_appletscript_SRCS + plasmoid/declarativeappletscript.cpp + plasmoid/appletinterface.cpp plasmoid/containmentinterface.cpp plasmoid/declarativeappletscript.cpp diff --git a/src/scriptengines/qml/plasmoid/appletinterface.cpp b/src/scriptengines/qml/plasmoid/appletinterface.cpp index eac58b51c..99a33c602 100644 --- a/src/scriptengines/qml/plasmoid/appletinterface.cpp +++ b/src/scriptengines/qml/plasmoid/appletinterface.cpp @@ -48,20 +48,18 @@ #include #include -#include + Q_DECLARE_METATYPE(AppletInterface*) AppletInterface::AppletInterface(DeclarativeAppletScript *script, QQuickItem *parent) - : QQuickItem(parent), - m_appletScriptEngine(script), + : AppletQuickItem(script->applet(), parent), m_actionSignals(0), + m_appletScriptEngine(script), m_backgroundHints(Plasma::Types::StandardBackground), m_busy(false), - m_expanded(false), m_hideOnDeactivate(true) { - qmlRegisterType(); qmlRegisterType(); connect(this, &AppletInterface::configNeedsSaving, @@ -74,80 +72,39 @@ AppletInterface::AppletInterface(DeclarativeAppletScript *script, QQuickItem *pa connect(applet(), &Plasma::Applet::statusChanged, this, &AppletInterface::statusChanged); - connect(m_appletScriptEngine, &DeclarativeAppletScript::formFactorChanged, + connect(appletScript(), &DeclarativeAppletScript::formFactorChanged, this, &AppletInterface::formFactorChanged); - connect(m_appletScriptEngine, &DeclarativeAppletScript::locationChanged, + connect(appletScript(), &DeclarativeAppletScript::locationChanged, this, &AppletInterface::locationChanged); - connect(m_appletScriptEngine, &DeclarativeAppletScript::contextChanged, + connect(appletScript(), &DeclarativeAppletScript::contextChanged, this, &AppletInterface::contextChanged); if (applet()->containment()) { connect(applet()->containment(), &Plasma::Containment::screenChanged, this, &ContainmentInterface::screenChanged); } - - m_qmlObject = new KDeclarative::QmlObject(this); - m_qmlObject->setInitializationDelayed(true); - - m_collapseTimer = new QTimer(this); - m_collapseTimer->setSingleShot(true); - connect(m_collapseTimer, &QTimer::timeout, this, &AppletInterface::compactRepresentationCheck); } AppletInterface::~AppletInterface() { } +DeclarativeAppletScript *AppletInterface::appletScript() const +{ + return m_appletScriptEngine; +} + void AppletInterface::init() { - if (m_qmlObject->rootObject()) { + if (qmlObject()->rootObject() && m_configuration) { return; } m_configuration = new KDeclarative::ConfigPropertyMap(applet()->configScheme(), this); - //use our own custom network access manager that will access Plasma packages and to manage security (i.e. deny access to remote stuff when the proper extension isn't enabled - QQmlEngine *engine = m_qmlObject->engine(); + AppletQuickItem::init(); - //Hook generic url resolution to the applet package as well - //TODO: same thing will have to be done for every qqmlengine: PackageUrlInterceptor is material for plasmaquick? - PackageUrlInterceptor *interceptor = new PackageUrlInterceptor(engine, m_appletScriptEngine->package()); - interceptor->addAllowedPath(applet()->containment()->corona()->package().path()); - engine->setUrlInterceptor(interceptor); - - m_qmlObject->setSource(QUrl::fromLocalFile(m_appletScriptEngine->mainScript())); - - if (!m_qmlObject->engine() || !m_qmlObject->engine()->rootContext() || !m_qmlObject->engine()->rootContext()->isValid() || m_qmlObject->mainComponent()->isError()) { - QString reason; - foreach (QQmlError error, m_qmlObject->mainComponent()->errors()) { - reason += error.toString()+'\n'; - } - reason = i18n("Error loading QML file: %1", reason); - - m_qmlObject->setSource(QUrl::fromLocalFile(applet()->containment()->corona()->package().filePath("appleterror"))); - m_qmlObject->completeInitialization(); - - - //even the error message QML may fail - if (m_qmlObject->mainComponent()->isError()) { - return; - } else { - m_qmlObject->rootObject()->setProperty("reason", reason); - } - - m_appletScriptEngine->setLaunchErrorMessage(reason); - } - - - m_qmlObject->engine()->rootContext()->setContextProperty("plasmoid", this); - - //initialize size, so an useless resize less - QVariantHash initialProperties; - initialProperties["width"] = width(); - initialProperties["height"] = height(); - m_qmlObject->completeInitialization(initialProperties); - - qDebug() << "Graphic object created:" << applet() << applet()->property("graphicObject"); + qDebug() << "Graphic object created:" << applet() << this; geometryChanged(QRectF(), QRectF(x(), y(), width(), height())); emit busyChanged(); @@ -167,7 +124,11 @@ Plasma::Types::Location AppletInterface::location() const QString AppletInterface::currentActivity() const { - return applet()->containment()->activity(); + if (applet()->containment()) { + return applet()->containment()->activity(); + } else { + return QString(); + } } QObject* AppletInterface::configuration() const @@ -212,7 +173,7 @@ void AppletInterface::setTitle(const QString &title) bool AppletInterface::isBusy() const { - return !m_qmlObject->rootObject() || m_busy; + return m_busy; } void AppletInterface::setBusy(bool busy) @@ -225,23 +186,6 @@ void AppletInterface::setBusy(bool busy) emit busyChanged(); } -bool AppletInterface::isExpanded() const -{ - return m_expanded; -} - -void AppletInterface::setExpanded(bool expanded) -{ - //if there is no compact representation it means it's always expanded - //Containnments are always expanded - if (!m_compactUiObject || qobject_cast(this) || m_expanded == expanded) { - return; - } - - m_expanded = expanded; - emit expandedChanged(); -} - Plasma::Types::BackgroundHints AppletInterface::backgroundHints() const { return m_backgroundHints; @@ -259,7 +203,7 @@ void AppletInterface::setBackgroundHints(Plasma::Types::BackgroundHints hint) void AppletInterface::setConfigurationRequired(bool needsConfiguring, const QString &reason) { - m_appletScriptEngine->setConfigurationRequired(needsConfiguring, reason); + appletScript()->setConfigurationRequired(needsConfiguring, reason); } QString AppletInterface::activeConfig() const @@ -277,7 +221,7 @@ void AppletInterface::setActiveConfig(const QString &name) Plasma::ConfigLoader *loader = m_configs.value(name, 0); if (!loader) { - QString path = m_appletScriptEngine->filePath("config", name + ".xml"); + QString path = appletScript()->filePath("config", name + ".xml"); if (path.isEmpty()) { return; } @@ -307,7 +251,7 @@ void AppletInterface::writeConfig(const QString &entry, const QVariant &value) config->blockSignals(true); config->writeConfig(); config->blockSignals(false); - m_appletScriptEngine->configNeedsSaving(); + appletScript()->configNeedsSaving(); } } else qWarning() << "Couldn't find a configuration entry"; @@ -333,12 +277,12 @@ QVariant AppletInterface::readConfig(const QString &entry) const QString AppletInterface::file(const QString &fileType) { - return m_appletScriptEngine->filePath(fileType, QString()); + return appletScript()->filePath(fileType, QString()); } QString AppletInterface::file(const QString &fileType, const QString &filePath) { - return m_appletScriptEngine->filePath(fileType, filePath); + return appletScript()->filePath(fileType, filePath); } QList AppletInterface::contextualActions() const @@ -392,7 +336,7 @@ void AppletInterface::setAction(const QString &name, const QString &text, const if (!m_actionSignals) { m_actionSignals = new QSignalMapper(this); connect(m_actionSignals, SIGNAL(mapped(QString)), - m_appletScriptEngine, SLOT(executeAction(QString))); + appletScript(), SLOT(executeAction(QString))); } connect(action, SIGNAL(triggered()), m_actionSignals, SLOT(map())); @@ -452,92 +396,6 @@ int AppletInterface::apiVersion() const return offers.first()->property("X-KDE-PluginInfo-Version", QVariant::Int).toInt(); } -bool AppletInterface::fillWidth() const -{ - if (!m_qmlObject->rootObject()) { - return false; - } - - - QVariant prop; - - if (m_compactUiObject) { - prop = m_compactUiObject.data()->property("fillWidth"); - } else { - prop = m_qmlObject->rootObject()->property("fillWidth"); - } - - if (prop.isValid() && prop.canConvert()) { - return prop.toBool(); - } else { - return false; - } -} - -bool AppletInterface::fillHeight() const -{ - if (!m_qmlObject->rootObject()) { - return false; - } - - - QVariant prop; - - if (m_compactUiObject) { - prop = m_compactUiObject.data()->property("fillHeight"); - } else { - prop = m_qmlObject->rootObject()->property("fillHeight"); - } - - if (prop.isValid() && prop.canConvert()) { - return prop.toBool(); - } else { - return false; - } -} - -//private api, just an helper -qreal AppletInterface::readGraphicsObjectSizeHint(const char *hint) const -{ - if (!m_qmlObject->rootObject()) { - return -1; - } - - - QVariant prop; - - if (m_compactUiObject) { - prop = m_compactUiObject.data()->property(hint); - } else { - prop = m_qmlObject->rootObject()->property(hint); - } - - if (prop.isValid() && prop.canConvert()) { - return prop.toReal(); - } else { - return -1; - } -} - -qreal AppletInterface::minimumWidth() const -{ - return readGraphicsObjectSizeHint("minimumWidth"); -} - -qreal AppletInterface::minimumHeight() const -{ - return readGraphicsObjectSizeHint("minimumHeight"); -} - -qreal AppletInterface::maximumWidth() const -{ - return readGraphicsObjectSizeHint("maximumWidth"); -} - -qreal AppletInterface::maximumHeight() const -{ - return readGraphicsObjectSizeHint("maximumHeight"); -} void AppletInterface::setAssociatedApplication(const QString &string) { @@ -601,245 +459,11 @@ QStringList AppletInterface::downloadedFiles() const return dir.entryList(QDir::Files | QDir::NoSymLinks | QDir::Readable); } -void AppletInterface::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +void AppletInterface::executeAction(const QString &name) { - Q_UNUSED(oldGeometry) - - QQuickItem::geometryChanged(newGeometry, oldGeometry); - m_collapseTimer->start(100); -} - -void AppletInterface::compactRepresentationCheck() -{ - if (width() <= 0 || height() <= 0 || !m_qmlObject->rootObject() || - qobject_cast(this)) { - return; + if (qmlObject()->rootObject()) { + QMetaObject::invokeMethod(qmlObject()->rootObject(), QString("action_" + name).toLatin1(), Qt::DirectConnection); } - - //Read the minimum width of the full representation, not our own, since we could be in collapsed mode - QSizeF minHint(-1, -1); - if (m_qmlObject->rootObject()->property("minimumWidth").canConvert()) { - minHint.setWidth(m_qmlObject->rootObject()->property("minimumWidth").toReal()); - } - - if (m_qmlObject->rootObject()->property("minimumHeight").canConvert()) { - minHint.setHeight(m_qmlObject->rootObject()->property("minimumHeight").toReal()); - } - - //Make it an icon - if (width() < minHint.width() || height() < minHint.height()) { - m_expanded = false; - - //we are already an icon: nothing to do - if (m_compactUiObject) { - return; - } - - m_compactUiObject = m_qmlObject->createObjectFromSource(QUrl::fromLocalFile(applet()->containment()->corona()->package().filePath("compactapplet"))); - - QObject *compactRepresentation = 0; - - //build the icon representation - if (m_compactUiObject) { - QQmlComponent *compactComponent = m_qmlObject->rootObject()->property("compactRepresentation").value(); - - if (compactComponent) { - compactRepresentation = compactComponent->create(compactComponent->creationContext()); - } else { - compactRepresentation = m_qmlObject->createObjectFromSource(QUrl::fromLocalFile(applet()->containment()->corona()->package().filePath("defaultcompactrepresentation"))); - } - - if (compactRepresentation && compactComponent) { - compactComponent->setParent(compactRepresentation); - } else { - delete compactComponent; - } - } - - if (m_compactUiObject && compactRepresentation) { - //put compactRepresentation in the icon place - compactRepresentation->setProperty("parent", QVariant::fromValue(m_compactUiObject.data())); - m_compactUiObject.data()->setProperty("compactRepresentation", QVariant::fromValue(compactRepresentation)); - - //replace the full applet with the collapsed view - m_compactUiObject.data()->setProperty("visible", true); - m_compactUiObject.data()->setProperty("parent", QVariant::fromValue(this)); - - { - //set anchors - QQmlExpression expr(m_qmlObject->engine()->rootContext(), m_compactUiObject.data(), "parent"); - QQmlProperty prop(m_compactUiObject.data(), "anchors.fill"); - prop.write(expr.evaluate()); - } - - m_qmlObject->rootObject()->setProperty("parent", QVariant::fromValue(m_compactUiObject.data())); - - - { - //reset all the anchors - QQmlExpression expr(m_qmlObject->engine()->rootContext(), m_qmlObject->rootObject(), "anchors.fill=undefined;anchors.left=undefined;anchors.right=undefined;anchors.top=undefined;anchors.bottom=undefined;"); - expr.evaluate(); - } - - KConfigGroup cg = applet()->config(); - cg = KConfigGroup(&cg, "PopupApplet"); - int width = cg.readEntry("DialogWidth", 0); - int height = cg.readEntry("DialogHeight", 0); - - m_qmlObject->rootObject()->setProperty("width", width); - m_qmlObject->rootObject()->setProperty("height", height); - - m_compactUiObject.data()->setProperty("applet", QVariant::fromValue(m_qmlObject->rootObject())); - - //hook m_compactUiObject size hints to this size hint - //Here we have to use the old connect syntax, because we don't have access to the class type - if (m_qmlObject->rootObject()) { - disconnect(m_qmlObject->rootObject(), 0, this, 0); - } - - //resize of the root object means popup resize when iconified - connect(m_qmlObject->rootObject(), SIGNAL(widthChanged()), - this, SLOT(updatePopupSize())); - connect(m_qmlObject->rootObject(), SIGNAL(heightChanged()), - this, SLOT(updatePopupSize())); - - if (m_compactUiObject.data()->property("minimumWidth").isValid()) { - connect(m_compactUiObject.data(), SIGNAL(minimumWidthChanged()), - this, SIGNAL(minimumWidthChanged())); - } - if (m_compactUiObject.data()->property("minimumHeight").isValid()) { - connect(m_compactUiObject.data(), SIGNAL(minimumHeightChanged()), - this, SIGNAL(minimumHeightChanged())); - } - - if (m_compactUiObject.data()->property("maximumWidth").isValid()) { - connect(m_compactUiObject.data(), SIGNAL(maximumWidthChanged()), - this, SIGNAL(maximumWidthChanged())); - } - if (m_compactUiObject.data()->property("maximumHeight").isValid()) { - connect(m_compactUiObject.data(), SIGNAL(maximumHeightChanged()), - this, SIGNAL(maximumHeightChanged())); - } - - if (m_compactUiObject.data()->property("implicitWidth").isValid()) { - connect(m_compactUiObject.data(), SIGNAL(implicitWidthChanged()), - this, SIGNAL(implicitWidthChanged())); - } - if (m_compactUiObject.data()->property("implicitHeight").isValid()) { - connect(m_compactUiObject.data(), SIGNAL(implicitHeightChanged()), - this, SIGNAL(implicitHeightChanged())); - } - - emit fillWidthChanged(); - emit fillHeightChanged(); - emit minimumWidthChanged(); - emit minimumHeightChanged(); - emit implicitWidthChanged(); - emit implicitHeightChanged(); - emit maximumWidthChanged(); - emit maximumHeightChanged(); - //failed to create UI, don't do anything, return in expanded status - } else { - m_expanded = true; - } - - emit expandedChanged(); - - //show the full UI - } else { - m_expanded = true; - emit expandedChanged(); - - //we are already expanded: nothing to do - if (m_compactUiObject) { - disconnect(m_compactUiObject.data(), 0, this, 0); - } - - disconnect(m_qmlObject->rootObject(), SIGNAL(widthChanged()), - this, SLOT(updatePopupSize())); - disconnect(m_qmlObject->rootObject(), SIGNAL(heightChanged()), - this, SLOT(updatePopupSize())); - - //Here we have to use the old connect syntax, because we don't have access to the class type - if (m_qmlObject->rootObject()->property("minimumWidth").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(minimumWidthChanged()), - this, SIGNAL(minimumWidthChanged())); - } - if (m_qmlObject->rootObject()->property("minimumHeight").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(minimumHeightChanged()), - this, SIGNAL(minimumHeightChanged())); - } - - if (m_qmlObject->rootObject()->property("maximumWidth").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(maximumWidthChanged()), - this, SIGNAL(maximumWidthChanged())); - } - if (m_qmlObject->rootObject()->property("maximumHeight").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(maximumHeightChanged()), - this, SIGNAL(maximumHeightChanged())); - } - - if (m_qmlObject->rootObject()->property("implicitWidth").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(implicitWidthChanged()), - this, SLOT(updateImplicitWidth())); - } - if (m_qmlObject->rootObject()->property("implicitHeight").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(implicitHeightChanged()), - this, SLOT(updateImplicitHeight())); - } - - emit fillWidthChanged(); - emit fillHeightChanged(); - emit minimumWidthChanged(); - emit minimumHeightChanged(); - emit maximumWidthChanged(); - emit maximumHeightChanged(); - - m_qmlObject->rootObject()->setProperty("parent", QVariant::fromValue(this)); - if (m_compactUiObject) { - m_compactUiObject.data()->deleteLater(); - } - - //set anchors - QQmlExpression expr(m_qmlObject->engine()->rootContext(), m_qmlObject->rootObject(), "parent"); - QQmlProperty prop(m_qmlObject->rootObject(), "anchors.fill"); - prop.write(expr.evaluate()); - } -} - -void AppletInterface::updateImplicitWidth() -{ - setImplicitWidth(readGraphicsObjectSizeHint("implicitWidth")); -} - -void AppletInterface::updateImplicitHeight() -{ - setImplicitHeight(readGraphicsObjectSizeHint("implicitHeight")); -} - - -void AppletInterface::updatePopupSize() -{ - KConfigGroup cg = applet()->config(); - cg = KConfigGroup(&cg, "PopupApplet"); - cg.writeEntry("DialogWidth", m_qmlObject->rootObject()->property("width").toInt()); - cg.writeEntry("DialogHeight", m_qmlObject->rootObject()->property("height").toInt()); -} - -void AppletInterface::itemChange(ItemChange change, const ItemChangeData &value) -{ - if (change == QQuickItem::ItemSceneChange) { - //we have a window: create the - if (value.window && !m_qmlObject->rootObject()) { - init(); - } - } - QQuickItem::itemChange(change, value); -} - -KDeclarative::QmlObject *AppletInterface::qmlObject() -{ - return m_qmlObject; } #include "moc_appletinterface.cpp" diff --git a/src/scriptengines/qml/plasmoid/appletinterface.h b/src/scriptengines/qml/plasmoid/appletinterface.h index 7714689fa..7c0c3cd7c 100644 --- a/src/scriptengines/qml/plasmoid/appletinterface.h +++ b/src/scriptengines/qml/plasmoid/appletinterface.h @@ -29,6 +29,7 @@ #include #include +#include #include "declarativeappletscript.h" class QAction; @@ -48,7 +49,7 @@ namespace Plasma class ConfigLoader; } // namespace Plasma -class AppletInterface : public QQuickItem +class AppletInterface : public AppletQuickItem { Q_OBJECT @@ -107,12 +108,6 @@ class AppletInterface : public QQuickItem */ Q_PROPERTY(bool busy WRITE setBusy READ isBusy NOTIFY busyChanged) - /** - * True when the applet is showing its full representation. either as the main only view, or in a popup. - * Setting it will open or close the popup if the plasmoid is iconified, however it won't have effect if the applet is open - */ - Q_PROPERTY(bool expanded WRITE setExpanded READ isExpanded NOTIFY expandedChanged) - /** * How the applet wants its background to be drawn. The containment may chose to ignore this hint. */ @@ -145,22 +140,6 @@ class AppletInterface : public QQuickItem // would be preferrable if found. Q_PROPERTY(int screen READ screen NOTIFY screenChanged) - //Size hints. Note that the containments may chose to not respect them. - Q_PROPERTY(qreal minimumWidth READ minimumWidth NOTIFY minimumWidthChanged) - Q_PROPERTY(qreal minimumHeight READ minimumHeight NOTIFY minimumHeightChanged) - Q_PROPERTY(qreal maximumWidth READ maximumWidth NOTIFY maximumWidthChanged) - Q_PROPERTY(qreal maximumHeight READ maximumHeight NOTIFY maximumHeightChanged) - - /** - * If the plasmoid is in a linear layout, such as a panel, it indicates to take as much horizontal space as possible - */ - Q_PROPERTY(bool fillWidth READ fillWidth NOTIFY fillWidthChanged) - - /** - * If the plasmoid is in a linear layout, such as a panel, it indicates to take as much vertical space as possible - */ - Q_PROPERTY(bool fillHeight READ fillHeight NOTIFY fillHeightChanged) - /** * Whether the dialog should be hidden when the dialog loses focus. * @@ -174,11 +153,12 @@ public: ~AppletInterface(); //API not intended for the QML part - KDeclarative::QmlObject *qmlObject(); + + DeclarativeAppletScript *appletScript() const; QList contextualActions() const; - inline Plasma::Applet *applet() const { return m_appletScriptEngine->applet(); } + void executeAction(const QString &name); //QML API------------------------------------------------------------------- @@ -237,7 +217,11 @@ public: * DEPRECATED: use plasmoid.configuration instead */ Q_INVOKABLE void writeConfig(const QString &entry, const QVariant &value); - + + static AppletInterface *qmlAttachedProperties(QObject *object) + { + return qobject_cast(AppletQuickItem::qmlAttachedProperties(object)); + } //PROPERTY ACCESSORS------------------------------------------------------------------- QString icon() const; @@ -259,9 +243,6 @@ public: bool isBusy() const; void setBusy(bool busy); - bool isExpanded() const; - void setExpanded(bool expanded); - Plasma::Types::BackgroundHints backgroundHints() const; void setBackgroundHints(Plasma::Types::BackgroundHints hint); @@ -283,13 +264,6 @@ public: bool hideOnWindowDeactivate() const; void setHideOnWindowDeactivate(bool hide); - bool fillWidth() const; - bool fillHeight() const; - qreal minimumWidth() const; - qreal minimumHeight() const; - qreal maximumWidth() const; - qreal maximumHeight() const; - Q_SIGNALS: /** * somebody else, usually the containment sent some data to the applet @@ -311,36 +285,15 @@ Q_SIGNALS: void statusChanged(); void backgroundHintsChanged(); void busyChanged(); - void expandedChanged(); void screenChanged(); void hideOnWindowDeactivateChanged(); - void minimumWidthChanged(); - void minimumHeightChanged(); - void maximumWidthChanged(); - void maximumHeightChanged(); - void fillWidthChanged(); - void fillHeightChanged(); void userConfiguringChanged(); -protected: - void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); - void itemChange(ItemChange change, const ItemChangeData &value); - - DeclarativeAppletScript *m_appletScriptEngine; - protected Q_SLOTS: virtual void init(); -private Q_SLOTS: - void compactRepresentationCheck(); - void updatePopupSize(); - void updateImplicitWidth(); - void updateImplicitHeight(); - private: - //Helper for minimumWidth etc. - qreal readGraphicsObjectSizeHint(const char *hint) const; QStringList m_actions; QSignalMapper *m_actionSignals; @@ -349,18 +302,17 @@ private: KDeclarative::ConfigPropertyMap *m_configuration; + DeclarativeAppletScript *m_appletScriptEngine; //UI-specific members ------------------ - KDeclarative::QmlObject *m_qmlObject; - QWeakPointer m_compactUiObject; - QTimer *m_collapseTimer; Plasma::Types::BackgroundHints m_backgroundHints; bool m_busy : 1; - bool m_expanded : 1; bool m_hideOnDeactivate : 1; friend class ContainmentInterface; }; +QML_DECLARE_TYPEINFO(AppletInterface, QML_HAS_ATTACHED_PROPERTIES) + #endif diff --git a/src/scriptengines/qml/plasmoid/containmentinterface.cpp b/src/scriptengines/qml/plasmoid/containmentinterface.cpp index 0d66a54ae..54bcac4b7 100644 --- a/src/scriptengines/qml/plasmoid/containmentinterface.cpp +++ b/src/scriptengines/qml/plasmoid/containmentinterface.cpp @@ -59,8 +59,6 @@ ContainmentInterface::ContainmentInterface(DeclarativeAppletScript *parent) { setAcceptedMouseButtons(Qt::AllButtons); - qmlRegisterType(); - connect(containment(), &Plasma::Containment::appletRemoved, this, &ContainmentInterface::appletRemovedForward); connect(containment(), &Plasma::Containment::appletAdded, @@ -117,15 +115,15 @@ void ContainmentInterface::init() pkg.setPath("org.kde.desktoptoolbox"); } - PackageUrlInterceptor *interceptor = dynamic_cast(m_qmlObject->engine()->urlInterceptor()); + PackageUrlInterceptor *interceptor = dynamic_cast(qmlObject()->engine()->urlInterceptor()); if (interceptor) { interceptor->addAllowedPath(pkg.path()); } if (pkg.isValid()) { - QObject *toolBoxObject = m_qmlObject->createObjectFromSource(QUrl::fromLocalFile(pkg.filePath("mainscript"))); + QObject *toolBoxObject = qmlObject()->createObjectFromSource(QUrl::fromLocalFile(pkg.filePath("mainscript"))); - QObject *containmentGraphicObject = m_qmlObject->rootObject(); + QObject *containmentGraphicObject = qmlObject()->rootObject(); if (containmentGraphicObject && toolBoxObject) { toolBoxObject->setProperty("parent", QVariant::fromValue(containmentGraphicObject)); @@ -142,50 +140,14 @@ void ContainmentInterface::init() //set parent, both as object hyerarchy and visually //do this only for containments, applets will do it in compactrepresentationcheck - if (m_qmlObject->rootObject()) { - m_qmlObject->rootObject()->setProperty("parent", QVariant::fromValue(this)); + if (qmlObject()->rootObject()) { + qmlObject()->rootObject()->setProperty("parent", QVariant::fromValue(this)); //set anchors - QQmlExpression expr(m_qmlObject->engine()->rootContext(), m_qmlObject->rootObject(), "parent"); - QQmlProperty prop(m_qmlObject->rootObject(), "anchors.fill"); + QQmlExpression expr(qmlObject()->engine()->rootContext(), qmlObject()->rootObject(), "parent"); + QQmlProperty prop(qmlObject()->rootObject(), "anchors.fill"); prop.write(expr.evaluate()); } - - if (m_qmlObject->rootObject()->property("minimumWidth").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(minimumWidthChanged()), - this, SIGNAL(minimumWidthChanged())); - } - if (m_qmlObject->rootObject()->property("minimumHeight").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(minimumHeightChanged()), - this, SIGNAL(minimumHeightChanged())); - } - - if (m_qmlObject->rootObject()->property("maximumWidth").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(maximumWidthChanged()), - this, SIGNAL(maximumWidthChanged())); - } - if (m_qmlObject->rootObject()->property("maximumHeight").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(maximumHeightChanged()), - this, SIGNAL(maximumHeightChanged())); - } - - if (m_qmlObject->rootObject()->property("implicitWidth").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(implicitWidthChanged()), - this, SIGNAL(implicitWidthChanged())); - } - if (m_qmlObject->rootObject()->property("implicitHeight").isValid()) { - connect(m_qmlObject->rootObject(), SIGNAL(implicitHeightChanged()), - this, SIGNAL(implicitHeightChanged())); - } - - emit fillWidthChanged(); - emit fillHeightChanged(); - emit minimumWidthChanged(); - emit minimumHeightChanged(); - emit implicitWidthChanged(); - emit implicitHeightChanged(); - emit maximumWidthChanged(); - emit maximumHeightChanged(); } QList ContainmentInterface::applets() @@ -195,12 +157,12 @@ QList ContainmentInterface::applets() Plasma::Types::ContainmentType ContainmentInterface::containmentType() const { - return m_appletScriptEngine->containmentType(); + return appletScript()->containmentType(); } void ContainmentInterface::setContainmentType(Plasma::Types::ContainmentType type) { - m_appletScriptEngine->setContainmentType(type); + appletScript()->setContainmentType(type); } void ContainmentInterface::lockWidgets(bool locked) @@ -242,7 +204,7 @@ Plasma::Applet *ContainmentInterface::addApplet(const QString &plugin, const QVa if (applet) { - QObject *appletGraphicObject = applet->property("graphicObject").value(); + QObject *appletGraphicObject = applet->property("_plasma_graphicObject").value(); blockSignals(false); @@ -259,7 +221,7 @@ void ContainmentInterface::setAppletArgs(Plasma::Applet *applet, const QString & return; } - AppletInterface *appletInterface = applet->property("graphicObject").value(); + AppletInterface *appletInterface = applet->property("_plasma_graphicObject").value(); if (appletInterface) { emit appletInterface->externalData(mimetype, data); } @@ -526,8 +488,8 @@ void ContainmentInterface::appletAddedForward(Plasma::Applet *applet) return; } - QObject *appletGraphicObject = applet->property("graphicObject").value(); - QObject *contGraphicObject = containment()->property("graphicObject").value(); + QObject *appletGraphicObject = applet->property("_plasma_graphicObject").value(); + QObject *contGraphicObject = containment()->property("_plasma_graphicObject").value(); qDebug() << "Applet added on containment:" << containment()->title() << contGraphicObject << "Applet: " << applet << applet->title() << appletGraphicObject; @@ -555,7 +517,7 @@ void ContainmentInterface::appletAddedForward(Plasma::Applet *applet) void ContainmentInterface::appletRemovedForward(Plasma::Applet *applet) { - QObject *appletGraphicObject = applet->property("graphicObject").value(); + QObject *appletGraphicObject = applet->property("_plasma_graphicObject").value(); m_appletInterfaces.removeAll(appletGraphicObject); emit appletRemoved(appletGraphicObject); emit appletsChanged(); diff --git a/src/scriptengines/qml/plasmoid/containmentinterface.h b/src/scriptengines/qml/plasmoid/containmentinterface.h index 67e945eae..cd1adb4d9 100644 --- a/src/scriptengines/qml/plasmoid/containmentinterface.h +++ b/src/scriptengines/qml/plasmoid/containmentinterface.h @@ -70,7 +70,7 @@ class ContainmentInterface : public AppletInterface public: ContainmentInterface(DeclarativeAppletScript *parent); //Not for QML - inline Plasma::Containment *containment() const { return static_cast(m_appletScriptEngine->applet()->containment()); } + Plasma::Containment *containment() const { return static_cast(appletScript()->applet()->containment()); } inline WallpaperInterface *wallpaperInterface() const { return m_wallpaperInterface;} @@ -105,6 +105,11 @@ public: */ Q_INVOKABLE void processMimeData(QMimeData *data, int x, int y); + static ContainmentInterface *qmlAttachedProperties(QObject *object) + { + return qobject_cast(AppletQuickItem::qmlAttachedProperties(object)); + } + protected: void init(); void mousePressEvent(QMouseEvent *event); @@ -159,4 +164,6 @@ private: KActivities::Info *m_activityInfo; }; +QML_DECLARE_TYPEINFO(ContainmentInterface, QML_HAS_ATTACHED_PROPERTIES) + #endif diff --git a/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp b/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp index 9876e8c7c..ab9cd856d 100644 --- a/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp +++ b/src/scriptengines/qml/plasmoid/declarativeappletscript.cpp @@ -42,6 +42,7 @@ #include "plasmoid/appletinterface.h" #include "plasmoid/containmentinterface.h" +#include "plasmoid/wallpaperinterface.h" #include #include @@ -54,7 +55,18 @@ DeclarativeAppletScript::DeclarativeAppletScript(QObject *parent, const QVariant : Plasma::AppletScript(parent), m_interface(0) { - qmlRegisterType(); + //qmlRegisterType(); + //FIXME: use this if/when will be possible to have properties of attached items subclasses on the left hand of expressions + /*qmlRegisterUncreatableType("org.kde.plasma.plasmoid", 2, 0, "Plasmoid", + QLatin1String("Do not create objects of type Plasmoid"));*/ + qmlRegisterUncreatableType("org.kde.plasma.plasmoid", 2, 0, "Plasmoid", + QLatin1String("Do not create objects of type Plasmoid")); + qmlRegisterUncreatableType("org.kde.plasma.plasmoid", 2, 0, "Containment", + QLatin1String("Do not create objects of type Containment")); + + qmlRegisterUncreatableType("org.kde.plasma.plasmoid", 2, 0, "Wallpaper", + QLatin1String("Do not create objects of type Wallpaper")); + qmlRegisterType(); Q_UNUSED(args); } @@ -81,8 +93,6 @@ bool DeclarativeAppletScript::init() } m_interface->setParent(this); - // set the graphicObject dynamic property on applet - a->setProperty("graphicObject", QVariant::fromValue(m_interface)); return true; } @@ -109,9 +119,7 @@ void DeclarativeAppletScript::constraintsEvent(Plasma::Types::Constraints constr void DeclarativeAppletScript::executeAction(const QString &name) { - if (m_interface->qmlObject()->rootObject()) { - QMetaObject::invokeMethod(m_interface->qmlObject()->rootObject(), QString("action_" + name).toLatin1(), Qt::DirectConnection); - } + m_interface->executeAction(name); } QList DeclarativeAppletScript::contextualActions() diff --git a/src/scriptengines/qml/plasmoid/declarativeappletscript.h b/src/scriptengines/qml/plasmoid/declarativeappletscript.h index 1649e5dd8..a3257ab7e 100644 --- a/src/scriptengines/qml/plasmoid/declarativeappletscript.h +++ b/src/scriptengines/qml/plasmoid/declarativeappletscript.h @@ -56,6 +56,7 @@ Q_SIGNALS: private: AppletInterface *m_interface; + friend class AppletLoader; friend class AppletInterface; friend class ContainmentInterface; }; diff --git a/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp b/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp index 1d5f80d9d..88099f185 100644 --- a/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp +++ b/src/scriptengines/qml/plasmoid/wallpaperinterface.cpp @@ -36,6 +36,8 @@ #include #include +QHash WallpaperInterface::s_rootObjects = QHash(); + WallpaperInterface::WallpaperInterface(ContainmentInterface *parent) : QQuickItem(parent), m_containmentInterface(parent), @@ -55,7 +57,9 @@ WallpaperInterface::WallpaperInterface(ContainmentInterface *parent) } WallpaperInterface::~WallpaperInterface() -{} +{ + s_rootObjects.remove(m_qmlObject->engine()); +} KPluginInfo::List WallpaperInterface::listWallpaperInfoForMimetype(const QString &mimetype, const QString &formFactor) { @@ -109,6 +113,7 @@ void WallpaperInterface::syncWallpaperPackage() if (!m_qmlObject) { m_qmlObject = new KDeclarative::QmlObject(this); + s_rootObjects[m_qmlObject->engine()] = this; m_qmlObject->setInitializationDelayed(true); } @@ -142,6 +147,7 @@ void WallpaperInterface::syncWallpaperPackage() } else if (m_qmlObject->mainComponent()) { qWarning() << "Error loading the wallpaper" << m_qmlObject->mainComponent()->errors(); + s_rootObjects.remove(m_qmlObject->engine()); m_qmlObject->deleteLater(); m_qmlObject = 0; diff --git a/src/scriptengines/qml/plasmoid/wallpaperinterface.h b/src/scriptengines/qml/plasmoid/wallpaperinterface.h index 8750dc03f..8a4621f9e 100644 --- a/src/scriptengines/qml/plasmoid/wallpaperinterface.h +++ b/src/scriptengines/qml/plasmoid/wallpaperinterface.h @@ -21,6 +21,7 @@ #define WALLPAPERINTERFACE_H #include +#include #include @@ -78,6 +79,17 @@ public: Q_INVOKABLE QAction *action(QString name) const; + static WallpaperInterface *qmlAttachedProperties(QObject *object) + { + //at the moment of the attached object creation, the root item is the only one that hasn't a parent + //only way to avoid creation of this attached for everybody but the root item + if (!object->parent() && s_rootObjects.contains(QtQml::qmlEngine(object))) { + return s_rootObjects.value(QtQml::qmlEngine(object)); + } else { + return 0; + } + } + Q_SIGNALS: void packageChanged(); void configurationChanged(); @@ -95,6 +107,10 @@ private: Plasma::ConfigLoader *m_configLoader; KActionCollection *m_actions; QSignalMapper *m_actionSignals; + + static QHash s_rootObjects; }; +QML_DECLARE_TYPEINFO(WallpaperInterface, QML_HAS_ATTACHED_PROPERTIES) + #endif diff --git a/src/shell/scripting/panel.cpp b/src/shell/scripting/panel.cpp index ee66c400e..8f268d020 100644 --- a/src/shell/scripting/panel.cpp +++ b/src/shell/scripting/panel.cpp @@ -182,7 +182,7 @@ void Panel::setOffset(int pixels) return; } - QQuickItem *graphicObject = qobject_cast(c->property("graphicObject").value()); + QQuickItem *graphicObject = qobject_cast(c->property("_plasma_graphicObject").value()); if (!graphicObject) { return; @@ -222,7 +222,7 @@ int Panel::length() const if (!c) { return 0; } - QQuickItem *graphicObject = qobject_cast(c->property("graphicObject").value()); + QQuickItem *graphicObject = qobject_cast(c->property("_plasma_graphicObject").value()); if (!graphicObject) { return 0; @@ -242,7 +242,7 @@ void Panel::setLength(int pixels) return; } - QQuickItem *graphicObject = qobject_cast(c->property("graphicObject").value()); + QQuickItem *graphicObject = qobject_cast(c->property("_plasma_graphicObject").value()); if (!graphicObject) { return; @@ -279,7 +279,7 @@ int Panel::height() const return 0; } - QQuickItem *graphicObject = qobject_cast(c->property("graphicObject").value()); + QQuickItem *graphicObject = qobject_cast(c->property("_plasma_graphicObject").value()); if (!graphicObject) { return 0; @@ -296,7 +296,7 @@ void Panel::setHeight(int height) return; } - QQuickItem *graphicObject = qobject_cast(c->property("graphicObject").value()); + QQuickItem *graphicObject = qobject_cast(c->property("_plasma_graphicObject").value()); if (!graphicObject) { return; diff --git a/tools/port-plasma2.sh b/tools/port-plasma2.sh index 3ce1a3c86..d4f398339 100755 --- a/tools/port-plasma2.sh +++ b/tools/port-plasma2.sh @@ -138,5 +138,19 @@ for FS in `find $PWD -name '*.h' -o -name '*.cpp'`; do perl -p -i -e 's/Plasma\:\:AcceptingInputStatus/Plasma::Types::AcceptingInputStatus/g' $FS done +# make compactrepresentation come from Plasmoid.* +# size hints come from Layout +for FS in `find $PWD -type f -name '*.qml'`; do + perl -p -i -e 's/property Component compactRepresentation/Plasmoid.compactRepresentation/g' $FS + perl -p -i -e 's/property int minimumWidth/Layout.minimumWidth/g' $FS + perl -p -i -e 's/property int minimumHeight/Layout.minimumHeight/g' $FS + perl -p -i -e 's/property int maximumWidth/Layout.maximumWidth/g' $FS + perl -p -i -e 's/property int maximumHeight/Layout.maximumHeight/g' $FS + perl -p -i -e 's/property bool fillWidth/Layout.fillWidth/g' $FS + perl -p -i -e 's/property bool fillHeight/Layout.fillHeight/g' $FS +done +for FS in `find $PWD -type f -name '*main.qml'`; do + perl -p -i -e 's/QtQuick 2.0/QtQuick 2.0\nimport org.kde.plasma.plasmoid 2.0/g' $FS +done