diff --git a/declarativeimports/plasmacomponents/CMakeLists.txt b/declarativeimports/plasmacomponents/CMakeLists.txt index 6e4b46d43..a9f951288 100644 --- a/declarativeimports/plasmacomponents/CMakeLists.txt +++ b/declarativeimports/plasmacomponents/CMakeLists.txt @@ -1,12 +1,14 @@ project(plasmacomponents) set(plasmacomponents_SRCS + fullscreendialog.cpp plasmacomponentsplugin.cpp qrangemodel.cpp enums.cpp qmenu.cpp qmenuitem.cpp kdialogproxy.cpp + ../core/declarativeitemcontainer.cpp ) INCLUDE_DIRECTORIES( @@ -19,7 +21,7 @@ qt4_automoc(${plasmacomponents_SRCS}) add_library(plasmacomponentsplugin SHARED ${plasmacomponents_SRCS}) -target_link_libraries(plasmacomponentsplugin ${QT_QTCORE_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDEUI_LIBRARY}) +target_link_libraries(plasmacomponentsplugin ${QT_QTCORE_LIBRARY} ${QT_QTDECLARATIVE_LIBRARY} ${QT_QTGUI_LIBRARY} ${KDE4_KDEUI_LIBRARY} ${KDE4_PLASMA_LIBS}) install(TARGETS plasmacomponentsplugin DESTINATION ${IMPORTS_INSTALL_DIR}/org/kde/plasma/components) diff --git a/declarativeimports/plasmacomponents/fullscreendialog.cpp b/declarativeimports/plasmacomponents/fullscreendialog.cpp new file mode 100644 index 000000000..dae1c2582 --- /dev/null +++ b/declarativeimports/plasmacomponents/fullscreendialog.cpp @@ -0,0 +1,304 @@ +/*************************************************************************** + * Copyright 2012 Marco Martin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU 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 "fullscreendialog.h" +#include "../core/declarativeitemcontainer_p.h" +#include "plasmacomponentsplugin.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +uint FullScreenDialog::s_numItems = 0; + +FullScreenDialog::FullScreenDialog(QDeclarativeItem *parent) + : QDeclarativeItem(parent), + m_declarativeItemContainer(0) +{ + m_view = new QGraphicsView(); + m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_view->installEventFilter(this); + m_view->setAutoFillBackground(false); + m_view->viewport()->setAutoFillBackground(false); + m_view->setAttribute(Qt::WA_TranslucentBackground); + m_view->setAttribute(Qt::WA_NoSystemBackground); + m_view->viewport()->setAttribute(Qt::WA_NoSystemBackground); + m_view->setCacheMode(QGraphicsView::CacheNone); + m_view->setWindowFlags(m_view->windowFlags() | Qt::FramelessWindowHint | Qt::CustomizeWindowHint); + m_view->setFrameShape(QFrame::NoFrame); + KWindowSystem::setOnAllDesktops(m_view->winId(), true); + unsigned long state = NET::Sticky | NET::StaysOnTop | NET::KeepAbove | NET::SkipTaskbar | NET::SkipPager | NET::MaxVert | NET::MaxHoriz; + KWindowSystem::setState(m_view->effectiveWinId(), state); + + //Try to figure out the path of the dialog component + QString componentsPlatform = getenv("KDE_PLASMA_COMPONENTS_PLATFORM"); + if (componentsPlatform.isEmpty()) { + KConfigGroup cg(KSharedConfig::openConfig("kdeclarativerc"), "Components-platform"); + componentsPlatform = cg.readEntry("name", "desktop"); + } + + QString filePath; + if (componentsPlatform == "desktop") { + foreach(const QString &importPath, KGlobal::dirs()->findDirs("module", "imports/")) { + filePath = importPath % "org/kde/plasma/components/Dialog.qml"; + QFile f(filePath); + if (f.exists()) { + break; + } + } + } else { + foreach(const QString &importPath, KGlobal::dirs()->findDirs("module", "platformimports/" % componentsPlatform)) { + filePath = importPath % "org/kde/plasma/components/Dialog.qml"; + QFile f(filePath); + if (f.exists()) { + break; + } + } + } + + + QDeclarativeEngine *engine = EngineBookKeeping::self()->engineFor(this); + QDeclarativeComponent *component = new QDeclarativeComponent(engine, filePath, this); + + QDeclarativeContext *creationContext = component->creationContext(); + m_rootObject = component->create(creationContext); + if (component->status() == QDeclarativeComponent::Error) { + kWarning()<errors(); + } + + if (m_rootObject) { + setMainItem(qobject_cast(m_rootObject.data())); + connect(m_rootObject.data(), SIGNAL(statusChanged()), this, SLOT(statusHasChanged())); + connect(m_rootObject.data(), SIGNAL(accepted()), this, SIGNAL(accepted())); + connect(m_rootObject.data(), SIGNAL(rejected()), this, SIGNAL(rejected())); + connect(m_rootObject.data(), SIGNAL(clickedOutside()), this, SIGNAL(clickedOutside())); + } +} + +FullScreenDialog::~FullScreenDialog() +{ + delete m_view; +} + +QGraphicsObject *FullScreenDialog::mainItem() const +{ + return m_mainItem.data(); +} + +void FullScreenDialog::setMainItem(QGraphicsObject *mainItem) +{ + if (m_mainItem.data() != mainItem) { + if (m_mainItem) { + m_mainItem.data()->setParent(mainItem->parent()); + m_mainItem.data()->removeEventFilter(this); + m_mainItem.data()->setY(0); + m_scene = 0; + } + m_mainItem = mainItem; + if (mainItem) { + mainItem->setParentItem(0); + mainItem->setParent(this); + m_scene = mainItem->scene(); + } + + mainItem->installEventFilter(this); + + //if this is called in Compenent.onCompleted we have to wait a loop the item is added to a scene + QTimer::singleShot(0, this, SLOT(syncMainItem())); + } +} + +void FullScreenDialog::syncMainItem() +{ + if (!m_mainItem) { + return; + } + + //not have a scene? go up in the hyerarchy until we find something with a scene + QGraphicsScene *scene = m_mainItem.data()->scene(); + if (!scene) { + QObject *parent = m_mainItem.data(); + while ((parent = parent->parent())) { + QGraphicsObject *qo = qobject_cast(parent); + if (qo) { + scene = qo->scene(); + + if (scene) { + scene->addItem(m_mainItem.data()); + ++s_numItems; + Plasma::Corona *corona = qobject_cast(scene); + QDeclarativeItem *di = qobject_cast(m_mainItem.data()); + + if (corona && di) { + if (!m_declarativeItemContainer) { + m_declarativeItemContainer = new DeclarativeItemContainer(); + scene->addItem(m_declarativeItemContainer); + corona->addOffscreenWidget(m_declarativeItemContainer); + } + m_declarativeItemContainer->setDeclarativeItem(di); + } else { + m_mainItem.data()->setY(-10000*s_numItems); + m_mainItem.data()->setY(10000*s_numItems); + } + break; + } + } + } + } + + if (!scene) { + return; + } + + m_view->setScene(scene); + + + if (m_declarativeItemContainer) { + m_declarativeItemContainer->resize(m_view->size()); + m_view->setSceneRect(m_declarativeItemContainer->geometry()); + } else { + m_mainItem.data()->setProperty("width", m_view->size().width()); + m_mainItem.data()->setProperty("height", m_view->size().height()); + QRectF itemGeometry(QPointF(m_mainItem.data()->x(), m_mainItem.data()->y()), + QSizeF(m_mainItem.data()->boundingRect().size())); + m_view->setSceneRect(itemGeometry); + } +} + +bool FullScreenDialog::isVisible() const +{ + return m_view->isVisible(); +} + +void FullScreenDialog::setVisible(const bool visible) +{ + if (m_view->isVisible() != visible) { + m_view->setVisible(visible); + if (visible) { + unsigned long state = NET::Sticky | NET::StaysOnTop | NET::KeepAbove | NET::SkipTaskbar | NET::SkipPager | NET::MaxVert | NET::MaxHoriz; + m_view->setVisible(visible); + KWindowSystem::setState(m_view->effectiveWinId(), state); + m_view->raise(); + } + } +} + +QDeclarativeListProperty FullScreenDialog::title() +{ + if (m_rootObject) { + return m_rootObject.data()->property("title").value >(); + } else { + return QDeclarativeListProperty(this, m_dummyTitleElements); + } +} + +QDeclarativeListProperty FullScreenDialog::content() +{ + if (m_rootObject) { + return m_rootObject.data()->property("content").value >(); + } else { + return QDeclarativeListProperty(this, m_dummyContentElements); + } +} + +QDeclarativeListProperty FullScreenDialog::buttons() +{ + if (m_rootObject) { + return m_rootObject.data()->property("buttons").value >(); + } else { + return QDeclarativeListProperty(this, m_dummyButtonsElements); + } +} + +DialogStatus::Status FullScreenDialog::status() const +{ + if (m_rootObject) { + return (DialogStatus::Status)m_rootObject.data()->property("status").toInt(); + } else { + return DialogStatus::Closed; + } +} + + +void FullScreenDialog::statusHasChanged() +{ + if (status() == DialogStatus::Closed) { + setVisible(false); + } else { + setVisible(true); + } + emit statusChanged(); +} + +void FullScreenDialog::open() +{ + if (m_rootObject) { + QMetaObject::invokeMethod(m_rootObject.data(), "open"); + } +} + +void FullScreenDialog::accept() +{ + if (m_rootObject) { + QMetaObject::invokeMethod(m_rootObject.data(), "accept"); + } +} + +void FullScreenDialog::reject() +{ + if (m_rootObject) { + QMetaObject::invokeMethod(m_rootObject.data(), "reject"); + } +} + +void FullScreenDialog::close() +{ + if (m_rootObject) { + QMetaObject::invokeMethod(m_rootObject.data(), "close"); + } +} + + + + +bool FullScreenDialog::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == m_view && + (event->type() == QEvent::Resize || event->type() == QEvent::Move)) { + syncMainItem(); + } + return false; +} + + + +#include "fullscreendialog.moc" + diff --git a/declarativeimports/plasmacomponents/fullscreendialog.h b/declarativeimports/plasmacomponents/fullscreendialog.h new file mode 100644 index 000000000..da79fe6a3 --- /dev/null +++ b/declarativeimports/plasmacomponents/fullscreendialog.h @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright 2012 Marco Martin * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU 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 FULLSCREENDIALOG_P +#define FULLSCREENDIALOG_P + +#include +#include +#include +#include +#include +#include + +#include "enums.h" + +class QGraphicsObject; +class QGraphicsView; +class QGraphicsScene; +class DeclarativeItemContainer; + +class FullScreenDialog : public QDeclarativeItem +{ + Q_OBJECT + + Q_PROPERTY(QDeclarativeListProperty title READ title DESIGNABLE false) + Q_PROPERTY(QDeclarativeListProperty content READ content DESIGNABLE false) + Q_PROPERTY(QDeclarativeListProperty buttons READ buttons DESIGNABLE false) + Q_PROPERTY(DialogStatus::Status status READ status NOTIFY statusChanged) + + +public: + FullScreenDialog(QDeclarativeItem *parent = 0); + ~FullScreenDialog(); + + QGraphicsObject *mainItem() const; + void setMainItem(QGraphicsObject *mainItem); + + bool isVisible() const; + void setVisible(const bool visible); + + + //QML properties + QDeclarativeListProperty title(); + QDeclarativeListProperty content(); + QDeclarativeListProperty buttons(); + DialogStatus::Status status() const; + + Q_INVOKABLE void open(); + Q_INVOKABLE void accept(); + Q_INVOKABLE void reject(); + Q_INVOKABLE void close(); + +Q_SIGNALS: + void accepted(); + void rejected(); + void clickedOutside(); + void statusChanged(); + + +private Q_SLOTS: + void syncMainItem(); + void statusHasChanged(); + +protected: + bool eventFilter(QObject *watched, QEvent *event); + +private: + QGraphicsView *m_view; + QWeakPointer m_mainItem; + DeclarativeItemContainer *m_declarativeItemContainer; + QGraphicsScene *m_scene; + QWeakPointer m_rootObject; + static uint s_numItems; + + //those only used in case of error, to not make plasma crash + QList m_dummyTitleElements; + QList m_dummyContentElements; + QList m_dummyButtonsElements; +}; + +#endif diff --git a/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp b/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp index 3a31a82f8..615cfe845 100644 --- a/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp +++ b/declarativeimports/plasmacomponents/plasmacomponentsplugin.cpp @@ -21,15 +21,65 @@ #include #include +#include +#include #include "qrangemodel.h" #include +#include #include "enums.h" #include "qmenu.h" #include "qmenuitem.h" #include "kdialogproxy.h" +#include "fullscreendialog.h" + +Q_EXPORT_PLUGIN2(plasmacomponentsplugin, PlasmaComponentsPlugin) + +class BKSingleton +{ +public: + EngineBookKeeping self; +}; +K_GLOBAL_STATIC(BKSingleton, privateBKSelf) + +EngineBookKeeping::EngineBookKeeping() +{ +} + +EngineBookKeeping *EngineBookKeeping::self() +{ + return &privateBKSelf->self; +} + +QDeclarativeEngine *EngineBookKeeping::engineFor(QObject *item) const +{return m_engines.values().first(); + foreach (QDeclarativeEngine *engine, m_engines) { + QObject *root = engine->rootContext()->contextObject(); + QObject *candidate = item; + while (candidate) { + if (candidate == root) { + return engine; + } + candidate = candidate->parent(); + } + } + return 0; +} + +void EngineBookKeeping::insertEngine(QDeclarativeEngine *engine) +{ + m_engines.insert(engine); +} + + + +void PlasmaComponentsPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri) +{ + QDeclarativeExtensionPlugin::initializeEngine(engine, uri); + EngineBookKeeping::self()->insertEngine(engine); +} void PlasmaComponentsPlugin::registerTypes(const char *uri) { @@ -41,11 +91,15 @@ void PlasmaComponentsPlugin::registerTypes(const char *uri) componentsPlatform = cg.readEntry("name", "desktop"); } + //platform specific c++ components if (componentsPlatform == "desktop") { qmlRegisterType(uri, 0, 1, "QueryDialog"); qmlRegisterType(uri, 0, 1, "Menu"); qmlRegisterType(uri, 0, 1, "MenuItem"); + //on touch systems the dialog is fullscreen, c++ needed to do that + } else { + qmlRegisterType(uri, 0, 1, "Dialog"); } qmlRegisterType(uri, 0, 1, "RangeModel"); diff --git a/declarativeimports/plasmacomponents/plasmacomponentsplugin.h b/declarativeimports/plasmacomponents/plasmacomponentsplugin.h index 65ca8bdca..11b19ea5f 100644 --- a/declarativeimports/plasmacomponents/plasmacomponentsplugin.h +++ b/declarativeimports/plasmacomponents/plasmacomponentsplugin.h @@ -21,15 +21,32 @@ #define PLASMACOMPONENTSPLUGIN_H #include +#include + +class QDeclarativeEngine; +class QDeclarativeItem; +class PlasmaComponentsPlugin; + +class EngineBookKeeping +{ +public: + EngineBookKeeping(); + static EngineBookKeeping *self(); + + void insertEngine(QDeclarativeEngine *engine); + QDeclarativeEngine *engineFor(QObject *item) const; + +private: + QSet m_engines; +}; class PlasmaComponentsPlugin : public QDeclarativeExtensionPlugin { Q_OBJECT public: + void initializeEngine(QDeclarativeEngine *engine, const char *uri); void registerTypes(const char *uri); }; -Q_EXPORT_PLUGIN2(plasmacomponentsplugin, PlasmaComponentsPlugin) - #endif diff --git a/declarativeimports/plasmacomponents/platformcomponents/touch/Dialog.qml b/declarativeimports/plasmacomponents/platformcomponents/touch/Dialog.qml index f81ca6b5f..e9af7b8cf 100644 --- a/declarativeimports/plasmacomponents/platformcomponents/touch/Dialog.qml +++ b/declarativeimports/plasmacomponents/platformcomponents/touch/Dialog.qml @@ -64,58 +64,76 @@ Item { function open() { - var pos = dialog.popupPosition(null, Qt.alignCenter) - dialog.x = pos.x - dialog.y = pos.y - - dialog.visible = true - dialog.activateWindow() + status = DialogStatus.Opening + delayOpenTimer.restart() } function accept() { if (status == DialogStatus.Open) { - dialog.visible = false + status = DialogStatus.Closing accepted() + dialog.state = "closed" } } - function reject() { + function reject() + { if (status == DialogStatus.Open) { - dialog.visible = false + status = DialogStatus.Closing + dialog.state = "closed" rejected() } } - function close() { - dialog.visible = false + function close() + { + dialog.state = "closed" } - visible: false - - PlasmaCore.Dialog { - id: dialog - windowFlags: Qt.Dialog - - //onFaderClicked: root.clickedOutside() - property Item rootItem - - //state: "Hidden" - visible: false - onVisibleChanged: { - if (visible) { - status = DialogStatus.Open - } else { - status = DialogStatus.Closed - } + Rectangle { + id: fader + property double alpha: 0 + color: Qt.rgba(0.0, 0.0, 0.0, alpha) + anchors.fill: parent + } + MouseArea { + anchors.fill: parent + onClicked: { + clickedOutside() + close() } - onActiveWindowChanged: if (!activeWindow) dialog.visible = false + } + Timer { + id: delayOpenTimer + running: false + interval: 100 + onTriggered: dialog.state = "" + } - mainItem: Item { + PlasmaCore.FrameSvgItem { + id: dialog + width: mainItem.width + margins.left + margins.right + height: mainItem.height + margins.top + margins.bottom + anchors.centerIn: parent + imagePath: "dialogs/background" + + state: "closed" + + transform: Translate { + id: dialogTransform + y: root.height - dialog.y + } + //state: "Hidden" + + Item { id: mainItem + x: dialog.margins.left + y: dialog.margins.top width: theme.defaultFont.mSize.width * 40 height: titleBar.childrenRect.height + contentItem.childrenRect.height + buttonItem.childrenRect.height + 8 + // Consume all key events that are not processed by children Keys.onPressed: event.accepted = true Keys.onReleased: event.accepted = true @@ -160,5 +178,70 @@ Item { Component.onCompleted: { rootItem = Utils.rootObject() } + + states: [ + State { + name: "closed" + PropertyChanges { + target: dialogTransform + y: root.height - dialog.y + } + PropertyChanges { + target: fader + alpha: 0 + } + }, + State { + name: "" + PropertyChanges { + target: dialogTransform + y: 0 + } + PropertyChanges { + target: fader + alpha: 0.6 + } + } + ] + + transitions: [ + // Transition between open and closed states. + Transition { + from: "" + to: "closed" + reversible: false + SequentialAnimation { + ScriptAction { + script: root.status = DialogStatus.Closing + } + PropertyAnimation { + properties: "y, alpha" + easing.type: Easing.InOutQuad + duration: 250 + } + ScriptAction { + script: root.status = DialogStatus.Closed + } + } + }, + Transition { + from: "closed" + to: "" + reversible: false + SequentialAnimation { + ScriptAction { + script: root.status = DialogStatus.Opening + } + PropertyAnimation { + properties: "y, alpha" + easing.type: Easing.InOutQuad + duration: 250 + } + ScriptAction { + script: root.status = DialogStatus.Open + } + } + } + ] } } diff --git a/declarativeimports/plasmacomponents/qmenu.cpp b/declarativeimports/plasmacomponents/qmenu.cpp index 137557308..6e00dbace 100644 --- a/declarativeimports/plasmacomponents/qmenu.cpp +++ b/declarativeimports/plasmacomponents/qmenu.cpp @@ -26,6 +26,7 @@ #include #include +#include "plasmacomponentsplugin.h" QMenuProxy::QMenuProxy (QObject *parent) : QObject(parent), m_status(DialogStatus::Closed) diff --git a/declarativeimports/plasmacomponents/qml/SelectionDialog.qml b/declarativeimports/plasmacomponents/qml/SelectionDialog.qml index c8d418e78..a23c2884c 100644 --- a/declarativeimports/plasmacomponents/qml/SelectionDialog.qml +++ b/declarativeimports/plasmacomponents/qml/SelectionDialog.qml @@ -81,8 +81,6 @@ CommonDialog { property int selectedIndex: -1 property Component delegate: defaultDelegate - privateCloseIcon: true - Component { id: defaultDelegate