]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiAlert.cpp
Make the InsetInfo dialog a bit less esoteric.
[lyx.git] / src / frontends / qt4 / GuiAlert.cpp
index ec904e96500fcdc218676f99fdf3634da34b5f41..ef4725c84accbc3173abefa5c174c34d99a12320 100644 (file)
@@ -4,6 +4,7 @@
  * Licence details can be found in the file COPYING.
  *
  * \author John Levon
+ * \author Jürgen Spitzmüller
  * \author Abdelrazak Younes
  *
  * Full author contact details are available in file CREDITS.
 #include <config.h>
 
 #include "alert.h"
+#include "InGuiThread.h"
 
 #include "frontends/Application.h"
 
 #include "qt_helpers.h"
-#include "support/debug.h"
 #include "LyX.h" // for lyx::use_gui
-#include "ui_AskForTextUi.h"
-#include "support/gettext.h"
 
+#include "support/gettext.h"
+#include "support/debug.h"
 #include "support/docstring.h"
 #include "support/lstrings.h"
+#include "support/lassert.h"
+#include "support/ProgressInterface.h"
 
 #include <QApplication>
+#include <QCheckBox>
 #include <QMessageBox>
 #include <QLineEdit>
 #include <QInputDialog>
+#include <QPushButton>
+#include <QSettings>
 
 #include <iomanip>
+#include <iostream>
+
+
+// sync with GuiView.cpp
+#define EXPORT_in_THREAD 1
+
 
 using namespace std;
 using namespace lyx::support;
