Lomiri
Loading...
Searching...
No Matches
WorkspaceModel.cpp
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 */
16
17#include "WorkspaceModel.h"
18#include "WorkspaceManager.h"
19#include "Workspace.h"
20#include "Screen.h"
21
22#include <QQmlEngine>
23
24Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
25
26#define DEBUG_MSG qCDebug(WORKSPACES).nospace().noquote() << __func__
27#define INFO_MSG qCInfo(WORKSPACES).nospace().noquote() << __func__
28
29WorkspaceModel::WorkspaceModel(QObject *parent)
30 : QAbstractListModel(parent)
31{
32}
33
34WorkspaceModel::~WorkspaceModel()
35{
36 qDeleteAll(m_workspaces.toList()); // make a copy so the list doesnt edit itself during delete.
37 m_workspaces.clear();
38}
39
40void WorkspaceModel::append(Workspace *workspace)
41{
42 insert(m_workspaces.count(), workspace);
43}
44
45void WorkspaceModel::insert(int index, Workspace *workspace)
46{
47 beginInsertRows(QModelIndex(), index, index);
48
49 m_workspaces.insert(index, workspace);
50
51 endInsertRows();
52
53 Q_EMIT workspaceInserted(index, workspace);
54 Q_EMIT countChanged();
55}
56
57void WorkspaceModel::remove(Workspace *workspace)
58{
59 int index = m_workspaces.indexOf(workspace);
60 if (index < 0) return;
61
62 beginRemoveRows(QModelIndex(), index, index);
63
64 m_workspaces.removeAt(index);
65 insertUnassigned(workspace);
66
67 endRemoveRows();
68
69 Q_EMIT workspaceRemoved(workspace);
70 Q_EMIT countChanged();
71}
72
73void WorkspaceModel::move(int from, int to)
74{
75 if (from == to) return;
76 DEBUG_MSG << " from=" << from << " to=" << to;
77
78 if (from >= 0 && from < m_workspaces.size() && to >= 0 && to < m_workspaces.size()) {
79 QModelIndex parent;
80
81 beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
82#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
83 const auto &window = m_windowModel.takeAt(from);
84 m_workspaces.insert(to, window);
85#else
86 m_workspaces.move(from, to);
87#endif
88 endMoveRows();
89
90 Q_EMIT workspaceMoved(from, to);
91 }
92}
93
94int WorkspaceModel::indexOf(Workspace *workspace) const
95{
96 return m_workspaces.indexOf(workspace);
97}
98
99Workspace *WorkspaceModel::get(int index) const
100{
101 if (index < 0 || index >= rowCount()) return nullptr;
102 return m_workspaces.at(index);
103}
104
105int WorkspaceModel::rowCount(const QModelIndex &) const
106{
107 return m_workspaces.count();
108}
109
110QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
111{
112 if (index.row() < 0 || index.row() >= m_workspaces.size())
113 return QVariant();
114
115 if (role == WorkspaceRole) {
116 Workspace *workspace = m_workspaces.at(index.row());
117 return QVariant::fromValue(workspace);
118 } else {
119 return QVariant();
120 }
121}
122
123void WorkspaceModel::sync(WorkspaceModel *proxy)
124{
125 if (!proxy) return;
126 const auto& proxyList = proxy->list();
127
128 // check for removals
129 int removedIndexWhichWasActive = -1;
130 QVector<Workspace*> dpCpy(this->list());
131 Q_FOREACH(auto workspace, dpCpy) {
132
133 bool found = false;
134 Q_FOREACH(auto p, proxyList) {
135 auto workspaceProxy = qobject_cast<ProxyWorkspace*>(p);
136 if (workspaceProxy->proxyObject() == workspace) {
137 found = true;
138 break;
139 }
140 }
141 if (!found) {
142 if (workspace->isActive()) {
143 removedIndexWhichWasActive = indexOf(workspace);
144 }
145 workspace->unassign();
146 }
147 }
148
149 // existing
150 QSet<Workspace*> newWorkspaces;
151 for (int i = 0; i < proxyList.count(); i++) {
152 auto workspaceProxy = qobject_cast<ProxyWorkspace*>(proxyList[i]);
153 auto workspace = workspaceProxy->proxyObject();
154
155 int oldIndex = this->indexOf(workspace);
156
157 if (oldIndex < 0) {
158 workspace->assign(this, QVariant(i));
159 } else if (oldIndex != i) {
160 this->move(oldIndex, i);
161 }
162 newWorkspaces.insert(workspace);
163 }
164
165 // Make sure we have at least one workspace in the model.
166 if (rowCount() == 0) {
167 Workspace* workspace = WorkspaceManager::instance()->createWorkspace();
168 workspace->assign(this);
169 (new ProxyWorkspace(workspace))->assign(proxy);
170 }
171
172 if (removedIndexWhichWasActive != -1) {
173 int newActiveIndex = qMin(removedIndexWhichWasActive, this->rowCount()-1);
174 Workspace* newActiveWorkspace = newActiveIndex >= 0 ? this->get(newActiveIndex) : nullptr;
175
176 WorkspaceManager::instance()->setActiveWorkspace(newActiveWorkspace);
177 }
178
179 proxy->finishSync();
180 finishSync();
181}
182
183void WorkspaceModel::finishSync()
184{
185 QSet<Workspace*> dpCpy(m_unassignedWorkspaces);
186 Q_FOREACH(auto workspace, dpCpy) {
187 delete workspace;
188 }
189 m_unassignedWorkspaces.clear();
190}
191
192void WorkspaceModel::insertUnassigned(Workspace *workspace)
193{
194 m_unassignedWorkspaces.insert(workspace);
195 connect(workspace, &Workspace::assigned, this, [=]() {
196 m_unassignedWorkspaces.remove(workspace);
197 disconnect(workspace, &Workspace::assigned, this, 0);
198 });
199 connect(workspace, &QObject::destroyed, this, [=]() {
200 m_unassignedWorkspaces.remove(workspace);
201 });
202}
203
204
205ProxyWorkspaceModel::ProxyWorkspaceModel(WorkspaceModel * const model, ProxyScreen* screen)
206 : m_original(model)
207 , m_screen(screen)
208{
209 Q_FOREACH(auto workspace, model->list()) {
210 auto proxy = new ProxyWorkspace(workspace);
211 QQmlEngine::setObjectOwnership(proxy, QQmlEngine::CppOwnership);
212 proxy->assign(this);
213 }
214 connect(m_original, &WorkspaceModel::workspaceInserted, this, [this](int index, Workspace* inserted) {
215 if (isSyncing()) return;
216
217 (new ProxyWorkspace(inserted))->assign(this, index);
218 });
219 connect(m_original, &WorkspaceModel::workspaceRemoved, this, [this](Workspace* removed) {
220 if (isSyncing()) return;
221
222 for (int i = 0; i < rowCount(); i++) {
223 auto workspaceProxy = qobject_cast<ProxyWorkspace*>(get(i));
224 auto w = workspaceProxy->proxyObject();
225 if (w == removed) {
226 remove(workspaceProxy);
227 break;
228 }
229 }
230 });
231 connect(m_original, &WorkspaceModel::workspaceMoved, this, [this](int from, int to) {
232 if (isSyncing()) return;
233
234 move(from, to);
235 });
236}
237
238void ProxyWorkspaceModel::move(int from, int to)
239{
240 WorkspaceModel::move(from, to);
241}
242
243bool ProxyWorkspaceModel::isSyncing() const
244{
245 return m_screen->isSyncing();
246}
247
248void ProxyWorkspaceModel::addWorkspace()
249{
250 auto newWorkspace = WorkspaceManager::instance()->createWorkspace();
251 m_original->insertUnassigned(newWorkspace);
252
253 (new ProxyWorkspace(newWorkspace))->assign(this);
254}