clean assets feature

This commit is contained in:
shun-iwasawa 2021-02-18 17:24:29 +09:00 committed by manongjohn
parent 53900472aa
commit f41dfc8dba
10 changed files with 200 additions and 60 deletions

View file

@ -269,6 +269,9 @@ public:
int matchLevelFormat(const TFilePath &fp)
const; //!< Returns the \a nonnegative index of the first level format
//! matching the specified file path, <I>or \p -1 if none</I>.
bool isAutoRemoveUnusedLevelsEnabled() const {
return isAutoExposeEnabled() && getBoolValue(autoRemoveUnusedLevels);
}
// Saving tab
TPixel getRasterBackgroundColor() const {

View file

@ -62,6 +62,7 @@ enum PreferencesItemId {
initialLoadTlvCachingBehavior,
columnIconLoadingPolicy,
levelFormats, // need to be handle separately
autoRemoveUnusedLevels,
//----------
// Saving

View file

@ -286,6 +286,7 @@ private:
ToonzScene(const ToonzScene &);
ToonzScene &operator=(const ToonzScene &);
public:
// if the option is set in the preferences,
// remove the scene numbers("c####_") from the file name
std::wstring getLevelNameWithoutSceneNumber(std::wstring orgName);

View file

@ -21,6 +21,7 @@
#include "cachefxcommand.h"
#include "xdtsio.h"
#include "expressionreferencemanager.h"
#include "levelcommand.h"
// TnzTools includes
#include "tools/toolhandle.h"
@ -356,6 +357,37 @@ int getLevelType(const TFilePath &actualPath) {
return UNKNOWN_XSHLEVEL;
}
//===========================================================================
// removeSameNamedUnusedLevel(scene, actualPath, levelName);
//---------------------------------------------------------------------------
void removeSameNamedUnusedLevel(ToonzScene *scene, const TFilePath actualPath,
std::wstring levelName) {
if (QString::fromStdWString(levelName).isEmpty()) {
// if the option is set in the preferences,
// remove the scene numbers("c####_") from the file name
levelName = scene->getLevelNameWithoutSceneNumber(actualPath.getWideName());
}
TLevelSet *levelSet = scene->getLevelSet();
NameModifier nm(levelName);
levelName = nm.getNext();
while (1) {
TXshLevel *existingLevel = levelSet->getLevel(levelName);
// if the level name is not used in the cast, nothing to do
if (!existingLevel) return;
// try if the existing level is unused in the xsheet and remove from the
// cast
else if (LevelCmd::removeLevelFromCast(existingLevel, scene, false)) {
DVGui::info(QObject::tr("Removed unused level %1 from the scene cast. "
"(This behavior can be disabled in Preferences.)")
.arg(QString::fromStdWString(levelName)));
return;
}
levelName = nm.getNext();
}
}
//===========================================================================
// class LoadLevelUndo
//---------------------------------------------------------------------------
@ -876,6 +908,11 @@ TXshLevel *loadLevel(ToonzScene *scene,
bool isFirstTime = !xl;
std::wstring name = actualPath.getWideName();
if (isFirstTime && expose &&
Preferences::instance()->isAutoRemoveUnusedLevelsEnabled()) {
removeSameNamedUnusedLevel(scene, actualPath, levelName);
}
IoCmd::ConvertingPopup *convertingPopup = new IoCmd::ConvertingPopup(
TApp::instance()->getMainWindow(),
QString::fromStdWString(name) +
@ -1404,6 +1441,15 @@ bool IoCmd::saveScene(const TFilePath &path, int flags) {
TXsheet *xsheet = 0;
if (saveSubxsheet) xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
// Automatically remove unused levels
if (!saveSubxsheet &&
Preferences::instance()->isAutoRemoveUnusedLevelsEnabled()) {
if (LevelCmd::removeUnusedLevelsFromCast(false))
DVGui::info(
QObject::tr("Removed unused levels from the scene cast. (This "
"behavior can be disabled in Preferences.)"));
}
// 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,

View file

@ -63,6 +63,61 @@ public:
} // namespace
//-----------------------------------------------------------------------------
bool LevelCmd::removeUnusedLevelsFromCast(bool showMessage) {
TApp *app = TApp::instance();
ToonzScene *scene = app->getCurrentScene()->getScene();
TLevelSet *levelSet = scene->getLevelSet();
std::set<TXshLevel *> usedLevels;
scene->getTopXsheet()->getUsedLevels(usedLevels);
std::vector<TXshLevel *> unused;
for (int i = 0; i < levelSet->getLevelCount(); i++) {
TXshLevel *xl = levelSet->getLevel(i);
if (usedLevels.count(xl) == 0) unused.push_back(xl);
}
if (unused.empty()) {
if (showMessage) DVGui::error(QObject::tr("No unused levels"));
return false;
} else {
TUndoManager *um = TUndoManager::manager();
um->beginBlock();
for (int i = 0; i < (int)unused.size(); i++) {
TXshLevel *xl = unused[i];
um->add(new DeleteLevelUndo(xl));
scene->getLevelSet()->removeLevel(xl);
}
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
TApp::instance()->getCurrentScene()->notifyCastChange();
um->endBlock();
}
return true;
}
bool LevelCmd::removeLevelFromCast(TXshLevel *level, ToonzScene *scene,
bool showMessage) {
if (!scene) scene = TApp::instance()->getCurrentScene()->getScene();
if (scene->getChildStack()->getTopXsheet()->isLevelUsed(level)) {
if (showMessage) {
DVGui::error(
QObject::tr("It is not possible to delete the used level %1.")
.arg(QString::fromStdWString(
level->getName()))); //"E_CantDeleteUsedLevel_%1"
}
return false;
} else {
TUndoManager *um = TUndoManager::manager();
um->add(new DeleteLevelUndo(level));
scene->getLevelSet()->removeLevel(level);
}
return true;
}
//=============================================================================
// RemoveUnusedLevelCommand
//-----------------------------------------------------------------------------
@ -71,38 +126,7 @@ class RemoveUnusedLevelsCommand final : public MenuItemHandler {
public:
RemoveUnusedLevelsCommand() : MenuItemHandler(MI_RemoveUnused) {}
void execute() override {
TApp *app = TApp::instance();
ToonzScene *scene = app->getCurrentScene()->getScene();
TLevelSet *levelSet = scene->getLevelSet();
std::set<TXshLevel *> usedLevels;
scene->getTopXsheet()->getUsedLevels(usedLevels);
std::vector<TXshLevel *> unused;
for (int i = 0; i < levelSet->getLevelCount(); i++) {
TXshLevel *xl = levelSet->getLevel(i);
if (usedLevels.count(xl) == 0) unused.push_back(xl);
}
if (unused.empty()) {
DVGui::error(QObject::tr("No unused levels"));
return;
} else {
TUndoManager *um = TUndoManager::manager();
um->beginBlock();
for (int i = 0; i < (int)unused.size(); i++) {
TXshLevel *xl = unused[i];
um->add(new DeleteLevelUndo(xl));
scene->getLevelSet()->removeLevel(xl);
}
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
TApp::instance()->getCurrentScene()->notifyCastChange();
um->endBlock();
}
}
void execute() override { LevelCmd::removeUnusedLevelsFromCast(); }
} removeUnusedLevelsCommand;
//=============================================================================
@ -113,22 +137,6 @@ class RemoveLevelCommand final : public MenuItemHandler {
public:
RemoveLevelCommand() : MenuItemHandler(MI_RemoveLevel) {}
bool removeLevel(TXshLevel *level) {
TApp *app = TApp::instance();
ToonzScene *scene = app->getCurrentScene()->getScene();
if (scene->getChildStack()->getTopXsheet()->isLevelUsed(level))
DVGui::error(
QObject::tr("It is not possible to delete the used level %1.")
.arg(QString::fromStdWString(
level->getName()))); //"E_CantDeleteUsedLevel_%1"
else {
TUndoManager *um = TUndoManager::manager();
um->add(new DeleteLevelUndo(level));
scene->getLevelSet()->removeLevel(level);
}
return true;
}
void execute() override {
TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
CastSelection *castSelection =
@ -143,7 +151,7 @@ public:
}
int count = 0;
for (int i = 0; i < (int)levels.size(); i++)
if (removeLevel(levels[i])) count++;
if (LevelCmd::removeLevelFromCast(levels[i])) count++;
if (count == 0) return;
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
TApp::instance()->getCurrentScene()->notifyCastChange();
@ -523,7 +531,24 @@ void LevelCmd::addMissingLevelsToCast(std::set<TXshLevel *> &levels) {
std::wstring oldName = levelName;
NameModifier nm(levelName);
levelName = nm.getNext();
while (levelSet->hasLevel(levelName)) levelName = nm.getNext();
while (1) {
TXshLevel *existingLevel = levelSet->getLevel(levelName);
// if the level name is not used in the cast, nothing to do
if (!existingLevel) break;
// try if the existing level is unused in the xsheet and remove from the
// cast
else if (Preferences::instance()->isAutoRemoveUnusedLevelsEnabled() &&
LevelCmd::removeLevelFromCast(
existingLevel,
TApp::instance()->getCurrentScene()->getScene(), false)) {
DVGui::info(
QObject::tr("Removed unused level %1 from the scene cast. (This "
"behavior can be disabled in Preferences.)")
.arg(QString::fromStdWString(levelName)));
break;
}
levelName = nm.getNext();
}
addLevelToCastUndo *undo =
new addLevelToCastUndo(level, levelName, oldName);
undo->m_isLastInRedoBlock = false; // prevent to emit signal

View file

@ -9,10 +9,23 @@
#include <QList>
class TXshLevel;
class ToonzScene;
namespace LevelCmd {
void addMissingLevelsToCast(const QList<TXshColumnP>& columns);
void addMissingLevelsToCast(std::set<TXshLevel*>& levels);
// Remove all unused level from the scene cast.
// When there is no unused level, show an error message if showmessage==true.
// Return true if something is removed.
bool removeUnusedLevelsFromCast(bool showMessage = true);
// Remove the level from the scene cast if it is not used in the xsheet.
// Return true if the level is unused and removed.
// When the level is used, an show error message if showMessage==true and
// returns false.
bool removeLevelFromCast(TXshLevel* level, ToonzScene* scene = nullptr,
bool showMessage = true);
} // namespace LevelCmd
#endif
#endif

View file

@ -5,6 +5,7 @@
// Tnz6 includes
#include "menubarcommandids.h"
#include "tapp.h"
#include "levelcommand.h"
// TnzTools includes
#include "tools/toolhandle.h"
@ -34,6 +35,7 @@
#include "toonz/palettecontroller.h"
#include "toonz/tproject.h"
#include "toonz/namebuilder.h"
#include "toonz/childstack.h"
// TnzCore includes
#include "tsystem.h"
@ -327,9 +329,16 @@ bool LevelCreatePopup::levelExists(std::wstring levelName) {
.withParentDir(parentDir);
actualFp = scene->decodeFilePath(fp);
if (levelSet->getLevel(levelName) != 0 ||
TSystem::doesExistFileOrLevel(actualFp)) {
if (TSystem::doesExistFileOrLevel(actualFp))
return true;
else if (TXshLevel *level = levelSet->getLevel(levelName)) {
// even if the level exists in the scene cast, it can be replaced if it is
// unused
if (Preferences::instance()->isAutoRemoveUnusedLevelsEnabled() &&
!scene->getChildStack()->getTopXsheet()->isLevelUsed(level))
return false;
else
return true;
} else
return false;
}
@ -469,12 +478,18 @@ bool LevelCreatePopup::apply() {
int numFrames = step * (((to - from) / inc) + 1);
if (scene->getLevelSet()->getLevel(levelName)) {
error(
tr("The level name specified is already used: please choose a "
"different level name"));
m_nameFld->selectAll();
return false;
TXshLevel *existingLevel = scene->getLevelSet()->getLevel(levelName);
if (existingLevel) {
// check if the existing level can be removed
if (!Preferences::instance()->isAutoRemoveUnusedLevelsEnabled() ||
scene->getChildStack()->getTopXsheet()->isLevelUsed(existingLevel)) {
error(
tr("The level name specified is already used: please choose a "
"different level name"));
m_nameFld->selectAll();
return false;
}
// if the exitingLevel is not null, it will be removed afterwards
}
TFilePath parentDir(m_pathFld->getPath().toStdWString());
@ -525,6 +540,18 @@ bool LevelCreatePopup::apply() {
}
}
TUndoManager::manager()->beginBlock();
// existingLevel is not nullptr only if the level is unused AND
// the preference option AutoRemoveUnusedLevels is ON
if (existingLevel) {
bool ok = LevelCmd::removeLevelFromCast(existingLevel, scene, false);
assert(ok);
DVGui::info(QObject::tr("Removed unused level %1 from the scene cast. "
"(This behavior can be disabled in Preferences.)")
.arg(QString::fromStdWString(levelName)));
}
/*-- これからLevelを配置しようとしているセルが空いているかどうかのチェック
* --*/
bool areColumnsShifted = false;
@ -560,6 +587,7 @@ bool LevelCreatePopup::apply() {
TXshLevel *level =
scene->createNewLevel(lType, levelName, TDimension(), 0, fp);
TXshSimpleLevel *sl = dynamic_cast<TXshSimpleLevel *>(level);
assert(sl);
// sl->setPath(fp, true);
if (lType == TZP_XSHLEVEL || lType == OVL_XSHLEVEL) {
@ -603,6 +631,8 @@ bool LevelCreatePopup::apply() {
undo->onAdd(sl);
TUndoManager::manager()->endBlock();
app->getCurrentScene()->notifySceneChanged();
app->getCurrentScene()->notifyCastChange();
app->getCurrentXsheet()->notifyXsheetChanged();

View file

@ -10,6 +10,7 @@
#include "castselection.h"
#include "fileselection.h"
#include "columnselection.h"
#include "levelcommand.h"
// TnzQt includes
#include "toonzqt/menubarcommand.h"
@ -964,6 +965,18 @@ void LevelSettingsPopup::onNameChanged() {
TLevelSet *levelSet =
TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
TUndoManager::manager()->beginBlock();
// remove existing & unused level
if (Preferences::instance()->isAutoRemoveUnusedLevelsEnabled()) {
TXshLevel *existingLevel = levelSet->getLevel(text.toStdWString());
if (existingLevel &&
LevelCmd::removeLevelFromCast(existingLevel, nullptr, false))
DVGui::info(QObject::tr("Removed unused level %1 from the scene cast. "
"(This behavior can be disabled in Preferences.)")
.arg(text));
}
if (!levelSet->renameLevel(level, text.toStdWString())) {
error("The name " + text +
" you entered for the level is already used.\nPlease enter a "
@ -975,6 +988,8 @@ void LevelSettingsPopup::onNameChanged() {
TUndoManager::manager()->add(
new LevelSettingsUndo(level, LevelSettingsUndo::Name, oldName, text));
TUndoManager::manager()->endBlock();
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
TApp::instance()->getCurrentScene()->notifyCastChange();
}

View file

@ -1027,6 +1027,8 @@ QString PreferencesPopup::getUIString(PreferencesItemId id) {
// Loading
{importPolicy, tr("Default File Import Behavior:")},
{autoExposeEnabled, tr("Expose Loaded Levels in the Scene")},
{autoRemoveUnusedLevels,
tr("Automatically Remove Unused Levels From Scene Cast")},
{subsceneFolderEnabled, tr("Create Sub-folder when Importing Sub-Scene")},
{removeSceneNumberFromLoadedLevelName,
tr("Automatically Remove Scene Number from Loaded Level Name")},
@ -1535,7 +1537,8 @@ QWidget* PreferencesPopup::createLoadingPage() {
setupLayout(lay);
insertUI(importPolicy, lay, getComboItemList(importPolicy));
insertUI(autoExposeEnabled, lay);
QGridLayout* autoExposeLay = insertGroupBoxUI(autoExposeEnabled, lay);
{ insertUI(autoRemoveUnusedLevels, autoExposeLay); }
insertUI(subsceneFolderEnabled, lay);
insertUI(removeSceneNumberFromLoadedLevelName, lay);
// insertUI(IgnoreImageDpi, lay);

View file

@ -456,6 +456,9 @@ void Preferences::definePreferenceItems() {
QMetaType::Int, 0); // On Demand
define(columnIconLoadingPolicy, "columnIconLoadingPolicy", QMetaType::Int,
(int)LoadAtOnce);
define(autoRemoveUnusedLevels, "autoRemoveUnusedLevels", QMetaType::Bool,
false);
//"levelFormats" need to be handle separately
// Saving