1 #include <memory>
2
3 #include "iocommand.h"
4
5 // Toonz includes
6 #include "menubarcommandids.h"
7 #include "filebrowserpopup.h"
8 #include "tapp.h"
9 #include "history.h"
10 #include "fileselection.h"
11 #include "previewer.h"
12 #include "previewfxmanager.h"
13 #include "tcontenthistory.h"
14 #include "filebrowsermodel.h"
15 #include "mainwindow.h"
16 #include "overwritepopup.h"
17 #include "cleanupsettingspopup.h"
18 #include "psdsettingspopup.h"
19 #include "filebrowser.h"
20 #include "versioncontrol.h"
21 #include "cachefxcommand.h"
22 #include "xdtsio.h"
23 #include "expressionreferencemanager.h"
24
25 // TnzTools includes
26 #include "tools/toolhandle.h"
27
28 // ToonzQt includes
29 #include "toonzqt/gutil.h"
30 #include "toonzqt/icongenerator.h"
31 #include "toonzqt/swatchviewer.h"
32 #include "toonzqt/tselectionhandle.h"
33 #include "toonzqt/dvdialog.h"
34
35 // ToonzLib includes
36 #include "toonz/palettecontroller.h"
37 #include "toonz/tscenehandle.h"
38 #include "toonz/tobjecthandle.h"
39 #include "toonz/tcolumnhandle.h"
40 #include "toonz/tframehandle.h"
41 #include "toonz/txsheethandle.h"
42 #include "toonz/txshlevelhandle.h"
43 #include "toonz/tpalettehandle.h"
44 #include "toonz/toonzscene.h"
45 #include "toonz/tproject.h"
46 #include "toonz/txshsimplelevel.h"
47 #include "toonz/txshchildlevel.h"
48 #include "toonz/sceneproperties.h"
49 #include "toonz/levelproperties.h"
50 #include "toonz/stage2.h"
51 #include "toonz/imagemanager.h"
52 #include "toonz/sceneresources.h"
53 #include "toonz/txshsoundlevel.h"
54 #include "toonz/txshpalettecolumn.h"
55 #include "toonz/txshpalettelevel.h"
56 #include "toonz/txshleveltypes.h"
57 #include "toonz/txshsoundtextcolumn.h"
58 #include "toonz/tstageobjecttree.h"
59 #include "toonz/levelset.h"
60 #include "toonz/namebuilder.h"
61 #include "toonz/fullcolorpalette.h"
62 #include "toonz/palettecmd.h"
63 #include "toonz/toonzimageutils.h"
64 #include "toonz/imagestyles.h"
65 #include "toutputproperties.h"
66 #include "toonz/studiopalette.h"
67
68 // TnzCore includes
69 #include "tofflinegl.h"
70 #include "tvectorimage.h"
71 #include "tvectorrenderdata.h"
72 #include "tropcm.h"
73 #include "tfiletype.h"
74 #include "tunit.h"
75 #include "tproperty.h"
76 #include "tlevel.h"
77 #include "tlevel_io.h"
78
79 // Qt includes
80 #include <QLabel>
81 #include <QApplication>
82 #include <QClipboard>
83
84 // boost includes
85 #include <boost/optional.hpp>
86 #include <boost/utility/in_place_factory.hpp>
87
88 //#define USE_SQLITE_HDPOOL
89
90 using namespace DVGui;
91
92 //-----------------------------------------------------------------------------
93 namespace {
94 //-----------------------------------------------------------------------------
95
96 TXshLevel *getLevelByPath(ToonzScene *scene, const TFilePath &actualPath);
97
98 // forward declaration
99 class RenderingSuspender;
100
101 //===========================================================================
102 // class ResourceImportDialog
103 //---------------------------------------------------------------------------
104
105 class ResourceImportDialog final : public ResourceImportStrategy {
106 OverwriteDialog *m_dialog;
107 bool m_isLastResource;
108 bool m_importQuestionAsked;
109 bool m_aborted;
110 TFilePath m_dstFolder;
111 bool m_importEnabled;
112 std::map<TFilePath, TFilePath> m_importedFiles;
113
114 public:
115 enum Resolution { A_IMPORT, A_LOAD, A_CANCEL };
116
117 public:
ResourceImportDialog()118 ResourceImportDialog()
119 : ResourceImportStrategy(ResourceImportStrategy::IMPORT_AND_RENAME)
120 , m_dialog(0)
121 , m_isLastResource(false)
122 , m_importQuestionAsked(false)
123 , m_aborted(false)
124 , m_importEnabled(false) {
125 m_dialog = new OverwriteDialog;
126 }
127
~ResourceImportDialog()128 ~ResourceImportDialog() {
129 if (m_dialog) m_dialog->deleteLater();
130 }
131
isImportEnabled() const132 bool isImportEnabled() const { return m_importEnabled; }
setImportEnabled(bool enabled)133 void setImportEnabled(bool enabled) {
134 m_importQuestionAsked = true, m_importEnabled = enabled;
135 }
136
setDstFolder(const TFilePath & dstFolder)137 void setDstFolder(const TFilePath &dstFolder) { m_dstFolder = dstFolder; }
getDstFolder() const138 TFilePath getDstFolder() const { return m_dstFolder; }
139
askImportQuestion(const TFilePath & path)140 int askImportQuestion(const TFilePath &path) {
141 if (m_importQuestionAsked)
142 return isImportEnabled() ? A_IMPORT : A_LOAD;
143 else {
144 m_importQuestionAsked = true;
145
146 QString label =
147 QObject::tr(
148 "File %1 doesn't belong to the current project.\n"
149 "Do you want to import it or load it from its original location?")
150 .arg(QString::fromStdWString(path.getWideString()));
151 QString checkBoxLabel =
152 QObject::tr("Always do this action.")
153 .arg(QString::fromStdWString(path.getWideString()));
154 QStringList buttons;
155 buttons << QObject::tr("Import") << QObject::tr("Load")
156 << QObject::tr("Cancel");
157 DVGui::MessageAndCheckboxDialog *importDialog =
158 DVGui::createMsgandCheckbox(DVGui::QUESTION, label, checkBoxLabel,
159 buttons, 0, Qt::Unchecked);
160 int ret = importDialog->exec();
161 int checked = importDialog->getChecked();
162 importDialog->deleteLater();
163
164 if (ret == 0 || ret == 3) {
165 m_aborted = true;
166 return A_CANCEL;
167 }
168 if (ret == 1 && checked > 0) {
169 Preferences::instance()->setValue(importPolicy, 1);
170 TApp::instance()->getCurrentScene()->notifyImportPolicyChanged(1);
171 } else if (ret == 2 && checked > 0) {
172 Preferences::instance()->setValue(importPolicy, 2);
173 TApp::instance()->getCurrentScene()->notifyImportPolicyChanged(2);
174 }
175 m_importEnabled = (ret == 1);
176 return ret == 1 ? A_IMPORT : A_LOAD;
177 }
178 }
179
setIsLastResource(bool isLastResource)180 void setIsLastResource(bool isLastResource) {
181 m_isLastResource = isLastResource;
182 }
183
aborted() const184 bool aborted() const { return m_aborted || m_dialog->cancelPressed(); }
185
186 //
187 // process the file 'srcPath' (possibly copying it)
188 // scrPath can be a coded path (related to srcScene); srcScene can be 0
189 // the method returns the processed codedPath (related to scene)
190 //
process(ToonzScene * scene,ToonzScene * srcScene,TFilePath srcPath)191 TFilePath process(ToonzScene *scene, ToonzScene *srcScene,
192 TFilePath srcPath) override {
193 TFilePath actualSrcPath = srcPath;
194 if (srcScene) actualSrcPath = srcScene->decodeFilePath(srcPath);
195
196 if (!isImportEnabled()) {
197 TFilePath path = scene->codeFilePath(actualSrcPath);
198 return path;
199 }
200 if ((!scene->isExternPath(actualSrcPath) && m_dstFolder.isEmpty()) ||
201 m_dialog->cancelPressed())
202 return srcPath;
203
204 // find the proper dstPath (coded)
205 TFilePath dstPath;
206 if (srcPath.getWideString().find(L'+') == 0) {
207 dstPath = srcPath;
208 // override the folder
209 if (m_dstFolder != TFilePath()) {
210 // +drawings/oldfolder/level.pli =>
211 // +drawings/xsheetfolder/oldfolder/level.pli
212 std::wstring head;
213 TFilePath tail;
214 dstPath.split(head, tail);
215 dstPath = TFilePath(head) + m_dstFolder + tail;
216 }
217 } else {
218 dstPath = scene->getImportedLevelPath(srcPath);
219 // override the folder
220 if (m_dstFolder != TFilePath())
221 dstPath = dstPath.withParentDir(dstPath.getParentDir() + m_dstFolder);
222 }
223
224 // actual path
225 TFilePath actualDstPath = scene->decodeFilePath(dstPath);
226 assert(actualDstPath != TFilePath());
227
228 std::map<TFilePath, TFilePath>::iterator it =
229 m_importedFiles.find(actualDstPath);
230 if (it != m_importedFiles.end()) return it->second;
231 m_importedFiles[actualDstPath] = dstPath;
232
233 // possibly, a level already exists
234 bool overwritten = false;
235 if (TSystem::doesExistFileOrLevel(actualDstPath)) {
236 std::wstring newName =
237 m_dialog->execute(scene, dstPath, m_isLastResource == false);
238 if (m_dialog->cancelPressed()) return srcPath;
239 int importMode = m_dialog->getChoice();
240 if (importMode == OverwriteDialog::KEEP_OLD)
241 return dstPath;
242 else if (importMode == OverwriteDialog::OVERWRITE)
243 overwritten = true;
244 else {
245 dstPath = dstPath.withName(newName);
246 m_importedFiles[actualDstPath] = dstPath;
247 actualDstPath = actualDstPath.withName(newName);
248 }
249 }
250
251 // copy resources
252 try {
253 if (TSystem::doesExistFileOrLevel(actualDstPath))
254 TSystem::removeFileOrLevel(actualDstPath);
255 if (TSystem::doesExistFileOrLevel(actualSrcPath))
256 TXshSimpleLevel::copyFiles(actualDstPath, actualSrcPath);
257 } catch (TException &e) {
258 DVGui::Dialog *errorDialog = DVGui::createMsgBox(
259 DVGui::WARNING,
260 "Can't copy resources: " + QString::fromStdWString(e.getMessage()),
261 QStringList("OK"), 0);
262
263 errorDialog->exec();
264 errorDialog->deleteLater();
265 }
266 // notify
267 FileBrowser::refreshFolder(actualDstPath.getParentDir());
268 IconGenerator::instance()->invalidate(actualDstPath);
269
270 // refresh icons and level path
271 if (overwritten) {
272 TXshLevel *xl = getLevelByPath(scene, actualDstPath);
273 TXshSimpleLevel *sl = 0;
274 if (xl && 0 != (sl = xl->getSimpleLevel())) {
275 std::vector<TFrameId> fids;
276 sl->getFids(fids);
277 sl->setPath(sl->getPath(), false);
278 for (int i = 0; i < (int)fids.size(); i++)
279 IconGenerator::instance()->invalidate(sl, fids[i]);
280 }
281 }
282 return dstPath;
283 }
284 };
285
286 //===========================================================================
287 // getLevelByPath(scene, actualPath)
288 //---------------------------------------------------------------------------
289
getLevelByPath(ToonzScene * scene,const TFilePath & actualPath)290 TXshLevel *getLevelByPath(ToonzScene *scene, const TFilePath &actualPath) {
291 TLevelSet *levelSet = scene->getLevelSet();
292 for (int i = 0; i < levelSet->getLevelCount(); i++) {
293 TXshLevel *xl = levelSet->getLevel(i);
294 if (!xl) continue;
295 TFilePath fp = scene->decodeFilePath(xl->getPath());
296 if (fp == actualPath) return xl;
297 }
298 return 0;
299 }
300
301 //===========================================================================
302 // getSimpleLevelByPath(scene, actualPath)
303 //---------------------------------------------------------------------------
304
getSimpleLevelByPath(ToonzScene * scene,const TFilePath & actualPath)305 TXshSimpleLevel *getSimpleLevelByPath(ToonzScene *scene,
306 const TFilePath &actualPath) {
307 TXshLevel *xl = getLevelByPath(scene, actualPath);
308 if (!xl) return 0;
309 TXshSimpleLevel *sl = xl->getSimpleLevel();
310 return sl;
311 }
312
313 //===========================================================================
314 // beforeCellsInsert(xsh, row, col, rowCount)
315 //---------------------------------------------------------------------------
316
beforeCellsInsert(TXsheet * xsh,int row,int & col,int rowCount,int newLevelColumnType)317 bool beforeCellsInsert(TXsheet *xsh, int row, int &col, int rowCount,
318 int newLevelColumnType) {
319 bool shiftColumn = false;
320 int i = 0;
321 TXshColumn *column = xsh->getColumn(col);
322
323 for (i = 0; i < rowCount && xsh->getCell(row + i, col).isEmpty(); i++) {
324 }
325 int type = column ? column->getColumnType() : newLevelColumnType;
326 // If some used cells in range or column type mismatch must insert a column.
327 if (col < 0 || i < rowCount || newLevelColumnType != type) {
328 col += 1;
329 TApp::instance()->getCurrentColumn()->setColumnIndex(col);
330 shiftColumn = true;
331 xsh->insertColumn(col);
332 } else {
333 // don't overlap
334 xsh->removeCells(row, col, rowCount);
335 }
336 return shiftColumn;
337 }
338
339 //===========================================================================
340 // getLevelType(actualLevelPath)
341 //---------------------------------------------------------------------------
342
getLevelType(const TFilePath & actualPath)343 int getLevelType(const TFilePath &actualPath) {
344 TFileType::Type type = TFileType::getInfo(actualPath);
345 if (type == TFileType::RASTER_IMAGE || type == TFileType::RASTER_LEVEL ||
346 type == TFileType::CMAPPED_LEVEL) {
347 std::string ext = actualPath.getType();
348 if (ext == "tzp" || ext == "tzu" || ext == "tzl" || ext == "tlv")
349 return TZP_XSHLEVEL;
350 else
351 return OVL_XSHLEVEL;
352 } else if (type == TFileType::VECTOR_LEVEL) {
353 return PLI_XSHLEVEL;
354 } else
355 return UNKNOWN_XSHLEVEL;
356 }
357
358 //===========================================================================
359 // class LoadLevelUndo
360 //---------------------------------------------------------------------------
361
362 class LoadLevelUndo final : public TUndo {
363 TXshLevelP m_level;
364 TFilePath m_levelSetFolder;
365 int m_row, m_col, m_rowCount;
366 bool m_columnInserted;
367 std::vector<TXshCell> m_cells;
368 bool m_isFirstTime;
369
370 public:
LoadLevelUndo()371 LoadLevelUndo()
372 : m_level()
373 , m_levelSetFolder()
374 , m_row(0)
375 , m_col(0)
376 , m_rowCount(0)
377 , m_columnInserted(false)
378 , m_isFirstTime(true) {}
setLevel(TXshLevel * xl)379 void setLevel(TXshLevel *xl) { m_level = xl; }
setLevelSetFolder(const TFilePath & levelSetFolder)380 void setLevelSetFolder(const TFilePath &levelSetFolder) {
381 m_levelSetFolder = levelSetFolder;
382 }
setIsFirstTime(bool flag)383 void setIsFirstTime(bool flag) { m_isFirstTime = flag; }
setCells(TXsheet * xsh,int row,int col,int rowCount)384 void setCells(TXsheet *xsh, int row, int col, int rowCount) {
385 m_row = row;
386 m_col = col;
387 m_rowCount = rowCount;
388 if (rowCount > 0) {
389 m_cells.resize(rowCount);
390 xsh->getCells(row, col, rowCount, &m_cells[0]);
391 } else
392 m_cells.clear();
393 }
setColumnInserted(bool columnInserted)394 void setColumnInserted(bool columnInserted) {
395 m_columnInserted = columnInserted;
396 }
397
undo() const398 void undo() const override {
399 TApp *app = TApp::instance();
400 /*- 最初にシーンに読み込んだ操作のUndoのとき、Castから除く -*/
401 if (m_level && m_isFirstTime)
402 app->getCurrentScene()->getScene()->getLevelSet()->removeLevel(
403 m_level.getPointer());
404 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
405 if (m_columnInserted)
406 xsh->removeColumn(m_col);
407 else {
408 xsh->removeCells(m_row, m_col, m_rowCount);
409 xsh->insertCells(m_row, m_col, m_rowCount); // insert empty cells
410 // Remove sound or palette column if it is empty.
411 if (xsh->getColumn(m_col) && xsh->getColumn(m_col)->isEmpty()) {
412 TXshColumn::ColumnType columnType =
413 xsh->getColumn(m_col)->getColumnType();
414 if (columnType != TXshColumn::eLevelType) {
415 TStageObjectTree *stageObjectTree = xsh->getStageObjectTree();
416 int lastIndex = stageObjectTree->getStageObjectCount();
417 stageObjectTree->getStageObject(TStageObjectId::ColumnId(lastIndex),
418 true);
419 stageObjectTree->swapColumns(m_col, lastIndex);
420 xsh->removeColumn(m_col);
421 xsh->insertColumn(m_col);
422 stageObjectTree->swapColumns(lastIndex, m_col);
423 }
424 }
425 }
426 app->getCurrentXsheet()->notifyXsheetChanged();
427 if (app->getCurrentFrame()->isEditingLevel() &&
428 app->getCurrentLevel()->getLevel() == m_level.getPointer())
429 app->getCurrentLevel()->setLevel(0);
430 app->getCurrentScene()->notifyCastChange();
431 }
redo() const432 void redo() const override {
433 TApp *app = TApp::instance();
434 if (m_level)
435 app->getCurrentScene()->getScene()->getLevelSet()->insertLevel(
436 m_level.getPointer());
437 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
438 if (m_columnInserted) xsh->insertColumn(m_col);
439 if (m_rowCount > 0) {
440 xsh->removeCells(m_row, m_col, m_rowCount);
441 xsh->insertCells(m_row, m_col, m_rowCount);
442 xsh->setCells(m_row, m_col, m_rowCount, &m_cells[0]);
443 }
444 app->getCurrentXsheet()->notifyXsheetChanged();
445 if (app->getCurrentFrame()->isEditingLevel() &&
446 app->getCurrentLevel()->getLevel() == 0)
447 app->getCurrentLevel()->setLevel(m_level.getPointer());
448 app->getCurrentScene()->notifyCastChange();
449 }
getSize() const450 int getSize() const override {
451 return sizeof(*this) + sizeof(TXshCell) * m_cells.size() +
452 sizeof(TXshLevel);
453 }
getHistoryString()454 QString getHistoryString() override {
455 return QObject::tr("Load Level %1")
456 .arg(QString::fromStdWString(m_level->getName()));
457 }
458 };
459
460 //===========================================================================
461 // class LoadLevelAndReplaceUndo
462 //---------------------------------------------------------------------------
463
464 class LoadAndReplaceLevelUndo final : public TUndo {
465 TXshSimpleLevelP m_level;
466 QMap<QPair<int, int>, QPair<TXshSimpleLevelP, TFrameId>> m_oldLevels;
467 int m_row0, m_col0, m_row1, m_col1;
468
469 public:
LoadAndReplaceLevelUndo(const TXshSimpleLevelP & level,int row0,int col0,int row1,int col1)470 LoadAndReplaceLevelUndo(const TXshSimpleLevelP &level, int row0, int col0,
471 int row1, int col1)
472 : m_level(level), m_row0(row0), m_row1(row1), m_col0(col0), m_col1(col1) {
473 int c, r;
474 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
475 for (c = m_col0; c <= m_col1; c++)
476 for (r = m_row0; r <= m_row1; r++) {
477 TXshSimpleLevel *oldLevel = xsh->getCell(r, c).getSimpleLevel();
478 TFrameId fid = xsh->getCell(r, c).getFrameId();
479 QPair<int, int> cellId(r, c);
480 m_oldLevels[cellId] = QPair<TXshSimpleLevelP, TFrameId>(oldLevel, fid);
481 }
482 }
483
undo() const484 void undo() const override {
485 TApp *app = TApp::instance();
486 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
487 int c, r;
488 for (c = m_col0; c <= m_col1; c++)
489 for (r = m_row0; r <= m_row1; r++) {
490 QPair<int, int> cellId(r, c);
491 TXshSimpleLevel *oldLevel = m_oldLevels[cellId].first.getPointer();
492 TFrameId fid = m_oldLevels[cellId].second;
493 TXshCell cell = xsh->getCell(r, c);
494 cell.m_level = oldLevel;
495 cell.m_frameId = fid;
496 xsh->setCell(r, c, cell);
497 }
498 app->getCurrentXsheet()->notifyXsheetChanged();
499 app->getCurrentScene()->notifyCastChange();
500 }
501
redo() const502 void redo() const override {
503 TApp *app = TApp::instance();
504 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
505 int c, r;
506 for (c = m_col0; c <= m_col1; c++)
507 for (r = m_row0; r <= m_row1; r++) {
508 QPair<int, int> cellId(r, c);
509 TFrameId fid = m_oldLevels[cellId].second;
510 TXshCell cell = xsh->getCell(r, c);
511 cell.m_level = m_level.getPointer();
512 cell.m_frameId = fid;
513 xsh->setCell(r, c, cell);
514 }
515 app->getCurrentXsheet()->notifyXsheetChanged();
516 app->getCurrentScene()->notifyCastChange();
517 }
518
getSize() const519 int getSize() const override { return sizeof(*this); }
getHistoryString()520 QString getHistoryString() override {
521 return QObject::tr("Load and Replace Level %1")
522 .arg(QString::fromStdWString(m_level->getName()));
523 }
524 };
525
526 //===========================================================================
527 // loadPalette(scene, actualPath, row, col)
528 //---------------------------------------------------------------------------
529
loadPalette(ToonzScene * scene,TFilePath actualPath,TFilePath castFolder,int row,int & col)530 TXshLevel *loadPalette(ToonzScene *scene, TFilePath actualPath,
531 TFilePath castFolder, int row, int &col) {
532 TFilePath palettePath = actualPath;
533 TXsheet *xsh = scene->getXsheet();
534 TXshPaletteColumn *column = new TXshPaletteColumn;
535 xsh->insertColumn(col, column);
536 TXshLevel *level =
537 scene->createNewLevel(PLT_XSHLEVEL, palettePath.getWideName());
538 level->getPaletteLevel()->setPath(scene->codeFilePath(palettePath));
539 level->getPaletteLevel()->load();
540 TXshCell cell;
541 cell.m_level = level;
542 cell.m_frameId = TFrameId(1);
543 xsh->setCell(row, col, cell);
544 xsh->updateFrameCount();
545 // Undo
546 LoadLevelUndo *undo = new LoadLevelUndo();
547 undo->setLevel(level);
548 undo->setLevelSetFolder(castFolder);
549 undo->setCells(scene->getXsheet(), row, col, 1);
550 undo->setColumnInserted(true);
551 TUndoManager::manager()->add(undo);
552 return level;
553 }
554
555 //===========================================================================
556 // substituteLevel() ; TODO: move to a different file
557 //---------------------------------------------------------------------------
558
substituteLevel(TXsheet * xsh,TXshLevel * srcLevel,TXshLevel * dstLevel)559 void substituteLevel(TXsheet *xsh, TXshLevel *srcLevel, TXshLevel *dstLevel) {
560 std::set<TXshChildLevel *> substitutedSubs;
561
562 for (int c = 0; c < xsh->getColumnCount(); c++) {
563 int r0 = 0, r1 = -1;
564 xsh->getCellRange(c, r0, r1);
565 if (r0 > r1) continue;
566 int rowCount = r1 - r0 + 1;
567 std::vector<TXshCell> cells(rowCount);
568 xsh->getCells(r0, c, rowCount, &cells[0]);
569 bool changed = false;
570 for (int i = 0; i < rowCount; i++) {
571 if (!cells[i].isEmpty()) {
572 if (cells[i].m_level.getPointer() == srcLevel) {
573 cells[i].m_level = dstLevel;
574 changed = true;
575 } else {
576 // Recursive on sub-xsheets
577 TXshChildLevel *childLevel = cells[i].m_level->getChildLevel();
578 if (childLevel)
579 if (substitutedSubs.find(childLevel) == substitutedSubs.end()) {
580 substituteLevel(childLevel->getXsheet(), srcLevel, dstLevel);
581 substitutedSubs.insert(childLevel);
582 }
583 }
584 }
585 }
586 if (changed) xsh->setCells(r0, c, rowCount, &cells[0]);
587 }
588 }
589
590 //===========================================================================
591 // class ChildLevelResourceImporter
592 //---------------------------------------------------------------------------
593
594 class ChildLevelResourceImporter final : public ResourceProcessor {
595 ToonzScene *m_parentScene;
596 ToonzScene *m_childScene;
597
598 ResourceImportStrategy &m_importStrategy;
599 TFilePath m_levelSetFolder;
600
601 public:
602 ChildLevelResourceImporter(ToonzScene *parentScene, ToonzScene *childScene,
603 ResourceImportStrategy &importStrategy);
604
setLevelSetFolder(const TFilePath & levelSetFolder)605 void setLevelSetFolder(const TFilePath &levelSetFolder) {
606 m_levelSetFolder = levelSetFolder;
607 }
608
609 void process(TXshSimpleLevel *sl) override;
610 void process(TXshPaletteLevel *sl) override;
611 void process(TXshSoundLevel *sl) override;
aborted() const612 bool aborted() const override { return m_importStrategy.aborted(); }
613 };
614
615 //---------------------------------------------------------------------------
616
ChildLevelResourceImporter(ToonzScene * parentScene,ToonzScene * childScene,ResourceImportStrategy & importStrategy)617 ChildLevelResourceImporter::ChildLevelResourceImporter(
618 ToonzScene *parentScene, ToonzScene *childScene,
619 ResourceImportStrategy &importStrategy)
620 : m_parentScene(parentScene)
621 , m_childScene(childScene)
622 , m_importStrategy(importStrategy)
623 , m_levelSetFolder() {}
624
625 //---------------------------------------------------------------------------
626
process(TXshSimpleLevel * sl)627 void ChildLevelResourceImporter::process(TXshSimpleLevel *sl) {
628 TLevelSet *parentLevelSet = m_parentScene->getLevelSet();
629 if (parentLevelSet->hasLevel(sl->getName())) {
630 TXshSimpleLevel *other =
631 parentLevelSet->getLevel(sl->getName())->getSimpleLevel();
632 if (other) // in case that the retrieved level from scene cast is
633 // subXSheetLevel
634 {
635 TFilePath otherActualPath =
636 m_parentScene->decodeFilePath(other->getPath());
637 TFilePath slActualPath = m_childScene->decodeFilePath(sl->getPath());
638 if (otherActualPath == slActualPath &&
639 other->getProperties()->options() == sl->getProperties()->options()) {
640 substituteLevel(m_childScene->getXsheet(), sl, other);
641 return;
642 }
643 }
644 }
645
646 TFilePath slPath = sl->getPath();
647 std::string suffix = ResourceImporter::extractPsdSuffix(slPath);
648
649 TFilePath path = m_importStrategy.process(m_parentScene, m_childScene,
650 slPath); // actualPath);
651 if (suffix != "") path = ResourceImporter::buildPsd(path, suffix);
652
653 sl->setPath(path, false); // m_parentScene->codeFilePath(actualPath), false);
654 NameModifier nm(sl->getName());
655 std::wstring levelName;
656 for (;;) {
657 levelName = nm.getNext();
658 if (!parentLevelSet->hasLevel(levelName)) break;
659 }
660 assert(sl->getRefCount() > 0);
661 sl->addRef();
662 m_childScene->getLevelSet()->removeLevel(sl);
663 sl->setName(levelName);
664 bool ret = parentLevelSet->insertLevel(sl);
665 assert(ret);
666 if (m_levelSetFolder != TFilePath())
667 parentLevelSet->moveLevelToFolder(m_levelSetFolder, sl);
668 sl->setScene(m_parentScene);
669 try {
670 sl->load();
671 } catch (...) {
672 }
673
674 // Check if the scene saved with the previous version AND the premultiply
675 // option is set to PNG level setting
676 if (m_childScene->getVersionNumber() <
677 VersionNumber(71, 1)) { // V1.4 = 71.0 , V1.5 = 71.1
678 if (!path.isEmpty() && path.getType() == "png" &&
679 sl->getProperties()->doPremultiply())
680 sl->getProperties()->setDoPremultiply(false);
681 }
682
683 sl->release();
684 }
685
686 //---------------------------------------------------------------------------
687
process(TXshPaletteLevel * pl)688 void ChildLevelResourceImporter::process(TXshPaletteLevel *pl) {
689 TLevelSet *parentLevelSet = m_parentScene->getLevelSet();
690
691 TFilePath plPath = pl->getPath();
692
693 TFilePath path =
694 m_importStrategy.process(m_parentScene, m_childScene, plPath);
695
696 pl->setPath(path);
697 NameModifier nm(pl->getName());
698 std::wstring levelName;
699 for (;;) {
700 levelName = nm.getNext();
701 if (!parentLevelSet->hasLevel(levelName)) break;
702 }
703 assert(pl->getRefCount() > 0);
704 pl->addRef();
705 m_childScene->getLevelSet()->removeLevel(pl);
706 pl->setName(levelName);
707 bool ret = parentLevelSet->insertLevel(pl);
708 assert(ret);
709 if (m_levelSetFolder != TFilePath())
710 parentLevelSet->moveLevelToFolder(m_levelSetFolder, pl);
711 pl->setScene(m_parentScene);
712 try {
713 pl->load();
714 } catch (...) {
715 }
716 pl->release();
717 }
718
process(TXshSoundLevel * sl)719 void ChildLevelResourceImporter::process(TXshSoundLevel *sl) {
720 TLevelSet *parentLevelSet = m_parentScene->getLevelSet();
721 TFilePath path =
722 m_importStrategy.process(m_parentScene, m_childScene, sl->getPath());
723 sl->setPath(path);
724 NameModifier nm(sl->getName());
725 std::wstring levelName;
726 for (;;) {
727 levelName = nm.getNext();
728 if (!parentLevelSet->hasLevel(levelName)) break;
729 }
730 assert(sl->getRefCount() > 0);
731 sl->addRef();
732 m_childScene->getLevelSet()->removeLevel(sl);
733 sl->setName(levelName);
734 bool ret = parentLevelSet->insertLevel(sl);
735 assert(ret);
736 if (m_levelSetFolder != TFilePath())
737 parentLevelSet->moveLevelToFolder(m_levelSetFolder, sl);
738 sl->setScene(m_parentScene);
739 try {
740 sl->loadSoundTrack();
741 } catch (...) {
742 }
743 sl->release();
744 }
745
746 //===========================================================================
747 // loadChildLevel(parentScene, actualPath, row, col, importStrategy)
748 //---------------------------------------------------------------------------
749
loadChildLevel(ToonzScene * parentScene,TFilePath actualPath,int row,int & col,ResourceImportDialog & importStrategy)750 TXshLevel *loadChildLevel(ToonzScene *parentScene, TFilePath actualPath,
751 int row, int &col,
752 ResourceImportDialog &importStrategy) {
753 TProjectP project = TProjectManager::instance()->loadSceneProject(actualPath);
754
755 // In Tab mode we don't need the project. Otherwise if it is not available
756 // we must exit
757 if (!project && !TProjectManager::instance()->isTabModeEnabled()) return 0;
758
759 // load the subxsheet
760 ToonzScene scene;
761 scene.loadTnzFile(actualPath);
762 scene.setProject(project.getPointer());
763 std::wstring subSceneName = actualPath.getWideName();
764
765 // camera settings. get the child camera ...
766 TXsheet *childXsh = scene.getXsheet();
767 TStageObjectId cameraId =
768 childXsh->getStageObjectTree()->getCurrentCameraId();
769 TStageObject *childCameraObject = childXsh->getStageObject(cameraId);
770 TCamera *childCamera = childCameraObject->getCamera();
771 // ...and the parent camera...
772 TXsheet *parentXsh = parentScene->getXsheet();
773 cameraId = parentXsh->getStageObjectTree()->getCurrentCameraId();
774 TStageObject *cameraObject = parentXsh->getStageObject(cameraId);
775 TCamera *camera = cameraObject->getCamera();
776
777 // if the camera settings are different ask the user
778 const double eps = 0.00001;
779 if (fabs(camera->getSize().lx - childCamera->getSize().lx) > eps ||
780 fabs(camera->getSize().ly - childCamera->getSize().ly) > eps ||
781 camera->getRes() != childCamera->getRes()) {
782 QString question(QObject::tr(
783 "The camera settings of the scene you are loading as sub-xsheet are "
784 "different from those of your current scene. What you want to do?"));
785 QList<QString> list;
786 list.append(QObject::tr("Keep the sub-xsheet original camera settings."));
787 list.append(QObject::tr(
788 "Apply the current scene camera settings to the sub-xsheet."));
789 int ret = DVGui::RadioButtonMsgBox(DVGui::WARNING, question, list);
790 if (ret == 0) return 0;
791 if (ret == 2) {
792 childCamera->setRes(camera->getRes());
793 childCamera->setSize(camera->getSize());
794 }
795 }
796
797 ChildLevelResourceImporter childLevelResourceImporter(parentScene, &scene,
798 importStrategy);
799 TFilePath dstFolder = importStrategy.getDstFolder();
800 if (dstFolder != TFilePath()) {
801 TLevelSet *levelSet = parentScene->getLevelSet();
802 TFilePath levelSetFolder = levelSet->createFolder(
803 levelSet->getDefaultFolder() + dstFolder.getParentDir(),
804 dstFolder.getWideName());
805 childLevelResourceImporter.setLevelSetFolder(levelSetFolder);
806 }
807
808 SceneResources resources(&scene, childXsh);
809 resources.accept(&childLevelResourceImporter);
810
811 scene.setProject(parentScene->getProject());
812 std::vector<TXshChildLevel *> childLevels;
813 for (int i = 0; i < scene.getLevelSet()->getLevelCount(); i++)
814 if (TXshChildLevel *cl = scene.getLevelSet()->getLevel(i)->getChildLevel())
815 childLevels.push_back(cl);
816 for (int i = 0; i < (int)childLevels.size(); i++) {
817 TXshChildLevel *cl = childLevels[i];
818 parentScene->getLevelSet()->insertLevel(cl);
819 // scene.getLevelSet()->removeLevel(cl);
820 }
821
822 TXshChildLevel *childLevel =
823 parentScene->createNewLevel(CHILD_XSHLEVEL, subSceneName)
824 ->getChildLevel();
825
826 int frameCount = scene.getXsheet()->getFrameCount();
827 childXsh->setScene(parentScene);
828 if (frameCount <= 0) frameCount = 1;
829 int dummy, lastOldRow;
830 parentXsh->getCellRange(col, dummy, lastOldRow);
831
832 childLevel->setXsheet(childXsh);
833 childXsh->getStageObjectTree()->invalidateAll();
834
835 bool shiftColumn = beforeCellsInsert(parentXsh, row, col, frameCount,
836 TXshColumn::eLevelType);
837 if (!shiftColumn) parentXsh->insertCells(row, col, frameCount);
838
839 for (int i = 0; i < frameCount; i++)
840 parentXsh->setCell(row + i, col, TXshCell(childLevel, TFrameId(1 + i)));
841
842 for (int i = 0; i < parentScene->getLevelSet()->getLevelCount(); i++)
843 parentScene->getLevelSet()->getLevel(i)->setScene(parentScene);
844
845 // Inform the cache fx command that a scene was loaded
846 CacheFxCommand::instance()->onSceneLoaded();
847
848 return childLevel;
849 }
850
851 //===========================================================================
852 // loadLevel(scene, path, castFolder, row, col)
853 // (path can be coded path)
854 // for loading the all types of level other than scene/palette/sound
855 //---------------------------------------------------------------------------
856
loadLevel(ToonzScene * scene,const IoCmd::LoadResourceArguments::ResourceData & rd,const TFilePath & castFolder,int row0,int & col0,int row1,int & col1,bool expose,std::vector<TFrameId> & fIds,int xFrom=-1,int xTo=-1,std::wstring levelName=L"",int step=-1,int inc=-1,int frameCount=-1,bool doesFileActuallyExist=true)857 TXshLevel *loadLevel(ToonzScene *scene,
858 const IoCmd::LoadResourceArguments::ResourceData &rd,
859 const TFilePath &castFolder, int row0, int &col0, int row1,
860 int &col1, bool expose, std::vector<TFrameId> &fIds,
861 int xFrom = -1, int xTo = -1, std::wstring levelName = L"",
862 int step = -1, int inc = -1, int frameCount = -1,
863 bool doesFileActuallyExist = true) {
864 TFilePath actualPath = scene->decodeFilePath(rd.m_path);
865
866 LoadLevelUndo *undo = 0;
867 LoadAndReplaceLevelUndo *replaceUndo = 0;
868
869 TXsheet *xsh = scene->getXsheet();
870
871 TFileType::Type type = TFileType::getInfo(actualPath);
872 // try to find the level with the same path in the Scene Cast. If found, reuse
873 // it
874 TXshLevel *xl = getLevelByPath(scene, actualPath);
875 bool isFirstTime = !xl;
876 std::wstring name = actualPath.getWideName();
877
878 IoCmd::ConvertingPopup *convertingPopup = new IoCmd::ConvertingPopup(
879 TApp::instance()->getMainWindow(),
880 QString::fromStdWString(name) +
881 QString::fromStdString(actualPath.getDottedType()));
882
883 convertingPopup->hide(); // Should be unnecessary
884
885 if (!xl) {
886 try {
887 std::string format = actualPath.getType();
888 if (format == "tzp" || format == "tzu") convertingPopup->show();
889
890 if (fIds.size() != 0 && doesFileActuallyExist)
891 xl = scene->loadLevel(actualPath, rd.m_options ? &*rd.m_options : 0,
892 levelName, fIds);
893 else
894 xl = scene->loadLevel(actualPath, rd.m_options ? &*rd.m_options : 0);
895 if (!xl) {
896 error("Failed to create level " + toQString(actualPath) +
897 " : this filetype is not supported.");
898 return 0;
899 }
900
901 TXshSimpleLevel *sl = xl->getSimpleLevel();
902 if (sl && sl->isReadOnly() &&
903 (sl->getType() == PLI_XSHLEVEL || sl->getType() == TZP_XSHLEVEL ||
904 sl->getType() == OVL_XSHLEVEL)) {
905 TLevelSet *levelSet = new TLevelSet;
906 levelSet->insertLevel(sl);
907 VersionControlManager::instance()->setFrameRange(levelSet, true);
908 }
909
910 if (convertingPopup->isVisible()) convertingPopup->hide();
911 } catch (TException &e) {
912 if (convertingPopup->isVisible()) convertingPopup->hide();
913
914 QString msg = QString::fromStdWString(e.getMessage());
915 if (msg == QString("Old 4.1 Palette"))
916 error("It is not possible to load the level " + toQString(actualPath) +
917 " because its version is not supported.");
918 else
919 error(QString::fromStdWString(e.getMessage()));
920
921 return 0;
922 }
923
924 if (xl->getSimpleLevel() &&
925 xl->getSimpleLevel()->getProperties()->isForbidden()) {
926 error("It is not possible to load the level " + toQString(actualPath) +
927 " because its version is not supported.");
928 scene->getLevelSet()->removeLevel(xl);
929 return 0;
930 }
931
932 if (castFolder != TFilePath())
933 scene->getLevelSet()->moveLevelToFolder(castFolder, xl);
934
935 History::instance()->addItem(actualPath);
936
937 if (row1 == -1 && col1 == -1) {
938 undo = new LoadLevelUndo();
939 undo->setLevel(xl);
940 undo->setLevelSetFolder(castFolder);
941 undo->setIsFirstTime(isFirstTime);
942 }
943 }
944 // if the level can be obtained (from scene cast or file)
945 if (xl) {
946 // placing in the xsheet
947 if (expose) {
948 // lo importo nell'xsheet
949 if (!undo) {
950 undo = new LoadLevelUndo();
951 undo->setLevel(xl);
952 undo->setIsFirstTime(isFirstTime);
953 }
954
955 int levelType = xl->getType();
956 TXshColumn::ColumnType newLevelColumnType =
957 TXshColumn::toColumnType(levelType);
958 bool columnInserted =
959 beforeCellsInsert(scene->getXsheet(), row0, col0, xl->getFrameCount(),
960 newLevelColumnType);
961
962 scene->getXsheet()->exposeLevel(row0, col0, xl, fIds, xFrom, xTo, step,
963 inc, frameCount, doesFileActuallyExist);
964
965 if (frameCount > 0)
966 undo->setCells(scene->getXsheet(), row0, col0, frameCount);
967 else
968 undo->setCells(scene->getXsheet(), row0, col0, xl->getFrameCount());
969 undo->setColumnInserted(columnInserted);
970 }
971 if (row1 != -1 || col1 != -1)
972 replaceUndo = new LoadAndReplaceLevelUndo(xl->getSimpleLevel(), row0,
973 col0, row1, col1);
974 }
975
976 if (undo) TUndoManager::manager()->add(undo);
977
978 if (replaceUndo) TUndoManager::manager()->add(replaceUndo);
979
980 return xl;
981 }
982
983 //===========================================================================
984 // loadResource(scene, path, castFolder, row, col, expose)
985 //---------------------------------------------------------------------------
986
loadResource(ToonzScene * scene,const IoCmd::LoadResourceArguments::ResourceData & rd,const TFilePath & castFolder,int row0,int & col0,int row1,int & col1,bool expose,std::vector<TFrameId> fIds=std::vector<TFrameId> (),int xFrom=-1,int xTo=-1,std::wstring levelName=L"",int step=-1,int inc=-1,int frameCount=-1,bool doesFileActuallyExist=true)987 TXshLevel *loadResource(
988 ToonzScene *scene, const IoCmd::LoadResourceArguments::ResourceData &rd,
989 const TFilePath &castFolder, int row0, int &col0, int row1, int &col1,
990 bool expose, std::vector<TFrameId> fIds = std::vector<TFrameId>(),
991 int xFrom = -1, int xTo = -1, std::wstring levelName = L"", int step = -1,
992 int inc = -1, int frameCount = -1, bool doesFileActuallyExist = true) {
993 IoCmd::LoadResourceArguments::ResourceData actualRd(rd);
994 actualRd.m_path = scene->decodeFilePath(rd.m_path);
995
996 TFileType::Type type = TFileType::getInfo(actualRd.m_path);
997 return (type == TFileType::PALETTE_LEVEL)
998 ? loadPalette(scene, actualRd.m_path, castFolder, row0, col0)
999 : loadLevel(scene, actualRd, castFolder, row0, col0, row1, col1,
1000 expose, fIds, xFrom, xTo, levelName, step, inc,
1001 frameCount, doesFileActuallyExist);
1002 }
1003
1004 //===========================================================================
1005
1006 enum ExposeType { eOverWrite, eShiftCells, eNone };
1007
1008 //===========================================================================
1009 // class ExposeLevelUndo
1010 //---------------------------------------------------------------------------
1011
1012 class ExposeLevelUndo final : public TUndo {
1013 TXshSimpleLevelP m_sl;
1014 std::vector<TXshCell> m_oldCells;
1015 std::vector<TFrameId> m_fids;
1016 int m_row;
1017 int m_col;
1018 int m_frameCount;
1019 bool m_insertEmptyColumn;
1020 ExposeType m_type;
1021
1022 public:
ExposeLevelUndo(TXshSimpleLevel * sl,int row,int col,int frameCount,bool insertEmptyColumn,ExposeType type=eNone)1023 ExposeLevelUndo(TXshSimpleLevel *sl, int row, int col, int frameCount,
1024 bool insertEmptyColumn, ExposeType type = eNone)
1025 : m_sl(sl)
1026 , m_row(row)
1027 , m_col(col)
1028 , m_frameCount(frameCount)
1029 , m_insertEmptyColumn(insertEmptyColumn)
1030 , m_fids()
1031 , m_type(type) {
1032 if (type == eOverWrite) {
1033 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
1034 int r;
1035 for (r = row; r < frameCount + row; r++)
1036 m_oldCells.push_back(xsh->getCell(r, col));
1037 }
1038 }
1039
setFids(const std::vector<TFrameId> & fids)1040 void setFids(const std::vector<TFrameId> &fids) { m_fids = fids; }
1041
undo() const1042 void undo() const override {
1043 TApp *app = TApp::instance();
1044 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
1045 if (m_insertEmptyColumn)
1046 xsh->removeColumn(m_col);
1047 else {
1048 xsh->removeCells(m_row, m_col, m_frameCount);
1049 if (m_type == eNone) xsh->insertCells(m_row, m_col, m_frameCount);
1050 if (m_type == eOverWrite) {
1051 xsh->insertCells(m_row, m_col, m_frameCount);
1052 if (!m_oldCells.empty())
1053 xsh->setCells(m_row, m_col, m_frameCount, &m_oldCells[0]);
1054 }
1055 app->getCurrentXsheet()->notifyXsheetChanged();
1056 }
1057 }
1058
redo() const1059 void redo() const override {
1060 TApp *app = TApp::instance();
1061 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
1062 if (m_insertEmptyColumn) xsh->insertColumn(m_col);
1063 int frameCount = 0;
1064 if (!m_fids.empty()) {
1065 if (m_type == eShiftCells) xsh->insertCells(m_row, m_col, m_frameCount);
1066 frameCount = (int)m_fids.size();
1067 std::vector<TFrameId>::const_iterator it;
1068 int row = m_row;
1069 for (it = m_fids.begin(); it != m_fids.end(); ++it) {
1070 xsh->setCell(row, m_col, TXshCell(m_sl.getPointer(), *it));
1071 ++row;
1072 }
1073 } else {
1074 xsh->removeCells(m_row, m_col, m_frameCount);
1075 frameCount = xsh->exposeLevel(m_row, m_col, m_sl.getPointer());
1076 }
1077 app->getCurrentXsheet()->notifyXsheetChanged();
1078 }
1079
getSize() const1080 int getSize() const override { return sizeof *this; }
1081
getHistoryString()1082 QString getHistoryString() override {
1083 return QObject::tr("Expose Level %1")
1084 .arg(QString::fromStdWString(m_sl->getName()));
1085 }
1086 };
1087
1088 //===========================================================================
1089 // class ExposeCommentUndo
1090 //---------------------------------------------------------------------------
1091
1092 class ExposeCommentUndo final : public TUndo {
1093 TXshSoundTextColumnP m_soundtextColumn;
1094 int m_col;
1095 bool m_insertEmptyColumn;
1096 QString m_columnName;
1097
1098 public:
ExposeCommentUndo(TXshSoundTextColumn * soundtextColumn,int col,bool insertEmptyColumn,QString columnName)1099 ExposeCommentUndo(TXshSoundTextColumn *soundtextColumn, int col,
1100 bool insertEmptyColumn, QString columnName)
1101 : m_soundtextColumn(soundtextColumn)
1102 , m_col(col)
1103 , m_insertEmptyColumn(insertEmptyColumn)
1104 , m_columnName(columnName) {}
1105
undo() const1106 void undo() const override {
1107 TApp *app = TApp::instance();
1108 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
1109 xsh->removeColumn(m_col);
1110 if (!m_insertEmptyColumn) xsh->insertColumn(m_col);
1111 app->getCurrentXsheet()->notifyXsheetChanged();
1112 }
1113
redo() const1114 void redo() const override {
1115 TApp *app = TApp::instance();
1116 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
1117 if (m_insertEmptyColumn) xsh->insertColumn(m_col);
1118 xsh->insertColumn(m_col, m_soundtextColumn.getPointer());
1119
1120 // Setto il nome di dafult della colonna al nome del file magpie.
1121 TStageObject *obj = xsh->getStageObject(TStageObjectId::ColumnId(m_col));
1122 std::string str = m_columnName.toStdString();
1123 obj->setName(str);
1124
1125 app->getCurrentXsheet()->notifyXsheetChanged();
1126 }
1127
getSize() const1128 int getSize() const override { return sizeof *this; }
1129 };
1130
1131 //=============================================================================
1132
1133 // This class is intended to serve as inhibitor for Previewer and SwatchViewer's
1134 // activity
1135 class RenderingSuspender {
1136 public:
RenderingSuspender()1137 RenderingSuspender() {
1138 Previewer::suspendRendering(true);
1139 PreviewFxManager::suspendRendering(true);
1140 SwatchViewer::suspendRendering(true);
1141 }
1142
~RenderingSuspender()1143 ~RenderingSuspender() {
1144 Previewer::suspendRendering(false);
1145 PreviewFxManager::suspendRendering(false);
1146 SwatchViewer::suspendRendering(false);
1147 }
1148 };
1149
1150 //=============================================================================
1151
dirtyWhite(const TPaletteP & plt)1152 inline TPaletteP dirtyWhite(const TPaletteP &plt) {
1153 TPaletteP out = TPaletteP(plt->clone());
1154 for (int i = 0; i < out->getStyleCount(); i++) {
1155 if (out->getStyle(i)->getMainColor() == TPixel::White) {
1156 out->getStyle(i)->setMainColor(TPixel(254, 254, 254, 255));
1157 }
1158 }
1159 return out;
1160 }
1161
1162 //---------------------------------------------------------------------------
1163 } // namespace
1164 //---------------------------------------------------------------------------
1165
1166 // Per ora e' usato solo per i formato "tzp" e "tzu".
ConvertingPopup(QWidget * parent,QString fileName)1167 IoCmd::ConvertingPopup::ConvertingPopup(QWidget *parent, QString fileName)
1168 : QDialog(parent) {
1169 setModal(true);
1170 setWindowFlags(Qt::Dialog | Qt::WindowTitleHint);
1171 setMinimumSize(70, 50);
1172 QVBoxLayout *mainLayout = new QVBoxLayout;
1173 mainLayout->setMargin(5);
1174 mainLayout->setSpacing(0);
1175
1176 QLabel *label = new QLabel(QString(
1177 QObject::tr("Converting %1 images to tlv format...").arg(fileName)));
1178 mainLayout->addWidget(label);
1179
1180 setLayout(mainLayout);
1181 }
1182
~ConvertingPopup()1183 IoCmd::ConvertingPopup::~ConvertingPopup() {}
1184
1185 //===========================================================================
1186 // IoCmd::saveSceneIfNeeded(message)
1187 //---------------------------------------------------------------------------
1188
saveSceneIfNeeded(QString msg)1189 bool IoCmd::saveSceneIfNeeded(QString msg) {
1190 TApp *app = TApp::instance();
1191
1192 if (app->getCurrentScene()->getDirtyFlag()) {
1193 QString question;
1194 question = QObject::tr(
1195 "%1: the current scene has been modified.\n"
1196 "What would you like to do?")
1197 .arg(msg);
1198 int ret = DVGui::MsgBox(
1199 question, QObject::tr("Save All"), QObject::tr("Save Scene Only"),
1200 QObject::tr("Discard Changes"), QObject::tr("Cancel"), 0);
1201 if (ret == 0 || ret == 4) {
1202 // cancel (or closed message box window)
1203 return false;
1204 } else if (ret == 1) {
1205 // save all
1206 if (!IoCmd::saveAll()) return false;
1207 } else if (ret == 2) {
1208 // save
1209 if (!IoCmd::saveScene()) return false;
1210 } else if (ret == 3) {
1211 }
1212 }
1213
1214 ToonzScene *scene = app->getCurrentScene()->getScene();
1215 if (scene) {
1216 QStringList dirtyResources;
1217 {
1218 SceneResources resources(scene, 0);
1219 resources.getDirtyResources(dirtyResources);
1220 }
1221
1222 if (!dirtyResources.empty()) {
1223 // show up to 5 items
1224 int extraCount = dirtyResources.count() - 5;
1225 if (extraCount > 0) {
1226 dirtyResources = dirtyResources.mid(0, 5);
1227 dirtyResources.append(
1228 QObject::tr("and %1 more item(s).").arg(extraCount));
1229 }
1230
1231 QString question;
1232
1233 question = msg + ":" +
1234 QObject::tr(" The following file(s) have been modified.\n\n");
1235
1236 question += " " + dirtyResources.join("\n ");
1237
1238 question += "\n" + QObject::tr("\nWhat would you like to do? ");
1239
1240 int ret =
1241 DVGui::MsgBox(question, QObject::tr("Save Changes"),
1242 msg + QObject::tr(" Anyway"), QObject::tr("Cancel"), 0);
1243 if (ret == 0 || ret == 3) {
1244 // cancel (or closed message box window)
1245 return false;
1246 } else if (ret == 1) {
1247 // save non scene files
1248 IoCmd::saveNonSceneFiles();
1249 } else if (ret == 2) {
1250 // do nothing and continue
1251 }
1252 }
1253
1254 RenderingSuspender suspender;
1255
1256 TFilePath scenePath(scene->getScenePath());
1257 scene->clear(); // note: this (possibly) removes the "untitled" folder
1258 app->getCurrentScene()->notifyCastChange();
1259 // Si deve notificare anche il cambiamento che ha subito l'xsheet.
1260 app->getCurrentXsheet()->notifyXsheetSwitched();
1261 FileBrowser::refreshFolder(scenePath.getParentDir());
1262 }
1263 app->getCurrentScene()->setDirtyFlag(false);
1264 return true;
1265 }
1266
1267 //===========================================================================
1268 // IoCmd::newScene()
1269 //---------------------------------------------------------------------------
1270
newScene()1271 void IoCmd::newScene() {
1272 RenderingSuspender suspender;
1273 TApp *app = TApp::instance();
1274 double cameraDpi = 120; // used to be 64 and 53.33333
1275
1276 if (!saveSceneIfNeeded(QApplication::tr("New Scene"))) return;
1277
1278 IconGenerator::instance()->clearRequests();
1279 IconGenerator::instance()->clearSceneIcons();
1280 ImageManager::instance()->clear();
1281 FullColorPalette::instance()->clear();
1282
1283 CacheFxCommand::instance()->onNewScene();
1284 CacheFxCommand::instance()->onSceneLoaded();
1285
1286 #ifdef USE_SQLITE_HDPOOL
1287 // INTERMEDIATE CACHE RESULTS MANAGEMENT: Clear all resources not accessed in
1288 // the last 2 sessions
1289 TCacheResourcePool::instance()->clearAccessedAfterSessions(
1290 1); // 0 would be after this session
1291 #endif
1292
1293 ToonzScene *scene = new ToonzScene();
1294 TImageStyle::setCurrentScene(scene);
1295
1296 TCamera *camera = scene->getCurrentCamera();
1297 TDimension res(1920, 1080);
1298 // TDimension res(768, 576);
1299 camera->setRes(res);
1300 camera->setSize(
1301 TDimensionD((double)res.lx / cameraDpi, (double)res.ly / cameraDpi));
1302 scene->getProperties()->setBgColor(TPixel32::White);
1303 TProjectManager::instance()->initializeScene(scene);
1304 if (Preferences::instance()->getPixelsOnly()) {
1305 TCamera *updateCamera = scene->getCurrentCamera();
1306 TDimension updateRes = updateCamera->getRes();
1307 updateCamera->setSize(TDimensionD((double)updateRes.lx / cameraDpi,
1308 (double)updateRes.ly / cameraDpi));
1309 }
1310 // Must set current scene after initializeScene!!
1311 app->getCurrentScene()->setScene(scene);
1312 // initializeScene() load project cleanup palette: set it to cleanup palette
1313 // handle.
1314 TPalette *palette = scene->getProperties()
1315 ->getCleanupParameters()
1316 ->m_cleanupPalette.getPointer();
1317 PaletteController *paletteController = app->getPaletteController();
1318 paletteController->getCurrentCleanupPalette()->setPalette(palette, -1);
1319 paletteController->editLevelPalette();
1320
1321 TFilePath scenePath = scene->getScenePath();
1322 DvDirModel::instance()->refreshFolder(scenePath.getParentDir());
1323
1324 Previewer::clearAll();
1325 PreviewFxManager::instance()->reset();
1326
1327 app->getCurrentScene()->notifyNameSceneChange();
1328 IconGenerator::instance()->invalidateSceneIcon();
1329 ToolHandle *toolH = TApp::instance()->getCurrentTool();
1330 if (toolH && toolH->getTool()) toolH->getTool()->reset();
1331
1332 CommandManager::instance()->execute("T_Hand");
1333
1334 CommandManager::instance()->enable(MI_SaveSubxsheetAs, false);
1335
1336 app->getCurrentScene()->notifySceneChanged();
1337 app->getCurrentScene()->setDirtyFlag(false);
1338 app->getCurrentObject()->setIsSpline(false);
1339 app->getCurrentColumn()->setColumnIndex(0);
1340
1341 CleanupParameters *cp = scene->getProperties()->getCleanupParameters();
1342 CleanupParameters::GlobalParameters.assign(cp);
1343
1344 // updateCleanupSettingsPopup();
1345
1346 CleanupPreviewCheck::instance()->setIsEnabled(false);
1347 CameraTestCheck::instance()->setIsEnabled(false);
1348 SetScanCropboxCheck::instance()->setIsEnabled(false);
1349
1350 if (!TApp::instance()->isApplicationStarting())
1351 QApplication::clipboard()->clear();
1352 TSelection::setCurrent(0);
1353 TUndoManager::manager()->reset();
1354
1355 bool exist = TSystem::doesExistFileOrLevel(
1356 scene->decodeFilePath(scene->getScenePath()));
1357 QAction *act = CommandManager::instance()->getAction(MI_RevertScene);
1358 if (act) act->setEnabled(exist);
1359 }
1360
1361 //===========================================================================
1362 // IoCmd::saveScene(scenePath, flags)
1363 //---------------------------------------------------------------------------
1364
saveScene(const TFilePath & path,int flags)1365 bool IoCmd::saveScene(const TFilePath &path, int flags) {
1366 bool overwrite = (flags & SILENTLY_OVERWRITE) != 0;
1367 bool saveSubxsheet = (flags & SAVE_SUBXSHEET) != 0;
1368 TApp *app = TApp::instance();
1369
1370 assert(!path.isEmpty());
1371 TFilePath scenePath = path;
1372 if (scenePath.getType() == "") scenePath = scenePath.withType("tnz");
1373 if (scenePath.getType() != "tnz") {
1374 error(
1375 QObject::tr("%1 has an invalid file extension.").arg(toQString(path)));
1376 return false;
1377 }
1378 TFileStatus dirStatus(scenePath.getParentDir());
1379 if (!(dirStatus.doesExist() && dirStatus.isWritable())) {
1380 error(QObject::tr("%1 is an invalid path.")
1381 .arg(toQString(scenePath.getParentDir())));
1382 return false;
1383 }
1384
1385 // notify user if the scene will be saved including any "broken" expression
1386 // reference
1387 if (!ExpressionReferenceManager::instance()->askIfParamIsIgnoredOnSave(
1388 saveSubxsheet))
1389 return false;
1390
1391 if (!overwrite && TFileStatus(scenePath).doesExist()) {
1392 QString question;
1393 question = QObject::tr(
1394 "The scene %1 already exists.\nDo you want to overwrite it?")
1395 .arg(QString::fromStdString(scenePath.getName()));
1396
1397 int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
1398 QObject::tr("Cancel"), 0);
1399 if (ret == 2 || ret == 0) return false;
1400 }
1401
1402 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1403
1404 TXsheet *xsheet = 0;
1405 if (saveSubxsheet) xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
1406
1407 // If the scene will be saved in the different folder, check out the scene
1408 // cast.
1409 // if the cast contains the level specified with $scenefolder alias,
1410 // open a warning popup notifying that such level will lose link.
1411
1412 // in case of saving subxsheet, the current scene will not be switched to the
1413 // saved one
1414 // so the level paths are needed to be reverted after saving
1415 QHash<TXshLevel *, TFilePath> orgLevelPaths;
1416 auto revertOrgLevelPaths = [&] {
1417 QHash<TXshLevel *, TFilePath>::const_iterator i =
1418 orgLevelPaths.constBegin();
1419 while (i != orgLevelPaths.constEnd()) {
1420 if (TXshSimpleLevel *sil = i.key()->getSimpleLevel())
1421 sil->setPath(i.value(), true);
1422 else if (TXshPaletteLevel *pal = i.key()->getPaletteLevel())
1423 pal->setPath(i.value());
1424 else if (TXshSoundLevel *sol = i.key()->getSoundLevel())
1425 sol->setPath(i.value());
1426 ++i;
1427 }
1428 };
1429
1430 if (!overwrite) {
1431 bool ret = takeCareSceneFolderItemsOnSaveSceneAs(scene, scenePath, xsheet,
1432 orgLevelPaths);
1433 if (!ret) {
1434 revertOrgLevelPaths();
1435 return false;
1436 }
1437 }
1438
1439 TFilePath oldFullPath = scene->decodeFilePath(scene->getScenePath());
1440 TFilePath newFullPath = scene->decodeFilePath(scenePath);
1441
1442 QApplication::setOverrideCursor(Qt::WaitCursor);
1443 if (app->getCurrentScene()->getDirtyFlag())
1444 scene->getContentHistory(true)->modifiedNow();
1445
1446 if (oldFullPath != newFullPath) {
1447 IconGenerator::instance()->clearRequests();
1448 IconGenerator::instance()->clearSceneIcons();
1449
1450 #ifdef USE_SQLITE_HDPOOL
1451 // Open the new cache resources HD pool
1452 TCacheResourcePool::instance()->setPath(
1453 QString::fromStdWString(
1454 ToonzFolder::getCacheRootFolder().getWideString()),
1455 QString::fromStdWString(scene->getProject()->getName().getWideName()),
1456 QString::fromStdWString(scene->getSceneName()));
1457 #endif
1458 }
1459
1460 CleanupParameters *cp = scene->getProperties()->getCleanupParameters();
1461 CleanupParameters oldCP(*cp);
1462 cp->assign(&CleanupParameters::GlobalParameters);
1463
1464 try {
1465 scene->save(scenePath, xsheet);
1466 } catch (const TSystemException &se) {
1467 DVGui::warning(QString::fromStdWString(se.getMessage()));
1468 } catch (...) {
1469 DVGui::error(QObject::tr("Couldn't save %1").arg(toQString(scenePath)));
1470 }
1471
1472 cp->assign(&oldCP);
1473
1474 // in case of saving subxsheet, revert the level paths after saving
1475 revertOrgLevelPaths();
1476
1477 if (!overwrite && !saveSubxsheet)
1478 app->getCurrentScene()->notifyNameSceneChange();
1479 FileBrowser::refreshFolder(scenePath.getParentDir());
1480 IconGenerator::instance()->invalidate(scenePath);
1481
1482 // Le seguenti notifiche non cambiano il dirty flag del livello o della
1483 // paletta
1484 // ma sono necessarie per aggiornare le titlebar dei pannelli.
1485 app->getCurrentLevel()->notifyLevelTitleChange();
1486 app->getCurrentPalette()->notifyPaletteTitleChanged();
1487
1488 app->getCurrentScene()->setDirtyFlag(false);
1489
1490 History::instance()->addItem(scenePath);
1491 RecentFiles::instance()->addFilePath(
1492 toQString(scenePath), RecentFiles::Scene,
1493 QString::fromStdString(app->getCurrentScene()
1494 ->getScene()
1495 ->getProject()
1496 ->getName()
1497 .getName()));
1498
1499 QApplication::restoreOverrideCursor();
1500
1501 bool exist = TSystem::doesExistFileOrLevel(
1502 scene->decodeFilePath(scene->getScenePath()));
1503 QAction *act = CommandManager::instance()->getAction(MI_RevertScene);
1504 if (act) act->setEnabled(exist);
1505
1506 return true;
1507 }
1508
1509 //===========================================================================
1510 // IoCmd::saveScene()
1511 //---------------------------------------------------------------------------
1512
saveScene()1513 bool IoCmd::saveScene() {
1514 TSelection *oldSelection =
1515 TApp::instance()->getCurrentSelection()->getSelection();
1516 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1517 if (scene->isUntitled()) {
1518 static SaveSceneAsPopup *popup = 0;
1519 if (!popup) popup = new SaveSceneAsPopup();
1520 int ret = popup->exec();
1521 if (ret == QDialog::Accepted) {
1522 TApp::instance()->getCurrentScene()->setDirtyFlag(false);
1523 return true;
1524 } else {
1525 TApp::instance()->getCurrentSelection()->setSelection(oldSelection);
1526 return false;
1527 }
1528 } else {
1529 TFilePath fp = scene->getScenePath();
1530 // salva la scena con il nome fp. se fp esiste gia' lo sovrascrive
1531 return saveScene(fp, SILENTLY_OVERWRITE);
1532 }
1533 }
1534
1535 //===========================================================================
1536 // IoCmd::saveLevel(levelPath)
1537 //---------------------------------------------------------------------------
1538
saveLevel(const TFilePath & path)1539 bool IoCmd::saveLevel(const TFilePath &path) {
1540 assert(!path.isEmpty());
1541
1542 TApp *app = TApp::instance();
1543 TXshSimpleLevel *sl =
1544 dynamic_cast<TXshSimpleLevel *>(app->getCurrentLevel()->getLevel());
1545 if (!sl) return false;
1546 std::string ext = sl->getPath().getType();
1547 std::string dotts = sl->getPath().getDots();
1548 TFilePath realPath = path;
1549 if (realPath.getType() == "")
1550 realPath = TFilePath(realPath.getWideString() + ::to_wstring(dotts + ext));
1551
1552 bool ret = saveLevel(realPath, sl, false);
1553 if (!ret) { // save level failed
1554 return false;
1555 }
1556
1557 RecentFiles::instance()->addFilePath(toQString(realPath), RecentFiles::Level);
1558
1559 TApp::instance()
1560 ->getPaletteController()
1561 ->getCurrentLevelPalette()
1562 ->notifyPaletteSwitched();
1563 return true;
1564 }
1565
1566 //===========================================================================
1567 // IoCmd::saveLevel()
1568 //---------------------------------------------------------------------------
1569
saveLevel()1570 bool IoCmd::saveLevel() {
1571 TApp *app = TApp::instance();
1572 TXshSimpleLevel *sl =
1573 dynamic_cast<TXshSimpleLevel *>(app->getCurrentLevel()->getLevel());
1574 if (!sl) return false;
1575 if (sl->getPath() == TFilePath()) return false;
1576 TFilePath path =
1577 app->getCurrentScene()->getScene()->decodeFilePath(sl->getPath());
1578 if (path == TFilePath()) return false;
1579 if (path.getWideString()[0] == L'+') return false;
1580 if (!path.isAbsolute()) return false;
1581
1582 if (!saveLevel(path, sl, true)) return false;
1583
1584 sl->setDirtyFlag(false);
1585 // for update title bar
1586 app->getCurrentLevel()->notifyLevelChange();
1587 return true;
1588 }
1589
1590 //===========================================================================
1591 // IoCmd::saveLevel(levelPath, simpleLevel, overwrite)
1592 //---------------------------------------------------------------------------
1593
saveLevel(const TFilePath & fp,TXshSimpleLevel * sl,bool overwrite)1594 bool IoCmd::saveLevel(const TFilePath &fp, TXshSimpleLevel *sl,
1595 bool overwrite) {
1596 assert(sl);
1597 bool fileDoesExist = TSystem::doesExistFileOrLevel(fp);
1598 if (!overwrite && fileDoesExist) {
1599 QString question;
1600 question = QObject::tr(
1601 "The level %1 already exists.\nDo you want to overwrite it?")
1602 .arg(toQString(fp));
1603 int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
1604 QObject::tr("Cancel"), 0);
1605 if (ret == 2 || ret == 0) return false;
1606 }
1607
1608 bool overwritePalette = false;
1609 // Confirmation of Overwrite palette
1610 // open dialog IF 1) the level is dirty, and 2) confirmation of overwrite
1611 // palette haven't been asked
1612 // for PLI file, do nothing
1613 if (sl->getPalette() && sl->getPalette()->getAskOverwriteFlag() &&
1614 sl->getPath().getType() != "pli") {
1615 /*-- ファイルが存在しない場合はパレットも必ず保存する --*/
1616 if (!fileDoesExist)
1617 overwritePalette = true;
1618 else {
1619 QString question;
1620 question =
1621 "Palette " +
1622 QString::fromStdWString(sl->getPalette()->getPaletteName()) +
1623 ".tpl has been modified. Do you want to overwrite palette as well ?";
1624 int ret =
1625 DVGui::MsgBox(question, QObject::tr("Overwrite Palette") /*ret = 1*/,
1626 QObject::tr("Don't Overwrite Palette") /*ret = 2*/, 0);
1627 if (ret == 1) overwritePalette = true;
1628 }
1629 }
1630
1631 QApplication::setOverrideCursor(Qt::WaitCursor);
1632 try {
1633 sl->save(fp, TFilePath(), overwritePalette);
1634 } catch (TSystemException se) {
1635 QApplication::restoreOverrideCursor();
1636 DVGui::warning(QString::fromStdWString(se.getMessage()));
1637 return false;
1638 } catch (...) {
1639 QApplication::restoreOverrideCursor();
1640 DVGui::error(QObject::tr("Couldn't save %1").arg(toQString(fp)));
1641 return false;
1642 }
1643 IconGenerator::instance()->invalidate(fp);
1644 FileBrowser::refreshFolder(fp.getParentDir());
1645 History::instance()->addItem(fp);
1646
1647 if (sl->getPalette()) {
1648 if (overwritePalette || sl->getPath().getType() == "pli")
1649 sl->getPalette()->setDirtyFlag(false);
1650 else // ask only once for save palette
1651 sl->getPalette()->setAskOverwriteFlag(false);
1652 }
1653
1654 RecentFiles::instance()->addFilePath(toQString(fp), RecentFiles::Level);
1655 QApplication::restoreOverrideCursor();
1656 TApp::instance()->getCurrentLevel()->notifyLevelTitleChange();
1657 TApp::instance()
1658 ->getPaletteController()
1659 ->getCurrentLevelPalette()
1660 ->notifyPaletteTitleChanged();
1661 return true;
1662 }
1663
1664 //===========================================================================
1665 // IoCmd::saveLevel(simpleLevel)
1666 //---------------------------------------------------------------------------
1667
saveLevel(TXshSimpleLevel * sl)1668 bool IoCmd::saveLevel(TXshSimpleLevel *sl) {
1669 return saveLevel(sl->getPath(), sl, true);
1670 }
1671
1672 //===========================================================================
1673 // IoCmd::saveAll()
1674 //---------------------------------------------------------------------------
1675
saveAll()1676 bool IoCmd::saveAll() {
1677 // try to save as much as possible
1678 // if anything is wrong, return false
1679 bool result = saveScene();
1680
1681 TApp *app = TApp::instance();
1682 ToonzScene *scene = app->getCurrentScene()->getScene();
1683 bool untitled = scene->isUntitled();
1684 SceneResources resources(scene, 0);
1685 resources.save(scene->getScenePath());
1686 resources.updatePaths();
1687
1688 // for update title bar
1689 app->getCurrentLevel()->notifyLevelTitleChange();
1690 app->getCurrentPalette()->notifyPaletteTitleChanged();
1691 if (untitled) scene->setUntitled();
1692 return result;
1693 }
1694
1695 //===========================================================================
1696 // IoCmd::saveNonSceneFiles()
1697 //---------------------------------------------------------------------------
1698
saveNonSceneFiles()1699 void IoCmd::saveNonSceneFiles() {
1700 // try to save non scene files
1701
1702 TApp *app = TApp::instance();
1703 ToonzScene *scene = app->getCurrentScene()->getScene();
1704 bool untitled = scene->isUntitled();
1705 SceneResources resources(scene, 0);
1706 resources.save(scene->getScenePath());
1707 if (untitled) scene->setUntitled();
1708 resources.updatePaths();
1709
1710 // for update title bar
1711 app->getCurrentLevel()->notifyLevelTitleChange();
1712 app->getCurrentPalette()->notifyPaletteTitleChanged();
1713 }
1714
1715 //===========================================================================
1716 // IoCmd::saveSound(soundPath, soundColumn, overwrite)
1717 //---------------------------------------------------------------------------
1718
saveSound(const TFilePath & fp,TXshSoundLevel * sl,bool overwrite)1719 bool IoCmd::saveSound(const TFilePath &fp, TXshSoundLevel *sl, bool overwrite) {
1720 if (!overwrite && TSystem::doesExistFileOrLevel(fp)) {
1721 QString question;
1722 question =
1723 QObject::tr(
1724 "The soundtrack %1 already exists.\nDo you want to overwrite it?")
1725 .arg(toQString(fp));
1726 int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
1727 QObject::tr("Cancel"), 0);
1728 if (ret == 2 || ret == 0) return false;
1729 }
1730 try {
1731 sl->save(fp);
1732 } catch (...) {
1733 DVGui::error(QObject::tr("Couldn't save %1").arg(toQString(fp)));
1734 return false;
1735 }
1736 QApplication::setOverrideCursor(Qt::WaitCursor);
1737 FileBrowser::refreshFolder(fp.getParentDir());
1738 History::instance()->addItem(fp);
1739 QApplication::restoreOverrideCursor();
1740 return true;
1741 }
1742
1743 //===========================================================================
1744 // IoCmd::saveSound(soundColumn)
1745 //---------------------------------------------------------------------------
1746
saveSound(TXshSoundLevel * sl)1747 bool IoCmd::saveSound(TXshSoundLevel *sl) {
1748 return saveSound(sl->getPath(), sl, true);
1749 }
1750
1751 //=========================================================================
1752 // IoCmd::loadScene(scene, scenePath, import)
1753 //---------------------------------------------------------------------------
1754
loadScene(ToonzScene & scene,const TFilePath & scenePath,bool import)1755 bool IoCmd::loadScene(ToonzScene &scene, const TFilePath &scenePath,
1756 bool import) {
1757 if (!TSystem::doesExistFileOrLevel(scenePath)) return false;
1758 scene.load(scenePath);
1759 // import if needed
1760 TProjectManager *pm = TProjectManager::instance();
1761 TProjectP currentProject = pm->getCurrentProject();
1762 if (!scene.getProject()) return false;
1763 if (scene.getProject()->getProjectPath() !=
1764 currentProject->getProjectPath()) {
1765 ResourceImportDialog resourceLoader;
1766 // resourceLoader.setImportEnabled(true);
1767 ResourceImporter importer(&scene, currentProject.getPointer(),
1768 resourceLoader);
1769 SceneResources resources(&scene, scene.getXsheet());
1770 resources.accept(&importer);
1771 scene.setScenePath(importer.getImportedScenePath());
1772 scene.setProject(currentProject.getPointer());
1773 }
1774 return true;
1775 }
1776
1777 //===========================================================================
1778 // IoCmd::loadScene(scenePath)
1779 //---------------------------------------------------------------------------
1780
loadScene(const TFilePath & path,bool updateRecentFile,bool checkSaveOldScene)1781 bool IoCmd::loadScene(const TFilePath &path, bool updateRecentFile,
1782 bool checkSaveOldScene) {
1783 RenderingSuspender suspender;
1784
1785 if (checkSaveOldScene)
1786 if (!saveSceneIfNeeded(QApplication::tr("Load Scene"))) return false;
1787 assert(!path.isEmpty());
1788 TFilePath scenePath = path;
1789 bool importScene = false;
1790 bool isXdts = scenePath.getType() == "xdts";
1791 if (scenePath.getType() == "") scenePath = scenePath.withType("tnz");
1792 if (scenePath.getType() != "tnz" && !isXdts) {
1793 QString msg;
1794 msg = QObject::tr("File %1 doesn't look like a TOONZ Scene")
1795 .arg(QString::fromStdWString(scenePath.getWideString()));
1796 DVGui::error(msg);
1797 return false;
1798 }
1799 if (!TSystem::doesExistFileOrLevel(scenePath)) return false;
1800
1801 TFilePath scenePathTemp(scenePath.getWideString() +
1802 QString(".tmp").toStdWString());
1803 if (TSystem::doesExistFileOrLevel(scenePathTemp)) {
1804 QString question =
1805 QObject::tr(
1806 "A prior save of Scene '%1' was critically interupted. \n\
1807 \nA partial save file was generated and changes may be manually salvaged from '%2'.\n\
1808 \nDo you wish to continue loading the last good save or stop and try to salvage the prior save?")
1809 .arg(QString::fromStdWString(scenePath.getWideString()))
1810 .arg(QString::fromStdWString(scenePathTemp.getWideString()));
1811 QString continueAnswer = QObject::tr("Continue");
1812 QString cancelAnswer = QObject::tr("Cancel");
1813 int ret = DVGui::MsgBox(question, continueAnswer, cancelAnswer, 0);
1814 if (ret == 2)
1815 return false;
1816 else
1817 TSystem::removeFileOrLevel(scenePathTemp);
1818 }
1819
1820 TProjectManager *pm = TProjectManager::instance();
1821 TProjectP sceneProject = pm->loadSceneProject(scenePath);
1822 if (!sceneProject) {
1823 QString msg;
1824 msg = QObject::tr(
1825 "It is not possible to load the scene %1 because it does not "
1826 "belong to any project.")
1827 .arg(QString::fromStdWString(scenePath.getWideString()));
1828 DVGui::warning(msg);
1829 }
1830 if (sceneProject && !sceneProject->isCurrent()) {
1831 QString currentProjectName = QString::fromStdWString(
1832 pm->getCurrentProject()->getName().getWideString());
1833 QString sceneProjectName =
1834 QString::fromStdWString(sceneProject->getName().getWideString());
1835
1836 /*QString question = "The Scene '"
1837 + QString::fromStdWString(scenePath.getWideString())
1838 + "' belongs to project '" + sceneProjectName + "'.\n"
1839 + "What do you want to do?";*/
1840 QString question =
1841 QObject::tr(
1842 "The Scene '%1' belongs to project '%2'.\nWhat do you want to do?")
1843 .arg(QString::fromStdWString(scenePath.getWideString()))
1844 .arg(sceneProjectName);
1845 QString importAnswer = QObject::tr("Import Scene");
1846 QString switchProjectAnswer = QObject::tr("Change Project");
1847 QString cancelAnswer = QObject::tr("Cancel");
1848 int ret = DVGui::MsgBox(question, importAnswer, switchProjectAnswer,
1849 cancelAnswer, 0);
1850 if (ret == 3 || ret == 0) {
1851 newScene();
1852 return false;
1853 }
1854 if (ret == 2)
1855 pm->setCurrentProjectPath(sceneProject->getProjectPath());
1856 else
1857 importScene = true;
1858 }
1859 QApplication::setOverrideCursor(Qt::WaitCursor);
1860
1861 TUndoManager::manager()->reset();
1862 IconGenerator::instance()->clearRequests();
1863 IconGenerator::instance()->clearSceneIcons();
1864 ImageManager::instance()->clear();
1865
1866 CacheFxCommand::instance()->onNewScene();
1867
1868 #ifdef USE_SQLITE_HDPOOL
1869 // INTERMEDIATE CACHE RESULTS MANAGEMENT: Clear all resources not accessed in
1870 // the last 2 sessions
1871 TCacheResourcePool::instance()->clearAccessedAfterSessions(
1872 1); // 0 would be after this session
1873 #endif
1874
1875 ToonzScene *scene = new ToonzScene();
1876 TImageStyle::setCurrentScene(scene);
1877 printf("%s:%s Progressing:\n", __FILE__, __FUNCTION__);
1878 try {
1879 if (isXdts)
1880 XdtsIo::loadXdtsScene(scene, scenePath);
1881 else
1882 /*-- プログレス表示を行いながらLoad --*/
1883 scene->load(scenePath);
1884 // import if needed
1885 TProjectManager *pm = TProjectManager::instance();
1886 TProjectP currentProject = pm->getCurrentProject();
1887 if (!scene->getProject() || scene->getProject()->getProjectPath() !=
1888 currentProject->getProjectPath()) {
1889 ResourceImportDialog resourceLoader;
1890 // resourceLoader.setImportEnabled(true);
1891 ResourceImporter importer(scene, currentProject.getPointer(),
1892 resourceLoader);
1893 SceneResources resources(scene, scene->getXsheet());
1894 resources.accept(&importer);
1895 scene->setScenePath(importer.getImportedScenePath());
1896 scene->setProject(currentProject.getPointer());
1897 }
1898 VersionControlManager::instance()->setFrameRange(scene->getLevelSet());
1899 } catch (...) {
1900 printf("%s:%s Exception ...:\n", __FILE__, __FUNCTION__);
1901 QString msg;
1902 msg = QObject::tr(
1903 "There were problems loading the scene %1.\n Some files may be "
1904 "missing.")
1905 .arg(QString::fromStdWString(scenePath.getWideString()));
1906 DVGui::warning(msg);
1907 }
1908 printf("%s:%s end load:\n", __FILE__, __FUNCTION__);
1909 TProject *project = scene->getProject();
1910 if (!project) {
1911 project = new TProject();
1912 project->setFolder("project", scenePath);
1913 scene->setProject(project);
1914 }
1915 TApp *app = TApp::instance();
1916 app->getCurrentScene()->setScene(scene);
1917 app->getCurrentScene()->notifyNameSceneChange();
1918 app->getCurrentFrame()->setFrame(0);
1919 app->getCurrentColumn()->setColumnIndex(0);
1920 TPalette *palette = 0;
1921 if (app->getCurrentLevel() && app->getCurrentLevel()->getSimpleLevel())
1922 palette = app->getCurrentLevel()->getSimpleLevel()->getPalette();
1923 app->getCurrentPalette()->setPalette(palette);
1924 app->getCurrentXsheet()->notifyXsheetSoundChanged();
1925 app->getCurrentObject()->setIsSpline(false);
1926
1927 Previewer::clearAll();
1928 PreviewFxManager::instance()->reset();
1929 // updateCleanupSettingsPopup();
1930 /*- CleanupParameterの更新 -*/
1931 CleanupParameters *cp = scene->getProperties()->getCleanupParameters();
1932 CleanupParameters::GlobalParameters.assign(cp);
1933
1934 CacheFxCommand::instance()->onSceneLoaded();
1935
1936 #ifdef USE_SQLITE_HDPOOL
1937 TCacheResourcePool::instance()->setPath(
1938 QString::fromStdWString(
1939 ToonzFolder::getCacheRootFolder().getWideString()),
1940 QString::fromStdWString(project->getName().getWideName()),
1941 QString::fromStdWString(scene->getSceneName()));
1942 #endif
1943
1944 UnitParameters::setFieldGuideAspectRatio(
1945 scene->getProperties()->getFieldGuideAspectRatio());
1946 IconGenerator::instance()->invalidateSceneIcon();
1947 DvDirModel::instance()->refreshFolder(scenePath.getParentDir());
1948 // set dirty for xdts files since converted tnz is not yet saved
1949 TApp::instance()->getCurrentScene()->setDirtyFlag(isXdts);
1950 History::instance()->addItem(scenePath);
1951 if (updateRecentFile)
1952 RecentFiles::instance()->addFilePath(
1953 toQString(scenePath), RecentFiles::Scene,
1954 QString::fromStdString(scene->getProject()->getName().getName()));
1955 QApplication::restoreOverrideCursor();
1956
1957 int forbiddenLevelCount = 0;
1958 for (int i = 0; i < scene->getLevelSet()->getLevelCount(); i++) {
1959 TXshLevel *xl = scene->getLevelSet()->getLevel(i);
1960 if (xl && xl->getSimpleLevel() &&
1961 xl->getSimpleLevel()->getProperties()->isForbidden())
1962 forbiddenLevelCount++;
1963 }
1964 if (forbiddenLevelCount > 0) {
1965 QString msg;
1966 msg = QObject::tr(
1967 "There were problems loading the scene %1.\nSome levels have not "
1968 "been loaded because their version is not supported")
1969 .arg(QString::fromStdWString(scenePath.getWideString()));
1970 DVGui::warning(msg);
1971 }
1972
1973 bool exist = TSystem::doesExistFileOrLevel(
1974 scene->decodeFilePath(scene->getScenePath()));
1975 QAction *act = CommandManager::instance()->getAction(MI_RevertScene);
1976 if (act) act->setEnabled(exist);
1977
1978 // check if the output dpi is incompatible with pixels only mode
1979 if (Preferences::instance()->getPixelsOnly()) {
1980 TPointD dpi = scene->getCurrentCamera()->getDpi();
1981 if (!areAlmostEqual(dpi.x, Stage::standardDpi, 0.1) ||
1982 !areAlmostEqual(dpi.y, Stage::standardDpi, 0.1)) {
1983 QString question = QObject::tr(
1984 "This scene is incompatible with pixels only mode of the current "
1985 "OpenToonz version.\nWhat would you like to do?");
1986 QString turnOffPixelAnswer = QObject::tr("Turn off pixels only mode");
1987 QString resizeSceneAnswer =
1988 QObject::tr("Keep pixels only mode on and resize the scene");
1989 int ret =
1990 DVGui::MsgBox(question, turnOffPixelAnswer, resizeSceneAnswer, 0);
1991 if (ret == 0) {
1992 } // do nothing
1993 else if (ret == 1) { // Turn off pixels only mode
1994 Preferences::instance()->setValue(pixelsOnly, false);
1995 app->getCurrentScene()->notifyPixelUnitSelected(false);
1996 } else { // ret = 2 : Resize the scene
1997 TDimensionD camSize = scene->getCurrentCamera()->getSize();
1998 TDimension camRes(camSize.lx * Stage::standardDpi,
1999 camSize.ly * Stage::standardDpi);
2000 scene->getCurrentCamera()->setRes(camRes);
2001 app->getCurrentScene()->setDirtyFlag(true);
2002 app->getCurrentXsheet()->notifyXsheetChanged();
2003 }
2004 }
2005 }
2006
2007 // Check if the scene saved with the previous version AND the premultiply
2008 // option is set to PNG level setting
2009 if (scene->getVersionNumber() <
2010 VersionNumber(71, 1)) { // V1.4 = 71.0 , V1.5 = 71.1
2011 QStringList modifiedPNGLevelNames;
2012 std::vector<TXshLevel *> levels;
2013 scene->getLevelSet()->listLevels(levels);
2014 for (auto level : levels) {
2015 if (!level || !level->getSimpleLevel()) continue;
2016 TFilePath path = level->getPath();
2017 if (path.isEmpty() || path.getType() != "png") continue;
2018 if (level->getSimpleLevel()->getProperties()->doPremultiply()) {
2019 level->getSimpleLevel()->getProperties()->setDoPremultiply(false);
2020 modifiedPNGLevelNames.append(QString::fromStdWString(level->getName()));
2021 }
2022 }
2023 if (!modifiedPNGLevelNames.isEmpty()) {
2024 DVGui::info(QObject::tr("The Premultiply options in the following levels "
2025 "are disabled, since PNG files are premultiplied "
2026 "on loading in the current version: %1")
2027 .arg(modifiedPNGLevelNames.join(", ")));
2028 app->getCurrentScene()->setDirtyFlag(true);
2029 }
2030 }
2031
2032 printf("%s:%s loadScene() completed :\n", __FILE__, __FUNCTION__);
2033 return true;
2034 }
2035
2036 //===========================================================================
2037 // IoCmd::loadScene()
2038 //---------------------------------------------------------------------------
2039
loadScene()2040 bool IoCmd::loadScene() {
2041 TSelection *oldSelection =
2042 TApp::instance()->getCurrentSelection()->getSelection();
2043 FileSelection *fileSelection =
2044 dynamic_cast<FileSelection *>(TSelection::getCurrent());
2045 if (fileSelection) {
2046 std::vector<TFilePath> files;
2047 fileSelection->getSelectedFiles(files);
2048 if (files.size() == 1 && files[0] != TFilePath() &&
2049 files[0].getType() == "tnz")
2050 return loadScene(files[0]);
2051 }
2052
2053 static LoadScenePopup *popup = 0;
2054 if (!popup) {
2055 popup = new LoadScenePopup();
2056 }
2057 int ret = popup->exec();
2058 if (ret == QDialog::Accepted) {
2059 return true;
2060 } else {
2061 TApp::instance()->getCurrentSelection()->setSelection(oldSelection);
2062 return false;
2063 }
2064 }
2065 //===========================================================================
2066 // IoCmd::loadSubScene()
2067 //---------------------------------------------------------------------------
2068
loadSubScene()2069 bool IoCmd::loadSubScene() {
2070 TSelection *oldSelection =
2071 TApp::instance()->getCurrentSelection()->getSelection();
2072 FileSelection *fileSelection =
2073 dynamic_cast<FileSelection *>(TSelection::getCurrent());
2074
2075 if (fileSelection) {
2076 IoCmd::LoadResourceArguments args;
2077 {
2078 std::vector<TFilePath> filePaths;
2079 fileSelection->getSelectedFiles(filePaths);
2080
2081 args.resourceDatas.assign(filePaths.begin(), filePaths.end());
2082 }
2083
2084 if (args.resourceDatas.size() == 1 &&
2085 args.resourceDatas[0].m_path != TFilePath() &&
2086 args.resourceDatas[0].m_path.getType() == "tnz") {
2087 loadResources(args);
2088 return true;
2089 }
2090 } else {
2091 static LoadSubScenePopup *popup = 0;
2092 if (!popup) {
2093 popup = new LoadSubScenePopup();
2094 popup->addFilterType("tnz");
2095 }
2096 int ret = popup->exec();
2097 if (ret == QDialog::Accepted) {
2098 TApp::instance()->getCurrentScene()->setDirtyFlag(false);
2099 return true;
2100 } else {
2101 TApp::instance()->getCurrentSelection()->setSelection(oldSelection);
2102 return false;
2103 }
2104 }
2105 return false;
2106 }
2107
loadSubScene(const TFilePath & scenePath)2108 bool IoCmd::loadSubScene(const TFilePath &scenePath) {
2109 IoCmd::LoadResourceArguments args(scenePath);
2110
2111 if (args.resourceDatas.size() == 1 &&
2112 args.resourceDatas[0].m_path != TFilePath() &&
2113 args.resourceDatas[0].m_path.getType() == "tnz") {
2114 loadResources(args);
2115 return true;
2116 }
2117
2118 return false;
2119 }
2120
2121 std::vector<int>
2122 loadedPsdLevelIndex; // memorizza gli indici dei livelli già caricati
2123 // serve per identificare i subfolder caricati
2124 // Trovare un metodo alternativo.
2125
2126 //! Returns the number of actually loaded levels
createSubXSheetFromPSDFolder(IoCmd::LoadResourceArguments & args,TXsheet * xsh,int & col0,int psdLevelIndex,PsdSettingsPopup * popup)2127 static int createSubXSheetFromPSDFolder(IoCmd::LoadResourceArguments &args,
2128 TXsheet *xsh, int &col0,
2129 int psdLevelIndex,
2130 PsdSettingsPopup *popup) {
2131 assert(popup->isFolder(psdLevelIndex));
2132
2133 int row0 = 0;
2134 int &row1 = args.row1, &col1 = args.col1;
2135
2136 TApp *app = TApp::instance();
2137 ToonzScene *scene = app->getCurrentScene()->getScene();
2138
2139 TXshLevel *cl = scene->createNewLevel(CHILD_XSHLEVEL);
2140 assert(cl);
2141
2142 TXshChildLevel *childLevel = cl->getChildLevel();
2143 assert(childLevel);
2144
2145 TXsheet *childXsh = childLevel->getXsheet();
2146
2147 int count = 0, subCol0 = 0;
2148 for (int i = 0; i < popup->getFramesCount(psdLevelIndex); ++i) {
2149 if (popup->isSubFolder(psdLevelIndex, i)) {
2150 // se è un subfolder allora è un livello
2151 int levelIndex = popup->getSubfolderLevelIndex(psdLevelIndex, i);
2152 count += createSubXSheetFromPSDFolder(args, childXsh, subCol0, levelIndex,
2153 popup);
2154 } else {
2155 TFilePath psdpath = popup->getPsdFramePath(psdLevelIndex, i);
2156 TXshLevel *xl = 0;
2157 try {
2158 xl = ::loadResource(scene, psdpath, args.castFolder, row0, col0, row1,
2159 col1, false);
2160 } catch (TException &e) {
2161 error(QString::fromStdWString(e.getMessage()));
2162 }
2163 if (xl) {
2164 // lo importo nell'xsheet
2165 childXsh->exposeLevel(0, subCol0, xl);
2166 args.loadedLevels.push_back(xl);
2167
2168 ++subCol0, ++count;
2169 loadedPsdLevelIndex.push_back(psdLevelIndex);
2170 }
2171 }
2172 }
2173 if (childXsh) {
2174 int rowCount = childXsh->getFrameCount();
2175 int r;
2176 for (r = 0; r < rowCount; r++)
2177 xsh->setCell(r, col0, TXshCell(cl, TFrameId(r + 1)));
2178 col0++;
2179 }
2180 return count;
2181 }
2182
2183 // Load a psd file
2184 //! Returns the number of actually loaded levels
loadPSDResource(IoCmd::LoadResourceArguments & args,bool updateRecentFile,PsdSettingsPopup * popup)2185 static int loadPSDResource(IoCmd::LoadResourceArguments &args,
2186 bool updateRecentFile, PsdSettingsPopup *popup) {
2187 int &row0 = args.row0;
2188 int &col0 = args.col0;
2189 int &row1 = args.row1;
2190 int &col1 = args.col1;
2191
2192 int count = 0;
2193 TApp *app = TApp::instance();
2194 ToonzScene *scene = app->getCurrentScene()->getScene();
2195 TXsheet *xsh = scene->getXsheet();
2196 if (row0 == -1) row0 = app->getCurrentFrame()->getFrameIndex();
2197 if (col0 == -1) col0 = app->getCurrentColumn()->getColumnIndex();
2198
2199 TXshLevel *cl = 0;
2200 TXsheet *childXsh = 0;
2201 // if the option "expose in sub-xsheet" is ON"
2202 if (popup->subxsheet()) {
2203 cl = scene->createNewLevel(CHILD_XSHLEVEL);
2204 assert(cl);
2205 TXshChildLevel *childLevel = cl->getChildLevel();
2206 assert(childLevel);
2207 childXsh = childLevel->getXsheet();
2208 }
2209 int subCol0 = args.col0;
2210 loadedPsdLevelIndex.clear();
2211 // for each layer in psd
2212 for (int i = 0; i < popup->getPsdLevelCount(); i++) {
2213 if (popup->isFolder(i) && popup->getFolderOption() == 1) {
2214 if (find(loadedPsdLevelIndex.begin(), loadedPsdLevelIndex.end(), i) !=
2215 loadedPsdLevelIndex.end())
2216 continue;
2217 if (childXsh)
2218 count +=
2219 createSubXSheetFromPSDFolder(args, childXsh, subCol0, i, popup);
2220 else
2221 count += createSubXSheetFromPSDFolder(args, xsh, subCol0, i, popup);
2222 } else {
2223 TFilePath psdpath = popup->getPsdPath(i);
2224 TXshLevel *xl = 0;
2225
2226 try {
2227 xl = ::loadResource(scene, psdpath, args.castFolder, row0, col0, row1,
2228 col1, !popup->subxsheet());
2229 } catch (TException &e) {
2230 error(QString::fromStdWString(e.getMessage()));
2231 }
2232 if (xl) {
2233 // lo importo nell'xsheet
2234 if (popup->subxsheet() && childXsh) {
2235 childXsh->exposeLevel(0, subCol0, xl);
2236 }
2237 args.loadedLevels.push_back(xl);
2238 subCol0++;
2239 count++;
2240
2241 // move the current column to the right
2242 col0++;
2243 app->getCurrentColumn()->setColumnIndex(col0);
2244 }
2245 }
2246 }
2247 if (childXsh) {
2248 int rowCount = childXsh->getFrameCount();
2249 int r;
2250 for (r = 0; r < rowCount; r++)
2251 xsh->setCell(row0 + r, col0, TXshCell(cl, TFrameId(r + 1)));
2252 }
2253
2254 return count;
2255 }
2256
2257 //===========================================================================
2258 // IoCmd::loadResources(actualPaths[], castFolder, row, col)
2259 //---------------------------------------------------------------------------
2260
2261 typedef IoCmd::LoadResourceArguments::ScopedBlock LoadScopedBlock;
2262
2263 struct LoadScopedBlock::Data {
2264 std::unique_ptr<DVGui::ProgressDialog>
2265 m_progressDialog; //!< Progress dialog displayed on multiple paths.
2266 int m_loadedCount; //!< Number of loaded levels.
2267 bool m_hasSoundLevel; //!< Whether a sound level was loaded.
2268
2269 public:
DataLoadScopedBlock::Data2270 Data() : m_loadedCount(), m_hasSoundLevel() {}
2271 };
2272
2273 //-----------------------------------------------------------------------------
2274
ScopedBlock()2275 LoadScopedBlock::ScopedBlock() : m_data(new Data) {}
2276
2277 //-----------------------------------------------------------------------------
2278
~ScopedBlock()2279 LoadScopedBlock::~ScopedBlock() {
2280 if (m_data->m_loadedCount > 0) {
2281 TApp *app = TApp::instance();
2282
2283 app->getCurrentXsheet()->notifyXsheetChanged();
2284 if (m_data->m_hasSoundLevel)
2285 app->getCurrentXsheet()->notifyXsheetSoundChanged();
2286 app->getCurrentScene()->notifyCastChange();
2287 app->getCurrentScene()->setDirtyFlag(true);
2288 app->getCurrentTool()->onImageChanged(
2289 (TImage::Type)app->getCurrentImageType());
2290 }
2291 }
2292
2293 //-----------------------------------------------------------------------------
2294
progressDialog() const2295 DVGui::ProgressDialog &LoadScopedBlock::progressDialog() const {
2296 if (!m_data->m_progressDialog.get()) {
2297 m_data->m_progressDialog.reset(
2298 new DVGui::ProgressDialog("", QObject::tr("Cancel"), 0, 0));
2299 }
2300
2301 return *m_data->m_progressDialog;
2302 }
2303
2304 //=============================================================================
2305
loadResources(LoadResourceArguments & args,bool updateRecentFile,LoadScopedBlock * sb)2306 int IoCmd::loadResources(LoadResourceArguments &args, bool updateRecentFile,
2307 LoadScopedBlock *sb) {
2308 struct locals {
2309 static bool isDir(const LoadResourceArguments::ResourceData &rd) {
2310 return QFileInfo(rd.m_path.getQString()).isDir();
2311 }
2312 }; // locals
2313
2314 if (args.resourceDatas.empty()) return 0;
2315
2316 // Redirect to resource folders loading in case they're all dirs
2317 if (std::all_of(args.resourceDatas.begin(), args.resourceDatas.end(),
2318 locals::isDir))
2319 return loadResourceFolders(args, sb);
2320
2321 boost::optional<LoadScopedBlock> sb_;
2322 if (!sb) sb = (sb_ = boost::in_place()).get_ptr();
2323
2324 int &row0 = args.row0, &col0 = args.col0, &row1 = args.row1,
2325 &col1 = args.col1;
2326
2327 // Setup local variables
2328 TApp *app = TApp::instance();
2329 ToonzScene *scene = app->getCurrentScene()->getScene();
2330 TXsheet *xsh = scene->getXsheet();
2331 // use current frame/column if row/col is not set
2332 if (row0 == -1) row0 = app->getCurrentFrame()->getFrameIndex();
2333 if (col0 == -1) col0 = app->getCurrentColumn()->getColumnIndex();
2334
2335 int rCount = args.resourceDatas.size(), loadedCount = 0;
2336 bool isSoundLevel = false;
2337
2338 // show wait cursor in case of caching all images because it is time consuming
2339 if (args.cachingBehavior == LoadResourceArguments::ALL_ICONS_AND_IMAGES)
2340 QApplication::setOverrideCursor(Qt::WaitCursor);
2341
2342 // Initialize progress dialog
2343 DVGui::ProgressDialog *progressDialog =
2344 (rCount > 1) ? &sb->progressDialog() : 0;
2345
2346 if (progressDialog) {
2347 progressDialog->setModal(true);
2348 progressDialog->setMinimum(0);
2349 progressDialog->setMaximum(rCount);
2350 progressDialog->show();
2351 }
2352
2353 // Initialize import dialog
2354 ResourceImportDialog importDialog;
2355 if (args.importPolicy != LoadResourceArguments::ASK_USER) {
2356 importDialog.setImportEnabled(args.importPolicy ==
2357 LoadResourceArguments::IMPORT);
2358 }
2359
2360 std::vector<TFilePath> paths;
2361 int all = 0;
2362
2363 // Loop for all the resources to load
2364 for (int r = 0; r != rCount; ++r) {
2365 if (importDialog.aborted()) break;
2366
2367 QString origName =
2368 args.resourceDatas[r].m_path.withoutParentDir().getQString();
2369
2370 LoadResourceArguments::ResourceData rd(args.resourceDatas[r]);
2371 TFilePath &path = rd.m_path;
2372
2373 if (!rd.m_path.isLevelName())
2374 path = TFilePath(path.getLevelNameW()).withParentDir(path.getParentDir());
2375
2376 if (std::find(paths.begin(), paths.end(), path) != paths.end()) {
2377 if (!all) {
2378 QString question =
2379 QObject::tr(
2380 "File '%1' will reload level '%2' as a duplicate column in the "
2381 "xsheet.\n\nAllow duplicate?")
2382 .arg(origName)
2383 .arg(QString::fromStdString(path.getName()));
2384 QString Yes = QObject::tr("Allow");
2385 QString YesAll = QObject::tr("Allow All Dups");
2386 QString No = QObject::tr("No");
2387 QString NoAll = QObject::tr("No to All Dups");
2388 int ret = DVGui::MsgBox(question, Yes, YesAll, No, NoAll, 0);
2389 switch (ret) {
2390 case 2:
2391 all = 1; // YesAll
2392 case 1:
2393 break; // Yes
2394 case 4:
2395 all = 2; // NoAll
2396 case 3:
2397 continue;
2398 }
2399 } else if (all == 2)
2400 continue;
2401 }
2402 paths.push_back(path);
2403
2404 if (progressDialog) {
2405 if (progressDialog->wasCanceled())
2406 break;
2407 else {
2408 progressDialog->setLabelText(
2409 DVGui::ProgressDialog::tr("Loading \"%1\"...")
2410 .arg(path.getQString()));
2411 progressDialog->setValue(r);
2412
2413 QCoreApplication::processEvents();
2414 }
2415 }
2416
2417 bool isLastResource = (r == rCount - 1);
2418 importDialog.setIsLastResource(isLastResource);
2419
2420 bool isScene = (TFileType::getInfo(path) == TFileType::TOONZSCENE);
2421
2422 if (scene->isExternPath(path) || isScene) {
2423 // extern resource: import or link?
2424 int ret = importDialog.askImportQuestion(path);
2425 if (ret == ResourceImportDialog::A_CANCEL) break;
2426 }
2427
2428 // for the scene file
2429 TXshLevel *xl = 0;
2430 if (isScene) {
2431 TFilePath oldDstFolder = importDialog.getDstFolder();
2432 TFilePath dstFolder = (Preferences::instance()->isSubsceneFolderEnabled())
2433 ? TFilePath(path.getName())
2434 : TFilePath();
2435
2436 importDialog.setDstFolder(dstFolder);
2437 importDialog.setIsLastResource(false);
2438
2439 // load the scene as subXsheet
2440 try {
2441 xl = loadChildLevel(scene, path, row0, col0, importDialog);
2442 if (dstFolder != TFilePath())
2443 app->getCurrentScene()->notifyCastFolderAdded(
2444 scene->getLevelSet()->getDefaultFolder() + dstFolder);
2445 // increment the number of resources actually loaded
2446 ++loadedCount;
2447 // move the column to the right
2448 ++col0;
2449 // register the loaded level to args
2450 args.loadedLevels.push_back(xl);
2451 app->getCurrentXsheet()->notifyXsheetSoundChanged();
2452 } catch (...) {
2453 }
2454
2455 importDialog.setIsLastResource(isLastResource);
2456 importDialog.setDstFolder(oldDstFolder);
2457
2458 app->getCurrentColumn()->setColumnIndex(col0);
2459
2460 continue;
2461 }
2462 // for other level files
2463 else {
2464 try {
2465 path = importDialog.process(scene, 0, path);
2466 // path = scene->decodeFilePath(codedPath);
2467 } catch (std::string msg) {
2468 error(QString::fromStdString(msg));
2469 continue;
2470 }
2471
2472 if (importDialog.aborted()) break;
2473 }
2474 if (path.getType() == "psd") {
2475 static PsdSettingsPopup *popup = 0;
2476 if (!popup) {
2477 popup = new PsdSettingsPopup();
2478 }
2479 popup->setPath(path);
2480
2481 int ret = popup->exec();
2482 if (ret == 0) continue;
2483
2484 loadedCount += loadPSDResource(args, updateRecentFile, popup);
2485
2486 if (updateRecentFile)
2487 RecentFiles::instance()->addFilePath(
2488 toQString(scene->decodeFilePath(path)), RecentFiles::Level);
2489 } else {
2490 // reuse TFrameIds retrieved by FileBrowser
2491 std::vector<TFrameId> fIds;
2492 if ((int)args.frameIdsSet.size() > r) // if there is fIds to be reused
2493 {
2494 fIds = args.frameIdsSet[r];
2495 }
2496
2497 try {
2498 xl = ::loadResource(
2499 scene, rd, args.castFolder, row0, col0, row1, col1, args.expose,
2500 #if (__cplusplus > 199711L)
2501 std::move(fIds),
2502 #else
2503 fIds,
2504 #endif
2505 args.xFrom, args.xTo, args.levelName, args.step, args.inc,
2506 args.frameCount, args.doesFileActuallyExist);
2507 if (updateRecentFile) {
2508 RecentFiles::instance()->addFilePath(
2509 toQString(scene->decodeFilePath(path)), RecentFiles::Level);
2510 }
2511 } catch (TException &e) {
2512 error(QString::fromStdWString(e.getMessage()));
2513 }
2514 // if load success
2515 if (xl) {
2516 isSoundLevel = isSoundLevel || xl->getType() == SND_XSHLEVEL;
2517 // register the loaded level to args
2518 args.loadedLevels.push_back(xl);
2519 // increment the number of loaded resources
2520 ++loadedCount;
2521
2522 // load the image data of all frames to cache at the beginning
2523 if (args.cachingBehavior != LoadResourceArguments::ON_DEMAND) {
2524 TXshSimpleLevel *simpleLevel = xl->getSimpleLevel();
2525 if (simpleLevel && simpleLevel->getType() == TZP_XSHLEVEL) {
2526 bool cacheImagesAsWell =
2527 (args.cachingBehavior ==
2528 LoadResourceArguments::ALL_ICONS_AND_IMAGES);
2529 simpleLevel->loadAllIconsAndPutInCache(cacheImagesAsWell);
2530 }
2531 }
2532 }
2533 }
2534 }
2535
2536 if (loadedCount) app->getCurrentFrame()->setFrameIndex(row0);
2537
2538 sb->data().m_loadedCount += loadedCount;
2539 sb->data().m_hasSoundLevel = sb->data().m_hasSoundLevel || isSoundLevel;
2540
2541 // revert the cursor
2542 if (args.cachingBehavior == LoadResourceArguments::ALL_ICONS_AND_IMAGES)
2543 QApplication::restoreOverrideCursor();
2544
2545 return loadedCount;
2546 }
2547
2548 //===========================================================================
2549 // IoCmd::exposeLevel(simpleLevel, row, col)
2550 //---------------------------------------------------------------------------
2551
exposeLevel(TXshSimpleLevel * sl,int row,int col,bool insert,bool overWrite)2552 bool IoCmd::exposeLevel(TXshSimpleLevel *sl, int row, int col, bool insert,
2553 bool overWrite) {
2554 TApp *app = TApp::instance();
2555 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
2556 assert(xsh);
2557 std::vector<TFrameId> fids;
2558 sl->getFids(fids);
2559 return exposeLevel(sl, row, col, fids, insert, overWrite);
2560 }
2561
2562 //===========================================================================
2563 // IoCmd::exposeLevel(simpleLevel, row, col)
2564 //---------------------------------------------------------------------------
2565
exposeLevel(TXshSimpleLevel * sl,int row,int col,const std::vector<TFrameId> & fids,bool insert,bool overWrite)2566 bool IoCmd::exposeLevel(TXshSimpleLevel *sl, int row, int col,
2567 const std::vector<TFrameId> &fids, bool insert,
2568 bool overWrite) {
2569 assert(sl);
2570
2571 TApp *app = TApp::instance();
2572 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
2573 assert(xsh);
2574 int frameCount = fids.size();
2575 bool insertEmptyColumn = false;
2576 if (!insert && !overWrite)
2577 insertEmptyColumn = beforeCellsInsert(
2578 xsh, row, col, fids.size(), TXshColumn::toColumnType(sl->getType()));
2579 ExposeType type = eNone;
2580 if (insert) type = eShiftCells;
2581 if (overWrite) type = eOverWrite;
2582 ExposeLevelUndo *undo =
2583 new ExposeLevelUndo(sl, row, col, frameCount, insertEmptyColumn, type);
2584 xsh->exposeLevel(row, col, sl, fids, overWrite);
2585 undo->setFids(fids);
2586 TUndoManager::manager()->add(undo);
2587 app->getCurrentXsheet()->notifyXsheetChanged();
2588 return true;
2589 }
2590
2591 //===========================================================================
2592 // exposeComment
2593 //---------------------------------------------------------------------------
2594
exposeComment(int row,int & col,QList<QString> commentList,QString fileName)2595 bool IoCmd::exposeComment(int row, int &col, QList<QString> commentList,
2596 QString fileName) {
2597 TApp *app = TApp::instance();
2598 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
2599 TXshSoundTextColumn *textSoundCol = new TXshSoundTextColumn();
2600 textSoundCol->setXsheet(xsh);
2601 textSoundCol->createSoundTextLevel(row, commentList);
2602 bool columnInserted = beforeCellsInsert(xsh, row, col, commentList.size(),
2603 TXshColumn::eSoundTextType);
2604 xsh->insertColumn(col, textSoundCol);
2605
2606 // Setto il nome di dafult della colonna al nome del file magpie.
2607 TStageObject *obj = xsh->getStageObject(TStageObjectId::ColumnId(col));
2608 std::string str = fileName.toStdString();
2609 obj->setName(str);
2610
2611 TUndoManager::manager()->add(
2612 new ExposeCommentUndo(textSoundCol, col, columnInserted, fileName));
2613
2614 return true;
2615 }
2616
2617 //===========================================================================
2618 // importLipSync
2619 //---------------------------------------------------------------------------
2620
importLipSync(TFilePath levelPath,QList<TFrameId> frameList,QList<QString> commentList,QString fileName)2621 bool IoCmd::importLipSync(TFilePath levelPath, QList<TFrameId> frameList,
2622 QList<QString> commentList, QString fileName) {
2623 TApp *app = TApp::instance();
2624 int col = app->getCurrentColumn()->getColumnIndex();
2625 int row = app->getCurrentFrame()->getFrameIndex();
2626
2627 IoCmd::LoadResourceArguments args;
2628 IoCmd::LoadResourceArguments::ScopedBlock sb;
2629
2630 // Create text column
2631 IoCmd::exposeComment(row, col, commentList, fileName);
2632
2633 // Load Level
2634 args.resourceDatas.push_back(levelPath);
2635 args.expose = false;
2636
2637 if (!IoCmd::loadResources(args, false, &sb)) {
2638 DVGui::error(QObject::tr("It is not possible to load the level %1")
2639 .arg(toQString(levelPath)));
2640 return false;
2641 }
2642
2643 // Expose Level in xsheet
2644 assert(args.loadedLevels.size() == 1);
2645 TXshLevel *loadedLevel = args.loadedLevels.at(0);
2646
2647 std::vector<TFrameId> fids;
2648 for (int i = 0; i < frameList.size(); i++) fids.push_back(frameList.at(i));
2649
2650 if (!IoCmd::exposeLevel(loadedLevel->getSimpleLevel(), row, col, fids)) {
2651 DVGui::error(QObject::tr("It is not possible to load the level %1")
2652 .arg(toQString(levelPath)));
2653 return false;
2654 }
2655
2656 return true;
2657 }
2658
2659 //===========================================================================
2660 // If the scene will be saved in the different folder, check out the scene
2661 // cast.
2662 // if the cast contains the level specified with $scenefolder alias,
2663 // open a warning popup notifying that such level will lose link.
2664 // return false if cancelled.
takeCareSceneFolderItemsOnSaveSceneAs(ToonzScene * scene,const TFilePath & newPath,TXsheet * subxsh,QHash<TXshLevel *,TFilePath> & orgLevelPaths)2665 bool IoCmd::takeCareSceneFolderItemsOnSaveSceneAs(
2666 ToonzScene *scene, const TFilePath &newPath, TXsheet *subxsh,
2667 QHash<TXshLevel *, TFilePath> &orgLevelPaths) {
2668 auto setPathToLevel = [&](TXshLevel *level, TFilePath fp) {
2669 // in case of saving subxsheet, the current scene will not be switched to
2670 // the saved one
2671 // so the level paths are needed to be reverted after saving
2672 if (subxsh) orgLevelPaths.insert(level, level->getPath());
2673 if (TXshSimpleLevel *sil = level->getSimpleLevel())
2674 sil->setPath(fp, true);
2675 else if (TXshPaletteLevel *pal = level->getPaletteLevel())
2676 pal->setPath(fp);
2677 else if (TXshSoundLevel *sol = level->getSoundLevel())
2678 sol->setPath(fp);
2679 };
2680
2681 TFilePath oldSceneFolder =
2682 scene->decodeFilePath(scene->getScenePath()).getParentDir();
2683 TFilePath newSceneFolder = scene->decodeFilePath(newPath).getParentDir();
2684
2685 // in case of saving in the same folder
2686 if (oldSceneFolder == newSceneFolder) return true;
2687
2688 TLevelSet *levelSet = scene->getLevelSet();
2689 std::vector<TXshLevel *> levels;
2690
2691 // in case of saving subxsheet, checking only used levels.
2692 if (subxsh) {
2693 std::set<TXshLevel *> saveSet;
2694 subxsh->getUsedLevels(saveSet);
2695 levels = std::vector<TXshLevel *>(saveSet.begin(), saveSet.end());
2696 }
2697 // in case of saving the scene (i.e. top xsheet)
2698 else
2699 levelSet->listLevels(levels);
2700
2701 QList<TXshLevel *> sceneFolderLevels;
2702 QString str;
2703 int count = 0;
2704 for (TXshLevel *level : levels) {
2705 if (!level->getPath().isEmpty() &&
2706 TFilePath("$scenefolder").isAncestorOf(level->getPath())) {
2707 TFilePath levelFullPath = scene->decodeFilePath(level->getPath());
2708 // check if the path can be re-coded with the new scene folder path
2709 if (newSceneFolder.isAncestorOf(levelFullPath)) {
2710 // just replace the path without warning
2711 TFilePath fp =
2712 TFilePath("$scenefolder") + (levelFullPath - newSceneFolder);
2713 setPathToLevel(level, fp);
2714 }
2715 // if re-coding is not possible, then it needs to ask user's preference
2716 else {
2717 sceneFolderLevels.append(level);
2718 if (count < 10) {
2719 str.append(" " + QString::fromStdWString(level->getName()) + " (" +
2720 level->getPath().getQString() + ")\n");
2721 }
2722 count++;
2723 }
2724 }
2725 }
2726 // list maximum 10 levels
2727 if (count > 10)
2728 str.append(QObject::tr(" + %1 more level(s) \n").arg(count - 10));
2729
2730 // in case there is no items with $scenefolder
2731 if (sceneFolderLevels.isEmpty()) return true;
2732
2733 str = QObject::tr(
2734 "The following level(s) use path with $scenefolder alias.\n\n") +
2735 str +
2736 QObject::tr(
2737 "\nThey will not be opened properly when you load the "
2738 "scene next time.\nWhat do you want to do?");
2739
2740 int ret = DVGui::MsgBox(
2741 str, QObject::tr("Copy the levels to correspondent paths"),
2742 QObject::tr("Decode all $scenefolder aliases"),
2743 QObject::tr("Save the scene only"), QObject::tr("Cancel"), 0);
2744 if (ret == 4 || ret == 0) return false;
2745
2746 if (ret == 1) { // copy the levels case
2747 enum OVERWRITEPOLICY { ASK, YES_FOR_ALL, NO_FOR_ALL } policy = ASK;
2748 for (int i = 0; i < sceneFolderLevels.size(); i++) {
2749 TXshLevel *level = sceneFolderLevels.at(i);
2750 TFilePath fp = level->getPath() - TFilePath("$scenefolder");
2751 fp = fp.withParentDir(newSceneFolder);
2752 // check the level existence
2753 if (TSystem::doesExistFileOrLevel(fp)) {
2754 bool overwrite = (policy == YES_FOR_ALL);
2755 if (policy == ASK) {
2756 QString question =
2757 QObject::tr(
2758 "File %1 already exists.\nDo you want to overwrite it?")
2759 .arg(fp.getQString());
2760 int ret_overwrite = DVGui::MsgBox(
2761 question, QObject::tr("Overwrite"),
2762 QObject::tr("Overwrite for All"), QObject::tr("Don't Overwrite"),
2763 QObject::tr("Don't Overwrite for All"), 0);
2764 if (ret_overwrite == 0) return false;
2765 if (ret_overwrite == 1)
2766 overwrite = true;
2767 else if (ret_overwrite == 2) {
2768 overwrite = true;
2769 policy = YES_FOR_ALL;
2770 } else if (ret_overwrite == 4)
2771 policy = NO_FOR_ALL;
2772 }
2773 if (!overwrite) continue;
2774 }
2775
2776 TFilePath srcFp = scene->decodeFilePath(level->getPath());
2777 if (!TSystem::copyFileOrLevel(fp, srcFp))
2778 warning(QObject::tr("Failed to overwrite %1").arg(fp.getQString()));
2779 // copy the palette as well
2780 if (level->getType() == TZP_XSHLEVEL) {
2781 if (!TSystem::copyFileOrLevel(fp.withType("tpl"),
2782 srcFp.withType("tpl")))
2783 warning(QObject::tr("Failed to overwrite %1")
2784 .arg(fp.withType("tpl").getQString()));
2785 }
2786 }
2787 } else if (ret == 2) { // decode $scenefolder aliases case
2788 Preferences::PathAliasPriority oldPriority =
2789 Preferences::instance()->getPathAliasPriority();
2790 Preferences::instance()->setValue(pathAliasPriority,
2791 Preferences::ProjectFolderOnly);
2792 for (int i = 0; i < sceneFolderLevels.size(); i++) {
2793 TXshLevel *level = sceneFolderLevels.at(i);
2794
2795 // decode and code again
2796 TFilePath fp =
2797 scene->codeFilePath(scene->decodeFilePath(level->getPath()));
2798 setPathToLevel(level, fp);
2799 }
2800 Preferences::instance()->setValue(pathAliasPriority, oldPriority);
2801 }
2802
2803 // Save the scene only case (ret == 3), do nothing
2804
2805 return true;
2806 }
2807
2808 //===========================================================================
2809 // Commands
2810 //---------------------------------------------------------------------------
2811
2812 class SaveSceneCommandHandler final : public MenuItemHandler {
2813 public:
SaveSceneCommandHandler()2814 SaveSceneCommandHandler() : MenuItemHandler(MI_SaveScene) {}
execute()2815 void execute() override { IoCmd::saveScene(); }
2816 } saveSceneCommandHandler;
2817
2818 //---------------------------------------------------------------------------
2819
2820 class SaveLevelCommandHandler final : public MenuItemHandler {
2821 public:
SaveLevelCommandHandler()2822 SaveLevelCommandHandler() : MenuItemHandler(MI_SaveLevel) {}
execute()2823 void execute() override {
2824 TXshSimpleLevel *sl = TApp::instance()->getCurrentLevel()->getSimpleLevel();
2825 if (!sl) {
2826 DVGui::warning(QObject::tr("No Current Level"));
2827 return;
2828 }
2829 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
2830 if (!scene) {
2831 DVGui::warning(QObject::tr("No Current Scene"));
2832 return; // non dovrebbe succedere mai
2833 }
2834 TFilePath levelPath = sl->getPath();
2835 levelPath = scene->decodeFilePath(levelPath);
2836 QString str = QString::fromStdWString(levelPath.getWideString());
2837 if (!(sl->getPath().isAbsolute() || !scene->isUntitled() ||
2838 (!sl->getPath().isAbsolute() && !str.contains("untitled")))) {
2839 error(QObject::tr("Save the scene first"));
2840 return;
2841 }
2842
2843 // reset the undo before save level
2844 if (Preferences::instance()->getBoolValue(resetUndoOnSavingLevel))
2845 TUndoManager::manager()->reset();
2846
2847 if (!IoCmd::saveLevel()) error(QObject::tr("Save level Failed"));
2848 }
2849 } saveLevelCommandHandler;
2850
2851 //-----------------------------------------------------------------------------
2852
2853 class SaveProjectTemplate final : public MenuItemHandler {
2854 public:
SaveProjectTemplate()2855 SaveProjectTemplate() : MenuItemHandler(MI_SaveDefaultSettings) {}
execute()2856 void execute() override {
2857 QString question;
2858 question =
2859 QObject::tr("Are you sure you want to save the Default Settings?");
2860 int ret =
2861 DVGui::MsgBox(question, QObject::tr("Save"), QObject::tr("Cancel"), 0);
2862 if (ret == 2 || ret == 0) return;
2863 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
2864 try {
2865 TProjectManager::instance()->saveTemplate(scene);
2866 } catch (TSystemException se) {
2867 DVGui::warning(QString::fromStdWString(se.getMessage()));
2868 return;
2869 }
2870 }
2871 } saveProjectTemplate;
2872
2873 //-----------------------------------------------------------------------------
2874
2875 class OpenRecentSceneFileCommandHandler final : public MenuItemHandler {
2876 public:
OpenRecentSceneFileCommandHandler()2877 OpenRecentSceneFileCommandHandler() : MenuItemHandler(MI_OpenRecentScene) {}
execute()2878 void execute() override {
2879 QAction *act = CommandManager::instance()->getAction(MI_OpenRecentScene);
2880 DVMenuAction *menu = dynamic_cast<DVMenuAction *>(act->menu());
2881 int index = menu->getTriggeredActionIndex();
2882 QString path =
2883 RecentFiles::instance()->getFilePath(index, RecentFiles::Scene);
2884 IoCmd::loadScene(TFilePath(path.toStdWString()), false);
2885 RecentFiles::instance()->moveFilePath(index, 0, RecentFiles::Scene);
2886 }
2887 } openRecentSceneFileCommandHandler;
2888
2889 //-----------------------------------------------------------------------------
2890
2891 class OpenRecentLevelFileCommandHandler final : public MenuItemHandler {
2892 public:
OpenRecentLevelFileCommandHandler()2893 OpenRecentLevelFileCommandHandler() : MenuItemHandler(MI_OpenRecentLevel) {}
execute()2894 void execute() override {
2895 QAction *act = CommandManager::instance()->getAction(MI_OpenRecentLevel);
2896 DVMenuAction *menu = dynamic_cast<DVMenuAction *>(act->menu());
2897 int index = menu->getTriggeredActionIndex();
2898 QString path =
2899 RecentFiles::instance()->getFilePath(index, RecentFiles::Level);
2900 IoCmd::LoadResourceArguments args(TFilePath(path.toStdWString()));
2901 IoCmd::loadResources(args, false);
2902
2903 RecentFiles::instance()->moveFilePath(index, 0, RecentFiles::Level);
2904 if (args.loadedLevels.empty()) {
2905 QString msg;
2906 msg = QObject::tr("It is not possible to load the %1 level.").arg(path);
2907 DVGui::error(msg);
2908 }
2909 }
2910 } openRecentLevelFileCommandHandler;
2911
2912 //-----------------------------------------------------------------------------
2913
2914 class ClearRecentSceneFileListCommandHandler final : public MenuItemHandler {
2915 public:
ClearRecentSceneFileListCommandHandler()2916 ClearRecentSceneFileListCommandHandler()
2917 : MenuItemHandler(MI_ClearRecentScene) {}
execute()2918 void execute() override {
2919 RecentFiles::instance()->clearRecentFilesList(RecentFiles::Scene);
2920 }
2921 } clearRecentSceneFileListCommandHandler;
2922
2923 //-----------------------------------------------------------------------------
2924
2925 class ClearRecentLevelFileListCommandHandler final : public MenuItemHandler {
2926 public:
ClearRecentLevelFileListCommandHandler()2927 ClearRecentLevelFileListCommandHandler()
2928 : MenuItemHandler(MI_ClearRecentLevel) {}
execute()2929 void execute() override {
2930 RecentFiles::instance()->clearRecentFilesList(RecentFiles::Level);
2931 }
2932 } clearRecentLevelFileListCommandHandler;
2933
2934 //-----------------------------------------------------------------------------
2935
2936 class RevertScene final : public MenuItemHandler {
2937 public:
RevertScene()2938 RevertScene() : MenuItemHandler(MI_RevertScene) {}
execute()2939 void execute() override {
2940 TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene();
2941 ToonzScene *scene = sceneHandle->getScene();
2942 assert(scene);
2943 TFilePath path = scene->getScenePath();
2944 TFilePath decodePath = scene->decodeFilePath(scene->getScenePath());
2945 if (!TSystem::doesExistFileOrLevel(decodePath)) {
2946 DVGui::warning(QObject::tr("The scene %1 doesn't exist.")
2947 .arg(toQString(decodePath)));
2948 return;
2949 }
2950 if (sceneHandle->getDirtyFlag()) {
2951 int ret = DVGui::MsgBox(
2952 QString(
2953 QObject::tr("Revert: the current scene has been modified.\nAre "
2954 "you sure you want to revert to previous version?")),
2955 QString(QObject::tr("Revert")), QString(QObject::tr("Cancel")));
2956 if (ret == 2 || ret == 0) return;
2957 }
2958 IoCmd::loadScene(path, false, false);
2959 }
2960 } RevertScene;
2961
2962 //=============================================================================
2963 // Overwrite palette
2964 //-----------------------------------------------------------------------------
2965 class OverwritePaletteCommandHandler final : public MenuItemHandler {
2966 public:
OverwritePaletteCommandHandler()2967 OverwritePaletteCommandHandler() : MenuItemHandler(MI_OverwritePalette) {}
2968
execute()2969 void execute() override {
2970 TXshLevel *level = TApp::instance()->getCurrentLevel()->getLevel();
2971 if (!level) {
2972 DVGui::warning("No current level.");
2973 return;
2974 }
2975 TXshSimpleLevel *sl = level->getSimpleLevel();
2976 TXshPaletteLevel *pl = level->getPaletteLevel();
2977 if (!sl && !pl) {
2978 DVGui::warning("Current level has no palette.");
2979 return;
2980 }
2981 /*-- SimpleLevel/PaletteLevelの場合毎にパレット/パスの取得の仕方を変える
2982 * --*/
2983 TPalette *palette;
2984 TFilePath palettePath;
2985 /*- SimpleLevelの場合 -*/
2986 if (sl) {
2987 palette = sl->getPalette();
2988 if (!palette) {
2989 DVGui::warning("No current palette");
2990 return;
2991 }
2992 if (sl->getPath().getType() == "pli")
2993 palettePath = sl->getPath();
2994 else if (sl->getType() & FULLCOLOR_TYPE)
2995 palettePath = FullColorPalette::instance()->getPath();
2996 else
2997 palettePath = sl->getPath().withType("tpl");
2998 }
2999 /*- PaletteLevelの場合 -*/
3000 else if (pl) {
3001 palette = pl->getPalette();
3002 if (!palette) {
3003 DVGui::warning("No current palette");
3004 return;
3005 }
3006 palettePath = pl->getPath();
3007 } else {
3008 DVGui::warning("This level is not SimpleLevel or PaletteLevel");
3009 return;
3010 }
3011
3012 QString question;
3013 int ret;
3014 if (sl && sl->getPath().getType() == "pli") {
3015 question = "Saving " + toQString(palettePath) +
3016 "\nThis command will ovewrite the level data as well. Are "
3017 "you sure ?";
3018 ret =
3019 DVGui::MsgBox(question, QObject::tr("OK"), QObject::tr("Cancel"), 0);
3020 } else {
3021 question = "Do you want to overwrite current palette to " +
3022 toQString(palettePath) + " ?";
3023 ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
3024 QObject::tr("Don't Overwrite"), 0);
3025 }
3026 if (ret == 2 || ret == 0) return;
3027
3028 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
3029 if (!palettePath.isAbsolute() && scene) {
3030 palettePath = scene->decodeFilePath(palettePath);
3031 }
3032
3033 if (sl && sl->getPath().getType() == "pli")
3034 sl->save(palettePath, TFilePath(), true);
3035 else if (sl && sl->getType() & FULLCOLOR_TYPE)
3036 FullColorPalette::instance()->savePalette(scene);
3037 else
3038 StudioPalette::instance()->save(palettePath, palette);
3039 /*- Dirtyフラグの変更 -*/
3040 if (sl)
3041 sl->getPalette()->setDirtyFlag(false);
3042 else if (pl)
3043 pl->getPalette()->setDirtyFlag(false);
3044
3045 if (Preferences::instance()->getBoolValue(resetUndoOnSavingLevel))
3046 TUndoManager::manager()->reset();
3047
3048 TApp::instance()
3049 ->getPaletteController()
3050 ->getCurrentLevelPalette()
3051 ->notifyPaletteDirtyFlagChanged();
3052 }
3053 } overwritePaletteCommandHandler;
3054
3055 //=============================================================================
3056 // Save scene and levels
3057 //-----------------------------------------------------------------------------
3058 class SaveAllCommandHandler final : public MenuItemHandler {
3059 public:
SaveAllCommandHandler()3060 SaveAllCommandHandler() : MenuItemHandler(MI_SaveAll) {}
execute()3061 void execute() override { IoCmd::saveAll(); }
3062 } saveAllCommandHandler;
3063
3064 //=============================================================================
3065 // Save all levels
3066 //-----------------------------------------------------------------------------
3067 class SaveAllLevelsCommandHandler : public MenuItemHandler {
3068 public:
SaveAllLevelsCommandHandler()3069 SaveAllLevelsCommandHandler() : MenuItemHandler(MI_SaveAllLevels) {}
execute()3070 void execute() { IoCmd::saveNonSceneFiles(); }
3071 } saveAllLevelsCommandHandler;
3072