diff --git a/shell/CMakeLists.txt b/shell/CMakeLists.txt index f69f1d25e..529e543bf 100644 --- a/shell/CMakeLists.txt +++ b/shell/CMakeLists.txt @@ -48,6 +48,7 @@ qt5_add_dbus_adaptor(scripting_SRC ${plasmashell_dbusXML} shellcorona.h ShellCor set (plasma_shell_SRCS activity.cpp + alternativesdialog.cpp main.cpp containmentconfigview.cpp currentcontainmentactionsmodel.cpp diff --git a/shell/alternativesdialog.cpp b/shell/alternativesdialog.cpp new file mode 100644 index 000000000..56d686ded --- /dev/null +++ b/shell/alternativesdialog.cpp @@ -0,0 +1,101 @@ +/* + * 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 "alternativesdialog.h" + +#include +#include + +#include +#include +#include +#include +#include + +AlternativesDialog::AlternativesDialog(Plasma::Applet *applet, QQuickItem *parent) + : PlasmaQuick::Dialog(parent), + m_applet(applet) +{ + setVisualParent(applet->property("_plasma_graphicObject").value()); + connect(applet, &QObject::destroyed, this, &AlternativesDialog::close); + setLocation(applet->location()); + setFlags(flags()|Qt::WindowStaysOnTopHint); + //We already have the proper shellpluginloader + Plasma::Package pkg; + if (applet && applet->containment() && applet->containment()->corona()) { + pkg = applet->containment()->corona()->package(); + } + //TODO: use the proper package: we must be in the corona + pkg.setPath("org.kde.plasma.desktop"); + + m_qmlObj = new KDeclarative::QmlObject(this); + m_qmlObj->setInitializationDelayed(true); + m_qmlObj->setSource(QUrl::fromLocalFile(pkg.filePath("explorer", "AppletAlternatives.qml"))); + m_qmlObj->engine()->rootContext()->setContextProperty("alternativesDialog", this); + m_qmlObj->completeInitialization(); + setMainItem(qobject_cast(m_qmlObj->rootObject())); +} + +AlternativesDialog::~AlternativesDialog() +{ +} + +QStringList AlternativesDialog::appletProvides() const +{ + return m_applet->pluginInfo().property("X-Plasma-Provides").value(); +} + +QString AlternativesDialog::currentPlugin() const +{ + return m_applet->pluginInfo().pluginName(); +} + +void AlternativesDialog::loadAlternative(const QString &plugin) +{ + if (plugin == m_applet->pluginInfo().pluginName() || m_applet->isContainment()) { + return; + } + + Plasma::Containment *cont = m_applet->containment(); + if (!cont) { + return; + } + + QQuickItem *appletItem = m_applet->property("_plasma_graphicObject").value(); + QQuickItem *contItem = cont->property("_plasma_graphicObject").value(); + if (!appletItem || !contItem) { + return; + } + + //TODO: map the position to containment coordinates + QMetaObject::invokeMethod(contItem, "createApplet", Q_ARG(QString, plugin), Q_ARG(QVariantList, QVariantList()), Q_ARG(QPoint, appletItem->mapToItem(contItem, QPointF(0,0)).toPoint())); + + m_applet->destroy(); +} + +//To emulate Qt::WA_DeleteOnClose that QWindow doesn't have +void AlternativesDialog::hideEvent(QHideEvent *ev) +{ + QQuickWindow::hideEvent(ev); + deleteLater(); +} + +#include "moc_alternativesdialog.cpp" + diff --git a/shell/alternativesdialog.h b/shell/alternativesdialog.h new file mode 100644 index 000000000..195b69a30 --- /dev/null +++ b/shell/alternativesdialog.h @@ -0,0 +1,55 @@ +/* + * 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 ALTERNATIVESDIALOG_H +#define ALTERNATIVESDIALOG_H + +#include + +#include + +namespace KDeclarative { + class QmlObject; +} + +//FIXME: this thing really ought to be in the shell +class AlternativesDialog : public PlasmaQuick::Dialog +{ + Q_OBJECT + Q_PROPERTY(QStringList appletProvides READ appletProvides CONSTANT) + Q_PROPERTY(QString currentPlugin READ currentPlugin CONSTANT) + +public: + AlternativesDialog(Plasma::Applet *applet, QQuickItem *parent = 0); + ~AlternativesDialog(); + + QStringList appletProvides() const; + QString currentPlugin() const; + + Q_INVOKABLE void loadAlternative(const QString &plugin); + +protected: + void hideEvent(QHideEvent *ev); + +private: + Plasma::Applet *m_applet; + KDeclarative::QmlObject *m_qmlObj; +}; + +#endif diff --git a/shell/plasmaquick/dialog.h b/shell/plasmaquick/dialog.h new file mode 100644 index 000000000..6759a6ea3 --- /dev/null +++ b/shell/plasmaquick/dialog.h @@ -0,0 +1,207 @@ +/*************************************************************************** + * Copyright 2011 Marco Martin * + * Copyright 2013 Sebastian Kügler * + * * + * 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 DIALOG_PROXY_P +#define DIALOG_PROXY_P + +#include +#include +#include +#include +#include + +#include +#include + +#include + +// +// W A R N I N G +// ------------- +// +// This file is not part of the public Plasma API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +class QQuickItem; +class QScreen; + + +namespace PlasmaQuick { + +class DialogPrivate; + +/** + * QML wrapper for dialogs + * + * Exposed as `PlasmaCore.Dialog` in QML. + */ +class Dialog : public QQuickWindow, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + + /** + * The main QML item that will be displayed in the Dialog + */ + Q_PROPERTY(QQuickItem *mainItem READ mainItem WRITE setMainItem NOTIFY mainItemChanged) + + /** + * The main QML item that will be displayed in the Dialog + */ + Q_PROPERTY(QQuickItem *visualParent READ visualParent WRITE setVisualParent NOTIFY visualParentChanged) + + /** + * Margins of the dialog around the mainItem. + * @see DialogMargins + */ + Q_PROPERTY(QObject *margins READ margins CONSTANT) + + /** + * Plasma Location of the dialog window. Useful if this dialog is a popup for a panel + */ + Q_PROPERTY(Plasma::Types::Location location READ location WRITE setLocation NOTIFY locationChanged) + + /** + * Type of the window + */ + Q_PROPERTY(WindowType type READ type WRITE setType NOTIFY typeChanged) + + /** + * Whether the dialog should be hidden when the dialog loses focus. + * + * The default value is @c false. + **/ + Q_PROPERTY(bool hideOnWindowDeactivate READ hideOnWindowDeactivate WRITE setHideOnWindowDeactivate NOTIFY hideOnWindowDeactivateChanged) + + /** + * Whether the dialog is output only. Default value is @c false. If it is @c true + * the dialog does not accept input and all pointer events are not accepted, thus the dialog + * is click through. + * + * This property is currently only supported on the X11 platform. On any other platform the + * property has no effect. + **/ + Q_PROPERTY(bool outputOnly READ isOutputOnly WRITE setOutputOnly NOTIFY outputOnlyChanged) + + /** + * This property holds the window flags of the window. + * The window flags control the window's appearance in the windowing system, + * whether it's a dialog, popup, or a regular window, and whether it should + * have a title bar, etc. + * Regardless to what the user sets, the flags will always have the + * FramelessWindowHint flag set + */ + Q_PROPERTY(Qt::WindowFlags flags READ flags WRITE setFramelessFlags NOTIFY flagsChanged) + + Q_CLASSINFO("DefaultProperty", "mainItem") + +public: + enum WindowType { + Normal = NET::Normal, + Dock = NET::Dock, + DialogWindow = NET::Dialog, + PopupMenu = NET::PopupMenu, + Tooltip = NET::Tooltip, + Notification = NET::Notification + }; + Q_ENUMS(WindowType) + + Dialog(QQuickItem *parent = 0); + ~Dialog(); + + //PROPERTIES ACCESSORS + QQuickItem *mainItem() const; + void setMainItem(QQuickItem *mainItem); + + QQuickItem *visualParent() const; + void setVisualParent(QQuickItem *visualParent); + + Plasma::Types::Location location() const; + void setLocation(Plasma::Types::Location location); + + QObject *margins() const; + + void setFramelessFlags(Qt::WindowFlags flags); + + void setType(WindowType type); + WindowType type() const; + + bool hideOnWindowDeactivate() const; + void setHideOnWindowDeactivate(bool hide); + + void setOutputOnly(bool outputOnly); + bool isOutputOnly() const; + + /** + * @returns The suggested screen position for the popup + * @arg item the item the popup has to be positioned relatively to. if null, the popup will be positioned in the center of the window + * @arg alignment alignment of the popup compared to the item + */ + virtual QPoint popupPosition(QQuickItem *item, const QSize &size); + +Q_SIGNALS: + void mainItemChanged(); + void locationChanged(); + void visualParentChanged(); + void typeChanged(); + void hideOnWindowDeactivateChanged(); + void outputOnlyChanged(); + void flagsChanged(); + +protected: + /* + * set the dialog position. subclasses may change it. ToolTipDialog adjusts the position in an animated way + */ + virtual void adjustGeometry(const QRect &geom); + + //Reimplementations + virtual void classBegin(); + virtual void componentComplete(); + virtual void resizeEvent(QResizeEvent *re); + virtual void focusInEvent(QFocusEvent *ev); + virtual void focusOutEvent(QFocusEvent *ev); + virtual void showEvent(QShowEvent *event); + virtual void hideEvent(QHideEvent *event); + virtual bool event(QEvent *event); + +private: + friend class DialogPrivate; + DialogPrivate *const d; + + Q_PRIVATE_SLOT(d, void syncBorders()) + Q_PRIVATE_SLOT(d, void updateContrast()) + Q_PRIVATE_SLOT(d, void updateVisibility(bool visible)) + + Q_PRIVATE_SLOT(d, void updateMinimumWidth()) + Q_PRIVATE_SLOT(d, void updateMinimumHeight()) + Q_PRIVATE_SLOT(d, void updateMaximumWidth()) + Q_PRIVATE_SLOT(d, void updateMaximumHeight()) + + Q_PRIVATE_SLOT(d, void syncMainItemToSize()) + Q_PRIVATE_SLOT(d, void syncToMainItemSize()) + Q_PRIVATE_SLOT(d, void requestSyncToMainItemSize(bool delayed)) +}; + +} + +#endif diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp index dc8b9b6f4..1d92cf8d1 100644 --- a/shell/shellcorona.cpp +++ b/shell/shellcorona.cpp @@ -48,7 +48,7 @@ #include "config-ktexteditor.h" // HAVE_KTEXTEDITOR - +#include "alternativesdialog.h" #include "activity.h" #include "desktopview.h" #include "panelview.h" @@ -107,6 +107,7 @@ public: QWeakPointer console; #endif + QPointer alternativesDialog; KScreen::Config *screenConfiguration; QTimer waitingPanelsTimer; QTimer appConfigSyncTimer; @@ -415,6 +416,15 @@ void ShellCorona::screenInvariants() const } } +void ShellCorona::showAlternativesForApplet(Plasma::Applet *applet) +{ + if (!d->alternativesDialog) { + d->alternativesDialog = new AlternativesDialog(applet); + } + + d->alternativesDialog->show(); +} + void ShellCorona::unload() { @@ -823,6 +833,8 @@ void ShellCorona::handleContainmentAdded(Plasma::Containment *c) { connect(c, &Plasma::Containment::showAddWidgetsInterface, this, &ShellCorona::toggleWidgetExplorer); + connect(c, &Plasma::Containment::appletAlternativesRequested, + this, &ShellCorona::showAlternativesForApplet); } void ShellCorona::toggleWidgetExplorer() diff --git a/shell/shellcorona.h b/shell/shellcorona.h index 2f9de03b1..2228b7632 100644 --- a/shell/shellcorona.h +++ b/shell/shellcorona.h @@ -135,6 +135,8 @@ protected Q_SLOTS: int screenForContainment(const Plasma::Containment *containment) const; + void showAlternativesForApplet(Plasma::Applet *applet); + private Q_SLOTS: void createWaitingPanels(); void handleContainmentAdded(Plasma::Containment *c); diff --git a/shell/widgetexplorer/plasmaappletitemmodel.cpp b/shell/widgetexplorer/plasmaappletitemmodel.cpp index a0307d91c..2f391d703 100644 --- a/shell/widgetexplorer/plasmaappletitemmodel.cpp +++ b/shell/widgetexplorer/plasmaappletitemmodel.cpp @@ -230,7 +230,18 @@ void PlasmaAppletItemModel::populateModel(const QStringList &whatChanged) //qDebug() << "number of applets is" // << Plasma::Applet::listAppletInfo(QString(), m_application).count(); - KService::List services = KServiceTypeTrader::self()->query("Plasma/Applet", QString()); + + QString constraint; + bool first = true; + foreach (const QString prov, m_provides) { + if (!first) { + constraint += " or "; + first = false; + } + constraint += "'" + prov + "' in [X-Plasma-Provides]"; + } + + KService::List services = KServiceTypeTrader::self()->query("Plasma/Applet", constraint); foreach (const QExplicitlySharedDataPointer service, services) { KPluginInfo info(service); @@ -348,6 +359,21 @@ void PlasmaAppletItemModel::setFavorite(const QString &plugin, bool favorite) m_configGroup.sync(); } +QStringList PlasmaAppletItemModel::provides() const +{ + return m_provides; +} + +void PlasmaAppletItemModel::setProvides(const QStringList &provides) +{ + if (m_provides == provides) { + return; + } + + m_provides = provides; + populateModel(); +} + void PlasmaAppletItemModel::setApplication(const QString &app) { m_application = app; diff --git a/shell/widgetexplorer/plasmaappletitemmodel_p.h b/shell/widgetexplorer/plasmaappletitemmodel_p.h index ebaa948a0..f9cc89f40 100644 --- a/shell/widgetexplorer/plasmaappletitemmodel_p.h +++ b/shell/widgetexplorer/plasmaappletitemmodel_p.h @@ -107,12 +107,16 @@ public: QString &Application(); + QStringList provides() const; + void setProvides(const QStringList &provides); + Q_SIGNALS: void modelPopulated(); private: QString m_application; QStringList m_favorites; + QStringList m_provides; KConfigGroup m_configGroup; private Q_SLOTS: diff --git a/shell/widgetexplorer/widgetexplorer.cpp b/shell/widgetexplorer/widgetexplorer.cpp index cef377c38..0ad5cc851 100644 --- a/shell/widgetexplorer/widgetexplorer.cpp +++ b/shell/widgetexplorer/widgetexplorer.cpp @@ -328,6 +328,22 @@ QString WidgetExplorer::application() return d->application; } +QStringList WidgetExplorer::provides() const +{ + return d->itemModel.provides(); +} + +void WidgetExplorer::setProvides(const QStringList &provides) +{ + if (d->itemModel.provides() == provides) { + return; + } + + d->itemModel.setProvides(provides); + emit providesChanged(); +} + + void WidgetExplorer::setContainment(Plasma::Containment *containment) { if (d->containment != containment) { diff --git a/shell/widgetexplorer/widgetexplorer.h b/shell/widgetexplorer/widgetexplorer.h index 2578574fa..4d089c6e4 100644 --- a/shell/widgetexplorer/widgetexplorer.h +++ b/shell/widgetexplorer/widgetexplorer.h @@ -80,6 +80,12 @@ class WidgetExplorer : public QObject */ Q_PROPERTY(QString application READ application WRITE setApplication NOTIFY applicationChanged) + /** + * Set the features the listed applets must provide: needed for listing alternatives + * to a particular applet + */ + Q_PROPERTY(QStringList provides READ provides WRITE setProvides NOTIFY providesChanged) + Q_PROPERTY(Plasma::Containment *containment READ containment WRITE setContainment NOTIFY containmentChanged) public: @@ -97,6 +103,9 @@ public: */ void setApplication(const QString &application = QString()); + QStringList provides() const; + void setProvides(const QStringList &provides); + /** * Changes the current default containment to add applets to * @@ -131,6 +140,7 @@ Q_SIGNALS: void viewChanged(); void applicationChanged(); void containmentChanged(); + void providesChanged(); public Q_SLOTS: /**