diff --git a/NEWS.md b/NEWS.md index 45ac6f586db..8d79b173da5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -27,6 +27,7 @@ * Automapping: Added per-input-layer properties for ignoring flip flags (#3803) * AutoMapping: Always apply output sets with empty index * Windows: Fixed the support for WebP images (updated to Qt 6.6.1, #3661) +* Fixed issues related to map and tileset reloading * Fixed possible crash after assigning to tiled.activeAsset * Fixed the option to resolve properties on export to also resolve class members (#3411, #3315) * Fixed terrain tool behavior and terrain overlays after changing terrain set type (#3204, #3260) diff --git a/docs/scripting-doc/index.d.ts b/docs/scripting-doc/index.d.ts index c6042e6fe51..14089409ea1 100644 --- a/docs/scripting-doc/index.d.ts +++ b/docs/scripting-doc/index.d.ts @@ -4607,6 +4607,13 @@ declare namespace tiled { */ export const assetOpened: Signal; + /** + * An asset has been reloaded. + * + * @since 1.11 + */ + export const assetReloaded: Signal; + /** * An asset is about to be saved. Can be used to make last-minute * changes. diff --git a/src/libtiled/layer.cpp b/src/libtiled/layer.cpp index e8363105800..f982709dabc 100644 --- a/src/libtiled/layer.cpp +++ b/src/libtiled/layer.cpp @@ -366,7 +366,7 @@ bool LayerIterator::operator==(const LayerIterator &other) const * Returns the global layer index for the given \a layer. Obtained by iterating * the layer's map while incrementing the index until layer is found. */ -int globalIndex(Layer *layer) +int globalIndex(const Layer *layer) { if (!layer) return -1; diff --git a/src/libtiled/layer.h b/src/libtiled/layer.h index d79e83d8a1e..ae6881e5b00 100644 --- a/src/libtiled/layer.h +++ b/src/libtiled/layer.h @@ -436,7 +436,7 @@ inline Layer *LayerIterator::operator->() const } -TILEDSHARED_EXPORT int globalIndex(Layer *layer); +TILEDSHARED_EXPORT int globalIndex(const Layer *layer); TILEDSHARED_EXPORT Layer *layerAtGlobalIndex(const Map *map, int index); } // namespace Tiled diff --git a/src/libtiled/wangset.cpp b/src/libtiled/wangset.cpp index 3bc9d590f88..c816022592e 100644 --- a/src/libtiled/wangset.cpp +++ b/src/libtiled/wangset.cpp @@ -418,6 +418,12 @@ WangSet::WangSet(Tileset *tileset, setType(type); } +WangSet::~WangSet() +{ + for (auto &color : std::as_const(mColors)) + color->mWangSet = nullptr; +} + /** * Changes the type of this Wang set. * diff --git a/src/libtiled/wangset.h b/src/libtiled/wangset.h index 08a67327812..2955762c0a9 100644 --- a/src/libtiled/wangset.h +++ b/src/libtiled/wangset.h @@ -258,6 +258,7 @@ class TILEDSHARED_EXPORT WangSet : public Object const QString &name, Type type, int imageTileId = -1); + ~WangSet(); Tileset *tileset() const; void setTileset(Tileset *tileset); diff --git a/src/tiled/brokenlinks.cpp b/src/tiled/brokenlinks.cpp index a11ad8d0415..2e52379b2d7 100644 --- a/src/tiled/brokenlinks.cpp +++ b/src/tiled/brokenlinks.cpp @@ -20,6 +20,7 @@ #include "brokenlinks.h" +#include "changeevents.h" #include "changetileimagesource.h" #include "documentmanager.h" #include "fileformat.h" @@ -117,6 +118,9 @@ void BrokenLinksModel::setDocument(Document *document) if (mDocument) { if (auto mapDocument = qobject_cast(mDocument)) { + connect(mDocument, &Document::changed, + this, &BrokenLinksModel::documentChanged); + connect(mapDocument, &MapDocument::tilesetAdded, this, &BrokenLinksModel::tilesetAdded); connect(mapDocument, &MapDocument::tilesetRemoved, @@ -127,8 +131,6 @@ void BrokenLinksModel::setDocument(Document *document) for (const SharedTileset &tileset : mapDocument->map()->tilesets()) connectToTileset(tileset); - connect(DocumentManager::instance(), &DocumentManager::templateTilesetReplaced, - this, &BrokenLinksModel::refresh); } else if (auto tilesetDocument = qobject_cast(mDocument)) { connectToTileset(tilesetDocument->tileset()); } @@ -304,15 +306,37 @@ QVariant BrokenLinksModel::headerData(int section, Qt::Orientation orientation, return QVariant(); } +void BrokenLinksModel::documentChanged(const ChangeEvent &event) +{ + switch (event.type) { + case ChangeEvent::DocumentAboutToReload: + if (auto mapDocument = qobject_cast(mDocument)) { + for (const SharedTileset &tileset : mapDocument->map()->tilesets()) + disconnectFromTileset(tileset); + } + break; + case ChangeEvent::DocumentReloaded: + refresh(); + + if (auto mapDocument = qobject_cast(mDocument)) { + for (const SharedTileset &tileset : mapDocument->map()->tilesets()) + connectToTileset(tileset); + } + break; + default: + break; + } +} + void BrokenLinksModel::tileImageSourceChanged(Tile *tile) { auto matchesTile = [tile](const BrokenLink &link) { return link.type == TilesetTileImageSource && link._tile == tile; }; - QVector::iterator it = std::find_if(mBrokenLinks.begin(), - mBrokenLinks.end(), - matchesTile); + auto it = std::find_if(mBrokenLinks.begin(), + mBrokenLinks.end(), + matchesTile); if (!tile->imageSource().isEmpty() && tile->imageStatus() == LoadingError) { if (it != mBrokenLinks.end()) { diff --git a/src/tiled/brokenlinks.h b/src/tiled/brokenlinks.h index f1af3eada06..96660590bfb 100644 --- a/src/tiled/brokenlinks.h +++ b/src/tiled/brokenlinks.h @@ -90,6 +90,8 @@ class BrokenLinksModel : public QAbstractListModel void hasBrokenLinksChanged(bool hasBrokenLinks); private: + void documentChanged(const ChangeEvent &event); + void tileImageSourceChanged(Tile *tile); void tilesetChanged(Tileset *tileset); diff --git a/src/tiled/changeevents.h b/src/tiled/changeevents.h index b01bbd77555..c5e4061f274 100644 --- a/src/tiled/changeevents.h +++ b/src/tiled/changeevents.h @@ -37,6 +37,8 @@ class ChangeEvent { public: enum Type { + DocumentAboutToReload, + DocumentReloaded, ObjectsChanged, MapChanged, LayerChanged, @@ -71,6 +73,22 @@ class ChangeEvent {} }; +class AboutToReloadEvent : public ChangeEvent +{ +public: + AboutToReloadEvent() + : ChangeEvent(DocumentAboutToReload) + {} +}; + +class ReloadEvent : public ChangeEvent +{ +public: + ReloadEvent() + : ChangeEvent(DocumentReloaded) + {} +}; + class ObjectsChangeEvent : public ChangeEvent { public: diff --git a/src/tiled/document.cpp b/src/tiled/document.cpp index ef0b7b404c8..0802fe17fe1 100644 --- a/src/tiled/document.cpp +++ b/src/tiled/document.cpp @@ -166,6 +166,10 @@ void Document::setCurrentObject(Object *object, Document *owningDocument) void Document::currentObjectDocumentChanged(const ChangeEvent &change) { switch (change.type) { + case ChangeEvent::DocumentAboutToReload: + setCurrentObject(nullptr); + break; + case ChangeEvent::TilesAboutToBeRemoved: { auto tilesEvent = static_cast(change); diff --git a/src/tiled/document.h b/src/tiled/document.h index 29995c50697..14fcac25e6a 100644 --- a/src/tiled/document.h +++ b/src/tiled/document.h @@ -88,6 +88,8 @@ class Document : public QObject, */ virtual bool save(const QString &fileName, QString *error = nullptr) = 0; + virtual bool canReload() const { return false; } + virtual FileFormat *writerFormat() const = 0; QDateTime lastSaved() const { return mLastSaved; } diff --git a/src/tiled/documentmanager.cpp b/src/tiled/documentmanager.cpp index d8a902e899b..458b175caae 100644 --- a/src/tiled/documentmanager.cpp +++ b/src/tiled/documentmanager.cpp @@ -116,6 +116,9 @@ DocumentManager::DocumentManager(QObject *parent) connect(mFileChangedWarning, &FileChangedWarning::reload, this, &DocumentManager::reloadCurrentDocument); connect(mFileChangedWarning, &FileChangedWarning::ignore, this, &DocumentManager::hideChangedWarning); + connect(this, &DocumentManager::templateTilesetReplaced, + mBrokenLinksModel, &BrokenLinksModel::refresh); + QVBoxLayout *vertical = new QVBoxLayout(mWidget); vertical->addWidget(mTabBar); vertical->addWidget(mFileChangedWarning); @@ -573,14 +576,18 @@ int DocumentManager::insertDocument(int index, const DocumentPtr &document) if (Editor *editor = mEditorForType.value(document->type())) editor->addDocument(documentPtr); - mTabBar->insertTab(index, QString()); - updateDocumentTab(documentPtr); - + // Connect before adding the tab, so that we handle the 'changed' signal + // first, since we may be creating TilesetDocument instances for tilesets + // used by a reloaded map (design not ideal...). connect(documentPtr, &Document::fileNameChanged, this, &DocumentManager::fileNameChanged); connect(documentPtr, &Document::modifiedChanged, this, [=] { updateDocumentTab(documentPtr); }); connect(documentPtr, &Document::isReadOnlyChanged, this, [=] { updateDocumentTab(documentPtr); }); + connect(documentPtr, &Document::changed, this, &DocumentManager::onDocumentChanged); connect(documentPtr, &Document::saved, this, &DocumentManager::onDocumentSaved); + mTabBar->insertTab(index, QString()); + updateDocumentTab(documentPtr); + if (auto *mapDocument = qobject_cast(documentPtr)) { connect(mapDocument, &MapDocument::tilesetAdded, this, &DocumentManager::tilesetAdded); connect(mapDocument, &MapDocument::tilesetRemoved, this, &DocumentManager::tilesetRemoved); @@ -904,55 +911,38 @@ bool DocumentManager::reloadCurrentDocument() } /** - * Reloads the document at the given \a index. It will lose any undo - * history and current selections. Will not ask the user whether to save - * any changes! + * Reloads the document at the given \a index. Will not ask the user whether to + * save any changes! * * Returns whether the document loaded successfully. */ bool DocumentManager::reloadDocumentAt(int index) { - const auto oldDocument = mDocuments.at(index); + const auto document = mDocuments.at(index); QString error; - if (auto mapDocument = oldDocument.objectCast()) { - auto readerFormat = mapDocument->readerFormat(); - if (!readerFormat) - return false; - - // TODO: Consider fixing the reload to avoid recreating the MapDocument - auto newDocument = MapDocument::load(oldDocument->fileName(), - readerFormat, - &error); - if (!newDocument) { - emit reloadError(tr("%1:\n\n%2").arg(oldDocument->fileName(), error)); + if (auto mapDocument = document.objectCast()) { + if (!mapDocument->reload(&error)) { + emit reloadError(tr("%1:\n\n%2").arg(document->fileName(), error)); return false; } - // Save the document state, to ensure the new document will match it - static_cast(editor(Document::MapDocumentType))->saveDocumentState(mapDocument.data()); - - // Replace old tab const bool isCurrent = index == mTabBar->currentIndex(); - insertDocument(index, newDocument); if (isCurrent) { - switchToDocument(index); - if (mBrokenLinksModel->hasBrokenLinks()) mBrokenLinksWidget->show(); } - closeDocumentAt(index + 1); - checkTilesetColumns(newDocument.data()); + checkTilesetColumns(mapDocument.data()); - } else if (auto tilesetDocument = qobject_cast(oldDocument)) { + } else if (auto tilesetDocument = qobject_cast(document)) { if (tilesetDocument->isEmbedded()) { // For embedded tilesets, we need to reload the map index = findDocument(tilesetDocument->mapDocuments().first()); if (!reloadDocumentAt(index)) return false; } else if (!tilesetDocument->reload(&error)) { - emit reloadError(tr("%1:\n\n%2").arg(oldDocument->fileName(), error)); + emit reloadError(tr("%1:\n\n%2").arg(document->fileName(), error)); return false; } @@ -962,6 +952,8 @@ bool DocumentManager::reloadDocumentAt(int index) if (!isDocumentChangedOnDisk(currentDocument())) mFileChangedWarning->setVisible(false); + emit documentReloaded(document.data()); + return true; } @@ -1035,6 +1027,27 @@ void DocumentManager::updateDocumentTab(Document *document) mTabBar->setTabToolTip(index, tabToolTip); } +void DocumentManager::onDocumentChanged(const ChangeEvent &event) +{ + auto mapDocument = qobject_cast(sender()); + if (!mapDocument) + return; + + // In case a map is reloaded, the set of used tilesets might have changed + switch (event.type) { + case ChangeEvent::DocumentAboutToReload: + for (const SharedTileset &tileset : mapDocument->map()->tilesets()) + removeFromTilesetDocument(tileset, mapDocument); + break; + case ChangeEvent::DocumentReloaded: + for (const SharedTileset &tileset : mapDocument->map()->tilesets()) + addToTilesetDocument(tileset, mapDocument); + break; + default: + break; + } +} + void DocumentManager::onDocumentSaved() { Document *document = static_cast(sender()); diff --git a/src/tiled/documentmanager.h b/src/tiled/documentmanager.h index bdc02fea170..04b9386c716 100644 --- a/src/tiled/documentmanager.h +++ b/src/tiled/documentmanager.h @@ -147,6 +147,7 @@ class DocumentManager : public QObject signals: void documentCreated(Document *document); void documentOpened(Document *document); + void documentReloaded(Document *document); void documentAboutToBeSaved(Document *document); void documentSaved(Document *document); @@ -198,6 +199,7 @@ public slots: void fileNameChanged(const QString &fileName, const QString &oldFileName); void updateDocumentTab(Document *document); + void onDocumentChanged(const ChangeEvent &event); void onDocumentSaved(); void documentTabMoved(int from, int to); void tabContextMenuRequested(const QPoint &pos); diff --git a/src/tiled/editablemap.cpp b/src/tiled/editablemap.cpp index b55031dbc6a..2d5d0a12540 100644 --- a/src/tiled/editablemap.cpp +++ b/src/tiled/editablemap.cpp @@ -698,6 +698,16 @@ void EditableMap::setDocument(Document *document) void EditableMap::documentChanged(const ChangeEvent &change) { switch (change.type) { + case ChangeEvent::DocumentAboutToReload: + for (Layer *layer : map()->layers()) + detachLayer(layer); + + mRenderer.reset(); + setObject(nullptr); + break; + case ChangeEvent::DocumentReloaded: + setObject(mapDocument()->map()); + break; case ChangeEvent::MapChanged: if (static_cast(change).property == Map::OrientationProperty) mRenderer.reset(); diff --git a/src/tiled/editabletileset.cpp b/src/tiled/editabletileset.cpp index 9c0f1910187..9662ccefc13 100644 --- a/src/tiled/editabletileset.cpp +++ b/src/tiled/editabletileset.cpp @@ -22,6 +22,7 @@ #include "addremovetiles.h" #include "addremovewangset.h" +#include "changeevents.h" #include "editabletile.h" #include "editablewangset.h" #include "scriptimage.h" @@ -402,6 +403,7 @@ void EditableTileset::setDocument(Document *document) if (auto doc = tilesetDocument()) { connect(doc, &Document::fileNameChanged, this, &EditableAsset::fileNameChanged); + connect(doc, &Document::changed, this, &EditableTileset::documentChanged); connect(doc, &TilesetDocument::tilesAdded, this, &EditableTileset::attachTiles); connect(doc, &TilesetDocument::tilesRemoved, this, &EditableTileset::detachTiles); connect(doc, &TilesetDocument::tileObjectGroupChanged, this, &EditableTileset::tileObjectGroupChanged); @@ -429,6 +431,23 @@ bool EditableTileset::tilesFromEditables(const QList &editableTiles, return true; } +void EditableTileset::documentChanged(const ChangeEvent &event) +{ + switch (event.type) { + case ChangeEvent::DocumentAboutToReload: + detachTiles(tileset()->tiles()); + detachWangSets(tileset()->wangSets()); + + setObject(nullptr); + break; + case ChangeEvent::DocumentReloaded: + setObject(tilesetDocument()->tileset().data()); + break; + default: + break; + } +} + void EditableTileset::attachTiles(const QList &tiles) { for (Tile *tile : tiles) { diff --git a/src/tiled/editabletileset.h b/src/tiled/editabletileset.h index 599934803cb..2d6390b87ed 100644 --- a/src/tiled/editabletileset.h +++ b/src/tiled/editabletileset.h @@ -25,6 +25,7 @@ namespace Tiled { +class ChangeEvent; class EditableTile; class EditableWangSet; class ScriptImage; @@ -179,6 +180,7 @@ public slots: private: bool tilesFromEditables(const QList &editableTiles, QList &tiles); + void documentChanged(const ChangeEvent &event); void attachTiles(const QList &tiles); void detachTiles(const QList &tiles); void detachWangSets(const QList &wangSets); diff --git a/src/tiled/layerdock.cpp b/src/tiled/layerdock.cpp index 19d5a43b4f0..4810d0367d2 100644 --- a/src/tiled/layerdock.cpp +++ b/src/tiled/layerdock.cpp @@ -312,6 +312,8 @@ void LayerView::setMapDocument(MapDocument *mapDocument) auto layerModel = mMapDocument->layerModel(); mProxyModel->setSourceModel(layerModel); + connect(mMapDocument, &MapDocument::changed, + this, &LayerView::documentChanged); connect(mMapDocument, &MapDocument::currentLayerChanged, this, &LayerView::currentLayerChanged); connect(mMapDocument, &MapDocument::selectedLayersChanged, @@ -319,14 +321,7 @@ void LayerView::setMapDocument(MapDocument *mapDocument) connect(mMapDocument, &MapDocument::layerRemoved, this, &LayerView::layerRemoved); - // Restore expanded layers - for (const int layerId : std::as_const(mMapDocument->expandedGroupLayers)) { - if (Layer *layer = mMapDocument->map()->findLayerById(layerId)) { - const QModelIndex sourceIndex = layerModel->index(layer); - const QModelIndex index = mProxyModel->mapFromSource(sourceIndex); - setExpanded(index, true); - } - } + restoreExpandedLayers(); currentLayerChanged(mMapDocument->currentLayer()); selectedLayersChanged(); @@ -358,6 +353,18 @@ void LayerView::onCollapsed(const QModelIndex &proxyIndex) mMapDocument->expandedGroupLayers.remove(layer->id()); } +void LayerView::restoreExpandedLayers() +{ + const LayerModel *layerModel = mMapDocument->layerModel(); + for (const int layerId : std::as_const(mMapDocument->expandedGroupLayers)) { + if (Layer *layer = mMapDocument->map()->findLayerById(layerId)) { + const QModelIndex sourceIndex = layerModel->index(layer); + const QModelIndex index = mProxyModel->mapFromSource(sourceIndex); + setExpanded(index, true); + } + } +} + void LayerView::currentRowChanged(const QModelIndex &proxyIndex) { if (!mMapDocument) @@ -377,6 +384,17 @@ void LayerView::indexPressed(const QModelIndex &proxyIndex) mMapDocument->setCurrentObject(layer); } +void LayerView::documentChanged(const ChangeEvent &event) +{ + switch (event.type) { + case ChangeEvent::DocumentReloaded: + restoreExpandedLayers(); + break; + default: + break; + } +} + void LayerView::currentLayerChanged(Layer *layer) { const LayerModel *layerModel = mMapDocument->layerModel(); diff --git a/src/tiled/layerdock.h b/src/tiled/layerdock.h index 61053a57e69..41e286c530f 100644 --- a/src/tiled/layerdock.h +++ b/src/tiled/layerdock.h @@ -103,9 +103,12 @@ class LayerView : public QTreeView private: void onExpanded(const QModelIndex &index); void onCollapsed(const QModelIndex &index); + void restoreExpandedLayers(); void currentRowChanged(const QModelIndex &proxyIndex); void indexPressed(const QModelIndex &proxyIndex); + + void documentChanged(const ChangeEvent &event); void currentLayerChanged(Layer *layer); void selectedLayersChanged(); void layerRemoved(Layer *layer); diff --git a/src/tiled/layermodel.cpp b/src/tiled/layermodel.cpp index da91ba463bf..0607add6eda 100644 --- a/src/tiled/layermodel.cpp +++ b/src/tiled/layermodel.cpp @@ -27,7 +27,6 @@ #include "map.h" #include "mapdocument.h" #include "reparentlayers.h" -#include "tilelayer.h" #include #include @@ -39,8 +38,6 @@ using namespace Tiled; LayerModel::LayerModel(QObject *parent): QAbstractItemModel(parent), - mMapDocument(nullptr), - mMap(nullptr), mTileLayerIcon(QLatin1String(":/images/16/layer-tile.png")), mObjectGroupIcon(QLatin1String(":/images/16/layer-object.png")), mImageLayerIcon(QLatin1String(":/images/16/layer-image.png")) @@ -53,7 +50,7 @@ QModelIndex LayerModel::index(int row, int column, const QModelIndex &parent) co { // Top-level layer index if (!parent.isValid()) { - if (row < mMap->layerCount()) + if (row < map()->layerCount()) return createIndex(row, column, nullptr); return QModelIndex(); } @@ -88,7 +85,7 @@ int LayerModel::rowCount(const QModelIndex &parent) const return 0; } - return mMap ? mMap->layerCount() : 0; + return map()->layerCount(); } int LayerModel::columnCount(const QModelIndex &parent) const @@ -305,7 +302,7 @@ bool LayerModel::dropMimeData(const QMimeData *data, Qt::DropAction action, while (!stream.atEnd()) { int globalIndex; stream >> globalIndex; - if (Layer *layer = layerAtGlobalIndex(mMap, globalIndex)) + if (Layer *layer = layerAtGlobalIndex(map(), globalIndex)) layers.append(layer); } @@ -333,7 +330,7 @@ QModelIndex LayerModel::index(Layer *layer, int column) const if (!layer) return QModelIndex(); - Q_ASSERT(layer->map() == mMap); + Q_ASSERT(layer->map() == map()); if (auto parentLayer = layer->parentLayer()) { int row = parentLayer->layers().indexOf(layer); @@ -341,7 +338,7 @@ QModelIndex LayerModel::index(Layer *layer, int column) const return createIndex(row, column, parentLayer); } - int row = mMap->layers().indexOf(layer); + int row = map()->layers().indexOf(layer); Q_ASSERT(row != -1); return createIndex(row, column, nullptr); } @@ -354,7 +351,7 @@ Layer *LayerModel::toLayer(const QModelIndex &index) const if (auto groupLayer = static_cast(index.internalPointer())) return groupLayer->layerAt(index.row()); - return mMap->layerAt(index.row()); + return map()->layerAt(index.row()); } /** @@ -373,7 +370,6 @@ void LayerModel::setMapDocument(MapDocument *mapDocument) beginResetModel(); mMapDocument = mapDocument; - mMap = mMapDocument->map(); endResetModel(); } @@ -388,7 +384,7 @@ void LayerModel::insertLayer(GroupLayer *parentLayer, int index, Layer *layer) if (parentLayer) parentLayer->insertLayer(index, layer); else - mMap->insertLayer(index, layer); + map()->insertLayer(index, layer); endInsertRows(); emit layerAdded(layer); } @@ -407,7 +403,7 @@ Layer *LayerModel::takeLayerAt(GroupLayer *parentLayer, int index) if (parentLayer) layer = parentLayer->takeLayerAt(index); else - layer = mMap->takeLayerAt(index); + layer = map()->takeLayerAt(index); endRemoveRows(); emit layerRemoved(layer); return layer; @@ -585,6 +581,12 @@ void LayerModel::toggleLockOtherLayers(const QList &layers) void LayerModel::documentChanged(const ChangeEvent &change) { switch (change.type) { + case ChangeEvent::DocumentAboutToReload: + beginResetModel(); + break; + case ChangeEvent::DocumentReloaded: + endResetModel(); + break; case ChangeEvent::LayerChanged: { const auto &layerChange = static_cast(change); @@ -610,4 +612,9 @@ void LayerModel::documentChanged(const ChangeEvent &change) } } +Map *LayerModel::map() const +{ + return mMapDocument->map(); +} + #include "moc_layermodel.cpp" diff --git a/src/tiled/layermodel.h b/src/tiled/layermodel.h index 6249ff18f67..8b837be5cc2 100644 --- a/src/tiled/layermodel.h +++ b/src/tiled/layermodel.h @@ -98,8 +98,9 @@ class LayerModel : public QAbstractItemModel private: void documentChanged(const ChangeEvent &change); - MapDocument *mMapDocument; - Map *mMap; + Map *map() const; + + MapDocument *mMapDocument = nullptr; QIcon mTileLayerIcon; QIcon mObjectGroupIcon; diff --git a/src/tiled/mainwindow.cpp b/src/tiled/mainwindow.cpp index 66a177a1137..483dc5c7435 100644 --- a/src/tiled/mainwindow.cpp +++ b/src/tiled/mainwindow.cpp @@ -2151,7 +2151,7 @@ void MainWindow::updateActions() mUi->actionExportAsImage->setEnabled(mapDocument); mUi->actionExport->setEnabled(mapDocument || tilesetDocument); mUi->actionExportAs->setEnabled(mapDocument || tilesetDocument); - mUi->actionReload->setEnabled(mapDocument || (tilesetDocument && tilesetDocument->canReload())); + mUi->actionReload->setEnabled(document && document->canReload()); mUi->actionClose->setEnabled(document); mUi->actionCloseAll->setEnabled(document); diff --git a/src/tiled/mapdocument.cpp b/src/tiled/mapdocument.cpp index ec679f8dc33..a2cae50efb6 100644 --- a/src/tiled/mapdocument.cpp +++ b/src/tiled/mapdocument.cpp @@ -69,6 +69,25 @@ using namespace Tiled; +class ReloadMap : public QUndoCommand +{ +public: + ReloadMap(MapDocument *mapDocument, std::unique_ptr map) + : mMapDocument(mapDocument) + , mMap(std::move(map)) + { + setText(QCoreApplication::translate("Undo Commands", "Reload Map")); + } + + void undo() override { mMapDocument->swapMap(mMap); } + void redo() override { mMapDocument->swapMap(mMap); } + +private: + MapDocument *mMapDocument; + std::unique_ptr mMap; +}; + + MapDocument::MapDocument(std::unique_ptr map) : Document(MapDocumentType, map->fileName) , mMap(std::move(map)) @@ -158,6 +177,42 @@ bool MapDocument::save(const QString &fileName, QString *error) return true; } +bool MapDocument::canReload() const +{ + return !fileName().isEmpty() && !mReaderFormat.isEmpty(); +} + +bool MapDocument::reload(QString *error) +{ + if (!canReload()) + return false; + + auto format = findFileFormat(mReaderFormat, FileFormat::Read); + if (!format) { + if (error) + *error = tr("Map format '%s' not found").arg(mReaderFormat); + return false; + } + + auto map = format->read(fileName()); + + if (!map) { + if (error) + *error = format->errorString(); + return false; + } + + map->fileName = fileName(); + + undoStack()->push(new ReloadMap(this, std::move(map))); + undoStack()->setClean(); + + mLastSaved = QFileInfo(fileName()).lastModified(); + setChangedOnDisk(false); + + return true; +} + MapDocumentPtr MapDocument::load(const QString &fileName, MapFormat *format, QString *error) @@ -1532,6 +1587,54 @@ void MapDocument::checkIssues() } } +void MapDocument::swapMap(std::unique_ptr &other) +{ + // Store previous state + const int currentLayerId = currentLayer() ? currentLayer()->id() : -1; + + QVector selectedLayerIds; + for (const Layer *layer : selectedLayers()) + selectedLayerIds.append(layer->id()); + + QVector selectedObjectIds; + for (const MapObject *object : selectedObjects()) + selectedObjectIds.append(object->id()); + + // Bring pointers to safety + setSelectedLayers({}); + setSelectedObjects({}); + setAboutToBeSelectedObjects({}); + setHoveredMapObject(nullptr); + setCurrentLayer(nullptr); + setCurrentObject(nullptr); + + emit changed(AboutToReloadEvent()); + + mMap.swap(other); + createRenderer(); + + emit changed(ReloadEvent()); + + // Restore previous state + QList selectedObjects; + for (int id : selectedObjectIds) { + if (MapObject *object = mMap->findObjectById(id)) + selectedObjects.append(object); + } + setSelectedObjects(selectedObjects); + + if (currentLayerId != -1) + if (auto layer = mMap->findLayerById(currentLayerId)) + switchCurrentLayer(layer); + + QList selectedLayers; + for (int id : selectedLayerIds) { + if (Layer *layer = mMap->findLayerById(id)) + selectedLayers.append(layer); + } + switchSelectedLayers(selectedLayers); +} + void MapDocument::updateTemplateInstances(const ObjectTemplate *objectTemplate) { QList objectList; diff --git a/src/tiled/mapdocument.h b/src/tiled/mapdocument.h index 2589e298f42..8131373e271 100644 --- a/src/tiled/mapdocument.h +++ b/src/tiled/mapdocument.h @@ -67,7 +67,7 @@ using MapDocumentPtr = QSharedPointer; * selected layer and provides an API for adding and removing map objects. It * also owns the QUndoStack. */ -class TILED_EDITOR_EXPORT MapDocument : public Document +class TILED_EDITOR_EXPORT MapDocument final : public Document { Q_OBJECT @@ -92,6 +92,9 @@ class TILED_EDITOR_EXPORT MapDocument : public Document bool save(const QString &fileName, QString *error = nullptr) override; + bool canReload() const override; + bool reload(QString *error); + /** * Loads a map and returns a MapDocument instance on success. Returns null * on error and sets the \a error message. @@ -260,6 +263,8 @@ class TILED_EDITOR_EXPORT MapDocument : public Document void checkIssues() override; + void swapMap(std::unique_ptr &other); + QSet expandedGroupLayers; QSet expandedObjectLayers; diff --git a/src/tiled/mapitem.cpp b/src/tiled/mapitem.cpp index 26829b4e52e..51486a84d05 100644 --- a/src/tiled/mapitem.cpp +++ b/src/tiled/mapitem.cpp @@ -358,6 +358,21 @@ void MapItem::repaintRegion(const QRegion ®ion, TileLayer *tileLayer) void MapItem::documentChanged(const ChangeEvent &change) { switch (change.type) { + case ChangeEvent::DocumentAboutToReload: + for (Layer *layer : mMapDocument->map()->layers()) + deleteLayerItems(layer); + break; + case ChangeEvent::DocumentReloaded: { + // The renderer has been re-created + auto lineWidth = Preferences::instance()->objectLineWidth(); + mapDocument()->renderer()->setObjectLineWidth(lineWidth); + + createLayerItems(mMapDocument->map()->layers()); + + updateBoundingRect(); + updateLayerPositions(); + break; + } case ChangeEvent::ObjectsChanged: { auto &objectsChange = static_cast(change); if (!objectsChange.objects.isEmpty() && (objectsChange.properties & ObjectsChangeEvent::ClassProperty)) { diff --git a/src/tiled/mapobjectmodel.cpp b/src/tiled/mapobjectmodel.cpp index 4ecde9dddc0..26a644d4034 100644 --- a/src/tiled/mapobjectmodel.cpp +++ b/src/tiled/mapobjectmodel.cpp @@ -75,8 +75,6 @@ const QIcon &ObjectIconManager::iconForObject(const MapObject &object) const MapObjectModel::MapObjectModel(QObject *parent) : QAbstractItemModel(parent) - , mMapDocument(nullptr) - , mMap(nullptr) , mObjectGroupIcon(QLatin1String(":/images/16/layer-object.png")) { mObjectGroupIcon.addFile(QLatin1String(":images/32/layer-object.png")); @@ -333,7 +331,7 @@ QModelIndex MapObjectModel::index(Layer *layer) const { Q_ASSERT(layer); Q_ASSERT(layer->isObjectGroup() || layer->isGroupLayer()); - Q_ASSERT(layer->map() == mMap); + Q_ASSERT(layer->map() == map()); const int row = filteredChildLayers(layer->parentLayer()).indexOf(layer); return createIndex(row, 0, layer); @@ -343,7 +341,7 @@ QModelIndex MapObjectModel::index(MapObject *mapObject, int column) const { Q_ASSERT(mapObject); Q_ASSERT(mapObject->objectGroup()); - Q_ASSERT(mapObject->map() == mMap); + Q_ASSERT(mapObject->map() == map()); const int row = mapObject->objectGroup()->objects().indexOf(mapObject); return createIndex(row, column, mapObject); @@ -413,13 +411,10 @@ void MapObjectModel::setMapDocument(MapDocument *mapDocument) beginResetModel(); mMapDocument = mapDocument; - mMap = nullptr; mFilteredLayers.clear(); if (mMapDocument) { - mMap = mMapDocument->map(); - connect(mMapDocument, &MapDocument::layerAdded, this, &MapObjectModel::layerAdded); connect(mMapDocument, &MapDocument::layerAboutToBeRemoved, @@ -464,7 +459,7 @@ void MapObjectModel::layerAdded(Layer *layer) void MapObjectModel::layerAboutToBeRemoved(GroupLayer *groupLayer, int index) { - const auto &layers = groupLayer ? groupLayer->layers() : mMap->layers(); + const auto &layers = groupLayer ? groupLayer->layers() : map()->layers(); Layer *layer = layers.at(index); if (layer->isObjectGroup() || layer->isGroupLayer()) { @@ -493,7 +488,7 @@ void MapObjectModel::classChanged(const QList &objects) for (Object *object : objects) affectedObjects.append(static_cast(object)); } else if (typeId == Object::TileType) { - for (const Layer *layer : mMap->objectGroups()) { + for (const Layer *layer : map()->objectGroups()) { auto objectGroup = static_cast(layer); for (MapObject *mapObject : objectGroup->objects()) { if (mapObject->className().isEmpty()) @@ -514,7 +509,7 @@ QList &MapObjectModel::filteredChildLayers(GroupLayer *parentLayer) con { if (!mFilteredLayers.contains(parentLayer)) { QList &filtered = mFilteredLayers[parentLayer]; - const auto &layers = parentLayer ? parentLayer->layers() : mMap->layers(); + const auto &layers = parentLayer ? parentLayer->layers() : map()->layers(); for (Layer *layer : layers) if (layer->isObjectGroup() || layer->isGroupLayer()) filtered.append(layer); @@ -540,6 +535,13 @@ void MapObjectModel::documentChanged(const ChangeEvent &change) { // Notify views about certain property changes switch (change.type) { + case ChangeEvent::DocumentAboutToReload: + beginResetModel(); + break; + case ChangeEvent::DocumentReloaded: + mFilteredLayers.clear(); + endResetModel(); + break; case ChangeEvent::ObjectsChanged: { auto &objectsChange = static_cast(change); if (objectsChange.properties & ObjectsChangeEvent::ClassProperty) @@ -613,4 +615,9 @@ void MapObjectModel::emitDataChanged(const QList &objects, } } +Map *MapObjectModel::map() const +{ + return mMapDocument->map(); +} + #include "moc_mapobjectmodel.cpp" diff --git a/src/tiled/mapobjectmodel.h b/src/tiled/mapobjectmodel.h index 5d046d6040f..aebbc64e47f 100644 --- a/src/tiled/mapobjectmodel.h +++ b/src/tiled/mapobjectmodel.h @@ -120,8 +120,9 @@ class MapObjectModel : public QAbstractItemModel const QVarLengthArray &columns, const QVector &roles = QVector()); - MapDocument *mMapDocument; - Map *mMap; + Map *map() const; + + MapDocument *mMapDocument = nullptr; // cache mutable QMap> mFilteredLayers; diff --git a/src/tiled/mapscene.cpp b/src/tiled/mapscene.cpp index 0b285f7cd75..968700a20ca 100644 --- a/src/tiled/mapscene.cpp +++ b/src/tiled/mapscene.cpp @@ -258,9 +258,20 @@ QPointF MapScene::parallaxOffset(const Layer &layer) const QPointF viewCenter = mViewRect.center(); - Map *map = layer.map(); - if (const MapItem *mapItem = mMapItems.value(map)) - viewCenter -= mapItem->pos() + map->parallaxOrigin(); + if (Map *map = layer.map()) { + viewCenter += map->parallaxOrigin(); + + const MapItem *mapItem = nullptr; + for (auto it = mMapItems.begin(); it != mMapItems.end(); ++it) { + if (it.key()->map() == map) { + mapItem = it.value(); + break; + } + } + + if (mapItem) + viewCenter -= mapItem->pos(); + } const QPointF parallaxFactor = layer.effectiveParallaxFactor(); return QPointF((1.0 - parallaxFactor.x()) * viewCenter.x(), @@ -272,7 +283,7 @@ QPointF MapScene::parallaxOffset(const Layer &layer) const */ void MapScene::refreshScene() { - QHash mapItems; + QHash mapItems; if (!mMapDocument) { mMapItems.swap(mapItems); @@ -282,7 +293,7 @@ void MapScene::refreshScene() } const WorldManager &worldManager = WorldManager::instance(); - const QString currentMapFile = mMapDocument->canonicalFilePath(); + const QString ¤tMapFile = mMapDocument->canonicalFilePath(); if (const World *world = worldManager.worldForMap(currentMapFile)) { const QPoint currentMapPosition = world->mapRect(currentMapFile).topLeft(); @@ -306,12 +317,12 @@ void MapScene::refreshScene() auto mapItem = takeOrCreateMapItem(mapDocument, displayMode); mapItem->setPos(mapEntry.rect.topLeft() - currentMapPosition); mapItem->setVisible(mWorldsEnabled || mapDocument == mMapDocument); - mapItems.insert(mapDocument->map(), mapItem); + mapItems.insert(mapDocument.data(), mapItem); } } } else { auto mapItem = takeOrCreateMapItem(mMapDocument->sharedFromThis(), MapItem::Editable); - mapItems.insert(mMapDocument->map(), mapItem); + mapItems.insert(mMapDocument, mapItem); } mMapItems.swap(mapItems); @@ -377,7 +388,7 @@ void MapScene::setWorldsEnabled(bool enabled) MapItem *MapScene::takeOrCreateMapItem(const MapDocumentPtr &mapDocument, MapItem::DisplayMode displayMode) { // Try to reuse an existing map item - auto mapItem = mMapItems.take(mapDocument->map()); + auto mapItem = mMapItems.take(mapDocument.data()); if (!mapItem) { mapItem = new MapItem(mapDocument, displayMode); mapItem->setShowTileCollisionShapes(mShowTileCollisionShapes); diff --git a/src/tiled/mapscene.h b/src/tiled/mapscene.h index 736376051f7..7eacf13290e 100644 --- a/src/tiled/mapscene.h +++ b/src/tiled/mapscene.h @@ -131,7 +131,7 @@ class MapScene : public QGraphicsScene bool toolMouseMoved(const QPointF &pos, Qt::KeyboardModifiers modifiers); MapDocument *mMapDocument = nullptr; - QHash mMapItems; + QHash mMapItems; AbstractTool *mSelectedTool = nullptr; DebugDrawItem *mDebugDrawItem = nullptr; bool mUnderMouse = false; @@ -162,7 +162,7 @@ inline MapDocument *MapScene::mapDocument() const */ inline MapItem *MapScene::mapItem(MapDocument *mapDocument) const { - return mapDocument ? mMapItems.value(mapDocument->map()) : nullptr; + return mapDocument ? mMapItems.value(mapDocument) : nullptr; } inline DebugDrawItem *MapScene::debugDrawItem() const diff --git a/src/tiled/objectselectionitem.cpp b/src/tiled/objectselectionitem.cpp index 729de2f515c..572e6650d2d 100644 --- a/src/tiled/objectselectionitem.cpp +++ b/src/tiled/objectselectionitem.cpp @@ -368,6 +368,27 @@ QVariant ObjectSelectionItem::itemChange(GraphicsItemChange change, const QVaria void ObjectSelectionItem::changeEvent(const ChangeEvent &event) { switch (event.type) { + case ChangeEvent::DocumentAboutToReload: + qDeleteAll(mObjectLabels); + qDeleteAll(mObjectOutlines); + qDeleteAll(mObjectHoverItems); + for (const auto &referenceItems : std::as_const(mReferencesBySourceObject)) + qDeleteAll(referenceItems); + + mObjectLabels.clear(); + mObjectOutlines.clear(); + mObjectHoverItems.clear(); + mReferencesBySourceObject.clear(); + mReferencesByTargetObject.clear(); + break; + + case ChangeEvent::DocumentReloaded: + if (objectLabelVisibility() == Preferences::AllObjectLabels) + addRemoveObjectLabels(); + + if (Preferences::instance()->showObjectReferences()) + addRemoveObjectReferences(); + break; case ChangeEvent::ObjectsChanged: { auto &objectsChange = static_cast(event); if (!objectsChange.objects.isEmpty() && (objectsChange.properties & ObjectsChangeEvent::ClassProperty)) { diff --git a/src/tiled/projectdocument.h b/src/tiled/projectdocument.h index 76e39c0459a..9d40f997f9b 100644 --- a/src/tiled/projectdocument.h +++ b/src/tiled/projectdocument.h @@ -26,7 +26,7 @@ namespace Tiled { -class ProjectDocument : public Document +class ProjectDocument final : public Document { Q_OBJECT diff --git a/src/tiled/scriptmodule.cpp b/src/tiled/scriptmodule.cpp index 148bcf1f8a3..394ac87c102 100644 --- a/src/tiled/scriptmodule.cpp +++ b/src/tiled/scriptmodule.cpp @@ -62,6 +62,7 @@ ScriptModule::ScriptModule(QObject *parent) if (auto documentManager = DocumentManager::maybeInstance()) { connect(documentManager, &DocumentManager::documentCreated, this, &ScriptModule::documentCreated); connect(documentManager, &DocumentManager::documentOpened, this, &ScriptModule::documentOpened); + connect(documentManager, &DocumentManager::documentReloaded, this, &ScriptModule::documentReloaded); connect(documentManager, &DocumentManager::documentAboutToBeSaved, this, &ScriptModule::documentAboutToBeSaved); connect(documentManager, &DocumentManager::documentSaved, this, &ScriptModule::documentSaved); connect(documentManager, &DocumentManager::documentAboutToClose, this, &ScriptModule::documentAboutToClose); @@ -676,6 +677,11 @@ void ScriptModule::documentOpened(Document *document) emit assetOpened(document->editable()); } +void ScriptModule::documentReloaded(Document *document) +{ + emit assetReloaded(document->editable()); +} + void ScriptModule::documentAboutToBeSaved(Document *document) { emit assetAboutToBeSaved(document->editable()); diff --git a/src/tiled/scriptmodule.h b/src/tiled/scriptmodule.h index 5b56296165c..5ce14b6d6d5 100644 --- a/src/tiled/scriptmodule.h +++ b/src/tiled/scriptmodule.h @@ -150,6 +150,7 @@ class ScriptModule : public QObject signals: void assetCreated(Tiled::EditableAsset *asset); void assetOpened(Tiled::EditableAsset *asset); + void assetReloaded(Tiled::EditableAsset *asset); void assetAboutToBeSaved(Tiled::EditableAsset *asset); void assetSaved(Tiled::EditableAsset *asset); void assetAboutToBeClosed(Tiled::EditableAsset *asset); @@ -174,6 +175,7 @@ public slots: private: void documentCreated(Document *document); void documentOpened(Document *document); + void documentReloaded(Document *document); void documentAboutToBeSaved(Document *document); void documentSaved(Document *document); void documentAboutToClose(Document *document); diff --git a/src/tiled/tileselectionitem.cpp b/src/tiled/tileselectionitem.cpp index d82e1364826..1748bac8f7d 100644 --- a/src/tiled/tileselectionitem.cpp +++ b/src/tiled/tileselectionitem.cpp @@ -21,8 +21,6 @@ #include "tileselectionitem.h" #include "changeevents.h" -#include "grouplayer.h" -#include "map.h" #include "mapdocument.h" #include "maprenderer.h" #include "mapscene.h" @@ -79,6 +77,10 @@ void TileSelectionItem::paint(QPainter *painter, void TileSelectionItem::documentChanged(const ChangeEvent &change) { switch (change.type) { + case ChangeEvent::DocumentReloaded: + selectionChanged(mMapDocument->selectedArea(), + mMapDocument->selectedArea()); + break; case ChangeEvent::LayerChanged: { const auto &layerChange = static_cast(change); if (layerChange.properties & LayerChangeEvent::PositionProperties) diff --git a/src/tiled/tilesetdocument.cpp b/src/tiled/tilesetdocument.cpp index 3f5123576b5..f378489189b 100644 --- a/src/tiled/tilesetdocument.cpp +++ b/src/tiled/tilesetdocument.cpp @@ -258,12 +258,15 @@ void TilesetDocument::swapTileset(SharedTileset &tileset) // Bring pointers to safety setSelectedTiles(QList()); setCurrentObject(mTileset.data()); - mEditable.reset(); + mWangColorModels.clear(); + + emit changed(AboutToReloadEvent()); sTilesetToDocument.remove(mTileset); mTileset->swap(*tileset); sTilesetToDocument.insert(mTileset, this); + emit changed(ReloadEvent()); emit tilesetChanged(mTileset.data()); } diff --git a/src/tiled/tilesetdocument.h b/src/tiled/tilesetdocument.h index 05f54db7265..d574d8d0907 100644 --- a/src/tiled/tilesetdocument.h +++ b/src/tiled/tilesetdocument.h @@ -46,7 +46,7 @@ using TilesetDocumentPtr = QSharedPointer; /** * Represents an editable tileset. */ -class TilesetDocument : public Document +class TilesetDocument final : public Document { Q_OBJECT @@ -58,7 +58,7 @@ class TilesetDocument : public Document bool save(const QString &fileName, QString *error = nullptr) override; - bool canReload() const; + bool canReload() const override; bool reload(QString *error); /** diff --git a/src/tiled/tilesetdocumentsmodel.cpp b/src/tiled/tilesetdocumentsmodel.cpp index 7c00dc104e1..161d0a6a9f9 100644 --- a/src/tiled/tilesetdocumentsmodel.cpp +++ b/src/tiled/tilesetdocumentsmodel.cpp @@ -25,8 +25,6 @@ #include "tilesetdocument.h" #include "tileset.h" -#include - namespace Tiled { TilesetDocumentsModel::TilesetDocumentsModel(QObject *parent) diff --git a/src/tiled/tilesetview.cpp b/src/tiled/tilesetview.cpp index d2f654b88ee..9693a45d6a7 100644 --- a/src/tiled/tilesetview.cpp +++ b/src/tiled/tilesetview.cpp @@ -825,6 +825,9 @@ void TilesetView::resizeEvent(QResizeEvent *event) void TilesetView::onChange(const ChangeEvent &change) { switch (change.type) { + case ChangeEvent::DocumentReloaded: + refreshColumnCount(); + break; case ChangeEvent::WangSetChanged: { auto &wangSetChange = static_cast(change); if (mEditWangSet && wangSetChange.wangSet == mWangSet && diff --git a/src/tiled/tilesetwangsetmodel.cpp b/src/tiled/tilesetwangsetmodel.cpp index e172d10fedc..5a6d6f5a6dc 100644 --- a/src/tiled/tilesetwangsetmodel.cpp +++ b/src/tiled/tilesetwangsetmodel.cpp @@ -35,6 +35,8 @@ TilesetWangSetModel::TilesetWangSetModel(TilesetDocument *tilesetDocument, QAbstractListModel(parent), mTilesetDocument(tilesetDocument) { + connect(tilesetDocument, &TilesetDocument::changed, + this, &TilesetWangSetModel::documentChanged); } TilesetWangSetModel::~TilesetWangSetModel() @@ -204,4 +206,18 @@ void TilesetWangSetModel::emitWangSetChange(WangSet *wangSet) emit wangSetChanged(wangSet); } +void TilesetWangSetModel::documentChanged(const ChangeEvent &event) +{ + switch (event.type) { + case ChangeEvent::DocumentAboutToReload: + beginResetModel(); + break; + case ChangeEvent::DocumentReloaded: + endResetModel(); + break; + default: + break; + } +} + #include "moc_tilesetwangsetmodel.cpp" diff --git a/src/tiled/tilesetwangsetmodel.h b/src/tiled/tilesetwangsetmodel.h index b1969de6953..3a61c2acd4c 100644 --- a/src/tiled/tilesetwangsetmodel.h +++ b/src/tiled/tilesetwangsetmodel.h @@ -30,6 +30,7 @@ namespace Tiled { class Tileset; +class ChangeEvent; class TilesetDocument; /** @@ -94,6 +95,8 @@ class TilesetWangSetModel : public QAbstractListModel void wangSetChanged(WangSet *wangSet); private: + void documentChanged(const ChangeEvent &event); + void emitWangSetChange(WangSet *wangSet); TilesetDocument *mTilesetDocument; diff --git a/src/tiled/wangdock.cpp b/src/tiled/wangdock.cpp index 64e862a6570..5ab91b65334 100644 --- a/src/tiled/wangdock.cpp +++ b/src/tiled/wangdock.cpp @@ -160,6 +160,8 @@ WangDock::WangDock(QWidget *parent) this, &WangDock::checkAnyWangSets); connect(mWangSetProxyModel, &QAbstractItemModel::modelReset, this, &WangDock::checkAnyWangSets); + connect(mWangSetProxyModel, &QAbstractItemModel::modelReset, + mWangSetView, &WangSetView::expandAll); connect(mWangSetProxyModel, &QAbstractItemModel::rowsInserted, this, &WangDock::expandRows); @@ -198,9 +200,9 @@ WangDock::WangDock(QWidget *parent) mWangSetToolBar->addAction(mDuplicateWangSet); mWangSetToolBar->addAction(mRemoveWangSet); - connect(mAddCornerWangSet, &QAction::triggered, this, [this] { addWangSetRequested(WangSet::Corner); }); - connect(mAddEdgeWangSet, &QAction::triggered, this, [this] { addWangSetRequested(WangSet::Edge); }); - connect(mAddMixedWangSet, &QAction::triggered, this, [this] { addWangSetRequested(WangSet::Mixed); }); + connect(mAddCornerWangSet, &QAction::triggered, this, [this] { emit addWangSetRequested(WangSet::Corner); }); + connect(mAddEdgeWangSet, &QAction::triggered, this, [this] { emit addWangSetRequested(WangSet::Edge); }); + connect(mAddMixedWangSet, &QAction::triggered, this, [this] { emit addWangSetRequested(WangSet::Mixed); }); connect(mDuplicateWangSet, &QAction::triggered, this, &WangDock::duplicateWangSetRequested); connect(mRemoveWangSet, &QAction::triggered, this, &WangDock::removeWangSetRequested); @@ -470,6 +472,17 @@ void WangDock::wangColorIndexPressed(const QModelIndex &index) void WangDock::documentChanged(const ChangeEvent &change) { switch (change.type) { + case ChangeEvent::DocumentAboutToReload: + // A reload of the TilesetDocument means our previously referenced + // WangSet will no longer be valid. + setCurrentWangSet(nullptr); + break; + case ChangeEvent::DocumentReloaded: + if (auto tilesetDocument = qobject_cast(mDocument)) { + QScopedValueRollback initializing(mInitializing, true); + setCurrentWangSet(firstWangSet(tilesetDocument)); + } + break; case ChangeEvent::WangSetChanged: if (static_cast(change).properties & WangSetChangeEvent::TypeProperty) mWangTemplateModel->wangSetChanged(); diff --git a/src/tiled/wangsetmodel.cpp b/src/tiled/wangsetmodel.cpp index a085ec81272..0d4fdf0ad90 100644 --- a/src/tiled/wangsetmodel.cpp +++ b/src/tiled/wangsetmodel.cpp @@ -21,7 +21,6 @@ #include "wangsetmodel.h" #include "changeevents.h" -#include "containerhelpers.h" #include "map.h" #include "mapdocument.h" #include "tile.h" @@ -259,6 +258,15 @@ void WangSetModel::onTilesetDataChanged(const QModelIndex &topLeft, const QModel void WangSetModel::onDocumentChanged(const ChangeEvent &change) { switch (change.type) { + // On tileset reload, we need to reset the model since we don't know what + // has changed. + case ChangeEvent::DocumentAboutToReload: + beginResetModel(); + break; + case ChangeEvent::DocumentReloaded: + endResetModel(); + break; + case ChangeEvent::WangSetAboutToBeAdded: { auto wangSetEvent = static_cast(change); diff --git a/src/tiled/worlddocument.h b/src/tiled/worlddocument.h index 01fd4918169..af17cfa94f6 100644 --- a/src/tiled/worlddocument.h +++ b/src/tiled/worlddocument.h @@ -31,7 +31,7 @@ namespace Tiled { /** * Represents an editable world document. */ -class WorldDocument : public Document +class WorldDocument final : public Document { Q_OBJECT