From 3550caa580e468e81d0b464b57f7c67413c0d79f Mon Sep 17 00:00:00 2001 From: Devin Lin Date: Fri, 21 Feb 2025 18:06:24 +0000 Subject: [PATCH] folio: Use smart pointers to manage delegate lifetimes Currently delegates do not get deleted when removed from models. Due to the complexity of drag state and other objects, we can't simply delete the delegate when removed from the model because they might still be involved in animations or other state at the time of removal. Use smart pointers to have the delegate objects deleted instead. QML unfortunately doesn't support QSharedPointer, so we need to expose raw pointers to it. --- .../folio/applicationlistmodel.cpp | 12 +-- .../homescreens/folio/applicationlistmodel.h | 2 +- containments/homescreens/folio/dragstate.cpp | 62 +++++++++------- containments/homescreens/folio/dragstate.h | 19 +++-- .../homescreens/folio/favouritesmodel.cpp | 20 ++--- .../homescreens/folio/favouritesmodel.h | 12 +-- .../homescreens/folio/folioapplication.cpp | 4 +- .../homescreens/folio/folioapplication.h | 6 +- .../folio/folioapplicationfolder.cpp | 44 +++++------ .../folio/folioapplicationfolder.h | 22 +++--- .../homescreens/folio/foliodelegate.cpp | 74 ++++++++++++------- .../homescreens/folio/foliodelegate.h | 60 +++++++++------ .../homescreens/folio/foliowidget.cpp | 6 +- containments/homescreens/folio/foliowidget.h | 8 +- .../homescreens/folio/homescreenstate.cpp | 19 +++-- .../homescreens/folio/homescreenstate.h | 9 ++- containments/homescreens/folio/pagemodel.cpp | 52 +++++++------ containments/homescreens/folio/pagemodel.h | 12 +-- 18 files changed, 250 insertions(+), 193 deletions(-) diff --git a/containments/homescreens/folio/applicationlistmodel.cpp b/containments/homescreens/folio/applicationlistmodel.cpp index c3953239..89b0f25e 100644 --- a/containments/homescreens/folio/applicationlistmodel.cpp +++ b/containments/homescreens/folio/applicationlistmodel.cpp @@ -80,17 +80,17 @@ void ApplicationListModel::load() m_delegates.clear(); - QList unorderedList; + QList unorderedList; const KService::List apps = KApplicationTrader::query(filter); for (const KService::Ptr &service : apps) { - FolioApplication *app = new FolioApplication{m_homeScreen, service}; - FolioDelegate *delegate = new FolioDelegate{app, m_homeScreen}; + FolioApplication::Ptr app = std::make_shared(m_homeScreen, service); + FolioDelegate::Ptr delegate = std::make_shared(app, m_homeScreen); unorderedList << delegate; } - std::sort(unorderedList.begin(), unorderedList.end(), [](FolioDelegate *a1, FolioDelegate *a2) { + std::sort(unorderedList.begin(), unorderedList.end(), [](FolioDelegate::Ptr &a1, FolioDelegate::Ptr &a2) { return a1->application()->name().compare(a2->application()->name(), Qt::CaseInsensitive) < 0; }); @@ -105,12 +105,12 @@ QVariant ApplicationListModel::data(const QModelIndex &index, int role) const return QVariant(); } - FolioDelegate *delegate = m_delegates.at(index.row()); + FolioDelegate::Ptr delegate = m_delegates.at(index.row()); switch (role) { case Qt::DisplayRole: case DelegateRole: - return QVariant::fromValue(delegate); + return QVariant::fromValue(delegate.get()); case NameRole: if (!delegate->application()) { return QVariant(); diff --git a/containments/homescreens/folio/applicationlistmodel.h b/containments/homescreens/folio/applicationlistmodel.h index 5e3a0ed0..0b3534bb 100644 --- a/containments/homescreens/folio/applicationlistmodel.h +++ b/containments/homescreens/folio/applicationlistmodel.h @@ -43,8 +43,8 @@ public Q_SLOTS: protected: HomeScreen *m_homeScreen{nullptr}; - QList m_delegates; + QList> m_delegates; QTimer *m_reloadAppsTimer{nullptr}; }; diff --git a/containments/homescreens/folio/dragstate.cpp b/containments/homescreens/folio/dragstate.cpp index 4947ae7b..6149663b 100644 --- a/containments/homescreens/folio/dragstate.cpp +++ b/containments/homescreens/folio/dragstate.cpp @@ -109,12 +109,17 @@ void DelegateDragPosition::setFolderPosition(int folderPosition) } } -FolioApplicationFolder *DelegateDragPosition::folder() const +FolioApplicationFolder::Ptr DelegateDragPosition::folder() const { return m_folder; } -void DelegateDragPosition::setFolder(FolioApplicationFolder *folder) +FolioApplicationFolder *DelegateDragPosition::folderRaw() const +{ + return m_folder.get(); +} + +void DelegateDragPosition::setFolder(FolioApplicationFolder::Ptr folder) { if (m_folder != folder) { m_folder = folder; @@ -197,12 +202,17 @@ DelegateDragPosition *DragState::startPosition() const return m_startPosition; } -FolioDelegate *DragState::dropDelegate() const +FolioDelegate::Ptr DragState::dropDelegate() const { return m_dropDelegate; } -void DragState::setDropDelegate(FolioDelegate *dropDelegate) +FolioDelegate *DragState::dropDelegateRaw() const +{ + return m_dropDelegate.get(); +} + +void DragState::setDropDelegate(FolioDelegate::Ptr dropDelegate) { m_dropDelegate = dropDelegate; Q_EMIT dropDelegateChanged(); @@ -266,7 +276,7 @@ void DragState::onDelegateDragPositionOverFolderViewChanged() qreal x = getPointerX(); qreal y = getPointerY(); - auto *folder = m_state->currentFolder(); + FolioApplicationFolder::Ptr folder = m_state->currentFolder(); if (!folder) { return; } @@ -370,7 +380,7 @@ void DragState::onDelegateDragPositionOverFavouritesChanged() // start folder open timer if hovering over a folder // get delegate being hovered over - FolioDelegate *delegate = favouritesModel->getEntryAt(dropIndex); + FolioDelegate::Ptr delegate = favouritesModel->getEntryAt(dropIndex); // check delegate is a folder and the drop delegate is an app if (delegate && delegate->type() == FolioDelegate::Folder && m_dropDelegate && m_dropDelegate->type() == FolioDelegate::Application) { @@ -430,7 +440,7 @@ void DragState::onDelegateDragPositionOverPageViewChanged() PageModel *pageModel = m_homeScreen->pageListModel()->getPage(page); if (pageModel) { // get delegate being hovered over - FolioDelegate *delegate = pageModel->getDelegate(row, column); + FolioDelegate::Ptr delegate = pageModel->getDelegate(row, column); // check delegate is a folder and the drop delegate is an app if (delegate && delegate->type() == FolioDelegate::Folder && m_dropDelegate && m_dropDelegate->type() == FolioDelegate::Application) { @@ -495,8 +505,8 @@ void DragState::onDelegateDragFromAppDrawerStarted(QString storageId) { // fetch delegate at start position if (KService::Ptr service = KService::serviceByStorageId(storageId)) { - FolioApplication *app = new FolioApplication{m_homeScreen, service}; - setDropDelegate(new FolioDelegate{app, m_homeScreen}); + FolioApplication::Ptr app = std::make_shared(m_homeScreen, service); + setDropDelegate(std::make_shared(app, m_homeScreen)); } else { setDropDelegate(nullptr); } @@ -511,7 +521,7 @@ void DragState::onDelegateDragFromFolderStarted(FolioApplicationFolder *folder, setDropDelegate(folder->applications()->getDelegate(position)); // set start location - m_startPosition->setFolder(folder); + m_startPosition->setFolder(folder->shared_from_this()); m_startPosition->setFolderPosition(position); m_startPosition->setLocation(DelegateDragPosition::Folder); } @@ -520,8 +530,8 @@ void DragState::onDelegateDragFromWidgetListStarted(QString appletPluginId) { // default widget has dimensions of 1x1, and id of -1 m_createdAppletPluginId = appletPluginId; - FolioWidget *widget = new FolioWidget{m_homeScreen, -1, 1, 1}; - setDropDelegate(new FolioDelegate{widget, m_homeScreen}); + FolioWidget::Ptr widget = std::make_shared(m_homeScreen, -1, 1, 1); + setDropDelegate(std::make_shared(widget, m_homeScreen)); // set start location m_startPosition->setLocation(DelegateDragPosition::WidgetList); @@ -619,7 +629,7 @@ void DragState::onOpenFolderTimerFinished() return; } - FolioApplicationFolder *folder = nullptr; + FolioApplicationFolder::Ptr folder = nullptr; QPointF screenPosition; switch (m_candidateDropPosition->location()) { @@ -631,7 +641,7 @@ void DragState::onOpenFolderTimerFinished() } // get delegate being hovered over - FolioDelegate *delegate = page->getDelegate(m_candidateDropPosition->pageRow(), m_candidateDropPosition->pageColumn()); + FolioDelegate::Ptr delegate = page->getDelegate(m_candidateDropPosition->pageRow(), m_candidateDropPosition->pageColumn()); if (!delegate || delegate->type() != FolioDelegate::Folder) { return; } @@ -643,7 +653,7 @@ void DragState::onOpenFolderTimerFinished() } case DelegateDragPosition::Favourites: { // get delegate being hovered over in favourites bar - FolioDelegate *delegate = m_homeScreen->favouritesModel()->getEntryAt(m_candidateDropPosition->favouritesPosition()); + FolioDelegate::Ptr delegate = m_homeScreen->favouritesModel()->getEntryAt(m_candidateDropPosition->favouritesPosition()); if (!delegate || delegate->type() != FolioDelegate::Folder) { return; } @@ -657,7 +667,7 @@ void DragState::onOpenFolderTimerFinished() } // open the folder - m_state->openFolder(screenPosition.x(), screenPosition.y(), folder); + m_state->openFolder(screenPosition.x(), screenPosition.y(), folder.get()); } void DragState::onLeaveFolderTimerFinished() @@ -678,7 +688,7 @@ void DragState::onChangeFolderPageTimerFinished() return; } - auto *folder = m_state->currentFolder(); + FolioApplicationFolder::Ptr folder = m_state->currentFolder(); qreal x = getPointerX(); qreal y = getPointerY(); @@ -714,7 +724,7 @@ void DragState::onFolderInsertBetweenTimerFinished() return; } - auto *folder = m_state->currentFolder(); + FolioApplicationFolder::Ptr folder = m_state->currentFolder(); // update the candidate drop position m_candidateDropPosition->setFolder(folder); @@ -782,10 +792,10 @@ bool DragState::createDropPositionDelegate() int column = m_candidateDropPosition->pageColumn(); // delegate to add - FolioPageDelegate *delegate = new FolioPageDelegate{row, column, m_dropDelegate, m_homeScreen}; + FolioPageDelegate::Ptr delegate = std::make_shared(row, column, m_dropDelegate, m_homeScreen); // delegate that exists at the drop position - FolioPageDelegate *existingDelegate = page->getDelegate(row, column); + FolioPageDelegate::Ptr existingDelegate = page->getDelegate(row, column); // if a delegate already exists at the spot, check if we can insert/create a folder if (existingDelegate) { @@ -801,10 +811,10 @@ bool DragState::createDropPositionDelegate() } else if (existingDelegate->type() == FolioDelegate::Application && !isStartPositionEqualDropPosition()) { // create a folder from the two apps - FolioApplicationFolder *folder = new FolioApplicationFolder(m_homeScreen, DEFAULT_FOLDER_NAME); + FolioApplicationFolder::Ptr folder = std::make_shared(m_homeScreen, DEFAULT_FOLDER_NAME); folder->addDelegate(delegate, 0); folder->addDelegate(existingDelegate, 0); - FolioPageDelegate *folderDelegate = new FolioPageDelegate{row, column, folder, m_homeScreen}; + FolioPageDelegate::Ptr folderDelegate = std::make_shared(row, column, folder, m_homeScreen); page->removeDelegate(row, column); page->addDelegate(folderDelegate); @@ -828,7 +838,7 @@ bool DragState::createDropPositionDelegate() } case DelegateDragPosition::Favourites: { // delegate that exists at the drop position - FolioDelegate *existingDelegate = m_homeScreen->favouritesModel()->getEntryAt(m_candidateDropPosition->favouritesPosition()); + FolioDelegate::Ptr existingDelegate = m_homeScreen->favouritesModel()->getEntryAt(m_candidateDropPosition->favouritesPosition()); // if a delegate already exists at the spot, check if we can insert/create a folder if (existingDelegate) { @@ -844,10 +854,10 @@ bool DragState::createDropPositionDelegate() } else if (existingDelegate->type() == FolioDelegate::Application && !isStartPositionEqualDropPosition()) { // create a folder from the two apps - FolioApplicationFolder *folder = new FolioApplicationFolder(m_homeScreen, DEFAULT_FOLDER_NAME); + FolioApplicationFolder::Ptr folder = std::make_shared(m_homeScreen, DEFAULT_FOLDER_NAME); folder->addDelegate(m_dropDelegate, 0); folder->addDelegate(existingDelegate, 0); - FolioDelegate *folderDelegate = new FolioDelegate{folder, m_homeScreen}; + FolioDelegate::Ptr folderDelegate = std::make_shared(folder, m_homeScreen); m_homeScreen->favouritesModel()->removeEntry(m_candidateDropPosition->favouritesPosition()); m_homeScreen->favouritesModel()->addEntry(m_candidateDropPosition->favouritesPosition(), folderDelegate); @@ -878,7 +888,7 @@ bool DragState::createDropPositionDelegate() break; } case DelegateDragPosition::Folder: { - auto *folder = m_candidateDropPosition->folder(); + FolioApplicationFolder::Ptr folder = m_candidateDropPosition->folder(); if (!folder) { break; } diff --git a/containments/homescreens/folio/dragstate.h b/containments/homescreens/folio/dragstate.h index 3822424b..32a0d82e 100644 --- a/containments/homescreens/folio/dragstate.h +++ b/containments/homescreens/folio/dragstate.h @@ -23,7 +23,7 @@ class DelegateDragPosition : public QObject Q_PROPERTY(int pageColumn READ pageColumn NOTIFY pageColumnChanged) Q_PROPERTY(int favouritesPosition READ favouritesPosition NOTIFY favouritesPositionChanged) Q_PROPERTY(int folderPosition READ folderPosition NOTIFY folderPositionChanged) - Q_PROPERTY(FolioApplicationFolder *folder READ folder NOTIFY folderChanged) + Q_PROPERTY(FolioApplicationFolder *folder READ folderRaw NOTIFY folderChanged) public: enum Location { Pages, Favourites, AppDrawer, Folder, WidgetList }; @@ -53,8 +53,9 @@ public: void setFolderPosition(int folderPosition); // TODO: what if the folder becomes invalid? we need to clear it - FolioApplicationFolder *folder() const; - void setFolder(FolioApplicationFolder *folder); + std::shared_ptr folder() const; + FolioApplicationFolder *folderRaw() const; + void setFolder(std::shared_ptr folder); Q_SIGNALS: void locationChanged(); @@ -72,7 +73,7 @@ private: int m_pageColumn{0}; int m_favouritesPosition{0}; int m_folderPosition{0}; - FolioApplicationFolder *m_folder{nullptr}; + std::shared_ptr m_folder{nullptr}; }; Q_DECLARE_METATYPE(DelegateDragPosition); @@ -82,15 +83,17 @@ class DragState : public QObject Q_OBJECT Q_PROPERTY(DelegateDragPosition *candidateDropPosition READ candidateDropPosition CONSTANT) Q_PROPERTY(DelegateDragPosition *startPosition READ startPosition CONSTANT) - Q_PROPERTY(FolioDelegate *dropDelegate READ dropDelegate NOTIFY dropDelegateChanged) + Q_PROPERTY(FolioDelegate *dropDelegate READ dropDelegateRaw NOTIFY dropDelegateChanged) public: DragState(HomeScreenState *state = nullptr, HomeScreen *parent = nullptr); DelegateDragPosition *candidateDropPosition() const; DelegateDragPosition *startPosition() const; - FolioDelegate *dropDelegate() const; - void setDropDelegate(FolioDelegate *dropDelegate); + + std::shared_ptr dropDelegate() const; + FolioDelegate *dropDelegateRaw() const; + void setDropDelegate(std::shared_ptr dropDelegate); Q_SIGNALS: void dropDelegateChanged(); @@ -157,7 +160,7 @@ private: int m_favouritesInsertBetweenIndex{0}; // the delegate that is being dropped - FolioDelegate *m_dropDelegate{nullptr}; + std::shared_ptr m_dropDelegate{nullptr}; // where we are hovering over, potentially to drop the delegate DelegateDragPosition *const m_candidateDropPosition{nullptr}; diff --git a/containments/homescreens/folio/favouritesmodel.cpp b/containments/homescreens/folio/favouritesmodel.cpp index cfdf66f3..35fb6079 100644 --- a/containments/homescreens/folio/favouritesmodel.cpp +++ b/containments/homescreens/folio/favouritesmodel.cpp @@ -40,7 +40,7 @@ QVariant FavouritesModel::data(const QModelIndex &index, int role) const switch (role) { case DelegateRole: - return QVariant::fromValue(m_delegates.at(index.row()).delegate); + return QVariant::fromValue(m_delegates.at(index.row()).delegate.get()); } return QVariant(); @@ -90,7 +90,7 @@ void FavouritesModel::moveEntry(int fromRow, int toRow) save(); } -bool FavouritesModel::canAddEntry(int row, FolioDelegate *delegate) +bool FavouritesModel::canAddEntry(int row, FolioDelegate::Ptr delegate) { if (!delegate) { return false; @@ -103,7 +103,7 @@ bool FavouritesModel::canAddEntry(int row, FolioDelegate *delegate) return true; } -bool FavouritesModel::addEntry(int row, FolioDelegate *delegate) +bool FavouritesModel::addEntry(int row, FolioDelegate::Ptr delegate) { if (!canAddEntry(row, delegate)) { return false; @@ -129,7 +129,7 @@ bool FavouritesModel::addEntry(int row, FolioDelegate *delegate) return true; } -FolioDelegate *FavouritesModel::getEntryAt(int row) +FolioDelegate::Ptr FavouritesModel::getEntryAt(int row) { if (row < 0 || row >= m_delegates.size()) { return nullptr; @@ -186,12 +186,12 @@ void FavouritesModel::setGhostEntry(int row) // if it doesn't, add a new empty delegate if (!found) { - FolioDelegate *ghost = new FolioDelegate{m_homeScreen}; + FolioDelegate::Ptr ghost = std::make_shared(m_homeScreen); addEntry(row, ghost); } } -void FavouritesModel::replaceGhostEntry(FolioDelegate *delegate) +void FavouritesModel::replaceGhostEntry(FolioDelegate::Ptr delegate) { for (int i = 0; i < m_delegates.size(); i++) { if (m_delegates[i].delegate->type() == FolioDelegate::None) { @@ -221,7 +221,7 @@ QJsonArray FavouritesModel::exportToJson() { QJsonArray arr; for (int i = 0; i < m_delegates.size(); i++) { - FolioDelegate *delegate = m_delegates[i].delegate; + FolioDelegate::Ptr delegate = m_delegates[i].delegate; // if this delegate is empty, ignore it if (!delegate || delegate->type() == FolioDelegate::None) { @@ -264,7 +264,7 @@ void FavouritesModel::loadFromJson(QJsonArray arr) for (QJsonValueRef r : arr) { QJsonObject obj = r.toObject(); - FolioDelegate *delegate = FolioDelegate::fromJson(obj, m_homeScreen); + FolioDelegate::Ptr delegate = FolioDelegate::fromJson(obj, m_homeScreen); if (delegate) { connectSaveRequests(delegate); @@ -275,10 +275,10 @@ void FavouritesModel::loadFromJson(QJsonArray arr) endResetModel(); } -void FavouritesModel::connectSaveRequests(FolioDelegate *delegate) +void FavouritesModel::connectSaveRequests(FolioDelegate::Ptr delegate) { if (delegate->type() == FolioDelegate::Folder && delegate->folder()) { - connect(delegate->folder(), &FolioApplicationFolder::saveRequested, this, &FavouritesModel::save); + connect(delegate->folder().get(), &FolioApplicationFolder::saveRequested, this, &FavouritesModel::save); } } diff --git a/containments/homescreens/folio/favouritesmodel.h b/containments/homescreens/folio/favouritesmodel.h index 1ff88b9e..1f3025a3 100644 --- a/containments/homescreens/folio/favouritesmodel.h +++ b/containments/homescreens/folio/favouritesmodel.h @@ -20,7 +20,7 @@ class HomeScreen; class FolioDelegate; struct FavouritesDelegate { - FolioDelegate *delegate; + std::shared_ptr delegate; qreal xPosition; }; @@ -41,9 +41,9 @@ public: Q_INVOKABLE void removeEntry(int row); void moveEntry(int fromRow, int toRow); - bool canAddEntry(int row, FolioDelegate *delegate); - bool addEntry(int row, FolioDelegate *delegate); - FolioDelegate *getEntryAt(int row); + bool canAddEntry(int row, std::shared_ptr delegate); + bool addEntry(int row, std::shared_ptr delegate); + std::shared_ptr getEntryAt(int row); // whether the dock is full, we can't add any more items bool isFull() const; @@ -53,7 +53,7 @@ public: // invisible - existing delegate looks like it doesn't exist int getGhostEntryPosition(); void setGhostEntry(int row); - void replaceGhostEntry(FolioDelegate *delegate); + void replaceGhostEntry(std::shared_ptr delegate); void deleteGhostEntry(); // whether the position given is in between 2 delegates, or at the edge. @@ -71,7 +71,7 @@ public: void loadFromJson(QJsonArray arr); private: - void connectSaveRequests(FolioDelegate *delegate); + void connectSaveRequests(std::shared_ptr delegate); // get the x (or y) position where delegates start being placed qreal getDelegateRowStartPos() const; diff --git a/containments/homescreens/folio/folioapplication.cpp b/containments/homescreens/folio/folioapplication.cpp index 3edd8b7b..40c3ccbf 100644 --- a/containments/homescreens/folio/folioapplication.cpp +++ b/containments/homescreens/folio/folioapplication.cpp @@ -35,11 +35,11 @@ FolioApplication::FolioApplication(HomeScreen *parent, KService::Ptr service) }); } -FolioApplication *FolioApplication::fromJson(QJsonObject &obj, HomeScreen *parent) +FolioApplication::Ptr FolioApplication::fromJson(QJsonObject &obj, HomeScreen *parent) { QString storageId = obj[QStringLiteral("storageId")].toString(); if (KService::Ptr service = KService::serviceByStorageId(storageId)) { - return new FolioApplication(parent, service); + return std::make_shared(parent, service); } return nullptr; } diff --git a/containments/homescreens/folio/folioapplication.h b/containments/homescreens/folio/folioapplication.h index 33fb1005..4193c078 100644 --- a/containments/homescreens/folio/folioapplication.h +++ b/containments/homescreens/folio/folioapplication.h @@ -23,7 +23,7 @@ class HomeScreen; /** * @short Object that represents an application. */ -class FolioApplication : public QObject +class FolioApplication : public QObject, public std::enable_shared_from_this { Q_OBJECT Q_PROPERTY(bool running READ running NOTIFY windowChanged) @@ -32,9 +32,11 @@ class FolioApplication : public QObject Q_PROPERTY(QString storageId READ storageId NOTIFY storageIdChanged) public: + typedef std::shared_ptr Ptr; + FolioApplication(HomeScreen *parent = nullptr, KService::Ptr service = QExplicitlySharedDataPointer{nullptr}); - static FolioApplication *fromJson(QJsonObject &obj, HomeScreen *parent); // may return nullptr + static FolioApplication::Ptr fromJson(QJsonObject &obj, HomeScreen *parent); // may return nullptr QJsonObject toJson() const; bool running() const; diff --git a/containments/homescreens/folio/folioapplicationfolder.cpp b/containments/homescreens/folio/folioapplicationfolder.cpp index e597ab76..d697dc82 100644 --- a/containments/homescreens/folio/folioapplicationfolder.cpp +++ b/containments/homescreens/folio/folioapplicationfolder.cpp @@ -15,17 +15,17 @@ FolioApplicationFolder::FolioApplicationFolder(HomeScreen *parent, QString name) { } -FolioApplicationFolder *FolioApplicationFolder::fromJson(QJsonObject &obj, HomeScreen *parent) +FolioApplicationFolder::Ptr FolioApplicationFolder::fromJson(QJsonObject &obj, HomeScreen *parent) { QString name = obj[QStringLiteral("name")].toString(); - QList apps; + QList apps; for (auto storageId : obj[QStringLiteral("apps")].toArray()) { if (KService::Ptr service = KService::serviceByStorageId(storageId.toString())) { - apps.append(new FolioApplication(parent, service)); + apps.append(std::make_shared(parent, service)); } } - FolioApplicationFolder *folder = new FolioApplicationFolder(parent, name); + FolioApplicationFolder::Ptr folder = std::make_shared(parent, name); folder->setApplications(apps); return folder; } @@ -69,7 +69,7 @@ QList FolioApplicationFolder::appPreviews() if (!m_delegates[i].delegate->application()) { continue; } - previews.push_back(m_delegates[i].delegate->application()); + previews.push_back(m_delegates[i].delegate->application().get()); } return previews; } @@ -79,15 +79,15 @@ ApplicationFolderModel *FolioApplicationFolder::applications() return m_applicationFolderModel; } -void FolioApplicationFolder::setApplications(QList applications) +void FolioApplicationFolder::setApplications(QList applications) { if (m_applicationFolderModel) { m_applicationFolderModel->deleteLater(); } m_delegates.clear(); - for (auto *app : applications) { - m_delegates.append({new FolioDelegate{app, m_homeScreen}, 0, 0}); + for (FolioApplication::Ptr app : applications) { + m_delegates.append({FolioDelegate::Ptr{new FolioDelegate{app, m_homeScreen}}, 0, 0, 0}); } m_applicationFolderModel = new ApplicationFolderModel{this}; m_applicationFolderModel->evaluateDelegateIndexes(); @@ -102,7 +102,7 @@ void FolioApplicationFolder::moveEntry(int fromRow, int toRow) m_applicationFolderModel->moveEntry(fromRow, toRow); } -bool FolioApplicationFolder::addDelegate(FolioDelegate *delegate, int row) +bool FolioApplicationFolder::addDelegate(FolioDelegate::Ptr delegate, int row) { return m_applicationFolderModel->addDelegate(delegate, row); } @@ -122,11 +122,11 @@ bool FolioApplicationFolder::isDropPositionOutside(qreal x, qreal y) return m_applicationFolderModel->isDropPositionOutside(x, y); } -ApplicationFolderModel::ApplicationFolderModel(FolioApplicationFolder *folder) - : QAbstractListModel{folder} - , m_folder{folder} +ApplicationFolderModel::ApplicationFolderModel(FolioApplicationFolder *parent) + : QAbstractListModel{parent} + , m_folder{parent} { - HomeScreenState *homeScreenState = folder->m_homeScreen->homeScreenState(); + HomeScreenState *homeScreenState = m_folder->m_homeScreen->homeScreenState(); connect(homeScreenState, &HomeScreenState::folderPageWidthChanged, this, [this]() { evaluateDelegateIndexes(); }); @@ -166,7 +166,7 @@ QVariant ApplicationFolderModel::data(const QModelIndex &index, int role) const switch (role) { case DelegateRole: - return QVariant::fromValue(m_folder->m_delegates.at(index.row()).delegate); + return QVariant::fromValue(m_folder->m_delegates.at(index.row()).delegate.get()); case columnIndexRole: return QVariant::fromValue(m_folder->m_delegates.at(index.row()).columnIndex); case rowIndexRole: @@ -183,7 +183,7 @@ QHash ApplicationFolderModel::roleNames() const return {{DelegateRole, "delegate"}, {columnIndexRole, "columnIndex"}, {rowIndexRole, "rowIndex"}, {pageIndexRole, "pageIndex"}}; } -FolioDelegate *ApplicationFolderModel::getDelegate(int index) +FolioDelegate::Ptr ApplicationFolderModel::getDelegate(int index) { if (index < 0 || index >= m_folder->m_delegates.size()) { return nullptr; @@ -217,7 +217,7 @@ void ApplicationFolderModel::moveEntry(int fromRow, int toRow) Q_EMIT m_folder->saveRequested(); } -bool ApplicationFolderModel::canAddDelegate(FolioDelegate *delegate, int index) +bool ApplicationFolderModel::canAddDelegate(FolioDelegate::Ptr delegate, int index) { if (index < 0 || index > m_folder->m_delegates.size()) { return false; @@ -230,7 +230,7 @@ bool ApplicationFolderModel::canAddDelegate(FolioDelegate *delegate, int index) return true; } -bool ApplicationFolderModel::addDelegate(FolioDelegate *delegate, int index) +bool ApplicationFolderModel::addDelegate(FolioDelegate::Ptr delegate, int index) { if (!canAddDelegate(delegate, index)) { return false; @@ -238,14 +238,14 @@ bool ApplicationFolderModel::addDelegate(FolioDelegate *delegate, int index) if (index == m_folder->m_delegates.size()) { beginInsertRows(QModelIndex(), index, index); - m_folder->m_delegates.append({delegate, 0, 0}); + m_folder->m_delegates.append({delegate, 0, 0, 0}); evaluateDelegateIndexes(false); endInsertRows(); } else if (m_folder->m_delegates[index].delegate->type() == FolioDelegate::None) { replaceGhostEntry(delegate); } else { beginInsertRows(QModelIndex(), index, index); - m_folder->m_delegates.insert(index, {delegate, 0, 0}); + m_folder->m_delegates.insert(index, {delegate, 0, 0, 0}); evaluateDelegateIndexes(false); endInsertRows(); } @@ -309,7 +309,7 @@ int ApplicationFolderModel::getGhostEntryPosition() void ApplicationFolderModel::setGhostEntry(int index) { - FolioDelegate *ghost = nullptr; + FolioDelegate::Ptr ghost = nullptr; // check if a ghost entry already exists for (int i = 0; i < m_folder->m_delegates.size(); i++) { @@ -328,14 +328,14 @@ void ApplicationFolderModel::setGhostEntry(int index) } if (!ghost) { - ghost = new FolioDelegate{m_folder->m_homeScreen}; + ghost = std::make_shared(m_folder->m_homeScreen); } // add empty delegate at new position addDelegate(ghost, index); } -void ApplicationFolderModel::replaceGhostEntry(FolioDelegate *delegate) +void ApplicationFolderModel::replaceGhostEntry(FolioDelegate::Ptr delegate) { for (int i = 0; i < m_folder->m_delegates.size(); i++) { if (m_folder->m_delegates[i].delegate->type() == FolioDelegate::None) { diff --git a/containments/homescreens/folio/folioapplicationfolder.h b/containments/homescreens/folio/folioapplicationfolder.h index a539b3f4..dd80b0b6 100644 --- a/containments/homescreens/folio/folioapplicationfolder.h +++ b/containments/homescreens/folio/folioapplicationfolder.h @@ -28,7 +28,7 @@ class FolioApplication; * @short Object that represents an application folder. */ -class FolioApplicationFolder : public QObject +class FolioApplicationFolder : public QObject, public std::enable_shared_from_this { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) @@ -36,9 +36,11 @@ class FolioApplicationFolder : public QObject Q_PROPERTY(ApplicationFolderModel *applications READ applications NOTIFY applicationsReset) public: + typedef std::shared_ptr Ptr; + FolioApplicationFolder(HomeScreen *parent = nullptr, QString name = QString{}); - static FolioApplicationFolder *fromJson(QJsonObject &obj, HomeScreen *parent); + static std::shared_ptr fromJson(QJsonObject &obj, HomeScreen *parent); QJsonObject toJson() const; QString name() const; @@ -47,10 +49,10 @@ public: QList appPreviews(); ApplicationFolderModel *applications(); - void setApplications(QList applications); + void setApplications(QList> applications); void moveEntry(int fromRow, int toRow); - bool addDelegate(FolioDelegate *delegate, int row); + bool addDelegate(std::shared_ptr delegate, int row); Q_INVOKABLE void removeDelegate(int row); int dropInsertPosition(int page, qreal x, qreal y); @@ -73,7 +75,7 @@ private: }; struct ApplicationDelegate { - FolioDelegate *delegate; + std::shared_ptr delegate; int columnIndex; int rowIndex; int pageIndex; @@ -91,16 +93,16 @@ public: rowIndexRole, pageIndexRole, }; - ApplicationFolderModel(FolioApplicationFolder *folder); + ApplicationFolderModel(FolioApplicationFolder *parent); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QHash roleNames() const override; - FolioDelegate *getDelegate(int index); + std::shared_ptr getDelegate(int index); void moveEntry(int fromRow, int toRow); - bool canAddDelegate(FolioDelegate *delegate, int index); - bool addDelegate(FolioDelegate *delegate, int index); + bool canAddDelegate(std::shared_ptr delegate, int index); + bool addDelegate(std::shared_ptr delegate, int index); void removeDelegate(int index); QPointF getDelegatePosition(int index); @@ -109,7 +111,7 @@ public: // invisible - existing delegate looks like it doesn't exist int getGhostEntryPosition(); void setGhostEntry(int index); - void replaceGhostEntry(FolioDelegate *delegate); + void replaceGhostEntry(std::shared_ptr delegate); void deleteGhostEntry(); // the index that dropping at the position given would place the delegate at. diff --git a/containments/homescreens/folio/foliodelegate.cpp b/containments/homescreens/folio/foliodelegate.cpp index 38973ad0..3b1d30d2 100644 --- a/containments/homescreens/folio/foliodelegate.cpp +++ b/containments/homescreens/folio/foliodelegate.cpp @@ -13,7 +13,7 @@ FolioDelegate::FolioDelegate(HomeScreen *parent) { } -FolioDelegate::FolioDelegate(FolioApplication *application, HomeScreen *parent) +FolioDelegate::FolioDelegate(FolioApplication::Ptr application, HomeScreen *parent) : QObject{parent} , m_type{FolioDelegate::Application} , m_application{application} @@ -22,7 +22,7 @@ FolioDelegate::FolioDelegate(FolioApplication *application, HomeScreen *parent) { } -FolioDelegate::FolioDelegate(FolioApplicationFolder *folder, HomeScreen *parent) +FolioDelegate::FolioDelegate(FolioApplicationFolder::Ptr folder, HomeScreen *parent) : QObject{parent} , m_type{FolioDelegate::Folder} , m_application{nullptr} @@ -31,7 +31,7 @@ FolioDelegate::FolioDelegate(FolioApplicationFolder *folder, HomeScreen *parent) { } -FolioDelegate::FolioDelegate(FolioWidget *widget, HomeScreen *parent) +FolioDelegate::FolioDelegate(FolioWidget::Ptr widget, HomeScreen *parent) : QObject{parent} , m_type{FolioDelegate::Widget} , m_application{nullptr} @@ -40,34 +40,34 @@ FolioDelegate::FolioDelegate(FolioWidget *widget, HomeScreen *parent) { } -FolioDelegate *FolioDelegate::fromJson(QJsonObject &obj, HomeScreen *parent) +FolioDelegate::Ptr FolioDelegate::fromJson(QJsonObject &obj, HomeScreen *parent) { const QString type = obj[QStringLiteral("type")].toString(); if (type == "application") { // read application - FolioApplication *app = FolioApplication::fromJson(obj, parent); + FolioApplication::Ptr app = FolioApplication::fromJson(obj, parent); if (app) { - return new FolioDelegate{app, parent}; + return std::make_shared(app, parent); } } else if (type == "folder") { // read folder - FolioApplicationFolder *folder = FolioApplicationFolder::fromJson(obj, parent); + FolioApplicationFolder::Ptr folder = FolioApplicationFolder::fromJson(obj, parent); if (folder) { - return new FolioDelegate{folder, parent}; + return std::make_shared(folder, parent); } } else if (type == "widget") { // read widget - FolioWidget *widget = FolioWidget::fromJson(obj, parent); + FolioWidget::Ptr widget = FolioWidget::fromJson(obj, parent); if (widget) { - return new FolioDelegate{widget, parent}; + return std::make_shared(widget, parent); } } else if (type == "none") { - return new FolioDelegate{parent}; + return std::make_shared(parent); } return nullptr; @@ -93,26 +93,41 @@ QJsonObject FolioDelegate::toJson() const return QJsonObject{}; } -FolioDelegate::Type FolioDelegate::type() +FolioDelegate::Type FolioDelegate::type() const { return m_type; } -FolioApplication *FolioDelegate::application() +FolioApplication::Ptr FolioDelegate::application() { return m_application; } -FolioApplicationFolder *FolioDelegate::folder() +FolioApplication *FolioDelegate::applicationRaw() +{ + return m_application.get(); +} + +FolioApplicationFolder::Ptr FolioDelegate::folder() { return m_folder; } -FolioWidget *FolioDelegate::widget() +FolioApplicationFolder *FolioDelegate::folderRaw() +{ + return m_folder.get(); +} + +FolioWidget::Ptr FolioDelegate::widget() { return m_widget; } +FolioWidget *FolioDelegate::widgetRaw() +{ + return m_widget.get(); +} + FolioPageDelegate::FolioPageDelegate(int row, int column, HomeScreen *parent) : FolioDelegate{parent} , m_homeScreen{parent} @@ -122,7 +137,7 @@ FolioPageDelegate::FolioPageDelegate(int row, int column, HomeScreen *parent) init(); } -FolioPageDelegate::FolioPageDelegate(int row, int column, FolioApplication *application, HomeScreen *parent) +FolioPageDelegate::FolioPageDelegate(int row, int column, FolioApplication::Ptr application, HomeScreen *parent) : FolioDelegate{application, parent} , m_homeScreen{parent} , m_row{row} @@ -131,7 +146,7 @@ FolioPageDelegate::FolioPageDelegate(int row, int column, FolioApplication *appl init(); } -FolioPageDelegate::FolioPageDelegate(int row, int column, FolioApplicationFolder *folder, HomeScreen *parent) +FolioPageDelegate::FolioPageDelegate(int row, int column, FolioApplicationFolder::Ptr folder, HomeScreen *parent) : FolioDelegate{folder, parent} , m_homeScreen{parent} , m_row{row} @@ -140,7 +155,7 @@ FolioPageDelegate::FolioPageDelegate(int row, int column, FolioApplicationFolder init(); } -FolioPageDelegate::FolioPageDelegate(int row, int column, FolioWidget *widget, HomeScreen *parent) +FolioPageDelegate::FolioPageDelegate(int row, int column, FolioWidget::Ptr widget, HomeScreen *parent) : FolioDelegate{widget, parent} , m_homeScreen{parent} , m_row{row} @@ -149,7 +164,7 @@ FolioPageDelegate::FolioPageDelegate(int row, int column, FolioWidget *widget, H init(); } -FolioPageDelegate::FolioPageDelegate(int row, int column, FolioDelegate *delegate, HomeScreen *parent) +FolioPageDelegate::FolioPageDelegate(int row, int column, FolioDelegate::Ptr delegate, HomeScreen *parent) : FolioDelegate{parent} , m_homeScreen{parent} , m_row{row} @@ -207,21 +222,21 @@ void FolioPageDelegate::init() } if (m_widget) { - connect(m_widget, &FolioWidget::realTopLeftPositionChanged, this, [this](int rowOffset, int columnOffset) { + connect(m_widget.get(), &FolioWidget::realTopLeftPositionChanged, this, [this](int rowOffset, int columnOffset) { m_realRow += rowOffset; m_realColumn += columnOffset; }); } connect(homeScreenState, &HomeScreenState::pageOrientationChanged, this, [this]() { - setRowOnly(getTranslatedTopLeftRow(m_homeScreen, m_realRow, m_realColumn, this)); - setColumnOnly(getTranslatedTopLeftColumn(m_homeScreen, m_realRow, m_realColumn, this)); + setRowOnly(getTranslatedTopLeftRow(m_homeScreen, m_realRow, m_realColumn, this->shared_from_this())); + setColumnOnly(getTranslatedTopLeftColumn(m_homeScreen, m_realRow, m_realColumn, this->shared_from_this())); }); } -FolioPageDelegate *FolioPageDelegate::fromJson(QJsonObject &obj, HomeScreen *parent) +FolioPageDelegate::Ptr FolioPageDelegate::fromJson(QJsonObject &obj, HomeScreen *parent) { - FolioDelegate *fd = FolioDelegate::fromJson(obj, parent); + FolioDelegate::Ptr fd = FolioDelegate::fromJson(obj, parent); if (!fd) { return nullptr; @@ -233,13 +248,13 @@ FolioPageDelegate *FolioPageDelegate::fromJson(QJsonObject &obj, HomeScreen *par int row = getTranslatedTopLeftRow(parent, realRow, realColumn, fd); int column = getTranslatedTopLeftColumn(parent, realRow, realColumn, fd); - FolioPageDelegate *delegate = new FolioPageDelegate{row, column, fd, parent}; + FolioPageDelegate::Ptr delegate = std::make_shared(row, column, fd, parent); fd->deleteLater(); return delegate; } -int FolioPageDelegate::getTranslatedTopLeftRow(HomeScreen *homeScreen, int realRow, int realColumn, FolioDelegate *fd) +int FolioPageDelegate::getTranslatedTopLeftRow(HomeScreen *homeScreen, int realRow, int realColumn, FolioDelegate::Ptr fd) { int row = getTranslatedRow(homeScreen, realRow, realColumn); int column = getTranslatedColumn(homeScreen, realRow, realColumn); @@ -252,7 +267,7 @@ int FolioPageDelegate::getTranslatedTopLeftRow(HomeScreen *homeScreen, int realR } } -int FolioPageDelegate::getTranslatedTopLeftColumn(HomeScreen *homeScreen, int realRow, int realColumn, FolioDelegate *fd) +int FolioPageDelegate::getTranslatedTopLeftColumn(HomeScreen *homeScreen, int realRow, int realColumn, FolioDelegate::Ptr fd) { int row = getTranslatedRow(homeScreen, realRow, realColumn); int column = getTranslatedColumn(homeScreen, realRow, realColumn); @@ -386,3 +401,8 @@ void FolioPageDelegate::setColumnOnly(int column) Q_EMIT columnChanged(); } } + +std::shared_ptr FolioPageDelegate::sharedPageDelegate() +{ + return static_pointer_cast(shared_from_this()); +} diff --git a/containments/homescreens/folio/foliodelegate.h b/containments/homescreens/folio/foliodelegate.h index 904f7e0d..359a2de6 100644 --- a/containments/homescreens/folio/foliodelegate.h +++ b/containments/homescreens/folio/foliodelegate.h @@ -15,15 +15,17 @@ class FolioApplication; class FolioApplicationFolder; class FolioWidget; -class FolioDelegate : public QObject +class FolioDelegate : public QObject, public std::enable_shared_from_this { Q_OBJECT Q_PROPERTY(FolioDelegate::Type type READ type CONSTANT) - Q_PROPERTY(FolioApplication *application READ application CONSTANT) - Q_PROPERTY(FolioApplicationFolder *folder READ folder CONSTANT) - Q_PROPERTY(FolioWidget *widget READ widget CONSTANT) + Q_PROPERTY(FolioApplication *application READ applicationRaw CONSTANT) + Q_PROPERTY(FolioApplicationFolder *folder READ folderRaw CONSTANT) + Q_PROPERTY(FolioWidget *widget READ widgetRaw CONSTANT) public: + typedef std::shared_ptr Ptr; + enum Type { None, Application, @@ -32,25 +34,31 @@ public: }; Q_ENUM(Type) - FolioDelegate(HomeScreen *parent = nullptr); - FolioDelegate(FolioApplication *application, HomeScreen *parent); - FolioDelegate(FolioApplicationFolder *folder, HomeScreen *parent); - FolioDelegate(FolioWidget *widget, HomeScreen *parent); + FolioDelegate(HomeScreen *parent); + FolioDelegate(std::shared_ptr application, HomeScreen *parent); + FolioDelegate(std::shared_ptr folder, HomeScreen *parent); + FolioDelegate(std::shared_ptr widget, HomeScreen *parent); - static FolioDelegate *fromJson(QJsonObject &obj, HomeScreen *parent); + static std::shared_ptr fromJson(QJsonObject &obj, HomeScreen *parent); virtual QJsonObject toJson() const; - FolioDelegate::Type type(); - FolioApplication *application(); - FolioApplicationFolder *folder(); - FolioWidget *widget(); + FolioDelegate::Type type() const; + + std::shared_ptr application(); + FolioApplication *applicationRaw(); + + std::shared_ptr folder(); + FolioApplicationFolder *folderRaw(); + + std::shared_ptr widget(); + FolioWidget *widgetRaw(); protected: FolioDelegate::Type m_type; - FolioApplication *m_application{nullptr}; - FolioApplicationFolder *m_folder{nullptr}; - FolioWidget *m_widget{nullptr}; + std::shared_ptr m_application{nullptr}; + std::shared_ptr m_folder{nullptr}; + std::shared_ptr m_widget{nullptr}; }; class FolioPageDelegate : public FolioDelegate @@ -61,15 +69,17 @@ class FolioPageDelegate : public FolioDelegate QML_UNCREATABLE("") public: - FolioPageDelegate(int row = 0, int column = 0, HomeScreen *parent = nullptr); - FolioPageDelegate(int row, int column, FolioApplication *application, HomeScreen *parent); - FolioPageDelegate(int row, int column, FolioApplicationFolder *folder, HomeScreen *parent); - FolioPageDelegate(int row, int column, FolioWidget *widget, HomeScreen *parent); - FolioPageDelegate(int row, int column, FolioDelegate *delegate, HomeScreen *parent); + typedef std::shared_ptr Ptr; - static FolioPageDelegate *fromJson(QJsonObject &obj, HomeScreen *parent); - static int getTranslatedTopLeftRow(HomeScreen *homeScreen, int realRow, int realColumn, FolioDelegate *fd); - static int getTranslatedTopLeftColumn(HomeScreen *homeScreen, int realRow, int realColumn, FolioDelegate *fd); + FolioPageDelegate(int row = 0, int column = 0, HomeScreen *parent = nullptr); + FolioPageDelegate(int row, int column, std::shared_ptr application, HomeScreen *parent); + FolioPageDelegate(int row, int column, std::shared_ptr folder, HomeScreen *parent); + FolioPageDelegate(int row, int column, std::shared_ptr widget, HomeScreen *parent); + FolioPageDelegate(int row, int column, std::shared_ptr delegate, HomeScreen *parent); + + static std::shared_ptr fromJson(QJsonObject &obj, HomeScreen *parent); + static int getTranslatedTopLeftRow(HomeScreen *homeScreen, int realRow, int realColumn, std::shared_ptr fd); + static int getTranslatedTopLeftColumn(HomeScreen *homeScreen, int realRow, int realColumn, std::shared_ptr fd); static int getTranslatedRow(HomeScreen *homeScreen, int realRow, int realColumn); static int getTranslatedColumn(HomeScreen *homeScreen, int realRow, int realColumn); @@ -81,6 +91,8 @@ public: int column(); void setColumn(int column); + std::shared_ptr sharedPageDelegate(); + Q_SIGNALS: void rowChanged(); void columnChanged(); diff --git a/containments/homescreens/folio/foliowidget.cpp b/containments/homescreens/folio/foliowidget.cpp index 9ba7ce3b..16bd2c1a 100644 --- a/containments/homescreens/folio/foliowidget.cpp +++ b/containments/homescreens/folio/foliowidget.cpp @@ -51,12 +51,12 @@ void FolioWidget::init() }); } -FolioWidget *FolioWidget::fromJson(QJsonObject &obj, HomeScreen *parent) +FolioWidget::Ptr FolioWidget::fromJson(QJsonObject &obj, HomeScreen *parent) { int id = obj[QStringLiteral("id")].toInt(); int gridWidth = obj[QStringLiteral("gridWidth")].toInt(); int gridHeight = obj[QStringLiteral("gridHeight")].toInt(); - return new FolioWidget(parent, id, gridWidth, gridHeight); + return std::make_shared(parent, id, gridWidth, gridHeight); } QJsonObject FolioWidget::toJson() const @@ -208,7 +208,7 @@ bool FolioWidget::isInBounds(int widgetRow, int widgetColumn, int row, int colum return (row >= widgetRow) && (row <= widgetRow + gridHeight() - 1) && (column >= widgetColumn) && (column <= widgetColumn + gridWidth() - 1); } -bool FolioWidget::overlapsWidget(int widgetRow, int widgetColumn, FolioWidget *otherWidget, int otherWidgetRow, int otherWidgetColumn) +bool FolioWidget::overlapsWidget(int widgetRow, int widgetColumn, FolioWidget::Ptr otherWidget, int otherWidgetRow, int otherWidgetColumn) { if (!otherWidget) { return false; diff --git a/containments/homescreens/folio/foliowidget.h b/containments/homescreens/folio/foliowidget.h index 34a6f2b6..36b27c51 100644 --- a/containments/homescreens/folio/foliowidget.h +++ b/containments/homescreens/folio/foliowidget.h @@ -22,7 +22,7 @@ public: /** * @short Object that represents a widget on the homescreen. */ -class FolioWidget : public QObject +class FolioWidget : public QObject, public std::enable_shared_from_this { Q_OBJECT Q_PROPERTY(int id READ id NOTIFY idChanged) @@ -32,10 +32,12 @@ class FolioWidget : public QObject Q_PROPERTY(PlasmaQuick::AppletQuickItem *visualApplet READ visualApplet NOTIFY visualAppletChanged) public: + typedef std::shared_ptr Ptr; + FolioWidget(HomeScreen *parent = nullptr, int id = -1, int gridWidth = 0, int gridHeight = 0); FolioWidget(HomeScreen *parent, Plasma::Applet *applet, int gridWidth, int gridHeight); - static FolioWidget *fromJson(QJsonObject &obj, HomeScreen *parent); + static std::shared_ptr fromJson(QJsonObject &obj, HomeScreen *parent); QJsonObject toJson() const; int id() const; @@ -59,7 +61,7 @@ public: // query whether (row, column) is inside this widget, if it was at position (widgetRow, widgetColumn) bool isInBounds(int widgetRow, int widgetColumn, int row, int column); - bool overlapsWidget(int widgetRow, int widgetColumn, FolioWidget *otherWidget, int otherWidgetRow, int otherWidgetColumn); + bool overlapsWidget(int widgetRow, int widgetColumn, std::shared_ptr otherWidget, int otherWidgetRow, int otherWidgetColumn); Plasma::Applet *applet() const; void setApplet(Plasma::Applet *applet); diff --git a/containments/homescreens/folio/homescreenstate.cpp b/containments/homescreens/folio/homescreenstate.cpp index cdac52ce..ab84c058 100644 --- a/containments/homescreens/folio/homescreenstate.cpp +++ b/containments/homescreens/folio/homescreenstate.cpp @@ -517,12 +517,17 @@ void HomeScreenState::setFolderOpenProgress(qreal folderOpenProgress) } } -FolioApplicationFolder *HomeScreenState::currentFolder() const +FolioApplicationFolder::Ptr HomeScreenState::currentFolder() const { return m_currentFolder; } -void HomeScreenState::setCurrentFolder(FolioApplicationFolder *folder) +FolioApplicationFolder *HomeScreenState::currentFolderRaw() const +{ + return m_currentFolder.get(); +} + +void HomeScreenState::setCurrentFolder(FolioApplicationFolder::Ptr folder) { if (m_currentFolder != folder) { m_currentFolder = folder; @@ -662,17 +667,17 @@ FolioDelegate *HomeScreenState::getPageDelegateAt(int page, int row, int column) return nullptr; } - FolioDelegate *delegate = pageModel->getDelegate(row, column); + FolioDelegate::Ptr delegate = pageModel->getDelegate(row, column); if (!delegate) { return nullptr; } - return delegate; + return delegate.get(); } FolioDelegate *HomeScreenState::getFavouritesDelegateAt(int position) { - return m_homeScreen->favouritesModel()->getEntryAt(position); + return m_homeScreen->favouritesModel()->getEntryAt(position).get(); } FolioDelegate *HomeScreenState::getFolderDelegateAt(int position) @@ -681,7 +686,7 @@ FolioDelegate *HomeScreenState::getFolderDelegateAt(int position) return nullptr; } - return m_currentFolder->applications()->getDelegate(position); + return m_currentFolder->applications()->getDelegate(position).get(); } QPointF HomeScreenState::getPageDelegateScreenPosition(int page, int row, int column) @@ -799,7 +804,7 @@ void HomeScreenState::goToFolderPage(int page, bool snap) void HomeScreenState::openFolder(qreal delegateX, qreal delegateY, FolioApplicationFolder *folder) { - setCurrentFolder(folder); + setCurrentFolder(folder->shared_from_this()); m_openFolderAnim->stop(); m_closeFolderAnim->stop(); diff --git a/containments/homescreens/folio/homescreenstate.h b/containments/homescreens/folio/homescreenstate.h index 28b5d3e5..9614ba8c 100644 --- a/containments/homescreens/folio/homescreenstate.h +++ b/containments/homescreens/folio/homescreenstate.h @@ -60,7 +60,7 @@ class HomeScreenState : public QObject Q_PROPERTY(qreal folderPageContentWidth READ folderPageContentWidth WRITE setFolderPageContentWidth NOTIFY folderPageContentWidthChanged) Q_PROPERTY(qreal folderPageContentHeight READ folderPageContentHeight WRITE setFolderPageContentHeight NOTIFY folderPageContentHeightChanged) Q_PROPERTY(qreal folderOpenProgress READ folderOpenProgress WRITE setFolderOpenProgress NOTIFY folderOpenProgressChanged) - Q_PROPERTY(FolioApplicationFolder *currentFolder READ currentFolder NOTIFY currentFolderChanged) + Q_PROPERTY(FolioApplicationFolder *currentFolder READ currentFolderRaw NOTIFY currentFolderChanged) Q_PROPERTY(qreal folderGridLength READ folderGridLength NOTIFY folderGridLengthChanged) Q_PROPERTY(qreal settingsOpenProgress READ settingsOpenProgress WRITE setSettingsOpenProgress NOTIFY settingsOpenProgressChanged) @@ -208,8 +208,9 @@ public: int folderGridLength() const; void calculateFolderGridLength(); - FolioApplicationFolder *currentFolder() const; - void setCurrentFolder(FolioApplicationFolder *folder); + std::shared_ptr currentFolder() const; + FolioApplicationFolder *currentFolderRaw() const; + void setCurrentFolder(std::shared_ptr folder); // the progress for the opening of the settings view qreal settingsOpenProgress(); @@ -389,7 +390,7 @@ private: qreal m_folderPageContentWidth{0}; qreal m_folderPageContentHeight{0}; qreal m_folderOpenProgress{0}; - FolioApplicationFolder *m_currentFolder{nullptr}; + std::shared_ptr m_currentFolder{nullptr}; int m_folderGridLength{0}; qreal m_settingsOpenProgress{0}; diff --git a/containments/homescreens/folio/pagemodel.cpp b/containments/homescreens/folio/pagemodel.cpp index 744a57af..0abe3438 100644 --- a/containments/homescreens/folio/pagemodel.cpp +++ b/containments/homescreens/folio/pagemodel.cpp @@ -6,7 +6,7 @@ #include "homescreenstate.h" #include "widgetsmanager.h" -PageModel::PageModel(QList delegates, QObject *parent, HomeScreen *homeScreen) +PageModel::PageModel(QList delegates, QObject *parent, HomeScreen *homeScreen) : QAbstractListModel{parent} , m_homeScreen{homeScreen} , m_delegates{delegates} @@ -15,7 +15,7 @@ PageModel::PageModel(QList delegates, QObject *parent, Home if (applet) { // delete any instance of this widget for (int i = 0; i < m_delegates.size(); i++) { - auto *delegate = m_delegates[i]; + FolioPageDelegate::Ptr delegate = m_delegates[i]; if (delegate->type() == FolioDelegate::Widget && delegate->widget()->applet() == applet) { removeDelegate(i); break; @@ -29,12 +29,12 @@ PageModel::~PageModel() = default; PageModel *PageModel::fromJson(QJsonArray &arr, QObject *parent, HomeScreen *homeScreen) { - QList delegates; + QList delegates; for (QJsonValueRef r : arr) { QJsonObject obj = r.toObject(); - FolioPageDelegate *delegate = FolioPageDelegate::fromJson(obj, homeScreen); + FolioPageDelegate::Ptr delegate = FolioPageDelegate::fromJson(obj, homeScreen); if (delegate) { delegates.append(delegate); } @@ -43,7 +43,7 @@ PageModel *PageModel::fromJson(QJsonArray &arr, QObject *parent, HomeScreen *hom PageModel *model = new PageModel{delegates, parent, homeScreen}; // ensure delegates can request saves - for (auto *delegate : delegates) { + for (FolioPageDelegate::Ptr delegate : delegates) { model->connectSaveRequests(delegate); } @@ -54,7 +54,7 @@ QJsonArray PageModel::toJson() const { QJsonArray arr; - for (FolioPageDelegate *delegate : m_delegates) { + for (FolioPageDelegate::Ptr delegate : m_delegates) { if (!delegate) { continue; } @@ -79,7 +79,7 @@ QVariant PageModel::data(const QModelIndex &index, int role) const switch (role) { case DelegateRole: - return QVariant::fromValue(m_delegates.at(index.row())); + return QVariant::fromValue(m_delegates.at(index.row()).get()); } return QVariant(); @@ -136,7 +136,7 @@ bool PageModel::canAddDelegate(int row, int column, FolioDelegate *delegate) } // check if any delegate exists at any of the spots where the widget is being added - for (FolioPageDelegate *d : m_delegates) { + for (FolioPageDelegate::Ptr d : m_delegates) { if (delegate->widget()->isInBounds(row, column, d->row(), d->column())) { return false; } else if (d->type() == FolioDelegate::Widget) { @@ -151,7 +151,7 @@ bool PageModel::canAddDelegate(int row, int column, FolioDelegate *delegate) // inserting app or folder... // check if there already exists a delegate in this space - for (FolioPageDelegate *d : m_delegates) { + for (FolioPageDelegate::Ptr d : m_delegates) { if (d->row() == row && d->column() == column) { return false; } else if (d->type() == FolioDelegate::Widget && d->widget()->isInBounds(d->row(), d->column(), row, column)) { @@ -163,9 +163,9 @@ bool PageModel::canAddDelegate(int row, int column, FolioDelegate *delegate) return true; } -bool PageModel::addDelegate(FolioPageDelegate *delegate) +bool PageModel::addDelegate(FolioPageDelegate::Ptr delegate) { - if (!canAddDelegate(delegate->row(), delegate->column(), delegate)) { + if (!canAddDelegate(delegate->row(), delegate->column(), delegate.get())) { return false; } @@ -180,9 +180,9 @@ bool PageModel::addDelegate(FolioPageDelegate *delegate) return true; } -FolioPageDelegate *PageModel::getDelegate(int row, int col) +FolioPageDelegate::Ptr PageModel::getDelegate(int row, int col) { - for (FolioPageDelegate *d : m_delegates) { + for (FolioPageDelegate::Ptr d : m_delegates) { if (d->row() == row && d->column() == col) { return d; } @@ -207,23 +207,21 @@ void PageModel::moveAndResizeWidgetDelegate(FolioPageDelegate *delegate, int new return; } - // test if we can add the delegate with new size and position - FolioWidget *testWidget = new FolioWidget(m_homeScreen, 0, 0, 0); - // we have to use setGridWidth and setGridHeight since it takes into account the page orientation + // Test if we can add the delegate with new size and position + FolioWidget::Ptr testWidget = std::make_shared(m_homeScreen, 0, 0, 0); + // We have to use setGridWidth and setGridHeight since it takes into account the page orientation testWidget->setGridWidth(newGridWidth); testWidget->setGridHeight(newGridHeight); - FolioDelegate *testDelegate = new FolioDelegate(testWidget, m_homeScreen); + FolioDelegate::Ptr testDelegate = std::make_shared(testWidget, m_homeScreen); + + // testWidget and testDelegate will get cleaned up automatically since are smart pointers // NOT THREAD SAFE! // which is fine, because the GUI isn't multithreaded - int index = m_delegates.indexOf(delegate); + int index = m_delegates.indexOf(delegate->sharedPageDelegate()); m_delegates.remove(index); // remove the delegate temporarily, since we don't want it to check overlapping of itself - bool canAdd = canAddDelegate(newRow, newColumn, testDelegate); - m_delegates.insert(index, delegate); // add it back - - // cleanup test delegate - testDelegate->deleteLater(); - testWidget->deleteLater(); + bool canAdd = canAddDelegate(newRow, newColumn, testDelegate.get()); + m_delegates.insert(index, delegate->sharedPageDelegate()); // add it back if (!canAdd) { return; @@ -240,12 +238,12 @@ bool PageModel::isPageEmpty() return m_delegates.size() == 0; } -void PageModel::connectSaveRequests(FolioDelegate *delegate) +void PageModel::connectSaveRequests(FolioDelegate::Ptr delegate) { if (delegate->type() == FolioDelegate::Folder && delegate->folder()) { - connect(delegate->folder(), &FolioApplicationFolder::saveRequested, this, &PageModel::save); + connect(delegate->folder().get(), &FolioApplicationFolder::saveRequested, this, &PageModel::save); } else if (delegate->type() == FolioDelegate::Widget && delegate->widget()) { - connect(delegate->widget(), &FolioWidget::saveRequested, this, &PageModel::save); + connect(delegate->widget().get(), &FolioWidget::saveRequested, this, &PageModel::save); } } diff --git a/containments/homescreens/folio/pagemodel.h b/containments/homescreens/folio/pagemodel.h index b0e6657e..1b9ce6a6 100644 --- a/containments/homescreens/folio/pagemodel.h +++ b/containments/homescreens/folio/pagemodel.h @@ -29,7 +29,9 @@ public: ShownRole, }; - PageModel(QList delegates = QList{}, QObject *parent = nullptr, HomeScreen *m_homeScreen = nullptr); + PageModel(QList> delegates = QList>{}, + QObject *parent = nullptr, + HomeScreen *m_homeScreen = nullptr); ~PageModel(); static PageModel *fromJson(QJsonArray &arr, QObject *parent, HomeScreen *homeScreen); @@ -43,8 +45,8 @@ public: Q_INVOKABLE void removeDelegate(int row, int col); Q_INVOKABLE void removeDelegate(int index); Q_INVOKABLE bool canAddDelegate(int row, int column, FolioDelegate *delegate); - bool addDelegate(FolioPageDelegate *delegate); - FolioPageDelegate *getDelegate(int row, int col); + bool addDelegate(std::shared_ptr delegate); + std::shared_ptr getDelegate(int row, int col); Q_INVOKABLE void moveAndResizeWidgetDelegate(FolioPageDelegate *delegate, int newRow, int newColumn, int newGridWidth, int newGridHeight); @@ -57,8 +59,8 @@ Q_SIGNALS: void saveRequested(); private: - void connectSaveRequests(FolioDelegate *delegate); + void connectSaveRequests(std::shared_ptr delegate); HomeScreen *m_homeScreen{nullptr}; - QList m_delegates; + QList> m_delegates; };