diff options
Diffstat (limited to 'src/Authoring/Qt3DStudio/Palettes/Slide/SlideModel.cpp')
-rw-r--r-- | src/Authoring/Qt3DStudio/Palettes/Slide/SlideModel.cpp | 468 |
1 files changed, 468 insertions, 0 deletions
diff --git a/src/Authoring/Qt3DStudio/Palettes/Slide/SlideModel.cpp b/src/Authoring/Qt3DStudio/Palettes/Slide/SlideModel.cpp new file mode 100644 index 00000000..c07377c1 --- /dev/null +++ b/src/Authoring/Qt3DStudio/Palettes/Slide/SlideModel.cpp @@ -0,0 +1,468 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SlideModel.h" + +#include "CmdActivateSlide.h" +#include "Core.h" +#include "Doc.h" +#include "StudioApp.h" +#include "SlideSystem.h" +#include "IDocumentEditor.h" + +#include "ClientDataModelBridge.h" +#include "Qt3DSDMStudioSystem.h" +#include "Qt3DSDMSlides.h" + +SlideModel::SlideModel(int slideCount, QObject *parent) : QAbstractListModel(parent) + , m_slides(slideCount) +{ +} + +QVariant SlideModel::data(const QModelIndex &index, int role) const +{ + if (!hasIndex(index.row(), index.column(),index.parent())) + return {}; + + const auto row = index.row(); + + switch (role) { + case NameRole: + return slideName(m_slides[row]); + case SelectedRole: + return row == m_selectedRow; + case VariantsRole: + int slideIdx = GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideIndex(m_slides[row]); + if (slideIdx < m_variantsModel.size()) { + const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef(); + const auto keys = m_variantsModelKeys[slideIdx]; + QString templ = QString::fromWCharArray(L"<font color='%1'>\u25A0</font>"); + QString slideVariants; + for (auto g : keys) // variants groups + slideVariants.append(templ.arg(variantsDef[g].m_color)); + + return slideVariants; + } + } + + return {}; +} + +bool SlideModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!hasIndex(index.row(), index.column(),index.parent())) + return false; + + auto &slideHandle = m_slides[index.row()]; + + switch (role) { + case NameRole: { + setSlideName(slideHandle, value.toString()); + Q_EMIT dataChanged(index, index, {role}); + break; + } + case HandleRole: { + slideHandle = value.value<qt3dsdm::Qt3DSDMSlideHandle>(); + qt3dsdm::Qt3DSDMInstanceHandle instanceHandle + = GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideInstance(slideHandle); + m_slideLookupHash.insert(instanceHandle, slideHandle); + Q_EMIT dataChanged(index, index, {HandleRole, NameRole}); + break; + } + case SelectedRole: { + m_selectedRow = value.toBool() ? index.row() : -1; + + if (m_selectedRow != -1) { + CCmdActivateSlide *theCmd = new CCmdActivateSlide(GetDoc(), m_slides[m_selectedRow]); + g_StudioApp.GetCore()->ExecuteCommand(theCmd); + } + + Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {role}); + break; + } + default: + return false; + } + + return true; +} + +int SlideModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return m_slides.count(); +} + +QHash<int, QByteArray> SlideModel::roleNames() const +{ + auto names = QAbstractListModel::roleNames(); + names.insert(NameRole, "name"); + names.insert(VariantsRole, "variants"); + names.insert(SelectedRole, "selected"); + + return names; +} + +bool SlideModel::insertRows(int row, int count, const QModelIndex &parent) +{ + if (row > m_slides.count()) + return false; + + beginInsertRows(parent, row, row + count - 1); + for (int i = 0; i < count; ++i) + m_slides.insert(row, {}); + endInsertRows(); + + setData(index(row + count - 1), true, SelectedRole); + return true; +} + +bool SlideModel::removeRows(int row, int count, const QModelIndex &parent) +{ + if (row + count > m_slides.count()) + return false; + + bool selectionRemoved = false; + beginRemoveRows(parent, row, row + count - 1); + for (int i = 0; i < count; ++i) { + if (m_selectedRow == row + i) + selectionRemoved = true; + m_slides.removeAt(row); + } + endRemoveRows(); + + auto newSelectedRow = -1; + if (selectionRemoved) { + if (row > 0) + newSelectedRow = row - 1; + else + newSelectedRow = 0; + } else if (m_selectedRow > row) { + newSelectedRow = m_selectedRow - count; + } + if (newSelectedRow != -1) + setData(index(newSelectedRow), true, SelectedRole); + + return true; +} + +void SlideModel::duplicateRow(int row) +{ + const auto handle = m_slides[row]; + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Duplicate Slide")) + ->DuplicateSlide(handle); +} + +void SlideModel::startRearrange(int row) +{ + m_rearrangeStartRow = row; + m_rearrangeEndRow = -1; +} + +void SlideModel::move(int fromRow, int toRow) +{ + if (fromRow == toRow) + return; + + onSlideRearranged({}, fromRow + 1, toRow + 1); +} + +void SlideModel::finishRearrange(bool commit) +{ + if (m_rearrangeEndRow != m_rearrangeStartRow + && m_rearrangeEndRow >= 0 && m_rearrangeStartRow >= 0) { + // Restore state before committing the actual change + // +1 added as DocumentEditor uses 1 based indexes for slides + int endRow = m_rearrangeEndRow + 1; + onSlideRearranged({}, endRow, m_rearrangeStartRow + 1); + + if (commit) { + auto handle = m_slides[m_rearrangeStartRow]; + m_rearrangeStartRow = -1; + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Rearrange Slide")) + ->RearrangeSlide(handle, endRow); + } + } + m_rearrangeEndRow = -1; + m_rearrangeStartRow = -1; +} + +void SlideModel::clear() +{ + beginResetModel(); + m_slides.clear(); + m_slideLookupHash.clear(); + endResetModel(); +} + +void SlideModel::addNewSlide(int row) +{ + const auto handle = (row < m_slides.size()) ? m_slides[row] : m_slides.last(); + const auto instanceHandle = GetBridge()->GetOwningComponentInstance(handle); + qt3dsdm::Qt3DSDMSlideHandle theMasterSlide = GetBridge()->GetComponentSlide(instanceHandle, 0); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Create Slide")) + ->AddSlide(theMasterSlide, row + 1); +} + +void SlideModel::removeSlide(int row) +{ + // Don't allow deleting of the last slide + if (m_slides.size() > 1) { + const auto handle = m_slides[row]; + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Delete Slide"))->DeleteSlide( + handle); + } +} + +void SlideModel::onNewSlide(const qt3dsdm::Qt3DSDMSlideHandle &inSlide) +{ + qt3dsdm::ISlideSystem &theSlideSystem(*GetDoc()->GetStudioSystem()->GetSlideSystem()); + + // Ignore new slides added to random different components + if (m_slides.size() && theSlideSystem.GetMasterSlide(inSlide) + != theSlideSystem.GetMasterSlide(m_slides[0])) { + return; + } + + finishRearrange(false); // Cancel any uncommitted rearrange + + // Find the slide index + int row = int(slideIndex(inSlide)); + + // Slide index zero indicates master slide. We can't add master slides + Q_ASSERT(row > 0); + + --row; + + beginInsertRows({}, row, row); + m_slides.insert(row, inSlide); + qt3dsdm::Qt3DSDMInstanceHandle instanceHandle + = GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideInstance(inSlide); + m_slideLookupHash.insert(instanceHandle, inSlide); + endInsertRows(); + + setData(index(row), true, SelectedRole); +} + +void SlideModel::onDeleteSlide(const qt3dsdm::Qt3DSDMSlideHandle &inSlide) +{ + for (int i = 0; i < m_slides.size(); ++i) { + if (m_slides[i] == inSlide) { + if (m_rearrangeStartRow >= 0) { + finishRearrange(false); // Cancel any uncommitted rearrange + // We need to re-resolve the index after rearrange cancel + for (int j = 0; j < m_slides.size(); ++j) { + if (m_slides[j] == inSlide) { + i = j; + break; + } + } + } + QList<qt3dsdm::Qt3DSDMInstanceHandle> keys = m_slideLookupHash.keys(inSlide); + for (auto key : keys) + m_slideLookupHash.remove(key); + removeRows(i, 1); + break; + } + } +} + +void SlideModel::onSlideRearranged(const qt3dsdm::Qt3DSDMSlideHandle &inMaster, int fromRow, + int toRow) +{ + if (inMaster.Valid()) { + // If imMaster is valid, this was triggered by either a rearrange commit or + // undo/redo of a rearrange, so we need to cancel any uncommitted rearrange. + finishRearrange(false); + // Check we are working on correct slide set + qt3dsdm::ISlideSystem &theSlideSystem(*GetDoc()->GetStudioSystem()->GetSlideSystem()); + if (fromRow - 1 >= m_slides.size() + || inMaster != theSlideSystem.GetMasterSlide(m_slides[fromRow - 1])) + return; + } else { + // Do not do uncommitted rearranges if we haven't started a rearrange (or more likely + // an uncommitted rearrange was canceled while in progress by undo/redo operation) + if (m_rearrangeStartRow < 0) + return; + } + + // -1 because internal slide model has 1-based indexing for non-master slides + if (fromRow > toRow) + beginMoveRows({}, fromRow - 1, fromRow - 1, {}, toRow - 1); + else + beginMoveRows({}, fromRow - 1, fromRow - 1, {}, toRow); + m_slides.move(fromRow - 1, toRow - 1); + m_rearrangeEndRow = toRow - 1; + + endMoveRows(); +} + +bool SlideModel::hasSlideWithName(const QString &name) const +{ + for (const auto &slide: m_slides) { + if (slideName(slide) == name) + return true; + } + return false; +} + +QString SlideModel::slideName(const qt3dsdm::Qt3DSDMSlideHandle &handle) const +{ + auto doc = GetDoc(); + if (!doc->isValid()) + return {}; + const auto instanceHandle = doc->GetStudioSystem()->GetSlideSystem()->GetSlideInstance(handle); + return GetBridge()->GetName(instanceHandle).toQString(); +} + +void SlideModel::setSlideName(const qt3dsdm::Qt3DSDMSlideHandle &handle, const QString &name) +{ + const auto oldName = slideName(handle); + if (oldName != name && !name.trimmed().isEmpty()) { + using namespace qt3dsdm; + CDoc *theDoc = GetDoc(); + CClientDataModelBridge *theBridge = GetBridge(); + if (!theBridge) + return; + const auto instanceHandle = GetDoc()->GetStudioSystem()-> + GetSlideSystem()->GetSlideInstance(handle); + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Set Slide Name")) + ->SetSlideName(instanceHandle, theBridge->GetNameProperty(), + Q3DStudio::CString::fromQString(oldName), + Q3DStudio::CString::fromQString(name)); + } +} + +void SlideModel::refreshVariants(const QVector<QHash<QString, QStringList>> &vModel, + const QVector<QStringList> &vModelKeys) +{ + m_variantsModel.clear(); + m_variantsModelKeys.clear(); + + if (vModel.isEmpty()) { + const auto *slideSystem = GetDoc()->GetStudioSystem()->GetSlideSystem(); + int slideCount = slideSystem->GetSlideCount(slideSystem->GetMasterSlide( + GetDoc()->GetActiveSlide())); + m_variantsModel.resize(slideCount); + m_variantsModelKeys.resize(slideCount); + + const auto propertySystem = GetDoc()->GetPropertySystem(); + const QVector<int> instances = GetDoc()->getVariantInstances(); + for (auto instance : instances) { + int slideIdx = slideIndex(slideSystem->GetAssociatedSlide(instance)); + qt3dsdm::SValue sValue; + if (propertySystem->GetInstancePropertyValue(instance, + GetBridge()->getVariantsProperty(instance), + sValue)) { + QString propVal = qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)->toQString(); + if (!propVal.isEmpty()) { + QStringList tagPairs = propVal.split(QLatin1Char(',')); + for (int i = 0; i < tagPairs.size(); ++i) { + QStringList pair = tagPairs[i].split(QLatin1Char(':')); + if (!m_variantsModel[slideIdx][pair[0]].contains(pair[1])) + m_variantsModel[slideIdx][pair[0]].append(pair[1]); + + if (!m_variantsModelKeys[slideIdx].contains(pair[0])) + m_variantsModelKeys[slideIdx].append(pair[0]); + } + } + } + } + + // add master slide variants to other slides + const auto keys = m_variantsModel[0].keys(); + for (int i = 1; i < slideCount; ++i) { + for (auto g : keys) { + for (int j = 0; j < m_variantsModel[0][g].length(); ++j) { + if (!m_variantsModel[i][g].contains(m_variantsModel[0][g][j])) + m_variantsModel[i][g].append(m_variantsModel[0][g][j]); + } + + if (!m_variantsModelKeys[i].contains(g)) + m_variantsModelKeys[i].append(g); + } + } + } else { + m_variantsModel = vModel; + m_variantsModelKeys = vModelKeys; + } + + Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {VariantsRole}); +} + +CDoc *SlideModel::GetDoc() const +{ + return g_StudioApp.GetCore()->GetDoc(); +} + +long SlideModel::slideIndex(const qt3dsdm::Qt3DSDMSlideHandle &handle) const +{ + return GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideIndex(handle); +} + +int SlideModel::rowToSlideIndex(int row) const +{ + return GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideIndex(m_slides[row]); +} + +CClientDataModelBridge *SlideModel::GetBridge() const +{ + auto doc = GetDoc(); + if (!doc->isValid()) + return nullptr; + return doc->GetStudioSystem()->GetClientDataModelBridge(); +} + +void SlideModel::refreshSlideLabel(qt3dsdm::Qt3DSDMInstanceHandle instanceHandle, + qt3dsdm::Qt3DSDMPropertyHandle propertyHandle) +{ + if (m_slideLookupHash.contains(instanceHandle) + && propertyHandle == GetBridge()->GetNameProperty()) { + qt3dsdm::Qt3DSDMSlideHandle slideHandle = m_slideLookupHash.value(instanceHandle); + for (int i = 0; i < m_slides.size(); ++i) { + if (m_slides[i] == slideHandle) { + setData(index(i, 0), GetBridge()->GetName(instanceHandle).toQString(), + SlideModel::NameRole); + break; + } + } + } +} + +// Set selected slide highlight on UI +void SlideModel::setSelectedSlideIndex(const QModelIndex &index) +{ + if (m_selectedRow == index.row() || + !hasIndex(index.row(), index.column(), index.parent())) + return; + + m_selectedRow = index.row(); + Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {SelectedRole}); +} |