1 
2 
3 #include "toonz/studiopalette.h"
4 #include "tfiletype.h"
5 #include "tstream.h"
6 #include "tconvert.h"
7 #include "tlevel_io.h"
8 #include "trasterimage.h"
9 #include "traster.h"
10 #include "tsystem.h"
11 #include "tcolorstyles.h"
12 #include "toonz/toonzfolders.h"
13 #include "toonz/tproject.h"
14 #include "toonz/toonzscene.h"
15 #include "tpalette.h"
16 
17 #include <time.h>
18 #include <stdio.h>
19 #include <sys/types.h>
20 #include <string.h>
21 
22 #include <QSettings>
23 
24 //===================================================================
25 
26 //-------------------------------------------------------------------
27 namespace {
28 //-------------------------------------------------------------------
29 
makeUniqueName(TFilePath fp)30 TFilePath makeUniqueName(TFilePath fp) {
31   if (TFileStatus(fp).doesExist() == false) return fp;
32   std::wstring name = fp.getWideName();
33   int index         = 2;
34   int j             = name.find_last_not_of(L"0123456789");
35   if (j != (int)std::wstring::npos && j + 1 < (int)name.length()) {
36     index = std::stoi(name.substr(j + 1)) + 1;
37     name  = name.substr(0, j + 1);
38   }
39   for (;;) {
40     fp = fp.withName(name + std::to_wstring(index));
41     if (TFileStatus(fp).doesExist() == false) return fp;
42     index++;
43   }
44 }
45 
46 //-------------------------------------------------------------------
47 
loadPliPalette(const TFilePath & fp)48 TPalette *loadPliPalette(const TFilePath &fp) {
49   TLevelReaderP lr(fp);
50   TLevelP level  = lr->loadInfo();
51   int frameCount = level->getFrameCount();
52   if (frameCount < 1) return 0;
53   TPalette *palette = level->getPalette();
54   if (!palette) return 0;
55   return palette->clone();
56 }
57 
58 //-------------------------------------------------------------------
59 
loadTplPalette(const TFilePath & fp)60 TPalette *loadTplPalette(const TFilePath &fp) {
61   TPersist *p = 0;
62   TIStream is(fp);
63   is >> p;
64   TPalette *palette = dynamic_cast<TPalette *>(p);
65   return palette;
66 }
67 
68 //-------------------------------------------------------------------
69 
loadToonz46Palette(const TFilePath & fp)70 TPalette *loadToonz46Palette(const TFilePath &fp) {
71   TImageP pltImg;
72   TImageReader::load(fp, pltImg);
73   if (!pltImg) return 0;
74   TRasterImageP pltRasImg(pltImg);
75   if (!pltRasImg) return 0;
76   TRaster32P rasPlt = pltRasImg->getRaster();
77   if (!rasPlt) return 0;
78   TPalette *palette = new TPalette();
79   const int offset  = 0;  // FirstUserStyle-1;
80   assert(rasPlt->getLy() == 2);
81   rasPlt->lock();
82   TPixel32 *pixelRow = rasPlt->pixels(0);
83   int x;
84   for (x = 1; x < rasPlt->getLx(); ++x) {
85     TPixel32 color = pixelRow[x];
86     int styleId    = offset + x;
87     if (styleId < palette->getStyleCount())
88       palette->setStyle(styleId, color);
89     else {
90       int j = palette->addStyle(color);
91       assert(j == styleId);
92     }
93   }
94 
95   // aggiungo solo i colori usati (salvo il BG)
96 
97   pixelRow             = rasPlt->pixels(1);
98   TPalette::Page *page = palette->getPage(0);
99   for (x = 1; x < rasPlt->getLx(); ++x) {
100     if (pixelRow[x].r == 255)
101       page->addStyle(offset +
102                      x);  // palette->addStyleToPage(offset+x, L"colors");
103   }
104   rasPlt->unlock();
105   return palette;
106 }
107 
108 //-------------------------------------------------------------------
109 
readPaletteGlobalName(TFilePath path)110 std::wstring readPaletteGlobalName(TFilePath path) {
111   try {
112     TIStream is(path);
113     if (!is) return L"";
114     std::string tagName;
115     if (!is.matchTag(tagName) || tagName != "palette") return L"";
116     std::string name;
117     if (is.getTagParam("name", name)) return ::to_wstring(name);
118   } catch (...) {
119   }
120   return L"";
121 }
122 //-------------------------------------------------------------------
123 
searchPalette(TFilePath path,std::wstring paletteId)124 TFilePath searchPalette(TFilePath path, std::wstring paletteId) {
125   TFilePathSet q;
126   try {
127     TSystem::readDirectory(q, path);
128   } catch (...) {
129   }
130 
131   for (TFilePathSet::iterator i = q.begin(); i != q.end(); ++i) {
132     TFilePath fp = *i;
133     if (fp.getType() == "tpl") {
134       std::wstring gname = readPaletteGlobalName(fp);
135       if (gname == paletteId) return fp;
136     } else if (TFileStatus(fp).isDirectory()) {
137       TFilePath palettePath = searchPalette(fp, paletteId);
138       if (palettePath != TFilePath()) return palettePath;
139     }
140   }
141   return TFilePath();
142 }
143 
144 bool studioPaletteHasBeenReferred = false;
145 
146 static std::map<std::wstring, TFilePath> table;
147 // table loaded from the cache. verify once before storing in the table
148 static std::map<std::wstring, TFilePath> table_cached;
149 
150 const std::string pathTableFileName = "palette_paths.ini";
151 
152 //-------------------------------------------------------------------
153 }  // namespace
154 //-------------------------------------------------------------------
155 
156 //===================================================================
157 //
158 // StudioPalette
159 //
160 //-------------------------------------------------------------------
161 
StudioPalette()162 StudioPalette::StudioPalette() {
163   try {
164     m_root = ToonzFolder::getStudioPaletteFolder();
165   } catch (...) {
166     return;
167   }
168   if (!TFileStatus(m_root).doesExist()) {
169     try {
170       TSystem::mkDir(m_root);
171       FolderListenerManager::instance()->notifyFolderChanged(
172           m_root.getParentDir());
173     } catch (...) {
174     }
175     try {
176       TSystem::mkDir(getLevelPalettesRoot());
177       FolderListenerManager::instance()->notifyFolderChanged(
178           getLevelPalettesRoot().getParentDir());
179     } catch (...) {
180     }
181   }
182 
183   // load [global id] - [path] table file
184   TFilePath rootFps[2] = {m_root, getProjectPalettesRoot()};
185   for (auto rootFp : rootFps) {
186     if (rootFp.isEmpty()) continue;
187     TFilePath tablePath = rootFp + pathTableFileName;
188     if (!TFileStatus(tablePath).doesExist()) continue;
189     QSettings tableSettings(QString::fromStdWString(tablePath.getWideString()),
190                             QSettings::IniFormat);
191     for (auto key : tableSettings.allKeys())
192       table_cached[key.toStdWString()] =
193           rootFp + TFilePath(tableSettings.value(key, "").toString());
194   }
195 }
196 
197 //-------------------------------------------------------------------
198 
~StudioPalette()199 StudioPalette::~StudioPalette() {}
200 
201 //-------------------------------------------------------------------
202 
203 bool StudioPalette::m_enabled = true;
204 
205 //-------------------------------------------------------------------
206 
enable(bool enabled)207 void StudioPalette::enable(bool enabled) {
208   assert(studioPaletteHasBeenReferred == false);
209   m_enabled = enabled;
210 }
211 
212 //-------------------------------------------------------------------
213 
instance()214 StudioPalette *StudioPalette::instance() {
215   static StudioPalette _instance;
216   studioPaletteHasBeenReferred = true;
217   assert(m_enabled);
218   return &_instance;
219 }
220 
221 //-------------------------------------------------------------------
222 
getLevelPalettesRoot()223 TFilePath StudioPalette::getLevelPalettesRoot() {
224   return m_root + "Global Palettes";
225 }
226 
227 //-------------------------------------------------------------------
228 
getProjectPalettesRoot()229 TFilePath StudioPalette::getProjectPalettesRoot() {
230   TProjectP p          = TProjectManager::instance()->getCurrentProject();
231   TFilePath folderName = p->getFolder(TProject::Palettes);
232   if (folderName.isEmpty()) return TFilePath();
233   if (folderName.isAbsolute()) return folderName;
234   return p->getProjectFolder() + folderName;
235 }
236 
237 //-------------------------------------------------------------------
238 
loadRefImg(TPalette * palette,TFilePath dir)239 static bool loadRefImg(TPalette *palette, TFilePath dir) {
240   assert(palette);
241   TFilePath fp = palette->getRefImgPath();
242   if (fp == TFilePath() || !TSystem::doesExistFileOrLevel(fp)) return false;
243   if (!fp.isAbsolute()) fp = dir + fp;
244   TLevelReaderP lr(fp);
245   if (!lr) return false;
246   TLevelP level = lr->loadInfo();
247   if (!level || level->getFrameCount() == 0) return false;
248   TLevel::Iterator it = level->begin();
249   TImageP img         = lr->getFrameReader(it->first)->load();
250   if (!img) return false;
251   img->setPalette(0);
252   palette->setRefImg(img);
253   return true;
254 }
255 
256 //-------------------------------------------------------------------
257 
getPalette(const TFilePath & path,bool loadRefImgFlag)258 TPalette *StudioPalette::getPalette(const TFilePath &path,
259                                     bool loadRefImgFlag) {
260   try {
261     if (path.getType() != "tpl") return 0;
262     TPalette *palette = load(path);
263     if (!palette) return 0;
264     if (loadRefImgFlag) loadRefImg(palette, path.getParentDir());
265     // palette->addRef(); // ci va??
266     return palette;
267   } catch (...) {
268     return 0;
269   }
270 }
271 
272 //-------------------------------------------------------------------
273 
movePalette(const TFilePath & dstPath,const TFilePath & srcPath)274 void StudioPalette::movePalette(const TFilePath &dstPath,
275                                 const TFilePath &srcPath) {
276   try {
277     // do not allow overwrite palette
278     TSystem::renameFile(dstPath, srcPath, false);
279   } catch (...) {
280     throw;
281   }
282   std::wstring id = readPaletteGlobalName(dstPath);
283   table.erase(id);
284   removeEntry(id);
285   FolderListenerManager::instance()->notifyFolderChanged(
286       dstPath.getParentDir());
287   notifyMove(dstPath, srcPath);
288 }
289 
290 //-------------------------------------------------------------------
291 
getChildren(std::vector<TFilePath> & fps,const TFilePath & folderPath)292 int StudioPalette::getChildren(std::vector<TFilePath> &fps,
293                                const TFilePath &folderPath) {
294   TFilePathSet q;
295   if (TFileStatus(folderPath).isDirectory()) {
296     try {
297       TSystem::readDirectory(q, folderPath, false, false);
298     } catch (...) {
299     }
300   }
301 
302   // put the folders above the palette items
303   std::vector<TFilePath> palettes;
304   for (TFilePathSet::iterator i = q.begin(); i != q.end(); ++i) {
305     if (isFolder(*i))
306       fps.push_back(*i);
307     else if (isPalette(*i))
308       palettes.push_back(*i);
309   }
310   if (!palettes.empty()) {
311     fps.reserve(fps.size() + palettes.size());
312     std::copy(palettes.begin(), palettes.end(), std::back_inserter(fps));
313   }
314   //  fps.push_back(m_root+"butta.tpl");
315   return fps.size();
316 }
317 
318 //-------------------------------------------------------------------
319 
getChildCount(const TFilePath & folderPath)320 int StudioPalette::getChildCount(const TFilePath &folderPath) {
321   TFilePathSet q;
322   try {
323     TSystem::readDirectory(q, folderPath);
324   } catch (...) {
325   }
326   return q.size();
327 }
328 
329 //-------------------------------------------------------------------
330 
isFolder(const TFilePath & path)331 bool StudioPalette::isFolder(const TFilePath &path) {
332   return TFileStatus(path).isDirectory();
333 }
334 
335 //-------------------------------------------------------------------
336 
isReadOnly(const TFilePath & path)337 bool StudioPalette::isReadOnly(const TFilePath &path) {
338   return !TFileStatus(path).isWritable();
339 }
340 
341 //-------------------------------------------------------------------
342 
isPalette(const TFilePath & path)343 bool StudioPalette::isPalette(const TFilePath &path) {
344   return path.getType() == "tpl";
345 }
346 
347 //-------------------------------------------------------------------
348 /*! check if the palette is studio palette or level palette in order to separate
349  * icons in the StudioPaletteTree.
350  */
hasGlobalName(const TFilePath & path)351 bool StudioPalette::hasGlobalName(const TFilePath &path) {
352   return (readPaletteGlobalName(path) != L"");
353 }
354 
355 //-------------------------------------------------------------------
356 
isLevelPalette(const TFilePath & path)357 bool StudioPalette::isLevelPalette(const TFilePath &path) {
358   TPalette *palette = getPalette(path);
359   if (!palette) return false;
360   bool ret = !palette->isCleanupPalette();
361   delete palette;
362   return ret;
363 }
364 
365 //-------------------------------------------------------------------
366 
createFolder(const TFilePath & parentFolderPath)367 TFilePath StudioPalette::createFolder(const TFilePath &parentFolderPath) {
368   TFilePath path = makeUniqueName(parentFolderPath + "new folder");
369   try {
370     TSystem::mkDir(path);
371   } catch (...) {
372     return TFilePath();
373   }
374   FolderListenerManager::instance()->notifyFolderChanged(parentFolderPath);
375   notifyTreeChange();
376   return path;
377 }
378 
379 //-------------------------------------------------------------------
380 
createFolder(const TFilePath & parentFolderPath,std::wstring name)381 void StudioPalette::createFolder(const TFilePath &parentFolderPath,
382                                  std::wstring name) {
383   TFilePath fp = parentFolderPath + name;
384   if (TFileStatus(fp).doesExist()) return;
385   try {
386     TSystem::mkDir(fp);
387   } catch (...) {
388     return;
389   }
390   FolderListenerManager::instance()->notifyFolderChanged(parentFolderPath);
391   notifyTreeChange();
392 }
393 
394 //-------------------------------------------------------------------
395 
createPalette(const TFilePath & folderPath,std::string name)396 TFilePath StudioPalette::createPalette(const TFilePath &folderPath,
397                                        std::string name) {
398   TPalette *palette = 0;
399   if (name == "") name = "new palette";
400   palette      = new TPalette();
401   TFilePath fp = makeUniqueName(folderPath + (name + ".tpl"));
402   time_t ltime;
403   time(&ltime);
404   std::wstring gname = std::to_wstring(ltime) + L"_" + std::to_wstring(rand());
405   palette->setGlobalName(gname);
406   setStylesGlobalNames(palette);
407   try {
408     save(fp, palette);
409   } catch (...) {
410     delete palette;
411     throw;
412   }
413   delete palette;
414   notifyTreeChange();
415   return fp;
416 }
417 
418 //-------------------------------------------------------------------
419 
setPalette(const TFilePath & palettePath,const TPalette * plt,bool notifyPaletteChanged)420 void StudioPalette::setPalette(const TFilePath &palettePath,
421                                const TPalette *plt, bool notifyPaletteChanged) {
422   assert(palettePath.getType() == "tpl");
423   TPalette *palette = plt->clone();
424   palette->setIsLocked(plt->isLocked());
425   palette->addRef();
426   std::wstring pgn = palette->getGlobalName();
427   if (TFileStatus(palettePath).doesExist())
428     pgn = readPaletteGlobalName(palettePath);
429   palette->setGlobalName(pgn);
430   setStylesGlobalNames(palette);
431   try {
432     save(palettePath, palette);
433   } catch (...) {
434     palette->release();
435     throw;
436   }
437   palette->release();
438   if (notifyPaletteChanged) notifyPaletteChange(palettePath);
439 }
440 
441 //-------------------------------------------------------------------
442 
deletePalette(const TFilePath & palettePath)443 void StudioPalette::deletePalette(const TFilePath &palettePath) {
444   assert(palettePath.getType() == "tpl");
445   try {
446     TSystem::deleteFile(palettePath);
447   } catch (...) {
448     return;
449   }
450   notifyTreeChange();
451 }
452 
453 //-------------------------------------------------------------------
454 
deleteFolder(const TFilePath & path)455 void StudioPalette::deleteFolder(const TFilePath &path) {
456   try {
457     TSystem::rmDirTree(path);
458   } catch (...) {
459   }
460   notifyTreeChange();
461 }
462 
463 //-------------------------------------------------------------------
464 
importPalette(const TFilePath & dstFolder,const TFilePath & srcPath)465 TFilePath StudioPalette::importPalette(const TFilePath &dstFolder,
466                                        const TFilePath &srcPath) {
467   TPaletteP palette;
468   std::string ext = srcPath.getType();
469   try {
470     if (ext == "plt")
471       palette = loadToonz46Palette(srcPath);
472     else if (ext == "pli")
473       palette = loadPliPalette(srcPath);
474     else if (ext == "tpl")
475       palette = loadTplPalette(srcPath);
476   } catch (...) {
477   }
478 
479   if (!palette) return TFilePath();
480   std::wstring name = srcPath.getWideName();
481 
482   assert(!palette->isCleanupPalette());
483   //    convertToLevelPalette(palette.getPointer());
484 
485   TFilePath fp = makeUniqueName(dstFolder + (name + L".tpl"));
486   time_t ltime;
487   time(&ltime);
488   std::wstring gname = std::to_wstring(ltime) + L"_" + std::to_wstring(rand());
489   palette->setGlobalName(gname);
490   setStylesGlobalNames(palette.getPointer());
491   TSystem::touchParentDir(fp);
492   save(fp, palette.getPointer());
493   notifyTreeChange();
494   return fp;
495 }
496 
497 //-------------------------------------------------------------------
498 
499 // TFilePath StudioPalette::getRefImage(const TFilePath palette)
500 //{
501 //  return palette.withType("pli");
502 //}
503 
504 //-------------------------------------------------------------------
505 
foobar(std::wstring paletteId)506 static void foobar(std::wstring paletteId) { table.erase(paletteId); }
507 
getPalettePath(std::wstring paletteId)508 TFilePath StudioPalette::getPalettePath(std::wstring paletteId) {
509   std::map<std::wstring, TFilePath>::iterator it = table.find(paletteId);
510   if (it != table.end()) return it->second;
511   TFilePath fp;
512   // not found in the verified table, then check for the cached table
513   it = table_cached.find(paletteId);
514   // found in the cached table
515   if (it != table_cached.end()) {
516     fp = it->second;
517     // verify if cached path is correct
518     if (fp.getType() != "tpl" ||
519         readPaletteGlobalName(it->second) != paletteId) {
520       fp = TFilePath();
521       // erase the entry
522       it = table_cached.erase(it);
523       removeEntry(paletteId);
524     }
525   }
526   if (fp.isEmpty()) {
527     fp = searchPalette(m_root, paletteId);
528     if (fp.isEmpty()) fp = searchPalette(getProjectPalettesRoot(), paletteId);
529 
530     addEntry(paletteId, fp);
531   }
532   table[paletteId] = fp;
533   return fp;
534 }
535 
536 //-------------------------------------------------------------------
537 
getPalette(std::wstring paletteId)538 TPalette *StudioPalette::getPalette(std::wstring paletteId) {
539   TFilePath palettePath = getPalettePath(paletteId);
540   if (palettePath != TFilePath())
541     return getPalette(palettePath);
542   else
543     return 0;
544 }
545 
546 //-------------------------------------------------------------------
547 
getStyle(std::wstring styleId)548 TColorStyle *StudioPalette::getStyle(std::wstring styleId) { return 0; }
549 
550 //-------------------------------------------------------------------
551 
getSourceStyle(TColorStyle * cs)552 std::pair<TFilePath, int> StudioPalette::getSourceStyle(TColorStyle *cs) {
553   std::pair<TFilePath, int> ret(TFilePath(), -1);
554   if (!cs) return ret;
555   std::wstring gname = cs->getGlobalName();
556   if (gname == L"") return ret;
557   int k = gname.find_first_of(L'-', 1);
558   if (k == (int)std::wstring::npos) return ret;
559   std::wstring paletteId = gname.substr(1, k - 1);
560   ret.first              = getPalettePath(paletteId) - m_root;
561   ret.second             = std::stoi(gname.substr(k + 1));
562   return ret;
563 }
564 
565 //-------------------------------------------------------------------
566 /*! return if any style in the palette is changed
567  */
updateLinkedColors(TPalette * palette)568 bool StudioPalette::updateLinkedColors(TPalette *palette) {
569   bool paletteIsChanged = false;
570   std::map<std::wstring, TPaletteP> table;
571 
572   for (int i = 0; i < palette->getStyleCount(); i++) {
573     TColorStyle *cs    = palette->getStyle(i);
574     std::wstring gname = cs->getGlobalName();
575     if (gname == L"" || gname[0] != L'+') continue;
576     int k = gname.find_first_of(L'-', 1);
577     if (k == (int)std::wstring::npos) continue;
578     std::wstring paletteId = gname.substr(1, k - 1);
579     std::map<std::wstring, TPaletteP>::iterator it;
580     it                  = table.find(paletteId);
581     TPalette *spPalette = 0;
582     if (it == table.end()) {
583       spPalette = getPalette(paletteId);
584       if (!spPalette) continue;
585       table[paletteId] = spPalette;
586       // spPalette->release();
587       assert(spPalette->getRefCount() == 1);
588     } else
589       spPalette = it->second.getPointer();
590 
591     int j = std::stoi(gname.substr(k + 1));
592     if (spPalette && 0 <= j && j < spPalette->getStyleCount()) {
593       TColorStyle *spStyle = spPalette->getStyle(j);
594       assert(spStyle);
595       spStyle = spStyle->clone();
596       spStyle->setGlobalName(gname);
597 
598       // put the style name in the studio palette into the original name
599       spStyle->setOriginalName(spStyle->getName());
600       //.. and keep the style name unchanged
601       spStyle->setName(cs->getName());
602 
603       palette->setStyle(i, spStyle);
604 
605       paletteIsChanged = true;
606     }
607   }
608   return paletteIsChanged;
609 }
610 
611 //-------------------------------------------------------------------
612 
setStylesGlobalNames(TPalette * palette)613 void StudioPalette::setStylesGlobalNames(TPalette *palette) {
614   for (int i = 0; i < palette->getStyleCount(); i++) {
615     TColorStyle *cs = palette->getStyle(i);
616     // set global name only to the styles of which the global name is empty
617     if (cs->getGlobalName() == L"") {
618       std::wstring gname =
619           L"-" + palette->getGlobalName() + L"-" + std::to_wstring(i);
620       cs->setGlobalName(gname);
621     }
622   }
623 }
624 
625 //-------------------------------------------------------------------
626 
save(const TFilePath & path,TPalette * palette)627 void StudioPalette::save(const TFilePath &path, TPalette *palette) {
628   TFileStatus fs(path);
629   if (fs.doesExist() && !fs.isWritable()) {
630     throw TSystemException(path,
631                            "The studio palette cannot be saved: it is a read "
632                            "only studio palette.");
633   }
634 
635   TOStream os(path);
636   if (!os) {
637     throw TSystemException(path,
638                            "The studio palette cannot be saved: the output "
639                            "stream status is invalid.");
640   }
641   std::map<std::string, std::string> attr;
642   attr["name"] = ::to_string(palette->getGlobalName());
643   os.openChild("palette", attr);
644   palette->saveData(os);
645   os.closeChild();
646 }
647 
648 //-------------------------------------------------------------------
649 
load(const TFilePath & path)650 TPalette *StudioPalette::load(const TFilePath &path) {
651   try {
652     TIStream is(path);
653     if (!is) return 0;
654     std::string tagName;
655     if (!is.matchTag(tagName) || tagName != "palette") return 0;
656     std::string gname;
657     is.getTagParam("name", gname);
658     TPalette *palette = new TPalette();
659     palette->loadData(is);
660     palette->setGlobalName(::to_wstring(gname));
661     is.matchEndTag();
662     palette->setPaletteName(path.getWideName());
663     return palette;
664   } catch (...) {
665     return 0;
666   }
667 }
668 
669 //-------------------------------------------------------------------
670 
addListener(Listener * listener)671 void StudioPalette::addListener(Listener *listener) {
672   if (std::find(m_listeners.begin(), m_listeners.end(), listener) ==
673       m_listeners.end())
674     m_listeners.push_back(listener);
675 }
676 
677 //-------------------------------------------------------------------
678 
removeListener(Listener * listener)679 void StudioPalette::removeListener(Listener *listener) {
680   m_listeners.erase(
681       std::remove(m_listeners.begin(), m_listeners.end(), listener),
682       m_listeners.end());
683 }
684 
685 //-------------------------------------------------------------------
686 
notifyTreeChange()687 void StudioPalette::notifyTreeChange() {
688   for (std::vector<Listener *>::iterator it = m_listeners.begin();
689        it != m_listeners.end(); ++it)
690     (*it)->onStudioPaletteTreeChange();
691 }
692 
693 //-------------------------------------------------------------------
694 
notifyMove(const TFilePath & dstPath,const TFilePath & srcPath)695 void StudioPalette::notifyMove(const TFilePath &dstPath,
696                                const TFilePath &srcPath) {
697   for (std::vector<Listener *>::iterator it = m_listeners.begin();
698        it != m_listeners.end(); ++it)
699     (*it)->onStudioPaletteMove(dstPath, srcPath);
700 }
701 
702 //-------------------------------------------------------------------
703 
notifyPaletteChange(const TFilePath & palette)704 void StudioPalette::notifyPaletteChange(const TFilePath &palette) {
705   for (std::vector<Listener *>::iterator it = m_listeners.begin();
706        it != m_listeners.end(); ++it)
707     (*it)->onStudioPaletteChange(palette);
708 }
709 
710 //-------------------------------------------------------------------
711 
removeEntry(const std::wstring paletteId)712 void StudioPalette::removeEntry(const std::wstring paletteId) {
713   TFilePath rootFps[2] = {m_root, getProjectPalettesRoot()};
714   for (auto rootFp : rootFps) {
715     if (rootFp.isEmpty()) continue;
716     TFilePath tablePath = rootFp + pathTableFileName;
717     if (!TFileStatus(tablePath).doesExist()) continue;
718     QSettings tableSettings(QString::fromStdWString(tablePath.getWideString()),
719                             QSettings::IniFormat);
720     if (tableSettings.contains(QString::fromStdWString(paletteId))) {
721       tableSettings.remove(QString::fromStdWString(paletteId));
722       break;
723     }
724   }
725 }
726 
727 //-------------------------------------------------------------------
728 
addEntry(const std::wstring paletteId,const TFilePath & path)729 void StudioPalette::addEntry(const std::wstring paletteId,
730                              const TFilePath &path) {
731   TFilePath rootFps[2] = {m_root, getProjectPalettesRoot()};
732   for (auto rootFp : rootFps) {
733     if (rootFp.isEmpty()) continue;
734     if (!rootFp.isAncestorOf(path)) continue;
735 
736     TFilePath tablePath = rootFp + pathTableFileName;
737     QSettings tableSettings(QString::fromStdWString(tablePath.getWideString()),
738                             QSettings::IniFormat);
739     QString pathValue = (path - rootFp).getQString();
740     tableSettings.setValue(QString::fromStdWString(paletteId), pathValue);
741   }
742 }