]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/GuiAlert.cpp
Generalize starred cite commands
[lyx.git] / src / frontends / qt4 / GuiAlert.cpp
1 /**
2  * \file qt4/GuiAlert.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Jürgen Spitzmüller
8  * \author Abdelrazak Younes
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "alert.h"
16 #include "InGuiThread.h"
17
18 #include "frontends/Application.h"
19
20 #include "qt_helpers.h"
21 #include "LyX.h" // for lyx::use_gui
22
23 #include "support/gettext.h"
24 #include "support/debug.h"
25 #include "support/docstring.h"
26 #include "support/lstrings.h"
27 #include "support/lassert.h"
28 #include "support/ProgressInterface.h"
29
30 #include <QApplication>
31 #include <QCheckBox>
32 #include <QMessageBox>
33 #include <QLineEdit>
34 #include <QInputDialog>
35 #include <QPushButton>
36 #include <QSettings>
37
38 #include <iomanip>
39 #include <iostream>
40
41
42 // sync with GuiView.cpp
43 #define EXPORT_in_THREAD 1
44
45
46 using namespace std;
47 using namespace lyx::support;
48
49 namespace lyx {
50 namespace frontend {
51
52
53 void noAppDialog(QString const & title, QString const & msg, QMessageBox::Icon mode)
54 {
55         int argc = 1;
56         const char *argv[] = { "lyx", 0 };
57
58         QApplication app(argc, (char**)argv);
59         switch (mode)
60         {
61                 case QMessageBox::Information: QMessageBox::information(0, title, msg); break;
62                 case QMessageBox::Warning: QMessageBox::warning(0, title, msg); break;
63                 case QMessageBox::Critical: QMessageBox::critical(0, title, msg); break;
64                 default: break;
65         }
66 }
67
68
69 namespace Alert {
70
71
72 docstring toPlainText(docstring const & msg)
73 {
74         return qstring_to_ucs4(qtHtmlToPlainText(toqstr(msg)));
75 }
76
77
78 int doPrompt(docstring const & title0, docstring const & question,
79                   int default_button, int cancel_button,
80                   docstring const & b1, docstring const & b2,
81                   docstring const & b3, docstring const & b4)
82 {
83         //lyxerr << "PROMPT" << title0 << "FOCUS: " << qApp->focusWidget() << endl;
84         if (!use_gui || lyxerr.debugging()) {
85                 lyxerr << toPlainText(title0) << '\n'
86                        << "----------------------------------------\n"
87                        << toPlainText(question) << endl;
88
89                 lyxerr << "Assuming answer is ";
90                 switch (default_button) {
91                 case 0: lyxerr << b1 << endl; break;
92                 case 1: lyxerr << b2 << endl; break;
93                 case 2: lyxerr << b3 << endl; break;
94                 case 3: lyxerr << b4 << endl;
95                 }
96                 if (!use_gui)
97                         return default_button;
98         }
99
100         docstring const title = bformat(_("LyX: %1$s"), title0);
101
102         /// Long operation in progress prevents user from Ok-ing the error dialog
103         bool long_op = theApp()->longOperationStarted();
104         if (long_op)
105                 theApp()->stopLongOperation();
106
107         // For some reason, sometimes Qt uses a hourglass or watch cursor when
108         // displaying the alert. Hence, we ask for the standard cursor shape.
109         qApp->setOverrideCursor(Qt::ArrowCursor);
110
111         // FIXME replace that with guiApp->currentView()
112         //LYXERR0("FOCUS: " << qApp->focusWidget());
113         QPushButton * b[4] = { 0, 0, 0, 0 };
114         QMessageBox msg_box(QMessageBox::Information,
115                         toqstr(title), toqstr(question),
116                         QMessageBox::NoButton, qApp->focusWidget());
117         b[0] = msg_box.addButton(b1.empty() ? "OK" : toqstr(b1),
118                                         QMessageBox::ActionRole);
119         if (!b2.empty())
120                 b[1] = msg_box.addButton(toqstr(b2), QMessageBox::ActionRole);
121         if (!b3.empty())
122                 b[2] = msg_box.addButton(toqstr(b3), QMessageBox::ActionRole);
123         if (!b4.empty())
124                 b[3] = msg_box.addButton(toqstr(b4), QMessageBox::ActionRole);
125         msg_box.setDefaultButton(b[default_button]);
126         msg_box.setEscapeButton(static_cast<QAbstractButton *>(b[cancel_button]));
127         int res = msg_box.exec();
128
129         qApp->restoreOverrideCursor();
130
131         if (long_op)
132                 theApp()->startLongOperation();
133
134         // Qt bug: can return -1 on cancel or WM close, despite the docs.
135         if (res == -1)
136                 res = cancel_button;
137         return res;
138 }
139
140 int prompt(docstring const & title0, docstring const & question,
141                   int default_button, int cancel_button,
142                   docstring const & b1, docstring const & b2,
143                   docstring const & b3, docstring const & b4)
144 {
145 #ifdef EXPORT_in_THREAD
146         return InGuiThread<int>().call(&doPrompt,
147 #else
148         return doPrompt(
149 #endif
150                                 title0, question, default_button,
151                                 cancel_button, b1, b2, b3, b4);
152 }
153
154 void doWarning(docstring const & title0, docstring const & message,
155              bool const & askshowagain)
156 {
157         lyxerr << "Warning: " << toPlainText(title0) << '\n'
158                << "----------------------------------------\n"
159                << toPlainText(message) << endl;
160
161         if (!use_gui)
162                 return;
163
164         docstring const title = bformat(_("LyX: %1$s"), title0);
165
166         if (theApp() == 0) {
167                 noAppDialog(toqstr(title), toqstr(message), QMessageBox::Warning);
168                 return;
169         }
170
171         /// Long operation in progress prevents user from Ok-ing the error dialog
172         bool long_op = theApp()->longOperationStarted();
173         if (long_op)
174                 theApp()->stopLongOperation();
175
176         // Don't use a hourglass cursor while displaying the alert
177         qApp->setOverrideCursor(Qt::ArrowCursor);
178
179         if (!askshowagain) {
180                 ProgressInterface::instance()->warning(
181                                 toqstr(title),
182                                 toqstr(message));
183         } else {
184                 ProgressInterface::instance()->toggleWarning(
185                                 toqstr(title),
186                                 toqstr(message),
187                                 toqstr(message));
188         }
189
190         qApp->restoreOverrideCursor();
191
192         if (long_op)
193                 theApp()->startLongOperation();
194 }
195
196 void warning(docstring const & title0, docstring const & message,
197              bool const & askshowagain)
198 {
199 #ifdef EXPORT_in_THREAD 
200         InGuiThread<void>().call(&doWarning,
201 #else
202         doWarning(
203 #endif
204                                 title0, message, askshowagain);
205 }
206
207 void doError(docstring const & title0, docstring const & message, bool backtrace)
208 {
209         lyxerr << "Error: " << toPlainText(title0) << '\n'
210                << "----------------------------------------\n"
211                << toPlainText(message) << endl;
212
213         QString details;
214         if (backtrace) {
215                 details = QString::fromLocal8Bit(to_local8bit(printCallStack()).c_str());
216         }
217
218         if (!use_gui)
219                 return;
220
221         docstring const title = bformat(_("LyX: %1$s"), title0);
222
223         if (theApp() == 0) {
224                 noAppDialog(toqstr(title), toqstr(message), QMessageBox::Critical);
225                 return;
226         }
227
228         /// Long operation in progress prevents user from Ok-ing the error dialog
229         bool long_op = theApp()->longOperationStarted();
230         if (long_op)
231                 theApp()->stopLongOperation();
232
233         // Don't use a hourglass cursor while displaying the alert
234         qApp->setOverrideCursor(Qt::ArrowCursor);
235
236         ProgressInterface::instance()->error(
237                 toqstr(title),
238                 toqstr(message),
239                 details);
240
241         qApp->restoreOverrideCursor();
242
243         if (long_op)
244                 theApp()->startLongOperation();
245 }
246
247 void error(docstring const & title0, docstring const & message, bool backtrace)
248 {
249 #ifdef EXPORT_in_THREAD
250         InGuiThread<void>().call(&doError, 
251 #else
252         doError(
253 #endif
254                                 title0, message, backtrace);
255 }
256
257 void doInformation(docstring const & title0, docstring const & message)
258 {
259         if (!use_gui || lyxerr.debugging())
260                 lyxerr << toPlainText(title0) << '\n'
261                        << "----------------------------------------\n"
262                        << toPlainText(message) << endl;
263
264         if (!use_gui)
265                 return;
266
267         docstring const title = bformat(_("LyX: %1$s"), title0);
268
269         if (theApp() == 0) {
270                 noAppDialog(toqstr(title), toqstr(message), QMessageBox::Information);
271                 return;
272         }
273
274         /// Long operation in progress prevents user from Ok-ing the error dialog
275         bool long_op = theApp()->longOperationStarted();
276         if (long_op)
277                 theApp()->stopLongOperation();
278
279         // Don't use a hourglass cursor while displaying the alert
280         qApp->setOverrideCursor(Qt::ArrowCursor);
281
282         ProgressInterface::instance()->information(
283                 toqstr(title),
284                 toqstr(message));
285
286         qApp->restoreOverrideCursor();
287
288         if (long_op)
289                 theApp()->startLongOperation();
290 }
291
292 void information(docstring const & title0, docstring const & message)
293 {
294 #ifdef EXPORT_in_THREAD
295         InGuiThread<void>().call(&doInformation,
296 #else
297         doInformation(
298 #endif
299                                 title0, message);
300 }
301
302 bool doAskForText(docstring & response, docstring const & msg,
303         docstring const & dflt)
304 {
305         if (!use_gui || lyxerr.debugging()) {
306                 lyxerr << "----------------------------------------\n"
307                        << toPlainText(msg) << '\n'
308                        << "Assuming answer is " << dflt << '\n'
309                        << "----------------------------------------" << endl;
310                 if (!use_gui) {
311                         response = dflt;
312                         return true;
313                 }
314         }
315
316         docstring const title = bformat(_("LyX: %1$s"), msg);
317
318         /// Long operation in progress prevents user from Ok-ing the error dialog
319         bool long_op = theApp()->longOperationStarted();
320         if (long_op)
321                 theApp()->stopLongOperation();
322
323         bool ok;
324         QString text = QInputDialog::getText(qApp->focusWidget(),
325                 toqstr(title),
326                 toqstr(char_type('&') + msg),
327                 QLineEdit::Normal,
328                 toqstr(dflt), &ok);
329
330         if (long_op)
331                 theApp()->startLongOperation();
332
333         if (ok) {
334                 response = qstring_to_ucs4(text);
335                 return true;
336         }
337         response.clear();
338         return false;
339 }
340
341 bool askForText(docstring & response, docstring const & msg,
342         docstring const & dflt)
343 {
344 #ifdef EXPORT_in_THREAD
345         return InGuiThread<bool>().call(&doAskForText,
346 #else
347         return doAskForText(
348 #endif
349                                 response, msg, dflt);
350 }
351
352 } // namespace Alert
353 } // namespace frontend
354 } // namespace lyx