1
2
3 #include "filebrowsermodel.h"
4 #include "tutil.h"
5 #include "tsystem.h"
6 #include "tconvert.h"
7 #include "tenv.h"
8 #include "toonz/tproject.h"
9 #include "toonz/toonzscene.h"
10 #include "toonzqt/gutil.h"
11
12 #include "filebrowser.h"
13 #include "history.h"
14 #include "iocommand.h"
15
16 #include "tapp.h"
17 #include "toonz/tscenehandle.h"
18
19 #include <QFileInfo>
20 #include <QDir>
21 #include <QDirIterator>
22
23 #ifdef _WIN32
24 #include <shlobj.h>
25 #include <winnetwk.h>
26 #include <wctype.h>
27 #endif
28 #ifdef MACOSX
29 #include <Cocoa/Cocoa.h>
30 #endif
31
32 namespace {
getMyDocumentsPath()33 TFilePath getMyDocumentsPath() {
34 #ifdef _WIN32
35 WCHAR szPath[MAX_PATH];
36 if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_PERSONAL, 0)) {
37 return TFilePath(szPath);
38 }
39 return TFilePath();
40 #elif defined MACOSX
41 NSArray *foundref = NSSearchPathForDirectoriesInDomains(
42 NSDocumentDirectory, NSUserDomainMask, YES);
43 if (!foundref) return TFilePath();
44 int c = [foundref count];
45 assert(c == 1);
46 NSString *documentsDirectory = [foundref objectAtIndex:0];
47 return TFilePath((const char *)[documentsDirectory
48 cStringUsingEncoding:NSASCIIStringEncoding]);
49 #else
50 QDir dir = QDir::home();
51 if (!dir.cd("Documents")) return TFilePath();
52 return TFilePath(dir.absolutePath().toStdString());
53 #endif
54 }
55
56 // Desktop Path
getDesktopPath()57 TFilePath getDesktopPath() {
58 #ifdef _WIN32
59 WCHAR szPath[MAX_PATH];
60 if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_DESKTOP, 0)) {
61 return TFilePath(szPath);
62 }
63 return TFilePath();
64 #elif defined MACOSX
65 NSArray *foundref = NSSearchPathForDirectoriesInDomains(
66 NSDesktopDirectory, NSUserDomainMask, YES);
67 if (!foundref) return TFilePath();
68 int c = [foundref count];
69 assert(c == 1);
70 NSString *desktopDirectory = [foundref objectAtIndex:0];
71 return TFilePath((const char *)[desktopDirectory
72 cStringUsingEncoding:NSASCIIStringEncoding]);
73 #else
74 QDir dir = QDir::home();
75 if (!dir.cd("Desktop")) return TFilePath();
76 return TFilePath(dir.absolutePath().toStdString());
77 #endif
78 }
79 } // namespace
80
81 //=============================================================================
82 //
83 // DvDirModelNode
84 //
85 //-----------------------------------------------------------------------------
86
DvDirModelNode(DvDirModelNode * parent,std::wstring name)87 DvDirModelNode::DvDirModelNode(DvDirModelNode *parent, std::wstring name)
88 : m_parent(parent)
89 , m_name(name)
90 , m_oldName()
91 , m_row(-1)
92 , m_childrenValid(false)
93 , m_renameEnabled(false)
94 , m_nodeType("") {}
95
96 //-----------------------------------------------------------------------------
97
~DvDirModelNode()98 DvDirModelNode::~DvDirModelNode() { clearPointerContainer(m_children); }
99
100 //-----------------------------------------------------------------------------
101
removeChildren(int row,int count)102 void DvDirModelNode::removeChildren(int row, int count) {
103 assert(0 <= row && row + count <= (int)m_children.size());
104 int i;
105 for (i = 0; i < count; i++) delete m_children[row + i];
106 m_children.erase(m_children.begin() + row, m_children.begin() + row + count);
107 for (i = 0; i < (int)m_children.size(); i++) m_children[i]->setRow(i);
108 }
109
110 //-----------------------------------------------------------------------------
111
addChild(DvDirModelNode * child)112 void DvDirModelNode::addChild(DvDirModelNode *child) {
113 child->setRow(m_children.size());
114 m_children.push_back(child);
115 }
116
117 //-----------------------------------------------------------------------------
118
getChildCount()119 int DvDirModelNode::getChildCount() {
120 if (!m_childrenValid) refreshChildren();
121 return (int)m_children.size();
122 }
123
124 //-----------------------------------------------------------------------------
125
getChild(int index)126 DvDirModelNode *DvDirModelNode::getChild(int index) {
127 if (!m_childrenValid) refreshChildren();
128 assert(0 <= index && index < getChildCount());
129 return m_children[index];
130 }
131
132 //-----------------------------------------------------------------------------
133
hasChildren()134 bool DvDirModelNode::hasChildren() {
135 if (m_childrenValid)
136 return getChildCount() > 0;
137 else
138 return true;
139 }
140
141 //-----------------------------------------------------------------------------
142
getPixmap(bool isOpen) const143 QPixmap DvDirModelNode::getPixmap(bool isOpen) const { return QPixmap(); }
144
145 //-----------------------------------------------------------------------------
146
setTemporaryName(const std::wstring & newName)147 void DvDirModelNode::setTemporaryName(const std::wstring &newName) {
148 m_oldName = getName();
149 m_name = newName;
150 }
151
152 //-----------------------------------------------------------------------------
153
restoreName()154 void DvDirModelNode::restoreName() {
155 if (m_oldName != L"") {
156 m_name = m_oldName;
157 m_oldName = L"";
158 }
159 }
160
161 //=============================================================================
162 //
163 // DvDirModelFileFolderNode [File folder]
164 //
165 //-----------------------------------------------------------------------------
166
DvDirModelFileFolderNode(DvDirModelNode * parent,std::wstring name,const TFilePath & path)167 DvDirModelFileFolderNode::DvDirModelFileFolderNode(DvDirModelNode *parent,
168 std::wstring name,
169 const TFilePath &path)
170 : DvDirModelNode(parent, name)
171 , m_path(path)
172 , m_isProjectFolder(false)
173 , m_existsChecked(false)
174 , m_exists(true)
175 , m_hasChildren(false)
176 , m_peeks(true) {
177 m_nodeType = "FileFolder";
178 }
179
180 //-----------------------------------------------------------------------------
181
DvDirModelFileFolderNode(DvDirModelNode * parent,const TFilePath & path)182 DvDirModelFileFolderNode::DvDirModelFileFolderNode(DvDirModelNode *parent,
183 const TFilePath &path)
184 : DvDirModelNode(parent, path.withoutParentDir().getWideString())
185 , m_path(path)
186 , m_isProjectFolder(false)
187 , m_existsChecked(false)
188 , m_exists(true)
189 , m_hasChildren(false)
190 , m_peeks(true) {
191 m_nodeType = "FileFolder";
192 }
193
194 //-----------------------------------------------------------------------------
195
exists()196 bool DvDirModelFileFolderNode::exists() {
197 return m_existsChecked ? m_exists : m_peeks
198 ? m_existsChecked = true,
199 m_exists = TFileStatus(m_path).doesExist() : true;
200 }
201
202 //-----------------------------------------------------------------------------
203
visualizeContent(FileBrowser * browser)204 void DvDirModelFileFolderNode::visualizeContent(FileBrowser *browser) {
205 browser->setFolder(m_path);
206 }
207
208 //-----------------------------------------------------------------------------
209
makeChild(std::wstring name)210 DvDirModelNode *DvDirModelFileFolderNode::makeChild(std::wstring name) {
211 return createNode(this, m_path + name);
212 }
213
214 //-----------------------------------------------------------------------------
215
createNode(DvDirModelNode * parent,const TFilePath & path)216 DvDirModelFileFolderNode *DvDirModelFileFolderNode::createNode(
217 DvDirModelNode *parent, const TFilePath &path) {
218 DvDirModelFileFolderNode *node;
219 // check the project nodes under the Poject Root Node
220 if (QString::fromStdWString(parent->getName()).startsWith("Project root") &&
221 TProjectManager::instance()->isProject(path))
222 node = new DvDirModelProjectNode(parent, path);
223 else {
224 node = new DvDirModelFileFolderNode(parent, path);
225 if (path.getName().find("_files") == std::string::npos)
226 node->enableRename(true);
227 }
228 return node;
229 }
230
231 //-----------------------------------------------------------------------------
232
setName(std::wstring newName)233 bool DvDirModelFileFolderNode::setName(std::wstring newName) {
234 if (isSpaceString(QString::fromStdWString(newName))) return true;
235
236 TFilePath srcPath = getPath();
237 TFilePath dstPath = getPath().getParentDir() + newName;
238 if (srcPath == dstPath) return false;
239 try {
240 TSystem::renameFile(dstPath, srcPath);
241 } catch (...) {
242 return false;
243 }
244 m_path = dstPath;
245 m_name = newName;
246 return true;
247 }
248
249 //-----------------------------------------------------------------------------
250
hasChildren()251 bool DvDirModelFileFolderNode::hasChildren() {
252 if (m_childrenValid) return m_hasChildren;
253
254 if (m_peeks) {
255 // Using QDirIterator and only checking existence of the first item
256 QDir dir(m_path.getQString());
257 dir.setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
258 QDirIterator it(dir);
259 return (it.hasNext());
260 } else
261 return true; // Not peeking nodes allow users to actively scan for
262 // sub-folders
263 }
264
265 //------------------------------------------------------------------------------
266
refreshChildren()267 void DvDirModelFileFolderNode::refreshChildren() {
268 m_childrenValid = true;
269
270 std::vector<std::wstring> names;
271 getChildrenNames(names);
272
273 std::vector<DvDirModelNode *> oldChildren;
274 oldChildren.swap(m_children);
275
276 std::vector<DvDirModelNode *>::iterator j;
277 int i;
278 for (i = 0; i < (int)names.size(); i++) {
279 std::wstring name = names[i];
280 for (j = oldChildren.begin();
281 j != oldChildren.end() && (*j)->getName() != name; ++j) {
282 }
283 DvDirModelNode *child = 0;
284 if (j != oldChildren.end()) {
285 child = *j;
286 oldChildren.erase(j);
287 } else {
288 child = makeChild(name);
289 if (DvDirModelFileFolderNode *folderNode =
290 dynamic_cast<DvDirModelFileFolderNode *>(child))
291 folderNode->setPeeking(m_peeks);
292 }
293
294 if (!child) continue;
295
296 addChild(child);
297 }
298 for (j = oldChildren.begin(); j != oldChildren.end(); ++j) {
299 DvDirModelNode *child = *j;
300 if (!!child && child->hasChildren())
301 child->removeChildren(0, child->getChildCount());
302
303 delete *j;
304 }
305
306 m_hasChildren = (m_children.size() > 0);
307 }
308
309 //-----------------------------------------------------------------------------
310
getChildrenNames(std::vector<std::wstring> & names) const311 void DvDirModelFileFolderNode::getChildrenNames(
312 std::vector<std::wstring> &names) const {
313 if (m_path.isEmpty()) return;
314 TFileStatus folderPathStatus(m_path);
315 if (folderPathStatus.isLink()) return;
316
317 if (!folderPathStatus.isDirectory()) return;
318
319 QStringList dirItems;
320 TSystem::readDirectory_DirItems(dirItems, m_path);
321 for (const QString &name : dirItems) names.push_back(name.toStdWString());
322
323 QDir dir(toQString(m_path));
324 }
325
326 //-----------------------------------------------------------------------------
327
rowByName(const std::wstring & name) const328 int DvDirModelFileFolderNode::rowByName(const std::wstring &name) const {
329 std::vector<std::wstring> names;
330 getChildrenNames(names);
331 std::vector<std::wstring>::iterator it =
332 std::find(names.begin(), names.end(), name);
333 if (it == names.end())
334 return -1;
335 else
336 return std::distance(names.begin(), it);
337 }
338
339 //-----------------------------------------------------------------------------
340
getNodeByPath(const TFilePath & path)341 DvDirModelNode *DvDirModelFileFolderNode::getNodeByPath(const TFilePath &path) {
342 if (path == m_path) return this;
343 if (!m_path.isAncestorOf(path)) return 0;
344 int i, n = getChildCount();
345 for (i = 0; i < n; i++) {
346 DvDirModelNode *node = getChild(i)->getNodeByPath(path);
347 if (node) return node;
348 }
349 return 0;
350 }
351
352 //-----------------------------------------------------------------------------
353
getPixmap(bool isOpen) const354 QPixmap DvDirModelFileFolderNode::getPixmap(bool isOpen) const {
355 static QPixmap openFolderPixmap(
356 svgToPixmap(getIconThemePath("actions/18/folder_on.svg")));
357 static QPixmap closeFolderPixmap(
358 svgToPixmap(getIconThemePath("actions/18/folder.svg")));
359 return isOpen ? openFolderPixmap : closeFolderPixmap;
360 }
361
362 //=============================================================================
363 //
364 // DvDirModelSpecialFileFolderNode [Special File Folder]
365 //
366 //-----------------------------------------------------------------------------
367
DvDirModelSpecialFileFolderNode(DvDirModelNode * parent,std::wstring name,const TFilePath & path)368 DvDirModelSpecialFileFolderNode::DvDirModelSpecialFileFolderNode(
369 DvDirModelNode *parent, std::wstring name, const TFilePath &path)
370 : DvDirModelFileFolderNode(parent, name, path) {}
371
372 //-----------------------------------------------------------------------------
373
getPixmap(bool isOpen) const374 QPixmap DvDirModelSpecialFileFolderNode::getPixmap(bool isOpen) const {
375 return m_pixmap;
376 }
377
378 //-----------------------------------------------------------------------------
379
setPixmap(const QPixmap & pixmap)380 void DvDirModelSpecialFileFolderNode::setPixmap(const QPixmap &pixmap) {
381 m_pixmap = pixmap;
382 }
383
384 //=============================================================================
385 //
386 // DvDirVersionControlNode [Special File Folder]
387 //
388 //-----------------------------------------------------------------------------
389
DvDirVersionControlNode(DvDirModelNode * parent,std::wstring name,const TFilePath & path)390 DvDirVersionControlNode::DvDirVersionControlNode(DvDirModelNode *parent,
391 std::wstring name,
392 const TFilePath &path)
393 : DvDirModelFileFolderNode(parent, name, path)
394 , m_isSynched(false)
395 , m_isUnversioned(false)
396 , m_oldName() {
397 this->setExists(TFileStatus(path).doesExist());
398 setIsUnderVersionControl(
399 VersionControl::instance()->isFolderUnderVersionControl(toQString(path)));
400 }
401
402 //-----------------------------------------------------------------------------
403
getMissingFiles() const404 QList<TFilePath> DvDirVersionControlNode::getMissingFiles() const {
405 QList<TFilePath> list;
406 QMap<QString, SVNStatus>::const_iterator i = m_statusMap.constBegin();
407 while (i != m_statusMap.constEnd()) {
408 SVNStatus s = i.value();
409 if (s.m_item == "missing" ||
410 (s.m_item == "none" && s.m_repoStatus == "added")) {
411 TFilePath path(getPath() + TFilePath(s.m_path.toStdWString()));
412 std::string dots = path.getDots();
413 if (dots != "") {
414 if (dots == "..") path = path.getParentDir() + path.getLevelNameW();
415 if (!list.contains(path)) list.append(path);
416 }
417 }
418 i++;
419 }
420 return list;
421 }
422
423 //-----------------------------------------------------------------------------
424
getMissingFiles(const QRegExp & filter) const425 QStringList DvDirVersionControlNode::getMissingFiles(
426 const QRegExp &filter) const {
427 QStringList list;
428 QMap<QString, SVNStatus>::const_iterator i = m_statusMap.constBegin();
429 for (; i != m_statusMap.constEnd(); i++) {
430 SVNStatus s = i.value();
431 if (s.m_item == "missing" ||
432 (s.m_item == "none" && s.m_repoStatus == "added")) {
433 TFilePath path(s.m_path.toStdWString());
434 if (!filter.exactMatch(
435 QString::fromStdWString(path.withoutParentDir().getWideString())))
436 continue;
437 std::string dots = path.getDots();
438 if (dots != "") list.append(toQString(path));
439 }
440 }
441 return list;
442 }
443
444 //-----------------------------------------------------------------------------
445
getMissingFolders() const446 QList<TFilePath> DvDirVersionControlNode::getMissingFolders() const {
447 QList<TFilePath> list;
448 QMap<QString, SVNStatus>::const_iterator i = m_statusMap.constBegin();
449 while (i != m_statusMap.constEnd()) {
450 SVNStatus s = i.value();
451 if (s.m_item == "missing" ||
452 (s.m_item == "none" && s.m_repoStatus == "added")) {
453 TFilePath path(getPath() + TFilePath(s.m_path.toStdWString()));
454 if (path.getDots() == "" || path.getType() == "tnz") {
455 QString currentFolderName =
456 QString::fromStdWString(getPath().getWideName());
457 if (currentFolderName != s.m_path) {
458 if (!s.m_path.contains("\\"))
459 list.append(path);
460 else {
461 QString newPath = s.m_path.replace(currentFolderName + "\\", "");
462 if (!newPath.contains("\\"))
463 list.append(getPath() + TFilePath(newPath.toStdWString()));
464 }
465 }
466 }
467 }
468 i++;
469 }
470 return list;
471 }
472
473 //-----------------------------------------------------------------------------
474
getChildrenNames(std::vector<std::wstring> & names) const475 void DvDirVersionControlNode::getChildrenNames(
476 std::vector<std::wstring> &names) const {
477 DvDirModelFileFolderNode::getChildrenNames(names);
478
479 QList<TFilePath> missingFolders = getMissingFolders();
480 int count = missingFolders.size();
481
482 for (int i = 0; i < count; i++) {
483 std::wstring name = missingFolders.at(i).getWideName();
484 if (find(names.begin(), names.end(), name) == names.end())
485 names.push_back(name);
486 }
487 }
488
489 //-----------------------------------------------------------------------------
490
setIsUnderVersionControl(bool value)491 void DvDirVersionControlNode::setIsUnderVersionControl(bool value) {
492 // Set the flags and enable/disable renaming accordling
493 m_isUnderVersionControl = value;
494 enableRename(!value);
495 }
496
497 //-----------------------------------------------------------------------------
498
makeChild(std::wstring name)499 DvDirModelNode *DvDirVersionControlNode::makeChild(std::wstring name) {
500 if (TProjectManager::instance()->isProject(getPath() + name))
501 return new DvDirVersionControlProjectNode(this, name, getPath() + name);
502 return new DvDirVersionControlNode(this, name, getPath() + name);
503 }
504
505 //-----------------------------------------------------------------------------
506
getPixmap(bool isOpen) const507 QPixmap DvDirVersionControlNode::getPixmap(bool isOpen) const {
508 static QPixmap openFolderPixmap(
509 svgToPixmap(getIconThemePath("actions/18/folder_on.svg")));
510 static QPixmap closeFolderPixmap(
511 svgToPixmap(getIconThemePath("actions/18/folder.svg")));
512 static QPixmap openMissingPixmap(
513 svgToPixmap(":Resources/vcfolder_mis_open.svg"));
514 static QPixmap closeMissingPixmap(
515 svgToPixmap(":Resources/vcfolder_mis_close.svg"));
516 static QPixmap openSceneFolderPixmap(
517 svgToPixmap(":Resources/browser_scene_open.svg"));
518 static QPixmap closeSceneFolderPixmap(
519 svgToPixmap(":Resources/browser_scene_close.svg"));
520
521 if (TFileStatus(getPath()).doesExist()) {
522 if (getPath().getType() == "tnz")
523 return isOpen ? openSceneFolderPixmap : closeSceneFolderPixmap;
524 else
525 return isOpen ? openFolderPixmap : closeFolderPixmap;
526 } else
527 return isOpen ? openMissingPixmap : closeMissingPixmap;
528 }
529
530 //-----------------------------------------------------------------------------
531
insertVersionControlStatus(const QString & fileName,SVNStatus status)532 void DvDirVersionControlNode::insertVersionControlStatus(
533 const QString &fileName, SVNStatus status) {
534 m_statusMap.insert(fileName, status);
535 }
536
537 //-----------------------------------------------------------------------------
538
getVersionControlStatus(const QString & fileName)539 SVNStatus DvDirVersionControlNode::getVersionControlStatus(
540 const QString &fileName) {
541 if (m_statusMap.contains(fileName)) return m_statusMap.value(fileName);
542
543 SVNStatus s = SVNStatus();
544 s.m_isLocked = false;
545 s.m_isPartialEdited = false;
546 s.m_isPartialLocked = false;
547 return s;
548 }
549
550 //-----------------------------------------------------------------------------
551
refreshVersionControl(const QList<SVNStatus> & status)552 QStringList DvDirVersionControlNode::refreshVersionControl(
553 const QList<SVNStatus> &status) {
554 TFilePath nodePath = getPath();
555 if (nodePath.isEmpty()) return QStringList();
556
557 int listSize = status.size();
558 bool isSynched = true;
559
560 QStringList checkPartialLockList;
561
562 for (int i = 0; i < listSize; i++) {
563 SVNStatus s = status.at(i);
564
565 // It is not needed to check and cache SVNStatus for files that are
566 // "outside" the node "scope"
567 if (s.m_path == "." || s.m_path == ".." || s.m_path.split("\\").size() > 2)
568 continue;
569
570 QString fileName = s.m_path;
571 if (nodePath.getType() == "") insertVersionControlStatus(fileName, s);
572
573 // Update also the status of the "scene" child folders
574 TFilePath path(fileName.toStdWString());
575 if (path.getType() == "tnz") {
576 DvDirVersionControlNode *childVcNode =
577 dynamic_cast<DvDirVersionControlNode *>(
578 getNodeByPath(nodePath + path));
579 if (childVcNode) {
580 childVcNode->setIsUnderVersionControl(true);
581 if (s.m_repoStatus == "modified" || s.m_item == "modified" ||
582 s.m_item == "missing" || s.m_item == "none")
583 childVcNode->setIsSynched(false);
584 else if (s.m_item == "unversioned")
585 childVcNode->setIsUnversioned(true);
586 else
587 childVcNode->setIsSynched(true);
588 }
589 }
590 // If a folder is unversioned, I set its status and even the unversioned
591 // status for its children
592 else if (path.getType() == "" && s.m_item == "unversioned") {
593 DvDirVersionControlNode *childVcNode =
594 dynamic_cast<DvDirVersionControlNode *>(
595 getNodeByPath(nodePath + path));
596 if (childVcNode) {
597 childVcNode->setIsUnversioned(true);
598 int childCount = childVcNode->getChildCount();
599 for (int i = 0; i < childCount; i++) {
600 DvDirVersionControlNode *subChildNode =
601 dynamic_cast<DvDirVersionControlNode *>(childVcNode->getChild(i));
602 if (subChildNode) subChildNode->setIsUnversioned(true);
603 }
604 }
605 }
606
607 // Check also the 'partial-lock' property
608 std::string type = TFilePath(s.m_path.toStdWString()).getType();
609 if (type == "tlv" || type == "pli") {
610 if (s.m_item != "unversioned" && s.m_item != "missing" &&
611 s.m_repoStatus != "added")
612 checkPartialLockList.append(s.m_path);
613 }
614
615 if (s.m_repoStatus == "modified" || s.m_item == "modified" ||
616 s.m_item == "unversioned" || s.m_item == "missing" ||
617 s.m_item == "none")
618 isSynched = false;
619 }
620
621 setIsSynched(isSynched);
622 return checkPartialLockList;
623 }
624
625 //-----------------------------------------------------------------------------
626
627 DvDirVersionControlRootNode *
getVersionControlRootNode()628 DvDirVersionControlNode::getVersionControlRootNode() {
629 DvDirModelNode *parent = getParent();
630 if (parent) return parent->getVersionControlRootNode();
631 return 0;
632 }
633
634 //=============================================================================
635 //
636 // DvDirVersionControlRootNode [Special File Folder]
637 //
638 //-----------------------------------------------------------------------------
639
DvDirVersionControlRootNode(DvDirModelNode * parent,std::wstring name,const TFilePath & path)640 DvDirVersionControlRootNode::DvDirVersionControlRootNode(DvDirModelNode *parent,
641 std::wstring name,
642 const TFilePath &path)
643 : DvDirVersionControlNode(parent, name, path) {
644 setPixmap(svgToPixmap(":Resources/vcroot.svg"));
645 setIsUnderVersionControl(true);
646 }
647
648 //-----------------------------------------------------------------------------
649
refreshChildren()650 void DvDirVersionControlRootNode::refreshChildren() {
651 DvDirModelFileFolderNode::refreshChildren();
652 }
653
654 //=============================================================================
655 // DvDirVersionControlProjectNode
656 //-----------------------------------------------------------------------------
657
DvDirVersionControlProjectNode(DvDirModelNode * parent,std::wstring name,const TFilePath & path)658 DvDirVersionControlProjectNode::DvDirVersionControlProjectNode(
659 DvDirModelNode *parent, std::wstring name, const TFilePath &path)
660 : DvDirVersionControlNode(parent, name, path) {
661 m_nodeType = "Project";
662 setIsUnderVersionControl(true);
663 }
664
665 //-----------------------------------------------------------------------------
666
getProjectPath() const667 TFilePath DvDirVersionControlProjectNode::getProjectPath() const {
668 return TProjectManager::instance()->projectFolderToProjectPath(getPath());
669 }
670
671 //-----------------------------------------------------------------------------
672
isCurrent() const673 bool DvDirVersionControlProjectNode::isCurrent() const {
674 TProjectManager *pm = TProjectManager::instance();
675 return pm->getCurrentProjectPath().getParentDir() == getPath();
676 }
677
678 //-----------------------------------------------------------------------------
679
makeCurrent()680 void DvDirVersionControlProjectNode::makeCurrent() {
681 TProjectManager *pm = TProjectManager::instance();
682 TFilePath projectPath = getProjectPath();
683 if (!IoCmd::saveSceneIfNeeded(QObject::tr("Change project"))) return;
684 pm->setCurrentProjectPath(projectPath);
685 IoCmd::newScene();
686 }
687
688 //-----------------------------------------------------------------------------
689
getPixmap(bool isOpen) const690 QPixmap DvDirVersionControlProjectNode::getPixmap(bool isOpen) const {
691 static QPixmap openPixmap(
692 svgToPixmap(":Resources/browser_vcproject_open.svg"));
693 static QPixmap closePixmap(
694 svgToPixmap(":Resources/browser_vcproject_close.svg"));
695 static QPixmap openMissingPixmap(
696 svgToPixmap(":Resources/vcfolder_mis_open.svg"));
697 static QPixmap closeMissingPixmap(
698 svgToPixmap(":Resources/vcfolder_mis_close.svg"));
699
700 if (TFileStatus(getPath()).doesExist())
701 return isOpen ? openPixmap : closePixmap;
702 else
703 return isOpen ? openMissingPixmap : closeMissingPixmap;
704 }
705
706 //-----------------------------------------------------------------------------
707
refreshChildren()708 void DvDirVersionControlProjectNode::refreshChildren() {
709 DvDirModelFileFolderNode::refreshChildren();
710 int i;
711 TProjectManager *pm = TProjectManager::instance();
712 TProject *project = new TProject();
713 project->load(getProjectPath());
714 for (i = 0; i < getChildCount(); i++) {
715 DvDirModelFileFolderNode *node =
716 dynamic_cast<DvDirModelFileFolderNode *>(getChild(i));
717 if (node) {
718 int k = project->getFolderIndexFromPath(node->getPath());
719 node->setIsProjectFolder(k >= 0);
720 }
721 }
722 delete project;
723 }
724
725 //-----------------------------------------------------------------------------
726
getChildrenNames(std::vector<std::wstring> & names) const727 void DvDirVersionControlProjectNode::getChildrenNames(
728 std::vector<std::wstring> &names) const {
729 DvDirVersionControlNode::getChildrenNames(names);
730 TProjectManager *pm = TProjectManager::instance();
731 TProject *project = new TProject();
732 project->load(getProjectPath());
733 int i;
734 for (i = 0; i < project->getFolderCount(); i++) {
735 std::string folderName = project->getFolderName(i);
736 TFilePath folderPath = project->getFolder(i);
737 // if(folderPath.isAbsolute() || folderPath.getParentDir() != TFilePath())
738 if (folderPath.isAbsolute() && project->isConstantFolder(i)) {
739 names.push_back(L"+" + ::to_wstring(folderName));
740 }
741 }
742 delete project;
743 }
744
745 //=============================================================================
746 //
747 // DvDirModelProjectNode [Project Folder]
748 //
749 //-----------------------------------------------------------------------------
750
DvDirModelProjectNode(DvDirModelNode * parent,const TFilePath & path)751 DvDirModelProjectNode::DvDirModelProjectNode(DvDirModelNode *parent,
752 const TFilePath &path)
753 : DvDirModelFileFolderNode(parent, path) {
754 m_nodeType = "Project";
755 }
756
757 //-----------------------------------------------------------------------------
758
getProjectPath() const759 TFilePath DvDirModelProjectNode::getProjectPath() const {
760 return TProjectManager::instance()->projectFolderToProjectPath(getPath());
761 }
762
763 //-----------------------------------------------------------------------------
764
isCurrent() const765 bool DvDirModelProjectNode::isCurrent() const {
766 TProjectManager *pm = TProjectManager::instance();
767 return pm->getCurrentProjectPath().getParentDir() == getPath();
768 }
769
770 //-----------------------------------------------------------------------------
771
makeCurrent()772 void DvDirModelProjectNode::makeCurrent() {
773 TProjectManager *pm = TProjectManager::instance();
774 TFilePath projectPath = getProjectPath();
775 if (!IoCmd::saveSceneIfNeeded(QObject::tr("Change project"))) return;
776
777 pm->setCurrentProjectPath(projectPath);
778 IoCmd::newScene();
779 }
780
781 //-----------------------------------------------------------------------------
782
getPixmap(bool isOpen) const783 QPixmap DvDirModelProjectNode::getPixmap(bool isOpen) const {
784 static QPixmap openProjectPixmap(
785 svgToPixmap(getIconThemePath("actions/18/folder_project_on.svg")));
786 static QPixmap closeProjectPixmap(
787 svgToPixmap(getIconThemePath("actions/18/folder_project.svg")));
788 return isOpen ? openProjectPixmap : closeProjectPixmap;
789 }
790
791 //-----------------------------------------------------------------------------
792
refreshChildren()793 void DvDirModelProjectNode::refreshChildren() {
794 DvDirModelFileFolderNode::refreshChildren();
795 int i;
796 TProjectManager *pm = TProjectManager::instance();
797 TProject *project = new TProject();
798 project->load(getProjectPath());
799 for (i = 0; i < getChildCount(); i++) {
800 DvDirModelFileFolderNode *node =
801 dynamic_cast<DvDirModelFileFolderNode *>(getChild(i));
802 if (node) {
803 int k = project->getFolderIndexFromPath(node->getPath());
804 node->setIsProjectFolder(k >= 0);
805 }
806 }
807 delete project;
808 }
809
810 //-----------------------------------------------------------------------------
811
getChildrenNames(std::vector<std::wstring> & names) const812 void DvDirModelProjectNode::getChildrenNames(
813 std::vector<std::wstring> &names) const {
814 DvDirModelFileFolderNode::getChildrenNames(names);
815 TProjectManager *pm = TProjectManager::instance();
816 TProject *project = new TProject();
817 project->load(getProjectPath());
818 int i;
819 for (i = 0; i < project->getFolderCount(); i++) {
820 std::string folderName = project->getFolderName(i);
821 TFilePath folderPath = project->getFolder(i);
822 // if(folderPath.isAbsolute() || folderPath.getParentDir() != TFilePath())
823 if (folderPath.isAbsolute() && project->isConstantFolder(i)) {
824 names.push_back(L"+" + ::to_wstring(folderName));
825 }
826 }
827 delete project;
828 }
829
830 //-----------------------------------------------------------------------------
831
makeChild(std::wstring name)832 DvDirModelNode *DvDirModelProjectNode::makeChild(std::wstring name) {
833 if (name != L"" && name[0] == L'+') {
834 TProjectManager *pm = TProjectManager::instance();
835 TProject *project = new TProject();
836 project->load(getProjectPath());
837 std::string folderName = ::to_string(name.substr(1));
838 TFilePath folderPath = project->getFolder(folderName);
839 DvDirModelNode *node = new DvDirModelFileFolderNode(this, name, folderPath);
840 delete project;
841 return node;
842 } else
843 return DvDirModelFileFolderNode::makeChild(name);
844 }
845
846 //=============================================================================
847 //
848 // DvDirModelDayNode [Day folder]
849 //
850 //-----------------------------------------------------------------------------
851
DvDirModelDayNode(DvDirModelNode * parent,std::wstring dayDateString)852 DvDirModelDayNode::DvDirModelDayNode(DvDirModelNode *parent,
853 std::wstring dayDateString)
854 : DvDirModelNode(parent, dayDateString)
855 , m_dayDateString(::to_string(dayDateString)) {
856 m_nodeType = "Day";
857 }
858
859 //-----------------------------------------------------------------------------
860
visualizeContent(FileBrowser * browser)861 void DvDirModelDayNode::visualizeContent(FileBrowser *browser) {
862 browser->setHistoryDay(m_dayDateString);
863 }
864
865 //-----------------------------------------------------------------------------
866
getPixmap(bool isOpen) const867 QPixmap DvDirModelDayNode::getPixmap(bool isOpen) const {
868 static QPixmap openFolderPixmap(
869 svgToPixmap(getIconThemePath("actions/18/folder_on.svg")));
870 static QPixmap closeFolderPixmap(
871 svgToPixmap(getIconThemePath("actions/18/folder.svg")));
872 return isOpen ? openFolderPixmap : closeFolderPixmap;
873 }
874
875 //=============================================================================
876 //
877 // DvDirModelHistoryNode [History]
878 //
879 //-----------------------------------------------------------------------------
880
DvDirModelHistoryNode(DvDirModelNode * parent)881 DvDirModelHistoryNode::DvDirModelHistoryNode(DvDirModelNode *parent)
882 : DvDirModelNode(parent, L"History") {
883 m_nodeType = "History";
884 }
885
886 //-----------------------------------------------------------------------------
887
refreshChildren()888 void DvDirModelHistoryNode::refreshChildren() {
889 m_children.clear();
890 m_childrenValid = true;
891 History *h = History::instance();
892 for (int i = 0; i < h->getDayCount(); i++) {
893 const History::Day *day = h->getDay(i);
894 DvDirModelNode *child =
895 new DvDirModelDayNode(this, ::to_wstring(day->getDate()));
896 addChild(child);
897 }
898 }
899
900 //-----------------------------------------------------------------------------
901
getPixmap(bool isOpen) const902 QPixmap DvDirModelHistoryNode::getPixmap(bool isOpen) const {
903 QIcon icon = createQIcon("history");
904 static QPixmap pixmap = icon.pixmap(16);
905 return pixmap;
906 }
907
908 //=============================================================================
909 //
910 // DvDirModelMyComputerNode [My Computer]
911 //
912 //-----------------------------------------------------------------------------
913
DvDirModelMyComputerNode(DvDirModelNode * parent)914 DvDirModelMyComputerNode::DvDirModelMyComputerNode(DvDirModelNode *parent)
915 : DvDirModelNode(parent, L"My Computer") {
916 // setIcon(QFileIconProvider().icon(QFileIconProvider::Computer));
917 m_nodeType = "MyComputer";
918 }
919
920 //-----------------------------------------------------------------------------
921
refreshChildren()922 void DvDirModelMyComputerNode::refreshChildren() {
923 m_childrenValid = true;
924 if (!m_children.empty()) clearPointerContainer(m_children);
925
926 TFilePathSet fps = TSystem::getDisks();
927
928 #ifdef MACOSX
929 fps.push_back(TFilePath("/Volumes/"));
930 #endif
931
932 TFilePathSet::iterator it;
933 for (it = fps.begin(); it != fps.end(); ++it) {
934 DvDirModelNode *child =
935 new DvDirModelFileFolderNode(this, it->getWideString(), *it);
936 addChild(child);
937 }
938 }
939
940 //-----------------------------------------------------------------------------
941
getPixmap(bool isOpen) const942 QPixmap DvDirModelMyComputerNode::getPixmap(bool isOpen) const {
943 QIcon icon = createQIcon("my_computer");
944 static QPixmap pixmap = icon.pixmap(16);
945 return pixmap;
946 }
947
948 //=============================================================================
949 //
950 // DvDirModelNetworkNode [Network]
951 //
952 //-----------------------------------------------------------------------------
953
DvDirModelNetworkNode(DvDirModelNode * parent)954 DvDirModelNetworkNode::DvDirModelNetworkNode(DvDirModelNode *parent)
955 : DvDirModelNode(parent, L"Network") {
956 m_nodeType = "Network";
957 }
958
959 //-----------------------------------------------------------------------------
960
refreshChildren()961 void DvDirModelNetworkNode::refreshChildren() {
962 m_childrenValid = true;
963
964 if (!m_children.empty()) clearPointerContainer(m_children);
965
966 #ifdef _WIN32
967
968 // Enumerate network nodes
969 HANDLE enumHandle;
970 DWORD err =
971 WNetOpenEnum(RESOURCE_CONTEXT, RESOURCETYPE_DISK, 0, NULL, &enumHandle);
972 assert(err == NO_ERROR);
973
974 DWORD count = -1,
975 bufferSize =
976 16 << 10; // Use 16 kB as recommended on Windows references
977 LPNETRESOURCE buffer = (LPNETRESOURCE)malloc(bufferSize);
978
979 do {
980 // Get the next bunch of network devices
981 memset(buffer, 0, bufferSize);
982 err = WNetEnumResource(enumHandle, &count, buffer, &bufferSize);
983
984 if (err == NO_ERROR) {
985 for (int i = 0; i < count; ++i) {
986 // Only list disk-type devices - in any case, the remote (UNC) name
987 // should exist
988 if (buffer[i].dwType == RESOURCETYPE_DISK && buffer[i].lpRemoteName) {
989 std::wstring wstr(buffer[i].lpRemoteName);
990
991 // Build a NOT PEEKING folder node. This is important since network
992 // access is SLOW.
993 DvDirModelFileFolderNode *child =
994 new DvDirModelFileFolderNode(this, wstr, TFilePath(wstr));
995 child->setPeeking(false);
996
997 addChild(child);
998 }
999 }
1000 } else if (err != ERROR_NO_MORE_ITEMS)
1001 break; // Excluding NO_ERROR and ERROR_NO_MORE_ITEMS, quit
1002
1003 } while (err != ERROR_NO_MORE_ITEMS);
1004
1005 err = WNetCloseEnum(enumHandle);
1006 assert(err == NO_ERROR);
1007
1008 free(buffer);
1009
1010 #endif
1011 }
1012
1013 //-----------------------------------------------------------------------------
1014
getPixmap(bool isOpen) const1015 QPixmap DvDirModelNetworkNode::getPixmap(bool isOpen) const {
1016 QIcon icon = createQIcon("network");
1017 static QPixmap pixmap = icon.pixmap(16);
1018 return pixmap;
1019 }
1020
1021 //=============================================================================
1022 //
1023 // DvDirModelRootNode [Root]
1024 //
1025 //-----------------------------------------------------------------------------
1026
DvDirModelRootNode()1027 DvDirModelRootNode::DvDirModelRootNode()
1028 : DvDirModelNode(0, L"Root")
1029 , m_myComputerNode(0)
1030 , m_networkNode(0)
1031 , m_sandboxProjectNode(0) {
1032 m_nodeType = "Root";
1033 }
1034
1035 //-----------------------------------------------------------------------------
1036
add(std::wstring name,const TFilePath & path)1037 void DvDirModelRootNode::add(std::wstring name, const TFilePath &path) {
1038 DvDirModelNode *child = new DvDirModelFileFolderNode(this, name, path);
1039 child->setRow((int)m_children.size());
1040 m_children.push_back(child);
1041 }
1042
1043 //-----------------------------------------------------------------------------
1044
refreshChildren()1045 void DvDirModelRootNode::refreshChildren() {
1046 m_childrenValid = true;
1047 if (m_children.empty()) {
1048 addChild(m_myComputerNode = new DvDirModelMyComputerNode(this));
1049
1050 #ifdef _WIN32
1051 addChild(m_networkNode = new DvDirModelNetworkNode(this));
1052 #endif
1053 DvDirModelSpecialFileFolderNode *child;
1054 child = new DvDirModelSpecialFileFolderNode(this, L"My Documents",
1055 getMyDocumentsPath());
1056 child->setPixmap(recolorPixmap(
1057 svgToPixmap(getIconThemePath("actions/16/my_documents.svg"))));
1058 m_specialNodes.push_back(child);
1059 addChild(child);
1060
1061 child =
1062 new DvDirModelSpecialFileFolderNode(this, L"Desktop", getDesktopPath());
1063 child->setPixmap(
1064 recolorPixmap(svgToPixmap(getIconThemePath("actions/16/desktop.svg"))));
1065 m_specialNodes.push_back(child);
1066 addChild(child);
1067
1068 child = new DvDirModelSpecialFileFolderNode(
1069 this, L"Library", ToonzFolder::getLibraryFolder());
1070 child->setPixmap(
1071 recolorPixmap(svgToPixmap(getIconThemePath("actions/16/library.svg"))));
1072 m_specialNodes.push_back(child);
1073 addChild(child);
1074
1075 addChild(new DvDirModelHistoryNode(this));
1076
1077 TProjectManager *pm = TProjectManager::instance();
1078 std::vector<TFilePath> projectRoots;
1079 pm->getProjectRoots(projectRoots);
1080
1081 int i;
1082 for (i = 0; i < (int)projectRoots.size(); i++) {
1083 TFilePath projectRoot = projectRoots[i];
1084 std::wstring roothDir = projectRoot.getWideString();
1085 DvDirModelSpecialFileFolderNode *projectRootNode =
1086 new DvDirModelSpecialFileFolderNode(
1087 this, L"Project root (" + roothDir + L")", projectRoot);
1088 projectRootNode->setPixmap(QPixmap(recolorPixmap(svgToPixmap(
1089 getIconThemePath("actions/18/folder_project_root.svg")))));
1090 m_projectRootNodes.push_back(projectRootNode);
1091 addChild(projectRootNode);
1092 }
1093
1094 TFilePath sandboxProjectPath = pm->getSandboxProjectFolder();
1095 m_sandboxProjectNode = new DvDirModelProjectNode(this, sandboxProjectPath);
1096 addChild(m_sandboxProjectNode);
1097
1098 // SVN Repositories
1099 QList<SVNRepository> repositories =
1100 VersionControl::instance()->getRepositories();
1101 int count = repositories.size();
1102 for (int i = 0; i < count; i++) {
1103 SVNRepository repo = repositories.at(i);
1104 DvDirVersionControlRootNode *node = new DvDirVersionControlRootNode(
1105 this, repo.m_name.toStdWString(),
1106 TFilePath(repo.m_localPath.toStdWString()));
1107 node->setRepositoryPath(repo.m_repoPath.toStdWString());
1108 node->setLocalPath(repo.m_localPath.toStdWString());
1109 node->setUserName(repo.m_username.toStdWString());
1110 node->setPassword(repo.m_password.toStdWString());
1111 m_versionControlNodes.push_back(node);
1112 addChild(node);
1113 }
1114
1115 // scenefolder node (access to the parent folder of the current scene file)
1116 m_sceneFolderNode =
1117 new DvDirModelSceneFolderNode(this, L"Scene Folder", TFilePath());
1118 m_sceneFolderNode->setPixmap(QPixmap(":Resources/clapboard.png"));
1119 }
1120 }
1121
1122 //-----------------------------------------------------------------------------
getNodeByPath(const TFilePath & path)1123 DvDirModelNode *DvDirModelRootNode::getNodeByPath(const TFilePath &path) {
1124 // Check first for version control nodes
1125 DvDirModelNode *node = 0;
1126 int i;
1127
1128 // search in #1 the project folders, #2 sandbox, #3 other folders in file
1129 // system
1130
1131 // check for the scene folder if it is the first priority
1132 Preferences::PathAliasPriority priority =
1133 Preferences::instance()->getPathAliasPriority();
1134 if (priority == Preferences::SceneFolderAlias &&
1135 !m_sceneFolderNode->getPath().isEmpty()) {
1136 node = m_sceneFolderNode->getNodeByPath(path);
1137 if (node) return node;
1138 }
1139
1140 // path could be a project, under some project root
1141 for (i = 0; i < (int)m_projectRootNodes.size(); i++) {
1142 node = m_projectRootNodes[i]->getNodeByPath(path);
1143 if (node) return node;
1144 // search in the project folders
1145 for (int j = 0; j < m_projectRootNodes[i]->getChildCount(); j++) {
1146 DvDirModelProjectNode *projectNode =
1147 dynamic_cast<DvDirModelProjectNode *>(
1148 m_projectRootNodes[i]->getChild(j));
1149 if (projectNode) {
1150 // for the normal folder in the project folder
1151 node = projectNode->getNodeByPath(path);
1152 if (node) return node;
1153
1154 if (projectNode->isCurrent()) {
1155 // for the aliases in the project folder ("+drawings" etc.)
1156 for (int k = 0; k < projectNode->getChildCount(); k++) {
1157 node = projectNode->getChild(k)->getNodeByPath(path);
1158 if (node) return node;
1159 }
1160 }
1161 } else // for the normal folder in the project root
1162 {
1163 node = m_projectRootNodes[i]->getChild(j)->getNodeByPath(path);
1164 if (node) return node;
1165 }
1166 }
1167 }
1168
1169 // it could be on a repository, under version control
1170 for (i = 0; i < (int)m_versionControlNodes.size(); i++) {
1171 node = m_versionControlNodes[i]->getNodeByPath(path);
1172 if (node) return node;
1173 }
1174
1175 // or it could be the sandbox project or in the sandbox project
1176 if (m_sandboxProjectNode && m_sandboxProjectNode->getPath() == path)
1177 return m_sandboxProjectNode;
1178 if (m_sandboxProjectNode) {
1179 for (i = 0; i < m_sandboxProjectNode->getChildCount(); i++) {
1180 DvDirModelNode *node =
1181 m_sandboxProjectNode->getChild(i)->getNodeByPath(path);
1182 if (node) return node;
1183 }
1184 }
1185
1186 // check for the scene folder if it is the second priority
1187 if (priority == Preferences::ProjectFolderAliases &&
1188 !m_sceneFolderNode->getPath().isEmpty()) {
1189 node = m_sceneFolderNode->getNodeByPath(path);
1190 if (node) return node;
1191 }
1192
1193 // check for the special folders (My Documents / Desktop / Library)
1194 for (DvDirModelSpecialFileFolderNode *specialNode : m_specialNodes) {
1195 DvDirModelNode *node = specialNode->getNodeByPath(path);
1196 if (node) return node;
1197 }
1198
1199 // it could be a regular folder, somewhere in the file system
1200 if (m_myComputerNode) {
1201 for (i = 0; i < m_myComputerNode->getChildCount(); i++) {
1202 DvDirModelNode *node = m_myComputerNode->getChild(i)->getNodeByPath(path);
1203 if (node) return node;
1204 }
1205 }
1206
1207 // it could be a network folder
1208 if (m_networkNode) {
1209 for (i = 0; i < m_networkNode->getChildCount(); i++) {
1210 DvDirModelNode *node = m_networkNode->getChild(i)->getNodeByPath(path);
1211 if (node) return node;
1212 }
1213 }
1214
1215 return 0;
1216 }
1217
1218 //-----------------------------------------------------------------------------
1219 // update the path of sceneLocationNode
1220
setSceneLocation(const TFilePath & path)1221 void DvDirModelRootNode::setSceneLocation(const TFilePath &path) {
1222 if (path == m_sceneFolderNode->getPath()) return;
1223 m_sceneFolderNode->setPath(path);
1224
1225 Preferences::PathAliasPriority priority =
1226 Preferences::instance()->getPathAliasPriority();
1227 if (priority == Preferences::ProjectFolderOnly) return;
1228
1229 updateSceneFolderNodeVisibility();
1230 }
1231
1232 //-----------------------------------------------------------------------------
1233
updateSceneFolderNodeVisibility(bool forceHide)1234 void DvDirModelRootNode::updateSceneFolderNodeVisibility(bool forceHide) {
1235 bool show = (forceHide) ? false : !m_sceneFolderNode->getPath().isEmpty();
1236 if (show && m_sceneFolderNode->getRow() == -1) {
1237 int row = getChildCount();
1238 DvDirModel::instance()->notifyBeginInsertRows(QModelIndex(), row, row + 1);
1239 addChild(m_sceneFolderNode);
1240 DvDirModel::instance()->notifyEndInsertRows();
1241 } else if (!show && m_sceneFolderNode->getRow() != -1) {
1242 int row = m_sceneFolderNode->getRow();
1243 DvDirModel::instance()->notifyBeginRemoveRows(QModelIndex(), row, row + 1);
1244 // remove the last child of the root node
1245 m_children.erase(m_children.begin() + row, m_children.begin() + row + 1);
1246 DvDirModel::instance()->notifyEndRemoveRows();
1247 m_sceneFolderNode->setRow(-1);
1248 }
1249 }
1250
1251 //=============================================================================
1252 //
1253 // DvDirModel
1254 //
1255 //-----------------------------------------------------------------------------
1256
DvDirModel()1257 DvDirModel::DvDirModel() {
1258 m_root = new DvDirModelRootNode();
1259 m_root->refreshChildren();
1260
1261 // when the scene switched, update the path of the scene location node
1262 TSceneHandle *sceneHandle = TApp::instance()->getCurrentScene();
1263 bool ret = true;
1264 ret = ret && connect(sceneHandle, SIGNAL(sceneSwitched()), this,
1265 SLOT(onSceneSwitched()));
1266 ret = ret && connect(sceneHandle, SIGNAL(nameSceneChanged()), this,
1267 SLOT(onSceneSwitched()));
1268 ret = ret && connect(sceneHandle, SIGNAL(preferenceChanged(const QString &)),
1269 this, SLOT(onPreferenceChanged(const QString &)));
1270 assert(ret);
1271
1272 onSceneSwitched();
1273 }
1274
1275 //-----------------------------------------------------------------------------
1276
~DvDirModel()1277 DvDirModel::~DvDirModel() { delete m_root; }
1278
1279 //-----------------------------------------------------------------------------
1280
onFolderChanged(const TFilePath & path)1281 void DvDirModel::onFolderChanged(const TFilePath &path) { refreshFolder(path); }
1282
1283 //-----------------------------------------------------------------------------
1284
refresh(const QModelIndex & index)1285 void DvDirModel::refresh(const QModelIndex &index) {
1286 if (!index.isValid()) return;
1287 DvDirModelNode *node = getNode(index);
1288 if (!node || node->getChildCount() < 1) return;
1289 emit layoutAboutToBeChanged();
1290 emit beginRemoveRows(index, 0, node->getChildCount() - 1);
1291 node->refreshChildren();
1292 emit endRemoveRows();
1293 emit layoutChanged();
1294 }
1295
1296 //-----------------------------------------------------------------------------
1297
refreshFolder(const TFilePath & folderPath,const QModelIndex & i)1298 void DvDirModel::refreshFolder(const TFilePath &folderPath,
1299 const QModelIndex &i) {
1300 DvDirModelNode *node = getNode(i);
1301 if (!node) return;
1302 if (node->isFolder(folderPath))
1303 refresh(i);
1304 else if (node->areChildrenValid()) {
1305 int count = rowCount(i);
1306 int r;
1307 for (r = 0; r < count; r++) refreshFolder(folderPath, index(r, 0, i));
1308 }
1309 }
1310
1311 //-----------------------------------------------------------------------------
1312
refreshFolderChild(const QModelIndex & i)1313 void DvDirModel::refreshFolderChild(const QModelIndex &i) {
1314 DvDirModelNode *node = getNode(i);
1315 if (!node || !node->areChildrenValid()) return;
1316
1317 if (node->isFolder() || dynamic_cast<DvDirModelMyComputerNode *>(node))
1318 refresh(i);
1319 int count = rowCount(i);
1320 int r;
1321 for (r = 0; r < count; r++) refreshFolderChild(index(r, 0, i));
1322 }
1323
1324 //-----------------------------------------------------------------------------
1325
getNode(const QModelIndex & index) const1326 DvDirModelNode *DvDirModel::getNode(const QModelIndex &index) const {
1327 if (index.isValid())
1328 return static_cast<DvDirModelNode *>(index.internalPointer());
1329 else
1330 return m_root;
1331 }
1332
1333 //-----------------------------------------------------------------------------
1334
index(int row,int column,const QModelIndex & parent) const1335 QModelIndex DvDirModel::index(int row, int column,
1336 const QModelIndex &parent) const {
1337 if (column != 0) return QModelIndex();
1338 DvDirModelNode *parentNode = m_root;
1339 if (parent.isValid()) parentNode = getNode(parent);
1340 if (row < 0 || row >= parentNode->getChildCount()) return QModelIndex();
1341 DvDirModelNode *node = parentNode->getChild(row);
1342 return createIndex(row, column, node);
1343 }
1344
1345 //-----------------------------------------------------------------------------
1346
parent(const QModelIndex & index) const1347 QModelIndex DvDirModel::parent(const QModelIndex &index) const {
1348 if (!index.isValid()) return QModelIndex();
1349 DvDirModelNode *node = getNode(index);
1350 DvDirModelNode *parentNode = node->getParent();
1351 if (!parentNode || parentNode == m_root)
1352 return QModelIndex();
1353 else
1354 return createIndex(parentNode->getRow(), 0, parentNode);
1355 }
1356
1357 //-----------------------------------------------------------------------------
1358
childByName(const QModelIndex & parent,const std::wstring & name) const1359 QModelIndex DvDirModel::childByName(const QModelIndex &parent,
1360 const std::wstring &name) const {
1361 if (!parent.isValid()) return QModelIndex();
1362 DvDirModelNode *parentNode = getNode(parent);
1363 if (!parentNode) return QModelIndex();
1364 int row = parentNode->rowByName(name);
1365 if (row < 0 || row >= parentNode->getChildCount()) return QModelIndex();
1366 DvDirModelNode *childNode = parentNode->getChild(row);
1367 return createIndex(row, 0, childNode);
1368 }
1369
1370 //-----------------------------------------------------------------------------
1371
rowCount(const QModelIndex & parent) const1372 int DvDirModel::rowCount(const QModelIndex &parent) const {
1373 DvDirModelNode *node = getNode(parent);
1374 return node->getChildCount();
1375 }
1376
1377 //-----------------------------------------------------------------------------
1378
hasChildren(const QModelIndex & parent) const1379 bool DvDirModel::hasChildren(const QModelIndex &parent) const {
1380 DvDirModelNode *node = getNode(parent);
1381 return node->hasChildren();
1382 }
1383
1384 //-----------------------------------------------------------------------------
1385
data(const QModelIndex & index,int role) const1386 QVariant DvDirModel::data(const QModelIndex &index, int role) const {
1387 if (!index.isValid()) return QVariant();
1388 DvDirModelNode *node = getNode(index);
1389 if (role == Qt::DisplayRole || role == Qt::EditRole)
1390 return QString::fromStdWString(node->getName());
1391 else if (role == Qt::DecorationRole) {
1392 return QVariant();
1393 } else if (role == Qt::ForegroundRole) {
1394 if (!node || !node->isRenameEnabled())
1395 return QBrush(Qt::blue);
1396 else
1397 return QVariant();
1398 } else
1399 return QVariant();
1400 }
1401
1402 //-----------------------------------------------------------------------------
1403
flags(const QModelIndex & index) const1404 Qt::ItemFlags DvDirModel::flags(const QModelIndex &index) const {
1405 Qt::ItemFlags flags = QAbstractItemModel::flags(index);
1406 if (index.isValid()) {
1407 DvDirModelNode *node = getNode(index);
1408 if (node && node->isRenameEnabled()) flags |= Qt::ItemIsEditable;
1409 }
1410 return flags;
1411 }
1412
1413 //-----------------------------------------------------------------------------
1414 /*! used only for name / rename of items
1415 */
setData(const QModelIndex & index,const QVariant & value,int role)1416 bool DvDirModel::setData(const QModelIndex &index, const QVariant &value,
1417 int role) {
1418 if (!index.isValid()) return false;
1419 DvDirModelNode *node = getNode(index);
1420 if (!node || !node->isRenameEnabled()) return false;
1421 QString newName = value.toString();
1422 if (newName == "") return false;
1423 if (!node->setName(newName.toStdWString())) return false;
1424 emit dataChanged(index, index);
1425 return true;
1426 }
1427
1428 //-----------------------------------------------------------------------------
1429
removeRows(int row,int count,const QModelIndex & parentIndex)1430 bool DvDirModel::removeRows(int row, int count,
1431 const QModelIndex &parentIndex) {
1432 if (!parentIndex.isValid()) return false;
1433 DvDirModelNode *node = getNode(parentIndex);
1434 if (!node) return false;
1435 emit beginRemoveRows(parentIndex, row, row + count - 1);
1436 node->removeChildren(row, count);
1437 emit endRemoveRows();
1438 return true;
1439 }
1440
1441 //-----------------------------------------------------------------------------
1442
getIndexByPath(const TFilePath & path) const1443 QModelIndex DvDirModel::getIndexByPath(const TFilePath &path) const {
1444 return getIndexByNode(m_root->getNodeByPath(path));
1445 }
1446
1447 //-----------------------------------------------------------------------------
1448
getIndexByNode(DvDirModelNode * node) const1449 QModelIndex DvDirModel::getIndexByNode(DvDirModelNode *node) const {
1450 if (!node) return QModelIndex();
1451 return createIndex(node->getRow(), 0, node);
1452 }
1453
1454 //-----------------------------------------------------------------------------
1455
getCurrentProjectIndex() const1456 QModelIndex DvDirModel::getCurrentProjectIndex() const {
1457 return getIndexByPath(
1458 TProjectManager::instance()->getCurrentProjectPath().getParentDir());
1459 }
1460
1461 //-----------------------------------------------------------------------------
1462
instance()1463 DvDirModel *DvDirModel::instance() {
1464 static DvDirModel _instance;
1465 return &_instance;
1466 }
1467
1468 //-----------------------------------------------------------------------------
1469
onSceneSwitched()1470 void DvDirModel::onSceneSwitched() {
1471 DvDirModelRootNode *rootNode = dynamic_cast<DvDirModelRootNode *>(m_root);
1472 if (rootNode) {
1473 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
1474 if (scene) {
1475 if (scene->isUntitled())
1476 rootNode->setSceneLocation(TFilePath());
1477 else
1478 rootNode->setSceneLocation(scene->getScenePath().getParentDir());
1479 }
1480 }
1481 }
1482
1483 //-----------------------------------------------------------------------------
1484
onPreferenceChanged(const QString & prefName)1485 void DvDirModel::onPreferenceChanged(const QString &prefName) {
1486 if (prefName != "PathAliasPriority") return;
1487
1488 Preferences::PathAliasPriority priority =
1489 Preferences::instance()->getPathAliasPriority();
1490 DvDirModelRootNode *rootNode = dynamic_cast<DvDirModelRootNode *>(m_root);
1491 if (rootNode)
1492 rootNode->updateSceneFolderNodeVisibility(priority ==
1493 Preferences::ProjectFolderOnly);
1494 }
1495