/*
* Copyright (C) 2017 Canonical, Ltd.
*
* 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; version 3.
*
* 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, see .
*/
#include "WorkspaceModel.h"
#include "WorkspaceManager.h"
#include "Workspace.h"
#include
Q_LOGGING_CATEGORY(WORKSPACES, "Workspaces", QtInfoMsg)
#define DEBUG_MSG qCDebug(WORKSPACES).nospace().noquote() << __func__
#define INFO_MSG qCInfo(WORKSPACES).nospace().noquote() << __func__
WorkspaceModel::WorkspaceModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void WorkspaceModel::append(Workspace *workspace)
{
insert(m_workspaces.count(), workspace);
}
void WorkspaceModel::insert(int index, Workspace *workspace)
{
beginInsertRows(QModelIndex(), index, index);
m_workspaces.insert(index, workspace);
endInsertRows();
Q_EMIT workspaceInserted(index, workspace);
Q_EMIT countChanged();
}
void WorkspaceModel::remove(Workspace *workspace)
{
int index = m_workspaces.indexOf(workspace);
if (index < 0) return;
beginRemoveRows(QModelIndex(), index, index);
m_workspaces.removeAt(index);
endRemoveRows();
Q_EMIT workspaceRemoved(workspace);
Q_EMIT countChanged();
}
void WorkspaceModel::move(int from, int to)
{
if (from == to) return;
DEBUG_MSG << " from=" << from << " to=" << to;
if (from >= 0 && from < m_workspaces.size() && to >= 0 && to < m_workspaces.size()) {
QModelIndex parent;
beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
const auto &window = m_windowModel.takeAt(from);
m_workspaces.insert(to, window);
#else
m_workspaces.move(from, to);
#endif
endMoveRows();
Q_EMIT workspaceMoved(from, to);
}
}
int WorkspaceModel::indexOf(Workspace *workspace) const
{
return m_workspaces.indexOf(workspace);
}
Workspace *WorkspaceModel::get(int index) const
{
if (index < 0 || index >= rowCount()) return nullptr;
return m_workspaces.at(index);
}
int WorkspaceModel::rowCount(const QModelIndex &) const
{
return m_workspaces.count();
}
QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_workspaces.size())
return QVariant();
if (role == WorkspaceRole) {
Workspace *workspace = m_workspaces.at(index.row());
return QVariant::fromValue(workspace);
} else {
return QVariant();
}
}
void WorkspaceModel::sync(WorkspaceModel *proxy)
{
if (!proxy) return;
m_syncing = proxy;
const auto& proxyList = proxy->list();
// check for removals
int removedIndexWhichWasActive = -1;
QVector dpCpy(this->list());
Q_FOREACH(auto workspace, dpCpy) {
bool found = false;
Q_FOREACH(auto p, proxyList) {
auto workspaceProxy = qobject_cast(p);
if (workspaceProxy->proxyObject() == workspace) {
found = true;
break;
}
}
if (!found) {
if (workspace->isActive()) {
removedIndexWhichWasActive = indexOf(workspace);
}
workspace->unassign();
}
}
// existing
QSet newWorkspaces;
for (int i = 0; i < proxyList.count(); i++) {
auto workspaceProxy = qobject_cast(proxyList[i]);
auto workspace = workspaceProxy->proxyObject();
int oldIndex = this->indexOf(workspace);
if (oldIndex < 0) {
workspace->assign(this, QVariant(i));
} else if (oldIndex != i) {
this->move(oldIndex, i);
}
newWorkspaces.insert(workspace);
}
// Make sure we have at least one workspace in the model.
if (rowCount() == 0) {
Workspace* workspace = WorkspaceManager::instance()->createWorkspace();
workspace->assign(this);
(new WorkspaceProxy(workspace))->assign(proxy);
}
if (removedIndexWhichWasActive != -1) {
int newActiveIndex = qMin(removedIndexWhichWasActive, this->rowCount()-1);
Workspace* newActiveWorkspace = newActiveIndex >= 0 ? this->get(newActiveIndex) : nullptr;
WorkspaceManager::instance()->setActiveWorkspace(newActiveWorkspace);
}
m_syncing = nullptr;
}
bool WorkspaceModel::isSyncingWith(WorkspaceModel *m)
{
return m_syncing == m;
}
WorkspaceModelProxy::WorkspaceModelProxy(WorkspaceModel * const model)
: m_original(model)
{
Q_FOREACH(auto workspace, model->list()) {
auto proxy = new WorkspaceProxy(workspace);
QQmlEngine::setObjectOwnership(proxy, QQmlEngine::CppOwnership);
proxy->assign(this);
}
connect(m_original, &WorkspaceModel::workspaceInserted, this, [this](int index, Workspace* inserted) {
if (m_original->isSyncingWith(this)) return;
(new WorkspaceProxy(inserted))->assign(this, index);
});
connect(m_original, &WorkspaceModel::workspaceRemoved, this, [this](Workspace* removed) {
if (m_original->isSyncingWith(this)) return;
for (int i = 0; i < rowCount(); i++) {
auto workspaceProxy = qobject_cast(get(i));
auto w = workspaceProxy->proxyObject();
if (w == removed) {
remove(workspaceProxy);
break;
}
}
});
connect(m_original, &WorkspaceModel::workspaceMoved, this, [this](int from, int to) {
if (m_original->isSyncingWith(this)) return;
move(from, to);
});
}
WorkspaceModelProxy::~WorkspaceModelProxy()
{
qDeleteAll(m_workspaces.toList()); // make a copy so the list doesnt edit itself during delete.
m_workspaces.clear();
}
void WorkspaceModelProxy::move(int from, int to)
{
WorkspaceModel::move(from, to);
}