src/gui/dialogs/qerrormessage.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qerrormessage.h"
       
    43 
       
    44 #ifndef QT_NO_ERRORMESSAGE
       
    45 
       
    46 #include "qapplication.h"
       
    47 #include "qcheckbox.h"
       
    48 #include "qlabel.h"
       
    49 #include "qlayout.h"
       
    50 #include "qmessagebox.h"
       
    51 #include "qpushbutton.h"
       
    52 #include "qstringlist.h"
       
    53 #include "qtextedit.h"
       
    54 #include "qdialog_p.h"
       
    55 #include "qpixmap.h"
       
    56 #include "qmetaobject.h"
       
    57 #include "qthread.h"
       
    58 #include "qqueue.h"
       
    59 #include "qset.h"
       
    60 
       
    61 #include <stdio.h>
       
    62 #include <stdlib.h>
       
    63 
       
    64 #ifdef Q_WS_WINCE
       
    65 extern bool qt_wince_is_mobile();    //defined in qguifunctions_wince.cpp
       
    66 extern bool qt_wince_is_high_dpi();  //defined in qguifunctions_wince.cpp
       
    67 
       
    68 #include "qguifunctions_wince.h"
       
    69 #endif
       
    70 
       
    71 #if defined(QT_SOFTKEYS_ENABLED)
       
    72 #include <qaction.h>
       
    73 #ifdef Q_WS_S60
       
    74 #include "private/qt_s60_p.h"
       
    75 #endif
       
    76 #endif
       
    77 
       
    78 QT_BEGIN_NAMESPACE
       
    79 
       
    80 class QErrorMessagePrivate : public QDialogPrivate
       
    81 {
       
    82     Q_DECLARE_PUBLIC(QErrorMessage)
       
    83 public:
       
    84     QPushButton * ok;
       
    85     QCheckBox * again;
       
    86     QTextEdit * errors;
       
    87     QLabel * icon;
       
    88 #ifdef QT_SOFTKEYS_ENABLED
       
    89     QAction *okAction;
       
    90 #endif
       
    91     QQueue<QPair<QString, QString> > pending;
       
    92     QSet<QString> doNotShow;
       
    93     QSet<QString> doNotShowType;
       
    94     QString currentMessage;
       
    95     QString currentType;
       
    96 
       
    97     bool nextPending();
       
    98     void retranslateStrings();
       
    99 };
       
   100 
       
   101 class QErrorMessageTextView : public QTextEdit
       
   102 {
       
   103 public:
       
   104     QErrorMessageTextView(QWidget *parent)
       
   105         : QTextEdit(parent) { setReadOnly(true); }
       
   106 
       
   107     virtual QSize minimumSizeHint() const;
       
   108     virtual QSize sizeHint() const;
       
   109 };
       
   110 
       
   111 QSize QErrorMessageTextView::minimumSizeHint() const
       
   112 {
       
   113 #ifdef Q_WS_WINCE
       
   114     if (qt_wince_is_mobile())
       
   115          if (qt_wince_is_high_dpi())
       
   116             return QSize(200, 200);
       
   117          else
       
   118              return QSize(100, 100);
       
   119     else
       
   120       return QSize(70, 70);
       
   121 #else
       
   122     return QSize(50, 50);
       
   123 #endif
       
   124 }
       
   125 
       
   126 QSize QErrorMessageTextView::sizeHint() const
       
   127 {
       
   128 #ifdef Q_WS_WINCE
       
   129     if (qt_wince_is_mobile())
       
   130          if (qt_wince_is_high_dpi())
       
   131             return QSize(400, 200);
       
   132          else
       
   133              return QSize(320, 120);
       
   134     else
       
   135       return QSize(300, 100);
       
   136 #else
       
   137 
       
   138 #ifdef Q_WS_S60
       
   139     const int smallerDimension = qMin(S60->screenHeightInPixels, S60->screenWidthInPixels);
       
   140     // In S60 layout data, error messages seem to be one third of the screen height (in portrait) minus two.
       
   141     return QSize(smallerDimension, smallerDimension/3-2);
       
   142 #else
       
   143     return QSize(250, 75);
       
   144 #endif //Q_WS_S60
       
   145 #endif //Q_WS_WINCE
       
   146 }
       
   147 
       
   148 /*!
       
   149     \class QErrorMessage
       
   150 
       
   151     \brief The QErrorMessage class provides an error message display dialog.
       
   152 
       
   153     \ingroup standard-dialog
       
   154 
       
   155     An error message widget consists of a text label and a checkbox. The
       
   156     checkbox lets the user control whether the same error message will be
       
   157     displayed again in the future, typically displaying the text,
       
   158     "Show this message again" translated into the appropriate local
       
   159     language.
       
   160 
       
   161     For production applications, the class can be used to display messages which
       
   162     the user only needs to see once. To use QErrorMessage like this, you create
       
   163     the dialog in the usual way, and show it by calling the showMessage() slot or
       
   164     connecting signals to it.
       
   165 
       
   166     The static qtHandler() function installs a message handler
       
   167     using qInstallMsgHandler() and creates a QErrorMessage that displays
       
   168     qDebug(), qWarning() and qFatal() messages. This is most useful in
       
   169     environments where no console is available to display warnings and
       
   170     error messages.
       
   171 
       
   172     In both cases QErrorMessage will queue pending messages and display
       
   173     them in order, with each new message being shown as soon as the user
       
   174     has accepted the previous message. Once the user has specified that a
       
   175     message is not to be shown again it is automatically skipped, and the
       
   176     dialog will show the next appropriate message in the queue.
       
   177 
       
   178     The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
       
   179     how to use QErrorMessage as well as other built-in Qt dialogs.
       
   180 
       
   181     \img qerrormessage.png
       
   182 
       
   183     \sa QMessageBox, QStatusBar::showMessage(), {Standard Dialogs Example}
       
   184 */
       
   185 
       
   186 static QErrorMessage * qtMessageHandler = 0;
       
   187 
       
   188 static void deleteStaticcQErrorMessage() // post-routine
       
   189 {
       
   190     if (qtMessageHandler) {
       
   191         delete qtMessageHandler;
       
   192         qtMessageHandler = 0;
       
   193     }
       
   194 }
       
   195 
       
   196 static bool metFatal = false;
       
   197 
       
   198 static void jump(QtMsgType t, const char * m)
       
   199 {
       
   200     if (!qtMessageHandler)
       
   201         return;
       
   202 
       
   203     QString rich;
       
   204 
       
   205     switch (t) {
       
   206     case QtDebugMsg:
       
   207     default:
       
   208         rich = QErrorMessage::tr("Debug Message:");
       
   209         break;
       
   210     case QtWarningMsg:
       
   211         rich = QErrorMessage::tr("Warning:");
       
   212         break;
       
   213     case QtFatalMsg:
       
   214         rich = QErrorMessage::tr("Fatal Error:");
       
   215     }
       
   216     rich = QString::fromLatin1("<p><b>%1</b></p>").arg(rich);
       
   217     rich += Qt::convertFromPlainText(QLatin1String(m), Qt::WhiteSpaceNormal);
       
   218 
       
   219     // ### work around text engine quirk
       
   220     if (rich.endsWith(QLatin1String("</p>")))
       
   221         rich.chop(4);
       
   222 
       
   223     if (!metFatal) {
       
   224         if (QThread::currentThread() == qApp->thread()) {
       
   225             qtMessageHandler->showMessage(rich);
       
   226         } else {
       
   227             QMetaObject::invokeMethod(qtMessageHandler,
       
   228                                       "showMessage",
       
   229                                       Qt::QueuedConnection,
       
   230                                       Q_ARG(QString, rich));
       
   231         }
       
   232         metFatal = (t == QtFatalMsg);
       
   233     }
       
   234 }
       
   235 
       
   236 
       
   237 /*!
       
   238     Constructs and installs an error handler window with the given \a
       
   239     parent.
       
   240 */
       
   241 
       
   242 QErrorMessage::QErrorMessage(QWidget * parent)
       
   243     : QDialog(*new QErrorMessagePrivate, parent)
       
   244 {
       
   245     Q_D(QErrorMessage);
       
   246     QGridLayout * grid = new QGridLayout(this);
       
   247     d->icon = new QLabel(this);
       
   248 #ifndef QT_NO_MESSAGEBOX
       
   249     d->icon->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
       
   250     d->icon->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
       
   251 #endif
       
   252     grid->addWidget(d->icon, 0, 0, Qt::AlignTop);
       
   253     d->errors = new QErrorMessageTextView(this);
       
   254     grid->addWidget(d->errors, 0, 1);
       
   255     d->again = new QCheckBox(this);
       
   256     d->again->setChecked(true);
       
   257     grid->addWidget(d->again, 1, 1, Qt::AlignTop);
       
   258     d->ok = new QPushButton(this);
       
   259 #ifdef QT_SOFTKEYS_ENABLED
       
   260     d->okAction = new QAction(d->ok);
       
   261     d->okAction->setSoftKeyRole(QAction::PositiveSoftKey);
       
   262     connect(d->okAction, SIGNAL(triggered()), this, SLOT(accept()));
       
   263     addAction(d->okAction);
       
   264 #endif
       
   265 
       
   266 
       
   267 #if defined(Q_WS_WINCE) || defined(Q_WS_S60)
       
   268     d->ok->setFixedSize(0,0);
       
   269 #endif
       
   270     connect(d->ok, SIGNAL(clicked()), this, SLOT(accept()));
       
   271     d->ok->setFocus();
       
   272     grid->addWidget(d->ok, 2, 0, 1, 2, Qt::AlignCenter);
       
   273     grid->setColumnStretch(1, 42);
       
   274     grid->setRowStretch(0, 42);
       
   275     d->retranslateStrings();
       
   276 }
       
   277 
       
   278 
       
   279 /*!
       
   280     Destroys the error message dialog.
       
   281 */
       
   282 
       
   283 QErrorMessage::~QErrorMessage()
       
   284 {
       
   285     if (this == qtMessageHandler) {
       
   286         qtMessageHandler = 0;
       
   287         QtMsgHandler tmp = qInstallMsgHandler(0);
       
   288         // in case someone else has later stuck in another...
       
   289         if (tmp != jump)
       
   290             qInstallMsgHandler(tmp);
       
   291     }
       
   292 }
       
   293 
       
   294 
       
   295 /*! \reimp */
       
   296 
       
   297 void QErrorMessage::done(int a)
       
   298 {
       
   299     Q_D(QErrorMessage);
       
   300     if (!d->again->isChecked() && !d->currentMessage.isEmpty() && d->currentType.isEmpty()) {
       
   301         d->doNotShow.insert(d->currentMessage);
       
   302     }
       
   303     if (!d->again->isChecked() && !d->currentType.isEmpty()) {
       
   304         d->doNotShowType.insert(d->currentType);
       
   305     }
       
   306     d->currentMessage.clear();
       
   307     d->currentType.clear();
       
   308     if (!d->nextPending()) {
       
   309         QDialog::done(a);
       
   310         if (this == qtMessageHandler && metFatal)
       
   311             exit(1);
       
   312     }
       
   313 }
       
   314 
       
   315 
       
   316 /*!
       
   317     Returns a pointer to a QErrorMessage object that outputs the
       
   318     default Qt messages. This function creates such an object, if there
       
   319     isn't one already.
       
   320 */
       
   321 
       
   322 QErrorMessage * QErrorMessage::qtHandler()
       
   323 {
       
   324     if (!qtMessageHandler) {
       
   325         qtMessageHandler = new QErrorMessage(0);
       
   326         qAddPostRoutine(deleteStaticcQErrorMessage); // clean up
       
   327         qtMessageHandler->setWindowTitle(QApplication::applicationName());
       
   328         qInstallMsgHandler(jump);
       
   329     }
       
   330     return qtMessageHandler;
       
   331 }
       
   332 
       
   333 
       
   334 /*! \internal */
       
   335 
       
   336 bool QErrorMessagePrivate::nextPending()
       
   337 {
       
   338     while (!pending.isEmpty()) {
       
   339         QPair<QString,QString> pendingMessage = pending.dequeue();
       
   340         QString message = pendingMessage.first;
       
   341         QString type = pendingMessage.second;
       
   342         if (!message.isEmpty() && ((type.isEmpty() && !doNotShow.contains(message)) || (!type.isEmpty() && !doNotShowType.contains(type)))) {
       
   343 #ifndef QT_NO_TEXTHTMLPARSER
       
   344             errors->setHtml(message);
       
   345 #else
       
   346             errors->setPlainText(message);
       
   347 #endif
       
   348             currentMessage = message;
       
   349             currentType = type;
       
   350             return true;
       
   351         }
       
   352     }
       
   353     return false;
       
   354 }
       
   355 
       
   356 
       
   357 /*!
       
   358     Shows the given message, \a message, and returns immediately. If the user
       
   359     has requested for the message not to be shown again, this function does
       
   360     nothing.
       
   361 
       
   362     Normally, the message is displayed immediately. However, if there are
       
   363     pending messages, it will be queued to be displayed later.
       
   364 */
       
   365 
       
   366 void QErrorMessage::showMessage(const QString &message)
       
   367 {
       
   368     Q_D(QErrorMessage);
       
   369     if (d->doNotShow.contains(message))
       
   370         return;
       
   371     d->pending.enqueue(qMakePair(message,QString()));
       
   372     if (!isVisible() && d->nextPending())
       
   373         show();
       
   374 }
       
   375 
       
   376 /*!
       
   377     \since 4.5
       
   378     \overload
       
   379 
       
   380     Shows the given message, \a message, and returns immediately. If the user
       
   381     has requested for messages of type, \a type, not to be shown again, this
       
   382     function does nothing.
       
   383 
       
   384     Normally, the message is displayed immediately. However, if there are
       
   385     pending messages, it will be queued to be displayed later.
       
   386 
       
   387     \sa showMessage()
       
   388 */
       
   389 
       
   390 void QErrorMessage::showMessage(const QString &message, const QString &type)
       
   391 {
       
   392     Q_D(QErrorMessage);
       
   393     if (d->doNotShow.contains(message) && d->doNotShowType.contains(type))
       
   394         return;
       
   395      d->pending.push_back(qMakePair(message,type));
       
   396     if (!isVisible() && d->nextPending())
       
   397         show();
       
   398 }
       
   399 
       
   400 /*!
       
   401     \reimp
       
   402 */
       
   403 void QErrorMessage::changeEvent(QEvent *e)
       
   404 {
       
   405     Q_D(QErrorMessage);
       
   406     if (e->type() == QEvent::LanguageChange) {
       
   407         d->retranslateStrings();
       
   408     }
       
   409     QDialog::changeEvent(e);
       
   410 }
       
   411 
       
   412 void QErrorMessagePrivate::retranslateStrings()
       
   413 {
       
   414     again->setText(QErrorMessage::tr("&Show this message again"));
       
   415     ok->setText(QErrorMessage::tr("&OK"));
       
   416 #ifdef QT_SOFTKEYS_ENABLED
       
   417     okAction->setText(ok->text());
       
   418 #endif
       
   419 }
       
   420 
       
   421 /*!
       
   422     \fn void QErrorMessage::message(const QString & message)
       
   423 
       
   424     Use showMessage(\a message) instead.
       
   425 */
       
   426 
       
   427 QT_END_NAMESPACE
       
   428 
       
   429 #endif // QT_NO_ERRORMESSAGE