]> git.lyx.org Git - lyx.git/blob - src/frontends/qt/GuiCompare.cpp
Properly scale some icons for HiDPI (#12695)
[lyx.git] / src / frontends / qt / GuiCompare.cpp
1 /**
2  * \file GuiCompare.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Vincent van Ravesteijn
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "GuiCompare.h"
14
15 #include "GuiApplication.h"
16
17 #include "Buffer.h"
18 #include "BufferView.h"
19 #include "BufferList.h"
20 #include "buffer_funcs.h"
21 #include "ColorCache.h"
22 #include "Compare.h"
23 #include "FuncRequest.h"
24 #include "GuiView.h"
25 #include "LyXRC.h"
26 #include "qt_helpers.h"
27
28 #include "frontends/alert.h"
29
30 #include "support/debug.h"
31 #include "support/filetools.h"
32 #include "support/FileName.h"
33 #include "support/gettext.h"
34
35 #include <QDialogButtonBox>
36 #include <QThread>
37
38
39 using namespace std;
40 using namespace lyx::support;
41
42 namespace lyx {
43 namespace frontend {
44
45
46 GuiCompare::GuiCompare(GuiView & lv)
47         : GuiDialog(lv, "compare", qt_("Compare LyX files")),
48         compare_(0), dest_buffer_(0), old_buffer_(0), new_buffer_(0)
49 {
50         setupUi(this);
51         setModal(Qt::WindowModal);
52
53         connect(buttonBox, SIGNAL(clicked(QAbstractButton *)),
54                 this, SLOT(slotButtonBox(QAbstractButton *)));
55
56         connect(newFilePB, SIGNAL(clicked()), this, SLOT(selectNewFile()));
57         connect(oldFilePB, SIGNAL(clicked()), this, SLOT(selectOldFile()));
58
59         connect(newFileCB, SIGNAL(currentIndexChanged(int)),
60                 this, SLOT(changeAdaptor()));
61         connect(newFileCB, SIGNAL(editTextChanged(const QString &)),
62                 this, SLOT(changeAdaptor()));
63         connect(oldFileCB, SIGNAL(currentIndexChanged(int)),
64                 this, SLOT(changeAdaptor()));
65         connect(oldFileCB, SIGNAL(editTextChanged(const QString &)),
66                 this, SLOT(changeAdaptor()));
67
68         newSettingsRB->setChecked(true);
69         trackingCB->setChecked(true);
70
71         buttonBox->button(QDialogButtonBox::Ok)->setCursor(Qt::ArrowCursor);
72
73         bc().setPolicy(ButtonPolicy::OkApplyCancelPolicy);
74         bc().setOK(buttonBox->button(QDialogButtonBox::Ok));
75 }
76
77 GuiCompare::~GuiCompare()
78 {
79         if (compare_)
80                 delete compare_;
81 }
82
83 void GuiCompare::closeEvent(QCloseEvent *)
84 {
85         slotCancel();
86 }
87
88
89 void GuiCompare::changeAdaptor()
90 {
91         changed();
92 }
93
94
95 bool GuiCompare::isValid()
96 {
97         bool const valid = !newFileCB->currentText().isEmpty()
98                 && !oldFileCB->currentText().isEmpty();
99         return valid;
100 }
101
102
103 void GuiCompare::updateContents()
104 {
105         if (compare_ && compare_->isRunning())
106                 return;
107
108         QString restore_filename1 = newFileCB->currentText();
109         QString restore_filename2 = oldFileCB->currentText();
110         newFileCB->clear();
111         oldFileCB->clear();
112         progressBar->setValue(0);
113         statusBar->clearMessage();
114         BufferList::iterator it = theBufferList().begin();
115         BufferList::iterator const end = theBufferList().end();
116         for (; it != end; ++it) {
117                 QString filename = toqstr((*it)->absFileName());
118                 newFileCB->addItem(filename);
119                 oldFileCB->addItem(filename);
120         }
121         if (!restore_filename1.isEmpty())
122                 newFileCB->setEditText(restore_filename1);
123         else if (lyxview().documentBufferView())
124                 newFileCB->setEditText(toqstr(buffer().absFileName()));
125
126         if (!restore_filename2.isEmpty())
127                 oldFileCB->setEditText(restore_filename2);
128         else
129                 oldFileCB->clearEditText();
130
131         if (isValid()) {
132                 bc().setValid(isValid());
133                 bc().apply();
134         }
135 }
136
137
138 void GuiCompare::selectNewFile()
139 {
140         QString name = browse(newFileCB->currentText());
141         if (!name.isEmpty())
142                 newFileCB->setEditText(name);
143         changed();
144 }
145
146
147 void GuiCompare::selectOldFile()
148 {
149         QString name = browse(oldFileCB->currentText());
150         if (!name.isEmpty())
151                 oldFileCB->setEditText(name);
152         changed();
153 }
154
155
156 QString GuiCompare::browse(QString const & in_name) const
157 {
158         QString const title = qt_("Select document");
159
160         QStringList const & filters = fileFilters(qt_("LyX Documents (*.lyx)"));
161
162         QString filename;
163         if (lyxview().documentBufferView()) {
164                 QString path = bufferFilePath();
165                 filename = browseRelToParent(in_name, path, title, filters, false,
166                         qt_("D&ocuments"), toqstr(lyxrc.document_path));
167         } else {
168                 QString path = toqstr(lyxrc.document_path);
169                 QString rel_filename = browseRelToParent(in_name, path, title, filters, false,
170                         qt_("D&ocuments"), toqstr(lyxrc.document_path));
171                 filename = makeAbsPath(rel_filename, path);
172         }
173         return filename;
174 }
175
176
177 void GuiCompare::enableControls(bool enable)
178 {
179         // Set the hourglass cursor for the dialog, but
180         // never for the cancel button.
181         setCursor(enable ? Qt::ArrowCursor : Qt::WaitCursor);
182
183         newFileLA->setEnabled(enable);
184         newFilePB->setEnabled(enable);
185         newFileCB->setEnabled(enable);
186         oldFileLA->setEnabled(enable);
187         oldFilePB->setEnabled(enable);
188         oldFileCB->setEnabled(enable);
189         buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enable);
190         groupBox->setEnabled(enable);
191         progressBar->setEnabled(!enable);
192
193         if (enable)
194                 buttonBox->button(QDialogButtonBox::Cancel)->setText(qt_("Close"));
195         else
196                 buttonBox->button(QDialogButtonBox::Cancel)->setText(qt_("Cancel"));
197 }
198
199
200 void GuiCompare::error()
201 {
202         Alert::error(_("Error"), _("Error while comparing documents."));
203         finished(true);
204 }
205
206 void GuiCompare::finished(bool aborted)
207 {
208         enableControls(true);
209
210         if (compare_) {
211                 delete compare_;
212                 compare_ = 0;
213         }
214
215         if (aborted) {
216                 if (dest_buffer_) {
217                         dest_buffer_->markClean();
218                         theBufferList().release(dest_buffer_);
219                 }
220                 progressBar->setValue(0);
221                 statusBar->showMessage(qt_("Aborted"), 5000);
222         } else {
223                 hideView();
224                 bc().ok();
225                 if (dest_buffer_) {
226                         dispatch(FuncRequest(LFUN_BUFFER_SWITCH,
227                                 dest_buffer_->absFileName()));
228                         if (trackingCB->isChecked()) {
229                                 dispatch(FuncRequest(LFUN_CHANGES_OUTPUT));
230                                 dispatch(FuncRequest(LFUN_CHANGES_TRACK));
231                         }
232                 }
233                 statusBar->showMessage(qt_("Finished"), 5000);
234         }
235 }
236
237
238 void GuiCompare::progress(int val)
239 {
240         progressBar->setValue(progressBar->value() + val);
241 }
242
243
244 void GuiCompare::progressMax(int max) const
245 {
246         progressBar->setMaximum(max);
247 }
248
249
250 void GuiCompare::setStatusMessage(QString const & msg)
251 {
252         statusBar->showMessage(msg);
253 }
254
255
256 void GuiCompare::slotOK()
257 {
258         enableControls(false);
259         if (!run())
260                 error();
261 }
262
263
264 void GuiCompare::slotCancel()
265 {
266         if (compare_ && compare_->isRunning()) {
267                 statusBar->showMessage(qt_("Aborting process..."));
268                 compare_->abort();
269         } else {
270                 GuiDialog::slotClose();
271                 progressBar->setValue(0);
272                 statusBar->clearMessage();
273         }
274 }
275
276
277 void GuiCompare::slotButtonBox(QAbstractButton * button)
278 {
279         switch (buttonBox->standardButton(button)) {
280         case QDialogButtonBox::Ok:
281                 slotOK();
282                 break;
283         case QDialogButtonBox::Cancel:
284                 slotCancel();
285                 break;
286         default:
287                 break;
288         }
289 }
290
291
292 Buffer const * GuiCompare::bufferFromFileName(string const & file) const
293 {
294         FileName fname;
295         if (FileName::isAbsolute(file))
296                 fname.set(file);
297         else if (lyxview().documentBufferView())
298                 fname = support::makeAbsPath(file, fromqstr(bufferFilePath()));
299
300         if (fname.empty()
301                         || (!fname.exists() && !theBufferList().getBuffer(fname))) {
302                 LYXERR0( "Unable to read: " << file);
303                 return 0;
304         }
305         return loadIfNeeded(fname);
306 }
307
308
309 int GuiCompare::run(bool blocking_mode)
310 {
311         progressBar->setValue(0);
312
313         new_buffer_ = bufferFromFileName(fromqstr(newFileCB->currentText()));
314         old_buffer_ = bufferFromFileName(fromqstr(oldFileCB->currentText()));
315
316         // new buffer that will carry the output
317         FileName initpath(lyxrc.document_path);
318         dest_buffer_ = newUnnamedFile(initpath, to_utf8(_("differences")));
319
320         if (!new_buffer_ || !old_buffer_ || !dest_buffer_)
321                 return 0;
322
323         dest_buffer_->changed(true);
324         if (blocking_mode)
325                 //blocking mode is infinitive and we don't want diff autosave
326                 //if user decides to kill ther running lyx instance
327                 dest_buffer_->markClean();
328         else
329                 dest_buffer_->markDirty();
330
331
332         // get the options from the dialog
333         CompareOptions options;
334         options.settings_from_new = newSettingsRB->isChecked();
335         options.author = authorCO->currentIndex();
336
337         // init the compare object and start it
338
339         compare_ = new Compare(new_buffer_, old_buffer_, dest_buffer_, options);
340
341         connect(compare_, SIGNAL(error()), this, SLOT(error()));
342         // Only connect the finished() method to the signal if we're *not* in blocking_mode
343         //  (i.e. we want to make it possible for caller to block for the results)
344         if (! blocking_mode) {
345                 connect(compare_, SIGNAL(finished(bool)), this, SLOT(finished(bool)));
346         }
347         connect(compare_, SIGNAL(progress(int)), this, SLOT(progress(int)));
348         connect(compare_, SIGNAL(progressMax(int)), this, SLOT(progressMax(int)));
349         connect(compare_, SIGNAL(statusMessage(QString)),
350                 this, SLOT(setStatusMessage(QString)));
351         compare_->start(QThread::LowPriority);
352
353         return 1;
354 }
355
356 bool GuiCompare::initialiseParams(std::string const &par)
357 {
358         //just for the sake of parsing arguments
359         FuncRequest cmd(LFUN_UNKNOWN_ACTION, par);
360         if (cmd.getArg(0) == "run" || cmd.getArg(0) == "run-blocking") {
361                 oldFileCB->setEditText(toqstr(cmd.getArg(1)));
362                 newFileCB->setEditText(toqstr(cmd.getArg(2)));
363
364                 if (cmd.getArg(0) == "run" ) {
365                         // Run asynchronously
366                         slotOK();
367                 }
368                 else {
369                         // Run synchronously
370                         enableControls(false);
371
372                         if (! run(true)) {
373                                 error();
374                                 return false;
375                         }
376
377                         // Wait for the Compare function to process in a thread
378                         compare_->wait();
379
380                         finished(false);
381                         //Hiding dialog does not work as intended through finished routine, because showView
382                         //is triggered after initialiseParams returns true. So we return false, warning will
383                         //show on the terminal though.
384                         return false;
385                 }
386         }
387
388         progressBar->setValue(0);
389         progressBar->setEnabled(false);
390         progressBar->setMaximum(1);
391
392         // If empty fill the author combobox with the current and the comparison
393         // author and their respective colors
394         if (authorCO->count() == 0) {
395                 authorCO->clear();
396                 QPixmap colorIcon(32, 32);
397                 colorIcon.fill(guiApp->colorCache().get(
398                         Color(Color_changedtext_workarea_author1)));
399                 authorCO->addItem(colorIcon, qt_("Current Author"));
400                 colorIcon.fill(guiApp->colorCache().get(
401                         Color(Color_changedtext_workarea_comparison)));
402                 authorCO->addItem(colorIcon, qt_("Document Comparison"));
403         }
404
405         return true;
406 }
407
408
409 } // namespace frontend
410 } // namespace lyx
411
412
413 #include "moc_GuiCompare.cpp"