From 7f18c9e8415429bfce258361a09472d97341f5a4 Mon Sep 17 00:00:00 2001 From: shun-iwasawa Date: Jul 03 2020 07:05:03 +0000 Subject: fix crash on saving studio palette --- diff --git a/toonz/sources/toonzlib/studiopalette.cpp b/toonz/sources/toonzlib/studiopalette.cpp index 36ac67d..625c3bf 100644 --- a/toonz/sources/toonzlib/studiopalette.cpp +++ b/toonz/sources/toonzlib/studiopalette.cpp @@ -328,7 +328,7 @@ bool StudioPalette::isPalette(const TFilePath &path) { //------------------------------------------------------------------- /*! check if the palette is studio palette or level palette in order to separate * icons in the StudioPaletteTree. -*/ + */ bool StudioPalette::hasGlobalName(const TFilePath &path) { return (readPaletteGlobalName(path) != L""); } @@ -376,16 +376,21 @@ void StudioPalette::createFolder(const TFilePath &parentFolderPath, TFilePath StudioPalette::createPalette(const TFilePath &folderPath, std::string name) { - TPalette *palette = 0; + TPalette *palette = 0; if (name == "") name = "new palette"; - palette = new TPalette(); - TFilePath fp = makeUniqueName(folderPath + (name + ".tpl")); + palette = new TPalette(); + TFilePath fp = makeUniqueName(folderPath + (name + ".tpl")); time_t ltime; time(<ime); std::wstring gname = std::to_wstring(ltime) + L"_" + std::to_wstring(rand()); palette->setGlobalName(gname); setStylesGlobalNames(palette); - save(fp, palette); + try { + save(fp, palette); + } catch (...) { + delete palette; + throw; + } delete palette; notifyTreeChange(); return fp; @@ -404,7 +409,12 @@ void StudioPalette::setPalette(const TFilePath &palettePath, pgn = readPaletteGlobalName(palettePath); palette->setGlobalName(pgn); setStylesGlobalNames(palette); - save(palettePath, palette); + try { + save(palettePath, palette); + } catch (...) { + palette->release(); + throw; + } palette->release(); if (notifyPaletteChanged) notifyPaletteChange(palettePath); } @@ -518,7 +528,7 @@ std::pair StudioPalette::getSourceStyle(TColorStyle *cs) { //------------------------------------------------------------------- /*! return if any style in the palette is changed -*/ + */ bool StudioPalette::updateLinkedColors(TPalette *palette) { bool paletteIsChanged = false; std::map table; @@ -587,6 +597,11 @@ void StudioPalette::save(const TFilePath &path, TPalette *palette) { } TOStream os(path); + if (!os) { + throw TSystemException(path, + "The studio palette cannot be saved: the output " + "stream status is invalid."); + } std::map attr; attr["name"] = ::to_string(palette->getGlobalName()); os.openChild("palette", attr); diff --git a/toonz/sources/toonzlib/studiopalettecmd.cpp b/toonz/sources/toonzlib/studiopalettecmd.cpp index 8038c20..ed909d4 100644 --- a/toonz/sources/toonzlib/studiopalettecmd.cpp +++ b/toonz/sources/toonzlib/studiopalettecmd.cpp @@ -33,6 +33,23 @@ namespace { //----------------------------------------------------------------------------- +bool trySetStudioPalette(const TFilePath &palettePath, const TPalette *plt, + bool notifyPaletteChanged) { + try { + StudioPalette::instance()->setPalette(palettePath, plt, + notifyPaletteChanged); + } catch (TSystemException se) { + DVGui::warning(QString::fromStdWString(se.getMessage())); + return false; + } catch (...) { + DVGui::warning( + QString::fromStdWString(palettePath.getWideString() + L"\n") + + QObject::tr("Failed to save palette.")); + return false; + } + return true; +} + //============================================================================= // PaletteAssignUndo : Undo for the "Load into Current Palette" command. @@ -91,13 +108,11 @@ public: , m_paletteHandle(paletteHandle) {} void undo() const override { - StudioPalette *sp = StudioPalette::instance(); - sp->setPalette(m_fp, m_oldPalette.getPointer(), true); + trySetStudioPalette(m_fp, m_oldPalette.getPointer(), true); m_paletteHandle->notifyPaletteChanged(); } void redo() const override { - StudioPalette *sp = StudioPalette::instance(); - sp->setPalette(m_fp, m_newPalette.getPointer(), true); + trySetStudioPalette(m_fp, m_newPalette.getPointer(), true); m_paletteHandle->notifyPaletteChanged(); } @@ -127,8 +142,7 @@ public: } void undo() const override { - StudioPalette::instance()->setPalette(m_palettePath, m_palette->clone(), - true); + trySetStudioPalette(m_palettePath, m_palette->clone(), true); } void redo() const override { StudioPalette::instance()->deletePalette(m_palettePath); @@ -157,8 +171,7 @@ public: StudioPalette::instance()->deletePalette(m_palettePath); } void redo() const override { - StudioPalette::instance()->setPalette(m_palettePath, m_palette->clone(), - true); + trySetStudioPalette(m_palettePath, m_palette->clone(), true); } int getSize() const override { return sizeof(*this) + sizeof(TPalette); } QString getHistoryString() override { @@ -195,8 +208,8 @@ public: it != m_pathSet.end(); it++) { TFilePath path = *it; if (path.getType() == "tpl") // Is a palette - StudioPalette::instance()->setPalette( - path, m_paletteList.at(++paletteCount)->clone(), true); + trySetStudioPalette(path, m_paletteList.at(++paletteCount)->clone(), + true); else // Is a folder StudioPalette::instance()->createFolder(path.getParentDir(), path.getWideName()); @@ -399,7 +412,7 @@ int findClosest(const TPixel &color, std::map &colorMap, if ((dm = (color.m - it->first.m) * (color.m - it->first.m)) > tolerance) continue; - int currDist = dr + dg + db + dm; + int currDist = dr + dg + db + dm; if (currDist < minDist) minDist = currDist, index = it->second; } ToleranceMap[color] = index; @@ -499,7 +512,7 @@ void adaptLevelToPalette(TXshLevelHandle *currentLevelHandle, currentLevelHandle->notifyLevelChange(); } -} // namespaxce +} // namespace //----------------------------------------------------------------------------- @@ -602,7 +615,11 @@ void StudioPaletteCmd::replaceWithCurrentPalette( // put back the global name palette->setGlobalName(oldGlobalName); - sp->setPalette(fp, current, true); + if (!trySetStudioPalette(fp, current, true)) { + palette->assign(old); + return; + } + TUndoManager::manager()->add( new StudioPaletteAssignUndo(fp, old, current->clone(), paletteHandle)); @@ -679,12 +696,16 @@ TFilePath StudioPaletteCmd::createPalette(const TFilePath &folderName, const TPalette *palette) { TFilePath palettePath; TFileStatus status(folderName); + // exception will be caught either in StudioPaletteTreeViewer::addNewPalette() + // or StudioPaletteTreeViewer::dropEvent() if (!status.isDirectory()) throw TException("Select a folder."); if (!status.doesExist()) { TSystem::mkDir(folderName); FolderListenerManager::instance()->notifyFolderChanged( folderName.getParentDir()); } + // StudioPalette::setPalette() and createPalette() may throw exception on + // saving, it will be caught in the upper functions as wel palettePath = StudioPalette::instance()->createPalette(folderName, paletteName); if (palette) diff --git a/toonz/sources/toonzqt/palettesscanpopup.cpp b/toonz/sources/toonzqt/palettesscanpopup.cpp index 0e7ab90..e738dfb 100644 --- a/toonz/sources/toonzqt/palettesscanpopup.cpp +++ b/toonz/sources/toonzqt/palettesscanpopup.cpp @@ -49,14 +49,14 @@ PalettesScanPopup::PalettesScanPopup() //----------------------------------------------------------------------------- /*! Set current folder path to \b path. -*/ + */ void PalettesScanPopup::setCurrentFolder(TFilePath path) { m_folderPath = path; } //----------------------------------------------------------------------------- /*! Return current folder path. -*/ + */ TFilePath PalettesScanPopup::getCurrentFolder() { return m_folderPath; } //----------------------------------------------------------------------------- @@ -84,7 +84,7 @@ void PalettesScanPopup::onOkBtnClicked() { //----------------------------------------------------------------------------- /*! Set label text to path \b fp. -*/ + */ void PalettesScanPopup::setLabel(const TFilePath &fp) { QString elideStr = elideText(toQString(fp), m_label->font(), m_label->width()); @@ -107,7 +107,7 @@ void PalettesScanPopup::timerEvent(QTimerEvent *event) { //----------------------------------------------------------------------------- /*! Push TFilePath \b fp to the top of directories stack. Set label text to fp. -*/ + */ void PalettesScanPopup::push(const TFilePath &fp) { setLabel(fp); Directory *dir = new Directory(); @@ -132,7 +132,7 @@ void PalettesScanPopup::push(const TFilePathSet &fs) { //----------------------------------------------------------------------------- /*! Removes the top item from the stack. If stack is empty return immediately. -*/ + */ void PalettesScanPopup::pop() { if (m_stack.empty()) return; Directory *dir = m_stack.back(); @@ -173,7 +173,7 @@ bool PalettesScanPopup::step() { //----------------------------------------------------------------------------- /*! Resets the content of the directories stack and set label text empty. -*/ + */ void PalettesScanPopup::clearStack() { for (int i = 0; i < (int)m_stack.size(); i++) delete m_stack[i]; m_stack.clear(); @@ -182,10 +182,17 @@ void PalettesScanPopup::clearStack() { //----------------------------------------------------------------------------- /*! Import palette, defined in path \b fp, in current \b StudioPalette folder. -*/ + */ void PalettesScanPopup::onPlt(const TFilePath &fp) { TFilePath root(m_field->getPath().toStdString()); assert(root.isAncestorOf(fp)); TFilePath q = fp.getParentDir() - root; - StudioPalette::instance()->importPalette(m_folderPath + q, fp); + try { + StudioPalette::instance()->importPalette(m_folderPath + q, fp); + } catch (TSystemException &se) { + DVGui::warning(QString::fromStdWString(se.getMessage())); + } catch (...) { + DVGui::warning(QString::fromStdWString(fp.getWideString() + L"\n") + + tr("Failed to import palette.")); + } } diff --git a/toonz/sources/toonzqt/paletteviewer.cpp b/toonz/sources/toonzqt/paletteviewer.cpp index b35d01d..bca0dd7 100644 --- a/toonz/sources/toonzqt/paletteviewer.cpp +++ b/toonz/sources/toonzqt/paletteviewer.cpp @@ -948,7 +948,16 @@ void PaletteViewer::saveStudioPalette() { int ret = DVGui::MsgBox(question, tr("Overwrite"), tr("Don't Overwrite"), 0); if (ret == 2 || ret == 0) return; - sp->setPalette(fp, getPalette(), false); + try { + sp->setPalette(fp, getPalette(), false); + } catch (TSystemException se) { + DVGui::warning(QString::fromStdWString(se.getMessage())); + return; + } catch (...) { + DVGui::warning(QString::fromStdWString(fp.getWideString() + L"\n") + + tr("Failed to save palette.")); + return; + } StudioPaletteCmd::updateAllLinkedStyles(m_paletteHandle, m_xsheetHandle); diff --git a/toonz/sources/toonzqt/studiopaletteviewer.cpp b/toonz/sources/toonzqt/studiopaletteviewer.cpp index 412eb5e..9627d0e 100644 --- a/toonz/sources/toonzqt/studiopaletteviewer.cpp +++ b/toonz/sources/toonzqt/studiopaletteviewer.cpp @@ -497,13 +497,26 @@ void StudioPaletteTreeViewer::onCurrentItemChanged(QTreeWidgetItem *current, return; } if (ret == 1) { - // If the palette is level palette (i.e. NOT stdio palette), just - // overwrite it - if (gname.empty()) - StudioPalette::instance()->save(oldPath, m_currentPalette.getPointer()); - else - StudioPalette::instance()->setPalette( - oldPath, m_currentPalette.getPointer(), false); + try { + // If the palette is level palette (i.e. NOT stdio palette), just + // overwrite it + if (gname.empty()) + StudioPalette::instance()->save(oldPath, + m_currentPalette.getPointer()); + else + StudioPalette::instance()->setPalette( + oldPath, m_currentPalette.getPointer(), false); + } catch (TSystemException se) { + DVGui::warning(QString::fromStdWString(se.getMessage())); + setCurrentItem(previous); + return; + } catch (...) { + DVGui::warning( + QString::fromStdWString(oldPath.getWideString() + L"\n") + + tr("Failed to save palette.")); + setCurrentItem(previous); + return; + } } m_currentPalette->setDirtyFlag(false); }