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