src/gui/dialogs/qerrormessage.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/dialogs/qerrormessage.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,429 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qerrormessage.h"
+
+#ifndef QT_NO_ERRORMESSAGE
+
+#include "qapplication.h"
+#include "qcheckbox.h"
+#include "qlabel.h"
+#include "qlayout.h"
+#include "qmessagebox.h"
+#include "qpushbutton.h"
+#include "qstringlist.h"
+#include "qtextedit.h"
+#include "qdialog_p.h"
+#include "qpixmap.h"
+#include "qmetaobject.h"
+#include "qthread.h"
+#include "qqueue.h"
+#include "qset.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef Q_WS_WINCE
+extern bool qt_wince_is_mobile();    //defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_high_dpi();  //defined in qguifunctions_wince.cpp
+
+#include "qguifunctions_wince.h"
+#endif
+
+#if defined(QT_SOFTKEYS_ENABLED)
+#include <qaction.h>
+#ifdef Q_WS_S60
+#include "private/qt_s60_p.h"
+#endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QErrorMessagePrivate : public QDialogPrivate
+{
+    Q_DECLARE_PUBLIC(QErrorMessage)
+public:
+    QPushButton * ok;
+    QCheckBox * again;
+    QTextEdit * errors;
+    QLabel * icon;
+#ifdef QT_SOFTKEYS_ENABLED
+    QAction *okAction;
+#endif
+    QQueue<QPair<QString, QString> > pending;
+    QSet<QString> doNotShow;
+    QSet<QString> doNotShowType;
+    QString currentMessage;
+    QString currentType;
+
+    bool nextPending();
+    void retranslateStrings();
+};
+
+class QErrorMessageTextView : public QTextEdit
+{
+public:
+    QErrorMessageTextView(QWidget *parent)
+        : QTextEdit(parent) { setReadOnly(true); }
+
+    virtual QSize minimumSizeHint() const;
+    virtual QSize sizeHint() const;
+};
+
+QSize QErrorMessageTextView::minimumSizeHint() const
+{
+#ifdef Q_WS_WINCE
+    if (qt_wince_is_mobile())
+         if (qt_wince_is_high_dpi())
+            return QSize(200, 200);
+         else
+             return QSize(100, 100);
+    else
+      return QSize(70, 70);
+#else
+    return QSize(50, 50);
+#endif
+}
+
+QSize QErrorMessageTextView::sizeHint() const
+{
+#ifdef Q_WS_WINCE
+    if (qt_wince_is_mobile())
+         if (qt_wince_is_high_dpi())
+            return QSize(400, 200);
+         else
+             return QSize(320, 120);
+    else
+      return QSize(300, 100);
+#else
+
+#ifdef Q_WS_S60
+    const int smallerDimension = qMin(S60->screenHeightInPixels, S60->screenWidthInPixels);
+    // In S60 layout data, error messages seem to be one third of the screen height (in portrait) minus two.
+    return QSize(smallerDimension, smallerDimension/3-2);
+#else
+    return QSize(250, 75);
+#endif //Q_WS_S60
+#endif //Q_WS_WINCE
+}
+
+/*!
+    \class QErrorMessage
+
+    \brief The QErrorMessage class provides an error message display dialog.
+
+    \ingroup standard-dialog
+
+    An error message widget consists of a text label and a checkbox. The
+    checkbox lets the user control whether the same error message will be
+    displayed again in the future, typically displaying the text,
+    "Show this message again" translated into the appropriate local
+    language.
+
+    For production applications, the class can be used to display messages which
+    the user only needs to see once. To use QErrorMessage like this, you create
+    the dialog in the usual way, and show it by calling the showMessage() slot or
+    connecting signals to it.
+
+    The static qtHandler() function installs a message handler
+    using qInstallMsgHandler() and creates a QErrorMessage that displays
+    qDebug(), qWarning() and qFatal() messages. This is most useful in
+    environments where no console is available to display warnings and
+    error messages.
+
+    In both cases QErrorMessage will queue pending messages and display
+    them in order, with each new message being shown as soon as the user
+    has accepted the previous message. Once the user has specified that a
+    message is not to be shown again it is automatically skipped, and the
+    dialog will show the next appropriate message in the queue.
+
+    The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
+    how to use QErrorMessage as well as other built-in Qt dialogs.
+
+    \img qerrormessage.png
+
+    \sa QMessageBox, QStatusBar::showMessage(), {Standard Dialogs Example}
+*/
+
+static QErrorMessage * qtMessageHandler = 0;
+
+static void deleteStaticcQErrorMessage() // post-routine
+{
+    if (qtMessageHandler) {
+        delete qtMessageHandler;
+        qtMessageHandler = 0;
+    }
+}
+
+static bool metFatal = false;
+
+static void jump(QtMsgType t, const char * m)
+{
+    if (!qtMessageHandler)
+        return;
+
+    QString rich;
+
+    switch (t) {
+    case QtDebugMsg:
+    default:
+        rich = QErrorMessage::tr("Debug Message:");
+        break;
+    case QtWarningMsg:
+        rich = QErrorMessage::tr("Warning:");
+        break;
+    case QtFatalMsg:
+        rich = QErrorMessage::tr("Fatal Error:");
+    }
+    rich = QString::fromLatin1("<p><b>%1</b></p>").arg(rich);
+    rich += Qt::convertFromPlainText(QLatin1String(m), Qt::WhiteSpaceNormal);
+
+    // ### work around text engine quirk
+    if (rich.endsWith(QLatin1String("</p>")))
+        rich.chop(4);
+
+    if (!metFatal) {
+        if (QThread::currentThread() == qApp->thread()) {
+            qtMessageHandler->showMessage(rich);
+        } else {
+            QMetaObject::invokeMethod(qtMessageHandler,
+                                      "showMessage",
+                                      Qt::QueuedConnection,
+                                      Q_ARG(QString, rich));
+        }
+        metFatal = (t == QtFatalMsg);
+    }
+}
+
+
+/*!
+    Constructs and installs an error handler window with the given \a
+    parent.
+*/
+
+QErrorMessage::QErrorMessage(QWidget * parent)
+    : QDialog(*new QErrorMessagePrivate, parent)
+{
+    Q_D(QErrorMessage);
+    QGridLayout * grid = new QGridLayout(this);
+    d->icon = new QLabel(this);
+#ifndef QT_NO_MESSAGEBOX
+    d->icon->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
+    d->icon->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
+#endif
+    grid->addWidget(d->icon, 0, 0, Qt::AlignTop);
+    d->errors = new QErrorMessageTextView(this);
+    grid->addWidget(d->errors, 0, 1);
+    d->again = new QCheckBox(this);
+    d->again->setChecked(true);
+    grid->addWidget(d->again, 1, 1, Qt::AlignTop);
+    d->ok = new QPushButton(this);
+#ifdef QT_SOFTKEYS_ENABLED
+    d->okAction = new QAction(d->ok);
+    d->okAction->setSoftKeyRole(QAction::PositiveSoftKey);
+    connect(d->okAction, SIGNAL(triggered()), this, SLOT(accept()));
+    addAction(d->okAction);
+#endif
+
+
+#if defined(Q_WS_WINCE) || defined(Q_WS_S60)
+    d->ok->setFixedSize(0,0);
+#endif
+    connect(d->ok, SIGNAL(clicked()), this, SLOT(accept()));
+    d->ok->setFocus();
+    grid->addWidget(d->ok, 2, 0, 1, 2, Qt::AlignCenter);
+    grid->setColumnStretch(1, 42);
+    grid->setRowStretch(0, 42);
+    d->retranslateStrings();
+}
+
+
+/*!
+    Destroys the error message dialog.
+*/
+
+QErrorMessage::~QErrorMessage()
+{
+    if (this == qtMessageHandler) {
+        qtMessageHandler = 0;
+        QtMsgHandler tmp = qInstallMsgHandler(0);
+        // in case someone else has later stuck in another...
+        if (tmp != jump)
+            qInstallMsgHandler(tmp);
+    }
+}
+
+
+/*! \reimp */
+
+void QErrorMessage::done(int a)
+{
+    Q_D(QErrorMessage);
+    if (!d->again->isChecked() && !d->currentMessage.isEmpty() && d->currentType.isEmpty()) {
+        d->doNotShow.insert(d->currentMessage);
+    }
+    if (!d->again->isChecked() && !d->currentType.isEmpty()) {
+        d->doNotShowType.insert(d->currentType);
+    }
+    d->currentMessage.clear();
+    d->currentType.clear();
+    if (!d->nextPending()) {
+        QDialog::done(a);
+        if (this == qtMessageHandler && metFatal)
+            exit(1);
+    }
+}
+
+
+/*!
+    Returns a pointer to a QErrorMessage object that outputs the
+    default Qt messages. This function creates such an object, if there
+    isn't one already.
+*/
+
+QErrorMessage * QErrorMessage::qtHandler()
+{
+    if (!qtMessageHandler) {
+        qtMessageHandler = new QErrorMessage(0);
+        qAddPostRoutine(deleteStaticcQErrorMessage); // clean up
+        qtMessageHandler->setWindowTitle(QApplication::applicationName());
+        qInstallMsgHandler(jump);
+    }
+    return qtMessageHandler;
+}
+
+
+/*! \internal */
+
+bool QErrorMessagePrivate::nextPending()
+{
+    while (!pending.isEmpty()) {
+        QPair<QString,QString> pendingMessage = pending.dequeue();
+        QString message = pendingMessage.first;
+        QString type = pendingMessage.second;
+        if (!message.isEmpty() && ((type.isEmpty() && !doNotShow.contains(message)) || (!type.isEmpty() && !doNotShowType.contains(type)))) {
+#ifndef QT_NO_TEXTHTMLPARSER
+            errors->setHtml(message);
+#else
+            errors->setPlainText(message);
+#endif
+            currentMessage = message;
+            currentType = type;
+            return true;
+        }
+    }
+    return false;
+}
+
+
+/*!
+    Shows the given message, \a message, and returns immediately. If the user
+    has requested for the message not to be shown again, this function does
+    nothing.
+
+    Normally, the message is displayed immediately. However, if there are
+    pending messages, it will be queued to be displayed later.
+*/
+
+void QErrorMessage::showMessage(const QString &message)
+{
+    Q_D(QErrorMessage);
+    if (d->doNotShow.contains(message))
+        return;
+    d->pending.enqueue(qMakePair(message,QString()));
+    if (!isVisible() && d->nextPending())
+        show();
+}
+
+/*!
+    \since 4.5
+    \overload
+
+    Shows the given message, \a message, and returns immediately. If the user
+    has requested for messages of type, \a type, not to be shown again, this
+    function does nothing.
+
+    Normally, the message is displayed immediately. However, if there are
+    pending messages, it will be queued to be displayed later.
+
+    \sa showMessage()
+*/
+
+void QErrorMessage::showMessage(const QString &message, const QString &type)
+{
+    Q_D(QErrorMessage);
+    if (d->doNotShow.contains(message) && d->doNotShowType.contains(type))
+        return;
+     d->pending.push_back(qMakePair(message,type));
+    if (!isVisible() && d->nextPending())
+        show();
+}
+
+/*!
+    \reimp
+*/
+void QErrorMessage::changeEvent(QEvent *e)
+{
+    Q_D(QErrorMessage);
+    if (e->type() == QEvent::LanguageChange) {
+        d->retranslateStrings();
+    }
+    QDialog::changeEvent(e);
+}
+
+void QErrorMessagePrivate::retranslateStrings()
+{
+    again->setText(QErrorMessage::tr("&Show this message again"));
+    ok->setText(QErrorMessage::tr("&OK"));
+#ifdef QT_SOFTKEYS_ENABLED
+    okAction->setText(ok->text());
+#endif
+}
+
+/*!
+    \fn void QErrorMessage::message(const QString & message)
+
+    Use showMessage(\a message) instead.
+*/
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_ERRORMESSAGE