source: trunk/src/gui/dialogs/qerrormessage.cpp@ 780

Last change on this file since 780 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 12.1 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
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
65extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp
66extern 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
78QT_BEGIN_NAMESPACE
79
80class QErrorMessagePrivate : public QDialogPrivate
81{
82 Q_DECLARE_PUBLIC(QErrorMessage)
83public:
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
101class QErrorMessageTextView : public QTextEdit
102{
103public:
104 QErrorMessageTextView(QWidget *parent)
105 : QTextEdit(parent) { setReadOnly(true); }
106
107 virtual QSize minimumSizeHint() const;
108 virtual QSize sizeHint() const;
109};
110
111QSize 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
126QSize 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
186static QErrorMessage * qtMessageHandler = 0;
187
188static void deleteStaticcQErrorMessage() // post-routine
189{
190 if (qtMessageHandler) {
191 delete qtMessageHandler;
192 qtMessageHandler = 0;
193 }
194}
195
196static bool metFatal = false;
197
198static 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
242QErrorMessage::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
283QErrorMessage::~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
297void 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
322QErrorMessage * 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
336bool 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
366void 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
390void 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*/
403void 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
412void 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
427QT_END_NAMESPACE
428
429#endif // QT_NO_ERRORMESSAGE
Note: See TracBrowser for help on using the repository browser.