1
2
3 #include "filebrowserpopup.h"
4
5 // Tnz6 includes
6 #include "menubarcommandids.h"
7 #include "iocommand.h"
8 #include "exportlevelcommand.h"
9 #include "filebrowser.h"
10 #include "tapp.h"
11 #include "filebrowsermodel.h"
12 #include "formatsettingspopups.h"
13 #include "magpiefileimportpopup.h"
14 #include "columnselection.h"
15 #include "convertpopup.h"
16 #include "matchline.h"
17 #include "colormodelbehaviorpopup.h"
18
19 // TnzQt includes
20 #include "toonzqt/gutil.h"
21 #include "toonzqt/icongenerator.h"
22 #include "toonzqt/colorfield.h"
23 #include "toonzqt/tselectionhandle.h"
24
25 // TnzLib includes
26 #include "toonz/tscenehandle.h"
27 #include "toonz/tpalettehandle.h"
28 #include "toonz/txshlevelhandle.h"
29 #include "toonz/txsheethandle.h"
30 #include "toonz/palettecontroller.h"
31 #include "toonz/studiopalette.h"
32 #include "toonz/toonzscene.h"
33 #include "toonz/tproject.h"
34 #include "toonz/txshcell.h"
35 #include "toonz/txshsimplelevel.h"
36 #include "toonz/tcamera.h"
37 #include "toonz/sceneproperties.h"
38 #include "toonz/tstageobjecttree.h"
39 #include "toonz/txshleveltypes.h"
40 // specify in the preference whether to replace the level after saveLevelAs
41 // command
42 #include "toonz/preferences.h"
43 #include "toonz/tcolumnhandle.h"
44 #include "toonz/tframehandle.h"
45 #include "toonz/levelset.h"
46 #include "toonz/palettecmd.h"
47 #include "toonz/stage.h"
48
49 // TnzCore includes
50 #include "tsystem.h"
51 #include "tiio.h"
52 #include "tlevel_io.h"
53 #include "tundo.h"
54
55 // Qt includes
56 #include <QVBoxLayout>
57 #include <QHBoxLayout>
58 #include <QGridLayout>
59 #include <QFrame>
60 #include <QPushButton>
61 #include <QLabel>
62 #include <QComboBox>
63 #include <QGroupBox>
64 #include <QCoreApplication>
65 #include <QMainWindow>
66 #include <QApplication>
67
68 //***********************************************************************************
69 // FileBrowserPopup implementation
70 //***********************************************************************************
71
FileBrowserPopup(const QString & title,Options options,QString applyButtonTxt,QWidget * customWidget)72 FileBrowserPopup::FileBrowserPopup(const QString &title, Options options,
73 QString applyButtonTxt,
74 QWidget *customWidget)
75 : QDialog(TApp::instance()->getMainWindow())
76 , m_isDirectoryOnly(false)
77 , m_multiSelectionEnabled(options & MULTISELECTION)
78 , m_forSaving(options & FOR_SAVING)
79 , m_dialogSize(800, 600)
80 , m_customWidget(customWidget) {
81 setWindowTitle(title);
82 setModal(false);
83
84 m_browser = new FileBrowser(this, 0, false, m_multiSelectionEnabled);
85 m_nameFieldLabel = new QLabel(tr("File name:"));
86 m_nameField = new DVGui::LineEdit(this);
87 m_okButton = new QPushButton(tr("OK"), this);
88 m_cancelButton = new QPushButton(tr("Cancel"), this);
89 QPushButton *applyButton = 0;
90 if (options & WITH_APPLY_BUTTON)
91 applyButton = new QPushButton(
92 (applyButtonTxt.isEmpty()) ? tr("Apply") : applyButtonTxt, this);
93
94 std::list<std::vector<TFrameId>> tmp_list;
95 m_currentFIdsSet = tmp_list;
96
97 //-------------
98
99 m_okButton->setMaximumWidth(100);
100 m_okButton->setAutoDefault(false);
101 m_cancelButton->setMaximumWidth(100);
102 m_cancelButton->setAutoDefault(false);
103 if (applyButton) {
104 applyButton->setMaximumWidth(100);
105 applyButton->setAutoDefault(false);
106 }
107
108 // layout
109 if (!(options & CUSTOM_LAYOUT)) {
110 QVBoxLayout *mainLayout = new QVBoxLayout();
111 mainLayout->setMargin(0);
112 mainLayout->setSpacing(3);
113 {
114 mainLayout->addWidget(m_browser, 1);
115
116 QHBoxLayout *bottomLay = new QHBoxLayout();
117 bottomLay->setMargin(5);
118 bottomLay->setSpacing(3);
119 {
120 bottomLay->addWidget(m_nameFieldLabel, 0);
121 bottomLay->addWidget(m_nameField, 1);
122 }
123 mainLayout->addLayout(bottomLay);
124
125 if (m_customWidget) mainLayout->addWidget(m_customWidget);
126
127 QHBoxLayout *buttonsLay = new QHBoxLayout();
128 buttonsLay->setMargin(5);
129 buttonsLay->setSpacing(15);
130 {
131 buttonsLay->addStretch();
132 buttonsLay->addWidget(m_okButton);
133 if (applyButton) buttonsLay->addWidget(applyButton);
134 buttonsLay->addWidget(m_cancelButton);
135 }
136 mainLayout->addLayout(buttonsLay);
137 }
138 setLayout(mainLayout);
139 }
140
141 // Establish connections
142 bool ret = true;
143 ret =
144 ret && connect(m_okButton, SIGNAL(clicked()), this, SLOT(onOkPressed()));
145 ret = ret && connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(close()));
146 ret =
147 ret &&
148 connect(
149 m_browser,
150 SIGNAL(filePathsSelected(const std::set<TFilePath> &,
151 const std::list<std::vector<TFrameId>> &)),
152 this,
153 SLOT(onFilePathsSelected(const std::set<TFilePath> &,
154 const std::list<std::vector<TFrameId>> &)));
155 ret = ret && connect(m_browser, SIGNAL(filePathClicked(const TFilePath &)),
156 this, SIGNAL(filePathClicked(const TFilePath &)));
157 if (applyButton) {
158 ret = ret &&
159 connect(applyButton, SIGNAL(clicked()), this, SLOT(onApplyPressed()));
160 }
161 assert(ret);
162
163 resize(m_dialogSize);
164 /*- Qt5 でQDialogがParentWidgetの中心位置に来ない不具合を回避する -*/
165 QPoint dialogCenter = mapToGlobal(rect().center());
166 QPoint parentWindowCenter = TApp::instance()->getMainWindow()->mapToGlobal(
167 TApp::instance()->getMainWindow()->rect().center());
168 move(parentWindowCenter - dialogCenter);
169 }
170
171 //-----------------------------------------------------------------------------
172
setFilterTypes(const QStringList & typesList)173 void FileBrowserPopup::setFilterTypes(const QStringList &typesList) {
174 m_browser->setFilterTypes(typesList);
175 }
176
177 //-----------------------------------------------------------------------------
178
removeFilterType(const QString & type)179 void FileBrowserPopup::removeFilterType(const QString &type) {
180 m_browser->removeFilterType(type);
181 }
182
183 //-----------------------------------------------------------------------------
184
addFilterType(const QString & type)185 void FileBrowserPopup::addFilterType(const QString &type) {
186 m_browser->addFilterType(type);
187 }
188
189 //-----------------------------------------------------------------------------
190
setFileMode(bool isDirectoryOnly)191 void FileBrowserPopup::setFileMode(bool isDirectoryOnly) {
192 m_isDirectoryOnly = isDirectoryOnly;
193 if (isDirectoryOnly) {
194 m_nameFieldLabel->setText(tr("Folder name:"));
195 connect(m_browser, SIGNAL(treeFolderChanged(const TFilePath &)), this,
196 SLOT(onFilePathClicked(const TFilePath &)));
197 } else {
198 m_nameFieldLabel->setText(tr("File name:"));
199 disconnect(m_browser, SIGNAL(treeFolderChanged(const TFilePath &)), this,
200 SLOT(onFilePathClicked(const TFilePath &)));
201 }
202 }
203
204 //-----------------------------------------------------------------------------
205
setFolder(const TFilePath & folderPath)206 void FileBrowserPopup::setFolder(const TFilePath &folderPath) {
207 m_browser->setFolder(folderPath, true);
208 }
209
210 //-----------------------------------------------------------------------------
211
setFilename(const TFilePath & filename)212 void FileBrowserPopup::setFilename(const TFilePath &filename) {
213 m_nameField->setText(QString::fromStdWString(filename.getWideString()));
214 }
215
216 //-----------------------------------------------------------------------------
217
onOkPressed()218 void FileBrowserPopup::onOkPressed() {
219 const TFilePath &folder = m_browser->getFolder();
220
221 // Rebuild paths selection in case the text field has an explicit entry
222 if (!m_nameField->text().isEmpty()) {
223 const QString &str = m_nameField->text();
224 if (!isValidFileName(QFileInfo(str).baseName()) && !m_isDirectoryOnly) {
225 DVGui::error(
226 QObject::tr("A filename cannot be empty or contain any of the "
227 "following characters:\n \\ / : * ? \" < > |"));
228 return;
229 }
230 if (isReservedFileName_message(QFileInfo(str).baseName())) return;
231
232 m_selectedPaths.clear();
233 if (!m_isDirectoryOnly)
234 m_selectedPaths.insert(folder +
235 TFilePath(m_nameField->text().toStdWString()));
236 else
237 m_selectedPaths.insert(TFilePath(m_nameField->text().toStdWString()));
238 }
239
240 // Analyze and correct the paths selection
241 std::set<TFilePath> pathSet;
242
243 std::set<TFilePath>::const_iterator pt, pEnd(m_selectedPaths.end());
244 for (pt = m_selectedPaths.begin(); pt != pEnd; ++pt) {
245 if (folder == TFilePath()) {
246 // history // That means, TFilePath()
247 // represents
248 if (*pt == TFilePath() ||
249 !pt->isAbsolute()) // the History folder? Really? That's lame...
250 {
251 DVGui::error(tr("Invalid file"));
252 return;
253 }
254 } else {
255 if (!m_isDirectoryOnly)
256 pathSet.insert(*pt);
257 else
258 pathSet.insert(folder);
259 }
260
261 if (!m_multiSelectionEnabled) break;
262 }
263
264 m_browser->selectNone();
265
266 m_selectedPaths.swap(pathSet);
267 if (execute()) {
268 QCoreApplication::processEvents(); // <Solves a bug on XP... Bugzilla
269 // #6041>
270 accept(); // Tempted to remove the above - it should
271 } // NOT be here, maybe in the executes()...
272 }
273
274 //-----------------------------------------------------------------------------
275 /*! process without closing the browser
276 */
onApplyPressed()277 void FileBrowserPopup::onApplyPressed() {
278 TFilePath folder = m_browser->getFolder();
279 std::set<TFilePath> pathSet;
280 if (!m_nameField->text().isEmpty()) // if the user has written in the text
281 // field that wins on the item
282 // sselection!
283 {
284 m_selectedPaths.clear();
285 if (!m_isDirectoryOnly)
286 m_selectedPaths.insert(folder +
287 TFilePath(m_nameField->text().toStdString()));
288 else
289 m_selectedPaths.insert(TFilePath(m_nameField->text().toStdWString()));
290 }
291
292 std::set<TFilePath>::const_iterator it = m_selectedPaths.begin();
293 while (it != m_selectedPaths.end()) {
294 if (folder == TFilePath()) {
295 // history
296 if (*it == TFilePath() || !it->isAbsolute()) {
297 DVGui::error(tr("Invalid file"));
298 return;
299 }
300 } else {
301 if (!m_isDirectoryOnly)
302 pathSet.insert(*it);
303 else
304 pathSet.insert(folder);
305 }
306 if (!m_multiSelectionEnabled) break;
307 ++it;
308 }
309
310 m_browser->selectNone();
311
312 m_selectedPaths.swap(pathSet);
313 if (executeApply()) {
314 QCoreApplication::processEvents();
315 }
316 }
317 //-----------------------------------------------------------------------------
318
onFilePathClicked(const TFilePath & fp)319 void FileBrowserPopup::onFilePathClicked(const TFilePath &fp) {
320 std::set<TFilePath> app;
321 app.insert(fp);
322 std::list<std::vector<TFrameId>> tmp;
323 onFilePathsSelected(app, tmp);
324 }
325
326 //-----------------------------------------------------------------------------
327
onFilePathsSelected(const std::set<TFilePath> & paths,const std::list<std::vector<TFrameId>> & fIds)328 void FileBrowserPopup::onFilePathsSelected(
329 const std::set<TFilePath> &paths,
330 const std::list<std::vector<TFrameId>> &fIds) {
331 if (paths.size() == 0 && m_forSaving) return;
332
333 m_selectedPaths = paths;
334 m_currentFIdsSet = fIds;
335
336 if (paths.size() == 1) {
337 const TFilePath &fp = *paths.begin();
338 QString text;
339 if (!m_isDirectoryOnly)
340 text = QString::fromStdWString(fp.getLevelNameW());
341 else
342 text = QString::fromStdWString(m_browser->getFolder().getWideString());
343
344 m_nameField->setText(text);
345 } else
346 m_nameField->setText("");
347 }
348
349 //-----------------------------------------------------------------------------
350
onFilePathDoubleClicked(const TFilePath &)351 void FileBrowserPopup::onFilePathDoubleClicked(const TFilePath &) {
352 // do nothing by default
353 }
354
355 //-----------------------------------------------------------------------------
356
setOkText(const QString & text)357 void FileBrowserPopup::setOkText(const QString &text) {
358 m_okButton->setText(text);
359 // if the button label is "Save" then the browser is assumed as for saving
360 if (text == QObject::tr("Save")) m_forSaving = true;
361 }
362
363 //-----------------------------------------------------------------------------
364
hideEvent(QHideEvent * e)365 void FileBrowserPopup::hideEvent(QHideEvent *e) {
366 TSelectionHandle::getCurrent()->popSelection();
367 m_dialogSize = size();
368 move(pos());
369 resize(size());
370 }
371
372 //-----------------------------------------------------------------------------
373
showEvent(QShowEvent *)374 void FileBrowserPopup::showEvent(QShowEvent *) {
375 TSelectionHandle::getCurrent()->pushSelection();
376 m_selectedPaths.clear();
377 m_currentFIdsSet.clear();
378
379 TFilePath projectPath = TProjectManager::instance()->getCurrentProjectPath();
380 if (m_currentProjectPath != projectPath) {
381 m_currentProjectPath = projectPath;
382 initFolder();
383
384 // set initial folder of all browsers to $scenefolder when the scene folder
385 // mode is set in user preferences
386 if (Preferences::instance()->getPathAliasPriority() ==
387 Preferences::SceneFolderAlias) {
388 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
389 if (scene && !scene->isUntitled())
390 setFolder(scene->getScenePath().getParentDir());
391 }
392
393 m_nameField->update();
394 m_nameField->setFocus();
395 }
396 resize(m_dialogSize);
397 }
398
399 //-----------------------------------------------------------------------------
400 // utility function. Make the widget to be a child of modal file browser in
401 // order to allow control.
402
setModalBrowserToParent(QWidget * widget)403 void FileBrowserPopup::setModalBrowserToParent(QWidget *widget) {
404 if (!widget) return;
405 for (QWidget *pwidget : QApplication::topLevelWidgets()) {
406 if ((pwidget->isWindow()) && (pwidget->isModal()) &&
407 (pwidget->isVisible())) {
408 FileBrowserPopup *popup = qobject_cast<FileBrowserPopup *>(pwidget);
409 if (popup) {
410 // According to the description of QDialog;
411 // "setParent() function will clear the window flags specifying the
412 // window-system properties for the widget (in particular it will reset
413 // the Qt::Dialog flag)."
414 // So keep the window flags and set back after calling setParent().
415 Qt::WindowFlags flags = widget->windowFlags();
416 widget->setParent(pwidget);
417 widget->setWindowFlags(flags);
418 return;
419 }
420 }
421 }
422 }
423
424 //***********************************************************************************
425 // GenericLoadFilePopup implementation
426 //***********************************************************************************
427
GenericLoadFilePopup(const QString & title)428 GenericLoadFilePopup::GenericLoadFilePopup(const QString &title)
429 : FileBrowserPopup(title) {}
430
431 //-----------------------------------------------------------------------------
432
execute()433 bool GenericLoadFilePopup::execute() {
434 if (m_selectedPaths.empty()) return false;
435
436 const TFilePath &path = *m_selectedPaths.begin();
437 assert(!path.isEmpty()); // Should always be, see
438 // FileBrowserPopup::onOk..()
439 return TFileStatus(path).doesExist();
440 }
441
442 //-----------------------------------------------------------------------------
443
getPath()444 TFilePath GenericLoadFilePopup::getPath() {
445 return (exec() == QDialog::Rejected) ? TFilePath() : *m_selectedPaths.begin();
446 }
447
448 //***********************************************************************************
449 // GenericSaveFilePopup implementation
450 //***********************************************************************************
451
GenericSaveFilePopup(const QString & title)452 GenericSaveFilePopup::GenericSaveFilePopup(const QString &title)
453 : FileBrowserPopup(title, Options(FOR_SAVING)) {
454 connect(m_nameField, SIGNAL(returnPressedNow()), m_okButton,
455 SLOT(animateClick()));
456 }
457
458 //-----------------------------------------------------------------------------
459
execute()460 bool GenericSaveFilePopup::execute() {
461 if (m_selectedPaths.empty()) return false;
462
463 TFilePath path(*m_selectedPaths.begin());
464 assert(!path.isEmpty());
465
466 // In case the path is not coherent with the specified type filter,
467 // it means that the user specified it by typing and forgot the right type
468 // (yep, even if a DIFFERENT type was specified - next time do it right :P)
469 const QStringList &extList = m_browser->getFilterTypes();
470
471 if (!m_isDirectoryOnly &&
472 !extList.contains(QString::fromStdString(path.getType()))) {
473 path =
474 TFilePath(path.getWideString() + L"." + extList.first().toStdWString());
475 }
476
477 // Ask for user permission to overwrite if necessary
478 if (!m_isDirectoryOnly && TFileStatus(path).doesExist()) {
479 const QString &question =
480 QObject::tr("File %1 already exists.\nDo you want to overwrite it?")
481 .arg(toQString(path));
482
483 int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
484 QObject::tr("Cancel"));
485 if (ret == 0 || ret == 2) return false;
486 }
487
488 m_selectedPaths.clear();
489 m_selectedPaths.insert(path);
490
491 return true;
492 }
493
494 //-----------------------------------------------------------------------------
495
getPath()496 TFilePath GenericSaveFilePopup::getPath() {
497 return (exec() == QDialog::Rejected) ? TFilePath() : *m_selectedPaths.begin();
498 }
499
500 //=============================================================================
501 // LoadScenePopup
502
LoadScenePopup()503 LoadScenePopup::LoadScenePopup() : FileBrowserPopup(tr("Load Scene")) {
504 setOkText(tr("Load"));
505 addFilterType("tnz");
506 addFilterType("xdts");
507
508 // set the initial current path according to the current module
509 setInitialFolderByCurrentRoom();
510
511 connect(m_browser, SIGNAL(filePathDoubleClicked(const TFilePath &)), this,
512 SLOT(onFilePathDoubleClicked(const TFilePath &)));
513 }
514
execute()515 bool LoadScenePopup::execute() {
516 if (m_selectedPaths.empty()) return false;
517
518 const TFilePath &fp = *m_selectedPaths.begin();
519
520 if (fp.getType() != "tnz" && fp.getType() != "xdts") {
521 DVGui::error(toQString(fp) + tr(" is not a scene file."));
522 return false;
523 }
524
525 if (!TFileStatus(fp).doesExist()) {
526 DVGui::error(toQString(fp) + tr(" does not exist."));
527 return false;
528 }
529
530 return IoCmd::loadScene(fp);
531 }
532
initFolder()533 void LoadScenePopup::initFolder() { setInitialFolderByCurrentRoom(); }
534
setInitialFolderByCurrentRoom()535 void LoadScenePopup::setInitialFolderByCurrentRoom() {
536 QString roomName = TApp::instance()->getCurrentRoomName();
537 TProjectP project = TProjectManager::instance()->getCurrentProject();
538 TFilePath scenePath;
539 if (roomName == "Cleanup" || roomName == "InknPaint")
540 scenePath = project->getFolder(TProject::Drawings, true);
541 else if (roomName == "PltEdit")
542 scenePath = project->getFolder(TProject::Palettes, true);
543 else
544 scenePath = project->getFolder(TProject::Scenes, true);
545 setFolder(scenePath);
546 }
547
showEvent(QShowEvent * e)548 void LoadScenePopup::showEvent(QShowEvent *e) {
549 m_nameField->clear();
550 FileBrowserPopup::showEvent(e);
551 }
552
onFilePathDoubleClicked(const TFilePath & path)553 void LoadScenePopup::onFilePathDoubleClicked(const TFilePath &path) {
554 Q_UNUSED(path);
555 onOkPressed();
556 }
557
558 //=============================================================================
559 // LoadSubScenePopup
560
LoadSubScenePopup()561 LoadSubScenePopup::LoadSubScenePopup()
562 : FileBrowserPopup(tr("Load Sub-Xsheet")) {
563 setOkText(tr("Load"));
564 addFilterType("tnz");
565 TFilePath scenePath =
566 TProjectManager::instance()->getCurrentProject()->getScenesPath();
567 setFolder(scenePath);
568 }
569
execute()570 bool LoadSubScenePopup::execute() {
571 if (m_selectedPaths.empty()) return false;
572
573 const TFilePath &fp = *m_selectedPaths.begin();
574
575 if (fp.getType() != "tnz") {
576 DVGui::error(toQString(fp) + tr(" is not a scene file."));
577 return false;
578 }
579
580 if (!TFileStatus(fp).doesExist()) {
581 DVGui::error(toQString(fp) + tr(" does not exist."));
582 return false;
583 }
584
585 return IoCmd::loadSubScene(fp);
586 }
587
initFolder()588 void LoadSubScenePopup::initFolder() {
589 setFolder(TProjectManager::instance()->getCurrentProject()->getScenesPath());
590 }
591
showEvent(QShowEvent * e)592 void LoadSubScenePopup::showEvent(QShowEvent *e) {
593 m_nameField->clear();
594 FileBrowserPopup::showEvent(e);
595 }
596
597 //=============================================================================
598 // SaveSceneAsPopup
599
SaveSceneAsPopup()600 SaveSceneAsPopup::SaveSceneAsPopup()
601 : FileBrowserPopup(tr("Save Scene"), Options(FOR_SAVING)) {
602 setOkText(tr("Save"));
603 addFilterType("tnz");
604 connect(m_nameField, SIGNAL(returnPressedNow()), m_okButton,
605 SLOT(animateClick()));
606 }
607
execute()608 bool SaveSceneAsPopup::execute() {
609 if (m_selectedPaths.empty()) return false;
610
611 const TFilePath &fp = *m_selectedPaths.begin();
612
613 if (isSpaceString(QString::fromStdString(
614 fp.getName()))) // Lol. Cmon! Really necessary?
615 return false;
616
617 return IoCmd::saveScene(fp, 0);
618 }
619
initFolder()620 void SaveSceneAsPopup::initFolder() {
621 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
622 if (!scene->isUntitled())
623 setFolder(scene->getScenePath().getParentDir());
624 else
625 setFolder(
626 TProjectManager::instance()->getCurrentProject()->getScenesPath());
627 }
628
629 //=============================================================================
630 // SaveSubSceneAsPopup
631
SaveSubSceneAsPopup()632 SaveSubSceneAsPopup::SaveSubSceneAsPopup()
633 : FileBrowserPopup(tr("Sub-xsheet"), Options(FOR_SAVING)) {
634 setOkText(tr("Save"));
635 connect(m_nameField, SIGNAL(returnPressedNow()), m_okButton,
636 SLOT(animateClick()));
637 }
638
execute()639 bool SaveSubSceneAsPopup::execute() {
640 if (m_selectedPaths.empty()) return false;
641
642 return IoCmd::saveScene(*m_selectedPaths.begin(), IoCmd::SAVE_SUBXSHEET);
643 }
644
initFolder()645 void SaveSubSceneAsPopup::initFolder() {
646 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
647 if (!scene->isUntitled())
648 setFolder(scene->getScenePath().getParentDir());
649 else
650 setFolder(
651 TProjectManager::instance()->getCurrentProject()->getScenesPath());
652 }
653
654 //=============================================================================
655 // LoadLevelPopup
656 namespace {
createShowButton(QWidget * parent)657 QPushButton *createShowButton(QWidget *parent) {
658 QPushButton *button = new QPushButton(parent);
659 button->setObjectName("menuToggleButton");
660 button->setFixedSize(15, 15);
661 button->setIcon(createQIcon("menu_toggle"));
662 button->setCheckable(true);
663 button->setChecked(false);
664 button->setAutoDefault(false);
665 return button;
666 }
667 } // namespace
668
LoadLevelPopup()669 LoadLevelPopup::LoadLevelPopup()
670 : FileBrowserPopup(tr("Load Level"),
671 Options(MULTISELECTION | WITH_APPLY_BUTTON), "",
672 new QWidget(0)) {
673 setModal(false);
674 setOkText(tr("Load"));
675
676 QWidget *optionWidget = (QWidget *)m_customWidget;
677
678 // choose tlv caching behavior
679 QLabel *cacheBehaviorLabel = new QLabel(tr("TLV Caching Behavior"), this);
680 m_loadTlvBehaviorComboBox = new QComboBox(this);
681
682 //----Load Subsequence Level
683 QPushButton *showSubsequenceButton = createShowButton(this);
684 QLabel *subsequenceLabel = new QLabel(tr("Load Subsequence Level"), this);
685 m_subsequenceFrame = new QFrame(this);
686 m_fromFrame = new DVGui::IntLineEdit(this, 1, 1);
687 m_toFrame = new DVGui::IntLineEdit(this, 1, 1);
688
689 //----Arrangement in Xsheet
690 m_arrLvlPropWidget = new QWidget(this);
691 QPushButton *showArrangementButton = createShowButton(this);
692 QLabel *arrangementLabel =
693 new QLabel(tr("Level Settings & Arrangement in Xsheet"), this);
694 m_arrangementFrame = new QFrame(this);
695 m_xFrom = new DVGui::IntLineEdit(this, 1, 1);
696 m_xTo = new DVGui::IntLineEdit(this, 1, 1);
697 m_stepCombo = new QComboBox(this);
698 m_incCombo = new QComboBox(this);
699 m_posFrom = new DVGui::IntLineEdit(this, 1, 1);
700 m_posTo = new DVGui::IntLineEdit(this, 1, 1);
701
702 //----Level Properties
703 m_levelPropertiesFrame = new QFrame(this);
704 m_levelName = new DVGui::LineEdit(this);
705 m_dpiWidget = new QWidget(this);
706 m_dpiPolicy = new QComboBox(this);
707 m_dpi = new DVGui::DoubleLineEdit(this);
708 m_subsampling = new DVGui::IntLineEdit(this, 1, 1);
709 m_antialias = new DVGui::IntLineEdit(this, 10, 0, 100);
710 m_premultiply = new DVGui::CheckBox(tr("Premultiply"), this);
711 m_whiteTransp = new DVGui::CheckBox(tr("White As Transparent"), this);
712
713 m_notExistLabel = new QLabel(tr("(FILE DOES NOT EXIST)"));
714
715 //----
716 m_loadTlvBehaviorComboBox->addItem(tr("On Demand"),
717 IoCmd::LoadResourceArguments::ON_DEMAND);
718 m_loadTlvBehaviorComboBox->addItem(tr("All Icons"),
719 IoCmd::LoadResourceArguments::ALL_ICONS);
720 m_loadTlvBehaviorComboBox->addItem(
721 tr("All Icons & Images"),
722 IoCmd::LoadResourceArguments::ALL_ICONS_AND_IMAGES);
723 // use the default value set in the preference
724 m_loadTlvBehaviorComboBox->setCurrentIndex(
725 m_loadTlvBehaviorComboBox->findData(
726 Preferences::instance()->getInitialLoadTlvCachingBehavior()));
727 cacheBehaviorLabel->setObjectName("TitleTxtLabel");
728
729 //----Load Subsequence Level
730 m_subsequenceFrame->setObjectName("LoadLevelFrame");
731 subsequenceLabel->setObjectName("TitleTxtLabel");
732 m_subsequenceFrame->hide();
733 m_fromFrame->setMaximumWidth(50);
734 m_toFrame->setMaximumWidth(50);
735
736 //----Arrangement in Xsheet
737 m_arrangementFrame->setObjectName("LoadLevelFrame");
738 m_levelPropertiesFrame->setObjectName("LoadLevelFrame");
739 arrangementLabel->setObjectName("TitleTxtLabel");
740 m_arrLvlPropWidget->hide();
741
742 QStringList sList;
743 sList << QString("Auto") << QString("1") << QString("2") << QString("3")
744 << QString("4") << QString("5") << QString("6") << QString("7")
745 << QString("8");
746 m_stepCombo->addItems(sList);
747 m_incCombo->addItems(sList);
748
749 //----Level Properties
750 m_dpiPolicy->addItem(QObject::tr("Image DPI"), LevelOptions::DP_ImageDpi);
751 m_dpiPolicy->addItem(QObject::tr("Custom DPI"), LevelOptions::DP_CustomDpi);
752 m_dpi->setRange(1, (std::numeric_limits<double>::max)());
753 m_dpi->setFixedWidth(54);
754
755 // initialize with the default value
756 LevelOptions options;
757 setLevelProperties(options);
758
759 //"FILE DOES NOT EXIST" lavel
760 m_notExistLabel->setObjectName("FileDoesNotExistLabel");
761 m_notExistLabel->hide();
762
763 //----layout
764 auto createVBoxLayout = [](int margin, int spacing) {
765 QVBoxLayout *layout = new QVBoxLayout();
766 layout->setMargin(margin);
767 layout->setSpacing(spacing);
768 return layout;
769 };
770 auto createHBoxLayout = [](int margin, int spacing) {
771 QHBoxLayout *layout = new QHBoxLayout();
772 layout->setMargin(margin);
773 layout->setSpacing(spacing);
774 return layout;
775 };
776
777 QVBoxLayout *mainLayout = createVBoxLayout(5, 3);
778 {
779 QHBoxLayout *cacheLay = createHBoxLayout(0, 5);
780 {
781 cacheLay->addStretch(1);
782 cacheLay->addWidget(cacheBehaviorLabel, 0);
783 cacheLay->addWidget(m_loadTlvBehaviorComboBox, 0);
784 }
785 mainLayout->addLayout(cacheLay, 0);
786
787 //----Load Subsequence Level
788
789 QHBoxLayout *subsequenceHeadLay = createHBoxLayout(0, 5);
790 {
791 QFontMetrics metrics(font());
792 subsequenceHeadLay->addSpacing(metrics.width("File name:") + 3);
793 subsequenceHeadLay->addWidget(m_notExistLabel, 0);
794 subsequenceHeadLay->addStretch(1);
795
796 subsequenceHeadLay->addWidget(subsequenceLabel, 0);
797 subsequenceHeadLay->addWidget(showSubsequenceButton, 0);
798 }
799 mainLayout->addLayout(subsequenceHeadLay, 0);
800
801 QHBoxLayout *subsequenceLay = createHBoxLayout(5, 5);
802 {
803 subsequenceLay->addWidget(new QLabel(tr("From:"), this), 0);
804 subsequenceLay->addWidget(m_fromFrame, 0);
805 subsequenceLay->addWidget(new QLabel(tr(" To:"), this), 0);
806 subsequenceLay->addWidget(m_toFrame, 0);
807 }
808 m_subsequenceFrame->setLayout(subsequenceLay);
809 mainLayout->addWidget(m_subsequenceFrame, 0,
810 Qt::AlignRight | Qt::AlignVCenter);
811
812 //----Arrangement in Xsheet
813
814 QHBoxLayout *arrangementHeadLay = createHBoxLayout(0, 3);
815 {
816 arrangementHeadLay->addWidget(arrangementLabel, 1,
817 Qt::AlignRight | Qt::AlignVCenter);
818 arrangementHeadLay->addWidget(showArrangementButton, 0);
819 }
820 mainLayout->addLayout(arrangementHeadLay);
821
822 QHBoxLayout *bottomLay = createHBoxLayout(0, 10);
823 {
824 QGridLayout *levelLay = new QGridLayout();
825 levelLay->setMargin(5);
826 levelLay->setSpacing(5);
827 {
828 levelLay->addWidget(new QLabel(tr("Level Name:"), this), 0, 0,
829 Qt::AlignRight | Qt::AlignVCenter);
830 levelLay->addWidget(m_levelName, 0, 1);
831 QHBoxLayout *dpiLay = createHBoxLayout(0, 5);
832 {
833 dpiLay->addSpacing(10);
834 dpiLay->addWidget(new QLabel(tr("DPI:"), this), 0,
835 Qt::AlignRight | Qt::AlignVCenter);
836 dpiLay->addWidget(m_dpiPolicy, 0);
837 dpiLay->addWidget(m_dpi, 1);
838 }
839 m_dpiWidget->setLayout(dpiLay);
840 levelLay->addWidget(m_dpiWidget, 0, 2, 1, 3);
841
842 levelLay->addWidget(m_premultiply, 1, 0, 1, 2);
843 levelLay->addWidget(m_whiteTransp, 2, 0, 1, 2);
844
845 // levelLay->addWidget(m_doAntialias, 1, 3, 1, 2);
846 levelLay->addWidget(new QLabel(tr("Antialias Softness:"), this), 1, 2,
847 1, 2, Qt::AlignRight | Qt::AlignVCenter);
848 levelLay->addWidget(m_antialias, 1, 4);
849 levelLay->addWidget(new QLabel(tr("Subsampling:"), this), 2, 2, 1, 2,
850 Qt::AlignRight | Qt::AlignVCenter);
851 levelLay->addWidget(m_subsampling, 2, 4);
852 }
853 levelLay->setColumnStretch(1, 1);
854 levelLay->setColumnStretch(4, 1);
855 m_levelPropertiesFrame->setLayout(levelLay);
856 bottomLay->addWidget(m_levelPropertiesFrame, 0);
857
858 QGridLayout *arrLay = new QGridLayout();
859 arrLay->setMargin(5);
860 arrLay->setSpacing(5);
861 {
862 arrLay->addWidget(new QLabel(tr("From:"), this), 0, 0,
863 Qt::AlignRight | Qt::AlignVCenter);
864 arrLay->addWidget(m_xFrom, 0, 1);
865 arrLay->addWidget(new QLabel(tr(" To:"), this), 0, 2,
866 Qt::AlignRight | Qt::AlignVCenter);
867 arrLay->addWidget(m_xTo, 0, 3);
868 arrLay->addWidget(new QLabel(tr(" Step:"), this), 1, 0,
869 Qt::AlignRight | Qt::AlignVCenter);
870 arrLay->addWidget(m_stepCombo, 1, 1);
871 arrLay->addWidget(new QLabel(tr(" Inc:"), this), 1, 2,
872 Qt::AlignRight | Qt::AlignVCenter);
873 arrLay->addWidget(m_incCombo, 1, 3);
874 arrLay->addWidget(new QLabel(tr(" Frames:"), this), 2, 0,
875 Qt::AlignRight | Qt::AlignVCenter);
876 arrLay->addWidget(m_posFrom, 2, 1);
877 arrLay->addWidget(new QLabel(tr("::"), this), 2, 2, Qt::AlignCenter);
878 arrLay->addWidget(m_posTo, 2, 3);
879 }
880 arrLay->setColumnStretch(1, 1);
881 arrLay->setColumnStretch(3, 1);
882 m_arrangementFrame->setLayout(arrLay);
883 bottomLay->addWidget(m_arrangementFrame, 0);
884 }
885 m_arrLvlPropWidget->setLayout(bottomLay);
886
887 mainLayout->addWidget(m_arrLvlPropWidget, 0,
888 Qt::AlignRight | Qt::AlignVCenter);
889 }
890 optionWidget->setLayout(mainLayout);
891
892 //----signal-slot connections
893 //----Load Subsequence Level
894 connect(showSubsequenceButton, SIGNAL(toggled(bool)), m_subsequenceFrame,
895 SLOT(setVisible(bool)));
896 connect(m_fromFrame, SIGNAL(editingFinished()),
897 SLOT(onSubsequentFrameChanged()));
898 connect(m_toFrame, SIGNAL(editingFinished()),
899 SLOT(onSubsequentFrameChanged()));
900
901 //----Arrangement in Xsheet
902 connect(showArrangementButton, SIGNAL(toggled(bool)), m_arrLvlPropWidget,
903 SLOT(setVisible(bool)));
904 connect(m_xFrom, SIGNAL(editingFinished()), SLOT(updatePosTo()));
905 connect(m_xTo, SIGNAL(editingFinished()), SLOT(updatePosTo()));
906 connect(m_posFrom, SIGNAL(editingFinished()), SLOT(updatePosTo()));
907 connect(m_stepCombo, SIGNAL(currentIndexChanged(int)), SLOT(updatePosTo()));
908 connect(m_incCombo, SIGNAL(currentIndexChanged(int)), SLOT(updatePosTo()));
909
910 connect(m_nameField, SIGNAL(editingFinished()), this,
911 SLOT(onNameSetEditted()));
912 connect(m_browser, SIGNAL(treeFolderChanged(const TFilePath &)), this,
913 SLOT(onNameSetEditted()));
914 connect(m_browser, SIGNAL(filePathDoubleClicked(const TFilePath &)), this,
915 SLOT(onFilePathDoubleClicked(const TFilePath &)));
916 //----Level Properties
917 connect(m_dpiPolicy, SIGNAL(activated(int)), this,
918 SLOT(onDpiPolicyActivated()));
919 connect(m_premultiply, SIGNAL(clicked(bool)), this,
920 SLOT(onDoPremultiplyClicked()));
921 connect(m_whiteTransp, SIGNAL(clicked(bool)), this,
922 SLOT(onWhiteTranspClicked()));
923 }
924
925 //-----------------------------------------------------------------------
926
onNameSetEditted()927 void LoadLevelPopup::onNameSetEditted() {
928 getCurrentPathSet().clear();
929 getCurrentFIdsSet().clear();
930
931 // if nothing input
932 if (m_nameField->text() == "") {
933 m_notExistLabel->hide();
934 updateBottomGUI();
935 }
936 // if the path exists
937 else {
938 TFilePath path =
939 m_browser->getFolder() + TFilePath(m_nameField->text().toStdString());
940 getCurrentPathSet().insert(path);
941 if (TSystem::doesExistFileOrLevel(path)) {
942 m_notExistLabel->hide();
943 updateBottomGUI();
944 } else {
945 m_notExistLabel->show();
946
947 m_fromFrame->setText("1");
948 m_toFrame->setText("1");
949 m_subsequenceFrame->setEnabled(true);
950
951 m_xFrom->setText("1");
952 m_xTo->setText("1");
953
954 m_levelName->setText(QString::fromStdString(path.getName()));
955
956 m_arrangementFrame->setEnabled(true);
957 m_levelName->setEnabled(true);
958 m_levelPropertiesFrame->setEnabled(true);
959 updatePosTo();
960 }
961 }
962
963 update();
964 }
965
966 //-----------------------------------------------------------------------
967
updatePosTo()968 void LoadLevelPopup::updatePosTo() {
969 // calcurate how mane frames to be occupied in the xsheet
970 TFilePath fp = getCurrentPath();
971
972 if (QString::fromStdString(fp.getType()) == "tpl") {
973 m_posTo->setText(m_posFrom->text());
974 return;
975 }
976
977 int xFrom = m_xFrom->text().toInt();
978 int xTo = m_xTo->text().toInt();
979
980 int frameLength;
981
982 bool isScene = (QString::fromStdString(fp.getType()) == "tnz");
983
984 //--- if loading the "missing" level
985 if (m_notExistLabel->isVisible()) {
986 int inc = m_incCombo->currentIndex();
987 if (inc == 0) // Inc = Auto
988 {
989 frameLength = (xTo - xFrom + 1) * ((m_stepCombo->currentIndex() == 0)
990 ? 1
991 : m_stepCombo->currentIndex());
992
993 } else // Inc =! Auto
994 {
995 int loopAmount;
996 loopAmount = tceil((double)(xTo - xFrom + 1) / (double)inc);
997 frameLength = loopAmount * ((m_stepCombo->currentIndex() == 0)
998 ? inc
999 : m_stepCombo->currentIndex());
1000 }
1001 }
1002
1003 //-- if loading the existing level
1004 else if (m_incCombo->currentIndex() == 0) // Inc = Auto
1005 {
1006 if (isScene) {
1007 frameLength = xTo - xFrom + 1;
1008 } else {
1009 std::vector<TFrameId> fIds = getCurrentFIds();
1010 //--- If loading the level with sequencial files, reuse the list of
1011 // TFrameId
1012 if (fIds.size() != 0) {
1013 if (m_stepCombo->currentIndex() == 0) // Step = Auto
1014 {
1015 std::vector<TFrameId>::iterator it;
1016 int firstFrame = 0;
1017 int lastFrame = 0;
1018 for (it = fIds.begin(); it != fIds.end(); it++) {
1019 if (xFrom <= it->getNumber()) {
1020 firstFrame = it->getNumber();
1021 break;
1022 }
1023 }
1024 for (it = fIds.begin(); it != fIds.end(); it++) {
1025 if (it->getNumber() <= xTo) {
1026 lastFrame = it->getNumber();
1027 }
1028 }
1029 frameLength = lastFrame - firstFrame + 1;
1030 } else // Step != Auto
1031 {
1032 std::vector<TFrameId>::iterator it;
1033 int loopAmount = 0;
1034 for (it = fIds.begin(); it != fIds.end(); it++) {
1035 if (xFrom <= it->getNumber() && it->getNumber() <= xTo)
1036 loopAmount++;
1037 }
1038 frameLength = loopAmount * m_stepCombo->currentIndex();
1039 }
1040
1041 }
1042 // loading another type of level such as tlv
1043 else {
1044 if (fp.isEmpty()) return;
1045 try {
1046 TLevelReaderP lr(fp);
1047 TLevelP level;
1048 if (lr) level = lr->loadInfo();
1049 if (!level.getPointer()) return;
1050
1051 if (m_stepCombo->currentIndex() == 0) // Step = Auto
1052 {
1053 TLevel::Iterator it;
1054 int firstFrame = 0;
1055 int lastFrame = 0;
1056 for (it = level->begin(); it != level->end(); it++) {
1057 if (xFrom <= it->first.getNumber()) {
1058 firstFrame = it->first.getNumber();
1059 break;
1060 }
1061 }
1062 for (it = level->begin(); it != level->end(); it++) {
1063 if (it->first.getNumber() <= xTo) {
1064 lastFrame = it->first.getNumber();
1065 }
1066 }
1067 frameLength = lastFrame - firstFrame + 1;
1068 } else // Step != Auto
1069 {
1070 TLevel::Iterator it;
1071 int loopAmount = 0;
1072 for (it = level->begin(); it != level->end(); it++) {
1073 if (xFrom <= it->first.getNumber() &&
1074 it->first.getNumber() <= xTo)
1075 loopAmount++;
1076 }
1077 frameLength = loopAmount * m_stepCombo->currentIndex();
1078 }
1079 } catch (...) {
1080 return;
1081 }
1082 }
1083 }
1084 }
1085 // Inc != Auto
1086 else {
1087 int inc = m_incCombo->currentIndex();
1088 int loopAmount;
1089 loopAmount = tceil((double)(xTo - xFrom + 1) / (double)inc);
1090 frameLength = loopAmount * ((m_stepCombo->currentIndex() == 0)
1091 ? inc
1092 : m_stepCombo->currentIndex());
1093 }
1094
1095 m_posTo->setText(
1096 QString::number(m_posFrom->text().toInt() + frameLength - 1));
1097 }
1098 //-----------------------------------------------------------------------
1099 /*! if the from / to values in the subsequent box, update m_xFrom and m_xTo
1100 */
onSubsequentFrameChanged()1101 void LoadLevelPopup::onSubsequentFrameChanged() {
1102 m_xFrom->setText(m_fromFrame->text());
1103 m_xTo->setText(m_toFrame->text());
1104 updatePosTo();
1105 }
1106
1107 //-----------------------------------------------------------------------
1108
showEvent(QShowEvent * e)1109 void LoadLevelPopup::showEvent(QShowEvent *e) {
1110 m_nameField->clear();
1111
1112 FileBrowserPopup::showEvent(e);
1113
1114 bool ret = true;
1115 TFrameHandle *fh = TApp::instance()->getCurrentFrame();
1116 ret = ret &&
1117 connect(fh, SIGNAL(frameSwitched()), this, SLOT(onFrameSwitched()));
1118 ret = ret &&
1119 connect(fh, SIGNAL(frameTypeChanged()), this, SLOT(onFrameSwitched()));
1120
1121 TSelectionHandle *sh = TApp::instance()->getCurrentSelection();
1122 ret = ret && connect(sh, SIGNAL(selectionChanged(TSelection *)), this,
1123 SLOT(onSelectionChanged(TSelection *)));
1124 ret = ret && connect(TApp::instance()->getCurrentScene(),
1125 SIGNAL(preferenceChanged(const QString &)), this,
1126 SLOT(onPreferenceChanged(const QString &)));
1127 assert(ret);
1128
1129 onFrameSwitched();
1130 onSelectionChanged(sh->getSelection());
1131 onPreferenceChanged("");
1132 onNameSetEditted(); // clear currentPathSet
1133 }
1134
1135 //-----------------------------------------------------------------------
1136
hideEvent(QHideEvent * e)1137 void LoadLevelPopup::hideEvent(QHideEvent *e) {
1138 FileBrowserPopup::hideEvent(e);
1139
1140 TFrameHandle *fh = TApp::instance()->getCurrentFrame();
1141 disconnect(fh, SIGNAL(frameSwitched()), this, SLOT(onFrameSwitched()));
1142 disconnect(fh, SIGNAL(frameTypeChanged()), this, SLOT(onFrameSwitched()));
1143
1144 TSelectionHandle *sh = TApp::instance()->getCurrentSelection();
1145 disconnect(sh, SIGNAL(selectionChanged(TSelection *)), this,
1146 SLOT(onSelectionChanged(TSelection *)));
1147 disconnect(TApp::instance()->getCurrentScene(),
1148 SIGNAL(preferenceChanged(const QString &)), this,
1149 SLOT(onPreferenceChanged(const QString &)));
1150 }
1151
1152 //-----------------------------------------------------------------------
1153
onFrameSwitched()1154 void LoadLevelPopup::onFrameSwitched() {
1155 TFrameHandle *fh = TApp::instance()->getCurrentFrame();
1156 if (fh->isEditingLevel())
1157 m_posFrom->setText("1");
1158 else
1159 m_posFrom->setText(QString::number(fh->getFrame() + 1));
1160 updatePosTo();
1161 }
1162
1163 //-----------------------------------------------------------------------
1164
execute()1165 bool LoadLevelPopup::execute() {
1166 if (m_selectedPaths.size() == 1) {
1167 const TFilePath &fp = *m_selectedPaths.begin();
1168 //---- SubSequent load
1169 // if loading the "missing" level
1170 if (m_notExistLabel->isVisible()) {
1171 int firstFrameNumber = m_fromFrame->text().toInt();
1172 int lastFrameNumber = m_toFrame->text().toInt();
1173 setLoadingLevelRange(firstFrameNumber, lastFrameNumber);
1174 } else if (m_subsequenceFrame->isEnabled() &&
1175 m_subsequenceFrame->isVisible()) {
1176 std::vector<TFrameId> fIds = getCurrentFIds();
1177 TFrameId firstFrame;
1178 TFrameId lastFrame;
1179 // if the level is sequencial and there is a reusable list of TFrameId
1180 if (fIds.size() != 0) {
1181 firstFrame = fIds[0];
1182 lastFrame = fIds[fIds.size() - 1];
1183 }
1184 // another case such as loading tlv
1185 else {
1186 try {
1187 TLevelReaderP lr(fp);
1188 TLevelP level;
1189 if (lr) level = lr->loadInfo();
1190 if (!level.getPointer()) return false;
1191
1192 firstFrame = level->begin()->first;
1193 lastFrame = (--level->end())->first;
1194 lr = TLevelReaderP();
1195 } catch (...) {
1196 return false;
1197 }
1198 }
1199 int firstFrameNumber = m_fromFrame->text().toInt();
1200 int lastFrameNumber = m_toFrame->text().toInt();
1201 if (firstFrame.getNumber() != firstFrameNumber ||
1202 lastFrame.getNumber() != lastFrameNumber)
1203 setLoadingLevelRange(firstFrameNumber, lastFrameNumber);
1204 }
1205
1206 IoCmd::LoadResourceArguments args(fp);
1207
1208 args.row0 = m_posFrom->text().toInt() - 1;
1209
1210 args.frameCount = m_posTo->text().toInt() - m_posFrom->text().toInt() + 1;
1211
1212 if ((int)getCurrentFIdsSet().size() != 0)
1213 args.frameIdsSet.push_back(*getCurrentFIdsSet().begin());
1214
1215 else if (m_notExistLabel->isVisible()) {
1216 int firstFrameNumber = m_fromFrame->text().toInt();
1217 int lastFrameNumber = m_toFrame->text().toInt();
1218 // putting the Fids in order to avoid LoadInfo later
1219 std::vector<TFrameId> tmp_fids;
1220 for (int i = firstFrameNumber; i <= lastFrameNumber; i++) {
1221 tmp_fids.push_back(TFrameId(i));
1222 }
1223 args.frameIdsSet.push_back(tmp_fids);
1224 }
1225
1226 int xFrom = m_xFrom->text().toInt();
1227 if (xFrom) args.xFrom = xFrom;
1228 int xTo = m_xTo->text().toInt();
1229 if (xTo) args.xTo = xTo;
1230
1231 args.levelName = m_levelName->text().toStdWString();
1232 args.step = m_stepCombo->currentIndex();
1233 args.inc = m_incCombo->currentIndex();
1234 args.doesFileActuallyExist = !m_notExistLabel->isVisible();
1235 args.cachingBehavior = IoCmd::LoadResourceArguments::CacheTlvBehavior(
1236 m_loadTlvBehaviorComboBox->currentData().toInt());
1237
1238 if (m_arrLvlPropWidget->isVisible() &&
1239 m_levelPropertiesFrame->isEnabled()) {
1240 for (IoCmd::LoadResourceArguments::ResourceData &rd :
1241 args.resourceDatas) {
1242 rd.m_options = LevelOptions();
1243 getLevelProperties(*rd.m_options);
1244 }
1245 }
1246
1247 return 0 < IoCmd::loadResources(args, true, 0);
1248
1249 } else {
1250 std::set<TFilePath>::const_iterator it;
1251 IoCmd::LoadResourceArguments args;
1252
1253 args.row0 = m_posFrom->text().toInt() - 1;
1254
1255 for (it = m_selectedPaths.begin(); it != m_selectedPaths.end(); ++it)
1256 args.resourceDatas.push_back(*it);
1257
1258 std::list<std::vector<TFrameId>> fIdsSet = getCurrentFIdsSet();
1259 if (fIdsSet.size() > 0) {
1260 std::list<std::vector<TFrameId>>::const_iterator fIdIt;
1261 for (fIdIt = fIdsSet.begin(); fIdIt != fIdsSet.end(); ++fIdIt)
1262 args.frameIdsSet.insert(args.frameIdsSet.begin(), *fIdIt);
1263 }
1264
1265 args.cachingBehavior = IoCmd::LoadResourceArguments::CacheTlvBehavior(
1266 m_loadTlvBehaviorComboBox->currentData().toInt());
1267
1268 if (m_arrLvlPropWidget->isVisible() &&
1269 m_levelPropertiesFrame->isEnabled()) {
1270 for (IoCmd::LoadResourceArguments::ResourceData &rd :
1271 args.resourceDatas) {
1272 rd.m_options = LevelOptions();
1273 getLevelProperties(*rd.m_options);
1274 }
1275 }
1276
1277 return 0 < IoCmd::loadResources(args, true, 0);
1278 }
1279 }
1280
1281 //-----------------------------------------------------------------------
1282
initFolder()1283 void LoadLevelPopup::initFolder() {
1284 TFilePath fp;
1285
1286 TProject *project =
1287 TProjectManager::instance()->getCurrentProject().getPointer();
1288 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1289
1290 if (scene) fp = scene->decodeFilePath(project->getProjectFolder());
1291
1292 setFolder(fp);
1293 onFilePathsSelected(getCurrentPathSet(), getCurrentFIdsSet());
1294 }
1295
1296 //----------------------------------------------------------------------------
1297
onFilePathDoubleClicked(const TFilePath & path)1298 void LoadLevelPopup::onFilePathDoubleClicked(const TFilePath &path) {
1299 Q_UNUSED(path);
1300 onOkPressed();
1301 }
1302
1303 //----------------------------------------------------------------------------
1304
onFilePathsSelected(const std::set<TFilePath> & paths,const std::list<std::vector<TFrameId>> & fIds)1305 void LoadLevelPopup::onFilePathsSelected(
1306 const std::set<TFilePath> &paths,
1307 const std::list<std::vector<TFrameId>> &fIds) {
1308 m_notExistLabel->hide();
1309 FileBrowserPopup::onFilePathsSelected(paths, fIds);
1310 updateBottomGUI();
1311 }
1312
1313 //----------------------------------------------------------------------------
1314
updateBottomGUI()1315 void LoadLevelPopup::updateBottomGUI() {
1316 auto disableAll = [&]() {
1317 m_fromFrame->setText("");
1318 m_toFrame->setText("");
1319 m_subsequenceFrame->setEnabled(false);
1320
1321 m_xFrom->setText("");
1322 m_xTo->setText("");
1323 m_levelName->setText("");
1324 m_posTo->setText("");
1325 m_arrangementFrame->setEnabled(false);
1326 m_levelPropertiesFrame->setEnabled(false);
1327 };
1328
1329 std::set<TFilePath> paths = getCurrentPathSet();
1330 std::list<std::vector<TFrameId>> fIdsSet = getCurrentFIdsSet();
1331
1332 if (paths.empty() || paths.size() > 1) {
1333 disableAll();
1334 if (paths.size() > 1) {
1335 m_levelName->setEnabled(false);
1336 m_levelPropertiesFrame->setEnabled(true);
1337 }
1338 return;
1339 }
1340
1341 TFilePath fp = getCurrentPath();
1342 std::vector<TFrameId> fIds = getCurrentFIds();
1343
1344 QString ext = QString::fromStdString(fp.getType());
1345
1346 // initialize
1347 if (fp.isEmpty() || ext == "") {
1348 disableAll();
1349 return;
1350 } else if (ext == "tpl") {
1351 QString str;
1352 m_fromFrame->setText(str.number(1));
1353 m_toFrame->setText(str.number(1));
1354 m_subsequenceFrame->setEnabled(false);
1355
1356 m_xFrom->setText("1");
1357 m_xTo->setText("1");
1358 m_levelName->setText(QString::fromStdString(fp.getName()));
1359 m_posTo->setText(m_posFrom->text());
1360 m_arrangementFrame->setEnabled(false);
1361 m_levelPropertiesFrame->setEnabled(false);
1362 } else if (ext == "tnz") {
1363 ToonzScene scene;
1364 scene.setScenePath(fp);
1365 int sceneLength = scene.getFrameCount();
1366 QString str;
1367 m_fromFrame->setText(str.number(std::min(1, sceneLength)));
1368 m_toFrame->setText(str.number(sceneLength));
1369 m_subsequenceFrame->setEnabled(false);
1370
1371 m_xFrom->setText(m_fromFrame->text());
1372 m_xTo->setText(m_toFrame->text());
1373 m_levelName->setText(QString::fromStdString(fp.getName()));
1374 m_stepCombo->setCurrentIndex(0);
1375 m_incCombo->setCurrentIndex(0);
1376 m_arrangementFrame->setEnabled(false);
1377 m_levelPropertiesFrame->setEnabled(false);
1378 } else {
1379 TFrameId firstFrame;
1380 TFrameId lastFrame;
1381 // for level with sequential frames
1382 if (fIds.size() != 0) {
1383 firstFrame = fIds[0];
1384 lastFrame = fIds[fIds.size() - 1];
1385 } else {
1386 try {
1387 TLevelReaderP lr(fp);
1388 TLevelP level;
1389 if (lr) level = lr->loadInfo();
1390 if (!level.getPointer() || level->getTable()->size() == 0) return;
1391
1392 firstFrame = level->begin()->first;
1393 lastFrame = (--level->end())->first;
1394 } catch (...) {
1395 disableAll();
1396 return;
1397 }
1398 }
1399
1400 m_fromFrame->setText(QString().number(firstFrame.getNumber()));
1401 m_toFrame->setText(QString().number(lastFrame.getNumber()));
1402 m_subsequenceFrame->setEnabled(true);
1403
1404 m_xFrom->setText(m_fromFrame->text());
1405 m_xTo->setText(m_toFrame->text());
1406
1407 // if some option in the preferences is selected, load the level with
1408 // removing
1409 // six letters of the scene name from the level name
1410 m_levelName->setText(getLevelNameWithoutSceneNumber(fp.getName()));
1411
1412 // If the option "Show "ABC" Appendix to the Frame Number in Xsheet Cell" is
1413 // ON, frame numbers normally increment at interval of 10.
1414 // Placing such level with "Auto" step option will cause unwanted
1415 // spacing between frames in Xsheet. Setting the step to "1" can prevent
1416 // such problem.
1417 if (Preferences::instance()->isShowFrameNumberWithLettersEnabled() &&
1418 m_stepCombo->currentIndex() == 0)
1419 m_stepCombo->setCurrentIndex(1);
1420
1421 m_arrangementFrame->setEnabled(true);
1422
1423 m_levelName->setEnabled(true);
1424 m_levelPropertiesFrame->setEnabled(true);
1425 }
1426 updatePosTo();
1427 }
1428 //----------------------------------------------------------------------------
1429
1430 //----------------------------------------------------------------------------
1431 /*! if some option in the preferences is selected, load the level with removing
1432 six letters of the scene name from the level name
1433 */
getLevelNameWithoutSceneNumber(std::string orgName)1434 QString LoadLevelPopup::getLevelNameWithoutSceneNumber(std::string orgName) {
1435 QString levelOrgName = QString::fromStdString(orgName);
1436
1437 // check out the preference
1438 if (!Preferences::instance()->isRemoveSceneNumberFromLoadedLevelNameEnabled())
1439 return levelOrgName;
1440
1441 // do nothing if the level name has less than 7 letters
1442 if (levelOrgName.size() <= 6) return levelOrgName;
1443
1444 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1445 if (!scene) return levelOrgName;
1446
1447 QString sceneName = QString::fromStdWString(scene->getSceneName()).left(5);
1448
1449 // if the first 5 letters are same a the scene name, then remove the letters
1450 // to the under score
1451 // this code is intended to cover both the case "c0001_hogehoge.tif" and
1452 // "c0001A_tif"
1453 if (!levelOrgName.startsWith(sceneName)) return levelOrgName;
1454
1455 if (!levelOrgName.contains("_")) return levelOrgName;
1456
1457 return levelOrgName.right(levelOrgName.size() - levelOrgName.indexOf("_") -
1458 1);
1459 }
1460
1461 //----------------------------------------------------------------------------
1462 /*! if the x-sheet cells are selected, load levels at the upper-left corner of
1463 * the selection
1464 */
onSelectionChanged(TSelection * selection)1465 void LoadLevelPopup::onSelectionChanged(TSelection *selection) {
1466 TCellSelection *cellSelection = dynamic_cast<TCellSelection *>(selection);
1467
1468 if (!cellSelection) return;
1469
1470 int r0, r1, c0, c1;
1471 cellSelection->getSelectedCells(r0, c0, r1, c1);
1472
1473 m_posFrom->setText(QString::number(r0 + 1));
1474
1475 updatePosTo();
1476 }
1477
1478 //----------------------------------------------------------------------------
1479
onPreferenceChanged(const QString & propertyName)1480 void LoadLevelPopup::onPreferenceChanged(const QString &propertyName) {
1481 if (!propertyName.isEmpty() && propertyName != "pixelsOnly") return;
1482 bool pixelsMode = Preferences::instance()->getBoolValue(pixelsOnly);
1483 m_dpiWidget->setHidden(pixelsMode);
1484 if (pixelsMode) {
1485 m_dpiPolicy->setCurrentIndex(
1486 m_dpiPolicy->findData(LevelOptions::DP_ImageDpi));
1487 m_dpi->setValue(Stage::standardDpi);
1488 m_dpi->setEnabled(false);
1489 }
1490 }
1491
1492 //----------------------------------------------------------------------------
1493
setLevelProperties(LevelOptions & options)1494 void LoadLevelPopup::setLevelProperties(LevelOptions &options) {
1495 m_dpiPolicy->setCurrentIndex(m_dpiPolicy->findData(options.m_dpiPolicy));
1496 m_dpi->setValue(options.m_dpi);
1497 m_subsampling->setValue(options.m_subsampling);
1498 m_antialias->setValue(options.m_antialias);
1499 m_whiteTransp->setChecked(options.m_whiteTransp);
1500 m_premultiply->setChecked(options.m_premultiply);
1501 onDpiPolicyActivated();
1502 }
1503
1504 //----------------------------------------------------------------------------
1505
getLevelProperties(LevelOptions & options)1506 void LoadLevelPopup::getLevelProperties(LevelOptions &options) {
1507 options.m_dpiPolicy =
1508 LevelOptions::DpiPolicy(m_dpiPolicy->currentData().toInt());
1509 options.m_dpi = m_dpi->getValue();
1510 options.m_subsampling = m_subsampling->getValue();
1511 options.m_antialias = m_antialias->getValue();
1512 options.m_whiteTransp = m_whiteTransp->isChecked();
1513 options.m_premultiply = m_premultiply->isChecked();
1514 }
1515
1516 //----------------------------------------------------------------------------
1517
onDpiPolicyActivated()1518 void LoadLevelPopup::onDpiPolicyActivated() {
1519 m_dpi->setEnabled(m_dpiPolicy->currentData().toInt() ==
1520 LevelOptions::DP_CustomDpi);
1521 }
1522
1523 //----------------------------------------------------------------------------
1524 // exclusive with the whiteTransp option
onDoPremultiplyClicked()1525 void LoadLevelPopup::onDoPremultiplyClicked() {
1526 if (m_whiteTransp->isChecked()) m_whiteTransp->setChecked(false);
1527 }
1528
1529 //----------------------------------------------------------------------------
1530 // exclusive with the doPremultiply option
onWhiteTranspClicked()1531 void LoadLevelPopup::onWhiteTranspClicked() {
1532 if (m_premultiply->isChecked()) m_premultiply->setChecked(false);
1533 }
1534
1535 //=============================================================================
1536 // SaveLevelAsPopup
1537
SaveLevelAsPopup()1538 SaveLevelAsPopup::SaveLevelAsPopup()
1539 : FileBrowserPopup(tr("Save Level"), Options(FOR_SAVING)) {
1540 setOkText(tr("Save"));
1541 connect(m_nameField, SIGNAL(returnPressedNow()), m_okButton,
1542 SLOT(animateClick()));
1543 }
1544
execute()1545 bool SaveLevelAsPopup::execute() {
1546 if (m_selectedPaths.empty()) return false;
1547
1548 TFilePath &fp = (TFilePath &)*m_selectedPaths.begin();
1549
1550 if (isSpaceString(QString::fromStdString(fp.getName()))) return false;
1551
1552 // pointer to be replaced
1553 TXshLevel *levelToBeReplaced =
1554 TApp::instance()->getCurrentLevel()->getLevel();
1555 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
1556 int curColumnIndex = TApp::instance()->getCurrentColumn()->getColumnIndex();
1557
1558 bool ret = IoCmd::saveLevel(fp);
1559
1560 // ask whether to expose the saved level in xsheet
1561 bool doExpose = true;
1562 if (levelToBeReplaced->getType() & FULLCOLOR_TYPE)
1563 doExpose = false;
1564 else if (ret &&
1565 !Preferences::instance()->isReplaceAfterSaveLevelAsEnabled()) {
1566 QString question(QObject::tr("Do you want to expose the renamed level ?"));
1567 int val = DVGui::MsgBox(question,
1568 QObject::tr("Expose"), // val = 1
1569 QObject::tr("Don't expose"), 0); // val = 2
1570 if (val == 0) return false; // close button
1571 if (val == 2) doExpose = false;
1572 }
1573
1574 // exposing the level
1575 if (ret && doExpose) {
1576 // if the extensions are missing, add them here
1577 TXshSimpleLevel *sl = dynamic_cast<TXshSimpleLevel *>(
1578 TApp::instance()->getCurrentLevel()->getLevel());
1579 if (!sl) return false;
1580 std::string ext = sl->getPath().getType();
1581 if (fp.getType() == "") fp = fp.withType(ext);
1582
1583 IoCmd::LoadResourceArguments args(fp);
1584 args.expose = false;
1585 int count = IoCmd::loadResources(args);
1586 if (count == 0) return false;
1587 TXshLevelP xl = args.loadedLevels[0];
1588
1589 // in case of replacing with a saved file
1590 if (Preferences::instance()->isReplaceAfterSaveLevelAsEnabled()) {
1591 for (int c = 0; c < xsh->getColumnCount(); c++) {
1592 if (xsh->isColumnEmpty(c)) continue;
1593 int r0, r1;
1594 xsh->getCellRange(c, r0, r1);
1595 for (int r = r0; r <= r1; r++) {
1596 TXshCell cell = xsh->getCell(r, c);
1597 if (cell.m_level.getPointer() != levelToBeReplaced) continue;
1598 cell.m_level = xl;
1599 xsh->setCell(r, c, cell);
1600 }
1601 }
1602 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1603
1604 //--- update the scene cast
1605 TLevelSet *levelSet =
1606 TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
1607 for (int i = 0; i < levelSet->getLevelCount(); i++) {
1608 TXshLevel *tmpLevel = levelSet->getLevel(i);
1609 if (tmpLevel != levelToBeReplaced) continue;
1610 if (!TApp::instance()
1611 ->getCurrentScene()
1612 ->getScene()
1613 ->getTopXsheet()
1614 ->isLevelUsed(tmpLevel))
1615 levelSet->removeLevel(tmpLevel);
1616 }
1617
1618 }
1619 // In case of loading the saved file into a vacant column
1620 else {
1621 // find the leftmost empty column
1622 int emptyColumnIndex = xsh->getFirstFreeColumnIndex();
1623
1624 // if the scene frame is selected and the old level is found in the
1625 // current column,
1626 // then place the new level at the same frame with the old one
1627 if (TApp::instance()->getCurrentFrame()->isEditingScene()) {
1628 // check out the current column
1629 int r0, r1;
1630 xsh->getCellRange(curColumnIndex, r0, r1);
1631
1632 for (int r = r0; r <= r1; r++) {
1633 TXshCell cell = xsh->getCell(r, curColumnIndex);
1634 if (!cell.isEmpty() &&
1635 cell.m_level.getPointer() == levelToBeReplaced) {
1636 // set the new level at the same frame with the old one
1637 cell.m_level = xl;
1638 xsh->setCell(r, emptyColumnIndex, cell);
1639 }
1640 }
1641 }
1642 // if the level editing mode, then just place the new level
1643 else {
1644 std::vector<TFrameId> dummy_fIds;
1645 xsh->exposeLevel(0, emptyColumnIndex, xl.getPointer(), dummy_fIds);
1646 }
1647 }
1648
1649 TApp::instance()->getCurrentLevel()->setLevel(xl.getPointer());
1650
1651 TApp::instance()->getCurrentScene()->notifyCastChange();
1652 TApp::instance()->getCurrentLevel()->notifyLevelChange();
1653
1654 DvDirModel::instance()->refreshFolder(fp.getParentDir());
1655
1656 // reset undo memory!!
1657 if (Preferences::instance()->getBoolValue(resetUndoOnSavingLevel))
1658 TUndoManager::manager()->reset();
1659 }
1660
1661 if (ret)
1662 std::cout << "SaveLevelAs complete." << std::endl;
1663 else
1664 std::cout << "SaveLevelAs failed for some reason." << std::endl;
1665
1666 return ret;
1667 }
1668
initFolder()1669 void SaveLevelAsPopup::initFolder() {
1670 TProject *project =
1671 TProjectManager::instance()->getCurrentProject().getPointer();
1672 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1673 TFilePath fp;
1674 if (scene) fp = scene->decodeFilePath(project->getFolder(TProject::Drawings));
1675 setFolder(fp);
1676 }
1677
1678 //---------------------------------------------------------------------------
1679 /*
1680 For Save Level As command, it is needed to check if the current level is
1681 selected (just like Save Level command) BEFORE opening the popup. So I decided
1682 to use an original MenuItemHandler rather than OpenPopupCommandHandler.
1683 06/07/2016 Shun
1684 */
1685
1686 class SaveLevelAsCommandHandler final : public MenuItemHandler {
1687 SaveLevelAsPopup *m_popup;
1688
1689 public:
SaveLevelAsCommandHandler()1690 SaveLevelAsCommandHandler() : MenuItemHandler(MI_SaveLevelAs), m_popup(0) {}
execute()1691 void execute() override {
1692 TXshSimpleLevel *sl = TApp::instance()->getCurrentLevel()->getSimpleLevel();
1693 if (!sl) {
1694 DVGui::warning(QObject::tr("No Current Level"));
1695 return;
1696 }
1697 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1698 if (!scene) {
1699 DVGui::warning(QObject::tr("No Current Scene"));
1700 return;
1701 }
1702 if (!m_popup) m_popup = new SaveLevelAsPopup();
1703 m_popup->show();
1704 m_popup->raise();
1705 m_popup->activateWindow();
1706 }
1707 } saveLevelAsCommandHandler;
1708
1709 //=============================================================================
1710 // Used both for ReplaceLevelPopup and ReplaceParentDirectoryPopup
1711 // which are needed to maintain the current selection on open.
1712
1713 template <class T>
1714 class OpenReplaceFilePopupHandler final : public MenuItemHandler {
1715 T *m_popup;
1716
1717 public:
OpenReplaceFilePopupHandler(CommandId cmdId)1718 OpenReplaceFilePopupHandler(CommandId cmdId)
1719 : MenuItemHandler(cmdId), m_popup(0) {}
1720
1721 // The current selection is cleared on the construction of FileBrowser
1722 // ( by calling makeCurrent() in DvDirTreeView::currentChanged() ).
1723 // Thus checking the selection must be done BEFORE making the browser
1724 // or it fails to get the selection on the first call of this command.
initialize(TCellSelection::Range & range,std::set<int> & columnRange,bool & replaceCells)1725 bool initialize(TCellSelection::Range &range, std::set<int> &columnRange,
1726 bool &replaceCells) {
1727 TSelection *sel = TApp::instance()->getCurrentSelection()->getSelection();
1728 if (!sel) return false;
1729 TCellSelection *cellSel = dynamic_cast<TCellSelection *>(sel);
1730 TColumnSelection *columnSel = dynamic_cast<TColumnSelection *>(sel);
1731 if ((!cellSel && !columnSel) || sel->isEmpty()) {
1732 DVGui::error(
1733 QObject::tr("Nothing to replace: no cells or columns selected."));
1734 return false;
1735 }
1736 if (cellSel) {
1737 range = cellSel->getSelectedCells();
1738 replaceCells = true;
1739 } else if (columnSel) {
1740 columnRange = columnSel->getIndices();
1741 replaceCells = false;
1742 }
1743 return true;
1744 }
1745
execute()1746 void execute() override {
1747 TCellSelection::Range range;
1748 std::set<int> columnRange;
1749 bool replaceCells;
1750 if (!initialize(range, columnRange, replaceCells)) return;
1751 if (!m_popup) m_popup = new T();
1752 m_popup->setRange(range, columnRange, replaceCells);
1753 m_popup->show();
1754 m_popup->raise();
1755 m_popup->activateWindow();
1756 }
1757 };
1758
1759 //=============================================================================
1760 // ReplaceLevelPopup
1761
ReplaceLevelPopup()1762 ReplaceLevelPopup::ReplaceLevelPopup()
1763 : FileBrowserPopup(tr("Replace Level"), Options(WITH_APPLY_BUTTON)) {
1764 setOkText(tr("Replace"));
1765 connect(TApp::instance()->getCurrentSelection(),
1766 SIGNAL(selectionChanged(TSelection *)), this,
1767 SLOT(onSelectionChanged(TSelection *)));
1768 }
1769
setRange(TCellSelection::Range & range,std::set<int> & columnRange,bool & replaceCells)1770 void ReplaceLevelPopup::setRange(TCellSelection::Range &range,
1771 std::set<int> &columnRange,
1772 bool &replaceCells) {
1773 m_range = range;
1774 m_columnRange = columnRange;
1775 m_replaceCells = replaceCells;
1776 }
1777
execute()1778 bool ReplaceLevelPopup::execute() {
1779 if (m_selectedPaths.empty()) return false;
1780
1781 const TFilePath &fp = *m_selectedPaths.begin();
1782 if (!TSystem::doesExistFileOrLevel(fp)) {
1783 DVGui::error(tr("File not found\n") + toQString(fp));
1784 return false;
1785 }
1786
1787 IoCmd::LoadResourceArguments args(fp);
1788 args.expose = false;
1789 args.col0 = m_range.m_c0;
1790 args.col1 = m_range.m_c1;
1791 args.row0 = m_range.m_r0;
1792 args.row1 = m_range.m_r1;
1793 int count = IoCmd::loadResources(args);
1794 if (count == 0) return false;
1795 TXshLevelP xl = args.loadedLevels[0];
1796
1797 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
1798
1799 // cell selection
1800 if (m_replaceCells) {
1801 int r, c;
1802 for (c = m_range.m_c0; c <= m_range.m_c1; c++)
1803 for (r = m_range.m_r0; r <= m_range.m_r1; r++) {
1804 TXshCell cell = xsh->getCell(r, c);
1805 if (!cell.m_level.getPointer()) continue;
1806 cell.m_level = xl;
1807 xsh->setCell(r, c, cell);
1808 }
1809 }
1810 // column selection
1811 else {
1812 int frameLength = xsh->getFrameCount();
1813 std::set<int>::iterator i = m_columnRange.begin();
1814 while (i != m_columnRange.end()) {
1815 for (int r = 0; r < frameLength; r++) {
1816 TXshCell cell = xsh->getCell(r, *i);
1817 if (!cell.m_level.getPointer()) continue;
1818 cell.m_level = xl;
1819 xsh->setCell(r, *i, cell);
1820 }
1821 i++;
1822 }
1823 }
1824
1825 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
1826 TApp::instance()->getCurrentScene()->notifyCastChange();
1827
1828 DvDirModel::instance()->refreshFolder(fp.getParentDir());
1829
1830 return true;
1831 }
1832 //-----------------------------------------------------------------------------
1833
initFolder()1834 void ReplaceLevelPopup::initFolder() {
1835 setFolder(
1836 TProjectManager::instance()->getCurrentProject()->getProjectFolder());
1837 }
1838
1839 //-----------------------------------------------------------------------------
1840
onSelectionChanged(TSelection * sel)1841 void ReplaceLevelPopup::onSelectionChanged(TSelection *sel) {
1842 if (!sel) return;
1843 TCellSelection *cellSel = dynamic_cast<TCellSelection *>(sel);
1844 TColumnSelection *columnSel = dynamic_cast<TColumnSelection *>(sel);
1845 if ((!cellSel && !columnSel) || sel->isEmpty()) return;
1846 if (cellSel) {
1847 m_range = cellSel->getSelectedCells();
1848 m_replaceCells = true;
1849 } else if (columnSel) {
1850 m_columnRange = columnSel->getIndices();
1851 m_replaceCells = false;
1852 }
1853 }
1854
1855 //=============================================================================
1856 // SavePaletteAsPopup
1857
SavePaletteAsPopup()1858 SavePaletteAsPopup::SavePaletteAsPopup()
1859 : FileBrowserPopup(tr("Save Palette"), Options(FOR_SAVING)) {
1860 setOkText(tr("Save"));
1861 addFilterType("tpl");
1862 connect(m_nameField, SIGNAL(returnPressedNow()), m_okButton,
1863 SLOT(animateClick()));
1864 }
1865
execute()1866 bool SavePaletteAsPopup::execute() {
1867 if (m_selectedPaths.empty()) return false;
1868
1869 TFilePath fp(*m_selectedPaths.begin());
1870
1871 TPaletteHandle *paletteHandle =
1872 TApp::instance()->getPaletteController()->getCurrentLevelPalette();
1873 TPalette *palette = paletteHandle->getPalette();
1874
1875 if (!palette) {
1876 DVGui::warning("No current palette exists");
1877 return true;
1878 }
1879
1880 const std::string &type = fp.getType();
1881
1882 if (!type.empty() && type != "tpl")
1883 return false;
1884 else if (type.empty())
1885 fp = fp.getParentDir() + TFilePath(fp.getName() + ".tpl");
1886
1887 if (TFileStatus(fp).doesExist()) {
1888 const QString &question =
1889 QObject::tr(
1890 "The palette %1 already exists.\nDo you want to overwrite it?")
1891 .arg(toQString(fp));
1892 int ret = DVGui::MsgBox(question, QObject::tr("Overwrite"),
1893 QObject::tr("Cancel"), 0);
1894 if (ret == 2 || ret == 0) return false;
1895 }
1896
1897 const TFilePath &refImagePath = palette->getRefImgPath();
1898 if (!refImagePath.isEmpty()) palette->setRefImgPath(TFilePath());
1899
1900 // In questo caso non voglio salvare la reference image.
1901 StudioPalette::instance()->save(fp, palette);
1902 if (!refImagePath.isEmpty()) palette->setRefImgPath(refImagePath);
1903
1904 palette->setDirtyFlag(false);
1905 paletteHandle->notifyPaletteChanged();
1906
1907 return true;
1908 }
1909
initFolder()1910 void SavePaletteAsPopup::initFolder() {
1911 setFolder(
1912 TProjectManager::instance()->getCurrentProjectPath().getParentDir());
1913 }
1914
1915 //=============================================================================
1916 // LoadColorModelPopup
1917
LoadColorModelPopup()1918 LoadColorModelPopup::LoadColorModelPopup()
1919 : FileBrowserPopup(tr("Load Color Model"), Options(), "", new QFrame(0)) {
1920 QFrame *optionFrame = (QFrame *)m_customWidget;
1921 m_paletteFrame = new DVGui::LineEdit("", this);
1922
1923 // layout
1924 QHBoxLayout *mainLayout = new QHBoxLayout();
1925 mainLayout->setMargin(5);
1926 mainLayout->setSpacing(5);
1927 {
1928 mainLayout->addStretch(1);
1929 mainLayout->addWidget(new QLabel(tr("Frames :"), this), 0);
1930 mainLayout->addWidget(m_paletteFrame, 0);
1931 }
1932 optionFrame->setLayout(mainLayout);
1933
1934 setOkText(tr("Load"));
1935 addFilterType("bmp");
1936 addFilterType("jpg");
1937 addFilterType("nol");
1938 addFilterType("pic");
1939 addFilterType("pict");
1940 addFilterType("pct");
1941 addFilterType("png");
1942 addFilterType("rgb");
1943 addFilterType("sgi");
1944 addFilterType("tga");
1945 addFilterType("tif");
1946 addFilterType("tiff");
1947 addFilterType("tlv");
1948 addFilterType("pli");
1949 addFilterType("psd");
1950 }
1951
1952 //--------------------------------------------------------------
1953
onFilePathsSelected(const std::set<TFilePath> & paths)1954 void LoadColorModelPopup::onFilePathsSelected(
1955 const std::set<TFilePath> &paths) {
1956 std::list<std::vector<TFrameId>> tmp;
1957 FileBrowserPopup::onFilePathsSelected(paths, tmp);
1958
1959 m_paletteFrame->setText("");
1960 if (paths.size() == 1) {
1961 // Initialize the line with the level's starting frame
1962 const TFilePath &fp = *paths.begin();
1963 try {
1964 TLevelReaderP lr(fp);
1965 TLevelP level;
1966 if (lr) level = lr->loadInfo();
1967
1968 if (level.getPointer() && level->begin() != level->end()) {
1969 int firstFrame = level->begin()->first.getNumber();
1970 if (firstFrame > 0)
1971 m_paletteFrame->setText(QString::number(firstFrame));
1972 }
1973 } catch (...) {
1974 }
1975 }
1976 }
1977
1978 //--------------------------------------------------------------
1979
execute()1980 bool LoadColorModelPopup::execute() {
1981 if (m_selectedPaths.empty()) return false;
1982
1983 const TFilePath &fp = *m_selectedPaths.begin();
1984
1985 TPaletteHandle *paletteHandle =
1986 TApp::instance()->getPaletteController()->getCurrentLevelPalette();
1987
1988 TPalette *palette = paletteHandle->getPalette();
1989 if (!palette || palette->isCleanupPalette()) {
1990 DVGui::error(QObject::tr("Cannot load Color Model in current palette."));
1991 return false;
1992 }
1993
1994 PaletteCmd::ColorModelLoadingConfiguration config;
1995
1996 // if the palette is locked, replace the color model's palette with the
1997 // destination
1998 if (palette->isLocked()) {
1999 // do nothing as config will use behavior = ReplaceColorModelPlt by default
2000 // config.behavior = PaletteCmd::ReplaceColorModelPlt;
2001 } else {
2002 ColorModelBehaviorPopup popup(m_selectedPaths, 0);
2003 int ret = popup.exec();
2004 if (ret == QDialog::Rejected) return false;
2005 popup.getLoadingConfiguration(config);
2006 }
2007
2008 std::vector<int> framesInput = string2Indexes(m_paletteFrame->text());
2009
2010 if (!framesInput.empty()) {
2011 for (int i = 0; i < framesInput.size(); i++)
2012 std::cout << framesInput[i] << std::endl;
2013 }
2014
2015 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
2016
2017 int isLoaded = PaletteCmd::loadReferenceImage(paletteHandle, config, fp,
2018 scene, framesInput);
2019 // return value - isLoaded
2020 // 2: failed to get palette
2021 // 1: failed to get image
2022 // 0: OK
2023 if (isLoaded == 2) {
2024 std::cout << "GetCurrentPalette Failed!" << std::endl;
2025 return false;
2026 } else if (isLoaded == 1) {
2027 std::cout << "GetReferenceImage Failed!" << std::endl;
2028 return false;
2029 } else if (0 != isLoaded) {
2030 std::cout << "loadReferenceImage Failed for some reason." << std::endl;
2031 return false;
2032 }
2033
2034 // no changes in the icon with replace (Keep the destination palette) option
2035 if (config.behavior != PaletteCmd::ReplaceColorModelPlt) {
2036 TXshLevel *level = TApp::instance()->getCurrentLevel()->getLevel();
2037 if (!level) return true;
2038 std::vector<TFrameId> fids;
2039 level->getFids(fids);
2040 invalidateIcons(level, fids);
2041 }
2042
2043 return true;
2044 }
2045
2046 //--------------------------------------------------------------
2047
showEvent(QShowEvent * e)2048 void LoadColorModelPopup::showEvent(QShowEvent *e) {
2049 m_nameField->clear();
2050 FileBrowserPopup::showEvent(e);
2051 }
2052
2053 //=============================================================================
2054 /*! replace the parent folder path of the levels in the selected cells
2055 */
2056
ReplaceParentDirectoryPopup()2057 ReplaceParentDirectoryPopup::ReplaceParentDirectoryPopup()
2058 : FileBrowserPopup(tr("Replace Parent Directory")) {
2059 setOkText(tr("Replace"));
2060 setFileMode(true); // isDirectoryOnly
2061 }
2062
setRange(TCellSelection::Range & range,std::set<int> & columnRange,bool & replaceCells)2063 void ReplaceParentDirectoryPopup::setRange(TCellSelection::Range &range,
2064 std::set<int> &columnRange,
2065 bool &replaceCells) {
2066 m_range = range;
2067 m_columnRange = columnRange;
2068 m_replaceCells = replaceCells;
2069 }
2070
execute()2071 bool ReplaceParentDirectoryPopup::execute() {
2072 if (m_selectedPaths.empty()) return false;
2073
2074 const TFilePath &fp = *m_selectedPaths.begin();
2075
2076 // make the level list in the selected cells
2077 TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
2078 std::vector<TXshLevel *> levelsToBeReplaced;
2079
2080 if (m_replaceCells) {
2081 int r, c;
2082 for (c = m_range.m_c0; c <= m_range.m_c1; c++) {
2083 for (r = m_range.m_r0; r <= m_range.m_r1; r++) {
2084 TXshCell cell = xsh->getCell(r, c);
2085 if (cell.isEmpty() ||
2086 !cell.m_level->getSimpleLevel()) // TLV and PLI only
2087 continue;
2088 levelsToBeReplaced.push_back(cell.m_level.getPointer());
2089 }
2090 }
2091 } else {
2092 // calcurate scene length
2093 int frameLength = xsh->getFrameCount();
2094 std::set<int>::iterator i = m_columnRange.begin();
2095 while (i != m_columnRange.end()) {
2096 for (int r = 0; r < frameLength; r++) {
2097 TXshCell cell = xsh->getCell(r, *i);
2098 if (!cell.m_level.getPointer()) continue;
2099 levelsToBeReplaced.push_back(cell.m_level.getPointer());
2100 }
2101 i++;
2102 }
2103 }
2104
2105 // avoid level duplication
2106 std::sort(levelsToBeReplaced.begin(), levelsToBeReplaced.end());
2107 levelsToBeReplaced.erase(
2108 std::unique(levelsToBeReplaced.begin(), levelsToBeReplaced.end()),
2109 levelsToBeReplaced.end());
2110
2111 if (levelsToBeReplaced.empty()) return false;
2112
2113 // check if the file exists. If exists, load it and store them in the map
2114 // rewrite the path in the level settings
2115 bool somethingChanged = false;
2116 std::vector<TXshLevel *>::iterator it = levelsToBeReplaced.begin();
2117 for (; it != levelsToBeReplaced.end(); it++) {
2118 TFilePath orgPath = (*it)->getPath();
2119 if (orgPath.isEmpty()) continue;
2120
2121 TFilePath newPath = orgPath.withParentDir(fp);
2122
2123 if (orgPath == newPath) continue;
2124
2125 // If the file exists
2126 if (TSystem::doesExistFileOrLevel(newPath)) {
2127 TXshSimpleLevel *sl = (*it)->getSimpleLevel();
2128 if (!sl) continue;
2129
2130 // replace the file with aliases, if possible
2131 newPath = TApp::instance()->getCurrentScene()->getScene()->codeFilePath(
2132 newPath);
2133
2134 sl->setPath(newPath);
2135 sl->invalidateFrames();
2136 std::vector<TFrameId> frames;
2137 sl->getFids(frames);
2138 std::vector<TFrameId>::iterator f_it = frames.begin();
2139 for (; f_it != frames.end(); f_it++)
2140 IconGenerator::instance()->invalidate(sl, *f_it);
2141
2142 somethingChanged = true;
2143 }
2144 }
2145
2146 if (!somethingChanged) return false;
2147
2148 TApp::instance()->getCurrentLevel()->notifyLevelChange();
2149 TApp::instance()->getCurrentScene()->notifySceneChanged();
2150 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
2151
2152 return true;
2153 }
2154
initFolder()2155 void ReplaceParentDirectoryPopup::initFolder() {
2156 setFolder(
2157 TProjectManager::instance()->getCurrentProjectPath().getParentDir());
2158 }
2159
2160 //=============================================================================
2161 // ImportMagpieFilePopup
2162
ImportMagpieFilePopup()2163 ImportMagpieFilePopup::ImportMagpieFilePopup()
2164 : FileBrowserPopup(tr("Import Toonz Lip Sync File")) {
2165 setOkText(tr("Load"));
2166 addFilterType("tls");
2167 }
2168
execute()2169 bool ImportMagpieFilePopup::execute() {
2170 if (m_selectedPaths.empty()) return false;
2171
2172 const TFilePath &fp = *m_selectedPaths.begin();
2173
2174 if (!TSystem::doesExistFileOrLevel(fp)) {
2175 DVGui::error(tr("%1 does not exist.").arg(toQString(fp)));
2176 return false;
2177 }
2178
2179 static MagpieFileImportPopup *magpieFileImportPopup =
2180 new MagpieFileImportPopup();
2181 magpieFileImportPopup->setFilePath(fp);
2182 magpieFileImportPopup->show();
2183
2184 return true;
2185 }
2186
initFolder()2187 void ImportMagpieFilePopup::initFolder() {
2188 TProject *project =
2189 TProjectManager::instance()->getCurrentProject().getPointer();
2190 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
2191 TFilePath fp;
2192 if (scene) fp = scene->decodeFilePath(project->getFolder(TProject::Drawings));
2193 setFolder(fp);
2194 }
2195
showEvent(QShowEvent * e)2196 void ImportMagpieFilePopup::showEvent(QShowEvent *e) {
2197 m_nameField->clear();
2198 FileBrowserPopup::showEvent(e);
2199 }
2200
2201 //=============================================================================
2202 // BrowserPopup
2203
BrowserPopup()2204 BrowserPopup::BrowserPopup() : FileBrowserPopup("") {
2205 setOkText(tr("Choose"));
2206 m_browser->enableGlobalSelection(false);
2207 }
2208
execute()2209 bool BrowserPopup::execute() {
2210 if (m_selectedPaths.empty()) return false;
2211
2212 const TFilePath &fp = *m_selectedPaths.begin();
2213
2214 if (!TSystem::doesExistFileOrLevel(fp)) {
2215 const QString &msg = tr("Path %1 doesn't exists.").arg(toQString(fp));
2216 DVGui::info(msg);
2217
2218 return false;
2219 }
2220
2221 m_path = fp;
2222 return true;
2223 }
2224
initFolder(TFilePath path)2225 void BrowserPopup::initFolder(TFilePath path) {
2226 // if the path is empty
2227 if (path.isEmpty()) {
2228 TProject *project =
2229 TProjectManager::instance()->getCurrentProject().getPointer();
2230 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
2231 if (scene)
2232 setFolder(scene->decodeFilePath(project->getFolder(TProject::Drawings)));
2233 return;
2234 }
2235 if (!TFileStatus(path).doesExist()) {
2236 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
2237 if (scene) path = scene->decodeFilePath(path);
2238 }
2239
2240 if (!path.getType().empty()) path = path.getParentDir();
2241
2242 setFolder(path);
2243 setFilename(TFilePath());
2244 }
2245
2246 //=============================================================================
2247 // BrowserPopupController
2248 /* N.B. Eliminare nel momento in cui la classe FileBrowserPopup, con tutte le
2249 classi annesse
2250 (FileBrowser, DvDirTreeView, ...), sara'
2251 spostata nella libreria toonzQt. */
BrowserPopupController()2252 BrowserPopupController::BrowserPopupController() : m_browserPopup() {
2253 m_isExecute = false;
2254 DVGui::FileField::setBrowserPopupController(this);
2255 }
2256
openPopup(QStringList filters,bool isDirectoryOnly,QString lastSelectedPath,const QWidget * parentWidget)2257 void BrowserPopupController::openPopup(QStringList filters,
2258 bool isDirectoryOnly,
2259 QString lastSelectedPath,
2260 const QWidget *parentWidget) {
2261 if (!m_browserPopup) m_browserPopup = new BrowserPopup();
2262 m_browserPopup->setWindowTitle(QString(""));
2263
2264 m_browserPopup->setFilterTypes(filters);
2265
2266 m_browserPopup->setWindowTitle((isDirectoryOnly)
2267 ? QString(QObject::tr("Choose Folder"))
2268 : QString(QObject::tr("File Browser")));
2269 m_browserPopup->initFolder(TFilePath(lastSelectedPath.toStdWString()));
2270 m_browserPopup->setFileMode(isDirectoryOnly);
2271
2272 Qt::WindowFlags flags = m_browserPopup->windowFlags();
2273 bool parentSet = false;
2274 if (parentWidget) {
2275 for (QWidget *pwidget : QApplication::topLevelWidgets()) {
2276 if (pwidget->isWindow() && pwidget->isVisible() &&
2277 pwidget->isAncestorOf(parentWidget)) {
2278 m_browserPopup->setParent(pwidget);
2279 m_browserPopup->setWindowFlags(flags);
2280 parentSet = true;
2281 break;
2282 }
2283 }
2284 }
2285
2286 if (isDirectoryOnly)
2287 m_browserPopup->setFilename(TFilePath(lastSelectedPath.toStdWString()));
2288
2289 if (m_browserPopup->exec() == QDialog::Accepted)
2290 m_isExecute = true;
2291 else
2292 m_isExecute = false;
2293
2294 // set back the parent to the main window in order to prevent to be
2295 // deleted along with the parent widget
2296 if (parentSet) {
2297 m_browserPopup->setParent(TApp::instance()->getMainWindow());
2298 m_browserPopup->setWindowFlags(flags);
2299 }
2300 }
2301
2302 // codePath is set to true by default
getPath(bool codePath)2303 QString BrowserPopupController::getPath(bool codePath) {
2304 m_isExecute = false;
2305 if (!m_browserPopup) return QString();
2306 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
2307 TFilePath fp = m_browserPopup->getPath();
2308 if (scene && codePath) fp = scene->codeFilePath(fp);
2309 std::cout << ::to_string(fp) << std::endl;
2310 return toQString(fp);
2311 }
2312
2313 //=============================================================================
2314 BrowserPopupController browserPopupController;
2315 //-----------------------------------------------------------------------------
2316
2317 OpenPopupCommandHandler<SaveSceneAsPopup> saveSceneAsPopupCommand(
2318 MI_SaveSceneAs);
2319 OpenPopupCommandHandler<SaveSubSceneAsPopup> saveSubSceneAsPopupCommand(
2320 MI_SaveSubxsheetAs);
2321 OpenPopupCommandHandler<LoadLevelPopup> loadLevelPopupCommand(MI_LoadLevel);
2322 OpenPopupCommandHandler<ConvertPopupWithInput> convertWithInputPopupCommand(
2323 MI_ConvertFileWithInput);
2324 OpenPopupCommandHandler<SavePaletteAsPopup> savePalettePopupCommand(
2325 MI_SavePaletteAs);
2326 OpenPopupCommandHandler<LoadColorModelPopup> loadColorModelPopupCommand(
2327 MI_LoadColorModel);
2328 OpenPopupCommandHandler<ImportMagpieFilePopup> importMagpieFilePopupCommand(
2329 MI_ImportMagpieFile);
2330
2331 // Note: MI_ReplaceLevel and MI_ReplaceParentDirectory uses the original
2332 // handler in order to obtain the selection information before making the
2333 // browser.
2334 OpenReplaceFilePopupHandler<ReplaceLevelPopup> replaceLevelPopupCommand(
2335 MI_ReplaceLevel);
2336 OpenReplaceFilePopupHandler<ReplaceParentDirectoryPopup>
2337 replaceParentFolderPopupCommand(MI_ReplaceParentDirectory);
2338