@@ -38,83 +50,48 @@ namespace lyx {
 namespace frontend {
 
 
-static docstring const formatted(docstring const & text)
+void noAppDialog(QString const & title, QString const & msg, QMessageBox::Icon mode)
 {
-       const int w = 80;
-       docstring sout;
-
-       if (text.empty())
-               return sout;
-
-       size_t curpos = 0;
-       docstring line;
-
-       while (true) {
-               size_t const nxtpos1 = text.find(' ',  curpos);
-               size_t const nxtpos2 = text.find('\n', curpos);
-               size_t const nxtpos = min(nxtpos1, nxtpos2);
-
-               docstring const word =
-                       nxtpos == docstring::npos ?
-                       text.substr(curpos) :
-                       text.substr(curpos, nxtpos - curpos);
-
-               bool const newline = (nxtpos2 != docstring::npos &&
-                                     nxtpos2 < nxtpos1);
-
-               docstring const line_plus_word =
-                       line.empty() ? word : line + char_type(' ') + word;
-
-               // FIXME: make w be size_t
-               if (int(line_plus_word.length()) >= w) {
-                       sout += line + char_type('\n');
-                       if (newline) {
-                               sout += word + char_type('\n');
-                               line.erase();
-                       } else {
-                               line = word;
-                       }
-
-               } else if (newline) {
-                       sout += line_plus_word + char_type('\n');
-                       line.erase();
-
-               } else {
-                       if (!line.empty())
-                               line += char_type(' ');
-                       line += word;
-               }
-
-               if (nxtpos == docstring::npos) {
-                       if (!line.empty())
-                               sout += line;
-                       break;
-               }
-
-               curpos = nxtpos + 1;
+       int argc = 1;
+       const char *argv[] = { "lyx", 0 };
+
+       QApplication app(argc, (char**)argv);
+       switch (mode)
+       {
+               case QMessageBox::Information: QMessageBox::information(0, title, msg); break;
+               case QMessageBox::Warning: QMessageBox::warning(0, title, msg); break;
+               case QMessageBox::Critical: QMessageBox::critical(0, title, msg); break;
+               default: break;
        }
-
-       return sout;
 }
 
 
 namespace Alert {
 
-int prompt(docstring const & title0, docstring const & question,
+
+docstring toPlainText(docstring const & msg)
+{
+       return qstring_to_ucs4(qtHtmlToPlainText(toqstr(msg)));
+}
+
+
+int doPrompt(docstring const & title0, docstring const & question,
                  int default_button, int cancel_button,
-                 docstring const & b1, docstring const & b2, docstring const & b3)
+                 docstring const & b1, docstring const & b2,
+                 docstring const & b3, docstring const & b4)
 {
-       lyxerr << "PROMPT" << title0 << "FOCUS: " << qApp->focusWidget() << endl;
+       //lyxerr << "PROMPT" << title0 << "FOCUS: " << qApp->focusWidget() << endl;
        if (!use_gui || lyxerr.debugging()) {
-               lyxerr << title0 << '\n'
+               lyxerr << toPlainText(title0) << '\n'
                       << "----------------------------------------\n"
-                      << question << endl;
+                      << toPlainText(question) << endl;
 
                lyxerr << "Assuming answer is ";
                switch (default_button) {
-               case 0: lyxerr << b1 << endl;
-               case 1: lyxerr << b2 << endl;
-               case 2: lyxerr << b3 << endl;
+               case 0: lyxerr << b1 << endl; break;
+               case 1: lyxerr << b2 << endl; break;
+               case 2: lyxerr << b3 << endl; break;
+               case 3: lyxerr << b4 << endl;
                }
                if (!use_gui)
                        return default_button;
@@ -122,20 +99,37 @@ int prompt(docstring const & title0, docstring const & question,
 
        docstring const title = bformat(_("LyX: %1$s"), title0);
 
-       // For some reason, sometimes Qt uses an hourglass or watch cursor when
+       /// Long operation in progress prevents user from Ok-ing the error dialog
+       bool long_op = theApp()->longOperationStarted();
+       if (long_op)
+               theApp()->stopLongOperation();
+
+       // For some reason, sometimes Qt uses a hourglass or watch cursor when
        // displaying the alert. Hence, we ask for the standard cursor shape.
-       // This call has no effect if the cursor has not been overridden.
-       qApp->changeOverrideCursor(Qt::ArrowCursor);
+       qApp->setOverrideCursor(Qt::ArrowCursor);
 
        // FIXME replace that with guiApp->currentView()
-       LYXERR0("FOCUS: " << qApp->focusWidget());
-       int res = QMessageBox::information(qApp->focusWidget(),
-                                          toqstr(title),
-                                          toqstr(formatted(question)),
-                                          toqstr(b1),
-                                          toqstr(b2),
-                                          b3.empty() ? QString::null : toqstr(b3),
-                                          default_button, cancel_button);
+       //LYXERR0("FOCUS: " << qApp->focusWidget());
+       QPushButton * b[4] = { 0, 0, 0, 0 };
+       QMessageBox msg_box(QMessageBox::Information,
+                       toqstr(title), toqstr(question),
+                       QMessageBox::NoButton, qApp->focusWidget());
+       b[0] = msg_box.addButton(b1.empty() ? "OK" : toqstr(b1),
+                                       QMessageBox::ActionRole);
+       if (!b2.empty())
+               b[1] = msg_box.addButton(toqstr(b2), QMessageBox::ActionRole);
+       if (!b3.empty())
+               b[2] = msg_box.addButton(toqstr(b3), QMessageBox::ActionRole);
+       if (!b4.empty())
+               b[3] = msg_box.addButton(toqstr(b4), QMessageBox::ActionRole);
+       msg_box.setDefaultButton(b[default_button]);
+       msg_box.setEscapeButton(static_cast<QAbstractButton *>(b[cancel_button]));
+       int res = msg_box.exec();
+
+       qApp->restoreOverrideCursor();
+
+       if (long_op)
+               theApp()->startLongOperation();
 
        // Qt bug: can return -1 on cancel or WM close, despite the docs.
        if (res == -1)
@@ -143,12 +137,26 @@ int prompt(docstring const & title0, docstring const & question,
        return res;
 }
 
+int prompt(docstring const & title0, docstring const & question,
+                 int default_button, int cancel_button,
+                 docstring const & b1, docstring const & b2,
+                 docstring const & b3, docstring const & b4)
+{
+#ifdef EXPORT_in_THREAD
+       return InGuiThread<int>().call(&doPrompt,
+#else
+       return doPrompt(
+#endif
+                               title0, question, default_button,
+                               cancel_button, b1, b2, b3, b4);
+}
 
-void warning(docstring const & title0, docstring const & message)
+void doWarning(docstring const & title0, docstring const & message,
+            bool const & askshowagain)
 {
-       lyxerr << "Warning: " << title0 << '\n'
+       lyxerr << "Warning: " << toPlainText(title0) << '\n'
               << "----------------------------------------\n"
-              << message << endl;
+              << toPlainText(message) << endl;
 
        if (!use_gui)
                return;
@@ -156,68 +164,146 @@ void warning(docstring const & title0, docstring const & message)
        docstring const title = bformat(_("LyX: %1$s"), title0);
 
        if (theApp() == 0) {
-               int argc = 1;
-               char * argv[1];
-               QApplication app(argc, argv);
-               QMessageBox::warning(0,
-                       toqstr(title),
-                       toqstr(formatted(message)));
+               noAppDialog(toqstr(title), toqstr(message), QMessageBox::Warning);
                return;
        }
-       QMessageBox::warning(qApp->focusWidget(),
-                            toqstr(title),
-                            toqstr(formatted(message)));
+
+       /// Long operation in progress prevents user from Ok-ing the error dialog
+       bool long_op = theApp()->longOperationStarted();
+       if (long_op)
+               theApp()->stopLongOperation();
+
+       // Don't use a hourglass cursor while displaying the alert
+       qApp->setOverrideCursor(Qt::ArrowCursor);
+
+       if (!askshowagain) {
+               ProgressInterface::instance()->warning(
+                               toqstr(title),
+                               toqstr(message));
+       } else {
+               ProgressInterface::instance()->toggleWarning(
+                               toqstr(title),
+                               toqstr(message),
+                               toqstr(message));
+       }
+
+       qApp->restoreOverrideCursor();
+
+       if (long_op)
+               theApp()->startLongOperation();
 }
 
+void warning(docstring const & title0, docstring const & message,
+            bool const & askshowagain)
+{
+#ifdef EXPORT_in_THREAD
+       InGuiThread<void>().call(&doWarning,
+#else
+       doWarning(
+#endif
+                               title0, message, askshowagain);
+}
 
-void error(docstring const & title0, docstring const & message)
+void doError(docstring const & title0, docstring const & message, bool backtrace)
 {
-       lyxerr << "Error: " << title0 << '\n'
+       lyxerr << "Error: " << toPlainText(title0) << '\n'
               << "----------------------------------------\n"
-              << message << endl;
+              << toPlainText(message) << endl;
+
+       QString details;
+       if (backtrace)
+               details = toqstr(printCallStack());
 
        if (!use_gui)
                return;
 
        docstring const title = bformat(_("LyX: %1$s"), title0);
+
        if (theApp() == 0) {
-               int argc = 1;
-               char * argv[1];
-               QApplication app(argc, argv);
-               QMessageBox::critical(0,
-                       toqstr(title),
-                       toqstr(formatted(message)));
+               noAppDialog(toqstr(title), toqstr(message), QMessageBox::Critical);
                return;
        }
-       QMessageBox::critical(qApp->focusWidget(),
-                             toqstr(title),
-                             toqstr(formatted(message)));
+
+       /// Long operation in progress prevents user from Ok-ing the error dialog
+       bool long_op = theApp()->longOperationStarted();
+       if (long_op)
+               theApp()->stopLongOperation();
+
+       // Don't use a hourglass cursor while displaying the alert
+       qApp->setOverrideCursor(Qt::ArrowCursor);
+
+       ProgressInterface::instance()->error(
+               toqstr(title),
+               toqstr(message),
+               details);
+
+       qApp->restoreOverrideCursor();
+
+       if (long_op)
+               theApp()->startLongOperation();
 }
 
+void error(docstring const & title0, docstring const & message, bool backtrace)
+{
+#ifdef EXPORT_in_THREAD
+       InGuiThread<void>().call(&doError,
+#else
+       doError(
+#endif
+                               title0, message, backtrace);
+}
 
-void information(docstring const & title0, docstring const & message)
+void doInformation(docstring const & title0, docstring const & message)
 {
        if (!use_gui || lyxerr.debugging())
-               lyxerr << title0 << '\n'
+               lyxerr << toPlainText(title0) << '\n'
                       << "----------------------------------------\n"
-                      << message << endl;
+                      << toPlainText(message) << endl;
 
        if (!use_gui)
                return;
 
        docstring const title = bformat(_("LyX: %1$s"), title0);
-       QMessageBox::information(qApp->focusWidget(),
-                                toqstr(title),
-                                toqstr(formatted(message)));
+
+       if (theApp() == 0) {
+               noAppDialog(toqstr(title), toqstr(message), QMessageBox::Information);
+               return;
+       }
+
+       /// Long operation in progress prevents user from Ok-ing the error dialog
+       bool long_op = theApp()->longOperationStarted();
+       if (long_op)
+               theApp()->stopLongOperation();
+
+       // Don't use a hourglass cursor while displaying the alert
+       qApp->setOverrideCursor(Qt::ArrowCursor);
+
+       ProgressInterface::instance()->information(
+               toqstr(title),
+               toqstr(message));
+
+       qApp->restoreOverrideCursor();
+
+       if (long_op)
+               theApp()->startLongOperation();
 }
 
+void information(docstring const & title0, docstring const & message)
+{
+#ifdef EXPORT_in_THREAD
+       InGuiThread<void>().call(&doInformation,
+#else
+       doInformation(
+#endif
+                               title0, message);
+}
 
-bool askForText(docstring & response, docstring const & msg,
+bool doAskForText(docstring & response, docstring const & msg,
        docstring const & dflt)
 {
        if (!use_gui || lyxerr.debugging()) {
                lyxerr << "----------------------------------------\n"
-                      << msg << '\n'
+                      << toPlainText(msg) << '\n'
                       << "Assuming answer is " << dflt << '\n'
                       << "----------------------------------------" << endl;
                if (!use_gui) {
@@ -228,6 +314,11 @@ bool askForText(docstring & response, docstring const & msg,
 
        docstring const title = bformat(_("LyX: %1$s"), msg);
 
+       /// Long operation in progress prevents user from Ok-ing the error dialog
+       bool long_op = theApp()->longOperationStarted();
+       if (long_op)
+               theApp()->stopLongOperation();
+
        bool ok;
        QString text = QInputDialog::getText(qApp->focusWidget(),
                toqstr(title),
@@ -235,7 +326,10 @@ bool askForText(docstring & response, docstring const & msg,
                QLineEdit::Normal,
                toqstr(dflt), &ok);
 
-       if (ok && !text.isEmpty()) {
+       if (long_op)
+               theApp()->startLongOperation();
+
+       if (ok) {
                response = qstring_to_ucs4(text);
                return true;
        }
@@ -243,6 +337,16 @@ bool askForText(docstring & response, docstring const & msg,
        return false;
 }
 
+bool askForText(docstring & response, docstring const & msg,
+       docstring const & dflt)
+{
+#ifdef EXPORT_in_THREAD
+       return InGuiThread<bool>().call(&doAskForText,
+#else
+       return doAskForText(
+#endif
+                               response, msg, dflt);
+}
 
 } // namespace Alert
 } // namespace frontend