diff --git a/toonz/sources/include/toonz/preferences.h b/toonz/sources/include/toonz/preferences.h index 572598f..8c1cbc6 100644 --- a/toonz/sources/include/toonz/preferences.h +++ b/toonz/sources/include/toonz/preferences.h @@ -78,6 +78,12 @@ public: enum SnappingTarge { SnapStrokes, SnapGuides, SnapAll }; + enum PathAliasPriority { + ProjectFolderAliases = 0, + SceneFolderAlias, + ProjectFolderOnly + }; + public: static Preferences *instance(); @@ -132,6 +138,9 @@ public: void enableWatchFileSystem(bool on); bool isWatchFileSystemEnabled() { return m_watchFileSystem; } + void setPathAliasPriority(PathAliasPriority priority); + PathAliasPriority getPathAliasPriority() const { return m_pathAliasPriority; } + // Interface tab void setCurrentLanguage(const QString ¤tLanguage); @@ -630,6 +639,9 @@ private: QString m_xsheetLayoutPreference, m_loadedXsheetLayout; // Classic, Classic-revised, compact + // defines which alias to be used if both are possible on coding file path + PathAliasPriority m_pathAliasPriority; + bool m_currentTimelineEnabled; private: diff --git a/toonz/sources/include/toonz/toonzscene.h b/toonz/sources/include/toonz/toonzscene.h index 9c975ee..3c0c97b 100644 --- a/toonz/sources/include/toonz/toonzscene.h +++ b/toonz/sources/include/toonz/toonzscene.h @@ -256,6 +256,9 @@ If \b scene is in +scenes/name.tnz return name, void setVersionNumber(VersionNumber version) { m_versionNumber = version; } VersionNumber getVersionNumber() { return m_versionNumber; } + // if the path is codable with $scenefolder alias, replace it and return true + bool codeFilePathWithSceneFolder(TFilePath &path) const; + private: TFilePath m_scenePath; //!< Full path to the scene file (.tnz). diff --git a/toonz/sources/toonz/filebrowsermodel.cpp b/toonz/sources/toonz/filebrowsermodel.cpp index 9dd57fc..b739367 100644 --- a/toonz/sources/toonz/filebrowsermodel.cpp +++ b/toonz/sources/toonz/filebrowsermodel.cpp @@ -13,6 +13,10 @@ #include "history.h" #include "iocommand.h" +#include "tapp.h" +#include "toonz/tscenehandle.h" +#include "toonz/toonzscene.h" + #include #include @@ -307,6 +311,7 @@ void DvDirModelFileFolderNode::refreshChildren() { void DvDirModelFileFolderNode::getChildrenNames( std::vector &names) const { + if (m_path.isEmpty()) return; TFileStatus folderPathStatus(m_path); if (folderPathStatus.isLink()) return; @@ -360,139 +365,6 @@ QPixmap DvDirModelFileFolderNode::getPixmap(bool isOpen) const { //============================================================================= // -// DvDirModelSceneFolderNode -// -//----------------------------------------------------------------------------- - -DvDirModelSceneFolderNode::DvDirModelSceneFolderNode(DvDirModelNode *parent, - std::wstring name, - const TFilePath &scenePath) - : DvDirModelFileFolderNode(parent, name, scenePath) {} - -//----------------------------------------------------------------------------- - -DvDirModelSceneFolderNode::DvDirModelSceneFolderNode(DvDirModelNode *parent, - const TFilePath &path) - : DvDirModelFileFolderNode(parent, path.withoutParentDir().getWideString(), - path) { - try { - ToonzScene scene; - scene.setScenePath(path); - TProjectP project = TProjectManager::instance()->loadSceneProject(path); - if (!project) return; - scene.setProject(project.getPointer()); - for (int i = 0; i < project->getFolderCount(); i++) { - std::string folderName = project->getFolderName(i); - TFilePath folderPath = project->getFolder(i); - if (folderPath.isAbsolute() && !project->isConstantFolder(i)) { - std::wstring alias = L"+" + ::to_wstring(folderName); - TFilePath folderActualPath = scene.decodeFilePath(TFilePath(alias)); - m_folders[alias] = folderActualPath; - } - } - } catch (...) { - } -} - -//----------------------------------------------------------------------------- - -DvDirModelSceneFolderNode::~DvDirModelSceneFolderNode() {} - -//----------------------------------------------------------------------------- - -bool DvDirModelSceneFolderNode::setName(std::wstring newName) { - m_name = newName; - return true; -} - -//----------------------------------------------------------------------------- - -QPixmap DvDirModelSceneFolderNode::getPixmap(bool isOpen) const { - static QPixmap openFolderPixmap( - svgToPixmap(":Resources/browser_scene_open.svg")); - static QPixmap closeFolderPixmap( - svgToPixmap(":Resources/browser_scene_close.svg")); - return isOpen ? openFolderPixmap : closeFolderPixmap; -} - -//----------------------------------------------------------------------------- - -DvDirModelNode *DvDirModelSceneFolderNode::makeChild(std::wstring name) { - TFilePath actualFolderPath = m_folders[name]; - DvDirModelFileFolderNode *node = - new DvDirModelFileFolderNode(this, name, actualFolderPath); - node->enableRename(false); - return node; -} - -//----------------------------------------------------------------------------- - -void DvDirModelSceneFolderNode::getChildrenNames( - std::vector &names) const { - std::map::const_iterator it; - for (it = m_folders.begin(); it != m_folders.end(); ++it) - names.push_back(it->first); -} - -//----------------------------------------------------------------------------- - -void DvDirModelSceneFolderNode::refreshChildren() { - m_childrenValid = true; - std::vector names; - getChildrenNames(names); - - std::vector oldChildren; - oldChildren.swap(m_children); - - std::vector::iterator j; - int i; - for (i = 0; i < (int)names.size(); i++) { - std::wstring name = names[i]; - for (j = oldChildren.begin(); - j != oldChildren.end() && (*j)->getName() != name; ++j) { - } - DvDirModelNode *child = 0; - if (j != oldChildren.end()) { - child = *j; - oldChildren.erase(j); - } else { - child = makeChild(name); - } - addChild(child); - } - for (j = oldChildren.begin(); j != oldChildren.end(); ++j) { - DvDirModelNode *child = *j; - if (!!child && child->hasChildren()) - child->removeChildren(0, child->getChildCount()); - delete *j; - } -} - -//----------------------------------------------------------------------------- - -DvDirModelFileFolderNode *DvDirModelSceneFolderNode::createNode( - DvDirModelNode *parent, const TFilePath &path) { - DvDirModelFileFolderNode *node = new DvDirModelFileFolderNode(parent, path); - if (path.getName().find("_files") == std::string::npos) - node->enableRename(true); - return node; -} - -//----------------------------------------------------------------------------- - -int DvDirModelSceneFolderNode::rowByName(const std::wstring &name) { - std::vector names; - getChildrenNames(names); - std::vector::iterator it = - std::find(names.begin(), names.end(), name); - if (it == names.end()) - return -1; - else - return std::distance(names.begin(), it); -} - -//============================================================================= -// // DvDirModelSpecialFileFolderNode [Special File Folder] // //----------------------------------------------------------------------------- @@ -1240,11 +1112,15 @@ void DvDirModelRootNode::refreshChildren() { m_versionControlNodes.push_back(node); addChild(node); } + + // scenefolder node (access to the parent folder of the current scene file) + m_sceneFolderNode = + new DvDirModelSceneFolderNode(this, L"Scene Folder", TFilePath()); + m_sceneFolderNode->setPixmap(QPixmap(":Resources/clapboard.png")); } } //----------------------------------------------------------------------------- - DvDirModelNode *DvDirModelRootNode::getNodeByPath(const TFilePath &path) { // Check first for version control nodes DvDirModelNode *node = 0; @@ -1253,6 +1129,15 @@ DvDirModelNode *DvDirModelRootNode::getNodeByPath(const TFilePath &path) { // search in #1 the project folders, #2 sandbox, #3 other folders in file // system + // check for the scene folder if it is the first priority + Preferences::PathAliasPriority priority = + Preferences::instance()->getPathAliasPriority(); + if (priority == Preferences::SceneFolderAlias && + !m_sceneFolderNode->getPath().isEmpty()) { + node = m_sceneFolderNode->getNodeByPath(path); + if (node) return node; + } + // path could be a project, under some project root for (i = 0; i < (int)m_projectRootNodes.size(); i++) { node = m_projectRootNodes[i]->getNodeByPath(path); @@ -1299,6 +1184,13 @@ DvDirModelNode *DvDirModelRootNode::getNodeByPath(const TFilePath &path) { } } + // check for the scene folder if it is the second priority + if (priority == Preferences::ProjectFolderAliases && + !m_sceneFolderNode->getPath().isEmpty()) { + node = m_sceneFolderNode->getNodeByPath(path); + if (node) return node; + } + // it could be a regular folder, somewhere in the file system if (m_myComputerNode) { for (i = 0; i < m_myComputerNode->getChildCount(); i++) { @@ -1318,6 +1210,39 @@ DvDirModelNode *DvDirModelRootNode::getNodeByPath(const TFilePath &path) { return 0; } +//----------------------------------------------------------------------------- +// update the path of sceneLocationNode + +void DvDirModelRootNode::setSceneLocation(const TFilePath &path) { + if (path == m_sceneFolderNode->getPath()) return; + m_sceneFolderNode->setPath(path); + + Preferences::PathAliasPriority priority = + Preferences::instance()->getPathAliasPriority(); + if (priority == Preferences::ProjectFolderOnly) return; + + updateSceneFolderNodeVisibility(); +} + +//----------------------------------------------------------------------------- + +void DvDirModelRootNode::updateSceneFolderNodeVisibility(bool forceHide) { + bool show = (forceHide) ? false : !m_sceneFolderNode->getPath().isEmpty(); + if (show && m_sceneFolderNode->getRow() == -1) { + int row = getChildCount(); + DvDirModel::instance()->notifyBeginInsertRows(QModelIndex(), row, row + 1); + addChild(m_sceneFolderNode); + DvDirModel::instance()->notifyEndInsertRows(); + } else if (!show && m_sceneFolderNode->getRow() != -1) { + int row = m_sceneFolderNode->getRow(); + DvDirModel::instance()->notifyBeginRemoveRows(QModelIndex(), row, row + 1); + // remove the last child of the root node + m_children.erase(m_children.begin() + row, m_children.begin() + row + 1); + DvDirModel::instance()->notifyEndRemoveRows(); + m_sceneFolderNode->setRow(-1); + } +} + //============================================================================= // // DvDirModel @@ -1327,6 +1252,19 @@ DvDirModelNode *DvDirModelRootNode::getNodeByPath(const TFilePath &path) { DvDirModel::DvDirModel() { m_root = new DvDirModelRootNode(); m_root->refreshChildren(); + + // when the scene switched, update the path of the scene location node + TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene(); + bool ret = true; + ret = ret && connect(sceneHandle, SIGNAL(sceneSwitched()), this, + SLOT(onSceneSwitched())); + ret = ret && connect(sceneHandle, SIGNAL(nameSceneChanged()), this, + SLOT(onSceneSwitched())); + ret = ret && connect(sceneHandle, SIGNAL(preferenceChanged(const QString &)), + this, SLOT(onPreferenceChanged(const QString &))); + assert(ret); + + onSceneSwitched(); } //----------------------------------------------------------------------------- @@ -1521,3 +1459,31 @@ DvDirModel *DvDirModel::instance() { static DvDirModel _instance; return &_instance; } + +//----------------------------------------------------------------------------- + +void DvDirModel::onSceneSwitched() { + DvDirModelRootNode *rootNode = dynamic_cast(m_root); + if (rootNode) { + ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); + if (scene) { + if (scene->isUntitled()) + rootNode->setSceneLocation(TFilePath()); + else + rootNode->setSceneLocation(scene->getScenePath().getParentDir()); + } + } +} + +//----------------------------------------------------------------------------- + +void DvDirModel::onPreferenceChanged(const QString &prefName) { + if (prefName != "PathAliasPriority") return; + + Preferences::PathAliasPriority priority = + Preferences::instance()->getPathAliasPriority(); + DvDirModelRootNode *rootNode = dynamic_cast(m_root); + if (rootNode) + rootNode->updateSceneFolderNodeVisibility(priority == + Preferences::ProjectFolderOnly); +} \ No newline at end of file diff --git a/toonz/sources/toonz/filebrowsermodel.h b/toonz/sources/toonz/filebrowsermodel.h index 830ad1f..31a4bdf 100644 --- a/toonz/sources/toonz/filebrowsermodel.h +++ b/toonz/sources/toonz/filebrowsermodel.h @@ -125,34 +125,27 @@ public: //----------------------------------------------------------------------------- -class DvDirModelSceneFolderNode final : public DvDirModelFileFolderNode { - std::map m_folders; +class DvDirModelSpecialFileFolderNode : public DvDirModelFileFolderNode { + QPixmap m_pixmap; public: - DvDirModelSceneFolderNode(DvDirModelNode *parent, std::wstring name, - const TFilePath &scenePath); - DvDirModelSceneFolderNode(DvDirModelNode *parent, const TFilePath &path); - ~DvDirModelSceneFolderNode(); - bool setName(std::wstring newName) override; + DvDirModelSpecialFileFolderNode(DvDirModelNode *parent, std::wstring name, + const TFilePath &localPath); QPixmap getPixmap(bool isOpen) const override; - DvDirModelNode *makeChild(std::wstring name) override; - void getChildrenNames(std::vector &names) const override; - void refreshChildren() override; - static DvDirModelFileFolderNode *createNode(DvDirModelNode *parent, - const TFilePath &path); - int rowByName(const std::wstring &name); + void setPixmap(const QPixmap &pixmap); }; //----------------------------------------------------------------------------- -class DvDirModelSpecialFileFolderNode final : public DvDirModelFileFolderNode { - QPixmap m_pixmap; - +class DvDirModelSceneFolderNode final : public DvDirModelSpecialFileFolderNode { public: - DvDirModelSpecialFileFolderNode(DvDirModelNode *parent, std::wstring name, - const TFilePath &localPath); - QPixmap getPixmap(bool isOpen) const override; - void setPixmap(const QPixmap &pixmap); + DvDirModelSceneFolderNode(DvDirModelNode *parent, std::wstring name, + const TFilePath &localPath) + : DvDirModelSpecialFileFolderNode(parent, name, localPath) {} + void setPath(const TFilePath &path) { + m_path = path; + refreshChildren(); + } }; //----------------------------------------------------------------------------- @@ -317,6 +310,7 @@ class DvDirModelRootNode final : public DvDirModelNode { DvDirModelMyComputerNode *m_myComputerNode; DvDirModelNetworkNode *m_networkNode; DvDirModelProjectNode *m_sandboxProjectNode; + DvDirModelSceneFolderNode *m_sceneFolderNode; void add(std::wstring name, const TFilePath &path); @@ -326,6 +320,10 @@ public: DvDirModelNode *getNodeByPath(const TFilePath &path) override; // QPixmap getPixmap(bool isOpen) const; + + // set the path of sceneLocationNode + void setSceneLocation(const TFilePath &path); + void updateSceneFolderNodeVisibility(bool forceHide = false); }; //============================================================================= @@ -333,6 +331,8 @@ public: // singleton class DvDirModel final : public QAbstractItemModel, public FolderListenerManager::Listener { + Q_OBJECT + DvDirModelNode *m_root; public: @@ -371,6 +371,20 @@ public: const QModelIndex &parent = QModelIndex()) override; QModelIndex getCurrentProjectIndex() const; + + void notifyBeginRemoveRows(const QModelIndex &parent, int first, int last) { + emit beginRemoveRows(parent, first, last); + } + void notifyEndRemoveRows() { emit endRemoveRows(); } + void notifyBeginInsertRows(const QModelIndex &parent, int first, int last) { + emit beginInsertRows(parent, first, last); + } + void notifyEndInsertRows() { emit endInsertRows(); } + +protected slots: + // when the scene switched, update the path of the scene location node + void onSceneSwitched(); + void onPreferenceChanged(const QString &); }; #endif diff --git a/toonz/sources/toonz/iocommand.cpp b/toonz/sources/toonz/iocommand.cpp index c0ffba5..4cbb585 100644 --- a/toonz/sources/toonz/iocommand.cpp +++ b/toonz/sources/toonz/iocommand.cpp @@ -1395,15 +1395,28 @@ bool IoCmd::saveScene(const TFilePath &path, int flags) { QObject::tr("Cancel"), 0); if (ret == 2 || ret == 0) return false; } + + ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); + + // If the scene will be saved in the different folder, check out the scene + // cast. + // if the cast contains the level specified with $scenefolder alias, + // open a warning popup notifying that such level will lose link. + if (!overwrite) { + bool ret = takeCareSceneFolderItemsOnSaveSceneAs(scene, scenePath); + if (!ret) return false; + } + + TFilePath oldFullPath = scene->decodeFilePath(scene->getScenePath()); + TFilePath newFullPath = scene->decodeFilePath(scenePath); + QApplication::setOverrideCursor(Qt::WaitCursor); - ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene(); TXsheet *xsheet = 0; if (saveSubxsheet) xsheet = TApp::instance()->getCurrentXsheet()->getXsheet(); if (app->getCurrentScene()->getDirtyFlag()) scene->getContentHistory(true)->modifiedNow(); - if (scene->decodeFilePath(scene->getScenePath()) != - scene->decodeFilePath(scenePath)) { + if (oldFullPath != newFullPath) { IconGenerator::instance()->clearRequests(); IconGenerator::instance()->clearSceneIcons(); @@ -2527,6 +2540,119 @@ bool IoCmd::importLipSync(TFilePath levelPath, QList frameList, } //=========================================================================== +// If the scene will be saved in the different folder, check out the scene +// cast. +// if the cast contains the level specified with $scenefolder alias, +// open a warning popup notifying that such level will lose link. +// return false if cancelled. +bool IoCmd::takeCareSceneFolderItemsOnSaveSceneAs(ToonzScene *scene, + const TFilePath &newPath) { + TFilePath oldFullPath = scene->decodeFilePath(scene->getScenePath()); + TFilePath newFullPath = scene->decodeFilePath(newPath); + // in case of saving in the same folder + if (oldFullPath.getParentDir() == newFullPath.getParentDir()) return true; + + TLevelSet *levelSet = scene->getLevelSet(); + std::vector levels; + QList sceneFolderLevels; + levelSet->listLevels(levels); + QString str; + for (int i = 0; i < levels.size(); i++) { + TXshLevel *level = levels.at(i); + if (!level->getPath().isEmpty() && + TFilePath("$scenefolder").isAncestorOf(level->getPath())) { + sceneFolderLevels.append(level); + str.append(" " + QString::fromStdWString(level->getName()) + " (" + + level->getPath().getQString() + ")\n"); + } + } + + // in case there is no items with $scenefolder + if (sceneFolderLevels.isEmpty()) return true; + + str = QObject::tr( + "The following level(s) use path with $scenefolder alias.\n\n") + + str + QObject::tr( + "\nThey will not be opened properly when you load the " + "scene next time.\nWhat do you want to do?"); + + int ret = DVGui::MsgBox( + str, QObject::tr("Copy the levels to correspondent paths"), + QObject::tr("Decode all $scenefolder aliases"), + QObject::tr("Save the scene only"), QObject::tr("Cancel"), 0); + if (ret == 4 || ret == 0) return false; + + if (ret == 1) { // copy the levels case + enum OVERWRITEPOLICY { ASK, YES_FOR_ALL, NO_FOR_ALL } policy = ASK; + for (int i = 0; i < sceneFolderLevels.size(); i++) { + TXshLevel *level = sceneFolderLevels.at(i); + TFilePath fp = level->getPath() - TFilePath("$scenefolder"); + fp = fp.withParentDir(newFullPath.getParentDir()); + // check the level existence + if (TSystem::doesExistFileOrLevel(fp)) { + bool overwrite = (policy == YES_FOR_ALL); + if (policy == ASK) { + QString question = + QObject::tr( + "File %1 already exists.\nDo you want to overwrite it?") + .arg(fp.getQString()); + int ret_overwrite = DVGui::MsgBox( + question, QObject::tr("Overwrite"), + QObject::tr("Overwrite for All"), QObject::tr("Don't Overwrite"), + QObject::tr("Don't Overwrite for All"), 0); + if (ret_overwrite == 0) return false; + if (ret_overwrite == 1) + overwrite = true; + else if (ret_overwrite == 2) { + overwrite = true; + policy = YES_FOR_ALL; + } else if (ret_overwrite == 4) + policy = NO_FOR_ALL; + } + if (!overwrite) continue; + } + + TFilePath srcFp = scene->decodeFilePath(level->getPath()); + if (!TSystem::copyFileOrLevel(fp, srcFp)) + warning(QObject::tr("Failed to overwrite %1").arg(fp.getQString())); + // copy the palette as well + if (level->getType() == TZP_XSHLEVEL) { + if (!TSystem::copyFileOrLevel(fp.withType("tpl"), + srcFp.withType("tpl"))) + warning(QObject::tr("Failed to overwrite %1") + .arg(fp.withType("tpl").getQString())); + } + } + } else if (ret == 2) { // decode $scenefolder aliases case + Preferences::PathAliasPriority oldPriority = + Preferences::instance()->getPathAliasPriority(); + Preferences::instance()->setPathAliasPriority( + Preferences::ProjectFolderOnly); + for (int i = 0; i < sceneFolderLevels.size(); i++) { + TXshLevel *level = sceneFolderLevels.at(i); + + // decode and code again + TFilePath fp = + scene->codeFilePath(scene->decodeFilePath(level->getPath())); + TXshSimpleLevel *sil = level->getSimpleLevel(); + TXshPaletteLevel *pal = level->getPaletteLevel(); + TXshSoundLevel *sol = level->getSoundLevel(); + if (sil) + sil->setPath(fp); + else if (pal) + pal->setPath(fp); + else if (sol) + sol->setPath(fp); + } + Preferences::instance()->setPathAliasPriority(oldPriority); + } + + // Save the scene only case (ret == 3), do nothing + + return true; +} + +//=========================================================================== // Commands //--------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/iocommand.h b/toonz/sources/toonz/iocommand.h index c4320b1..d23c480 100644 --- a/toonz/sources/toonz/iocommand.h +++ b/toonz/sources/toonz/iocommand.h @@ -252,6 +252,13 @@ bool exposeComment(int row, int &col, QList commentList, bool importLipSync(TFilePath levelPath, QList frameList, QList commentList, QString fileName); +// If the scene will be saved in the different folder, check out the scene +// cast. +// if the cast contains the level specified with $scenefolder alias, +// open a warning popup notifying that such level will lose link. +bool takeCareSceneFolderItemsOnSaveSceneAs(ToonzScene *scene, + const TFilePath &newPath); + } // namespace IoCmd #endif // IOCOMMAND_H diff --git a/toonz/sources/toonz/penciltestpopup.cpp b/toonz/sources/toonz/penciltestpopup.cpp index 79605b6..8bc3f04 100644 --- a/toonz/sources/toonz/penciltestpopup.cpp +++ b/toonz/sources/toonz/penciltestpopup.cpp @@ -864,7 +864,15 @@ PencilTestSaveInFolderPopup::PencilTestSaveInFolderPopup(QWidget* parent) QString PencilTestSaveInFolderPopup::getPath() { if (!m_subFolderCB->isChecked()) return m_parentFolderField->getPath(); - return m_parentFolderField->getPath() + "\\" + m_subFolderNameField->text(); + // re-code filepath + TFilePath path(m_parentFolderField->getPath() + "\\" + + m_subFolderNameField->text()); + ToonzScene* scene = TApp::instance()->getCurrentScene()->getScene(); + if (scene) { + path = scene->decodeFilePath(path); + path = scene->codeFilePath(path); + } + return path.getQString(); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index 674575a..068c140 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -341,10 +341,10 @@ void PreferencesPopup::onRoomChoiceChanged(int index) { //----------------------------------------------------------------------------- void PreferencesPopup::onDropdownShortcutsCycleOptionsChanged(int index) { - m_pref->setDropdownShortcutsCycleOptions(index); + m_pref->setDropdownShortcutsCycleOptions(index); } - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- void PreferencesPopup::onInterfaceFontChanged(int index) { QString font = m_interfaceFont->currentText(); @@ -1120,6 +1120,15 @@ void PreferencesPopup::onWatchFileSystemClicked(int on) { //----------------------------------------------------------------------------- +void PreferencesPopup::onPathAliasPriorityChanged(int index) { + m_pref->setPathAliasPriority( + static_cast(index)); + TApp::instance()->getCurrentScene()->notifyPreferenceChanged( + "PathAliasPriority"); +} + +//----------------------------------------------------------------------------- + void PreferencesPopup::onShowCurrentTimelineChanged(int index) { m_pref->enableCurrentTimelineIndicator(index == Qt::Checked); } @@ -1180,6 +1189,8 @@ PreferencesPopup::PreferencesPopup() m_projectRootDirections = new QLabel( tr("Advanced: Multiple paths can be separated by ** (No Spaces)")); + QComboBox *pathAliasPriority = new QComboBox(); + QLabel *note_general = new QLabel(tr("* Changes will take effect the next time you run Toonz")); note_general->setStyleSheet("font-size: 10px; font: italic;"); @@ -1453,6 +1464,19 @@ PreferencesPopup::PreferencesPopup() m_customProjectRootLabel->hide(); m_projectRootDirections->hide(); } + + QStringList pathAliasPriorityList; + pathAliasPriorityList + << tr("Project Folder Aliases (+drawings, +scenes, etc.)") + << tr("Scene Folder Alias ($scenefolder)") + << tr("Use Project Folder Aliases Only"); + pathAliasPriority->addItems(pathAliasPriorityList); + pathAliasPriority->setCurrentIndex( + static_cast(m_pref->getPathAliasPriority())); + pathAliasPriority->setToolTip( + tr("This option defines which alias to be used\nif both are possible on " + "coding file path.")); + //--- Interface ------------------------------ QStringList styleSheetList; currentIndex = 0; @@ -1817,6 +1841,18 @@ PreferencesPopup::PreferencesPopup() } projectGroupBox->setLayout(projectRootLay); generalFrameLay->addWidget(projectGroupBox, 0); + + QHBoxLayout *pathAliasLay = new QHBoxLayout(); + pathAliasLay->setMargin(0); + pathAliasLay->setSpacing(5); + { + QLabel *PAPLabel = new QLabel(tr("Path Alias Priority:"), this); + PAPLabel->setToolTip(pathAliasPriority->toolTip()); + pathAliasLay->addWidget(PAPLabel, 0); + pathAliasLay->addWidget(pathAliasPriority, 0); + pathAliasLay->addStretch(1); + } + generalFrameLay->addLayout(pathAliasLay, 0); generalFrameLay->addStretch(1); generalFrameLay->addWidget(note_general, 0); @@ -2425,6 +2461,9 @@ PreferencesPopup::PreferencesPopup() SLOT(onProjectRootChanged())); ret = ret && connect(m_projectRootCustom, SIGNAL(stateChanged(int)), SLOT(onProjectRootChanged())); + ret = ret && connect(pathAliasPriority, SIGNAL(currentIndexChanged(int)), + SLOT(onPathAliasPriorityChanged(int))); + //--- Interface ---------------------- ret = ret && connect(styleSheetType, SIGNAL(currentIndexChanged(const QString &)), diff --git a/toonz/sources/toonz/preferencespopup.h b/toonz/sources/toonz/preferencespopup.h index 522cde8..47912c5 100644 --- a/toonz/sources/toonz/preferencespopup.h +++ b/toonz/sources/toonz/preferencespopup.h @@ -57,7 +57,6 @@ private: *m_vectorSnappingTargetCB, *m_dropdownShortcutsCycleOptionsCB, *m_interfaceFont, *m_interfaceFontWeight, *m_guidedDrawingStyle; - DVGui::MeasuredDoubleLineEdit *m_defLevelWidth, *m_defLevelHeight; DVGui::DoubleLineEdit *m_defLevelDpi; @@ -196,6 +195,7 @@ private slots: void onInterfaceFontChanged(int index); void onInterfaceFontWeightChanged(int index); void onXsheetLayoutChanged(const QString &text); + void onPathAliasPriorityChanged(int index); void onShowCurrentTimelineChanged(int); }; diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index 38b06d1..fcb46bf 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -332,6 +332,7 @@ Preferences::Preferences() , m_shortcutCommandsWhileRenamingCellEnabled(false) , m_xsheetLayoutPreference("Classic-revised") , m_loadedXsheetLayout("Classic-revised") + , m_pathAliasPriority(ProjectFolderOnly) , m_currentTimelineEnabled(true) { TCamera camera; m_defLevelType = PLI_XSHLEVEL; @@ -643,6 +644,9 @@ Preferences::Preferences() getValue(*m_settings, "watchFileSystemEnabled", m_watchFileSystem); getValue(*m_settings, "shortcutCommandsWhileRenamingCellEnabled", m_shortcutCommandsWhileRenamingCellEnabled); + int pathAliasPriority = static_cast(m_pathAliasPriority); + getValue(*m_settings, "pathAliasPriority", pathAliasPriority); + m_pathAliasPriority = static_cast(pathAliasPriority); QString xsheetLayoutPreference; xsheetLayoutPreference = @@ -1582,6 +1586,13 @@ void Preferences::enableShortcutCommandsWhileRenamingCell(bool on) { //----------------------------------------------------------------- +void Preferences::setPathAliasPriority(PathAliasPriority priority) { + m_pathAliasPriority = priority; + m_settings->setValue("pathAliasPriority", static_cast(priority)); +} + +//----------------------------------------------------------------- + void Preferences::enableCurrentTimelineIndicator(bool on) { m_currentTimelineEnabled = on; m_settings->setValue("currentTimelineEnabled", on ? "1" : "0"); diff --git a/toonz/sources/toonzlib/toonzscene.cpp b/toonz/sources/toonzlib/toonzscene.cpp index cc63006..129d339 100644 --- a/toonz/sources/toonzlib/toonzscene.cpp +++ b/toonz/sources/toonzlib/toonzscene.cpp @@ -1225,35 +1225,43 @@ TFilePath ToonzScene::decodeFilePath(const TFilePath &path) const { std::string h; std::wstring s; - if (head != L"" && head[0] == L'+') { - if (TProjectManager::instance()->isTabModeEnabled()) { - return m_scenePath.getParentDir() + - (m_scenePath.getWideName() + L"_files") + tail; - } + if (head != L"") { + // in case of the project folder aliases + if (head[0] == L'+') { + if (TProjectManager::instance()->isTabModeEnabled()) { + return m_scenePath.getParentDir() + + (m_scenePath.getWideName() + L"_files") + tail; + } - if (TProjectManager::instance()->isTabKidsModeEnabled()) { - return m_scenePath.getParentDir() + m_scenePath.getWideName() + tail; - } + if (TProjectManager::instance()->isTabKidsModeEnabled()) { + return m_scenePath.getParentDir() + m_scenePath.getWideName() + tail; + } - if (projectIsEmpty) { - TFilePath dir = m_scenePath.getParentDir(); - if (dir.getName() == "scenes") - return dir.withName(head.substr(1)) + tail; - else - return dir + tail; + if (projectIsEmpty) { + TFilePath dir = m_scenePath.getParentDir(); + if (dir.getName() == "scenes") + return dir.withName(head.substr(1)) + tail; + else + return dir + tail; + } + if (project) { + h = ::to_string(head.substr(1)); + TFilePath f = project->getFolder(h); + if (f != TFilePath()) s = f.getWideString(); + } } - if (project) { - h = ::to_string(head.substr(1)); - TFilePath f = project->getFolder(h); - if (f != TFilePath()) s = f.getWideString(); + // in case of the scene folder alias + else if (head == L"$scenefolder") { + TFilePath dir = m_scenePath.getParentDir(); + return dir + tail; } } if (s != L"") { std::map table; - // se la scena e' untitled e l'espansione del path - // dipende dalla scena (o perche' l'espansione contiene - // $scenename, $scenepath o perche' si usa il savepath) + // if the scene is untitled and path expansion depends on the scene + // (because the expansion contains $ scenename, $ scenepath, or it uses the + // savepath) if (m_isUntitled && (s.find(L"$scene") != std::wstring::npos || project->getUseScenePath(h) || @@ -1307,6 +1315,13 @@ TFilePath ToonzScene::codeFilePath(const TFilePath &path) const { TFilePath fp(path); TProject *project = getProject(); + Preferences::PathAliasPriority priority = + Preferences::instance()->getPathAliasPriority(); + if (priority == Preferences::SceneFolderAlias && + codeFilePathWithSceneFolder(fp)) { + return fp; + } + if (project) for (int i = 0; i < project->getFolderCount(); i++) { TFilePath folderName("+" + project->getFolderName(i)); @@ -1316,10 +1331,28 @@ TFilePath ToonzScene::codeFilePath(const TFilePath &path) const { return fp; } } + + if (priority == Preferences::ProjectFolderAliases) + codeFilePathWithSceneFolder(fp); + return fp; } //----------------------------------------------------------------------------- +// if the path is codable with $scenefolder alias, replace it and return true + +bool ToonzScene::codeFilePathWithSceneFolder(TFilePath &path) const { + // if the scene is untitled, then do nothing and return false + if (isUntitled()) return false; + TFilePath sceneFolderPath = m_scenePath.getParentDir(); + if (sceneFolderPath.isAncestorOf(path)) { + path = TFilePath("$scenefolder") + (path - sceneFolderPath); + return true; + } + return false; +} + +//----------------------------------------------------------------------------- TFilePath ToonzScene::getDefaultLevelPath(int levelType, std::wstring levelName) const { @@ -1391,6 +1424,11 @@ TFilePath ToonzScene::decodeSavePath(TFilePath path) const { TFilePath savePath = getSavePath(); s.replace(i, savePathString.length(), savePath.getWideString()); return TFilePath(s); + } + // in case of the scene folder alias (start with "$scenefolder") + else if (s.find(L"$scenefolder") == 0) { + s.replace(0, 12, m_scenePath.getParentDir().getWideString()); + return TFilePath(s); } else return path; }