1
2
3 #include "overwritepopup.h"
4
5 // Tnz6 includes
6 #include "tapp.h"
7 #include "tsystem.h"
8
9 // TnzQt includes
10 #include "toonzqt/checkbox.h"
11 #include "toonzqt/dvdialog.h"
12 #include "toonzqt/lineedit.h"
13 #include "toonzqt/gutil.h"
14
15 // TnzLib includes
16 #include "toonz/toonzscene.h"
17
18 // TnzCore includes
19 #include "tfilepath.h"
20
21 // Qt includes
22 #include <QLabel>
23 #include <QPushButton>
24 #include <QRadioButton>
25 #include <QButtonGroup>
26 #include <QApplication>
27 #include <QMainWindow>
28
29 //************************************************************************************
30 // OverwriteDialog::ExistsFunc implementation
31 //************************************************************************************
32
conflictString(const TFilePath & fp) const33 QString OverwriteDialog::DecodeFileExistsFunc::conflictString(
34 const TFilePath &fp) const {
35 return OverwriteDialog::tr(
36 "File \"%1\" already exists.\nWhat do you want to do?")
37 .arg(toQString(fp));
38 }
39
40 //----------------------------------------------------------------------------------
41
operator ()(const TFilePath & fp) const42 bool OverwriteDialog::DecodeFileExistsFunc::operator()(
43 const TFilePath &fp) const {
44 return TSystem::doesExistFileOrLevel(m_scene->decodeFilePath(fp));
45 }
46
47 //************************************************************************************
48 // OverwriteDialog implementation
49 //************************************************************************************
50
OverwriteDialog()51 OverwriteDialog::OverwriteDialog()
52 : DVGui::Dialog(TApp::instance()->getMainWindow(), true) {
53 setModal(true);
54 setWindowTitle(tr("Warning!"));
55
56 QButtonGroup *buttonGroup = new QButtonGroup(this);
57 buttonGroup->setExclusive(true);
58 bool ret = connect(buttonGroup, SIGNAL(buttonClicked(int)), this,
59 SLOT(onButtonClicked(int)));
60
61 beginVLayout();
62
63 m_label = new QLabel(this);
64 addWidget(m_label);
65
66 m_keep = new QRadioButton(tr("Keep existing file"), this);
67 buttonGroup->addButton(m_keep);
68 addWidget(m_keep);
69
70 m_overwrite = new QRadioButton(
71 tr("Overwrite the existing file with the new one"), this);
72 buttonGroup->addButton(m_overwrite);
73 addWidget(m_overwrite);
74
75 m_rename =
76 new QRadioButton(tr("Rename the new file adding the suffix"), this);
77 buttonGroup->addButton(m_rename);
78
79 m_suffix = new DVGui::LineEdit("_1", this);
80 m_suffix->setFixedWidth(25);
81 m_suffix->setEnabled(false);
82
83 QHBoxLayout *boxLayout = new QHBoxLayout();
84 boxLayout->setMargin(0);
85 boxLayout->setSpacing(0);
86 boxLayout->addWidget(m_rename);
87 boxLayout->addWidget(m_suffix);
88 boxLayout->setAlignment(m_rename, Qt::AlignLeft);
89 boxLayout->setAlignment(m_suffix, Qt::AlignLeft);
90 addLayout(boxLayout);
91
92 endVLayout();
93
94 m_okBtn = new QPushButton(QString(tr("Apply")), this);
95 ret = ret && connect(m_okBtn, SIGNAL(clicked()), this, SLOT(accept()));
96 addButtonBarWidget(m_okBtn);
97
98 m_okToAllBtn = new QPushButton(QString(tr("Apply to All")), this);
99 ret =
100 ret && connect(m_okToAllBtn, SIGNAL(clicked()), this, SLOT(applyToAll()));
101 addButtonBarWidget(m_okToAllBtn);
102
103 m_cancelBtn = new QPushButton(QString(tr("Cancel")), this);
104 ret = ret && connect(m_cancelBtn, SIGNAL(clicked()), this, SLOT(cancel()));
105 addButtonBarWidget(m_cancelBtn);
106
107 assert(ret);
108
109 reset();
110 m_keep->setChecked(true);
111 }
112
113 //----------------------------------------------------------------------------------
114
reset()115 void OverwriteDialog::reset() {
116 m_choice = KEEP_OLD;
117 m_applyToAll = false;
118 m_cancelPressed = false;
119 }
120
121 //----------------------------------------------------------------------------------
122
getSuffix()123 std::wstring OverwriteDialog::getSuffix() {
124 return m_suffix->text().toStdWString();
125 }
126
127 //----------------------------------------------------------------------------------
128
applyToAll()129 void OverwriteDialog::applyToAll() {
130 m_applyToAll = true;
131 accept();
132 }
133
134 //----------------------------------------------------------------------------------
135
cancel()136 void OverwriteDialog::cancel() {
137 m_cancelPressed = true;
138 reject();
139 }
140
141 //----------------------------------------------------------------------------------
142
onButtonClicked(int)143 void OverwriteDialog::onButtonClicked(int) {
144 m_suffix->setEnabled(m_rename->isChecked());
145 }
146
147 //----------------------------------------------------------------------------------
148
addSuffix(const TFilePath & src) const149 TFilePath OverwriteDialog::addSuffix(const TFilePath &src) const {
150 return src.withName(src.getWideName() + m_suffix->text().toStdWString());
151 }
152
153 //----------------------------------------------------------------------------------
154
execute(TFilePath & filePath,const ExistsFunc & exists,Resolution acceptedRes,Flags flags)155 OverwriteDialog::Resolution OverwriteDialog::execute(TFilePath &filePath,
156 const ExistsFunc &exists,
157 Resolution acceptedRes,
158 Flags flags) {
159 typedef QRadioButton *OverwriteDialog::*RadioRes;
160 static const RadioRes radios[3] = {&OverwriteDialog::m_keep,
161 &OverwriteDialog::m_overwrite,
162 &OverwriteDialog::m_rename};
163
164 struct locals {
165 static inline int idx(Resolution res) {
166 int r = 0;
167 while (r < 3 && !(res & (1 << r))) ++r;
168 return r;
169 }
170 };
171
172 TFilePath writePath = filePath;
173
174 // Deal with the case where "Apply To All" was already clicked
175 if (m_applyToAll && (m_choice & acceptedRes)) {
176 if (m_choice == RENAME) writePath = addSuffix(writePath);
177
178 if (m_choice != RENAME || !exists(writePath))
179 return filePath = writePath, m_choice;
180 }
181
182 reset();
183
184 // Find a compatible suffix to be displayed
185 if (acceptedRes & RENAME)
186 for (int i = 1; exists(addSuffix(filePath)); ++i)
187 m_suffix->setText("_" + QString::number(i));
188
189 // Show the various dialog components as specified
190 m_overwrite->setVisible(acceptedRes & OVERWRITE);
191 m_keep->setVisible(acceptedRes & KEEP_OLD);
192 m_rename->setVisible(acceptedRes & RENAME);
193 m_suffix->setVisible(acceptedRes & RENAME);
194 m_okToAllBtn->setVisible(flags & APPLY_TO_ALL_FLAG);
195
196 // Ensure that there is a checked button among the accepted resolutions
197 for (int r = 0; r < 3; ++r)
198 if ((this->*radios[r])->isChecked()) {
199 if (!(acceptedRes & (1 << r)))
200 (this->*radios[locals::idx(acceptedRes)])->setChecked(true);
201 break;
202 }
203
204 // Prompt the dialog to let the user decide resolution
205 while (true) {
206 // Build text to be displayed
207 m_label->setText(exists.conflictString(writePath));
208
209 // Execute dialog
210 int retCode = exec();
211
212 m_choice = (retCode == QDialog::Rejected)
213 ? CANCELED
214 : m_overwrite->isChecked()
215 ? OVERWRITE
216 : m_rename->isChecked() ? RENAME : KEEP_OLD;
217
218 if (m_choice == RENAME) {
219 if (exists(writePath = addSuffix(filePath))) continue;
220 }
221
222 break;
223 }
224
225 return filePath = writePath, m_choice;
226 }
227
228 //----------------------------------------------------------------------------------
229
execute(ToonzScene * scene,const TFilePath & srcLevelPath,bool multiload)230 std::wstring OverwriteDialog::execute(ToonzScene *scene,
231 const TFilePath &srcLevelPath,
232 bool multiload) {
233 TFilePath levelPath = srcLevelPath;
234 TFilePath actualLevelPath = scene->decodeFilePath(levelPath);
235 if (!TSystem::doesExistFileOrLevel(actualLevelPath))
236 return levelPath.getWideName();
237
238 if (m_applyToAll && m_choice == RENAME) {
239 levelPath = addSuffix(levelPath);
240 actualLevelPath = scene->decodeFilePath(levelPath);
241 }
242 if (m_applyToAll) {
243 if (m_choice != RENAME || !TSystem::doesExistFileOrLevel(actualLevelPath))
244 return levelPath.getWideName();
245 }
246
247 m_label->setText(tr("File %1 already exists.\nWhat do you want to do?")
248 .arg(toQString(levelPath)));
249 // find a compatible suffix
250 if (TSystem::doesExistFileOrLevel(actualLevelPath)) {
251 int i = 0;
252 while (TSystem::doesExistFileOrLevel(
253 scene->decodeFilePath(addSuffix(srcLevelPath)))) {
254 m_suffix->setText("_" + QString::number(++i));
255 }
256 }
257
258 if (multiload)
259 m_okToAllBtn->show();
260 else
261 m_okToAllBtn->hide();
262
263 // there could be a WaitCursor cursor
264 QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
265 raise();
266 exec();
267 QApplication::restoreOverrideCursor();
268
269 if (m_rename->isChecked()) {
270 if (m_suffix->text() == "") {
271 DVGui::warning(tr("The suffix field is empty. Please specify a suffix."));
272 return execute(scene, srcLevelPath, multiload);
273 }
274 levelPath = addSuffix(srcLevelPath);
275 actualLevelPath = scene->decodeFilePath(levelPath);
276 if (TSystem::doesExistFileOrLevel(actualLevelPath)) {
277 DVGui::warning(
278 tr("File %1 exists as well; please choose a different suffix.")
279 .arg(toQString(levelPath)));
280 return execute(scene, srcLevelPath, multiload);
281 }
282 m_choice = RENAME;
283 } else if (m_overwrite->isChecked())
284 m_choice = OVERWRITE;
285 else {
286 assert(m_keep->isChecked());
287 m_choice = KEEP_OLD;
288 }
289
290 return levelPath.getWideName();
291 }
292