on 3667e72 help sign in
unity8/plugins/WindowManager/WorkspaceModel.cpp
252 lines 7.2 kB history raw
1/*
2 * Copyright (C) 2017 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17#include "WorkspaceModel.h"
18#include "WorkspaceManager.h"
19#include "Workspace.h"
21#include <QQmlEngine>
23Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
25#define DEBUG_MSG qCDebug(WORKSPACES).nospace().noquote() << __func__
26#define INFO_MSG qCInfo(WORKSPACES).nospace().noquote() << __func__
28WorkspaceModel::WorkspaceModel(QObject *parent)
29 : QAbstractListModel(parent)
33WorkspaceModel::~WorkspaceModel()
35 qDeleteAll(m_workspaces.toList()); // make a copy so the list doesnt edit itself during delete.
36 m_workspaces.clear();
39void WorkspaceModel::append(Workspace *workspace)
41 insert(m_workspaces.count(), workspace);
44void WorkspaceModel::insert(int index, Workspace *workspace)
46 beginInsertRows(QModelIndex(), index, index);
48 m_workspaces.insert(index, workspace);
50 endInsertRows();
52 Q_EMIT workspaceInserted(index, workspace);
53 Q_EMIT countChanged();
56void WorkspaceModel::remove(Workspace *workspace)
58 int index = m_workspaces.indexOf(workspace);
59 if (index < 0) return;
61 beginRemoveRows(QModelIndex(), index, index);
63 m_workspaces.removeAt(index);
64 insertUnassigned(workspace);
66 endRemoveRows();
68 Q_EMIT workspaceRemoved(workspace);
69 Q_EMIT countChanged();
72void WorkspaceModel::move(int from, int to)
74 if (from == to) return;
75 DEBUG_MSG << " from=" << from << " to=" << to;
77 if (from >= 0 && from < m_workspaces.size() && to >= 0 && to < m_workspaces.size()) {
78 QModelIndex parent;
80 beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
81#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
82 const auto &window = m_windowModel.takeAt(from);
83 m_workspaces.insert(to, window);
84#else
85 m_workspaces.move(from, to);
86#endif
87 endMoveRows();
89 Q_EMIT workspaceMoved(from, to);
90 }
93int WorkspaceModel::indexOf(Workspace *workspace) const
95 return m_workspaces.indexOf(workspace);
98Workspace *WorkspaceModel::get(int index) const
100 if (index < 0 || index >= rowCount()) return nullptr;
101 return m_workspaces.at(index);
104int WorkspaceModel::rowCount(const QModelIndex &) const
106 return m_workspaces.count();
109QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
111 if (index.row() < 0 || index.row() >= m_workspaces.size())
112 return QVariant();
114 if (role == WorkspaceRole) {
115 Workspace *workspace = m_workspaces.at(index.row());
116 return QVariant::fromValue(workspace);
117 } else {
118 return QVariant();
119 }
122void WorkspaceModel::setSyncing(bool syncing)
124 m_syncing = syncing;
127void WorkspaceModel::sync(WorkspaceModel *proxy)
129 if (!proxy) return;
130 const auto& proxyList = proxy->list();
132 // check for removals
133 int removedIndexWhichWasActive = -1;
134 QVector<Workspace*> dpCpy(this->list());
135 Q_FOREACH(auto workspace, dpCpy) {
137 bool found = false;
138 Q_FOREACH(auto p, proxyList) {
139 auto workspaceProxy = qobject_cast<ProxyWorkspace*>(p);
140 if (workspaceProxy->proxyObject() == workspace) {
141 found = true;
142 break;
143 }
144 }
145 if (!found) {
146 if (workspace->isActive()) {
147 removedIndexWhichWasActive = indexOf(workspace);
148 }
149 workspace->unassign();
150 }
151 }
153 // existing
154 QSet<Workspace*> newWorkspaces;
155 for (int i = 0; i < proxyList.count(); i++) {
156 auto workspaceProxy = qobject_cast<ProxyWorkspace*>(proxyList[i]);
157 auto workspace = workspaceProxy->proxyObject();
159 int oldIndex = this->indexOf(workspace);
161 if (oldIndex < 0) {
162 workspace->assign(this, QVariant(i));
163 } else if (oldIndex != i) {
164 this->move(oldIndex, i);
165 }
166 newWorkspaces.insert(workspace);
167 }
169 // Make sure we have at least one workspace in the model.
170 if (rowCount() == 0) {
171 Workspace* workspace = WorkspaceManager::instance()->createWorkspace();
172 workspace->assign(this);
173 (new ProxyWorkspace(workspace))->assign(proxy);
174 }
176 if (removedIndexWhichWasActive != -1) {
177 int newActiveIndex = qMin(removedIndexWhichWasActive, this->rowCount()-1);
178 Workspace* newActiveWorkspace = newActiveIndex >= 0 ? this->get(newActiveIndex) : nullptr;
180 WorkspaceManager::instance()->setActiveWorkspace(newActiveWorkspace);
181 }
183 proxy->finishSync();
184 finishSync();
187void WorkspaceModel::finishSync()
189 QSet<Workspace*> dpCpy(m_unassignedWorkspaces);
190 Q_FOREACH(auto workspace, dpCpy) {
191 delete workspace;
192 }
193 m_unassignedWorkspaces.clear();
196void WorkspaceModel::insertUnassigned(Workspace *workspace)
198 m_unassignedWorkspaces.insert(workspace);
199 connect(workspace, &Workspace::assigned, this, [=]() {
200 m_unassignedWorkspaces.remove(workspace);
201 disconnect(workspace, &Workspace::assigned, this, 0);
202 });
203 connect(workspace, &QObject::destroyed, this, [=]() {
204 m_unassignedWorkspaces.remove(workspace);
205 });
209ProxyWorkspaceModel::ProxyWorkspaceModel(WorkspaceModel * const model)
210 : m_original(model)
212 Q_FOREACH(auto workspace, model->list()) {
213 auto proxy = new ProxyWorkspace(workspace);
214 QQmlEngine::setObjectOwnership(proxy, QQmlEngine::CppOwnership);
215 proxy->assign(this);
216 }
217 connect(m_original, &WorkspaceModel::workspaceInserted, this, [this](int index, Workspace* inserted) {
218 if (m_original->isSyncing()) return;
220 (new ProxyWorkspace(inserted))->assign(this, index);
221 });
222 connect(m_original, &WorkspaceModel::workspaceRemoved, this, [this](Workspace* removed) {
223 if (m_original->isSyncing()) return;
225 for (int i = 0; i < rowCount(); i++) {
226 auto workspaceProxy = qobject_cast<ProxyWorkspace*>(get(i));
227 auto w = workspaceProxy->proxyObject();
228 if (w == removed) {
229 remove(workspaceProxy);
230 break;
231 }
232 }
233 });
234 connect(m_original, &WorkspaceModel::workspaceMoved, this, [this](int from, int to) {
235 if (m_original->isSyncing()) return;
237 move(from, to);
238 });
241void ProxyWorkspaceModel::move(int from, int to)
243 WorkspaceModel::move(from, to);
246void ProxyWorkspaceModel::addWorkspace()
248 auto newWorkspace = WorkspaceManager::instance()->createWorkspace();
249 m_original->insertUnassigned(newWorkspace);
251 (new ProxyWorkspace(newWorkspace))->assign(this);