1
2
3 #include "versioncontrol.h"
4 #include "versioncontrolgui.h"
5
6 #include "toonzqt/gutil.h"
7 #include "toonzqt/dvdialog.h"
8 #include "toonzqt/icongenerator.h"
9 #include "toonz/sceneresources.h"
10 #include "toonz/toonzscene.h"
11 #include "toonz/levelset.h"
12 #include "toonz/txshsimplelevel.h"
13 #include "toonz/txshlevelhandle.h"
14 #include "toonz/txshleveltypes.h"
15 #include "toonz/palettecontroller.h"
16 #include "toonz/tpalettehandle.h"
17 #include "toonz/tscenehandle.h"
18 #include "toonz/tproject.h"
19 #include "tsystem.h"
20 #include "tenv.h"
21 #include "tapp.h"
22 #include "permissionsmanager.h"
23
24 #include <QFile>
25 #include <QDir>
26 #include <QSettings>
27 #include <QRegExp>
28
29 namespace {
30
getFrameRange(const TFilePath & path,unsigned int & from,unsigned int & to)31 bool getFrameRange(const TFilePath &path, unsigned int &from,
32 unsigned int &to) {
33 // Set frame range
34 if (path.getDots() == "..") {
35 TFilePath dir = path.getParentDir();
36 QDir qDir(QString::fromStdWString(dir.getWideString()));
37 QString levelName =
38 QRegExp::escape(QString::fromStdWString(path.getWideName()));
39 QString levelType = QString::fromStdString(path.getType());
40 QString exp(levelName + ".[0-9]{1,4}." + levelType);
41 QRegExp regExp(exp);
42 QStringList list = qDir.entryList(QDir::Files);
43 QStringList levelFrames = list.filter(regExp);
44
45 from = -1;
46 to = -1;
47 for (int i = 0; i < levelFrames.size(); i++) {
48 TFilePath frame = dir + TFilePath(levelFrames[i].toStdWString());
49 if (frame.isEmpty() || !frame.isAbsolute()) continue;
50 TFileStatus filestatus(frame);
51 if (filestatus.isWritable()) {
52 if (from == -1)
53 from = i;
54 else
55 to = i;
56 } else if (from != -1 && to != -1)
57 break;
58 }
59
60 if (from != -1 && to != -1)
61 return true;
62 else
63 return false;
64 }
65 return false;
66 }
67
68 } // namespace
69
70 //=============================================================================
71 // VersionControlThread
72 //-----------------------------------------------------------------------------
73
VersionControlThread(QObject * parent)74 VersionControlThread::VersionControlThread(QObject *parent)
75 : QThread(parent)
76 , m_abort(false)
77 , m_restart(false)
78 , m_getStatus(false)
79 , m_readOutputOnDone(true)
80 , m_process(0) {}
81
82 //-----------------------------------------------------------------------------
83
~VersionControlThread()84 VersionControlThread::~VersionControlThread() {
85 m_mutex.lock();
86 m_abort = true;
87 m_condition.wakeOne();
88 m_mutex.unlock();
89
90 wait();
91 }
92
93 //-----------------------------------------------------------------------------
94
run()95 void VersionControlThread::run() {
96 forever {
97 m_mutex.lock();
98 QString workingDir = m_workingDir;
99 QString binary = m_binary;
100 QStringList args = m_args;
101
102 // Add Username and Password (if exists)
103
104 VersionControl *vc = VersionControl::instance();
105
106 QString userName = vc->getUserName();
107 QString password = vc->getPassword();
108
109 if (!userName.isEmpty() || !password.isEmpty()) {
110 args << QString("--username") << userName << QString("--password")
111 << password;
112 }
113
114 // Add "non-interactive" and "trust-server-cert" global options
115 args << "--non-interactive";
116 args << "--trust-server-cert";
117
118 QString executablePath = vc->getExecutablePath();
119 if (!executablePath.isEmpty()) binary = executablePath + "/" + m_binary;
120
121 m_mutex.unlock();
122
123 if (m_abort) {
124 if (m_process) {
125 m_process->close();
126 disconnect(m_process, SIGNAL(readyReadStandardOutput()), this,
127 SLOT(onStandardOutputReady()));
128 delete m_process;
129 m_process = 0;
130 }
131 return;
132 }
133
134 if (m_process) {
135 m_process->close();
136 disconnect(m_process, SIGNAL(readyReadStandardOutput()), this,
137 SLOT(onStandardOutputReady()));
138 delete m_process;
139 m_process = 0;
140 }
141
142 m_process = new QProcess;
143 if (!workingDir.isEmpty() && QFile::exists(workingDir))
144 m_process->setWorkingDirectory(workingDir);
145
146 QStringList env = QProcess::systemEnvironment();
147 env << "LC_MESSAGES=en_EN"; // Add this environment variables to fix the
148 // language to English
149 m_process->setEnvironment(env);
150
151 if (!m_readOutputOnDone)
152 connect(m_process, SIGNAL(readyReadStandardOutput()), this,
153 SLOT(onStandardOutputReady()));
154
155 m_process->start(binary, args);
156 if (!m_process->waitForStarted()) {
157 QString err = QString("Unable to launch \"%1\": %2")
158 .arg(binary, m_process->errorString());
159 emit error(err);
160 return;
161 }
162
163 m_process->closeWriteChannel();
164
165 // Wait until users press cancel (every 1 sec I check for abort..
166 while (!m_process->waitForFinished(1000)) {
167 if (m_abort) {
168 m_process->kill();
169 m_process->waitForFinished();
170 return;
171 }
172 }
173
174 if (m_process->exitStatus() != QProcess::NormalExit) {
175 QString err = QString("\"%1\" crashed.").arg(binary);
176 emit error(err);
177 return;
178 }
179
180 if (m_process->exitCode()) {
181 emit error(QString::fromUtf8(m_process->readAllStandardError().data()));
182 return;
183 }
184
185 if (m_getStatus) {
186 emit statusRetrieved(
187 QString::fromUtf8(m_process->readAllStandardOutput().data()));
188 m_getStatus = false;
189 } else
190 emit done(QString::fromUtf8(m_process->readAllStandardOutput().data()));
191
192 m_mutex.lock();
193 if (!m_restart) m_condition.wait(&m_mutex);
194 m_restart = false;
195 m_mutex.unlock();
196 }
197 }
198
199 //-----------------------------------------------------------------------------
200
onStandardOutputReady()201 void VersionControlThread::onStandardOutputReady() {
202 QString str = QString::fromUtf8(m_process->readAllStandardOutput().data());
203 if (str.isEmpty()) return;
204 emit outputRetrieved(str);
205 }
206
207 //-----------------------------------------------------------------------------
208
executeCommand(const QString & workingDir,const QString & binary,const QStringList & args,bool readOutputOnDone)209 void VersionControlThread::executeCommand(const QString &workingDir,
210 const QString &binary,
211 const QStringList &args,
212 bool readOutputOnDone) {
213 QMutexLocker locker(&m_mutex);
214
215 m_readOutputOnDone = readOutputOnDone;
216 m_workingDir = workingDir;
217 m_binary = binary;
218 m_args = args;
219
220 if (m_binary.isEmpty()) return;
221
222 if (!isRunning()) {
223 start(QThread::NormalPriority);
224 } else {
225 m_restart = true;
226 m_condition.wakeOne();
227 }
228 }
229
230 //-----------------------------------------------------------------------------
231
getSVNStatus(const QString & path,bool showUpdates,bool nonRecursive,bool depthInfinity)232 void VersionControlThread::getSVNStatus(const QString &path, bool showUpdates,
233 bool nonRecursive, bool depthInfinity) {
234 QMutexLocker locker(&m_mutex);
235
236 m_workingDir = path;
237 m_binary = QString("svn");
238 QStringList args;
239 args << "status";
240 if (showUpdates)
241 args << "-vu";
242 else
243 args << "-v";
244 if (nonRecursive) args << "--non-recursive";
245 if (depthInfinity)
246 args << "--depth"
247 << "infinity";
248
249 args << "--xml";
250 m_args = args;
251
252 m_getStatus = true;
253 m_readOutputOnDone = true;
254
255 if (!isRunning()) {
256 start(QThread::NormalPriority);
257 } else {
258 m_restart = true;
259 m_condition.wakeOne();
260 }
261 }
262
263 //-----------------------------------------------------------------------------
264
getSVNStatus(const QString & path,const QStringList & files,bool showUpdates,bool nonRecursive,bool depthInfinity)265 void VersionControlThread::getSVNStatus(const QString &path,
266 const QStringList &files,
267 bool showUpdates, bool nonRecursive,
268 bool depthInfinity) {
269 QMutexLocker locker(&m_mutex);
270 m_workingDir = path;
271 m_binary = QString("svn");
272 QStringList args;
273 args << "status";
274 if (showUpdates)
275 args << "-vu";
276 else
277 args << "-v";
278
279 int filesCount = files.size();
280 for (int i = 0; i < filesCount; i++) {
281 QString f = files.at(i);
282 if (!f.isEmpty()) args << f;
283 }
284 if (nonRecursive) args << "--non-recursive";
285 if (depthInfinity)
286 args << "--depth"
287 << "infinity";
288
289 args << "--xml";
290 m_args = args;
291
292 m_getStatus = true;
293 m_readOutputOnDone = true;
294
295 if (!isRunning()) {
296 start(QThread::NormalPriority);
297 } else {
298 m_restart = true;
299 m_condition.wakeOne();
300 }
301 }
302
303 //=============================================================================
304 // VersionControlManager
305 //-----------------------------------------------------------------------------
306
VersionControlManager()307 VersionControlManager::VersionControlManager()
308 : m_scene(0), m_levelSet(0), m_isRunning(false), m_deleteLater(false) {
309 connect(&m_thread, SIGNAL(error(const QString &)), this,
310 SLOT(onError(const QString &)));
311 }
312
313 //-----------------------------------------------------------------------------
314
instance()315 VersionControlManager *VersionControlManager::instance() {
316 static VersionControlManager _instance;
317 return &_instance;
318 }
319
320 //-----------------------------------------------------------------------------
setVersionControlCredentials(QString currentPath)321 static void setVersionControlCredentials(QString currentPath) {
322 VersionControl *vc = VersionControl::instance();
323 QList<SVNRepository> repositories = vc->getRepositories();
324 int repoCount = repositories.size();
325 for (int i = 0; i < repoCount; i++) {
326 SVNRepository r = repositories.at(i);
327 if (!currentPath.startsWith(r.m_localPath)) continue;
328 vc->setUserName(r.m_username);
329 vc->setPassword(r.m_password);
330 return;
331 }
332 }
333
setFrameRange(TLevelSet * levelSet,bool deleteLater)334 void VersionControlManager::setFrameRange(TLevelSet *levelSet,
335 bool deleteLater) {
336 if (levelSet->getLevelCount() == 0) return;
337
338 if (!m_isRunning) {
339 m_scene = 0; // Just to be sure
340 m_levelSet = levelSet;
341 m_deleteLater = deleteLater;
342
343 QStringList args;
344 args << "proplist";
345
346 bool checkVersionControl = false;
347 bool filesAddedToArgs = false;
348
349 for (int i = 0; i < levelSet->getLevelCount(); i++) {
350 TXshLevel *level = levelSet->getLevel(i);
351 TXshSimpleLevel *sl = level->getSimpleLevel();
352
353 if (sl && !checkVersionControl) {
354 TFilePath parentDir =
355 sl->getScene()->decodeFilePath(sl->getPath().getParentDir());
356 if (VersionControl::instance()->isFolderUnderVersionControl(
357 toQString(parentDir))) {
358 checkVersionControl = true;
359 setVersionControlCredentials(toQString(parentDir));
360 }
361 }
362
363 if (sl && sl->isReadOnly()) {
364 if (!m_scene) m_scene = sl->getScene();
365
366 if (sl->getType() == PLI_XSHLEVEL || sl->getType() == TZP_XSHLEVEL) {
367 filesAddedToArgs = true;
368 args << toQString(m_scene->decodeFilePath(level->getPath()));
369 } else if (sl->getType() == OVL_XSHLEVEL) {
370 unsigned int from;
371 unsigned int to;
372 bool ret = getFrameRange(m_scene->decodeFilePath(level->getPath()),
373 from, to);
374 if (ret)
375 sl->setEditableRange(
376 from, to,
377 VersionControl::instance()->getUserName().toStdWString());
378 }
379 }
380 }
381
382 if (!checkVersionControl || !filesAddedToArgs) {
383 if (m_deleteLater) {
384 m_deleteLater = false;
385 for (int i = m_levelSet->getLevelCount() - 1; i >= 0; i--) {
386 TXshLevel *l = m_levelSet->getLevel(i);
387 m_levelSet->removeLevel(l);
388 }
389 delete m_levelSet;
390 m_levelSet = 0;
391 }
392 m_scene = 0;
393 return;
394 }
395
396 args << "--xml";
397 args << "-v";
398
399 TFilePath path = m_scene->getScenePath();
400 path = m_scene->decodeFilePath(path);
401 QString workingDir = toQString(path.getParentDir());
402
403 m_thread.disconnect(SIGNAL(done(const QString &)));
404 connect(&m_thread, SIGNAL(done(const QString &)), this,
405 SLOT(onFrameRangeDone(const QString)));
406 m_thread.executeCommand(workingDir, "svn", args, true);
407 m_isRunning = true;
408 }
409 }
410
411 //-----------------------------------------------------------------------------
412
onFrameRangeDone(const QString & text)413 void VersionControlManager::onFrameRangeDone(const QString &text) {
414 m_isRunning = false;
415
416 SVNPartialLockReader lockReader(text);
417 QList<SVNPartialLock> list = lockReader.getPartialLock();
418 if (list.isEmpty()) {
419 if (m_deleteLater) {
420 m_deleteLater = false;
421
422 for (int i = m_levelSet->getLevelCount() - 1; i >= 0; i--) {
423 TXshLevel *l = m_levelSet->getLevel(i);
424 TXshSimpleLevel *sl = l->getSimpleLevel();
425 if (sl) sl->clearEditableRange();
426 m_levelSet->removeLevel(l);
427 }
428
429 delete m_levelSet;
430 m_levelSet = 0;
431 }
432 m_scene = 0;
433 return;
434 }
435
436 int listSize = list.count();
437 for (int l = 0; l < listSize; l++) {
438 SVNPartialLock pl = list.at(l);
439
440 QList<SVNPartialLockInfo> lockInfos = pl.m_partialLockList;
441
442 TFilePath currentPath = TFilePath(pl.m_fileName.toStdWString());
443
444 TXshSimpleLevel *level;
445 for (int i = 0; i < m_levelSet->getLevelCount(); i++) {
446 TXshLevel *l = m_levelSet->getLevel(i);
447 TFilePath levelPath = m_scene->decodeFilePath(l->getPath());
448 if (levelPath == currentPath) {
449 level = l->getSimpleLevel();
450 break;
451 }
452 }
453
454 setVersionControlCredentials(toQString(currentPath));
455
456 QString username = VersionControl::instance()->getUserName();
457 QString hostName = TSystem::getHostName();
458
459 int count = lockInfos.size();
460 for (int i = 0; i < count; i++) {
461 SVNPartialLockInfo info = lockInfos.at(i);
462 if (info.m_userName == username && info.m_hostName == hostName) {
463 level->setEditableRange(info.m_from - 1, info.m_to - 1,
464 info.m_userName.toStdWString());
465 invalidateIcons(level, level->getEditableRange());
466 TApp *app = TApp::instance();
467 if (app->getCurrentLevel()->getLevel() == level) {
468 app->getPaletteController()->getCurrentLevelPalette()->setPalette(
469 level->getPalette());
470 app->getCurrentLevel()->notifyLevelChange();
471 }
472 break;
473 }
474 }
475 }
476
477 if (m_deleteLater) {
478 m_deleteLater = false;
479
480 for (int i = m_levelSet->getLevelCount() - 1; i >= 0; i--) {
481 TXshLevel *l = m_levelSet->getLevel(i);
482 m_levelSet->removeLevel(l);
483 }
484
485 delete m_levelSet;
486 m_levelSet = 0;
487 }
488 m_scene = 0;
489 }
490
491 //-----------------------------------------------------------------------------
492
onError(const QString & text)493 void VersionControlManager::onError(const QString &text) {
494 m_isRunning = false;
495 if (m_deleteLater) {
496 m_deleteLater = false;
497 for (int i = m_levelSet->getLevelCount() - 1; i >= 0; i--) {
498 TXshLevel *l = m_levelSet->getLevel(i);
499 m_levelSet->removeLevel(l);
500 }
501 delete m_levelSet;
502 m_levelSet = 0;
503 }
504 m_scene = 0;
505 DVGui::warning(text);
506 }
507
508 //=============================================================================
509 // VersionControl
510 //-----------------------------------------------------------------------------
511
VersionControl()512 VersionControl::VersionControl()
513 : m_userName(), m_password(), m_executablePath() {}
514
515 //-----------------------------------------------------------------------------
516
instance()517 VersionControl *VersionControl::instance() {
518 static VersionControl _instance;
519 return &_instance;
520 }
521
522 //-----------------------------------------------------------------------------
523
init()524 void VersionControl::init() {
525 QString configFileName = QString::fromStdWString(
526 TFilePath(TEnv::getConfigDir() + "versioncontrol.xml").getWideString());
527
528 if (QFile::exists(configFileName)) {
529 QFile file(configFileName);
530 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
531 QString content = QString(file.readAll());
532 SVNConfigReader reader(content);
533 m_repositories = reader.getRepositories();
534 m_executablePath = reader.getSVNPath();
535 }
536 }
537 }
538
539 //-----------------------------------------------------------------------------
540
testSetup()541 bool VersionControl::testSetup() {
542 QString configFileName = QString::fromStdWString(
543 TFilePath(TEnv::getConfigDir() + "versioncontrol.xml").getWideString());
544
545 int repositoriesCount = 0;
546 QString path;
547 if (QFile::exists(configFileName)) {
548 QFile file(configFileName);
549 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
550 QString content = QString(file.readAll());
551 SVNConfigReader reader(content);
552 repositoriesCount = reader.getRepositories().size();
553 path = reader.getSVNPath();
554 }
555 }
556
557 // Test configuration file
558 if (repositoriesCount == 0) {
559 DVGui::error(
560 tr("The version control configuration file is empty or wrongly "
561 "defined.\nPlease refer to the user guide for details."));
562 return false;
563 }
564
565 // Test if svnPath is correct (adding another "/" before binary name doesn't
566 // create any issue both on Windows and on Mac
567 #ifdef MACOSX
568 if (!path.isEmpty() && !QFile::exists(path + "/svn"))
569 #else
570 if (!path.isEmpty() && !QFile::exists(path + "/svn.exe"))
571 #endif
572 {
573 DVGui::error(tr(
574 "The version control client application specified on the configuration "
575 "file cannot be found.\nPlease refer to the user guide for details."));
576 return false;
577 }
578
579 // Try to run svn executable, if the path is not specified in the config file,
580 // to test if exist
581 // In the meantime check for svn version
582 if (path.isEmpty()) {
583 QProcess p;
584
585 QStringList env = QProcess::systemEnvironment();
586 env << "LC_MESSAGES=en_EN"; // Add this environment variables to fix the
587 // language to English
588 p.setEnvironment(env);
589
590 p.start("svn", QStringList("--version"));
591
592 if (!p.waitForStarted()) {
593 DVGui::error(
594 tr("The version control client application is not installed on your "
595 "computer.\nSubversion 1.5 or later is required.\nPlease refer to "
596 "the user guide for details."));
597 return false;
598 }
599
600 if (!p.waitForFinished()) {
601 DVGui::error(
602 tr("The version control client application is not installed on your "
603 "computer.\nSubversion 1.5 or later is required.\nPlease refer to "
604 "the user guide for details."));
605 return false;
606 }
607
608 QString output(p.readAllStandardOutput());
609
610 QStringList list = output.split("\n");
611
612 if (!list.isEmpty()) {
613 QString firstLine = list.first();
614 firstLine = firstLine.remove("svn, version ");
615
616 double version = firstLine.left(3).toDouble();
617 if (version <= 1.5) {
618 DVGui::warning(
619 tr("The version control client application installed on your "
620 "computer needs to be updated, otherwise some features may not "
621 "be available.\nSubversion 1.5 or later is required.\nPlease "
622 "refer to the user guide for details."));
623 return true;
624 }
625 }
626 }
627 return true;
628 }
629
630 //-----------------------------------------------------------------------------
isFolderUnderVersionControl(const QString & folderPath)631 bool VersionControl::isFolderUnderVersionControl(const QString &folderPath) {
632 QDir dir(folderPath);
633 if (dir.entryList(QDir::AllDirs | QDir::Hidden).contains(".svn")) return true;
634 // For SVN 1.7 and greater, check parent directories to see if it's under
635 // version control
636 while (dir.cdUp()) {
637 if (dir.entryList(QDir::AllDirs | QDir::Hidden).contains(".svn"))
638 return true;
639 }
640
641 return false;
642 }
643
644 //-----------------------------------------------------------------------------
645
commit(QWidget * parent,const QString & workingDir,const QStringList & filesToCommit,bool folderOnly,int sceneIconAdded)646 void VersionControl::commit(QWidget *parent, const QString &workingDir,
647 const QStringList &filesToCommit, bool folderOnly,
648 int sceneIconAdded) {
649 SVNCommitDialog *dialog = new SVNCommitDialog(
650 parent, workingDir, filesToCommit, folderOnly, sceneIconAdded);
651 connect(dialog, SIGNAL(done(const QStringList &)), this,
652 SIGNAL(commandDone(const QStringList &)));
653 dialog->show();
654 dialog->raise();
655 }
656
657 //-----------------------------------------------------------------------------
658
revert(QWidget * parent,const QString & workingDir,const QStringList & files,bool folderOnly,int sceneIconAdded)659 void VersionControl::revert(QWidget *parent, const QString &workingDir,
660 const QStringList &files, bool folderOnly,
661 int sceneIconAdded) {
662 SVNRevertDialog *dialog = new SVNRevertDialog(parent, workingDir, files,
663 folderOnly, sceneIconAdded);
664 connect(dialog, SIGNAL(done(const QStringList &)), this,
665 SIGNAL(commandDone(const QStringList &)));
666 dialog->show();
667 dialog->raise();
668 }
669
670 //-----------------------------------------------------------------------------
671
update(QWidget * parent,const QString & workingDir,const QStringList & filesToUpdate,int sceneIconsCounts,bool folderOnly,bool updateToRevision,bool nonRecursive)672 void VersionControl::update(QWidget *parent, const QString &workingDir,
673 const QStringList &filesToUpdate,
674 int sceneIconsCounts, bool folderOnly,
675 bool updateToRevision, bool nonRecursive) {
676 SVNUpdateDialog *dialog =
677 new SVNUpdateDialog(parent, workingDir, filesToUpdate, sceneIconsCounts,
678 folderOnly, updateToRevision, nonRecursive);
679 connect(dialog, SIGNAL(done(const QStringList &)), this,
680 SIGNAL(commandDone(const QStringList &)));
681 dialog->show();
682 dialog->raise();
683 }
684
685 //-----------------------------------------------------------------------------
686
updateAndLock(QWidget * parent,const QString & workingDir,const QStringList & files,int workingRevision,int sceneIconAdded)687 void VersionControl::updateAndLock(QWidget *parent, const QString &workingDir,
688 const QStringList &files,
689 int workingRevision, int sceneIconAdded) {
690 SVNUpdateAndLockDialog *dialog = new SVNUpdateAndLockDialog(
691 parent, workingDir, files, workingRevision, sceneIconAdded);
692 connect(dialog, SIGNAL(done(const QStringList &)), this,
693 SIGNAL(commandDone(const QStringList &)));
694 dialog->show();
695 dialog->raise();
696 }
697
698 //-----------------------------------------------------------------------------
699
lock(QWidget * parent,const QString & workingDir,const QStringList & filesToLock,int sceneIconAdded)700 void VersionControl::lock(QWidget *parent, const QString &workingDir,
701 const QStringList &filesToLock, int sceneIconAdded) {
702 SVNLockDialog *dialog =
703 new SVNLockDialog(parent, workingDir, filesToLock, true, sceneIconAdded);
704 connect(dialog, SIGNAL(done(const QStringList &)), this,
705 SIGNAL(commandDone(const QStringList &)));
706 dialog->show();
707 dialog->raise();
708 }
709
710 //-----------------------------------------------------------------------------
711
unlock(QWidget * parent,const QString & workingDir,const QStringList & filesToUnlock,int sceneIconAdded)712 void VersionControl::unlock(QWidget *parent, const QString &workingDir,
713 const QStringList &filesToUnlock,
714 int sceneIconAdded) {
715 SVNLockDialog *dialog = new SVNLockDialog(parent, workingDir, filesToUnlock,
716 false, sceneIconAdded);
717 connect(dialog, SIGNAL(done(const QStringList &)), this,
718 SIGNAL(commandDone(const QStringList &)));
719 dialog->show();
720 dialog->raise();
721 }
722
723 //-----------------------------------------------------------------------------
724
lockFrameRange(QWidget * parent,const QString & workingDir,const QString & file,int frameCount)725 void VersionControl::lockFrameRange(QWidget *parent, const QString &workingDir,
726 const QString &file, int frameCount) {
727 SVNLockFrameRangeDialog *dialog =
728 new SVNLockFrameRangeDialog(parent, workingDir, file, frameCount);
729 connect(dialog, SIGNAL(done(const QStringList &)), this,
730 SIGNAL(commandDone(const QStringList &)));
731 dialog->show();
732 dialog->raise();
733 }
734
735 //-----------------------------------------------------------------------------
736
lockFrameRange(QWidget * parent,const QString & workingDir,const QStringList & files)737 void VersionControl::lockFrameRange(QWidget *parent, const QString &workingDir,
738 const QStringList &files) {
739 SVNLockMultiFrameRangeDialog *dialog =
740 new SVNLockMultiFrameRangeDialog(parent, workingDir, files);
741 connect(dialog, SIGNAL(done(const QStringList &)), this,
742 SIGNAL(commandDone(const QStringList &)));
743 dialog->show();
744 dialog->raise();
745 }
746
747 //-----------------------------------------------------------------------------
748
unlockFrameRange(QWidget * parent,const QString & workingDir,const QString & file)749 void VersionControl::unlockFrameRange(QWidget *parent,
750 const QString &workingDir,
751 const QString &file) {
752 SVNUnlockFrameRangeDialog *dialog =
753 new SVNUnlockFrameRangeDialog(parent, workingDir, file);
754 connect(dialog, SIGNAL(done(const QStringList &)), this,
755 SIGNAL(commandDone(const QStringList &)));
756 dialog->show();
757 dialog->raise();
758 }
759
760 //-----------------------------------------------------------------------------
761
unlockFrameRange(QWidget * parent,const QString & workingDir,const QStringList & files)762 void VersionControl::unlockFrameRange(QWidget *parent,
763 const QString &workingDir,
764 const QStringList &files) {
765 SVNUnlockMultiFrameRangeDialog *dialog =
766 new SVNUnlockMultiFrameRangeDialog(parent, workingDir, files);
767 connect(dialog, SIGNAL(done(const QStringList &)), this,
768 SIGNAL(commandDone(const QStringList &)));
769 dialog->show();
770 dialog->raise();
771 }
772
773 //-----------------------------------------------------------------------------
774
showFrameRangeLockInfo(QWidget * parent,const QString & workingDir,const QString & file)775 void VersionControl::showFrameRangeLockInfo(QWidget *parent,
776 const QString &workingDir,
777 const QString &file) {
778 SVNFrameRangeLockInfoDialog *dialog =
779 new SVNFrameRangeLockInfoDialog(parent, workingDir, file);
780 dialog->show();
781 dialog->raise();
782 }
783
784 //-----------------------------------------------------------------------------
785
showFrameRangeLockInfo(QWidget * parent,const QString & workingDir,const QStringList & files)786 void VersionControl::showFrameRangeLockInfo(QWidget *parent,
787 const QString &workingDir,
788 const QStringList &files) {
789 SVNMultiFrameRangeLockInfoDialog *dialog =
790 new SVNMultiFrameRangeLockInfoDialog(parent, workingDir, files);
791 dialog->show();
792 dialog->raise();
793 }
794
795 //-----------------------------------------------------------------------------
796
commitFrameRange(QWidget * parent,const QString & workingDir,const QString & file)797 void VersionControl::commitFrameRange(QWidget *parent,
798 const QString &workingDir,
799 const QString &file) {
800 SVNCommitFrameRangeDialog *dialog =
801 new SVNCommitFrameRangeDialog(parent, workingDir, file);
802 connect(dialog, SIGNAL(done(const QStringList &)), this,
803 SIGNAL(commandDone(const QStringList &)));
804 dialog->show();
805 dialog->raise();
806 }
807
808 //-----------------------------------------------------------------------------
809
revertFrameRange(QWidget * parent,const QString & workingDir,const QString & file,const QString & tempFileName)810 void VersionControl::revertFrameRange(QWidget *parent,
811 const QString &workingDir,
812 const QString &file,
813 const QString &tempFileName) {
814 SVNRevertFrameRangeDialog *dialog =
815 new SVNRevertFrameRangeDialog(parent, workingDir, file, tempFileName);
816 connect(dialog, SIGNAL(done(const QStringList &)), this,
817 SIGNAL(commandDone(const QStringList &)));
818 dialog->show();
819 dialog->raise();
820 }
821
822 //-----------------------------------------------------------------------------
823
deleteFiles(QWidget * parent,const QString & workingDir,const QStringList & filesToDelete,int sceneIconAdded)824 void VersionControl::deleteFiles(QWidget *parent, const QString &workingDir,
825 const QStringList &filesToDelete,
826 int sceneIconAdded) {
827 SVNDeleteDialog *dialog = new SVNDeleteDialog(
828 parent, workingDir, filesToDelete, false, sceneIconAdded);
829 connect(dialog, SIGNAL(done(const QStringList &)), this,
830 SIGNAL(commandDone(const QStringList &)));
831 dialog->show();
832 dialog->raise();
833 }
834
835 //-----------------------------------------------------------------------------
836
deleteFolder(QWidget * parent,const QString & workingDir,const QString & folderName)837 void VersionControl::deleteFolder(QWidget *parent, const QString &workingDir,
838 const QString &folderName) {
839 SVNDeleteDialog *dialog =
840 new SVNDeleteDialog(parent, workingDir, QStringList(folderName), true, 0);
841 connect(dialog, SIGNAL(done(const QStringList &)), this,
842 SIGNAL(commandDone(const QStringList &)));
843 dialog->show();
844 dialog->raise();
845 }
846
847 //-----------------------------------------------------------------------------
848
cleanupFolder(QWidget * parent,const QString & workingDir)849 void VersionControl::cleanupFolder(QWidget *parent, const QString &workingDir) {
850 SVNCleanupDialog *dialog = new SVNCleanupDialog(parent, workingDir);
851 dialog->show();
852 dialog->raise();
853 }
854
855 //-----------------------------------------------------------------------------
856
purgeFolder(QWidget * parent,const QString & workingDir)857 void VersionControl::purgeFolder(QWidget *parent, const QString &workingDir) {
858 SVNPurgeDialog *dialog = new SVNPurgeDialog(parent, workingDir);
859 dialog->show();
860 dialog->raise();
861 }
862
863 //-----------------------------------------------------------------------------
864
getSceneContents(const QString & wokingDir,const QString & sceneFileName)865 QStringList VersionControl::getSceneContents(const QString &wokingDir,
866 const QString &sceneFileName) {
867 QStringList sceneContents;
868
869 TFilePath scenePath =
870 TFilePath(wokingDir.toStdWString()) + sceneFileName.toStdWString();
871 if (!TFileStatus(scenePath).doesExist()) return sceneContents;
872
873 ToonzScene scene;
874 try {
875 scene.load(scenePath);
876 } catch (...) {
877 }
878 std::vector<TXshLevel *> levels;
879 scene.getLevelSet()->listLevels(levels);
880 std::vector<TXshLevel *>::iterator it;
881 for (it = levels.begin(); it != levels.end(); ++it) {
882 TFilePath levelPath = scene.decodeFilePath((*it)->getPath());
883
884 if (levelPath.getDots() == "..") {
885 TFilePath dir = levelPath.getParentDir();
886 QDir qDir(QString::fromStdWString(dir.getWideString()));
887 QString levelName =
888 QRegExp::escape(QString::fromStdWString(levelPath.getWideName()));
889 QString levelType = QString::fromStdString(levelPath.getType());
890 QString exp(levelName + ".[0-9]{1,4}." + levelType);
891 QRegExp regExp(exp);
892 QStringList list = qDir.entryList(QDir::Files);
893 list = list.filter(regExp);
894 for (int i = 0; i < list.size(); i++) {
895 QString fileName = list.at(i);
896 sceneContents.append(toQString(dir + fileName.toStdWString()));
897 }
898 } else
899 sceneContents.append(toQString(levelPath));
900
901 TFilePathSet fpset;
902 TXshSimpleLevel::getFiles(levelPath, fpset);
903
904 TFilePathSet::iterator it;
905 for (it = fpset.begin(); it != fpset.end(); ++it)
906 sceneContents.append(toQString(scene.decodeFilePath((*it))));
907 }
908
909 return sceneContents;
910 }
911
912 //-----------------------------------------------------------------------------
913
getCurrentSceneContents() const914 QStringList VersionControl::getCurrentSceneContents() const {
915 QStringList contents;
916 ToonzScene *scene = TApp::instance()->getCurrentScene()->getScene();
917 if (!scene) return QStringList();
918
919 std::vector<TXshLevel *> levels;
920 scene->getLevelSet()->listLevels(levels);
921 std::vector<TXshLevel *>::iterator it;
922 for (it = levels.begin(); it != levels.end(); ++it) {
923 TFilePath levelPath = scene->decodeFilePath((*it)->getPath());
924 contents.append(toQString(levelPath));
925
926 TFilePathSet fpset;
927 TXshSimpleLevel::getFiles(levelPath, fpset);
928
929 TFilePathSet::iterator it;
930 for (it = fpset.begin(); it != fpset.end(); ++it)
931 contents.append(toQString(scene->decodeFilePath((*it))));
932 }
933 return contents;
934 }
935