1 
2 
3 #include "svnrevertdialog.h"
4 
5 // Tnz6 includes
6 #include "tapp.h"
7 
8 // TnzQt includes
9 #include "toonzqt/gutil.h"
10 
11 // TnzLib includes
12 #include "toonz/txshsimplelevel.h"
13 
14 // TnzCore includes
15 #include "tfilepath.h"
16 #include "tsystem.h"
17 
18 // Qt includes
19 #include <QPushButton>
20 #include <QTreeWidget>
21 #include <QHeaderView>
22 #include <QCheckBox>
23 #include <QMovie>
24 #include <QLabel>
25 #include <QDir>
26 #include <QRegExp>
27 #include <QMainWindow>
28 
29 //=============================================================================
30 // SVNRevertDialog
31 //-----------------------------------------------------------------------------
32 
SVNRevertDialog(QWidget * parent,const QString & workingDir,const QStringList & files,bool folderOnly,int sceneIconAdded)33 SVNRevertDialog::SVNRevertDialog(QWidget *parent, const QString &workingDir,
34                                  const QStringList &files, bool folderOnly,
35                                  int sceneIconAdded)
36     : Dialog(TApp::instance()->getMainWindow(), true, false)
37     , m_workingDir(workingDir)
38     , m_files(files)
39     , m_revertSceneContentsCheckBox(0)
40     , m_folderOnly(folderOnly)
41     , m_sceneIconAdded(sceneIconAdded) {
42   setModal(false);
43   setMinimumSize(300, 150);
44   setAttribute(Qt::WA_DeleteOnClose, true);
45   setWindowTitle(tr("Version Control: Revert changes"));
46 
47   QWidget *container = new QWidget;
48 
49   QVBoxLayout *mainLayout = new QVBoxLayout;
50   mainLayout->setAlignment(Qt::AlignHCenter);
51   mainLayout->setMargin(0);
52 
53   QHBoxLayout *hLayout = new QHBoxLayout;
54 
55   m_waitingLabel      = new QLabel;
56   QMovie *waitingMove = new QMovie(":Resources/waiting.gif");
57   waitingMove->setParent(this);
58 
59   m_waitingLabel->setMovie(waitingMove);
60   waitingMove->setCacheMode(QMovie::CacheAll);
61   waitingMove->start();
62 
63   m_textLabel = new QLabel(tr("Getting repository status..."));
64 
65   hLayout->addStretch();
66   hLayout->addWidget(m_waitingLabel);
67   hLayout->addWidget(m_textLabel);
68   hLayout->addStretch();
69 
70   mainLayout->addLayout(hLayout);
71 
72   m_treeWidget = new QTreeWidget;
73   m_treeWidget->setStyleSheet("QTreeWidget { border: 1px solid gray; }");
74   m_treeWidget->header()->hide();
75   m_treeWidget->hide();
76   mainLayout->addWidget(m_treeWidget);
77 
78   if (!m_folderOnly) {
79     mainLayout->addSpacing(10);
80     QHBoxLayout *checkBoxLayout = new QHBoxLayout;
81     checkBoxLayout->setMargin(0);
82     m_revertSceneContentsCheckBox = new QCheckBox(this);
83     connect(m_revertSceneContentsCheckBox, SIGNAL(toggled(bool)), this,
84             SLOT(onRevertSceneContentsToggled(bool)));
85     m_revertSceneContentsCheckBox->setChecked(false);
86     m_revertSceneContentsCheckBox->hide();
87     m_revertSceneContentsCheckBox->setText(tr("Revert Scene Contents"));
88     checkBoxLayout->addStretch();
89     checkBoxLayout->addWidget(m_revertSceneContentsCheckBox);
90     checkBoxLayout->addStretch();
91     mainLayout->addLayout(checkBoxLayout);
92   }
93 
94   container->setLayout(mainLayout);
95 
96   beginHLayout();
97   addWidget(container, false);
98   endHLayout();
99 
100   m_revertButton = new QPushButton(tr("Revert"));
101   m_revertButton->setEnabled(false);
102   connect(m_revertButton, SIGNAL(clicked()), this,
103           SLOT(onRevertButtonClicked()));
104 
105   m_cancelButton = new QPushButton(tr("Cancel"));
106   connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
107 
108   addButtonBarWidget(m_revertButton, m_cancelButton);
109 
110   // 0. Connect for svn errors (that may occurs everythings)
111   connect(&m_thread, SIGNAL(error(const QString &)), this,
112           SLOT(onError(const QString &)));
113 
114   // 1. Getting status
115   connect(&m_thread, SIGNAL(statusRetrieved(const QString &)), this,
116           SLOT(onStatusRetrieved(const QString &)));
117   m_thread.getSVNStatus(m_workingDir);
118 }
119 
120 //-----------------------------------------------------------------------------
121 
onStatusRetrieved(const QString & xmlResponse)122 void SVNRevertDialog::onStatusRetrieved(const QString &xmlResponse) {
123   SVNStatusReader sr(xmlResponse);
124   m_status   = sr.getStatus();
125   int height = 50;
126 
127   checkFiles();
128 
129   int fileSize = m_filesToRevert.size();
130   for (int i = 0; i < fileSize; i++) {
131     if (m_filesToRevert.at(i).endsWith(".tnz")) {
132       if (m_revertSceneContentsCheckBox) m_revertSceneContentsCheckBox->show();
133       break;
134     }
135   }
136 
137   initTreeWidget();
138 
139   if (m_filesToRevert.size() == 0) {
140     QString msg = QString(tr("No items to revert."));
141     m_textLabel->setText(msg);
142     switchToCloseButton();
143   } else {
144     if (m_treeWidget->isVisible()) height += (m_filesToRevert.size() * 50);
145 
146     setMinimumSize(300, std::min(height, 350));
147 
148     QString msg = QString(tr("%1 items to revert."))
149                       .arg(m_filesToRevert.size() == 1
150                                ? 1
151                                : m_filesToRevert.size() - m_sceneIconAdded);
152     m_textLabel->setText(msg);
153 
154     m_waitingLabel->hide();
155     m_revertButton->setEnabled(true);
156 
157     m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
158   }
159 }
160 
161 //-----------------------------------------------------------------------------
162 
checkFiles()163 void SVNRevertDialog::checkFiles() {
164   int statusCount = m_status.size();
165   for (int i = 0; i < statusCount; i++) {
166     SVNStatus s = m_status.at(i);
167     if (s.m_path == "." || s.m_path == "..") continue;
168     if (s.m_item != "normal" && s.m_item != "unversioned") {
169       if (m_folderOnly || m_files.contains(s.m_path))
170         m_filesToRevert.append(s.m_path);
171     }
172   }
173 }
174 
175 //-----------------------------------------------------------------------------
176 
initTreeWidget()177 void SVNRevertDialog::initTreeWidget() {
178   int filesSize = m_filesToRevert.size();
179 
180   bool itemAdded = false;
181 
182   for (int i = 0; i < filesSize; i++) {
183     QString fileName = m_filesToRevert.at(i);
184     TFilePath fp =
185         TFilePath(m_workingDir.toStdWString()) + fileName.toStdWString();
186     TFilePathSet fpset;
187     TXshSimpleLevel::getFiles(fp, fpset);
188 
189     QStringList linkedFiles;
190 
191     TFilePathSet::iterator it;
192     for (it = fpset.begin(); it != fpset.end(); ++it) {
193       QString fn = toQString((*it).withoutParentDir());
194 
195       if (m_filesToRevert.contains(fn)) linkedFiles.append(fn);
196     }
197 
198     if (!linkedFiles.isEmpty()) {
199       itemAdded            = true;
200       QTreeWidgetItem *twi = new QTreeWidgetItem(m_treeWidget);
201       twi->setText(0, fileName);
202       twi->setFirstColumnSpanned(false);
203       twi->setFlags(Qt::NoItemFlags);
204 
205       for (int i = 0; i < linkedFiles.size(); i++) {
206         QTreeWidgetItem *child = new QTreeWidgetItem(twi);
207         child->setText(0, linkedFiles.at(i));
208         child->setFlags(Qt::NoItemFlags);
209       }
210       twi->setExpanded(true);
211     }
212   }
213 
214   if (itemAdded) m_treeWidget->show();
215 }
216 
217 //-----------------------------------------------------------------------------
218 
switchToCloseButton()219 void SVNRevertDialog::switchToCloseButton() {
220   m_waitingLabel->hide();
221   m_treeWidget->hide();
222   m_revertButton->disconnect();
223   m_revertButton->setText("Close");
224   m_revertButton->setEnabled(true);
225   m_cancelButton->hide();
226   connect(m_revertButton, SIGNAL(clicked()), this, SLOT(close()));
227 }
228 
229 //-----------------------------------------------------------------------------
230 
onRevertButtonClicked()231 void SVNRevertDialog::onRevertButtonClicked() {
232   m_revertButton->setEnabled(false);
233   revertFiles();
234 }
235 
236 //-----------------------------------------------------------------------------
237 
revertFiles()238 void SVNRevertDialog::revertFiles() {
239   m_treeWidget->hide();
240   if (m_revertSceneContentsCheckBox) m_revertSceneContentsCheckBox->hide();
241   m_waitingLabel->show();
242 
243   int fileToRevertSize          = m_filesToRevert.size();
244   int sceneResourceToRevertSize = m_sceneResources.size();
245   int totalFilesToRevert        = fileToRevertSize + sceneResourceToRevertSize;
246   if (totalFilesToRevert > 0) {
247     m_textLabel->setText(tr("Reverting %1 items...")
248                              .arg(totalFilesToRevert == 1
249                                       ? 1
250                                       : totalFilesToRevert - m_sceneIconAdded));
251 
252     QStringList args;
253     args << "revert";
254 
255     for (int i = 0; i < fileToRevertSize; i++) args << m_filesToRevert.at(i);
256 
257     for (int i = 0; i < sceneResourceToRevertSize; i++)
258       args << m_sceneResources.at(i);
259 
260     connect(&m_thread, SIGNAL(done(const QString &)), SLOT(onRevertDone()));
261     m_thread.executeCommand(m_workingDir, "svn", args);
262   } else
263     onRevertDone();
264 }
265 
266 //-----------------------------------------------------------------------------
267 
onRevertDone()268 void SVNRevertDialog::onRevertDone() {
269   m_textLabel->setText(tr("Revert done successfully."));
270 
271   QStringList files;
272   for (int i = 0; i < m_filesToRevert.size(); i++)
273     files.append(m_filesToRevert.at(i));
274   emit done(files);
275 
276   switchToCloseButton();
277 }
278 
279 //-----------------------------------------------------------------------------
280 
onError(const QString & errorString)281 void SVNRevertDialog::onError(const QString &errorString) {
282   m_textLabel->setText(errorString);
283   switchToCloseButton();
284   update();
285 }
286 
287 //-----------------------------------------------------------------------------
288 
onRevertSceneContentsToggled(bool checked)289 void SVNRevertDialog::onRevertSceneContentsToggled(bool checked) {
290   if (!checked)
291     m_sceneResources.clear();
292   else {
293     VersionControl *vc = VersionControl::instance();
294 
295     int fileSize = m_filesToRevert.count();
296     for (int i = 0; i < fileSize; i++) {
297       QString fileName = m_filesToRevert.at(i);
298       if (fileName.endsWith(".tnz")) {
299         if (m_filesToRevert.contains(fileName))
300           m_sceneResources.append(vc->getSceneContents(m_workingDir, fileName));
301       }
302     }
303   }
304   m_textLabel->setText(
305       tr("%1 items to revert.")
306           .arg(m_filesToRevert.size() + m_sceneResources.size() == 1
307                    ? 1
308                    : m_filesToRevert.size() + m_sceneResources.size() -
309                          m_sceneIconAdded));
310 }
311 
312 //=============================================================================
313 // SVNRevertFrameRangeDialog
314 //-----------------------------------------------------------------------------
315 
SVNRevertFrameRangeDialog(QWidget * parent,const QString & workingDir,const QString & file,const QString & tempFileName)316 SVNRevertFrameRangeDialog::SVNRevertFrameRangeDialog(
317     QWidget *parent, const QString &workingDir, const QString &file,
318     const QString &tempFileName)
319     : Dialog(TApp::instance()->getMainWindow(), true, false)
320     , m_workingDir(workingDir)
321     , m_file(file)
322     , m_tempFileName(tempFileName) {
323   setModal(false);
324   setMinimumSize(300, 150);
325   setAttribute(Qt::WA_DeleteOnClose, true);
326   setWindowTitle(tr("Version Control: Revert Frame Range changes"));
327 
328   beginVLayout();
329 
330   m_waitingLabel      = new QLabel;
331   QMovie *waitingMove = new QMovie(":Resources/waiting.gif");
332   waitingMove->setParent(this);
333 
334   m_waitingLabel->setMovie(waitingMove);
335   waitingMove->setCacheMode(QMovie::CacheAll);
336   waitingMove->start();
337   m_waitingLabel->hide();
338 
339   m_textLabel = new QLabel(tr("1 item to revert."));
340 
341   addWidgets(m_waitingLabel, m_textLabel);
342 
343   endVLayout();
344 
345   m_revertButton = new QPushButton(tr("Revert"));
346   connect(m_revertButton, SIGNAL(clicked()), this,
347           SLOT(onRevertButtonClicked()));
348 
349   m_cancelButton = new QPushButton(tr("Cancel"));
350   connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
351 
352   addButtonBarWidget(m_revertButton, m_cancelButton);
353 }
354 
355 //-----------------------------------------------------------------------------
356 
switchToCloseButton()357 void SVNRevertFrameRangeDialog::switchToCloseButton() {
358   m_waitingLabel->hide();
359   m_revertButton->disconnect();
360   m_revertButton->setText("Close");
361   m_revertButton->setEnabled(true);
362   m_cancelButton->hide();
363   connect(m_revertButton, SIGNAL(clicked()), this, SLOT(close()));
364 }
365 
366 //-----------------------------------------------------------------------------
367 
onRevertButtonClicked()368 void SVNRevertFrameRangeDialog::onRevertButtonClicked() {
369   m_revertButton->setEnabled(false);
370   revertFiles();
371 }
372 
373 //-----------------------------------------------------------------------------
374 
revertFiles()375 void SVNRevertFrameRangeDialog::revertFiles() {
376   m_waitingLabel->show();
377   m_textLabel->setText(tr("Reverting 1 item..."));
378 
379   try {
380     TFilePath pathToRemove = TFilePath(m_tempFileName.toStdWString());
381     if (TSystem::doesExistFileOrLevel(pathToRemove))
382       TSystem::removeFileOrLevel(TFilePath(m_tempFileName.toStdWString()));
383     if (pathToRemove.getType() == "tlv") {
384       pathToRemove = pathToRemove.withType("tpl");
385       if (TSystem::doesExistFileOrLevel(pathToRemove))
386         TSystem::removeFileOrLevel(pathToRemove);
387     }
388 
389     TFilePath hookFilePath =
390         pathToRemove.withName(pathToRemove.getName() + "_hooks")
391             .withType("xml");
392     if (TSystem::doesExistFileOrLevel(hookFilePath))
393       TSystem::removeFileOrLevel(hookFilePath);
394   } catch (...) {
395     m_textLabel->setText(tr("It is not possible to revert the file."));
396     switchToCloseButton();
397     return;
398   }
399 
400   TFilePath path =
401       TFilePath(m_workingDir.toStdWString()) + m_file.toStdWString();
402 
403   if (path.getDots() == "..") {
404     TFilePath dir = path.getParentDir();
405     QDir qDir(QString::fromStdWString(dir.getWideString()));
406     QString levelName =
407         QRegExp::escape(QString::fromStdWString(path.getWideName()));
408     QString levelType = QString::fromStdString(path.getType());
409     QString exp(levelName + ".[0-9]{1,4}." + levelType);
410     QRegExp regExp(exp);
411     QStringList list = qDir.entryList(QDir::Files);
412     m_files          = list.filter(regExp);
413 
414     // 0. Connect for svn errors (that may occurs everythings)
415     connect(&m_thread, SIGNAL(error(const QString &)), this,
416             SLOT(onError(const QString &)));
417 
418     // 1. Getting status
419     connect(&m_thread, SIGNAL(statusRetrieved(const QString &)), this,
420             SLOT(onStatusRetrieved(const QString &)));
421     m_thread.getSVNStatus(m_workingDir, m_files);
422   } else {
423     m_textLabel->setText(tr("Revert done successfully."));
424 
425     QStringList files;
426     files.append(m_file);
427     emit done(files);
428 
429     switchToCloseButton();
430   }
431 }
432 
433 //-----------------------------------------------------------------------------
434 
onStatusRetrieved(const QString & xmlResponse)435 void SVNRevertFrameRangeDialog::onStatusRetrieved(const QString &xmlResponse) {
436   SVNStatusReader sr(xmlResponse);
437   m_status = sr.getStatus();
438 
439   checkFiles();
440 
441   int fileToRevertCount = m_filesToRevert.size();
442 
443   if (fileToRevertCount == 0) {
444     m_textLabel->setText(tr("Revert done successfully."));
445     switchToCloseButton();
446   } else {
447     m_thread.disconnect(SIGNAL(statusRetrieved(const QString &)));
448     m_textLabel->setText(
449         tr("Reverting %1 items...").arg(QString::number(fileToRevertCount)));
450 
451     QStringList args;
452     args << "revert";
453     for (int i = 0; i < fileToRevertCount; i++) args << m_filesToRevert.at(i);
454 
455     connect(&m_thread, SIGNAL(done(const QString &)), SLOT(onRevertDone()));
456     m_thread.executeCommand(m_workingDir, "svn", args);
457   }
458 }
459 
460 //-----------------------------------------------------------------------------
461 
onError(const QString & errorString)462 void SVNRevertFrameRangeDialog::onError(const QString &errorString) {
463   m_textLabel->setText(errorString);
464   switchToCloseButton();
465   update();
466 }
467 
468 //-----------------------------------------------------------------------------
469 
checkFiles()470 void SVNRevertFrameRangeDialog::checkFiles() {
471   int statusCount = m_status.size();
472   for (int i = 0; i < statusCount; i++) {
473     SVNStatus s = m_status.at(i);
474     if (s.m_item != "normal" && s.m_item != "unversioned") {
475       if (m_files.contains(s.m_path)) m_filesToRevert.append(s.m_path);
476     }
477   }
478 }
479 
480 //-----------------------------------------------------------------------------
481 
onRevertDone()482 void SVNRevertFrameRangeDialog::onRevertDone() {
483   m_textLabel->setText(tr("Revert done successfully."));
484 
485   QStringList files;
486   for (int i = 0; i < m_filesToRevert.size(); i++)
487     files.append(m_filesToRevert.at(i));
488   emit done(files);
489 
490   switchToCloseButton();
491 }
492