diff --git a/src/tiled/automappingmanager.cpp b/src/tiled/automappingmanager.cpp index 9ddb6ff576..2b4e9bfc82 100644 --- a/src/tiled/automappingmanager.cpp +++ b/src/tiled/automappingmanager.cpp @@ -36,6 +36,8 @@ using namespace Tiled; +SessionOption AutomappingManager::automappingWhileDrawing { "automapping.whileDrawing", false }; + AutomappingManager::AutomappingManager(QObject *parent) : QObject(parent) , mMapDocument(nullptr) @@ -85,7 +87,7 @@ void AutomappingManager::autoMapRegion(const QRegion ®ion) void AutomappingManager::onRegionEdited(const QRegion &where, Layer *touchedLayer) { - if (Preferences::automappingWhileDrawing) + if (automappingWhileDrawing) autoMapInternal(where, touchedLayer); } diff --git a/src/tiled/automappingmanager.h b/src/tiled/automappingmanager.h index 64e38385b8..146097a40c 100644 --- a/src/tiled/automappingmanager.h +++ b/src/tiled/automappingmanager.h @@ -20,6 +20,8 @@ #pragma once +#include "session.h" + #include #include #include @@ -61,6 +63,8 @@ class AutomappingManager : public QObject void autoMap(); void autoMapRegion(const QRegion ®ion); + static SessionOption automappingWhileDrawing; + signals: /** * This signal is emitted after automapping was done and an error occurred. diff --git a/src/tiled/documentmanager.cpp b/src/tiled/documentmanager.cpp index 05c425c7ef..3750910db0 100644 --- a/src/tiled/documentmanager.cpp +++ b/src/tiled/documentmanager.cpp @@ -38,6 +38,7 @@ #include "mapview.h" #include "noeditorwidget.h" #include "preferences.h" +#include "session.h" #include "tabbar.h" #include "terrain.h" #include "tilesetdocument.h" @@ -142,6 +143,9 @@ DocumentManager::DocumentManager(QObject *parent) connect(TilesetManager::instance(), &TilesetManager::tilesetImagesChanged, this, &DocumentManager::tilesetImagesChanged); + connect(Preferences::instance(), &Preferences::aboutToSwitchSession, + this, &DocumentManager::updateSession); + OpenFile::activated = [this] (const OpenFile &open) { openFile(open.file); }; @@ -591,8 +595,6 @@ void DocumentManager::insertDocument(int index, const DocumentPtr &document) if (mBrokenLinksModel->hasBrokenLinks()) mBrokenLinksWidget->show(); - updateSession(); - emit documentOpened(documentPtr); } @@ -891,8 +893,6 @@ void DocumentManager::closeDocumentAt(int index) if (!document->fileName().isEmpty()) Preferences::instance()->addRecentFile(document->fileName()); - - updateSession(); } /** @@ -988,8 +988,6 @@ void DocumentManager::currentIndexChanged() mBrokenLinksModel->setDocument(document); - updateSession(); - emit currentDocumentChanged(document); } @@ -1217,11 +1215,10 @@ void DocumentManager::updateSession() const } auto doc = currentDocument(); - auto prefs = Preferences::instance(); - prefs->session().openFiles = fileList; - prefs->session().activeFile = doc ? doc->fileName() : QString(); - prefs->saveSession(); + auto &session = Session::current(); + session.setOpenFiles(fileList); + session.setActiveFile(doc ? doc->fileName() : QString()); } MapDocument *DocumentManager::openMapFile(const QString &path) diff --git a/src/tiled/main.cpp b/src/tiled/main.cpp index dcf56dfafc..dbe8ba88bb 100644 --- a/src/tiled/main.cpp +++ b/src/tiled/main.cpp @@ -42,6 +42,8 @@ #include #include +#include "qtcompat_p.h" + #include #ifdef Q_OS_WIN @@ -66,12 +68,12 @@ class CommandLineHandler : public CommandLineParser public: CommandLineHandler(); - bool quit; - bool showedVersion; - bool disableOpenGL; - bool exportMap; - bool exportTileset; - bool newInstance; + bool quit = false; + bool showedVersion = false; + bool disableOpenGL = false; + bool exportMap = false; + bool exportTileset = false; + bool newInstance = false; Preferences::ExportOptions exportOptions; private: @@ -185,12 +187,6 @@ inline T *findExportFormat(const QString *filter, CommandLineHandler::CommandLineHandler() - : quit(false) - , showedVersion(false) - , disableOpenGL(false) - , exportMap(false) - , exportTileset(false) - , newInstance(false) { option<&CommandLineHandler::showVersion>( QLatin1Char('v'), @@ -470,18 +466,33 @@ int main(int argc, char *argv[]) return 0; } - if (!commandLine.filesToOpen().isEmpty() && !commandLine.newInstance) { - // Convert files to absolute paths because the already running Tiled + QStringList filesToOpen; + + for (const QString &fileName : commandLine.filesToOpen()) { + const QFileInfo fileInfo(fileName); + const QString filePath = QDir::cleanPath(fileInfo.absoluteFilePath()); + + if (fileInfo.suffix() == QLatin1String("tiled-project")) { + if (!fileInfo.exists()) { + qWarning().noquote() << QCoreApplication::translate("Command line", "Project file '%1' not found.").arg(fileName); + return 1; + } + Preferences::setStartupProject(filePath); + } else { + filesToOpen.append(filePath); + } + } + + if (!filesToOpen.isEmpty() && !commandLine.newInstance) { + // Files need to be absolute paths because the already running Tiled // instance likely does not have the same working directory. - QStringList absolutePaths; - for (const QString &fileName : commandLine.filesToOpen()) - absolutePaths.append(QFileInfo(fileName).absoluteFilePath()); - QJsonDocument doc(QJsonArray::fromStringList(absolutePaths)); + QJsonDocument doc(QJsonArray::fromStringList(filesToOpen)); if (a.sendMessage(QLatin1String(doc.toJson()))) return 0; } StyleHelper::initialize(); + Session::initialize(); MainWindow w; w.show(); @@ -498,9 +509,8 @@ int main(int argc, char *argv[]) w.initializeSession(); - if (!commandLine.filesToOpen().isEmpty()) - for (const QString &fileName : commandLine.filesToOpen()) - w.openFile(fileName); + for (const QString &fileName : qAsConst(filesToOpen)) + w.openFile(fileName); return a.exec(); } diff --git a/src/tiled/mainwindow.cpp b/src/tiled/mainwindow.cpp index 7647fd8942..c61ea4bd74 100644 --- a/src/tiled/mainwindow.cpp +++ b/src/tiled/mainwindow.cpp @@ -420,7 +420,7 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) mUi->actionHighlightCurrentLayer->setChecked(preferences->highlightCurrentLayer()); mUi->actionHighlightHoveredObject->setChecked(preferences->highlightHoveredObject()); - bindToOption(mUi->actionAutoMapWhileDrawing, Preferences::automappingWhileDrawing); + bindToOption(mUi->actionAutoMapWhileDrawing, AutomappingManager::automappingWhileDrawing); mUi->actionHighlightCurrentLayer->setIcon(highlightCurrentLayerIcon); mUi->actionHighlightCurrentLayer->setIconVisibleInMenu(false); @@ -584,7 +584,7 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) if (!WorldManager::instance().loadWorld(worldFile, &errorString)) QMessageBox::critical(this, tr("Error Loading World"), errorString); else - Preferences::loadedWorlds = WorldManager::instance().worlds().keys(); + mLoadedWorlds = WorldManager::instance().worlds().keys(); }); connect(mUi->menuUnloadWorld, &QMenu::aboutToShow, this, [this] { mUi->menuUnloadWorld->clear(); @@ -599,7 +599,7 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) return; WorldManager::instance().unloadWorld(fileName); - Preferences::loadedWorlds = WorldManager::instance().worlds().keys(); + mLoadedWorlds = WorldManager::instance().worlds().keys(); }); } }); @@ -620,7 +620,7 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) if (!WorldManager::instance().addEmptyWorld(worldFile, &errorString)) QMessageBox::critical(this, tr("Error Creating World"), errorString); else - Preferences::loadedWorlds = WorldManager::instance().worlds().keys(); + mLoadedWorlds = WorldManager::instance().worlds().keys(); }); connect(mUi->menuSaveWorld, &QMenu::aboutToShow, this, [this] { mUi->menuSaveWorld->clear(); @@ -810,7 +810,7 @@ MainWindow::MainWindow(QWidget *parent, Qt::WindowFlags flags) MainWindow::~MainWindow() { - Preferences::instance()->saveSessionNow(); + emit Preferences::instance()->aboutToSwitchSession(); mDocumentManager->closeAllDocuments(); mDocumentManager->deleteEditors(); @@ -914,12 +914,13 @@ void MainWindow::newMap() void MainWindow::initializeSession() { - const auto prefs = Preferences::instance(); - const auto &session = prefs->session(); + const auto &session = Session::current(); // Restore associated project if applicable Project project; - if (!session.project.isEmpty() && project.load(session.project)) { + bool projectLoaded = !session.project.isEmpty() && project.load(session.project); + + if (projectLoaded) { mProjectDock->setProject(std::move(project)); updateWindowTitle(); } @@ -929,7 +930,7 @@ void MainWindow::initializeSession() // adding the project's extension path. ScriptManager::instance().initialize(); - if (prefs->restoreSessionOnStartup()) + if (projectLoaded || Preferences::instance()->restoreSessionOnStartup()) restoreSession(); } @@ -1304,14 +1305,12 @@ void MainWindow::saveProjectAs() tr("An error occurred while saving the project.")); } - prefs->addRecentProject(fileName); - prefs->session().project = fileName; - - const auto sessionFileName = Session::defaultFileNameForProject(fileName); - prefs->session().setFileName(sessionFileName); + Session &session = Session::current(); + session.setFileName(Session::defaultFileNameForProject(fileName)); + session.setProject(fileName); - prefs->saveSessionNow(); - prefs->setLastSession(sessionFileName); + prefs->addRecentProject(fileName); + prefs->setLastSession(session.fileName()); updateWindowTitle(); updateActions(); @@ -1329,22 +1328,21 @@ void MainWindow::closeProject() void MainWindow::switchProject(Project project) { auto prefs = Preferences::instance(); - prefs->saveSessionNow(); + emit prefs->aboutToSwitchSession(); if (!closeAllFiles()) return; WorldManager::instance().unloadAllWorlds(); - Session session { Session::defaultFileNameForProject(project.fileName()) }; + auto &session = Session::switchCurrent(Session::defaultFileNameForProject(project.fileName())); if (!project.fileName().isEmpty()) { - session.project = project.fileName(); + session.setProject(project.fileName()); prefs->addRecentProject(project.fileName()); } mProjectDock->setProject(std::move(project)); - prefs->switchSession(std::move(session)); ScriptManager::instance().refreshExtensionsPaths(); @@ -1355,7 +1353,7 @@ void MainWindow::switchProject(Project project) void MainWindow::restoreSession() { - const auto &session = Preferences::instance()->session(); + const auto &session = Session::current(); // Copy values because the session will get changed while restoring it const auto openFiles = session.openFiles; @@ -1365,7 +1363,7 @@ void MainWindow::restoreSession() openFile(file); mDocumentManager->switchToDocument(activeFile); - WorldManager::instance().loadWorlds(Preferences::loadedWorlds); + WorldManager::instance().loadWorlds(mLoadedWorlds); mProjectDock->setExpandedPaths(session.expandedProjectPaths); } @@ -1746,7 +1744,7 @@ void MainWindow::openRecentFile() void MainWindow::reopenClosedFile() { - const auto recentFiles = Preferences::instance()->session().recentFiles; + const auto &recentFiles = Session::current().recentFiles; for (const QString &file : recentFiles) { if (mDocumentManager->findDocument(file) == -1) { openFile(file); @@ -1767,7 +1765,7 @@ void MainWindow::openRecentProject() */ void MainWindow::updateRecentFilesMenu() { - const QStringList files = Preferences::instance()->session().recentFiles; + const auto &files = Session::current().recentFiles; const int numRecentFiles = qMin(files.size(), Preferences::MaxRecentFiles); for (int i = 0; i < numRecentFiles; ++i) { diff --git a/src/tiled/mainwindow.h b/src/tiled/mainwindow.h index a17732e60c..5ac752a33e 100644 --- a/src/tiled/mainwindow.h +++ b/src/tiled/mainwindow.h @@ -28,6 +28,7 @@ #include "preferences.h" #include "preferencesdialog.h" #include "project.h" +#include "session.h" #include #include @@ -246,6 +247,8 @@ class MainWindow : public QMainWindow QMap mMainWindowStates; + SessionOption mLoadedWorlds { "loadedWorlds" }; + static MainWindow *mInstance; }; diff --git a/src/tiled/mapeditor.cpp b/src/tiled/mapeditor.cpp index 16dad6a437..fab6d40d9c 100644 --- a/src/tiled/mapeditor.cpp +++ b/src/tiled/mapeditor.cpp @@ -311,7 +311,7 @@ MapEditor::MapEditor(QObject *parent) connect(prefs, &Preferences::languageChanged, this, &MapEditor::retranslateUi); connect(prefs, &Preferences::showTileCollisionShapesChanged, this, &MapEditor::showTileCollisionShapesChanged); - connect(prefs, &Preferences::aboutToSaveSession, + connect(prefs, &Preferences::aboutToSwitchSession, this, [this] { if (mCurrentMapDocument) saveDocumentState(mCurrentMapDocument); }); connect(&WorldManager::instance(), &WorldManager::worldsChanged, @@ -622,9 +622,7 @@ void MapEditor::saveDocumentState(MapDocument *mapDocument) const fileState.insert(QLatin1String("viewCenter"), toSettingsValue(viewCenter)); fileState.insert(QLatin1String("selectedLayer"), globalIndex(mapDocument->currentLayer())); - Preferences *prefs = Preferences::instance(); - prefs->session().setFileState(mapDocument->fileName(), fileState); - prefs->saveSession(); + Session::current().setFileState(mapDocument->fileName(), fileState); } void MapEditor::restoreDocumentState(MapDocument *mapDocument) const @@ -633,8 +631,7 @@ void MapEditor::restoreDocumentState(MapDocument *mapDocument) const if (!mapView) return; - Preferences *prefs = Preferences::instance(); - const QVariantMap fileState = prefs->session().fileState(mapDocument->fileName()); + const QVariantMap fileState = Session::current().fileState(mapDocument->fileName()); if (fileState.isEmpty()) return; diff --git a/src/tiled/mapscene.cpp b/src/tiled/mapscene.cpp index 167448e82c..54d18cdf44 100644 --- a/src/tiled/mapscene.cpp +++ b/src/tiled/mapscene.cpp @@ -40,6 +40,7 @@ #include "worldmanager.h" #include +#include #include #include #include diff --git a/src/tiled/preferences.cpp b/src/tiled/preferences.cpp index 9d19f362f2..521c865e1a 100644 --- a/src/tiled/preferences.cpp +++ b/src/tiled/preferences.cpp @@ -26,6 +26,7 @@ #include "mapdocument.h" #include "pluginmanager.h" #include "savefile.h" +#include "session.h" #include "tilesetmanager.h" #include @@ -35,10 +36,8 @@ using namespace Tiled; -SessionOption Preferences::automappingWhileDrawing { "automapping.whileDrawing", false }; -SessionOption Preferences::loadedWorlds { "loadedWorlds" }; - Preferences *Preferences::mInstance; +QString Preferences::mStartupProject; Preferences *Preferences::instance() { @@ -54,7 +53,6 @@ void Preferences::deleteInstance() } Preferences::Preferences() - : mSession(restoreSessionOnStartup() ? lastSession() : Session::defaultFileName()) { // Make sure the data directory exists const QDir dataDir { dataLocation() }; @@ -94,81 +92,6 @@ Preferences::Preferences() Object::setObjectTypes(objectTypes); - mSaveSessionTimer.setInterval(1000); - mSaveSessionTimer.setSingleShot(true); - connect(&mSaveSessionTimer, &QTimer::timeout, this, [this] { saveSessionNow(); }); - - // Migrate some preferences to the session for compatibility - migrateToSession("Automapping/WhileDrawing", "automapping.whileDrawing"); - - migrateToSession("LoadedWorlds", "loadedWorlds"); - migrateToSession("Storage/StampsDirectory", "stampsFolder"); - - migrateToSession("Map/Orientation", "map.orientation"); - migrateToSession("Storage/LayerDataFormat", "map.layerDataFormat"); - migrateToSession("Storage/MapRenderOrder", "map.renderOrder"); - migrateToSession("Map/FixedSize", "map.fixedSize"); - migrateToSession("Map/Width", "map.width"); - migrateToSession("Map/Height", "map.height"); - migrateToSession("Map/TileWidth", "map.tileWidth"); - migrateToSession("Map/TileHeight", "map.tileHeight"); - - migrateToSession("Tileset/Type", "tileset.type"); - migrateToSession("Tileset/EmbedInMap", "tileset.embedInMap"); - migrateToSession("Tileset/UseTransparentColor", "tileset.useTransparentColor"); - migrateToSession("Tileset/TransparentColor", "tileset.transparentColor"); - migrateToSession("Tileset/TileSize", "tileset.tileSize"); - migrateToSession("Tileset/Spacing", "tileset.spacing"); - migrateToSession("Tileset/Margin", "tileset.margin"); - - migrateToSession("AddPropertyDialog/PropertyType", "property.type"); - - migrateToSession("Console/History", "console.history"); - - migrateToSession("SaveAsImage/VisibleLayersOnly", "exportAsImage.visibleLayersOnly"); - migrateToSession("SaveAsImage/CurrentScale", "exportAsImage.useCurrentScale"); - migrateToSession("SaveAsImage/DrawGrid", "exportAsImage.drawTileGrid"); - migrateToSession("SaveAsImage/IncludeBackgroundColor", "exportAsImage.includeBackgroundColor"); - - migrateToSession("ResizeMap/RemoveObjects", "resizeMap.removeObjects"); - - migrateToSession("Animation/FrameDuration", "frame.defaultDuration"); - - migrateToSession("lastUsedExportFilter", "map.lastUsedExportFilter"); - migrateToSession("lastUsedMapFormat", "map.lastUsedFormat"); - migrateToSession("lastUsedOpenFilter", "file.lastUsedOpenFilter"); - migrateToSession("lastUsedTilesetExportFilter", "tileset.lastUsedExportFilter"); - migrateToSession("lastUsedTilesetFilter", "tileset.lastUsedFilter"); - migrateToSession("lastUsedTilesetFormat", "tileset.lastUsedFormat"); - - // Migrate some preferences that need manual handling - if (mSession.fileName() == Session::defaultFileName()) { - if (contains(QLatin1String("recentFiles"))) { - mSession.recentFiles = get("recentFiles/fileNames"); - mSession.openFiles = get("recentFiles/lastOpenFiles"); - mSession.activeFile = get("recentFiles/lastActive"); - } - - if (contains(QLatin1String("MapEditor/MapStates"))) { - const auto mapStates = get("MapEditor/MapStates"); - - for (auto it = mapStates.begin(); it != mapStates.end(); ++it) { - const QString &fileName = it.key(); - auto mapState = it.value().toMap(); - - const QPointF viewCenter = mapState.value(QLatin1String("viewCenter")).toPointF(); - - mapState.insert(QLatin1String("viewCenter"), toSettingsValue(viewCenter)); - - mSession.setFileState(fileName, mapState); - } - } - - if (mSession.save()) { - remove(QLatin1String("recentFiles")); - remove(QLatin1String("MapEditor/MapStates")); - } - } TilesetManager *tilesetManager = TilesetManager::instance(); tilesetManager->setReloadTilesetsOnChange(reloadTilesetsOnChange()); @@ -670,11 +593,12 @@ void Preferences::setDonationDialogReminder(const QDate &date) QString Preferences::fileDialogStartLocation() const { - if (!mSession.activeFile.isEmpty()) - return QFileInfo(mSession.activeFile).path(); + const auto &session = Session::current(); + if (!session.activeFile.isEmpty()) + return QFileInfo(session.activeFile).path(); - if (!mSession.recentFiles.isEmpty()) - return QFileInfo(mSession.recentFiles.first()).path(); + if (!session.recentFiles.isEmpty()) + return QFileInfo(session.recentFiles.first()).path(); return QStandardPaths::writableLocation(QStandardPaths::HomeLocation); } @@ -684,8 +608,7 @@ QString Preferences::fileDialogStartLocation() const */ void Preferences::addRecentFile(const QString &fileName) { - mSession.addRecentFile(fileName); - saveSession(); + Session::current().addRecentFile(fileName); emit recentFilesChanged(); } @@ -704,8 +627,13 @@ void Preferences::addRecentProject(const QString &fileName) emit recentProjectsChanged(); } -QString Preferences::lastSession() const +QString Preferences::startupSession() const { + if (!startupProject().isEmpty()) + return Session::defaultFileNameForProject(startupProject()); + if (!restoreSessionOnStartup()) + return Session::defaultFileName(); + const auto session = get("Project/LastSession"); return session.isEmpty() ? Session::defaultFileName() : session; } @@ -720,28 +648,6 @@ bool Preferences::restoreSessionOnStartup() const return get("Startup/RestorePreviousSession", true); } -void Preferences::switchSession(Session session) -{ - mSession = std::move(session); - setLastSession(mSession.fileName()); - - Session::notifySessionChanged(); - emit recentFilesChanged(); -} - -void Preferences::saveSession() -{ - if (!mSaveSessionTimer.isActive()) - mSaveSessionTimer.start(); -} - -void Preferences::saveSessionNow() -{ - emit aboutToSaveSession(); - mSaveSessionTimer.stop(); - mSession.save(); -} - void Preferences::addToRecentFileList(const QString &fileName, QStringList& files) { // Remember the file by its absolute file path (not the canonical one, @@ -758,8 +664,7 @@ void Preferences::addToRecentFileList(const QString &fileName, QStringList& file void Preferences::clearRecentFiles() { - mSession.recentFiles.clear(); - saveSession(); + Session::current().clearRecentFiles(); emit recentFilesChanged(); } @@ -846,6 +751,22 @@ QString Preferences::configLocation() return QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); } +QString Preferences::startupProject() +{ + return mStartupProject; +} + +/** + * Sets the project to load on startup (passed on command-line). + * + * Needs to be set before the Session is initialized, because it determines + * the location of the session file. + */ +void Preferences::setStartupProject(const QString &filePath) +{ + mStartupProject = filePath; +} + QString Preferences::objectTypesFile() const { QString file = get("Storage/ObjectTypesFile"); diff --git a/src/tiled/preferences.h b/src/tiled/preferences.h index 227ecb31d1..cda8f9da65 100644 --- a/src/tiled/preferences.h +++ b/src/tiled/preferences.h @@ -29,7 +29,6 @@ #include "filesystemwatcher.h" #include "map.h" #include "objecttypes.h" -#include "session.h" namespace Tiled { @@ -165,13 +164,9 @@ class Preferences : public QSettings QStringList recentProjects() const; void addRecentProject(const QString &fileName); - QString lastSession() const; + QString startupSession() const; void setLastSession(const QString &fileName); - Session &session(); bool restoreSessionOnStartup() const; - void switchSession(Session session); - void saveSession(); - void saveSessionNow(); bool checkForUpdates() const; void setCheckForUpdates(bool on); @@ -188,8 +183,8 @@ class Preferences : public QSettings static QString dataLocation(); static QString configLocation(); - static SessionOption automappingWhileDrawing; - static SessionOption loadedWorlds; + static QString startupProject(); + static void setStartupProject(const QString &filePath); public slots: void setShowGrid(bool showGrid); @@ -249,43 +244,22 @@ public slots: void checkForUpdatesChanged(bool on); void displayNewsChanged(bool on); - void aboutToSaveSession(); + void aboutToSwitchSession(); private: - template - void migrateToSession(const char *preferencesKey, const char *sessionKey) - { - if (mSession.isSet(sessionKey)) - return; - - const auto value = QSettings::value(QLatin1String(preferencesKey)); - if (!value.isValid()) - return; - - mSession.set(sessionKey, value.value()); - } - void addToRecentFileList(const QString &fileName, QStringList &files); void objectTypesFileChangedOnDisk(); FileSystemWatcher mWatcher; - Session mSession; - QTimer mSaveSessionTimer; - QDateTime mObjectTypesFileLastSaved; static Preferences *mInstance; + static QString mStartupProject; }; -inline Session &Preferences::session() -{ - return mSession; -} - - template class Preference { diff --git a/src/tiled/projectdock.cpp b/src/tiled/projectdock.cpp index a0a0a6380d..de51ebc19b 100644 --- a/src/tiled/projectdock.cpp +++ b/src/tiled/projectdock.cpp @@ -26,6 +26,7 @@ #include "objecttemplate.h" #include "preferences.h" #include "projectmodel.h" +#include "session.h" #include "templatemanager.h" #include "utils.h" @@ -95,9 +96,8 @@ ProjectDock::ProjectDock(QWidget *parent) setWidget(widget); retranslateUi(); - auto prefs = Preferences::instance(); - connect(prefs, &Preferences::aboutToSaveSession, - this, [this, prefs] { prefs->session().expandedProjectPaths = mProjectView->expandedPaths(); }); + connect(Preferences::instance(), &Preferences::aboutToSwitchSession, + this, [this] { Session::current().expandedProjectPaths = mProjectView->expandedPaths(); }); connect(mProjectView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &ProjectDock::onCurrentRowChanged); diff --git a/src/tiled/session.cpp b/src/tiled/session.cpp index 76a5038473..83358ebeab 100644 --- a/src/tiled/session.cpp +++ b/src/tiled/session.cpp @@ -55,6 +55,7 @@ QStringList FileHelper::resolve(const QStringList &fileNames) const } QHash Session::mChangedCallbacks; +std::unique_ptr Session::mCurrent; Session::Session(const QString &fileName) : FileHelper { fileName } @@ -68,10 +69,22 @@ Session::Session(const QString &fileName) const auto states = get("fileStates"); for (auto it = states.constBegin(); it != states.constEnd(); ++it) fileStates.insert(resolve(it.key()), it.value()); + + mSyncSettingsTimer.setInterval(1000); + mSyncSettingsTimer.setSingleShot(true); + QObject::connect(&mSyncSettingsTimer, &QTimer::timeout, [this] { sync(); }); } -bool Session::save() +Session::~Session() +{ + if (mSyncSettingsTimer.isActive()) + sync(); +} + +void Session::sync() { + mSyncSettingsTimer.stop(); + set("project", relative(project)); set("recentFiles", relative(recentFiles)); set("openFiles", relative(openFiles)); @@ -82,7 +95,11 @@ bool Session::save() for (auto it = fileStates.constBegin(); it != fileStates.constEnd(); ++it) states.insert(relative(it.key()), it.value()); set("fileStates", states); +} +bool Session::save() +{ + sync(); settings->sync(); return settings->status() == QSettings::NoError; } @@ -94,6 +111,10 @@ bool Session::save() */ void Session::setFileName(const QString &fileName) { + // Make sure we have no pending changes to save to our old location + if (mSyncSettingsTimer.isActive()) + sync(); + auto newSettings = Utils::jsonSettings(fileName); // Copy over all settings @@ -104,6 +125,14 @@ void Session::setFileName(const QString &fileName) settings = std::move(newSettings); FileHelper::setFileName(fileName); + + scheduleSync(); +} + +void Session::setProject(const QString &fileName) +{ + project = fileName; + scheduleSync(); } void Session::addRecentFile(const QString &fileName) @@ -118,6 +147,26 @@ void Session::addRecentFile(const QString &fileName) recentFiles.prepend(absoluteFilePath); while (recentFiles.size() > Preferences::MaxRecentFiles) recentFiles.removeLast(); + + scheduleSync(); +} + +void Session::clearRecentFiles() +{ + recentFiles.clear(); + scheduleSync(); +} + +void Session::setOpenFiles(const QStringList &fileNames) +{ + openFiles = fileNames; + scheduleSync(); +} + +void Session::setActiveFile(const QString &fileNames) +{ + activeFile = fileNames; + scheduleSync(); } QVariantMap Session::fileState(const QString &fileName) const @@ -128,6 +177,7 @@ QVariantMap Session::fileState(const QString &fileName) const void Session::setFileState(const QString &fileName, const QVariantMap &fileState) { fileStates.insert(fileName, fileState); + scheduleSync(); } QString Session::defaultFileName() @@ -150,16 +200,128 @@ QString Session::defaultFileNameForProject(const QString &projectFile) return sessionFile; } +Session &Session::initialize() +{ + Q_ASSERT(!mCurrent); + return switchCurrent(Preferences::instance()->startupSession()); +} + Session &Session::current() { - return Preferences::instance()->session(); + Q_ASSERT(mCurrent); + return *mCurrent; } -void Session::notifySessionChanged() +static void migratePreferences(); + +Session &Session::switchCurrent(const QString &fileName) { + const bool initialSession = !mCurrent; + + mCurrent = std::make_unique(fileName); + Preferences::instance()->setLastSession(mCurrent->fileName()); + + if (initialSession) + migratePreferences(); + + // Call all registered callbacks because any value may have changed for (const auto &callbacks : qAsConst(mChangedCallbacks)) for (const auto &callback : callbacks) callback(); + + return *mCurrent; +} + +template +static void migrateToSession(const char *preferencesKey, const char *sessionKey) +{ + auto &session = Session::current(); + if (session.isSet(sessionKey)) + return; + + const auto value = Preferences::instance()->value(QLatin1String(preferencesKey)); + if (!value.isValid()) + return; + + session.set(sessionKey, value.value()); +} + +static void migratePreferences() +{ + // Migrate some preferences to the session for compatibility + migrateToSession("Automapping/WhileDrawing", "automapping.whileDrawing"); + + migrateToSession("LoadedWorlds", "loadedWorlds"); + migrateToSession("Storage/StampsDirectory", "stampsFolder"); + + migrateToSession("Map/Orientation", "map.orientation"); + migrateToSession("Storage/LayerDataFormat", "map.layerDataFormat"); + migrateToSession("Storage/MapRenderOrder", "map.renderOrder"); + migrateToSession("Map/FixedSize", "map.fixedSize"); + migrateToSession("Map/Width", "map.width"); + migrateToSession("Map/Height", "map.height"); + migrateToSession("Map/TileWidth", "map.tileWidth"); + migrateToSession("Map/TileHeight", "map.tileHeight"); + + migrateToSession("Tileset/Type", "tileset.type"); + migrateToSession("Tileset/EmbedInMap", "tileset.embedInMap"); + migrateToSession("Tileset/UseTransparentColor", "tileset.useTransparentColor"); + migrateToSession("Tileset/TransparentColor", "tileset.transparentColor"); + migrateToSession("Tileset/TileSize", "tileset.tileSize"); + migrateToSession("Tileset/Spacing", "tileset.spacing"); + migrateToSession("Tileset/Margin", "tileset.margin"); + + migrateToSession("AddPropertyDialog/PropertyType", "property.type"); + + migrateToSession("Console/History", "console.history"); + + migrateToSession("SaveAsImage/VisibleLayersOnly", "exportAsImage.visibleLayersOnly"); + migrateToSession("SaveAsImage/CurrentScale", "exportAsImage.useCurrentScale"); + migrateToSession("SaveAsImage/DrawGrid", "exportAsImage.drawTileGrid"); + migrateToSession("SaveAsImage/IncludeBackgroundColor", "exportAsImage.includeBackgroundColor"); + + migrateToSession("ResizeMap/RemoveObjects", "resizeMap.removeObjects"); + + migrateToSession("Animation/FrameDuration", "frame.defaultDuration"); + + migrateToSession("lastUsedExportFilter", "map.lastUsedExportFilter"); + migrateToSession("lastUsedMapFormat", "map.lastUsedFormat"); + migrateToSession("lastUsedOpenFilter", "file.lastUsedOpenFilter"); + migrateToSession("lastUsedTilesetExportFilter", "tileset.lastUsedExportFilter"); + migrateToSession("lastUsedTilesetFilter", "tileset.lastUsedFilter"); + migrateToSession("lastUsedTilesetFormat", "tileset.lastUsedFormat"); + + auto &session = Session::current(); + auto prefs = Preferences::instance(); + + // Migrate some preferences that need manual handling + if (session.fileName() == Session::defaultFileName()) { + if (prefs->contains(QLatin1String("recentFiles"))) { + session.recentFiles = prefs->get("recentFiles/fileNames"); + session.setOpenFiles(prefs->get("recentFiles/lastOpenFiles")); + session.setActiveFile(prefs->get("recentFiles/lastActive")); + } + + if (prefs->contains(QLatin1String("MapEditor/MapStates"))) { + const auto mapStates = prefs->get("MapEditor/MapStates"); + + for (auto it = mapStates.begin(); it != mapStates.end(); ++it) { + const QString &fileName = it.key(); + auto mapState = it.value().toMap(); + + const QPointF viewCenter = mapState.value(QLatin1String("viewCenter")).toPointF(); + + mapState.insert(QLatin1String("viewCenter"), toSettingsValue(viewCenter)); + + session.setFileState(fileName, mapState); + } + } + + if (session.save()) { + prefs->remove(QLatin1String("recentFiles")); + prefs->remove(QLatin1String("MapEditor/MapStates")); + } + } } } // namespace Tiled diff --git a/src/tiled/session.h b/src/tiled/session.h index c87f93f4d1..cdf9febc8b 100644 --- a/src/tiled/session.h +++ b/src/tiled/session.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -117,21 +118,31 @@ class Session : protected FileHelper std::unique_ptr settings; public: - explicit Session(const QString &fileName = QString()); + explicit Session(const QString &fileName); + ~Session(); bool save(); QString fileName() const; void setFileName(const QString &fileName); + void setProject(const QString &fileName); + void addRecentFile(const QString &fileName); + void clearRecentFiles(); + + void setOpenFiles(const QStringList &fileNames); + void setActiveFile(const QString &fileNames); QVariantMap fileState(const QString &fileName) const; void setFileState(const QString &fileName, const QVariantMap &fileState); template T get(const char *key, const T &defaultValue = T()) const - { return fromSettingsValue(settings->value(QLatin1String(key), toSettingsValue(defaultValue))); } + { + return fromSettingsValue(settings->value(QLatin1String(key), + toSettingsValue(defaultValue))); + } template void set(const char *key, const T &value) const @@ -152,9 +163,10 @@ class Session : protected FileHelper static QString defaultFileName(); static QString defaultFileNameForProject(const QString &projectFile); - static Session ¤t(); - static void notifySessionChanged(); + static Session &initialize(); + static Session ¤t(); + static Session &switchCurrent(const QString &fileName); QString project; QStringList recentFiles; @@ -170,6 +182,12 @@ class Session : protected FileHelper private: template friend class SessionOption; + void scheduleSync() { mSyncSettingsTimer.start(); } + void sync(); + + QTimer mSyncSettingsTimer; + + static std::unique_ptr mCurrent; static QHash mChangedCallbacks; };