diff --git a/toonz/sources/toonzlib/studiopalette.cpp b/toonz/sources/toonzlib/studiopalette.cpp index 1847833..20b0729 100644 --- a/toonz/sources/toonzlib/studiopalette.cpp +++ b/toonz/sources/toonzlib/studiopalette.cpp @@ -256,9 +256,10 @@ TPalette *StudioPalette::getPalette(const TFilePath &path, void StudioPalette::movePalette(const TFilePath &dstPath, const TFilePath &srcPath) { try { - TSystem::renameFile(dstPath, srcPath); + // do not allow overwrite palette + TSystem::renameFile(dstPath, srcPath, false); } catch (...) { - return; + throw; } std::wstring id = readPaletteGlobalName(dstPath); table.erase(id); @@ -279,8 +280,18 @@ int StudioPalette::getChildren(std::vector &fps, } } - for (TFilePathSet::iterator i = q.begin(); i != q.end(); ++i) - if (isFolder(*i) || isPalette(*i)) fps.push_back(*i); + // put the folders above the palette items + std::vector palettes; + for (TFilePathSet::iterator i = q.begin(); i != q.end(); ++i) { + if (isFolder(*i)) + fps.push_back(*i); + else if (isPalette(*i)) + palettes.push_back(*i); + } + if (!palettes.empty()) { + fps.reserve(fps.size() + palettes.size()); + std::copy(palettes.begin(), palettes.end(), std::back_inserter(fps)); + } // fps.push_back(m_root+"butta.tpl"); return fps.size(); } diff --git a/toonz/sources/toonzlib/studiopalettecmd.cpp b/toonz/sources/toonzlib/studiopalettecmd.cpp index c8023ec..8038c20 100644 --- a/toonz/sources/toonzlib/studiopalettecmd.cpp +++ b/toonz/sources/toonzlib/studiopalettecmd.cpp @@ -10,6 +10,7 @@ #include "tconvert.h" #include "ttoonzimage.h" #include "timagecache.h" +#include "tmsgcore.h" #include "toonz/studiopalette.h" #include "toonz/toonzscene.h" @@ -241,23 +242,50 @@ public: class MovePaletteUndo final : public TUndo { TFilePath m_dstPath, m_srcPath; + bool m_isRename; public: MovePaletteUndo(const TFilePath &dstPath, const TFilePath &srcPath) - : m_dstPath(dstPath), m_srcPath(srcPath) {} + : m_dstPath(dstPath), m_srcPath(srcPath) { + m_isRename = (m_srcPath.getParentDir() == m_dstPath.getParentDir()); + } void undo() const override { - StudioPalette::instance()->movePalette(m_srcPath, m_dstPath); + QString errorStr = (m_isRename) ? QObject::tr("Can't undo rename palette") + : QObject::tr("Can't undo move palette"); + try { + StudioPalette::instance()->movePalette(m_srcPath, m_dstPath); + } catch (TException &e) { + DVGui::error(errorStr + " : " + + QString(::to_string(e.getMessage()).c_str())); + } catch (...) { + DVGui::error(errorStr); + } } + void redo() const override { - StudioPalette::instance()->movePalette(m_dstPath, m_srcPath); + QString errorStr = (m_isRename) ? QObject::tr("Can't redo rename palette") + : QObject::tr("Can't redo move palette"); + try { + StudioPalette::instance()->movePalette(m_dstPath, m_srcPath); + } catch (TException &e) { + DVGui::error(errorStr + ":" + + QString(::to_string(e.getMessage()).c_str())); + } catch (...) { + DVGui::error(errorStr); + } } int getSize() const override { return sizeof(*this); } QString getHistoryString() override { - return QObject::tr("Move Studio Palette Folder : %1 : %2 > %3") - .arg(QString::fromStdString(m_srcPath.getName())) - .arg(QString::fromStdString(m_srcPath.getParentDir().getName())) - .arg(QString::fromStdString(m_dstPath.getParentDir().getName())); + if (m_isRename) + return QObject::tr("Rename Studio Palette : %1 > %2") + .arg(QString::fromStdString(m_srcPath.getName())) + .arg(QString::fromStdString(m_dstPath.getName())); + else + return QObject::tr("Move Studio Palette Folder : %1 : %2 > %3") + .arg(QString::fromStdString(m_srcPath.getName())) + .arg(QString::fromStdString(m_srcPath.getParentDir().getName())) + .arg(QString::fromStdString(m_dstPath.getParentDir().getName())); } int getHistoryType() override { return HistoryType::Palette; } }; diff --git a/toonz/sources/toonzqt/studiopaletteviewer.cpp b/toonz/sources/toonzqt/studiopaletteviewer.cpp index 1203b96..a033f05 100644 --- a/toonz/sources/toonzqt/studiopaletteviewer.cpp +++ b/toonz/sources/toonzqt/studiopaletteviewer.cpp @@ -227,15 +227,19 @@ QTreeWidgetItem *StudioPaletteTreeViewer::createItem(const TFilePath path) { QString itemName = toQString(TFilePath(path.getWideName())); QTreeWidgetItem *item = new QTreeWidgetItem((QTreeWidget *)0, QStringList(itemName)); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | + Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); if (studioPalette->isPalette(path)) { if (studioPalette->hasGlobalName(path)) item->setIcon(0, m_studioPaletteIcon); else item->setIcon(0, m_levelPaletteIcon); - } else if (studioPalette->isFolder(path)) + item->setFlags(item->flags() | Qt::ItemNeverHasChildren); + } else if (studioPalette->isFolder(path)) { item->setIcon(0, m_folderIcon); + item->setFlags(item->flags() | Qt::ItemIsDropEnabled); + } item->setData(1, Qt::UserRole, toQString(path)); - item->setFlags(item->flags() | Qt::ItemIsEditable); return item; } @@ -349,6 +353,17 @@ void StudioPaletteTreeViewer::onRefreshTreeShortcutTriggered() { */ void StudioPaletteTreeViewer::refreshItem(QTreeWidgetItem *item) { + struct Locals { + bool isUpper(const TFilePath &fp1, const TFilePath &fp2) { + bool fp1IsFolder = StudioPalette::instance()->isFolder(fp1); + bool fp2IsFolder = StudioPalette::instance()->isFolder(fp2); + if (fp1IsFolder == fp2IsFolder) + return fp1 < fp2; + else + return fp1IsFolder; + } + } locals; + TFilePath folderPath = getItemPath(item); assert(folderPath != TFilePath()); // correct only tpl files and folders @@ -374,14 +389,13 @@ void StudioPaletteTreeViewer::refreshItem(QTreeWidgetItem *item) { if (path == currentItemPath) { itemIndex++; pathIndex++; - } else if ((!path.isEmpty() && path < currentItemPath) || + } else if ((!path.isEmpty() && locals.isUpper(path, currentItemPath)) || currentItemPath.isEmpty()) { currentItem = createItem(path); - item->insertChild(itemIndex, currentItem); - itemIndex++; + item->insertChild(pathIndex, currentItem); pathIndex++; } else { - assert(currentItemPath < path || path.isEmpty()); + assert(locals.isUpper(currentItemPath, path) || path.isEmpty()); assert(currentItem); item->removeChild(currentItem); itemIndex++; @@ -1034,6 +1048,23 @@ void StudioPaletteTreeViewer::dragMoveEvent(QDragMoveEvent *event) { if (m_dropItem) m_dropItem->setTextColor(0, Qt::black); if (item) { + // drop will not be executed on the same item + const QMimeData *mimeData = event->mimeData(); + if (mimeData->hasUrls() && mimeData->urls().size() == 1) { + TFilePath path = + TFilePath(mimeData->urls()[0].toLocalFile().toStdWString()); + if (path == getItemPath(item)) { + m_dropItem = 0; + event->ignore(); + viewport()->update(); + return; + } + } + // when dragging over other items, drop destination will be the parent + // folder of it + if (item->flags() & Qt::ItemNeverHasChildren) { + item = item->parent(); + } m_dropItem = item; event->acceptProposedAction(); } else { @@ -1075,15 +1106,33 @@ void StudioPaletteTreeViewer::dropEvent(QDropEvent *event) { if (!mimeData->hasUrls() || mimeData->urls().size() == 0) return; QList urls = mimeData->urls(); - TUndoManager::manager()->beginBlock(); - int i; - for (i = 0; i < urls.size(); i++) { - QUrl url = urls[i]; - TFilePath path = TFilePath(url.toLocalFile().toStdWString()); - StudioPalette *studioPalette = StudioPalette::instance(); - if (path == newPath || path.getParentDir() == newPath) continue; + // make the list of palette paths which will be actually moved + QList palettePaths; + for (int i = 0; i < urls.size(); i++) { + TFilePath path = TFilePath(urls[i].toLocalFile().toStdWString()); + if (path != newPath && path.getParentDir() != newPath) + palettePaths.append(path); + } + if (palettePaths.isEmpty()) return; + + // open the confirmation dialog in order to prevent unintended move + QString pltName; + if (palettePaths.size() == 1) + pltName = tr("the palette \"%1\"") + .arg(QString::fromStdWString(palettePaths[0].getWideName())); + else + pltName = tr("the selected palettes"); + QString dstName = QString::fromStdWString(newPath.getWideName()); + + QString question = + tr("Move %1 to \"%2\". Are you sure ?").arg(pltName).arg(dstName); + int ret = DVGui::MsgBox(question, tr("Move"), tr("Cancel")); + if (ret == 0 || ret == 2) return; + TUndoManager::manager()->beginBlock(); + for (int i = 0; i < palettePaths.size(); i++) { + TFilePath path = palettePaths[i]; if (isInStudioPalette(path)) { TFilePath newPalettePath = newPath + @@ -1099,7 +1148,7 @@ void StudioPaletteTreeViewer::dropEvent(QDropEvent *event) { } } TUndoManager::manager()->endBlock(); - event->setDropAction(Qt::CopyAction); + event->setDropAction(Qt::MoveAction); event->accept(); }