1
2
3 #include "svnupdatedialog.h"
4
5 // Tnz6 includes
6 #include "tapp.h"
7 #include "versioncontrolwidget.h"
8
9 // TnzQt includes
10 #include "toonzqt/gutil.h"
11
12 // TnzLib includes
13 #include "toonz/txshsimplelevel.h"
14 #include "toonz/toonzscene.h"
15
16 // Qt includes
17 #include <QWidget>
18 #include <QPushButton>
19 #include <QScrollBar>
20 #include <QBoxLayout>
21 #include <QLabel>
22 #include <QMovie>
23 #include <QTextEdit>
24 #include <QCheckBox>
25 #include <QRegExp>
26 #include <QDir>
27 #include <QMainWindow>
28
29 //=============================================================================
30 // SVNUpdateDialog
31 //-----------------------------------------------------------------------------
32
SVNUpdateDialog(QWidget * parent,const QString & workingDir,const QStringList & files,int sceneIconsCount,bool isFolderOnly,bool updateToRevision,bool nonRecursive)33 SVNUpdateDialog::SVNUpdateDialog(QWidget *parent, const QString &workingDir,
34 const QStringList &files, int sceneIconsCount,
35 bool isFolderOnly, bool updateToRevision,
36 bool nonRecursive)
37 : Dialog(TApp::instance()->getMainWindow(), true, false)
38 , m_updateSceneContentsCheckBox(0)
39 , m_workingDir(workingDir)
40 , m_files(files)
41 , m_updateToRevision(updateToRevision)
42 , m_nonRecursive(nonRecursive)
43 , m_sceneIconsCount(sceneIconsCount)
44 , m_someSceneIsMissing(false) {
45 setModal(false);
46 setMinimumSize(300, 180);
47 setAttribute(Qt::WA_DeleteOnClose, true);
48 setWindowTitle(tr("Version Control: Update"));
49
50 QWidget *container = new QWidget;
51
52 QVBoxLayout *mainLayout = new QVBoxLayout;
53 mainLayout->setAlignment(Qt::AlignHCenter);
54 mainLayout->setMargin(0);
55
56 QHBoxLayout *hLayout = new QHBoxLayout;
57
58 m_waitingLabel = new QLabel;
59 QMovie *waitingMove = new QMovie(":Resources/waiting.gif");
60 waitingMove->setParent(this);
61
62 m_waitingLabel->setMovie(waitingMove);
63 waitingMove->setCacheMode(QMovie::CacheAll);
64 waitingMove->start();
65
66 m_textLabel = new QLabel(tr("Getting repository status..."));
67
68 hLayout->addStretch();
69 hLayout->addWidget(m_waitingLabel);
70 hLayout->addWidget(m_textLabel);
71 hLayout->addStretch();
72
73 mainLayout->addLayout(hLayout);
74
75 m_output = new QTextEdit;
76 m_output->setTextInteractionFlags(Qt::NoTextInteraction);
77 m_output->setReadOnly(true);
78 m_output->hide();
79
80 mainLayout->addWidget(m_output);
81
82 m_conflictWidget = new ConflictWidget;
83 m_conflictWidget->hide();
84
85 mainLayout->addWidget(m_conflictWidget);
86
87 m_dateChooserWidget = new DateChooserWidget;
88 m_dateChooserWidget->hide();
89
90 mainLayout->addWidget(m_dateChooserWidget);
91
92 if (!isFolderOnly) {
93 QHBoxLayout *checkBoxLayout = new QHBoxLayout;
94 checkBoxLayout->setMargin(0);
95 m_updateSceneContentsCheckBox = new QCheckBox(this);
96 m_updateSceneContentsCheckBox->setChecked(false);
97 m_updateSceneContentsCheckBox->setText(tr("Get Scene Contents"));
98 m_updateSceneContentsCheckBox->hide();
99 connect(m_updateSceneContentsCheckBox, SIGNAL(toggled(bool)), this,
100 SLOT(onUpdateSceneContentsToggled(bool)));
101
102 checkBoxLayout->addStretch();
103 checkBoxLayout->addWidget(m_updateSceneContentsCheckBox);
104 checkBoxLayout->addStretch();
105
106 mainLayout->addSpacing(10);
107 mainLayout->addLayout(checkBoxLayout);
108 }
109
110 container->setLayout(mainLayout);
111
112 beginHLayout();
113 addWidget(container, false);
114 endHLayout();
115
116 m_updateButton = new QPushButton(tr("Update"));
117 m_updateButton->hide();
118 if (m_updateToRevision)
119 connect(m_updateButton, SIGNAL(clicked()), this,
120 SLOT(onUpdateToRevisionButtonClicked()));
121 else
122 connect(m_updateButton, SIGNAL(clicked()), this,
123 SLOT(onUpdateButtonClicked()));
124
125 m_closeButton = new QPushButton(tr("Close"));
126 m_closeButton->setEnabled(false);
127 connect(m_closeButton, SIGNAL(clicked()), this, SLOT(close()));
128
129 m_cancelButton = new QPushButton(tr("Cancel"));
130 connect(m_cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
131
132 addButtonBarWidget(m_updateButton, m_closeButton, m_cancelButton);
133
134 // 0. Connect for svn errors (that may occurs everythings)
135 connect(&m_thread, SIGNAL(error(const QString &)), this,
136 SLOT(onError(const QString &)));
137
138 // 1. Getting status
139 connect(&m_thread, SIGNAL(statusRetrieved(const QString &)), this,
140 SLOT(onStatusRetrieved(const QString &)));
141 m_thread.getSVNStatus(m_workingDir, m_files, true, false, true);
142 }
143
144 //-----------------------------------------------------------------------------
145
onStatusRetrieved(const QString & xmlResponse)146 void SVNUpdateDialog::onStatusRetrieved(const QString &xmlResponse) {
147 m_waitingLabel->hide();
148
149 SVNStatusReader sr(xmlResponse);
150 m_status = sr.getStatus();
151
152 checkFiles();
153
154 // Check if a scene files is found
155 int fileSize = m_filesToUpdate.size();
156 for (int i = 0; i < fileSize; i++) {
157 if (m_filesToUpdate.at(i).endsWith(".tnz")) {
158 if (fileSize == 1)
159 m_textLabel->setText(
160 tr("%1 items to update.")
161 .arg(m_filesToUpdate.size() + m_sceneResources.size()));
162 else
163 m_textLabel->setText(tr("%1 items to update.")
164 .arg(m_filesToUpdate.size() +
165 m_sceneResources.size() -
166 m_sceneIconsCount));
167 if (m_updateSceneContentsCheckBox && !m_someSceneIsMissing)
168 m_updateSceneContentsCheckBox->show();
169 m_updateButton->show();
170 m_closeButton->hide();
171 return;
172 }
173 }
174
175 if (m_updateToRevision) {
176 if (m_filesWithConflict.count() > 0) {
177 m_textLabel->setText(
178 tr("Some items are currently modified in your working copy.\nPlease "
179 "commit or revert changes first."));
180 m_textLabel->show();
181 switchToCloseButton();
182 return;
183 }
184
185 m_textLabel->setText(tr("Update to:"));
186 m_textLabel->show();
187 m_dateChooserWidget->show();
188 m_updateButton->show();
189 m_closeButton->hide();
190
191 adjustSize();
192 } else {
193 // Resolve first files with conflict
194 if (m_filesWithConflict.count() > 0) {
195 m_textLabel->setText(tr("Some conflict found. Select.."));
196 m_textLabel->show();
197 m_updateButton->setEnabled(false);
198 m_updateButton->show();
199 m_closeButton->hide();
200
201 QStringList fileswithConflict;
202 int fileswithConflictCount = m_filesWithConflict.size();
203 for (int i = 0; i < fileswithConflictCount; i++)
204 fileswithConflict.append(m_filesWithConflict.at(i));
205 m_conflictWidget->setFiles(fileswithConflict);
206 m_conflictWidget->show();
207 adjustSize();
208 connect(m_conflictWidget, SIGNAL(allConflictSetted()), this,
209 SLOT(onConflictSetted()));
210 } else
211 updateFiles();
212 }
213 }
214
215 //-----------------------------------------------------------------------------
216
checkFiles()217 void SVNUpdateDialog::checkFiles() {
218 int statusCount = m_status.size();
219 for (int i = 0; i < statusCount; i++) {
220 SVNStatus s = m_status.at(i);
221 if (s.m_path == "." || s.m_path == "..") continue;
222 if ((m_updateToRevision && s.m_item == "modified") ||
223 (s.m_item == "modified" && s.m_repoStatus == "modified"))
224 m_filesWithConflict.prepend(s.m_path);
225 else if (s.m_item == "none" || s.m_item == "missing" ||
226 s.m_repoStatus == "modified" || s.m_repoStatus == "modified") {
227 if (s.m_path.endsWith(".tnz") &&
228 (s.m_item == "missing" ||
229 (s.m_item == "none" && s.m_repoStatus == "added"))) {
230 TFilePath scenePath =
231 TFilePath(m_workingDir.toStdWString()) + s.m_path.toStdWString();
232 TFilePath iconPath = ToonzScene::getIconPath(scenePath);
233 QDir dir(m_workingDir);
234 #ifdef MACOSX
235 m_filesToUpdate.append(dir.relativeFilePath(toQString(iconPath)));
236 #else
237 m_filesToUpdate.append(
238 dir.relativeFilePath(toQString(iconPath)).replace("/", "\\"));
239 #endif
240 m_sceneIconsCount++;
241 m_someSceneIsMissing = true;
242 }
243 if (m_files.count() == 1 || m_files.contains(s.m_path))
244 m_filesToUpdate.prepend(s.m_path);
245 }
246 }
247 }
248
249 //-----------------------------------------------------------------------------
250
updateFiles()251 void SVNUpdateDialog::updateFiles() {
252 if (m_filesToUpdate.count() == 0) {
253 QString msg = QString(tr("No items to update."));
254 m_textLabel->setText(msg);
255 m_textLabel->show();
256 switchToCloseButton();
257 return;
258 }
259
260 setMinimumSize(300, 200);
261
262 if (m_updateSceneContentsCheckBox) m_updateSceneContentsCheckBox->hide();
263 m_updateButton->setEnabled(false);
264 m_waitingLabel->hide();
265 m_textLabel->hide();
266 m_output->show();
267
268 QStringList args;
269 args << "update";
270
271 int filesCount = m_filesToUpdate.count();
272 for (int i = 0; i < filesCount; i++) {
273 QString file = m_filesToUpdate.at(i);
274 if (!file.isEmpty()) args << file;
275 }
276
277 int resourceCount = m_sceneResources.size();
278 for (int i = 0; i < resourceCount; i++) args << m_sceneResources.at(i);
279
280 if (m_nonRecursive) args << "--non-recursive";
281
282 m_thread.disconnect(SIGNAL(done(const QString &)));
283 connect(&m_thread, SIGNAL(outputRetrieved(const QString &)),
284 SLOT(addOutputText(const QString &)));
285 connect(&m_thread, SIGNAL(done(const QString &)),
286 SLOT(onUpdateDone(const QString &)));
287 m_thread.executeCommand(m_workingDir, "svn", args, false);
288 }
289
290 //-----------------------------------------------------------------------------
291
switchToCloseButton()292 void SVNUpdateDialog::switchToCloseButton() {
293 if (m_updateSceneContentsCheckBox) m_updateSceneContentsCheckBox->hide();
294 m_cancelButton->hide();
295 m_updateButton->hide();
296 m_closeButton->show();
297 m_closeButton->setEnabled(true);
298 }
299
300 //-----------------------------------------------------------------------------
301
addOutputText(const QString & text)302 void SVNUpdateDialog::addOutputText(const QString &text) {
303 QRegExp regExp("Updated to revision (\\d+)\\.");
304 QString temp = text;
305 temp.remove(regExp);
306
307 QStringList split = temp.split(QRegExp("\\r\\n|\\n"));
308
309 for (int i = 0; i < split.size(); i++) {
310 QString s = split.at(i);
311 if (!s.isEmpty()) m_output->insertPlainText(s + "\n");
312 }
313 QScrollBar *scrollBar = m_output->verticalScrollBar();
314 scrollBar->setValue(scrollBar->maximum());
315 }
316
317 //-----------------------------------------------------------------------------
318
onUpdateToRevisionButtonClicked()319 void SVNUpdateDialog::onUpdateToRevisionButtonClicked() {
320 m_textLabel->hide();
321 m_cancelButton->hide();
322 m_updateButton->hide();
323 m_dateChooserWidget->hide();
324 m_output->show();
325
326 QStringList args;
327 args << "update";
328
329 // Pay attention: I have to perform update of the whole selected files
330 // (that could become updatable "looking in the past")
331 int filesCount = m_files.count();
332 for (int i = 0; i < filesCount; i++) {
333 QString file = m_files.at(i);
334 if (!file.isEmpty()) args << file;
335 }
336 QString revisionString = m_dateChooserWidget->getRevisionString();
337
338 args << "-r" << revisionString;
339
340 connect(&m_thread, SIGNAL(outputRetrieved(const QString &)),
341 SLOT(addOutputText(const QString &)));
342 connect(&m_thread, SIGNAL(done(const QString &)),
343 SLOT(onUpdateDone(const QString &)));
344 m_thread.executeCommand(m_workingDir, "svn", args, false);
345 }
346
347 //-----------------------------------------------------------------------------
348
onUpdateButtonClicked()349 void SVNUpdateDialog::onUpdateButtonClicked() {
350 // Update to mine
351 QStringList files = m_conflictWidget->getFilesWithOption(0);
352 if (files.size() > 0) {
353 m_waitingLabel->show();
354 m_textLabel->setText(tr("Updating items..."));
355 QStringList args;
356 args << "update";
357 args.append(files);
358 args << "--accept"
359 << "mine-full";
360
361 m_thread.disconnect(SIGNAL(done(const QString &)));
362 connect(&m_thread, SIGNAL(done(const QString &)),
363 SLOT(onUpdateToMineDone()));
364 m_thread.executeCommand(m_workingDir, "svn", args);
365 } else
366 onUpdateToMineDone();
367 }
368
369 //-----------------------------------------------------------------------------
370
onUpdateToMineDone()371 void SVNUpdateDialog::onUpdateToMineDone() {
372 // Update to theirs
373 QStringList files = m_conflictWidget->getFilesWithOption(1);
374 if (files.size() > 0) {
375 m_waitingLabel->show();
376 m_textLabel->setText(tr("Updating to their items..."));
377 QStringList args;
378 args << "update";
379 args.append(files);
380 args << "--accept"
381 << "theirs-full";
382
383 m_thread.disconnect(SIGNAL(done(const QString &)));
384 connect(&m_thread, SIGNAL(done(const QString &)),
385 SLOT(onConflictResolved()));
386 m_thread.executeCommand(m_workingDir, "svn", args);
387 } else
388 onConflictResolved();
389 }
390
391 //-----------------------------------------------------------------------------
392
onConflictResolved()393 void SVNUpdateDialog::onConflictResolved() {
394 m_conflictWidget->hide();
395 updateFiles();
396 }
397
398 //-----------------------------------------------------------------------------
399
onError(const QString & errorString)400 void SVNUpdateDialog::onError(const QString &errorString) {
401 m_waitingLabel->hide();
402 if (m_output->isVisible())
403 addOutputText(errorString);
404 else {
405 m_textLabel->setText(errorString);
406 m_textLabel->show();
407 }
408 switchToCloseButton();
409 }
410
411 //-----------------------------------------------------------------------------
412
onUpdateDone(const QString & text)413 void SVNUpdateDialog::onUpdateDone(const QString &text) {
414 addOutputText(text);
415
416 QStringList files;
417 for (int i = 0; i < m_filesToUpdate.size(); i++)
418 files.append(m_filesToUpdate.at(i));
419 emit done(files);
420
421 switchToCloseButton();
422 }
423
424 //-----------------------------------------------------------------------------
425
onConflictSetted()426 void SVNUpdateDialog::onConflictSetted() { m_updateButton->setEnabled(true); }
427
428 //-----------------------------------------------------------------------------
429
onUpdateSceneContentsToggled(bool checked)430 void SVNUpdateDialog::onUpdateSceneContentsToggled(bool checked) {
431 if (!checked)
432 m_sceneResources.clear();
433 else {
434 VersionControl *vc = VersionControl::instance();
435
436 int fileSize = m_filesToUpdate.count();
437 for (int i = 0; i < fileSize; i++) {
438 QString fileName = m_filesToUpdate.at(i);
439 if (fileName.endsWith(".tnz"))
440 m_sceneResources.append(vc->getSceneContents(m_workingDir, fileName));
441 }
442 }
443
444 if (m_filesToUpdate.size() == 1)
445 m_textLabel->setText(
446 tr("%1 items to update.")
447 .arg(m_filesToUpdate.size() + m_sceneResources.size()));
448 else
449 m_textLabel->setText(tr("%1 items to update.")
450 .arg(m_filesToUpdate.size() +
451 m_sceneResources.size() - m_sceneIconsCount));
452 }
453