From ff04a41db25e012ed42a254cd5fe79b6056891fa Mon Sep 17 00:00:00 2001 From: GriffinR Date: Tue, 26 Nov 2024 11:36:11 -0500 Subject: [PATCH] Add map list tool tips / copy actions, simplify MapListModel --- include/mainwindow.h | 3 +- include/ui/maplistmodels.h | 125 +++------ src/mainwindow.cpp | 80 ++++-- src/ui/maplistmodels.cpp | 538 ++++++++++++------------------------- 4 files changed, 263 insertions(+), 483 deletions(-) diff --git a/include/mainwindow.h b/include/mainwindow.h index a144d6e3..17f19623 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -180,6 +180,7 @@ private slots: void duplicate(); void setClipboardData(poryjson::Json::object); void setClipboardData(QImage); + void setClipboardData(const QString &text); void copy(); void paste(); @@ -350,7 +351,7 @@ private: void openNewMapDialog(); void openNewLayoutDialog(); void openSubWindow(QWidget * window); - void scrollMapList(MapTree *list, QString itemName); + void scrollMapList(MapTree *list, const QString &itemName); void scrollMapListToCurrentMap(MapTree *list); void scrollMapListToCurrentLayout(MapTree *list); void resetMapListFilters(); diff --git a/include/ui/maplistmodels.h b/include/ui/maplistmodels.h index 59b65e50..1962ad40 100644 --- a/include/ui/maplistmodels.h +++ b/include/ui/maplistmodels.h @@ -61,15 +61,42 @@ class MapListModel : public QStandardItemModel { Q_OBJECT public: - MapListModel(QObject *parent = nullptr) : QStandardItemModel(parent) {}; + MapListModel(Project *project, QObject *parent = nullptr); ~MapListModel() { } - virtual QModelIndex indexOf(QString id) const = 0; + void setActiveItem(const QString &itemName) { this->activeItemName = itemName; } + + virtual QStandardItem *insertMapItem(const QString &mapName, const QString &folderName); + virtual QStandardItem *insertMapFolderItem(const QString &folderName); + + virtual QModelIndex indexOf(const QString &itemName) const; virtual void removeItemAt(const QModelIndex &index); - virtual QStandardItem *getItem(const QModelIndex &index) const = 0; + virtual QStandardItem *getItem(const QModelIndex &index) const; + + virtual QVariant data(const QModelIndex &index, int role) const override; protected: - virtual void removeItem(QStandardItem *item) = 0; + Project *project; + QStandardItem *root = nullptr; + + QString activeItemName; + QString folderTypeName; + bool sortingEnabled = false; + bool editable = false; + + QIcon mapGrayIcon; + QIcon mapIcon; + QIcon mapEditedIcon; + QIcon mapOpenedIcon; + QIcon mapFolderIcon; + QIcon emptyMapFolderIcon; + + QMap mapFolderItems; + QMap mapItems; + + virtual QStandardItem *createMapItem(const QString &mapName, QStandardItem *map = nullptr); + virtual QStandardItem *createMapFolderItem(const QString &groupName, QStandardItem *fromItem = nullptr); + virtual void removeItem(QStandardItem *item) = 0; }; class MapGroupModel : public MapListModel { @@ -80,44 +107,20 @@ public: ~MapGroupModel() { } QVariant data(const QModelIndex &index, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; Qt::DropActions supportedDropActions() const override; QStringList mimeTypes() const override; - virtual QMimeData *mimeData(const QModelIndexList &indexes) const override; - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; - - virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - -public: - void setMap(QString mapName) { this->openMap = mapName; } - - QStandardItem *createGroupItem(QString groupName, QStandardItem *fromItem = nullptr); - QStandardItem *createMapItem(QString mapName, QStandardItem *fromItem = nullptr); - - QStandardItem *insertGroupItem(QString groupName); - QStandardItem *insertMapItem(QString mapName, QString groupName); - - virtual QStandardItem *getItem(const QModelIndex &index) const override; - virtual QModelIndex indexOf(QString mapName) const override; - - void initialize(); + QMimeData *mimeData(const QModelIndexList &indexes) const override; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; protected: - virtual void removeItem(QStandardItem *item) override; + void removeItem(QStandardItem *item) override; private: friend class MapTree; void updateProject(); -private: - Project *project; - QStandardItem *root = nullptr; - - QMap groupItems; - QMap mapItems; - - QString openMap; - signals: void dragMoveCompleted(); }; @@ -131,36 +134,8 @@ public: MapAreaModel(Project *project, QObject *parent = nullptr); ~MapAreaModel() {} - QVariant data(const QModelIndex &index, int role) const override; - -public: - void setMap(QString mapName) { this->openMap = mapName; } - - QStandardItem *createAreaItem(QString areaName); - QStandardItem *createMapItem(QString mapName); - - QStandardItem *insertAreaItem(QString areaName); - QStandardItem *insertMapItem(QString mapName, QString areaName); - - virtual QStandardItem *getItem(const QModelIndex &index) const override; - virtual QModelIndex indexOf(QString mapName) const override; - - void initialize(); - protected: - virtual void removeItem(QStandardItem *item) override; - -private: - Project *project; - QStandardItem *root = nullptr; - - QMap areaItems; - QMap mapItems; - - QString openMap; - -signals: - void edited(); + void removeItem(QStandardItem *item) override; }; @@ -174,34 +149,8 @@ public: QVariant data(const QModelIndex &index, int role) const override; -public: - void setLayout(QString layoutId) { this->openLayout = layoutId; } - - QStandardItem *createLayoutItem(QString layoutId); - QStandardItem *createMapItem(QString mapName); - - QStandardItem *insertLayoutItem(QString layoutId); - QStandardItem *insertMapItem(QString mapName, QString layoutId); - - virtual QStandardItem *getItem(const QModelIndex &index) const override; - virtual QModelIndex indexOf(QString layoutName) const override; - - void initialize(); - protected: - virtual void removeItem(QStandardItem *item) override; - -private: - Project *project; - QStandardItem *root = nullptr; - - QMap layoutItems; - QMap mapItems; - - QString openLayout; - -signals: - void edited(); + void removeItem(QStandardItem *item) override; }; #endif // MAPLISTMODELS_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 615fd40d..bb01d5c5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -956,9 +956,6 @@ bool MainWindow::setLayout(QString layoutId) { logInfo("Switching to layout-only editing mode. Disabling map-related edits."); unsetMap(); - - layoutTreeModel->setLayout(layoutId); - refreshMapScene(); updateWindowTitle(); updateMapList(); @@ -1163,7 +1160,7 @@ void MainWindow::clearProjectUI() { Event::clearIcons(); } -void MainWindow::scrollMapList(MapTree *list, QString itemName) { +void MainWindow::scrollMapList(MapTree *list, const QString &itemName) { if (!list || itemName.isEmpty()) return; auto model = static_cast(list->model()); @@ -1208,9 +1205,16 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) { QAction* addToFolderAction = nullptr; QAction* deleteFolderAction = nullptr; QAction* openItemAction = nullptr; + QAction* copyDisplayNameAction = nullptr; + QAction* copyToolTipAction = nullptr; + if (itemType == "map_name") { // Right-clicking on a map. openItemAction = menu.addAction("Open Map"); + menu.addSeparator(); + copyDisplayNameAction = menu.addAction("Copy Map Name"); + copyToolTipAction = menu.addAction("Copy Map ID"); + menu.addSeparator(); connect(menu.addAction("Duplicate Map"), &QAction::triggered, [this, itemName] { auto dialog = new NewMapDialog(this->editor->project, this->editor->project->getMap(itemName), this); dialog->open(); @@ -1226,12 +1230,18 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) { // Right-clicking on a MAPSEC folder addToFolderAction = menu.addAction("Add New Map to Area"); menu.addSeparator(); + copyDisplayNameAction = menu.addAction("Copy Area Name"); + menu.addSeparator(); deleteFolderAction = menu.addAction("Delete Area"); if (itemName == this->editor->project->getEmptyMapsecName()) deleteFolderAction->setEnabled(false); // Disallow deleting the default name } else if (itemType == "map_layout") { // Right-clicking on a map layout openItemAction = menu.addAction("Open Layout"); + menu.addSeparator(); + copyDisplayNameAction = menu.addAction("Copy Layout Name"); + copyToolTipAction = menu.addAction("Copy Layout ID"); + menu.addSeparator(); connect(menu.addAction("Duplicate Layout"), &QAction::triggered, [this, itemName] { auto layout = this->editor->project->loadLayout(itemName); if (layout) { @@ -1261,8 +1271,21 @@ void MainWindow::onOpenMapListContextMenu(const QPoint &point) { deleteFolderAction->setEnabled(false); } } + if (openItemAction) { - connect(openItemAction, &QAction::triggered, [this, index] { openMapListItem(index); }); + connect(openItemAction, &QAction::triggered, [this, index] { + openMapListItem(index); + }); + } + if (copyDisplayNameAction) { + connect(copyDisplayNameAction, &QAction::triggered, [this, sourceModel, index] { + setClipboardData(sourceModel->data(index, Qt::DisplayRole).toString()); + }); + } + if (copyToolTipAction) { + connect(copyToolTipAction, &QAction::triggered, [this, sourceModel, index] { + setClipboardData(sourceModel->data(index, Qt::ToolTipRole).toString()); + }); } if (menu.actions().length() != 0) @@ -1399,17 +1422,17 @@ void MainWindow::onNewLayoutCreated(Layout *layout) { } // Add new layout to the Layouts map list view - this->layoutTreeModel->insertLayoutItem(layout->id); + this->layoutTreeModel->insertMapFolderItem(layout->id); } void MainWindow::onNewMapGroupCreated(const QString &groupName) { // Add new map group to the Groups map list view - this->mapGroupModel->insertGroupItem(groupName); + this->mapGroupModel->insertMapFolderItem(groupName); } void MainWindow::onNewMapSectionCreated(const QString &idName) { // Add new map section to the Areas map list view - this->mapAreaModel->insertAreaItem(idName); + this->mapAreaModel->insertMapFolderItem(idName); // TODO: Refresh Region Map Editor's map section dropdown, if it's open } @@ -1627,28 +1650,28 @@ void MainWindow::openMapListItem(const QModelIndex &index) { } void MainWindow::updateMapList() { + // Get the name of the open map/layout (or clear the relevant selection if there is none). + QString activeItemName; if (this->editor->map) { - this->mapGroupModel->setMap(this->editor->map->name()); - this->groupListProxyModel->layoutChanged(); - this->mapAreaModel->setMap(this->editor->map->name()); - this->areaListProxyModel->layoutChanged(); + activeItemName = this->editor->map->name(); } else { - this->mapGroupModel->setMap(QString()); - this->groupListProxyModel->layoutChanged(); - this->ui->mapList->clearSelection(); - this->mapAreaModel->setMap(QString()); - this->areaListProxyModel->layoutChanged(); - this->ui->areaList->clearSelection(); + ui->mapList->clearSelection(); + ui->areaList->clearSelection(); + + if (this->editor->layout) { + activeItemName = this->editor->layout->id; + } else { + ui->layoutList->clearSelection(); + } } - if (this->editor->layout) { - this->layoutTreeModel->setLayout(this->editor->layout->id); - this->layoutListProxyModel->layoutChanged(); - } else { - this->layoutTreeModel->setLayout(QString()); - this->layoutListProxyModel->layoutChanged(); - this->ui->layoutList->clearSelection(); - } + this->mapGroupModel->setActiveItem(activeItemName); + this->mapAreaModel->setActiveItem(activeItemName); + this->layoutTreeModel->setActiveItem(activeItemName); + + this->groupListProxyModel->layoutChanged(); + this->areaListProxyModel->layoutChanged(); + this->layoutListProxyModel->layoutChanged(); } void MainWindow::on_action_Save_Project_triggered() { @@ -1782,6 +1805,11 @@ void MainWindow::setClipboardData(OrderedJson::object object) { clipboard->setText(newText); } +void MainWindow::setClipboardData(const QString &text) { + QClipboard *clipboard = QGuiApplication::clipboard(); + clipboard->setText(text); +} + void MainWindow::setClipboardData(QImage image) { QClipboard *clipboard = QGuiApplication::clipboard(); clipboard->setImage(image); diff --git a/src/ui/maplistmodels.cpp b/src/ui/maplistmodels.cpp index be5b0932..6d5dd45d 100644 --- a/src/ui/maplistmodels.cpp +++ b/src/ui/maplistmodels.cpp @@ -38,6 +38,43 @@ void MapTree::keyPressEvent(QKeyEvent *event) { } } + + +MapListModel::MapListModel(Project *project, QObject *parent) : QStandardItemModel(parent) { + this->project = project; + this->root = invisibleRootItem(); + + this->mapGrayIcon = QIcon(QStringLiteral(":/icons/map_grayed.ico")); + this->mapIcon = QIcon(QStringLiteral(":/icons/map.ico")); + this->mapEditedIcon = QIcon(QStringLiteral(":/icons/map_edited.ico")); + this->mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico")); + + this->mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off); + this->mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On); + + this->emptyMapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off); + this->emptyMapFolderIcon.addFile(QStringLiteral(":/icons/folder.ico"), QSize(), QIcon::Normal, QIcon::On); +} + +QStandardItem *MapListModel::getItem(const QModelIndex &index) const { + if (index.isValid()) { + QStandardItem *item = static_cast(index.internalPointer()); + if (item) + return item; + } + return this->root; +} + +QModelIndex MapListModel::indexOf(const QString &itemName) const { + if (this->mapItems.contains(itemName)) + return this->mapItems.value(itemName)->index(); + + if (this->mapFolderItems.contains(itemName)) + return this->mapFolderItems.value(itemName)->index(); + + return QModelIndex(); +} + void MapListModel::removeItemAt(const QModelIndex &index) { QStandardItem *item = this->getItem(index)->child(index.row(), index.column()); if (!item) @@ -49,11 +86,89 @@ void MapListModel::removeItemAt(const QModelIndex &index) { } else { // TODO: Because there's no support for deleting maps we can only delete empty folders if (!item->hasChildren()) { - this->removeItem(item); + removeItem(item); } } } +QStandardItem *MapListModel::createMapItem(const QString &mapName, QStandardItem *map) { + if (!map) map = new QStandardItem; + map->setText(mapName); + map->setData(mapName, MapListUserRoles::NameRole); + map->setData("map_name", MapListUserRoles::TypeRole); + map->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemNeverHasChildren); + map->setEditable(this->editable); // Will override flags if necessary + this->mapItems.insert(mapName, map); + return map; +} + +QStandardItem *MapListModel::createMapFolderItem(const QString &folderName, QStandardItem *folder) { + if (!folder) folder = new QStandardItem; + folder->setText(folderName); + folder->setData(folderName, MapListUserRoles::NameRole); + folder->setData(this->folderTypeName, MapListUserRoles::TypeRole); + folder->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); + folder->setEditable(this->editable); // Will override flags if necessary + this->mapFolderItems.insert(folderName, folder); + return folder; +} + +QStandardItem *MapListModel::insertMapItem(const QString &mapName, const QString &folderName) { + // Disallow adding MAP_DYNAMIC to the map list. + if (mapName == this->project->getDynamicMapName()) + return nullptr; + + QStandardItem *folder = this->mapFolderItems[folderName]; + if (!folder) folder = insertMapFolderItem(folderName); + + QStandardItem *map = createMapItem(mapName); + folder->appendRow(map); + if (this->sortingEnabled) + this->sort(0, Qt::AscendingOrder); + return map; +} + +QStandardItem *MapListModel::insertMapFolderItem(const QString &folderName) { + QStandardItem *item = createMapFolderItem(folderName); + this->root->appendRow(item); + if (this->sortingEnabled) + this->sort(0, Qt::AscendingOrder); + return item; +} + +QVariant MapListModel::data(const QModelIndex &index, int role) const { + if (!index.isValid()) + return QVariant(); + + int row = index.row(); + int col = index.column(); + + const QStandardItem *item = this->getItem(index)->child(row, col); + const QString type = item->data(MapListUserRoles::TypeRole).toString(); + const QString name = item->data(MapListUserRoles::NameRole).toString(); + + if (type == "map_name") { + // Data for maps in the map list + if (role == Qt::DecorationRole) { + if (name == this->activeItemName) + return this->mapOpenedIcon; + + const Map* map = this->project->mapCache.value(name); + if (!map) + return this->mapGrayIcon; + return map->hasUnsavedChanges() ? this->mapEditedIcon : this->mapIcon; + } else if (role == Qt::ToolTipRole) { + return this->project->mapNamesToMapConstants.value(name); + } + } else if (type == this->folderTypeName) { + // Data for map folders in the map list + if (role == Qt::DecorationRole) { + return item->hasChildren() ? this->mapFolderIcon : this->emptyMapFolderIcon; + } + } + return QStandardItemModel::data(index, role); +} + QWidget *GroupNameDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &) const { @@ -83,11 +198,15 @@ void GroupNameDelegate::updateEditorGeometry(QWidget *editor, const QStyleOption -MapGroupModel::MapGroupModel(Project *project, QObject *parent) : MapListModel(parent) { - this->project = project; - this->root = this->invisibleRootItem(); +MapGroupModel::MapGroupModel(Project *project, QObject *parent) : MapListModel(project, parent) { + this->folderTypeName = "map_group"; + this->editable = true; - initialize(); + for (const auto &groupName : this->project->groupNames) { + for (const auto &mapName : this->project->groupNameToMapNames.value(groupName)) { + insertMapItem(mapName, groupName); + } + } } Qt::DropActions MapGroupModel::supportedDropActions() const { @@ -173,7 +292,7 @@ bool MapGroupModel::dropMimeData(const QMimeData *data, Qt::DropAction action, i QModelIndex groupIndex = index(row, 0, parentIndex); QStandardItem *groupItem = this->itemFromIndex(groupIndex); - createGroupItem(groupName, groupItem); + createMapFolderItem(groupName, groupItem); for (QString mapName : mapsToMove) { QStandardItem *mapItem = createMapItem(mapName); @@ -251,143 +370,36 @@ void MapGroupModel::updateProject() { this->project->hasUnsavedDataChanges = true; } -QStandardItem *MapGroupModel::createGroupItem(QString groupName, QStandardItem *group) { - if (!group) group = new QStandardItem; - group->setText(groupName); - group->setData(groupName, MapListUserRoles::NameRole); - group->setData("map_group", MapListUserRoles::TypeRole); - group->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable); - this->groupItems.insert(groupName, group); - return group; -} - -QStandardItem *MapGroupModel::createMapItem(QString mapName, QStandardItem *map) { - if (!map) map = new QStandardItem; - map->setData(mapName, MapListUserRoles::NameRole); - map->setData("map_name", MapListUserRoles::TypeRole); - map->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); - this->mapItems[mapName] = map; - return map; -} - -QStandardItem *MapGroupModel::insertGroupItem(QString groupName) { - QStandardItem *group = createGroupItem(groupName); - this->root->appendRow(group); - return group; -} - void MapGroupModel::removeItem(QStandardItem *item) { this->removeRow(item->row()); this->updateProject(); } -QStandardItem *MapGroupModel::insertMapItem(QString mapName, QString groupName) { - QStandardItem *group = this->groupItems[groupName]; - if (!group) { - group = insertGroupItem(groupName); - } - QStandardItem *map = createMapItem(mapName); - group->appendRow(map); - return map; -} - -void MapGroupModel::initialize() { - this->groupItems.clear(); - this->mapItems.clear(); - - - for (const auto &groupName : this->project->groupNames) { - QStandardItem *group = createGroupItem(groupName); - root->appendRow(group); - for (const auto &mapName : this->project->groupNameToMapNames.value(groupName)) { - group->appendRow(createMapItem(mapName)); - } - } -} - -QStandardItem *MapGroupModel::getItem(const QModelIndex &index) const { - if (index.isValid()) { - QStandardItem *item = static_cast(index.internalPointer()); - if (item) - return item; - } - return this->root; -} - -QModelIndex MapGroupModel::indexOf(QString mapName) const { - if (this->mapItems.contains(mapName)) { - return this->mapItems[mapName]->index(); - } - return QModelIndex(); -} - QVariant MapGroupModel::data(const QModelIndex &index, int role) const { - if (!index.isValid()) return QVariant(); + if (!index.isValid()) + return QVariant(); int row = index.row(); int col = index.column(); - if (role == Qt::DecorationRole) { - static QIcon mapGrayIcon = QIcon(QStringLiteral(":/icons/map_grayed.ico")); - static QIcon mapIcon = QIcon(QStringLiteral(":/icons/map.ico")); - static QIcon mapEditedIcon = QIcon(QStringLiteral(":/icons/map_edited.ico")); - static QIcon mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico")); - - static QIcon mapFolderIcon; - static QIcon folderIcon; - static bool loaded = false; - if (!loaded) { - mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off); - mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On); - folderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off); - folderIcon.addFile(QStringLiteral(":/icons/folder.ico"), QSize(), QIcon::Normal, QIcon::On); - loaded = true; - } - - QStandardItem *item = this->getItem(index)->child(row, col); - QString type = item->data(MapListUserRoles::TypeRole).toString(); - - if (type == "map_group") { - if (!item->hasChildren()) { - return folderIcon; - } - return mapFolderIcon; - } else if (type == "map_name") { - QString mapName = item->data(MapListUserRoles::NameRole).toString(); - if (mapName == this->openMap) { - return mapOpenedIcon; - } - else if (this->project->mapCache.contains(mapName)) { - if (this->project->mapCache.value(mapName)->hasUnsavedChanges()) { - return mapEditedIcon; - } - else { - return mapIcon; - } - } - return mapGrayIcon; - } - } - else if (role == Qt::DisplayRole) { - QStandardItem *item = this->getItem(index)->child(row, col); - QString type = item->data(MapListUserRoles::TypeRole).toString(); + const QStandardItem *item = this->getItem(index)->child(row, col); + const QString type = item->data(MapListUserRoles::TypeRole).toString(); + const QString name = item->data(MapListUserRoles::NameRole).toString(); + if (role == Qt::DisplayRole) { if (type == "map_name") { - return QString("[%1.%2] ").arg(this->getItem(index)->row()).arg(row, 2, 10, QLatin1Char('0')) + item->data(MapListUserRoles::NameRole).toString(); + return QString("[%1.%2] ").arg(this->getItem(index)->row()).arg(row, 2, 10, QLatin1Char('0')) + name; } - else if (type == "map_group") { - return item->data(MapListUserRoles::NameRole).toString(); + else if (type == this->folderTypeName) { + return name; } } - - return QStandardItemModel::data(index, role); + return MapListModel::data(index, role); } bool MapGroupModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == MapListUserRoles::NameRole && data(index, MapListUserRoles::TypeRole).toString() == "map_group") { - // verify uniqueness of new group name - // TODO: Check that the name is a valid symbol name (i.e. only word characters, not starting with a number) - if (this->project->groupNames.contains(value.toString())) { + if (!this->project->isIdentifierUnique(value.toString())) { return false; } } @@ -399,50 +411,15 @@ bool MapGroupModel::setData(const QModelIndex &index, const QVariant &value, int -MapAreaModel::MapAreaModel(Project *project, QObject *parent) : MapListModel(parent) { - this->project = project; - this->root = this->invisibleRootItem(); +MapAreaModel::MapAreaModel(Project *project, QObject *parent) : MapListModel(project, parent) { + this->folderTypeName = "map_section"; - initialize(); -} - -QStandardItem *MapAreaModel::createAreaItem(QString mapsecName) { - QStandardItem *area = new QStandardItem; - area->setText(mapsecName); - area->setEditable(false); - area->setData(mapsecName, MapListUserRoles::NameRole); - area->setData("map_section", MapListUserRoles::TypeRole); - // group->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); - this->areaItems.insert(mapsecName, area); - return area; -} - -QStandardItem *MapAreaModel::createMapItem(QString mapName) { - QStandardItem *map = new QStandardItem; - map->setText(mapName); - map->setEditable(false); - map->setData(mapName, MapListUserRoles::NameRole); - map->setData("map_name", MapListUserRoles::TypeRole); - // map->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); - this->mapItems.insert(mapName, map); - return map; -} - -QStandardItem *MapAreaModel::insertAreaItem(QString areaName) { - QStandardItem *item = createAreaItem(areaName); - this->root->appendRow(item); - this->sort(0, Qt::AscendingOrder); - return item; -} - -QStandardItem *MapAreaModel::insertMapItem(QString mapName, QString areaName) { - QStandardItem *area = this->areaItems[areaName]; - if (!area) { - return nullptr; + for (const auto &mapName : this->project->mapNames) { + insertMapItem(mapName, this->project->mapNameToMapSectionName.value(mapName)); } - QStandardItem *map = createMapItem(mapName); - area->appendRow(map); - return map; + + this->sortingEnabled = true; + sort(0, Qt::AscendingOrder); } void MapAreaModel::removeItem(QStandardItem *item) { @@ -450,227 +427,52 @@ void MapAreaModel::removeItem(QStandardItem *item) { this->removeRow(item->row()); } -void MapAreaModel::initialize() { - this->areaItems.clear(); - this->mapItems.clear(); - for (const auto &idName : this->project->mapSectionIdNames) { - this->root->appendRow(createAreaItem(idName)); - } + +LayoutTreeModel::LayoutTreeModel(Project *project, QObject *parent) : MapListModel(project, parent) { + this->folderTypeName = "map_layout"; for (const auto &mapName : this->project->mapNames) { - const QString mapsecName = this->project->mapNameToMapSectionName.value(mapName); - if (this->areaItems.contains(mapsecName)) - this->areaItems[mapsecName]->appendRow(createMapItem(mapName)); + insertMapItem(mapName, this->project->mapNameToLayoutId.value(mapName)); } - this->sort(0, Qt::AscendingOrder); -} - -QStandardItem *MapAreaModel::getItem(const QModelIndex &index) const { - if (index.isValid()) { - QStandardItem *item = static_cast(index.internalPointer()); - if (item) - return item; - } - return this->root; -} - -QModelIndex MapAreaModel::indexOf(QString mapName) const { - if (this->mapItems.contains(mapName)) { - return this->mapItems[mapName]->index(); - } - return QModelIndex(); -} - -QVariant MapAreaModel::data(const QModelIndex &index, int role) const { - if (!index.isValid()) return QVariant(); - - int row = index.row(); - int col = index.column(); - - if (role == Qt::DecorationRole) { - static QIcon mapGrayIcon = QIcon(QStringLiteral(":/icons/map_grayed.ico")); - static QIcon mapIcon = QIcon(QStringLiteral(":/icons/map.ico")); - static QIcon mapEditedIcon = QIcon(QStringLiteral(":/icons/map_edited.ico")); - static QIcon mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico")); - - static QIcon mapFolderIcon; - static QIcon folderIcon; - static bool loaded = false; - if (!loaded) { - mapFolderIcon.addFile(QStringLiteral(":/icons/folder_closed_map.ico"), QSize(), QIcon::Normal, QIcon::Off); - mapFolderIcon.addFile(QStringLiteral(":/icons/folder_map.ico"), QSize(), QIcon::Normal, QIcon::On); - folderIcon.addFile(QStringLiteral(":/icons/folder_closed.ico"), QSize(), QIcon::Normal, QIcon::Off); - folderIcon.addFile(QStringLiteral(":/icons/folder.ico"), QSize(), QIcon::Normal, QIcon::On); - loaded = true; - } - - QStandardItem *item = this->getItem(index)->child(row, col); - QString type = item->data(MapListUserRoles::TypeRole).toString(); - - if (type == "map_section") { - if (item->hasChildren()) { - return mapFolderIcon; - } - return folderIcon; - } else if (type == "map_name") { - QString mapName = item->data(MapListUserRoles::NameRole).toString(); - if (mapName == this->openMap) { - return mapOpenedIcon; - } - else if (this->project->mapCache.contains(mapName)) { - if (this->project->mapCache.value(mapName)->hasUnsavedChanges()) { - return mapEditedIcon; - } - else { - return mapIcon; - } - } - return mapGrayIcon; - } - } - else if (role == Qt::DisplayRole) { - QStandardItem *item = this->getItem(index)->child(row, col); - QString type = item->data(MapListUserRoles::TypeRole).toString(); - - if (type == "map_section") { - return item->data(MapListUserRoles::NameRole).toString(); - } - } - - return QStandardItemModel::data(index, role); -} - - - -LayoutTreeModel::LayoutTreeModel(Project *project, QObject *parent) : MapListModel(parent) { - this->project = project; - this->root = this->invisibleRootItem(); - - initialize(); -} - -QStandardItem *LayoutTreeModel::createLayoutItem(QString layoutId) { - QStandardItem *layout = new QStandardItem; - layout->setText(this->project->mapLayouts[layoutId]->name); - layout->setEditable(false); - layout->setData(layoutId, MapListUserRoles::NameRole); - layout->setData("map_layout", MapListUserRoles::TypeRole); - // // group->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); - this->layoutItems.insert(layoutId, layout); - return layout; -} - -QStandardItem *LayoutTreeModel::createMapItem(QString mapName) { - QStandardItem *map = new QStandardItem; - map->setText(mapName); - map->setEditable(false); - map->setData(mapName, MapListUserRoles::NameRole); - map->setData("map_name", MapListUserRoles::TypeRole); - map->setFlags(Qt::NoItemFlags | Qt::ItemNeverHasChildren); - this->mapItems.insert(mapName, map); - return map; -} - -QStandardItem *LayoutTreeModel::insertLayoutItem(QString layoutId) { - QStandardItem *layoutItem = this->createLayoutItem(layoutId); - this->root->appendRow(layoutItem); - this->sort(0, Qt::AscendingOrder); - return layoutItem; -} - -QStandardItem *LayoutTreeModel::insertMapItem(QString mapName, QString layoutId) { - QStandardItem *layout = nullptr; - if (this->layoutItems.contains(layoutId)) { - layout = this->layoutItems[layoutId]; - } - else { - layout = createLayoutItem(layoutId); - this->root->appendRow(layout); - } - if (!layout) { - return nullptr; - } - QStandardItem *map = createMapItem(mapName); - layout->appendRow(map); - return map; + this->sortingEnabled = true; + sort(0, Qt::AscendingOrder); } void LayoutTreeModel::removeItem(QStandardItem *) { // TODO: Deleting layouts not supported } - -void LayoutTreeModel::initialize() { - this->layoutItems.clear(); - this->mapItems.clear(); - - for (const auto &layoutId : this->project->layoutIds) { - this->root->appendRow(createLayoutItem(layoutId)); - } - - for (const auto &mapName : this->project->mapNames) { - QString layoutId = project->mapNameToLayoutId.value(mapName); - if (this->layoutItems.contains(layoutId)) - this->layoutItems[layoutId]->appendRow(createMapItem(mapName)); - } - - this->sort(0, Qt::AscendingOrder); -} - -QStandardItem *LayoutTreeModel::getItem(const QModelIndex &index) const { - if (index.isValid()) { - QStandardItem *item = static_cast(index.internalPointer()); - if (item) - return item; - } - return this->root; -} - -QModelIndex LayoutTreeModel::indexOf(QString layoutName) const { - if (this->layoutItems.contains(layoutName)) { - return this->layoutItems[layoutName]->index(); - } - return QModelIndex(); -} - QVariant LayoutTreeModel::data(const QModelIndex &index, int role) const { - if (!index.isValid()) return QVariant(); + if (!index.isValid()) + return QVariant(); int row = index.row(); int col = index.column(); - if (role == Qt::DecorationRole) { - static QIcon mapGrayIcon = QIcon(QStringLiteral(":/icons/map_grayed.ico")); - static QIcon mapIcon = QIcon(QStringLiteral(":/icons/map.ico")); - static QIcon mapEditedIcon = QIcon(QStringLiteral(":/icons/map_edited.ico")); - static QIcon mapOpenedIcon = QIcon(QStringLiteral(":/icons/map_opened.ico")); + const QStandardItem *item = this->getItem(index)->child(row, col); + const QString type = item->data(MapListUserRoles::TypeRole).toString(); + const QString name = item->data(MapListUserRoles::NameRole).toString(); - QStandardItem *item = this->getItem(index)->child(row, col); - QString type = item->data(MapListUserRoles::TypeRole).toString(); + if (type == this->folderTypeName) { + const Layout* layout = this->project->mapLayouts.value(name); - if (type == "map_layout") { - QString layoutId = item->data(MapListUserRoles::NameRole).toString(); - if (layoutId == this->openLayout) { - return mapOpenedIcon; - } - else if (this->project->mapLayouts.contains(layoutId)) { - if (this->project->mapLayouts.value(layoutId)->hasUnsavedChanges()) { - return mapEditedIcon; - } - else if (!this->project->mapLayouts[layoutId]->loaded) { - return mapGrayIcon; - } - } - return mapIcon; + if (role == Qt::DecorationRole) { + // Map layouts are used as folders, but we display them with the same icons as maps. + if (name == this->activeItemName) + return this->mapOpenedIcon; + + if (!layout || !layout->loaded) + return this->mapGrayIcon; + return layout->hasUnsavedChanges() ? this->mapEditedIcon : this->mapIcon; } - else if (type == "map_name") { - return QVariant(); + else if (role == Qt::DisplayRole) { + // Despite using layout IDs internally, the Layouts map list shows layouts using their file path name. + if (layout) return layout->name; + } else if (role == Qt::ToolTipRole) { + if (layout) return layout->id; } - - return QVariant(); } - - return QStandardItemModel::data(index, role); + return MapListModel::data(index, role); }