Skip to content

Commit

Permalink
Fixed some issues related to template reloading
Browse files Browse the repository at this point in the history
* Delay template reload by 500 ms, to avoid issues where the file that
  changed hasn't been fully written yet.

* Don't report error when reloading template, when the template file
  didn't load in the first place. This is currently often the case, when
  it was just a file that we tried to load as a template before.

* Make sure that when a template file changed, that we don't reload it
  when we we're the ones that saved it.

* Fixed the Template Editor to refresh its dummy object when the file
  was changed externally.

Closes mapeditor#2836
  • Loading branch information
bjorn committed Jun 19, 2020
1 parent ea7ad58 commit a7ec030
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 25 deletions.
16 changes: 16 additions & 0 deletions src/libtiled/objecttemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@

#include "objecttemplateformat.h"

#include <QFileInfo>

namespace Tiled {

ObjectTemplate::ObjectTemplate()
Expand Down Expand Up @@ -88,4 +90,18 @@ ObjectTemplateFormat *ObjectTemplate::format() const
return mFormat;
}

bool ObjectTemplate::save()
{
if (!mFormat)
return false;
if (mFileName.isEmpty())
return false;

const bool result = mFormat->write(this, mFileName);

mLastSaved = QFileInfo(mFileName).lastModified();

return result;
}

} // namespace Tiled
8 changes: 8 additions & 0 deletions src/libtiled/objecttemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "mapobject.h"
#include "tileset.h"

#include <QDateTime>
#include <QPointer>

#include <memory>
Expand All @@ -57,13 +58,17 @@ class TILEDSHARED_EXPORT ObjectTemplate : public Object
void setFormat(ObjectTemplateFormat *format);
ObjectTemplateFormat *format() const;

bool save();
QDateTime lastSaved() const;

const SharedTileset &tileset() const;

private:
QString mFileName;
QPointer<ObjectTemplateFormat> mFormat;
std::unique_ptr<MapObject> mObject;
SharedTileset mTileset;
QDateTime mLastSaved;
};

inline const MapObject *ObjectTemplate::object() const
Expand All @@ -75,6 +80,9 @@ inline const QString &ObjectTemplate::fileName() const
inline void ObjectTemplate::setFileName(const QString &fileName)
{ mFileName = fileName; }

inline QDateTime ObjectTemplate::lastSaved() const
{ return mLastSaved; }

inline const SharedTileset &ObjectTemplate::tileset() const
{ return mTileset; }

Expand Down
38 changes: 23 additions & 15 deletions src/libtiled/templatemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "logginginterface.h"

#include <QFile>
#include <QFileInfo>

using namespace Tiled;

Expand All @@ -51,8 +52,8 @@ TemplateManager::TemplateManager(QObject *parent)
: QObject(parent),
mWatcher(new FileSystemWatcher(this))
{
connect(mWatcher, &FileSystemWatcher::fileChanged,
this, &TemplateManager::fileChanged);
connect(mWatcher, &FileSystemWatcher::pathsChanged,
this, &TemplateManager::pathsChanged);
}

TemplateManager::~TemplateManager()
Expand Down Expand Up @@ -83,19 +84,26 @@ ObjectTemplate *TemplateManager::loadObjectTemplate(const QString &fileName, QSt
return objectTemplate;
}

void TemplateManager::fileChanged(const QString &fileName)
void TemplateManager::pathsChanged(const QStringList &paths)
{
ObjectTemplate *objectTemplate = findObjectTemplate(fileName);

// Most likely the file was removed.
if (!objectTemplate)
return;

auto newTemplate = readObjectTemplate(fileName);
if (newTemplate) {
objectTemplate->setObject(newTemplate->object());
emit objectTemplateChanged(objectTemplate);
} else {
ERROR(tr("Unable to reload template file: %1").arg(fileName));
for (const QString &fileName : paths) {
ObjectTemplate *objectTemplate = findObjectTemplate(fileName);

// Most likely the file was removed.
if (!objectTemplate)
continue;

// Check whether we were the ones saving this file.
if (objectTemplate->lastSaved() == QFileInfo(fileName).lastModified())
continue;

auto newTemplate = readObjectTemplate(fileName);
if (newTemplate) {
objectTemplate->setObject(newTemplate->object());
objectTemplate->setFormat(newTemplate->format());
emit objectTemplateChanged(objectTemplate);
} else if (objectTemplate->object()) { // only report error if it had loaded fine before
ERROR(tr("Unable to reload template file: %1").arg(fileName));
}
}
}
2 changes: 1 addition & 1 deletion src/libtiled/templatemanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class TILEDSHARED_EXPORT TemplateManager : public QObject
TemplateManager(QObject *parent = nullptr);
~TemplateManager();

void fileChanged(const QString &fileName);
void pathsChanged(const QStringList &paths);

QHash<QString, ObjectTemplate*> mObjectTemplates;
FileSystemWatcher *mWatcher;
Expand Down
39 changes: 30 additions & 9 deletions src/tiled/templatesdock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ using namespace Tiled;
// This references created dummy documents, to make sure they are shared if the
// same template is open in the MapEditor and the TilesetEditor.
QHash<ObjectTemplate*, QWeakPointer<MapDocument>> TemplatesDock::ourDummyDocuments;
bool TemplatesDock::ourEmittingChanged;

TemplatesDock::TemplatesDock(QWidget *parent)
: QDockWidget(parent)
Expand Down Expand Up @@ -138,6 +139,9 @@ TemplatesDock::TemplatesDock(QWidget *parent)
connect(mToolManager, &ToolManager::selectedToolChanged,
mMapScene, &MapScene::setSelectedTool);

connect(TemplateManager::instance(), &TemplateManager::objectTemplateChanged,
this, &TemplatesDock::objectTemplateChanged);

setFocusPolicy(Qt::ClickFocus);
mMapView->setFocusProxy(this);
}
Expand Down Expand Up @@ -213,20 +217,26 @@ void TemplatesDock::setTemplate(ObjectTemplate *objectTemplate)
return;

