diff --git a/src/libs/advanceddockingsystem/ads_globals.h b/src/libs/advanceddockingsystem/ads_globals.h index e61bfa7ceb4..eede7a171ae 100644 --- a/src/libs/advanceddockingsystem/ads_globals.h +++ b/src/libs/advanceddockingsystem/ads_globals.h @@ -126,8 +126,6 @@ enum eBitwiseOperator }; namespace internal { -const bool restoreTesting = true; -const bool restore = false; const char *const closedProperty = "close"; const char *const dirtyProperty = "dirty"; diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp index 051fa68a406..2e0d7c0dd61 100644 --- a/src/libs/advanceddockingsystem/dockmanager.cpp +++ b/src/libs/advanceddockingsystem/dockmanager.cpp @@ -106,17 +106,12 @@ namespace ADS DockManagerPrivate(DockManager *parent); /** - * Checks if the given data stream is a valid docking system state - * file. - */ - bool checkFormat(const QByteArray &state, int version); - - /** - * Restores the state + * Restores the state. If testing is set to true it will check if + * the given data stream is a valid docking system state file. */ bool restoreStateFromXml(const QByteArray &state, int version, - bool testing = internal::restore); + bool testing = false); /** * Restore state @@ -174,11 +169,6 @@ namespace ADS return result; } - bool DockManagerPrivate::checkFormat(const QByteArray &state, int version) - { - return restoreStateFromXml(state, version, internal::restoreTesting); - } - bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version, bool testing) { Q_UNUSED(version) // TODO version is not needed, why is it in here in the first place? @@ -297,7 +287,8 @@ namespace ADS bool DockManagerPrivate::restoreState(const QByteArray &state, int version) { QByteArray currentState = state.startsWith("m_workspaceName) + .arg(workspaceNameToFilePath(d->m_workspaceName) .toUserOutput())); } @@ -613,6 +604,8 @@ namespace ADS const QString m_dirName = QLatin1String("workspaces"); const QString m_fileExt = QLatin1String(".wrk"); // TODO + QString DockManager::workspaceFileExtension() const { return m_fileExt; } + QStringList DockManager::workspaces() { if (d->m_workspaces.isEmpty() || d->m_workspaceListDirty) { @@ -622,14 +615,13 @@ namespace ADS QDir workspaceDir(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/') + m_dirName); QFileInfoList workspaceFiles - = workspaceDir.entryInfoList(QStringList() << QLatin1String("*.wrk"), + = workspaceDir.entryInfoList(QStringList() << QLatin1Char('*') + m_fileExt, QDir::NoFilter, QDir::Time); for (const QFileInfo &fileInfo : workspaceFiles) { - QString filename = fileInfo.completeBaseName(); - filename.replace("_", " "); - d->m_workspaceDateTimes.insert(filename, fileInfo.lastModified()); - tmp.insert(filename); + QString workspaceName = fileNameToWorkspaceName(fileInfo.completeBaseName()); + d->m_workspaceDateTimes.insert(workspaceName, fileInfo.lastModified()); + tmp.insert(workspaceName); } d->m_workspaceListDirty = false; @@ -643,13 +635,11 @@ namespace ADS if (d->m_workspacePresets.isEmpty()) { QDir workspacePresetsDir(d->m_workspacePresetsPath); QFileInfoList workspacePresetsFiles - = workspacePresetsDir.entryInfoList(QStringList() << QLatin1String("*.wrk"), + = workspacePresetsDir.entryInfoList(QStringList() << QLatin1Char('*') + m_fileExt, QDir::NoFilter, QDir::Time); for (const QFileInfo &fileInfo : workspacePresetsFiles) { - QString filename = fileInfo.completeBaseName(); - filename.replace("_", " "); - d->m_workspacePresets.insert(filename); + d->m_workspacePresets.insert(fileNameToWorkspaceName(fileInfo.completeBaseName())); } } return d->m_workspacePresets; @@ -660,13 +650,27 @@ namespace ADS return d->m_workspaceDateTimes.value(workspace); } - Utils::FilePath DockManager::workspaceNameToFileName(const QString &workspaceName) const + Utils::FilePath DockManager::workspaceNameToFilePath(const QString &workspaceName) const { QTC_ASSERT(d->m_settings, return {}); - QString workspaceNameCopy = workspaceName; return Utils::FilePath::fromString( QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/') + m_dirName - + QLatin1Char('/') + workspaceNameCopy.replace(" ", "_") + QLatin1String(".wrk")); + + QLatin1Char('/') + workspaceNameToFileName(workspaceName)); + } + + QString DockManager::fileNameToWorkspaceName(const QString &fileName) const + { + QString copy = QFileInfo(fileName).baseName(); + copy.replace("_", " "); + return copy; + } + + QString DockManager::workspaceNameToFileName(const QString &workspaceName) const + { + QString copy = workspaceName; + copy.replace(" ", "_"); + copy.append(m_fileExt); + return copy; } /** @@ -686,7 +690,7 @@ namespace ADS QMessageBox::warning(parentWidget(), tr("Cannot Save Workspace"), tr("Could not save workspace to file %1") - .arg(workspaceNameToFileName(d->m_workspaceName) + .arg(workspaceNameToFilePath(d->m_workspaceName) .toUserOutput())); } @@ -775,7 +779,7 @@ namespace ADS return false; // Remove corresponding workspace file - QFile fi(workspaceNameToFileName(workspace).toString()); + QFile fi(workspaceNameToFilePath(workspace).toString()); if (fi.exists()) { if (fi.remove()) { d->m_workspaces.removeOne(workspace); @@ -799,12 +803,12 @@ namespace ADS if (!d->m_workspaces.contains(original)) return false; - QFile fi(workspaceNameToFileName(original).toString()); + QFile fi(workspaceNameToFilePath(original).toString()); // If the file does not exist, we can still clone - if (!fi.exists() || fi.copy(workspaceNameToFileName(clone).toString())) { + if (!fi.exists() || fi.copy(workspaceNameToFilePath(clone).toString())) { d->m_workspaces.insert(1, clone); d->m_workspaceDateTimes - .insert(clone, workspaceNameToFileName(clone).toFileInfo().lastModified()); + .insert(clone, workspaceNameToFilePath(clone).toFileInfo().lastModified()); emit workspaceListChanged(); return true; } @@ -825,17 +829,14 @@ namespace ADS if (!isWorkspacePreset(workspace)) return false; - Utils::FilePath filename = workspaceNameToFileName(workspace); + Utils::FilePath fileName = workspaceNameToFilePath(workspace); - if (!QFile::remove(filename.toString())) + if (!QFile::remove(fileName.toString())) return false; QDir presetsDir(d->m_workspacePresetsPath); - QString presetName = workspace; - presetName.replace(" ", "_"); - presetName.append(".wrk"); - - bool result = QFile::copy(presetsDir.filePath(presetName), filename.toString()); + bool result = QFile::copy(presetsDir.filePath(workspaceNameToFileName(workspace)), + fileName.toString()); if (result) d->m_workspaceDateTimes.insert(workspace, QDateTime::currentDateTime()); @@ -852,13 +853,89 @@ namespace ADS return d->m_modeChangeState; } + void DockManager::importWorkspace(const QString &workspace) + { + // Extract workspace name + QString workspaceName = fileNameToWorkspaceName(workspace); + + // Check if the workspace is already contained in the list of workspaces. If that is the case + // add a counter to the workspace name. + if (workspaces().contains(workspaceName)) { + int i = 2; + QString copy; + do { + copy = workspaceName + QLatin1String(" (") + QString::number(i) + QLatin1Char(')'); + ++i; + } while (workspaces().contains(copy)); + workspaceName = copy; + } + + QString fileName = workspaceNameToFileName(workspaceName); + QFile file(workspace); + if (!file.exists()) { + qCInfo(adsLog) << QString("File doesn't exist '%1'").arg(workspace); + return; + } + + QDir workspaceDir(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/') + m_dirName); + + if (!file.copy(workspaceDir.filePath(fileName))) { + qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg( + workspace, workspaceDir.filePath(fileName), file.errorString()); + } else { + d->m_workspaces.insert(1, workspaceName); + d->m_workspaceDateTimes.insert(workspaceName, + workspaceNameToFilePath(workspaceName).toFileInfo().lastModified()); + d->m_workspaceListDirty = true; + // After importing the workspace, update the workspace list + workspaces(); + emit workspaceListChanged(); + } + } + + void DockManager::exportWorkspace(const QString &target, const QString &workspace) + { + // If we came this far the user decided that in case the target already exists to overwrite it. + // We first need to remove the existing file, otherwise QFile::copy() will fail. + QFileInfo targetFileInfo(target); + + // Remove the file which supposed to be overwritten + if (targetFileInfo.exists()) { + QFile fi(targetFileInfo.absoluteFilePath()); + if (!fi.remove()) { + qCInfo(adsLog) << QString("Couldn't remove '%1'").arg(targetFileInfo.absoluteFilePath()); + return; + } + } + + // Check if the target directory exists + if (!targetFileInfo.absoluteDir().exists()) { + qCInfo(adsLog) << QString("Directory doesn't exist '%1'").arg(targetFileInfo.dir().dirName()); + return; + } + + // Check if the workspace exists + Utils::FilePath workspaceFilePath = workspaceNameToFilePath(workspace); + if (!workspaceFilePath.exists()) { + qCInfo(adsLog) << QString("Workspace doesn't exist '%1'").arg(workspaceFilePath.toString()); + return; + } + + // Finally copy the workspace to the target + QFile workspaceFile(workspaceFilePath.toString()); + if (!workspaceFile.copy(targetFileInfo.absoluteFilePath())) { + qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg( + workspace, workspaceFilePath.toString(), workspaceFile.errorString()); + } + } + bool DockManager::write(const QString &workspace, const QByteArray &data, QString *errorString) const { - Utils::FilePath filename = workspaceNameToFileName(workspace); + Utils::FilePath fileName = workspaceNameToFilePath(workspace); QDir tmp; - tmp.mkpath(filename.toFileInfo().path()); - Utils::FileSaver fileSaver(filename.toString(), QIODevice::Text); + tmp.mkpath(fileName.toFileInfo().path()); + Utils::FileSaver fileSaver(fileName.toString(), QIODevice::Text); if (!fileSaver.hasError()) fileSaver.write(data); @@ -884,7 +961,7 @@ namespace ADS QByteArray DockManager::loadWorkspace(const QString &workspace) const { QByteArray data; - Utils::FilePath fileName = workspaceNameToFileName(workspace); + Utils::FilePath fileName = workspaceNameToFilePath(workspace); if (fileName.exists()) { QFile file(fileName.toString()); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -920,17 +997,14 @@ namespace ADS } for (const auto &preset : presets) { - QString filename = preset; - filename.replace(" ", "_"); - filename.append(".wrk"); - - QString filePath = presetsDir.filePath(filename); + QString fileName = workspaceNameToFileName(preset); + QString filePath = presetsDir.filePath(fileName); QFile file(filePath); if (file.exists()) { - if (!file.copy(workspaceDir.filePath(filename))) { + if (!file.copy(workspaceDir.filePath(fileName))) { qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg( - filePath, workspaceDir.filePath(filename), file.errorString()); + filePath, workspaceDir.filePath(fileName), file.errorString()); } d->m_workspaceListDirty = true; } diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h index 506335714e0..658c9a2d6c4 100644 --- a/src/libs/advanceddockingsystem/dockmanager.h +++ b/src/libs/advanceddockingsystem/dockmanager.h @@ -232,7 +232,7 @@ public: virtual ~DockManager() override; /** - * This function returns the global configuration flags + * This function returns the global configuration flags. */ static ConfigFlags configFlags(); @@ -244,13 +244,13 @@ public: static void setConfigFlags(const ConfigFlags flags); /** - * Set a certain config flag + * Set a certain config flag. * \see setConfigFlags() */ static void setConfigFlag(eConfigFlag flag, bool on = true); /** - * Returns true if the given config flag is set + * Returns true if the given config flag is set. */ static bool testConfigFlag(eConfigFlag flag); @@ -263,7 +263,7 @@ public: /** * The distance the user needs to move the mouse with the left button - * hold down before a dock widget start floating + * hold down before a dock widget start floating. */ static int startDragDistance(); @@ -319,35 +319,35 @@ public: /** * Searches for a registered doc widget with the given ObjectName * \return Return the found dock widget or nullptr if a dock widget with the - * given name is not registered + * given name is not registered. */ DockWidget *findDockWidget(const QString &objectName) const; /** - * Remove the given Dock from the dock manager + * Remove the given DockWidget from the dock manager. */ void removeDockWidget(DockWidget *dockWidget); /** * This function returns a readable reference to the internal dock - * widgets map so that it is possible to iterate over all dock widgets + * widgets map so that it is possible to iterate over all dock widgets. */ QMap dockWidgetsMap() const; /** * Returns the list of all active and visible dock containers - * Dock containers are the main dock manager and all floating widgets + * Dock containers are the main dock manager and all floating widgets. */ const QList dockContainers() const; /** - * Returns the list of all floating widgets + * Returns the list of all floating widgets. */ const QList floatingWidgets() const; /** * This function always return 0 because the main window is always behind - * any floating widget + * any floating widget. */ virtual unsigned int zOrderIndex() const override; @@ -378,33 +378,33 @@ public: signals: /** - * This signal is emitted if the list of perspectives changed + * This signal is emitted if the list of workspaces changed. */ void workspaceListChanged(); /** - * This signal is emitted if perspectives have been removed + * This signal is emitted if workspaces have been removed. */ void workspacesRemoved(); /** * This signal is emitted, if the restore function is called, just before * the dock manager starts restoring the state. - * If this function is called, nothing has changed yet + * If this function is called, nothing has changed yet. */ void restoringState(); /** * This signal is emitted if the state changed in restoreState. * The signal is emitted if the restoreState() function is called or - * if the openWorkspace() function is called + * if the openWorkspace() function is called. */ void stateRestored(); /** * This signal is emitted, if the dock manager starts opening a - * perspective. - * Opening a perspective may take more than a second if there are + * workspace. + * Opening a workspace may take more than a second if there are * many complex widgets. The application may use this signal * to show some progress indicator or to change the mouse cursor * into a busy cursor. @@ -413,7 +413,7 @@ signals: /** * This signal is emitted if the dock manager finished opening a - * perspective + * workspace. */ void workspaceOpened(const QString &workspaceName); @@ -432,8 +432,7 @@ signals: void dockAreaCreated(DockAreaWidget *dockArea); /** - * This signal is emitted just before the given dock widget is removed - * from the + * This signal is emitted just before removal of the given DockWidget. */ void dockWidgetAboutToBeRemoved(DockWidget *dockWidget); @@ -452,10 +451,13 @@ public: QString activeWorkspace() const; QString lastWorkspace() const; bool autoRestorLastWorkspace() const; + QString workspaceFileExtension() const; QStringList workspaces(); QSet workspacePresets() const; QDateTime workspaceDateTime(const QString &workspace) const; - Utils::FilePath workspaceNameToFileName(const QString &workspaceName) const; + Utils::FilePath workspaceNameToFilePath(const QString &workspaceName) const; + QString fileNameToWorkspaceName(const QString &fileName) const; + QString workspaceNameToFileName(const QString &workspaceName) const; bool createWorkspace(const QString &workspace); @@ -478,6 +480,9 @@ public: void setModeChangeState(bool value); bool isModeChangeState() const; + void importWorkspace(const QString &workspace); + void exportWorkspace(const QString &target, const QString &workspace); + signals: void aboutToUnloadWorkspace(QString workspaceName); void aboutToLoadWorkspace(QString workspaceName); diff --git a/src/libs/advanceddockingsystem/workspacedialog.cpp b/src/libs/advanceddockingsystem/workspacedialog.cpp index a458940aa00..0226f4a5974 100644 --- a/src/libs/advanceddockingsystem/workspacedialog.cpp +++ b/src/libs/advanceddockingsystem/workspacedialog.cpp @@ -170,6 +170,14 @@ WorkspaceDialog::WorkspaceDialog(DockManager *manager, QWidget *parent) &WorkspaceView::selected, this, &WorkspaceDialog::updateActions); + connect(m_ui.btImport, + &QAbstractButton::clicked, + m_ui.workspaceView, + &WorkspaceView::importWorkspace); + connect(m_ui.btExport, + &QAbstractButton::clicked, + m_ui.workspaceView, + &WorkspaceView::exportCurrentWorkspace); m_ui.whatsAWorkspaceLabel->setOpenExternalLinks(true); @@ -199,6 +207,7 @@ void WorkspaceDialog::updateActions(const QStringList &workspaces) m_ui.btClone->setEnabled(false); m_ui.btReset->setEnabled(false); m_ui.btSwitch->setEnabled(false); + m_ui.btExport->setEnabled(false); return; } const bool presetIsSelected = Utils::anyOf(workspaces, [this](const QString &workspace) { @@ -212,6 +221,7 @@ void WorkspaceDialog::updateActions(const QStringList &workspaces) m_ui.btClone->setEnabled(workspaces.size() == 1); m_ui.btReset->setEnabled(presetIsSelected); m_ui.btSwitch->setEnabled(workspaces.size() == 1); + m_ui.btExport->setEnabled(workspaces.size() == 1); } } // namespace ADS diff --git a/src/libs/advanceddockingsystem/workspacedialog.ui b/src/libs/advanceddockingsystem/workspacedialog.ui index 93e40aeefc7..ea494218aad 100644 --- a/src/libs/advanceddockingsystem/workspacedialog.ui +++ b/src/libs/advanceddockingsystem/workspacedialog.ui @@ -6,8 +6,8 @@ 0 0 - 373 - 282 + 400 + 300 @@ -90,6 +90,20 @@ + + + + Import + + + + + + + Export + + + diff --git a/src/libs/advanceddockingsystem/workspacemodel.cpp b/src/libs/advanceddockingsystem/workspacemodel.cpp index badf2633687..2fb1dc52beb 100644 --- a/src/libs/advanceddockingsystem/workspacemodel.cpp +++ b/src/libs/advanceddockingsystem/workspacemodel.cpp @@ -260,6 +260,18 @@ void WorkspaceModel::switchToWorkspace(const QString &workspace) emit workspaceSwitched(); } +void WorkspaceModel::importWorkspace(const QString &workspace) +{ + m_manager->importWorkspace(workspace); + m_sortedWorkspaces = m_manager->workspaces(); + sort(m_currentSortColumn, m_currentSortOrder); +} + +void WorkspaceModel::exportWorkspace(const QString &target, const QString &workspace) +{ + m_manager->exportWorkspace(target, workspace); +} + void WorkspaceModel::runWorkspaceNameInputDialog(WorkspaceNameInputDialog *workspaceInputDialog, std::function createWorkspace) { diff --git a/src/libs/advanceddockingsystem/workspacemodel.h b/src/libs/advanceddockingsystem/workspacemodel.h index 3ccd70db922..9b4ce5fc48b 100644 --- a/src/libs/advanceddockingsystem/workspacemodel.h +++ b/src/libs/advanceddockingsystem/workspacemodel.h @@ -77,6 +77,9 @@ public: void resetWorkspace(const QString &workspace); void switchToWorkspace(const QString &workspace); + void importWorkspace(const QString &workspace); + void exportWorkspace(const QString &target, const QString &workspace); + private: void runWorkspaceNameInputDialog(WorkspaceNameInputDialog *workspaceInputDialog, std::function createWorkspace); diff --git a/src/libs/advanceddockingsystem/workspaceview.cpp b/src/libs/advanceddockingsystem/workspaceview.cpp index 087fc056afc..7c730443b40 100644 --- a/src/libs/advanceddockingsystem/workspaceview.cpp +++ b/src/libs/advanceddockingsystem/workspaceview.cpp @@ -40,6 +40,7 @@ #include +#include #include #include #include @@ -135,6 +136,38 @@ void WorkspaceView::deleteWorkspaces(const QStringList &workspaces) m_workspaceModel.deleteWorkspaces(workspaces); } +void WorkspaceView::importWorkspace() +{ + static QString lastDir; + const QString currentDir = lastDir.isEmpty() ? "" : lastDir; + const auto fileName = QFileDialog::getOpenFileName(this, + tr("Import Workspace"), + currentDir, + "Workspaces (*" + m_manager->workspaceFileExtension() + ")"); + + if (!fileName.isEmpty()) + lastDir = QFileInfo(fileName).absolutePath(); + + m_workspaceModel.importWorkspace(fileName); +} + +void WorkspaceView::exportCurrentWorkspace() +{ + static QString lastDir; + const QString currentDir = lastDir.isEmpty() ? "" : lastDir; + QFileInfo fileInfo(currentDir, m_manager->workspaceNameToFileName(currentWorkspace())); + + const auto fileName = QFileDialog::getSaveFileName(this, + tr("Export Workspace"), + fileInfo.absoluteFilePath(), + "Workspaces (*" + m_manager->workspaceFileExtension() + ")"); + + if (!fileName.isEmpty()) + lastDir = QFileInfo(fileName).absolutePath(); + + m_workspaceModel.exportWorkspace(fileName, currentWorkspace()); +} + void WorkspaceView::cloneCurrentWorkspace() { m_workspaceModel.cloneWorkspace(this, currentWorkspace()); diff --git a/src/libs/advanceddockingsystem/workspaceview.h b/src/libs/advanceddockingsystem/workspaceview.h index 428c0cbd1de..3edd668cc23 100644 --- a/src/libs/advanceddockingsystem/workspaceview.h +++ b/src/libs/advanceddockingsystem/workspaceview.h @@ -60,6 +60,9 @@ public: void resetCurrentWorkspace(); void switchToCurrentWorkspace(); + void importWorkspace(); + void exportCurrentWorkspace(); + QString currentWorkspace(); WorkspaceModel *workspaceModel(); void selectActiveWorkspace();