diff --git a/stuff/profiles/layouts/rooms/Default/menubar_template.xml b/stuff/profiles/layouts/rooms/Default/menubar_template.xml index 1898a36..8218e71 100644 --- a/stuff/profiles/layouts/rooms/Default/menubar_template.xml +++ b/stuff/profiles/layouts/rooms/Default/menubar_template.xml @@ -40,6 +40,8 @@ MI_Preferences MI_ShortcutPopup + MI_ClearCacheFolder + MI_Quit @@ -313,6 +315,6 @@ MI_OpenOnlineManual - MI_About + MI_About diff --git a/stuff/profiles/layouts/rooms/StudioGhibli/room6_menubar.xml b/stuff/profiles/layouts/rooms/StudioGhibli/room6_menubar.xml index 46eab24..ae745ae 100644 --- a/stuff/profiles/layouts/rooms/StudioGhibli/room6_menubar.xml +++ b/stuff/profiles/layouts/rooms/StudioGhibli/room6_menubar.xml @@ -15,6 +15,8 @@ "MI_RunScript" "MI_OpenScriptConsole" "MI_ReloadStyle" + + "MI_ClearCacheFolder" MI_About diff --git a/toonz/sources/common/tapptools/tenv.cpp b/toonz/sources/common/tapptools/tenv.cpp index 9918612..fce9708 100644 --- a/toonz/sources/common/tapptools/tenv.cpp +++ b/toonz/sources/common/tapptools/tenv.cpp @@ -33,10 +33,9 @@ using namespace TVER; namespace { const std::map systemPathMap{ - {"LIBRARY", "library"}, {"STUDIOPALETTE", "studiopalette"}, - {"FXPRESETS", "fxs"}, {"CACHEROOT", "cache"}, - {"PROFILES", "profiles"}, {"CONFIG", "config"}, - {"PROJECTS", "projects"}}; + {"LIBRARY", "library"}, {"STUDIOPALETTE", "studiopalette"}, + {"FXPRESETS", "fxs"}, {"PROFILES", "profiles"}, + {"CONFIG", "config"}, {"PROJECTS", "projects"}}; class EnvGlobals { // singleton @@ -470,7 +469,7 @@ Variable::Variable(std::string name) Variable::Variable(std::string name, std::string defaultValue) : m_imp(VariableSet::instance()->getImp(name)) { // assert(!m_imp->m_defaultDefined); - m_imp->m_defaultDefined = true; + m_imp->m_defaultDefined = true; if (!m_imp->m_loaded) m_imp->m_value = defaultValue; } @@ -567,11 +566,11 @@ TFilePathSet TEnv::getSystemVarPathSetValue(std::string varName) { TFilePathSet lst; EnvGlobals *eg = EnvGlobals::instance(); // if the path is registered by command line argument, then use it - std::string value = eg->getArgPathValue(varName); + std::string value = eg->getArgPathValue(varName); if (value == "") value = eg->getSystemVarValue(varName); - int len = (int)value.size(); - int i = 0; - int j = value.find(';'); + int len = (int)value.size(); + int i = 0; + int j = value.find(';'); while (j != std::string::npos) { std::string s = value.substr(i, j - i); lst.push_back(TFilePath(s)); diff --git a/toonz/sources/tcleanupper/tcleanupper.cpp b/toonz/sources/tcleanupper/tcleanupper.cpp index 852163e..05746b4 100644 --- a/toonz/sources/tcleanupper/tcleanupper.cpp +++ b/toonz/sources/tcleanupper/tcleanupper.cpp @@ -224,7 +224,7 @@ int FarmControllerPort; TFarmController *FarmController = 0; string TaskId; -} +} // namespace //======================================================================== // // searchLevelsToCleanup @@ -491,6 +491,12 @@ int main(int argc, char *argv[]) { // questo definisce la registry root e inizializza TEnv TEnv::setRootVarName(rootVarName); TEnv::setSystemVarPrefix(systemVarPrefix); + + QCoreApplication::setOrganizationName("OpenToonz"); + QCoreApplication::setOrganizationDomain(""); + QCoreApplication::setApplicationName( + QString::fromStdString(TEnv::getApplicationName())); + TSystem::hasMainLoop(false); int i; for (i = 0; i < argc; i++) // tmsg must be set as soon as it's possible @@ -527,7 +533,7 @@ int main(int argc, char *argv[]) { TVectorImagePatternStrokeStyle::setRootDir(libraryFolder); TPalette::setRootDir(libraryFolder); TImageStyle::setLibraryDir(libraryFolder); - TFilePath cacheRoot = ToonzFolder::getCacheRootFolder(); + TFilePath cacheRoot = ToonzFolder::getCacheRootFolder(); if (cacheRoot.isEmpty()) cacheRoot = TEnv::getStuffDir() + "cache"; TImageCache::instance()->setRootDir(cacheRoot); diff --git a/toonz/sources/tcomposer/tcomposer.cpp b/toonz/sources/tcomposer/tcomposer.cpp index 3eea750..e3b1d39 100644 --- a/toonz/sources/tcomposer/tcomposer.cpp +++ b/toonz/sources/tcomposer/tcomposer.cpp @@ -658,6 +658,11 @@ int main(int argc, char *argv[]) { TEnv::setRootVarName(rootVarName); TEnv::setSystemVarPrefix(systemVarPrefix); + QCoreApplication::setOrganizationName("OpenToonz"); + QCoreApplication::setOrganizationDomain(""); + QCoreApplication::setApplicationName( + QString::fromStdString(TEnv::getApplicationName())); + QHash::const_iterator argItr = argumentPathValues.constBegin(); while (argItr != argumentPathValues.constEnd()) { diff --git a/toonz/sources/toonz/main.cpp b/toonz/sources/toonz/main.cpp index 8ae73fc..8c2bbeb 100644 --- a/toonz/sources/toonz/main.cpp +++ b/toonz/sources/toonz/main.cpp @@ -166,7 +166,7 @@ static void initToonzEnv(QHash &argPathValues) { QCoreApplication::setOrganizationName("OpenToonz"); QCoreApplication::setOrganizationDomain(""); QCoreApplication::setApplicationName( - QString::fromStdString(TEnv::getApplicationFullName())); + QString::fromStdString(TEnv::getApplicationName())); /*-- TOONZROOTのPathの確認 --*/ // controllo se la xxxroot e' definita e corrisponde ad un folder esistente @@ -229,7 +229,7 @@ project->setUseScenePath(TProject::Extras, false); // Imposto la rootDir per ImageCache /*-- TOONZCACHEROOTの設定 --*/ - TFilePath cacheDir = ToonzFolder::getCacheRootFolder(); + TFilePath cacheDir = ToonzFolder::getCacheRootFolder(); if (cacheDir.isEmpty()) cacheDir = TEnv::getStuffDir() + "cache"; TImageCache::instance()->setRootDir(cacheDir); } @@ -315,11 +315,10 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); #ifdef MACOSX -// This workaround is to avoid missing left button problem on Qt5.6.0. -// To invalidate m_rightButtonClicked in Qt/qnsview.mm, sending NSLeftButtonDown -// event -// before NSLeftMouseDragged event propagated to QApplication. -// See more details in ../mousedragfilter/mousedragfilter.mm. + // This workaround is to avoid missing left button problem on Qt5.6.0. + // To invalidate m_rightButtonClicked in Qt/qnsview.mm, sending + // NSLeftButtonDown event before NSLeftMouseDragged event propagated to + // QApplication. See more details in ../mousedragfilter/mousedragfilter.mm. #include "mousedragfilter.h" diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index 68f6062..a41612c 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -57,6 +57,7 @@ #include #include #include +#include TEnv::IntVar ViewCameraToggleAction("ViewCameraToggleAction", 1); TEnv::IntVar ViewTableToggleAction("ViewTableToggleAction", 1); @@ -459,6 +460,7 @@ centralWidget->setLayout(centralWidgetLayout);*/ &MainWindow::onNewToonzRasterLevelButtonPressed); setCommandHandler("MI_NewRasterLevel", this, &MainWindow::onNewRasterLevelButtonPressed); + setCommandHandler(MI_ClearCacheFolder, this, &MainWindow::clearCacheFolder); // remove ffmpegCache if still exists from crashed exit QString ffmpegCachePath = ToonzFolder::getCacheRootFolder().getQString() + "//ffmpeg"; @@ -1596,6 +1598,7 @@ void MainWindow::defineActions() { createMenuAction(MI_LoadRecentImage, tr("&Load Recent Image Files"), files); createMenuFileAction(MI_ClearRecentImage, tr("&Clear Recent Flipbook Image List"), ""); + createMenuFileAction(MI_ClearCacheFolder, tr("&Clear Cache Folder"), ""); createRightClickMenuAction(MI_PreviewFx, tr("Preview Fx"), ""); @@ -2337,6 +2340,96 @@ void MainWindow::onNewRasterLevelButtonPressed() { } //----------------------------------------------------------------------------- +// delete unused files / folders in the cache +void MainWindow::clearCacheFolder() { + // currently cache folder is used for following purposes + // 1. $CACHE/[ProcessID] : for disk swap of image cache. + // To be deleted on exit. Remains on crash. + // 2. $CACHE/ffmpeg : ffmpeg cache. + // To be cleared on the end of rendering, on exist and on launch. + // 3. $CACHE/temp : untitled scene data. + // To be deleted on switching or exiting scenes. Remains on crash. + + // So, this function will delete all files / folders in $CACHE + // except the following items: + // 1. $CACHE/[Current ProcessID] + // 2. $CACHE/temp/[Current scene folder] if the current scene is untitled + + TFilePath cacheRoot = ToonzFolder::getCacheRootFolder(); + if (cacheRoot.isEmpty()) cacheRoot = TEnv::getStuffDir() + "cache"; + + TFilePathSet filesToBeRemoved; + + TSystem::readDirectory(filesToBeRemoved, cacheRoot, false); + + // keep the imagecache folder + filesToBeRemoved.remove(cacheRoot + std::to_string(TSystem::getProcessId())); + // keep the untitled scene data folder + if (TApp::instance()->getCurrentScene()->getScene()->isUntitled()) { + filesToBeRemoved.remove(cacheRoot + "temp"); + TFilePathSet untitledData = + TSystem::readDirectory(cacheRoot + "temp", false); + untitledData.remove(TApp::instance() + ->getCurrentScene() + ->getScene() + ->getScenePath() + .getParentDir()); + filesToBeRemoved.insert(filesToBeRemoved.end(), untitledData.begin(), + untitledData.end()); + } + + // return if there is no files/folders to be deleted + if (filesToBeRemoved.size() == 0) { + QMessageBox::information( + this, tr("Clear Cache Folder"), + tr("There are no unused items in the cache folder.")); + return; + } + + QString message(tr("Deleting the following items:\n")); + int count = 0; + for (const auto &fileToBeRemoved : filesToBeRemoved) { + QString dirPrefix = + (TFileStatus(fileToBeRemoved).isDirectory()) ? tr(" ") : ""; + message += + " " + dirPrefix + (fileToBeRemoved - cacheRoot).getQString() + "\n"; + count++; + if (count == 5) break; + } + if (filesToBeRemoved.size() > 5) + message += + tr(" ... and %1 more items\n").arg(filesToBeRemoved.size() - 5); + + message += + tr("\nAre you sure?\n\nN.B. Make sure you are not running another " + "process of OpenToonz,\nor you may delete necessary files for it."); + + QMessageBox::StandardButton ret = QMessageBox::question( + this, tr("Clear Cache Folder"), message, + QMessageBox::StandardButtons(QMessageBox::Ok | QMessageBox::Cancel)); + + if (ret != QMessageBox::Ok) return; + + for (const auto &fileToBeRemoved : filesToBeRemoved) { + try { + if (TFileStatus(fileToBeRemoved).isDirectory()) + TSystem::rmDirTree(fileToBeRemoved); + else + TSystem::deleteFile(fileToBeRemoved); + } catch (TException &e) { + QMessageBox::warning( + this, tr("Clear Cache Folder"), + tr("Can't delete %1 : ").arg(fileToBeRemoved.getQString()) + + QString::fromStdWString(e.getMessage())); + } catch (...) { + QMessageBox::warning( + this, tr("Clear Cache Folder"), + tr("Can't delete %1 : ").arg(fileToBeRemoved.getQString())); + } + } +} + +//----------------------------------------------------------------------------- class ReloadStyle final : public MenuItemHandler { public: diff --git a/toonz/sources/toonz/mainwindow.h b/toonz/sources/toonz/mainwindow.h index 1e7379c..6bdbb26 100644 --- a/toonz/sources/toonz/mainwindow.h +++ b/toonz/sources/toonz/mainwindow.h @@ -112,6 +112,7 @@ public: void onNewVectorLevelButtonPressed(); void onNewToonzRasterLevelButtonPressed(); void onNewRasterLevelButtonPressed(); + void clearCacheFolder(); QString getLayoutName() { return m_layoutName; } diff --git a/toonz/sources/toonz/menubar.cpp b/toonz/sources/toonz/menubar.cpp index cc8d616..f7dc057 100644 --- a/toonz/sources/toonz/menubar.cpp +++ b/toonz/sources/toonz/menubar.cpp @@ -117,7 +117,7 @@ void RoomTabWidget::mouseReleaseEvent(QMouseEvent *event) { //----------------------------------------------------------------------------- /*! Set a text field with focus in event position to edit tab name. -*/ + */ void RoomTabWidget::mouseDoubleClickEvent(QMouseEvent *event) { if (m_isLocked) return; int index = tabAt(event->pos()); @@ -1117,6 +1117,8 @@ QMenuBar *StackedMenuBar::createFullMenuBar() { addMenuItem(fileMenu, MI_Preferences); addMenuItem(fileMenu, MI_ShortcutPopup); fileMenu->addSeparator(); + addMenuItem(fileMenu, MI_ClearCacheFolder); + fileMenu->addSeparator(); addMenuItem(fileMenu, MI_Quit); // Menu' EDIT diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h index 3f7dba7..4882888 100644 --- a/toonz/sources/toonz/menubarcommandids.h +++ b/toonz/sources/toonz/menubarcommandids.h @@ -346,5 +346,5 @@ #define MI_SeparateColors "MI_SeparateColors" #define MI_OpenOnlineManual "MI_OpenOnlineManual" - +#define MI_ClearCacheFolder "MI_ClearCacheFolder" #endif diff --git a/toonz/sources/toonzlib/toonzfolders.cpp b/toonz/sources/toonzlib/toonzfolders.cpp index a9bc0cf..223e527 100644 --- a/toonz/sources/toonzlib/toonzfolders.cpp +++ b/toonz/sources/toonzlib/toonzfolders.cpp @@ -6,6 +6,7 @@ #include "tconvert.h" #include "toonz/preferences.h" #include +#include using namespace TEnv; @@ -23,7 +24,7 @@ TFilePath getDesktopPath() { QStandardPaths::standardLocations(QStandardPaths::DesktopLocation)[0]; return TFilePath(desktopPath); } -} +} // namespace //------------------------------------------------------------------- TFilePath ToonzFolder::getModulesDir() { @@ -107,10 +108,16 @@ TFilePath ToonzFolder::getFxPresetFolder() { } TFilePath ToonzFolder::getCacheRootFolder() { - TFilePath fp = getSystemVarPathValue(getSystemVarPrefix() + "CACHEROOT"); - if (fp == TFilePath()) - fp = getStuffDir() + TEnv::getSystemPathMap().at("CACHEROOT"); - return fp; + static enum STATE { FIRSTTIME, OK, NG } state = FIRSTTIME; + QString cacheDir = + QStandardPaths::writableLocation(QStandardPaths::CacheLocation); + if (state == FIRSTTIME) { + if (QDir(cacheDir).mkpath(".")) + state = OK; + else + state = NG; + } + return (state == OK) ? TFilePath(cacheDir) : TFilePath(); } TFilePath ToonzFolder::getProfileFolder() {