1 
2 
3 #include "svndeletedialog.h"
4 
5 // Tnz6 includes
6 #include "tapp.h"
7 #include "tsystem.h"
8 #include "tfilepath.h"
9 #include "filebrowser.h"
10 #include "fileselection.h"
11 
12 // TnzQt includes
13 #include "toonzqt/tselectionhandle.h"
14 #include "toonzqt/gutil.h"
15 
16 // TnzLib includes
17 #include "toonz/txshsimplelevel.h"
18 
19 // Qt includes
20 #include <QWidget>
21 #include <QLabel>
22 #include <QMovie>
23 #include <QCheckBox>
24 #include <QPlainTextEdit>
25 #include <QPushButton>
26 #include <QBoxLayout>
27 #include <QFormLayout>
28 #include <QTreeWidget>
29 #include <QHeaderView>
30 #include <QTextStream>
31 #include <QDir>
32 #include <QMainWindow>
33 
34 //=============================================================================
35 // SVNDeleteDialog
36 //-----------------------------------------------------------------------------
37 
SVNDeleteDialog(QWidget * parent,const QString & workingDir,const QStringList & files,bool isFolder,int sceneIconAdded)38 SVNDeleteDialog::SVNDeleteDialog(QWidget *parent, const QString &workingDir,
39                                  const QStringList &files, bool isFolder,
40                                  int sceneIconAdded)
41     : Dialog(TApp::instance()->getMainWindow(), true, false)
42     , m_deleteSceneContentsCheckBox(0)
43     , m_workingDir(workingDir)
44     , m_files(files)
45     , m_targetTempFile(0)
46     , m_isFolder(isFolder)
47     , m_sceneIconAdded(sceneIconAdded) {
48   setModal(false);
49   setAttribute(Qt::WA_DeleteOnClose, true);
50 
51   setWindowTitle(tr("Version Control: Delete"));
52 
53   setMinimumSize(300, 180);
54 
55   QWidget *container = new QWidget;
56 
57   QVBoxLayout *mainLayout = new QVBoxLayout;
58   mainLayout->setAlignment(Qt::AlignHCenter);
59   mainLayout->setMargin(0);
60 
61   QHBoxLayout *hLayout = new QHBoxLayout;
62 
63   m_waitingLabel      = new QLabel;
64   QMovie *waitingMove = new QMovie(":Resources/waiting.gif");
65   waitingMove->setParent(this);
66   m_waitingLabel->hide();
67 
68   m_waitingLabel->setMovie(waitingMove);
69   waitingMove->setCacheMode(QMovie::CacheAll);
70   waitingMove->start();
71 
72   m_textLabel = new QLabel;
73 
74   if (m_isFolder) {
75     QDir dir(m_workingDir + "/" + m_files.at(0));
76     int filesCount = dir.entryList(QDir::Files | QDir::Dirs).count();
77     if (filesCount > 0)
78       m_textLabel->setText(tr("Delete folder that contains %1 items.")
79                                .arg(filesCount - m_sceneIconAdded));
80     else
81       m_textLabel->setText(tr("Delete empty folder."));
82   } else
83     m_textLabel->setText(
84         tr("Delete %1 items.").arg(m_files.size() - m_sceneIconAdded));
85 
86   hLayout->addStretch();
87   hLayout->addWidget(m_waitingLabel);
88   hLayout->addWidget(m_textLabel);
89   hLayout->addStretch();
90 
91   mainLayout->addLayout(hLayout);
92 
93   m_treeWidget = new QTreeWidget;
94   m_treeWidget->setStyleSheet("QTreeWidget { border: 1px solid gray; }");
95   m_treeWidget->header()->hide();
96   m_treeWidget->hide();
97   mainLayout->addWidget(m_treeWidget);
98 
99   QFormLayout *formLayout = new QFormLayout;
100   formLayout->setLabelAlignment(Qt::AlignRight);
101   formLayout->setFormAlignment(Qt::AlignHCenter | Qt::AlignTop);
102   formLayout->setSpacing(10);
103   formLayout->setMargin(0);
104 
105   m_commentTextEdit = new QPlainTextEdit;
106   m_commentTextEdit->setMaximumHeight(50);
107 
108   m_commentLabel = new QLabel(tr("Comment:"));
109   m_commentLabel->setFixedWidth(55);
110 
111   m_commentTextEdit->hide();
112   m_commentLabel->hide();
113 
114   formLayout->addRow(m_commentLabel, m_commentTextEdit);
115 
116   if (!m_isFolder) {
117     m_deleteSceneContentsCheckBox = new QCheckBox(this);
118     connect(m_deleteSceneContentsCheckBox, SIGNAL(toggled(bool)), this,
119             SLOT(onDeleteSceneContentsToggled(bool)));
120     m_deleteSceneContentsCheckBox->setChecked(false);
121     m_deleteSceneContentsCheckBox->hide();
122     m_deleteSceneContentsCheckBox->setText(tr("Delete Scene Contents"));
123 
124     formLayout->addRow("", m_deleteSceneContentsCheckBox);
125 
126     int fileSize = m_files.size();
127     for (int i = 0; i < fileSize; i++) {
128       if (m_files.at(i).endsWith(".tnz")) {
129         m_deleteSceneContentsCheckBox->show();
130         break;
131       }
132     }
133   }
134 
135   m_keepLocalCopyCheckBox = new QCheckBox(tr(" Keep Local Copy"));
136   m_keepLocalCopyCheckBox->setChecked(true);
137   m_keepLocalCopyCheckBox->hide();
138 
139   formLayout->addRow("", m_keepLocalCopyCheckBox);
140 
141   mainLayout->addLayout(formLayout);
142 
143   container->setLayout(mainLayout);
144 
145   beginHLayout();
146   addWidget(container, false);
147   endHLayout();
148 
149   m_deleteLocalButton = new QPushButton();
150   m_deleteLocalButton->setText(tr("Delete Local Copy "));
151   connect(m_deleteLocalButton, SIGNAL(clicked()), this,
152           SLOT(onDeleteLocalButtonClicked()));
153 
154   m_deleteServerButton = new QPushButton();
155   m_deleteServerButton->setText(tr("Delete on Server "));
156   connect(m_deleteServerButton, SIGNAL(clicked()), this,
157           SLOT(onDeleteServerButtonClicked()));
158 
159   m_cancelButton = new QPushButton(tr("Cancel"));
160   connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
161 
162   addButtonBarWidget(m_deleteLocalButton, m_deleteServerButton, m_cancelButton);
163 
164   // 0. Connect for svn errors (that may occurs)
165   connect(&m_thread, SIGNAL(error(const QString &)), this,
166           SLOT(onError(const QString &)));
167 }
168 
169 //-----------------------------------------------------------------------------
170 
showEvent(QShowEvent * e)171 void SVNDeleteDialog::showEvent(QShowEvent *e) {
172   if (!m_isFolder) {
173     initTreeWidget();
174 
175     int height = 50;
176     if (m_treeWidget->isVisible()) height += (m_files.size() * 50);
177 
178     setMinimumSize(300, std::min(height, 350));
179   }
180   QDialog::showEvent(e);
181 }
182 
183 //-----------------------------------------------------------------------------
184 
onError(const QString & errorString)185 void SVNDeleteDialog::onError(const QString &errorString) {
186   if (m_targetTempFile) {
187     QFile::remove(m_targetTempFile->fileName());
188     delete m_targetTempFile;
189     m_targetTempFile = 0;
190   }
191 
192   m_textLabel->setText(errorString);
193   switchToCloseButton();
194   update();
195 }
196 
197 //-----------------------------------------------------------------------------
198 
switchToCloseButton()199 void SVNDeleteDialog::switchToCloseButton() {
200   if (m_deleteSceneContentsCheckBox) m_deleteSceneContentsCheckBox->hide();
201   m_commentTextEdit->hide();
202   m_commentLabel->hide();
203   m_waitingLabel->hide();
204   m_treeWidget->hide();
205   m_keepLocalCopyCheckBox->hide();
206   m_deleteLocalButton->disconnect();
207   m_deleteLocalButton->setText("Close");
208   m_deleteLocalButton->show();
209   m_cancelButton->hide();
210   m_deleteServerButton->hide();
211   connect(m_deleteLocalButton, SIGNAL(clicked()), this, SLOT(close()));
212 }
213 
214 //-----------------------------------------------------------------------------
215 
onDeleteLocalButtonClicked()216 void SVNDeleteDialog::onDeleteLocalButtonClicked() {
217   // Delete files locally
218   int fileCount = m_files.size();
219   m_waitingLabel->show();
220   m_textLabel->setText(
221       tr("Deleting %1 items...")
222           .arg(fileCount + m_sceneResources.size() - m_sceneIconAdded));
223   m_textLabel->show();
224 
225   for (int i = 0; i < fileCount; i++) {
226     TFilePath fp((m_workingDir + "/" + m_files.at(i)).toStdWString());
227     TSystem::moveFileOrLevelToRecycleBin(fp);
228   }
229 
230   int sceneResourcesCount = m_sceneResources.size();
231   for (int i = 0; i < sceneResourcesCount; i++) {
232     TFilePath fp(m_sceneResources.at(i).toStdWString());
233     TSystem::moveFileOrLevelToRecycleBin(fp);
234   }
235 
236   updateFileBrowser();
237 
238   emit done(m_files);
239 
240   m_waitingLabel->hide();
241   m_textLabel->hide();
242 
243   close();
244 }
245 
246 //-----------------------------------------------------------------------------
247 
updateFileBrowser()248 void SVNDeleteDialog::updateFileBrowser() {
249   // Reset the selection
250   TSelection *selection =
251       TApp::instance()->getCurrentSelection()->getSelection();
252   FileSelection *fileSelection = dynamic_cast<FileSelection *>(selection);
253   if (fileSelection) fileSelection->selectNone();
254 
255   TFilePath fp((m_workingDir + "/" + m_files.at(0)).toStdWString());
256 
257   // Refresh FileBrowser
258   FileBrowser::refreshFolder(fp.getParentDir());
259 }
260 
261 //-----------------------------------------------------------------------------
262 
onDeleteServerButtonClicked()263 void SVNDeleteDialog::onDeleteServerButtonClicked() {
264   m_deleteLocalButton->hide();
265 
266   disconnect(m_deleteServerButton, SIGNAL(clicked()), this,
267              SLOT(onDeleteServerButtonClicked()));
268   m_deleteServerButton->setText(tr("Delete"));
269   connect(m_deleteServerButton, SIGNAL(clicked()), this, SLOT(deleteFiles()));
270 
271   int height = 175;
272   if (m_treeWidget->isVisible()) height += (m_files.size() * 50);
273   setMinimumSize(300, std::min(height, 350));
274 
275   m_textLabel->setText(
276       tr("You are deleting items also on repository. Are you sure ?"));
277   m_commentLabel->show();
278   m_commentTextEdit->show();
279   m_keepLocalCopyCheckBox->show();
280 }
281 
282 //-----------------------------------------------------------------------------
283 
deleteFiles()284 void SVNDeleteDialog::deleteFiles() {
285   m_waitingLabel->show();
286   m_textLabel->setText(
287       tr("Deleting %1 items...")
288           .arg(QString::number(m_files.size() + m_sceneResources.size() -
289                                m_sceneIconAdded)));
290   m_commentLabel->hide();
291   m_commentTextEdit->hide();
292   m_treeWidget->hide();
293   m_keepLocalCopyCheckBox->hide();
294   if (m_deleteSceneContentsCheckBox) m_deleteSceneContentsCheckBox->hide();
295   m_deleteServerButton->hide();
296   m_cancelButton->hide();
297 
298   QStringList args;
299   args << "delete";
300 
301   if (m_keepLocalCopyCheckBox->isChecked()) args << "--keep-local";
302 
303   // Use a temporary file to store all the files list
304   m_targetTempFile = new QFile(m_workingDir + "/" + "tempDeleteFile");
305   if (m_targetTempFile->open(QFile::WriteOnly | QFile::Truncate)) {
306     QTextStream out(m_targetTempFile);
307 
308     int filesCount = m_files.count();
309     for (int i = 0; i < filesCount; i++) out << m_files.at(i) + "\n";
310 
311     int sceneResourcesCount = m_sceneResources.size();
312     for (int i = 0; i < sceneResourcesCount; i++)
313       out << m_sceneResources.at(i) + "\n";
314   }
315   m_targetTempFile->close();
316 
317   args << "--targets";
318   args << "tempDeleteFile";
319 
320   m_thread.disconnect(SIGNAL(done(const QString &)));
321   connect(&m_thread, SIGNAL(done(const QString &)), SLOT(commitDeletedFiles()));
322   m_thread.executeCommand(m_workingDir, "svn", args, false);
323 }
324 
325 //-----------------------------------------------------------------------------
326 
commitDeletedFiles()327 void SVNDeleteDialog::commitDeletedFiles() {
328   updateFileBrowser();
329   QStringList args;
330   args << "commit";
331   args << "--targets";
332   args << "tempDeleteFile";
333 
334   if (!m_commentTextEdit->toPlainText().isEmpty())
335     args << QString("-m").append(m_commentTextEdit->toPlainText());
336   else
337     args << QString("-m").append(VersionControl::instance()->getUserName() +
338                                  " delete files.");
339   m_thread.disconnect(SIGNAL(done(const QString &)));
340   connect(&m_thread, SIGNAL(done(const QString &)), SLOT(onCommitDone()));
341   m_thread.executeCommand(m_workingDir, "svn", args);
342 }
343 
344 //-----------------------------------------------------------------------------
345 
onCommitDone()346 void SVNDeleteDialog::onCommitDone() {
347   if (m_targetTempFile) {
348     QFile::remove(m_targetTempFile->fileName());
349     delete m_targetTempFile;
350     m_targetTempFile = 0;
351   }
352 
353   emit done(m_files);
354   close();
355 }
356 
357 //-----------------------------------------------------------------------------
358 
initTreeWidget()359 void SVNDeleteDialog::initTreeWidget() {
360   int filesSize  = m_files.size();
361   bool itemAdded = false;
362 
363   for (int i = 0; i < filesSize; i++) {
364     QString fileName = m_files.at(i);
365     TFilePath fp =
366         TFilePath(m_workingDir.toStdWString()) + fileName.toStdWString();
367     TFilePathSet fpset;
368     TXshSimpleLevel::getFiles(fp, fpset);
369 
370     QStringList linkedFiles;
371 
372     TFilePathSet::iterator it;
373     for (it = fpset.begin(); it != fpset.end(); ++it) {
374       QString fn = toQString((*it).withoutParentDir());
375 
376       if (m_files.contains(fn)) linkedFiles.append(fn);
377     }
378 
379     if (!linkedFiles.isEmpty()) {
380       itemAdded            = true;
381       QTreeWidgetItem *twi = new QTreeWidgetItem(m_treeWidget);
382       twi->setText(0, fileName);
383       twi->setFirstColumnSpanned(false);
384       twi->setFlags(Qt::NoItemFlags);
385 
386       for (int i = 0; i < linkedFiles.size(); i++) {
387         QTreeWidgetItem *child = new QTreeWidgetItem(twi);
388         child->setText(0, linkedFiles.at(i));
389         child->setFlags(Qt::NoItemFlags);
390       }
391       twi->setExpanded(true);
392     }
393   }
394 
395   if (itemAdded) m_treeWidget->show();
396 }
397 
398 //-----------------------------------------------------------------------------
399 
onDeleteSceneContentsToggled(bool checked)400 void SVNDeleteDialog::onDeleteSceneContentsToggled(bool checked) {
401   if (!checked)
402     m_sceneResources.clear();
403   else {
404     VersionControl *vc = VersionControl::instance();
405 
406     int fileSize = m_files.count();
407     for (int i = 0; i < fileSize; i++) {
408       QString fileName = m_files.at(i);
409       if (fileName.endsWith(".tnz")) {
410         if (m_files.contains(fileName))
411           m_sceneResources.append(vc->getSceneContents(m_workingDir, fileName));
412       }
413     }
414   }
415   m_textLabel->setText(
416       tr("Delete %1 items.")
417           .arg(m_files.size() - m_sceneIconAdded + m_sceneResources.size()));
418 }
419