mObjectTemplate = objectTemplate;
refreshDummyObject();

emit currentTemplateChanged(mObjectTemplate);
}

void TemplatesDock::refreshDummyObject()
{
mMapScene->setSelectedTool(nullptr);
MapDocumentPtr previousDocument = mDummyMapDocument;

mMapView->setEnabled(objectTemplate);
mMapView->setEnabled(mObjectTemplate);

if (objectTemplate && objectTemplate->object()) {
mDummyMapDocument = ourDummyDocuments.value(objectTemplate);
if (mObjectTemplate && mObjectTemplate->object()) {
mDummyMapDocument = ourDummyDocuments.value(mObjectTemplate);

if (!mDummyMapDocument) {
Map::Orientation orientation = Map::Orthogonal;
std::unique_ptr<Map> map { new Map(orientation, 1, 1, 1, 1) };

MapObject *dummyObject = objectTemplate->object()->clone();
MapObject *dummyObject = mObjectTemplate->object()->clone();
dummyObject->markAsTemplateBase();

if (Tileset *tileset = dummyObject->cell().tileset()) {
Expand All @@ -245,7 +255,7 @@ void TemplatesDock::setTemplate(ObjectTemplate *objectTemplate)
mDummyMapDocument->setAllowHidingObjects(false);
mDummyMapDocument->switchCurrentLayer(objectGroup);

ourDummyDocuments.insert(objectTemplate, mDummyMapDocument);
ourDummyDocuments.insert(mObjectTemplate, mDummyMapDocument);
}

mDummyMapDocument->setCurrentObject(dummyObject());
Expand All @@ -269,8 +279,6 @@ void TemplatesDock::setTemplate(ObjectTemplate *objectTemplate)

if (previousDocument)
previousDocument->undoStack()->disconnect(this);

emit currentTemplateChanged(mObjectTemplate);
}

void TemplatesDock::checkTileset()
Expand Down Expand Up @@ -308,6 +316,18 @@ void TemplatesDock::checkTileset()
}
}

void TemplatesDock::objectTemplateChanged(ObjectTemplate *objectTemplate)
{
if (ourEmittingChanged)
return;

// Apparently the template was changed externally
ourDummyDocuments.remove(objectTemplate);

if (mObjectTemplate == objectTemplate)
refreshDummyObject();
}

void TemplatesDock::undo()
{
if (mDummyMapDocument) {
Expand All @@ -329,15 +349,16 @@ void TemplatesDock::applyChanges()
mObjectTemplate->setObject(dummyObject());

// Write out the template file
mObjectTemplate->format()->write(mObjectTemplate,
mObjectTemplate->fileName());
mObjectTemplate->save();

mUndoAction->setEnabled(mDummyMapDocument->undoStack()->canUndo());
mRedoAction->setEnabled(mDummyMapDocument->undoStack()->canRedo());

checkTileset();

ourEmittingChanged = true;
emit TemplateManager::instance()->objectTemplateChanged(mObjectTemplate);
ourEmittingChanged = false;
}

void TemplatesDock::focusInEvent(QFocusEvent *event)
Expand Down
4 changes: 4 additions & 0 deletions src/tiled/templatesdock.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ public slots:

private:
void setTemplate(ObjectTemplate *objectTemplate);
void refreshDummyObject();
void checkTileset();

void objectTemplateChanged(ObjectTemplate *objectTemplate);

void undo();
void redo();
void applyChanges();
Expand All @@ -96,6 +99,7 @@ public slots:
ToolManager *mToolManager;

static QHash<ObjectTemplate*, QWeakPointer<MapDocument>> ourDummyDocuments;
static bool ourEmittingChanged;
};

inline void TemplatesDock::setPropertiesDock(PropertiesDock *propertiesDock)
Expand Down

0 comments on commit a7ec030

Please sign in to comment.