diff --git a/containments/desktop/package/contents/config/main.xml b/containments/desktop/package/contents/config/main.xml --- a/containments/desktop/package/contents/config/main.xml +++ b/containments/desktop/package/contents/config/main.xml @@ -37,6 +37,10 @@ + + desktop:/ diff --git a/containments/desktop/package/contents/ui/FolderView.qml b/containments/desktop/package/contents/ui/FolderView.qml --- a/containments/desktop/package/contents/ui/FolderView.qml +++ b/containments/desktop/package/contents/ui/FolderView.qml @@ -58,6 +58,7 @@ property alias scrollUp: gridView.scrollUp property alias scrollDown: gridView.scrollDown property alias hoveredItem: gridView.hoveredItem + property alias screen: dir.screen property var history: [] property Item backButton: null property var dialog: null @@ -1072,6 +1073,9 @@ parseDesktopFiles: (plasmoid.configuration.url == "desktop:/") previews: plasmoid.configuration.previews previewPlugins: plasmoid.configuration.previewPlugins + screen: plasmoid.screen + screenMapper: Folder.ScreenMapper + appletInterface: plasmoid onListingCompleted: { if (!gridView.model && plasmoid.expanded) { diff --git a/containments/desktop/package/contents/ui/FolderViewLayer.qml b/containments/desktop/package/contents/ui/FolderViewLayer.qml --- a/containments/desktop/package/contents/ui/FolderViewLayer.qml +++ b/containments/desktop/package/contents/ui/FolderViewLayer.qml @@ -188,6 +188,18 @@ onPositionsChanged: { folderView.positions = plasmoid.configuration.positions; } + + onScreenMappingChanged: { + Folder.ScreenMapper.screenMapping = plasmoid.configuration.screenMapping; + } + } + + Connections { + target: Folder.ScreenMapper + + onScreenMappingChanged: { + plasmoid.configuration.screenMapping = Folder.ScreenMapper.screenMapping; + } } PlasmaCore.ColorScope { @@ -227,8 +239,10 @@ } Component.onCompleted: { + Folder.ScreenMapper.screenMapping = plasmoid.configuration.screenMapping; folderView.sortMode = plasmoid.configuration.sortMode; folderView.positions = plasmoid.configuration.positions; + folderView.screen = plasmoid.screen; } } } diff --git a/containments/desktop/plugins/folder/CMakeLists.txt b/containments/desktop/plugins/folder/CMakeLists.txt --- a/containments/desktop/plugins/folder/CMakeLists.txt +++ b/containments/desktop/plugins/folder/CMakeLists.txt @@ -20,6 +20,7 @@ viewpropertiesmenu.cpp wheelinterceptor.cpp shortcut.cpp + screenmapper.cpp ) install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/private/desktopcontainment/folder) diff --git a/containments/desktop/plugins/folder/foldermodel.h b/containments/desktop/plugins/folder/foldermodel.h --- a/containments/desktop/plugins/folder/foldermodel.h +++ b/containments/desktop/plugins/folder/foldermodel.h @@ -56,6 +56,8 @@ class DropJob; } +class ScreenMapper; + class DirLister : public KDirLister { Q_OBJECT @@ -94,6 +96,9 @@ Q_PROPERTY(QString filterPattern READ filterPattern WRITE setFilterPattern NOTIFY filterPatternChanged) Q_PROPERTY(QStringList filterMimeTypes READ filterMimeTypes WRITE setFilterMimeTypes NOTIFY filterMimeTypesChanged) Q_PROPERTY(QObject* newMenu READ newMenu CONSTANT) + Q_PROPERTY(int screen READ screen WRITE setScreen NOTIFY screenChanged) + Q_PROPERTY(ScreenMapper* screenMapper READ screenMapper WRITE setScreenMapper NOTIFY screenMapperChanged) + Q_PROPERTY(QObject* appletInterface READ appletInterface WRITE setAppletInterface NOTIFY appletInterfaceChanged); public: enum DataRole { @@ -180,6 +185,15 @@ QStringList filterMimeTypes() const; void setFilterMimeTypes(const QStringList &mimeList); + int screen() const; + void setScreen(int screen); + + ScreenMapper* screenMapper() const; + void setScreenMapper(ScreenMapper* screenMapper); + + QObject *appletInterface() const; + void setAppletInterface(QObject *appletInterface); + KFileItem rootItem() const; Q_INVOKABLE void up(); @@ -254,6 +268,9 @@ void filterModeChanged() const; void filterPatternChanged() const; void filterMimeTypesChanged() const; + void screenChanged() const; + void screenMapperChanged() const; + void appletInterfaceChanged() const; void requestRename() const; void move(int x, int y, QList urls); void popupMenuAboutToShow(KIO::DropJob *dropJob, QMimeData *mimeData, int x, int y); @@ -321,6 +338,9 @@ bool m_filterPatternMatchAll; QSet m_mimeSet; QList m_regExps; + int m_screen = -1; + ScreenMapper *m_screenMapper = nullptr; + QObject *m_appletInterface = nullptr; }; #endif diff --git a/containments/desktop/plugins/folder/foldermodel.cpp b/containments/desktop/plugins/folder/foldermodel.cpp --- a/containments/desktop/plugins/folder/foldermodel.cpp +++ b/containments/desktop/plugins/folder/foldermodel.cpp @@ -24,6 +24,7 @@ #include "foldermodel.h" #include "itemviewadapter.h" #include "positioner.h" +#include "screenmapper.h" #include #include @@ -73,6 +74,9 @@ #include #include #include +#include +#include +#include DirLister::DirLister(QObject *parent) : KDirLister(parent) { @@ -518,6 +522,24 @@ } } +int FolderModel::screen() const +{ + return m_screen; +} + +void FolderModel::setScreen(int screen) +{ + if (m_screen == screen) + return; + + if (m_usedByContainment && m_screenMapper) { + m_screenMapper->registerScreen(screen); + invalidateFilter(); + } + m_screen = screen; + emit screenChanged(); +} + KFileItem FolderModel::rootItem() const { return m_dirModel->dirLister()->rootItem(); @@ -1286,13 +1308,25 @@ bool FolderModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { + const KDirModel *dirModel = static_cast(sourceModel()); + const KFileItem item = dirModel->itemForIndex(dirModel->index(sourceRow, KDirModel::Name, sourceParent)); + + const QString name = item.url().toString(); + if (m_usedByContainment) { + const int screen = m_screenMapper->screenForUrl(name); + if (m_screen != -1) { + if (screen == -1) { + m_screenMapper->addMapping(name, m_screen); + } else if (m_screen != screen) { + return false; + } + } + } + if (m_filterMode == NoFilter) { return true; } - const KDirModel *dirModel = static_cast(sourceModel()); - const KFileItem item = dirModel->itemForIndex(dirModel->index(sourceRow, KDirModel::Name, sourceParent)); - if (m_filterMode == FilterShowMatches) { return (matchPattern(item) && matchMimeType(item)); } else { @@ -1620,6 +1654,53 @@ m_dirModel->dirLister()->updateDirectory(m_dirModel->dirLister()->url()); } +ScreenMapper *FolderModel::screenMapper() const +{ + return m_screenMapper; +} + +void FolderModel::setScreenMapper(ScreenMapper *screenMapper) +{ + if (m_screenMapper == screenMapper) + return; + + m_screenMapper = screenMapper; + if (m_screenMapper && m_screen != -1) { + m_screenMapper->registerScreen(m_screen); + invalidateFilter(); + connect(m_screenMapper, &ScreenMapper::screensChanged, this, &FolderModel::invalidateFilter); + } + emit screenMapperChanged(); +} + +QObject *FolderModel::appletInterface() const +{ + return m_appletInterface; +} + +void FolderModel::setAppletInterface(QObject *appletInterface) +{ + if (m_appletInterface != appletInterface) { + m_appletInterface = appletInterface; + + if (appletInterface) { + + Plasma::Applet *applet = appletInterface->property("_plasma_applet").value(); + Plasma::Containment *containment = applet->containment(); + + if (containment) { + Plasma::Corona *corona = containment->corona(); + + if (corona) { + m_screenMapper->registerCorona(corona); + } + } + } + + emit appletInterfaceChanged(); + } +} + void FolderModel::moveSelectedToTrash() { if (!m_selectionModel->hasSelection()) { diff --git a/containments/desktop/plugins/folder/folderplugin.cpp b/containments/desktop/plugins/folder/folderplugin.cpp --- a/containments/desktop/plugins/folder/folderplugin.cpp +++ b/containments/desktop/plugins/folder/folderplugin.cpp @@ -32,15 +32,28 @@ #include "viewpropertiesmenu.h" #include "wheelinterceptor.h" #include "shortcut.h" +#include "screenmapper.h" +#include +#include static QObject *menuHelperSingletonProvider(QQmlEngine *engine, QJSEngine *jsEngine) { Q_UNUSED(engine); Q_UNUSED(jsEngine); return new MenuHelper(); } +static QObject *screenMapperProvider(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(scriptEngine); + + QObject *mapper = ScreenMapper::instance(); + engine->setObjectOwnership(mapper, QQmlEngine::CppOwnership); + return mapper; +} + + void FolderPlugin::registerTypes(const char *uri) { Q_ASSERT(uri == QLatin1String("org.kde.private.desktopcontainment.folder")); @@ -58,5 +71,6 @@ qmlRegisterType(uri, 0, 1, "ViewPropertiesMenu"); qmlRegisterType(uri, 0, 1, "WheelInterceptor"); qmlRegisterType(uri, 0, 1, "ShortCut"); + qmlRegisterSingletonType(uri, 0, 1, "ScreenMapper", screenMapperProvider); } diff --git a/containments/desktop/plugins/folder/screenmapper.h b/containments/desktop/plugins/folder/screenmapper.h new file mode 100644 --- /dev/null +++ b/containments/desktop/plugins/folder/screenmapper.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company * + * * + * Author: Andras Mantia * + * Work sponsored by the LiMux project of the city of Munich. * * + * * + * 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 SCREENMAPPER_H +#define SCREENMAPPER_H + +#include +#include +#include + +class QScreen; + +namespace Plasma { + class Corona; +} + +class ScreenMapper : public QObject +{ + Q_OBJECT + Q_PROPERTY(QStringList screenMapping READ screenMapping WRITE setScreenMapping NOTIFY screenMappingChanged) + +public: + static ScreenMapper *instance(); + ~ScreenMapper() override = default; + + QStringList screenMapping() const; + void setScreenMapping(const QStringList &mapping); + + int screenForUrl(const QString &url) const; + Q_INVOKABLE void addMapping(const QString &url, int screen); + void registerScreen(int screen); + int firstScreen() const; + void registerCorona(Plasma::Corona *corona); + +Q_SIGNALS: + void screenMappingChanged() const; + void screensChanged() const; + +private: + ScreenMapper(QObject *parent = nullptr); + void handleScreenRemoved(QScreen *screen); + void removeScreen(int screenId); + void handleScreenAdded(QScreen *screen); + void addScreen(int screenId); + + QHash m_screenUrlMap; + QHash m_urlsOnDisabledScreensMap; + int m_firstScreen = -1; + QVector m_availableScreens; + Plasma::Corona *m_corona = nullptr; + static ScreenMapper *s_instance; +}; + +#endif // SCREENMAPPER_H diff --git a/containments/desktop/plugins/folder/screenmapper.cpp b/containments/desktop/plugins/folder/screenmapper.cpp new file mode 100644 --- /dev/null +++ b/containments/desktop/plugins/folder/screenmapper.cpp @@ -0,0 +1,140 @@ +/*************************************************************************** + * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company * + * * + * Author: Andras Mantia * + * Work sponsored by the LiMux project of the city of Munich. * * + * 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 "screenmapper.h" + +#include +#include + +#include + +ScreenMapper* ScreenMapper::s_instance = nullptr; + +ScreenMapper *ScreenMapper::instance() { + if (s_instance) + return s_instance; + + s_instance = new ScreenMapper(); + return s_instance; +} + +ScreenMapper::ScreenMapper(QObject *parent) : QObject(parent) +{ +} + +void ScreenMapper::removeScreen(int screenId) +{ + // store the original location for the items + auto it = m_screenUrlMap.constBegin(); + while (it != m_screenUrlMap.constEnd()) { + if (it.value() == screenId) { + m_urlsOnDisabledScreensMap[screenId].append(it.key()); + } + ++it; + } + + m_availableScreens.removeAll(screenId); + emit screensChanged(); +} + +void ScreenMapper::addScreen(int screenId) +{ + // restore the stored locations + auto it = m_urlsOnDisabledScreensMap.find(screenId); + if (it != m_urlsOnDisabledScreensMap.end()) { + for (const auto &url: it.value()) { + addMapping(url, screenId); + } + m_urlsOnDisabledScreensMap.erase(it); + } + m_availableScreens.append(screenId); + emit screensChanged(); +} + +void ScreenMapper::addMapping(const QString &url, int screen) +{ + m_screenUrlMap[url] = screen; + emit screenMappingChanged(); +} + +void ScreenMapper::registerScreen(int screen) +{ + if (screen < 0) + return; + + if (m_firstScreen == -1 || screen < m_firstScreen) + m_firstScreen = screen; + m_availableScreens.append(screen); +} + +int ScreenMapper::firstScreen() const +{ + return m_firstScreen; +} + +void ScreenMapper::registerCorona(Plasma::Corona *corona) +{ + if (m_corona != corona) { + m_corona = corona; + m_availableScreens.clear(); + if (m_corona) { + connect(m_corona, &Plasma::Corona::screenRemoved, this, &ScreenMapper::removeScreen); + connect(m_corona, &Plasma::Corona::screenAdded, this, &ScreenMapper::addScreen); + } + } +} + +QStringList ScreenMapper::screenMapping() const +{ + QStringList result; + result.reserve(m_screenUrlMap.count() * 2); + auto it = m_screenUrlMap.constBegin(); + while (it != m_screenUrlMap.constEnd()) { + result.append(it.key()); + result.append(QString::number(it.value())); + ++it; + } + + return result; +} + +void ScreenMapper::setScreenMapping(const QStringList &mapping) +{ + QHash newMap; + const int count = mapping.count(); + for (int i = 0; i < count - 1; i += 2) { + if ( i + 1 < count) { + newMap[mapping[i]] = mapping[i + 1].toInt(); + } + } + + if (m_screenUrlMap != newMap) { + m_screenUrlMap = newMap; + emit screenMappingChanged(); + } +} + +int ScreenMapper::screenForUrl(const QString &url) const +{ + int screen = m_screenUrlMap.value(url, -1); + if (!m_availableScreens.contains(screen)) + screen = -1; + return screen; +}