summaryrefslogtreecommitdiffstats
path: root/src/widgets/dialogs
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/dialogs')
-rw-r--r--src/widgets/dialogs/dialogs.pri82
-rw-r--r--src/widgets/dialogs/images/qtlogo-64.pngbin0 -> 2991 bytes
-rw-r--r--src/widgets/dialogs/qcolordialog.cpp2115
-rw-r--r--src/widgets/dialogs/qcolordialog.h150
-rw-r--r--src/widgets/dialogs/qcolordialog_mac.mm505
-rw-r--r--src/widgets/dialogs/qcolordialog_p.h142
-rw-r--r--src/widgets/dialogs/qcolordialog_symbian.cpp107
-rw-r--r--src/widgets/dialogs/qdialog.cpp1272
-rw-r--r--src/widgets/dialogs/qdialog.h140
-rw-r--r--src/widgets/dialogs/qdialog_p.h113
-rw-r--r--src/widgets/dialogs/qdialogsbinarycompat_win.cpp137
-rw-r--r--src/widgets/dialogs/qerrormessage.cpp429
-rw-r--r--src/widgets/dialogs/qerrormessage.h88
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp3555
-rw-r--r--src/widgets/dialogs/qfiledialog.h331
-rw-r--r--src/widgets/dialogs/qfiledialog.ui356
-rw-r--r--src/widgets/dialogs/qfiledialog_embedded.ui340
-rw-r--r--src/widgets/dialogs/qfiledialog_mac.mm1157
-rw-r--r--src/widgets/dialogs/qfiledialog_p.h427
-rw-r--r--src/widgets/dialogs/qfiledialog_symbian.cpp199
-rw-r--r--src/widgets/dialogs/qfiledialog_win.cpp839
-rw-r--r--src/widgets/dialogs/qfiledialog_win_p.h243
-rw-r--r--src/widgets/dialogs/qfileinfogatherer.cpp355
-rw-r--r--src/widgets/dialogs/qfileinfogatherer_p.h207
-rw-r--r--src/widgets/dialogs/qfilesystemmodel.cpp2029
-rw-r--r--src/widgets/dialogs/qfilesystemmodel.h180
-rw-r--r--src/widgets/dialogs/qfilesystemmodel_p.h337
-rw-r--r--src/widgets/dialogs/qfontdialog.cpp1077
-rw-r--r--src/widgets/dialogs/qfontdialog.h147
-rw-r--r--src/widgets/dialogs/qfontdialog_mac.mm699
-rw-r--r--src/widgets/dialogs/qfontdialog_p.h166
-rw-r--r--src/widgets/dialogs/qfscompleter_p.h82
-rw-r--r--src/widgets/dialogs/qinputdialog.cpp1489
-rw-r--r--src/widgets/dialogs/qinputdialog.h256
-rw-r--r--src/widgets/dialogs/qmessagebox.cpp2753
-rw-r--r--src/widgets/dialogs/qmessagebox.h365
-rw-r--r--src/widgets/dialogs/qmessagebox.qrc5
-rw-r--r--src/widgets/dialogs/qnspanelproxy_mac.mm228
-rw-r--r--src/widgets/dialogs/qprogressdialog.cpp907
-rw-r--r--src/widgets/dialogs/qprogressdialog.h145
-rw-r--r--src/widgets/dialogs/qsidebar.cpp509
-rw-r--r--src/widgets/dialogs/qsidebar_p.h158
-rw-r--r--src/widgets/dialogs/qwizard.cpp3928
-rw-r--r--src/widgets/dialogs/qwizard.h268
-rw-r--r--src/widgets/dialogs/qwizard_win.cpp773
-rw-r--r--src/widgets/dialogs/qwizard_win_p.h158
46 files changed, 29948 insertions, 0 deletions
diff --git a/src/widgets/dialogs/dialogs.pri b/src/widgets/dialogs/dialogs.pri
new file mode 100644
index 0000000000..41d81b8afc
--- /dev/null
+++ b/src/widgets/dialogs/dialogs.pri
@@ -0,0 +1,82 @@
+# Qt dialogs module
+
+HEADERS += \
+ dialogs/qcolordialog.h \
+ dialogs/qcolordialog_p.h \
+ dialogs/qfscompleter_p.h \
+ dialogs/qdialog.h \
+ dialogs/qdialog_p.h \
+ dialogs/qerrormessage.h \
+ dialogs/qfiledialog.h \
+ dialogs/qfiledialog_p.h \
+ dialogs/qfontdialog.h \
+ dialogs/qfontdialog_p.h \
+ dialogs/qinputdialog.h \
+ dialogs/qmessagebox.h \
+ dialogs/qprogressdialog.h \
+ dialogs/qsidebar_p.h \
+ dialogs/qfilesystemmodel.h \
+ dialogs/qfilesystemmodel_p.h \
+ dialogs/qfileinfogatherer_p.h \
+ dialogs/qwizard.h
+
+!qpa:mac {
+ OBJECTIVE_SOURCES += dialogs/qfiledialog_mac.mm \
+ dialogs/qfontdialog_mac.mm \
+ dialogs/qnspanelproxy_mac.mm
+
+# Compile qcolordialog_mac.mm with exception support, disregarding the -no-exceptions
+# configure option. (qcolordialog_mac needs to catch exceptions thrown by cocoa)
+ EXCEPTION_SOURCES = dialogs/qcolordialog_mac.mm
+ exceptions_compiler.commands = $$QMAKE_CXX -c
+ exceptions_compiler.commands += $(CXXFLAGS) $(INCPATH) ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT}
+ exceptions_compiler.commands += -fexceptions
+ exceptions_compiler.dependency_type = TYPE_C
+ exceptions_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ exceptions_compiler.input = EXCEPTION_SOURCES
+ exceptions_compiler.variable_out = OBJECTS
+ exceptions_compiler.name = compiling[exceptopns] ${QMAKE_FILE_IN}
+ silent:exceptions_compiler.commands = @echo compiling[exceptopns] ${QMAKE_FILE_IN} && $$exceptions_compiler.commands
+ QMAKE_EXTRA_COMPILERS += exceptions_compiler
+}
+
+win32 {
+ qpa:DEFINES += QT_NO_PRINTDIALOG
+
+ HEADERS += dialogs/qwizard_win_p.h \
+ dialogs/qfiledialog_win_p.h
+ SOURCES += dialogs/qdialogsbinarycompat_win.cpp \
+ dialogs/qfiledialog_win.cpp \
+ dialogs/qwizard_win.cpp
+
+ !win32-borland:!wince*: LIBS += -lshell32 # the filedialog needs this library
+}
+
+wince*|symbian: FORMS += dialogs/qfiledialog_embedded.ui
+else: FORMS += dialogs/qfiledialog.ui
+
+INCLUDEPATH += $$PWD
+SOURCES += \
+ dialogs/qcolordialog.cpp \
+ dialogs/qdialog.cpp \
+ dialogs/qerrormessage.cpp \
+ dialogs/qfiledialog.cpp \
+ dialogs/qfontdialog.cpp \
+ dialogs/qinputdialog.cpp \
+ dialogs/qmessagebox.cpp \
+ dialogs/qprogressdialog.cpp \
+ dialogs/qsidebar.cpp \
+ dialogs/qfilesystemmodel.cpp \
+ dialogs/qfileinfogatherer.cpp \
+ dialogs/qwizard.cpp \
+
+symbian:contains(QT_CONFIG, s60) {
+ LIBS += -lCommonDialogs
+ SOURCES += dialogs/qfiledialog_symbian.cpp \
+ dialogs/qcolordialog_symbian.cpp
+}
+
+RESOURCES += dialogs/qmessagebox.qrc
+
+# Compensate for lack of platform defines in Symbian3
+symbian: DEFINES += SYMBIAN_VERSION_$$upper($$replace(SYMBIAN_VERSION,\\.,_))
diff --git a/src/widgets/dialogs/images/qtlogo-64.png b/src/widgets/dialogs/images/qtlogo-64.png
new file mode 100644
index 0000000000..4f68e162de
--- /dev/null
+++ b/src/widgets/dialogs/images/qtlogo-64.png
Binary files differ
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
new file mode 100644
index 0000000000..b26e911899
--- /dev/null
+++ b/src/widgets/dialogs/qcolordialog.cpp
@@ -0,0 +1,2115 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcolordialog_p.h"
+
+#ifndef QT_NO_COLORDIALOG
+
+#include "qapplication.h"
+#include "qdesktopwidget.h"
+#include "qdrawutil.h"
+#include "qevent.h"
+#include "qimage.h"
+#include "qdrag.h"
+#include "qlabel.h"
+#include "qlayout.h"
+#include "qlineedit.h"
+#include "qmenu.h"
+#include "qpainter.h"
+#include "qpixmap.h"
+#include "qpushbutton.h"
+#include "qsettings.h"
+#include "qstyle.h"
+#include "qstyleoption.h"
+#include "qvalidator.h"
+#include "qmime.h"
+#include "qspinbox.h"
+#include "qdialogbuttonbox.h"
+#include "private/qguiplatformplugin_p.h"
+
+#ifdef Q_WS_S60
+#include "private/qt_s60_p.h"
+#endif
+
+#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5)
+# define QT_SMALL_COLORDIALOG
+#endif
+
+QT_BEGIN_NAMESPACE
+
+//////////// QWellArray BEGIN
+
+struct QWellArrayData;
+
+class QWellArray : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(int selectedColumn READ selectedColumn)
+ Q_PROPERTY(int selectedRow READ selectedRow)
+
+public:
+ QWellArray(int rows, int cols, QWidget* parent=0);
+ ~QWellArray() {}
+ QString cellContent(int row, int col) const;
+
+ int selectedColumn() const { return selCol; }
+ int selectedRow() const { return selRow; }
+
+ virtual void setCurrent(int row, int col);
+ virtual void setSelected(int row, int col);
+
+ QSize sizeHint() const;
+
+ virtual void setCellBrush(int row, int col, const QBrush &);
+ QBrush cellBrush(int row, int col);
+
+ inline int cellWidth() const
+ { return cellw; }
+
+ inline int cellHeight() const
+ { return cellh; }
+
+ inline int rowAt(int y) const
+ { return y / cellh; }
+
+ inline int columnAt(int x) const
+ { if (isRightToLeft()) return ncols - (x / cellw) - 1; return x / cellw; }
+
+ inline int rowY(int row) const
+ { return cellh * row; }
+
+ inline int columnX(int column) const
+ { if (isRightToLeft()) return cellw * (ncols - column - 1); return cellw * column; }
+
+ inline int numRows() const
+ { return nrows; }
+
+ inline int numCols() const
+ {return ncols; }
+
+ inline QRect cellRect() const
+ { return QRect(0, 0, cellw, cellh); }
+
+ inline QSize gridSize() const
+ { return QSize(ncols * cellw, nrows * cellh); }
+
+ QRect cellGeometry(int row, int column)
+ {
+ QRect r;
+ if (row >= 0 && row < nrows && column >= 0 && column < ncols)
+ r.setRect(columnX(column), rowY(row), cellw, cellh);
+ return r;
+ }
+
+ inline void updateCell(int row, int column) { update(cellGeometry(row, column)); }
+
+signals:
+ void selected(int row, int col);
+
+protected:
+ virtual void paintCell(QPainter *, int row, int col, const QRect&);
+ virtual void paintCellContents(QPainter *, int row, int col, const QRect&);
+
+ void mousePressEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
+ void keyPressEvent(QKeyEvent*);
+ void focusInEvent(QFocusEvent*);
+ void focusOutEvent(QFocusEvent*);
+ void paintEvent(QPaintEvent *);
+
+private:
+ Q_DISABLE_COPY(QWellArray)
+
+ int nrows;
+ int ncols;
+ int cellw;
+ int cellh;
+ int curRow;
+ int curCol;
+ int selRow;
+ int selCol;
+ QWellArrayData *d;
+};
+
+void QWellArray::paintEvent(QPaintEvent *e)
+{
+ QRect r = e->rect();
+ int cx = r.x();
+ int cy = r.y();
+ int ch = r.height();
+ int cw = r.width();
+ int colfirst = columnAt(cx);
+ int collast = columnAt(cx + cw);
+ int rowfirst = rowAt(cy);
+ int rowlast = rowAt(cy + ch);
+
+ if (isRightToLeft()) {
+ int t = colfirst;
+ colfirst = collast;
+ collast = t;
+ }
+
+ QPainter painter(this);
+ QPainter *p = &painter;
+ QRect rect(0, 0, cellWidth(), cellHeight());
+
+
+ if (collast < 0 || collast >= ncols)
+ collast = ncols-1;
+ if (rowlast < 0 || rowlast >= nrows)
+ rowlast = nrows-1;
+
+ // Go through the rows
+ for (int r = rowfirst; r <= rowlast; ++r) {
+ // get row position and height
+ int rowp = rowY(r);
+
+ // Go through the columns in the row r
+ // if we know from where to where, go through [colfirst, collast],
+ // else go through all of them
+ for (int c = colfirst; c <= collast; ++c) {
+ // get position and width of column c
+ int colp = columnX(c);
+ // Translate painter and draw the cell
+ rect.translate(colp, rowp);
+ paintCell(p, r, c, rect);
+ rect.translate(-colp, -rowp);
+ }
+ }
+}
+
+struct QWellArrayData {
+ QBrush *brush;
+};
+
+QWellArray::QWellArray(int rows, int cols, QWidget *parent)
+ : QWidget(parent)
+ ,nrows(rows), ncols(cols)
+{
+ d = 0;
+ setFocusPolicy(Qt::StrongFocus);
+ cellw = 28;
+ cellh = 24;
+ curCol = 0;
+ curRow = 0;
+ selCol = -1;
+ selRow = -1;
+}
+
+QSize QWellArray::sizeHint() const
+{
+ ensurePolished();
+ return gridSize().boundedTo(QSize(640, 480));
+}
+
+
+void QWellArray::paintCell(QPainter* p, int row, int col, const QRect &rect)
+{
+ int b = 3; //margin
+
+ const QPalette & g = palette();
+ QStyleOptionFrame opt;
+ int dfw = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
+ opt.lineWidth = dfw;
+ opt.midLineWidth = 1;
+ opt.rect = rect.adjusted(b, b, -b, -b);
+ opt.palette = g;
+ opt.state = QStyle::State_Enabled | QStyle::State_Sunken;
+ style()->drawPrimitive(QStyle::PE_Frame, &opt, p, this);
+ b += dfw;
+
+ if ((row == curRow) && (col == curCol)) {
+ if (hasFocus()) {
+ QStyleOptionFocusRect opt;
+ opt.palette = g;
+ opt.rect = rect;
+ opt.state = QStyle::State_None | QStyle::State_KeyboardFocusChange;
+ style()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p, this);
+ }
+ }
+ paintCellContents(p, row, col, opt.rect.adjusted(dfw, dfw, -dfw, -dfw));
+}
+
+/*!
+ Reimplement this function to change the contents of the well array.
+ */
+void QWellArray::paintCellContents(QPainter *p, int row, int col, const QRect &r)
+{
+ if (d) {
+ p->fillRect(r, d->brush[row*numCols()+col]);
+ } else {
+ p->fillRect(r, Qt::white);
+ p->setPen(Qt::black);
+ p->drawLine(r.topLeft(), r.bottomRight());
+ p->drawLine(r.topRight(), r.bottomLeft());
+ }
+}
+
+void QWellArray::mousePressEvent(QMouseEvent *e)
+{
+ // The current cell marker is set to the cell the mouse is pressed in
+ QPoint pos = e->pos();
+ setCurrent(rowAt(pos.y()), columnAt(pos.x()));
+}
+
+void QWellArray::mouseReleaseEvent(QMouseEvent * /* event */)
+{
+ // The current cell marker is set to the cell the mouse is clicked in
+ setSelected(curRow, curCol);
+}
+
+
+/*
+ Sets the cell currently having the focus. This is not necessarily
+ the same as the currently selected cell.
+*/
+
+void QWellArray::setCurrent(int row, int col)
+{
+ if ((curRow == row) && (curCol == col))
+ return;
+
+ if (row < 0 || col < 0)
+ row = col = -1;
+
+ int oldRow = curRow;
+ int oldCol = curCol;
+
+ curRow = row;
+ curCol = col;
+
+ updateCell(oldRow, oldCol);
+ updateCell(curRow, curCol);
+}
+
+/*
+ Sets the currently selected cell to \a row, \a column. If \a row or
+ \a column are less than zero, the current cell is unselected.
+
+ Does not set the position of the focus indicator.
+*/
+void QWellArray::setSelected(int row, int col)
+{
+ int oldRow = selRow;
+ int oldCol = selCol;
+
+ if (row < 0 || col < 0)
+ row = col = -1;
+
+ selCol = col;
+ selRow = row;
+
+ updateCell(oldRow, oldCol);
+ updateCell(selRow, selCol);
+ if (row >= 0)
+ emit selected(row, col);
+
+#ifndef QT_NO_MENU
+ if (isVisible() && qobject_cast<QMenu*>(parentWidget()))
+ parentWidget()->close();
+#endif
+}
+
+void QWellArray::focusInEvent(QFocusEvent*)
+{
+ updateCell(curRow, curCol);
+}
+
+void QWellArray::setCellBrush(int row, int col, const QBrush &b)
+{
+ if (!d) {
+ d = new QWellArrayData;
+ int i = numRows()*numCols();
+ d->brush = new QBrush[i];
+ }
+ if (row >= 0 && row < numRows() && col >= 0 && col < numCols())
+ d->brush[row*numCols()+col] = b;
+}
+
+/*
+ Returns the brush set for the cell at \a row, \a column. If no brush is
+ set, Qt::NoBrush is returned.
+*/
+
+QBrush QWellArray::cellBrush(int row, int col)
+{
+ if (d && row >= 0 && row < numRows() && col >= 0 && col < numCols())
+ return d->brush[row*numCols()+col];
+ return Qt::NoBrush;
+}
+
+
+
+/*!\reimp
+*/
+
+void QWellArray::focusOutEvent(QFocusEvent*)
+{
+ updateCell(curRow, curCol);
+}
+
+/*\reimp
+*/
+void QWellArray::keyPressEvent(QKeyEvent* e)
+{
+ switch(e->key()) { // Look at the key code
+ case Qt::Key_Left: // If 'left arrow'-key,
+ if(curCol > 0) // and cr't not in leftmost col
+ setCurrent(curRow, curCol - 1); // set cr't to next left column
+ break;
+ case Qt::Key_Right: // Correspondingly...
+ if(curCol < numCols()-1)
+ setCurrent(curRow, curCol + 1);
+ break;
+ case Qt::Key_Up:
+ if(curRow > 0)
+ setCurrent(curRow - 1, curCol);
+ break;
+ case Qt::Key_Down:
+ if(curRow < numRows()-1)
+ setCurrent(curRow + 1, curCol);
+ break;
+#if 0
+ // bad idea that shouldn't have been implemented; very counterintuitive
+ case Qt::Key_Return:
+ case Qt::Key_Enter:
+ /*
+ ignore the key, so that the dialog get it, but still select
+ the current row/col
+ */
+ e->ignore();
+ // fallthrough intended
+#endif
+ case Qt::Key_Space:
+ setSelected(curRow, curCol);
+ break;
+ default: // If not an interesting key,
+ e->ignore(); // we don't accept the event
+ return;
+ }
+
+}
+
+//////////// QWellArray END
+
+static bool initrgb = false;
+static QRgb stdrgb[6*8];
+static QRgb cusrgb[2*8];
+static bool customSet = false;
+
+
+static void initRGB()
+{
+ if (initrgb)
+ return;
+ initrgb = true;
+ int i = 0;
+ for (int g = 0; g < 4; g++)
+ for (int r = 0; r < 4; r++)
+ for (int b = 0; b < 3; b++)
+ stdrgb[i++] = qRgb(r * 255 / 3, g * 255 / 3, b * 255 / 2);
+
+ for (i = 0; i < 2*8; i++)
+ cusrgb[i] = 0xffffffff;
+}
+
+/*!
+ Returns the number of custom colors supported by QColorDialog. All
+ color dialogs share the same custom colors.
+*/
+int QColorDialog::customCount()
+{
+ return 2 * 8;
+}
+
+/*!
+ \since 4.5
+
+ Returns the custom color at the given \a index as a QRgb value.
+*/
+QRgb QColorDialog::customColor(int index)
+{
+ if (uint(index) >= uint(customCount()))
+ return qRgb(255, 255, 255);
+ initRGB();
+ return cusrgb[index];
+}
+
+/*!
+ Sets the custom color at \a index to the QRgb \a color value.
+
+ \note This function does not apply to the Native Color Dialog on the Mac
+ OS X platform. If you still require this function, use the
+ QColorDialog::DontUseNativeDialog option.
+*/
+void QColorDialog::setCustomColor(int index, QRgb color)
+{
+ if (uint(index) >= uint(customCount()))
+ return;
+ initRGB();
+ customSet = true;
+ cusrgb[index] = color;
+}
+
+/*!
+ Sets the standard color at \a index to the QRgb \a color value.
+
+ \note This function does not apply to the Native Color Dialog on the Mac
+ OS X platform. If you still require this function, use the
+ QColorDialog::DontUseNativeDialog option.
+*/
+
+void QColorDialog::setStandardColor(int index, QRgb color)
+{
+ if (uint(index) >= uint(6 * 8))
+ return;
+ initRGB();
+ stdrgb[index] = color;
+}
+
+static inline void rgb2hsv(QRgb rgb, int &h, int &s, int &v)
+{
+ QColor c;
+ c.setRgb(rgb);
+ c.getHsv(&h, &s, &v);
+}
+
+class QColorWell : public QWellArray
+{
+public:
+ QColorWell(QWidget *parent, int r, int c, QRgb *vals)
+ :QWellArray(r, c, parent), values(vals), mousePressed(false), oldCurrent(-1, -1)
+ { setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); }
+
+protected:
+ void paintCellContents(QPainter *, int row, int col, const QRect&);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *e);
+ void dragLeaveEvent(QDragLeaveEvent *e);
+ void dragMoveEvent(QDragMoveEvent *e);
+ void dropEvent(QDropEvent *e);
+#endif
+
+private:
+ QRgb *values;
+ bool mousePressed;
+ QPoint pressPos;
+ QPoint oldCurrent;
+
+};
+
+void QColorWell::paintCellContents(QPainter *p, int row, int col, const QRect &r)
+{
+ int i = row + col*numRows();
+ p->fillRect(r, QColor(values[i]));
+}
+
+void QColorWell::mousePressEvent(QMouseEvent *e)
+{
+ oldCurrent = QPoint(selectedRow(), selectedColumn());
+ QWellArray::mousePressEvent(e);
+ mousePressed = true;
+ pressPos = e->pos();
+}
+
+void QColorWell::mouseMoveEvent(QMouseEvent *e)
+{
+ QWellArray::mouseMoveEvent(e);
+#ifndef QT_NO_DRAGANDDROP
+ if (!mousePressed)
+ return;
+ if ((pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
+ setCurrent(oldCurrent.x(), oldCurrent.y());
+ int i = rowAt(pressPos.y()) + columnAt(pressPos.x()) * numRows();
+ QColor col(values[i]);
+ QMimeData *mime = new QMimeData;
+ mime->setColorData(col);
+ QPixmap pix(cellWidth(), cellHeight());
+ pix.fill(col);
+ QPainter p(&pix);
+ p.drawRect(0, 0, pix.width() - 1, pix.height() - 1);
+ p.end();
+ QDrag *drg = new QDrag(this);
+ drg->setMimeData(mime);
+ drg->setPixmap(pix);
+ mousePressed = false;
+ drg->start();
+ }
+#endif
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QColorWell::dragEnterEvent(QDragEnterEvent *e)
+{
+ if (qvariant_cast<QColor>(e->mimeData()->colorData()).isValid())
+ e->accept();
+ else
+ e->ignore();
+}
+
+void QColorWell::dragLeaveEvent(QDragLeaveEvent *)
+{
+ if (hasFocus())
+ parentWidget()->setFocus();
+}
+
+void QColorWell::dragMoveEvent(QDragMoveEvent *e)
+{
+ if (qvariant_cast<QColor>(e->mimeData()->colorData()).isValid()) {
+ setCurrent(rowAt(e->pos().y()), columnAt(e->pos().x()));
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+
+void QColorWell::dropEvent(QDropEvent *e)
+{
+ QColor col = qvariant_cast<QColor>(e->mimeData()->colorData());
+ if (col.isValid()) {
+ int i = rowAt(e->pos().y()) + columnAt(e->pos().x()) * numRows();
+ values[i] = col.rgb();
+ update();
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+void QColorWell::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (!mousePressed)
+ return;
+ QWellArray::mouseReleaseEvent(e);
+ mousePressed = false;
+}
+
+class QColorPicker : public QFrame
+{
+ Q_OBJECT
+public:
+ QColorPicker(QWidget* parent);
+ ~QColorPicker();
+
+public slots:
+ void setCol(int h, int s);
+
+signals:
+ void newCol(int h, int s);
+
+protected:
+ QSize sizeHint() const;
+ void paintEvent(QPaintEvent*);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void resizeEvent(QResizeEvent *);
+
+private:
+ int hue;
+ int sat;
+
+ QPoint colPt();
+ int huePt(const QPoint &pt);
+ int satPt(const QPoint &pt);
+ void setCol(const QPoint &pt);
+
+ QPixmap pix;
+};
+
+static int pWidth = 220;
+static int pHeight = 200;
+
+class QColorLuminancePicker : public QWidget
+{
+ Q_OBJECT
+public:
+ QColorLuminancePicker(QWidget* parent=0);
+ ~QColorLuminancePicker();
+
+public slots:
+ void setCol(int h, int s, int v);
+ void setCol(int h, int s);
+
+signals:
+ void newHsv(int h, int s, int v);
+
+protected:
+ void paintEvent(QPaintEvent*);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+
+private:
+ enum { foff = 3, coff = 4 }; //frame and contents offset
+ int val;
+ int hue;
+ int sat;
+
+ int y2val(int y);
+ int val2y(int val);
+ void setVal(int v);
+
+ QPixmap *pix;
+};
+
+
+int QColorLuminancePicker::y2val(int y)
+{
+ int d = height() - 2*coff - 1;
+ return 255 - (y - coff)*255/d;
+}
+
+int QColorLuminancePicker::val2y(int v)
+{
+ int d = height() - 2*coff - 1;
+ return coff + (255-v)*d/255;
+}
+
+QColorLuminancePicker::QColorLuminancePicker(QWidget* parent)
+ :QWidget(parent)
+{
+ hue = 100; val = 100; sat = 100;
+ pix = 0;
+ // setAttribute(WA_NoErase, true);
+}
+
+QColorLuminancePicker::~QColorLuminancePicker()
+{
+ delete pix;
+}
+
+void QColorLuminancePicker::mouseMoveEvent(QMouseEvent *m)
+{
+ setVal(y2val(m->y()));
+}
+void QColorLuminancePicker::mousePressEvent(QMouseEvent *m)
+{
+ setVal(y2val(m->y()));
+}
+
+void QColorLuminancePicker::setVal(int v)
+{
+ if (val == v)
+ return;
+ val = qMax(0, qMin(v,255));
+ delete pix; pix=0;
+ repaint();
+ emit newHsv(hue, sat, val);
+}
+
+//receives from a hue,sat chooser and relays.
+void QColorLuminancePicker::setCol(int h, int s)
+{
+ setCol(h, s, val);
+ emit newHsv(h, s, val);
+}
+
+void QColorLuminancePicker::paintEvent(QPaintEvent *)
+{
+ int w = width() - 5;
+
+ QRect r(0, foff, w, height() - 2*foff);
+ int wi = r.width() - 2;
+ int hi = r.height() - 2;
+ if (!pix || pix->height() != hi || pix->width() != wi) {
+ delete pix;
+ QImage img(wi, hi, QImage::Format_RGB32);
+ int y;
+ uint *pixel = (uint *) img.scanLine(0);
+ for (y = 0; y < hi; y++) {
+ const uint *end = pixel + wi;
+ while (pixel < end) {
+ QColor c;
+ c.setHsv(hue, sat, y2val(y+coff));
+ *pixel = c.rgb();
+ ++pixel;
+ }
+ }
+ pix = new QPixmap(QPixmap::fromImage(img));
+ }
+ QPainter p(this);
+ p.drawPixmap(1, coff, *pix);
+ const QPalette &g = palette();
+ qDrawShadePanel(&p, r, g, true);
+ p.setPen(g.foreground().color());
+ p.setBrush(g.foreground());
+ QPolygon a;
+ int y = val2y(val);
+ a.setPoints(3, w, y, w+5, y+5, w+5, y-5);
+ p.eraseRect(w, 0, 5, height());
+ p.drawPolygon(a);
+}
+
+void QColorLuminancePicker::setCol(int h, int s , int v)
+{
+ val = v;
+ hue = h;
+ sat = s;
+ delete pix; pix=0;
+ repaint();
+}
+
+QPoint QColorPicker::colPt()
+{
+ QRect r = contentsRect();
+ return QPoint((360 - hue) * (r.width() - 1) / 360, (255 - sat) * (r.height() - 1) / 255);
+}
+
+int QColorPicker::huePt(const QPoint &pt)
+{
+ QRect r = contentsRect();
+ return 360 - pt.x() * 360 / (r.width() - 1);
+}
+
+int QColorPicker::satPt(const QPoint &pt)
+{
+ QRect r = contentsRect();
+ return 255 - pt.y() * 255 / (r.height() - 1);
+}
+
+void QColorPicker::setCol(const QPoint &pt)
+{
+ setCol(huePt(pt), satPt(pt));
+}
+
+QColorPicker::QColorPicker(QWidget* parent)
+ : QFrame(parent)
+{
+ hue = 0; sat = 0;
+ setCol(150, 255);
+
+ setAttribute(Qt::WA_NoSystemBackground);
+ setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
+}
+
+QColorPicker::~QColorPicker()
+{
+}
+
+QSize QColorPicker::sizeHint() const
+{
+ return QSize(pWidth + 2*frameWidth(), pHeight + 2*frameWidth());
+}
+
+void QColorPicker::setCol(int h, int s)
+{
+ int nhue = qMin(qMax(0,h), 359);
+ int nsat = qMin(qMax(0,s), 255);
+ if (nhue == hue && nsat == sat)
+ return;
+
+ QRect r(colPt(), QSize(20,20));
+ hue = nhue; sat = nsat;
+ r = r.united(QRect(colPt(), QSize(20,20)));
+ r.translate(contentsRect().x()-9, contentsRect().y()-9);
+ // update(r);
+ repaint(r);
+}
+
+void QColorPicker::mouseMoveEvent(QMouseEvent *m)
+{
+ QPoint p = m->pos() - contentsRect().topLeft();
+ setCol(p);
+ emit newCol(hue, sat);
+}
+
+void QColorPicker::mousePressEvent(QMouseEvent *m)
+{
+ QPoint p = m->pos() - contentsRect().topLeft();
+ setCol(p);
+ emit newCol(hue, sat);
+}
+
+void QColorPicker::paintEvent(QPaintEvent* )
+{
+ QPainter p(this);
+ drawFrame(&p);
+ QRect r = contentsRect();
+
+ p.drawPixmap(r.topLeft(), pix);
+ QPoint pt = colPt() + r.topLeft();
+ p.setPen(Qt::black);
+
+ p.fillRect(pt.x()-9, pt.y(), 20, 2, Qt::black);
+ p.fillRect(pt.x(), pt.y()-9, 2, 20, Qt::black);
+
+}
+
+void QColorPicker::resizeEvent(QResizeEvent *ev)
+{
+ QFrame::resizeEvent(ev);
+
+ int w = width() - frameWidth() * 2;
+ int h = height() - frameWidth() * 2;
+ QImage img(w, h, QImage::Format_RGB32);
+ int x, y;
+ uint *pixel = (uint *) img.scanLine(0);
+ for (y = 0; y < h; y++) {
+ const uint *end = pixel + w;
+ x = 0;
+ while (pixel < end) {
+ QPoint p(x, y);
+ QColor c;
+ c.setHsv(huePt(p), satPt(p), 200);
+ *pixel = c.rgb();
+ ++pixel;
+ ++x;
+ }
+ }
+ pix = QPixmap::fromImage(img);
+}
+
+
+class QColSpinBox : public QSpinBox
+{
+public:
+ QColSpinBox(QWidget *parent)
+ : QSpinBox(parent) { setRange(0, 255); }
+ void setValue(int i) {
+ bool block = signalsBlocked();
+ blockSignals(true);
+ QSpinBox::setValue(i);
+ blockSignals(block);
+ }
+};
+
+class QColorShowLabel;
+
+class QColorShower : public QWidget
+{
+ Q_OBJECT
+public:
+ QColorShower(QColorDialog *parent);
+
+ //things that don't emit signals
+ void setHsv(int h, int s, int v);
+
+ int currentAlpha() const
+ { return (colorDialog->options() & QColorDialog::ShowAlphaChannel) ? alphaEd->value() : 255; }
+ void setCurrentAlpha(int a) { alphaEd->setValue(a); rgbEd(); }
+ void showAlpha(bool b);
+ bool isAlphaVisible() const;
+
+ QRgb currentColor() const { return curCol; }
+ QColor currentQColor() const { return curQColor; }
+ void retranslateStrings();
+ void updateQColor();
+
+public slots:
+ void setRgb(QRgb rgb);
+
+signals:
+ void newCol(QRgb rgb);
+ void currentColorChanged(const QColor &color);
+
+private slots:
+ void rgbEd();
+ void hsvEd();
+private:
+ void showCurrentColor();
+ int hue, sat, val;
+ QRgb curCol;
+ QColor curQColor;
+ QLabel *lblHue;
+ QLabel *lblSat;
+ QLabel *lblVal;
+ QLabel *lblRed;
+ QLabel *lblGreen;
+ QLabel *lblBlue;
+ QColSpinBox *hEd;
+ QColSpinBox *sEd;
+ QColSpinBox *vEd;
+ QColSpinBox *rEd;
+ QColSpinBox *gEd;
+ QColSpinBox *bEd;
+ QColSpinBox *alphaEd;
+ QLabel *alphaLab;
+ QColorShowLabel *lab;
+ bool rgbOriginal;
+ QColorDialog *colorDialog;
+
+ friend class QColorDialog;
+ friend class QColorDialogPrivate;
+};
+
+class QColorShowLabel : public QFrame
+{
+ Q_OBJECT
+
+public:
+ QColorShowLabel(QWidget *parent) : QFrame(parent) {
+ setFrameStyle(QFrame::Panel|QFrame::Sunken);
+ setAcceptDrops(true);
+ mousePressed = false;
+ }
+ void setColor(QColor c) { col = c; }
+
+signals:
+ void colorDropped(QRgb);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *e);
+ void dragLeaveEvent(QDragLeaveEvent *e);
+ void dropEvent(QDropEvent *e);
+#endif
+
+private:
+ QColor col;
+ bool mousePressed;
+ QPoint pressPos;
+};
+
+void QColorShowLabel::paintEvent(QPaintEvent *e)
+{
+ QPainter p(this);
+ drawFrame(&p);
+ p.fillRect(contentsRect()&e->rect(), col);
+}
+
+void QColorShower::showAlpha(bool b)
+{
+ alphaLab->setVisible(b);
+ alphaEd->setVisible(b);
+}
+
+inline bool QColorShower::isAlphaVisible() const
+{
+ return alphaLab->isVisible();
+}
+
+void QColorShowLabel::mousePressEvent(QMouseEvent *e)
+{
+ mousePressed = true;
+ pressPos = e->pos();
+}
+
+void QColorShowLabel::mouseMoveEvent(QMouseEvent *e)
+{
+#ifdef QT_NO_DRAGANDDROP
+ Q_UNUSED(e);
+#else
+ if (!mousePressed)
+ return;
+ if ((pressPos - e->pos()).manhattanLength() > QApplication::startDragDistance()) {
+ QMimeData *mime = new QMimeData;
+ mime->setColorData(col);
+ QPixmap pix(30, 20);
+ pix.fill(col);
+ QPainter p(&pix);
+ p.drawRect(0, 0, pix.width() - 1, pix.height() - 1);
+ p.end();
+ QDrag *drg = new QDrag(this);
+ drg->setMimeData(mime);
+ drg->setPixmap(pix);
+ mousePressed = false;
+ drg->start();
+ }
+#endif
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QColorShowLabel::dragEnterEvent(QDragEnterEvent *e)
+{
+ if (qvariant_cast<QColor>(e->mimeData()->colorData()).isValid())
+ e->accept();
+ else
+ e->ignore();
+}
+
+void QColorShowLabel::dragLeaveEvent(QDragLeaveEvent *)
+{
+}
+
+void QColorShowLabel::dropEvent(QDropEvent *e)
+{
+ QColor color = qvariant_cast<QColor>(e->mimeData()->colorData());
+ if (color.isValid()) {
+ col = color;
+ repaint();
+ emit colorDropped(col.rgb());
+ e->accept();
+ } else {
+ e->ignore();
+ }
+}
+#endif // QT_NO_DRAGANDDROP
+
+void QColorShowLabel::mouseReleaseEvent(QMouseEvent *)
+{
+ if (!mousePressed)
+ return;
+ mousePressed = false;
+}
+
+QColorShower::QColorShower(QColorDialog *parent)
+ : QWidget(parent)
+{
+ colorDialog = parent;
+
+ curCol = qRgb(255, 255, 255);
+ curQColor = Qt::white;
+
+ QGridLayout *gl = new QGridLayout(this);
+ gl->setMargin(gl->spacing());
+ lab = new QColorShowLabel(this);
+
+#ifdef QT_SMALL_COLORDIALOG
+# ifdef Q_WS_S60
+ const bool nonTouchUI = !S60->hasTouchscreen;
+# elif defined Q_WS_MAEMO_5
+ const bool nonTouchUI = false;
+# endif
+#endif
+
+#ifndef Q_WS_WINCE
+#ifdef QT_SMALL_COLORDIALOG
+ lab->setMinimumHeight(60);
+#endif
+ lab->setMinimumWidth(60);
+#else
+ lab->setMinimumWidth(20);
+#endif
+
+// In S60, due to small screen and different screen layouts need to re-arrange the widgets.
+// For QVGA screens only the comboboxes and color label are visible.
+// For nHD screens only color and luminence pickers and color label are visible.
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(lab, 0, 0, -1, 1);
+#else
+ if (nonTouchUI)
+ gl->addWidget(lab, 0, 0, 1, -1);
+ else
+ gl->addWidget(lab, 0, 0, -1, 1);
+#endif
+ connect(lab, SIGNAL(colorDropped(QRgb)), this, SIGNAL(newCol(QRgb)));
+ connect(lab, SIGNAL(colorDropped(QRgb)), this, SLOT(setRgb(QRgb)));
+
+ hEd = new QColSpinBox(this);
+ hEd->setRange(0, 359);
+ lblHue = new QLabel(this);
+#ifndef QT_NO_SHORTCUT
+ lblHue->setBuddy(hEd);
+#endif
+ lblHue->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(lblHue, 0, 1);
+ gl->addWidget(hEd, 0, 2);
+#else
+ if (nonTouchUI) {
+ gl->addWidget(lblHue, 1, 0);
+ gl->addWidget(hEd, 2, 0);
+ } else {
+ lblHue->hide();
+ hEd->hide();
+ }
+#endif
+
+ sEd = new QColSpinBox(this);
+ lblSat = new QLabel(this);
+#ifndef QT_NO_SHORTCUT
+ lblSat->setBuddy(sEd);
+#endif
+ lblSat->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(lblSat, 1, 1);
+ gl->addWidget(sEd, 1, 2);
+#else
+ if (nonTouchUI) {
+ gl->addWidget(lblSat, 1, 1);
+ gl->addWidget(sEd, 2, 1);
+ } else {
+ lblSat->hide();
+ sEd->hide();
+ }
+#endif
+
+ vEd = new QColSpinBox(this);
+ lblVal = new QLabel(this);
+#ifndef QT_NO_SHORTCUT
+ lblVal->setBuddy(vEd);
+#endif
+ lblVal->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(lblVal, 2, 1);
+ gl->addWidget(vEd, 2, 2);
+#else
+ if (nonTouchUI) {
+ gl->addWidget(lblVal, 1, 2);
+ gl->addWidget(vEd, 2, 2);
+ } else {
+ lblVal->hide();
+ vEd->hide();
+ }
+#endif
+
+ rEd = new QColSpinBox(this);
+ lblRed = new QLabel(this);
+#ifndef QT_NO_SHORTCUT
+ lblRed->setBuddy(rEd);
+#endif
+ lblRed->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(lblRed, 0, 3);
+ gl->addWidget(rEd, 0, 4);
+#else
+ if (nonTouchUI) {
+ gl->addWidget(lblRed, 3, 0);
+ gl->addWidget(rEd, 4, 0);
+ } else {
+ lblRed->hide();
+ rEd->hide();
+ }
+#endif
+
+ gEd = new QColSpinBox(this);
+ lblGreen = new QLabel(this);
+#ifndef QT_NO_SHORTCUT
+ lblGreen->setBuddy(gEd);
+#endif
+ lblGreen->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(lblGreen, 1, 3);
+ gl->addWidget(gEd, 1, 4);
+#else
+ if (nonTouchUI) {
+ gl->addWidget(lblGreen, 3, 1);
+ gl->addWidget(gEd, 4, 1);
+ } else {
+ lblGreen->hide();
+ gEd->hide();
+ }
+#endif
+
+ bEd = new QColSpinBox(this);
+ lblBlue = new QLabel(this);
+#ifndef QT_NO_SHORTCUT
+ lblBlue->setBuddy(bEd);
+#endif
+ lblBlue->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(lblBlue, 2, 3);
+ gl->addWidget(bEd, 2, 4);
+#else
+ if (nonTouchUI) {
+ gl->addWidget(lblBlue, 3, 2);
+ gl->addWidget(bEd, 4, 2);
+ } else {
+ lblBlue->hide();
+ bEd->hide();
+ }
+#endif
+
+ alphaEd = new QColSpinBox(this);
+ alphaLab = new QLabel(this);
+#ifndef QT_NO_SHORTCUT
+ alphaLab->setBuddy(alphaEd);
+#endif
+ alphaLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
+#if !defined(QT_SMALL_COLORDIALOG)
+ gl->addWidget(alphaLab, 3, 1, 1, 3);
+ gl->addWidget(alphaEd, 3, 4);
+#else
+ if (nonTouchUI) {
+ gl->addWidget(alphaLab, 1, 3, 3, 1);
+ gl->addWidget(alphaEd, 4, 3);
+ } else {
+ alphaLab->hide();
+ alphaEd->hide();
+ }
+#endif
+ alphaEd->hide();
+ alphaLab->hide();
+
+ connect(hEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
+ connect(sEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
+ connect(vEd, SIGNAL(valueChanged(int)), this, SLOT(hsvEd()));
+
+ connect(rEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
+ connect(gEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
+ connect(bEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
+ connect(alphaEd, SIGNAL(valueChanged(int)), this, SLOT(rgbEd()));
+
+ retranslateStrings();
+}
+
+inline QRgb QColorDialogPrivate::currentColor() const { return cs->currentColor(); }
+inline int QColorDialogPrivate::currentAlpha() const { return cs->currentAlpha(); }
+inline void QColorDialogPrivate::setCurrentAlpha(int a) { cs->setCurrentAlpha(a); }
+inline void QColorDialogPrivate::showAlpha(bool b) { cs->showAlpha(b); }
+inline bool QColorDialogPrivate::isAlphaVisible() const { return cs->isAlphaVisible(); }
+
+QColor QColorDialogPrivate::currentQColor() const
+{
+ return cs->currentQColor();
+}
+
+void QColorShower::showCurrentColor()
+{
+ lab->setColor(currentColor());
+ lab->repaint();
+}
+
+void QColorShower::rgbEd()
+{
+ rgbOriginal = true;
+ curCol = qRgba(rEd->value(), gEd->value(), bEd->value(), currentAlpha());
+
+ rgb2hsv(currentColor(), hue, sat, val);
+
+ hEd->setValue(hue);
+ sEd->setValue(sat);
+ vEd->setValue(val);
+
+ showCurrentColor();
+ emit newCol(currentColor());
+ updateQColor();
+}
+
+void QColorShower::hsvEd()
+{
+ rgbOriginal = false;
+ hue = hEd->value();
+ sat = sEd->value();
+ val = vEd->value();
+
+ QColor c;
+ c.setHsv(hue, sat, val);
+ curCol = c.rgb();
+
+ rEd->setValue(qRed(currentColor()));
+ gEd->setValue(qGreen(currentColor()));
+ bEd->setValue(qBlue(currentColor()));
+
+ showCurrentColor();
+ emit newCol(currentColor());
+ updateQColor();
+}
+
+void QColorShower::setRgb(QRgb rgb)
+{
+ rgbOriginal = true;
+ curCol = rgb;
+
+ rgb2hsv(currentColor(), hue, sat, val);
+
+ hEd->setValue(hue);
+ sEd->setValue(sat);
+ vEd->setValue(val);
+
+ rEd->setValue(qRed(currentColor()));
+ gEd->setValue(qGreen(currentColor()));
+ bEd->setValue(qBlue(currentColor()));
+
+ showCurrentColor();
+ updateQColor();
+}
+
+void QColorShower::setHsv(int h, int s, int v)
+{
+ if (h < -1 || (uint)s > 255 || (uint)v > 255)
+ return;
+
+ rgbOriginal = false;
+ hue = h; val = v; sat = s;
+ QColor c;
+ c.setHsv(hue, sat, val);
+ curCol = c.rgb();
+
+ hEd->setValue(hue);
+ sEd->setValue(sat);
+ vEd->setValue(val);
+
+ rEd->setValue(qRed(currentColor()));
+ gEd->setValue(qGreen(currentColor()));
+ bEd->setValue(qBlue(currentColor()));
+
+ showCurrentColor();
+ updateQColor();
+}
+
+void QColorShower::retranslateStrings()
+{
+ lblHue->setText(QColorDialog::tr("Hu&e:"));
+ lblSat->setText(QColorDialog::tr("&Sat:"));
+ lblVal->setText(QColorDialog::tr("&Val:"));
+ lblRed->setText(QColorDialog::tr("&Red:"));
+ lblGreen->setText(QColorDialog::tr("&Green:"));
+ lblBlue->setText(QColorDialog::tr("Bl&ue:"));
+ alphaLab->setText(QColorDialog::tr("A&lpha channel:"));
+}
+
+void QColorShower::updateQColor()
+{
+ QColor oldQColor(curQColor);
+ curQColor.setRgba(qRgba(qRed(curCol), qGreen(curCol), qBlue(curCol), currentAlpha()));
+ if (curQColor != oldQColor)
+ emit currentColorChanged(curQColor);
+}
+
+//sets all widgets to display h,s,v
+void QColorDialogPrivate::_q_newHsv(int h, int s, int v)
+{
+ cs->setHsv(h, s, v);
+ cp->setCol(h, s);
+ lp->setCol(h, s, v);
+}
+
+//sets all widgets to display rgb
+void QColorDialogPrivate::setCurrentColor(QRgb rgb)
+{
+ cs->setRgb(rgb);
+ _q_newColorTypedIn(rgb);
+}
+
+// hack; doesn't keep curCol in sync, so use with care
+void QColorDialogPrivate::setCurrentQColor(const QColor &color)
+{
+ Q_Q(QColorDialog);
+ if (cs->curQColor != color) {
+ cs->curQColor = color;
+ emit q->currentColorChanged(color);
+ }
+}
+
+bool QColorDialogPrivate::selectColor(const QColor &col)
+{
+ QRgb color = col.rgb();
+ int i = 0, j = 0;
+ // Check standard colors
+ if (standard) {
+ for (i = 0; i < 6; i++) {
+ for (j = 0; j < 8; j++) {
+ if (color == stdrgb[i + j*6]) {
+ _q_newStandard(i, j);
+ standard->setCurrent(i, j);
+ standard->setSelected(i, j);
+ standard->setFocus();
+ return true;
+ }
+ }
+ }
+ }
+ // Check custom colors
+ if (custom) {
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 8; j++) {
+ if (color == cusrgb[i + j*2]) {
+ _q_newCustom(i, j);
+ custom->setCurrent(i, j);
+ custom->setSelected(i, j);
+ custom->setFocus();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+//sets all widgets except cs to display rgb
+void QColorDialogPrivate::_q_newColorTypedIn(QRgb rgb)
+{
+ int h, s, v;
+ rgb2hsv(rgb, h, s, v);
+ cp->setCol(h, s);
+ lp->setCol(h, s, v);
+}
+
+void QColorDialogPrivate::_q_newCustom(int r, int c)
+{
+ int i = r+2*c;
+ setCurrentColor(cusrgb[i]);
+ nextCust = i;
+ if (standard)
+ standard->setSelected(-1,-1);
+}
+
+void QColorDialogPrivate::_q_newStandard(int r, int c)
+{
+ setCurrentColor(stdrgb[r+c*6]);
+ if (custom)
+ custom->setSelected(-1,-1);
+}
+
+void QColorDialogPrivate::init(const QColor &initial)
+{
+ Q_Q(QColorDialog);
+
+ q->setSizeGripEnabled(false);
+ q->setWindowTitle(QColorDialog::tr("Select Color"));
+
+ nativeDialogInUse = false;
+
+ nextCust = 0;
+ QVBoxLayout *mainLay = new QVBoxLayout(q);
+ // there's nothing in this dialog that benefits from sizing up
+ mainLay->setSizeConstraint(QLayout::SetFixedSize);
+
+ QHBoxLayout *topLay = new QHBoxLayout();
+ mainLay->addLayout(topLay);
+
+ leftLay = 0;
+
+#if defined(Q_WS_WINCE) || defined(QT_SMALL_COLORDIALOG)
+ smallDisplay = true;
+ const int lumSpace = 20;
+#else
+ // small displays (e.g. PDAs) cannot fit the full color dialog,
+ // so just use the color picker.
+ smallDisplay = (QApplication::desktop()->width() < 480 || QApplication::desktop()->height() < 350);
+ const int lumSpace = topLay->spacing() / 2;
+#endif
+
+ if (!smallDisplay) {
+ leftLay = new QVBoxLayout;
+ topLay->addLayout(leftLay);
+ }
+
+ initRGB();
+
+#ifndef QT_NO_SETTINGS
+ if (!customSet) {
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ for (int i = 0; i < 2*8; ++i) {
+ QVariant v = settings.value(QLatin1String("Qt/customColors/") + QString::number(i));
+ if (v.isValid()) {
+ QRgb rgb = v.toUInt();
+ cusrgb[i] = rgb;
+ }
+ }
+ }
+#endif
+
+#if defined(QT_SMALL_COLORDIALOG)
+# if defined(Q_WS_S60)
+ const bool nonTouchUI = !S60->hasTouchscreen;
+# elif defined(Q_WS_MAEMO_5)
+ const bool nonTouchUI = false;
+# endif
+#endif
+
+ if (!smallDisplay) {
+ standard = new QColorWell(q, 6, 8, stdrgb);
+ lblBasicColors = new QLabel(q);
+#ifndef QT_NO_SHORTCUT
+ lblBasicColors->setBuddy(standard);
+#endif
+ q->connect(standard, SIGNAL(selected(int,int)), SLOT(_q_newStandard(int,int)));
+ leftLay->addWidget(lblBasicColors);
+ leftLay->addWidget(standard);
+
+#if !defined(Q_WS_WINCE)
+ leftLay->addStretch();
+#endif
+
+ custom = new QColorWell(q, 2, 8, cusrgb);
+ custom->setAcceptDrops(true);
+
+ q->connect(custom, SIGNAL(selected(int,int)), SLOT(_q_newCustom(int,int)));
+ lblCustomColors = new QLabel(q);
+#ifndef QT_NO_SHORTCUT
+ lblCustomColors->setBuddy(custom);
+#endif
+ leftLay->addWidget(lblCustomColors);
+ leftLay->addWidget(custom);
+
+ addCusBt = new QPushButton(q);
+ QObject::connect(addCusBt, SIGNAL(clicked()), q, SLOT(_q_addCustom()));
+ leftLay->addWidget(addCusBt);
+ } else {
+ // better color picker size for small displays
+#if defined(QT_SMALL_COLORDIALOG)
+ QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
+ pWidth = pHeight = qMin(screenSize.width(), screenSize.height());
+ pHeight -= 20;
+ if(screenSize.height() > screenSize.width())
+ pWidth -= 20;
+#else
+ pWidth = 150;
+ pHeight = 100;
+#endif
+ custom = 0;
+ standard = 0;
+ }
+
+ QVBoxLayout *rightLay = new QVBoxLayout;
+ topLay->addLayout(rightLay);
+
+ QHBoxLayout *pickLay = new QHBoxLayout;
+ rightLay->addLayout(pickLay);
+
+ QVBoxLayout *cLay = new QVBoxLayout;
+ pickLay->addLayout(cLay);
+ cp = new QColorPicker(q);
+
+ cp->setFrameStyle(QFrame::Panel + QFrame::Sunken);
+
+#if defined(QT_SMALL_COLORDIALOG)
+ if (!nonTouchUI) {
+ pickLay->addWidget(cp);
+ cLay->addSpacing(lumSpace);
+ } else {
+ cp->hide();
+ }
+#else
+ cLay->addSpacing(lumSpace);
+ cLay->addWidget(cp);
+#endif
+ cLay->addSpacing(lumSpace);
+
+ lp = new QColorLuminancePicker(q);
+#if defined(QT_SMALL_COLORDIALOG)
+ QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
+ const int minDimension = qMin(screenSize.height(), screenSize.width());
+ //set picker to be finger-usable
+ int pickerWidth = !nonTouchUI ? minDimension/9 : minDimension/12;
+ lp->setFixedWidth(pickerWidth);
+ if (!nonTouchUI)
+ pickLay->addWidget(lp);
+ else
+ lp->hide();
+#else
+ lp->setFixedWidth(20);
+ pickLay->addWidget(lp);
+#endif
+
+ QObject::connect(cp, SIGNAL(newCol(int,int)), lp, SLOT(setCol(int,int)));
+ QObject::connect(lp, SIGNAL(newHsv(int,int,int)), q, SLOT(_q_newHsv(int,int,int)));
+
+ rightLay->addStretch();
+
+ cs = new QColorShower(q);
+ QObject::connect(cs, SIGNAL(newCol(QRgb)), q, SLOT(_q_newColorTypedIn(QRgb)));
+ QObject::connect(cs, SIGNAL(currentColorChanged(QColor)),
+ q, SIGNAL(currentColorChanged(QColor)));
+#if defined(QT_SMALL_COLORDIALOG)
+ if (!nonTouchUI)
+ pWidth -= cp->size().width();
+ topLay->addWidget(cs);
+#else
+ rightLay->addWidget(cs);
+#endif
+
+ buttons = new QDialogButtonBox(q);
+ mainLay->addWidget(buttons);
+
+ ok = buttons->addButton(QDialogButtonBox::Ok);
+ QObject::connect(ok, SIGNAL(clicked()), q, SLOT(accept()));
+ ok->setDefault(true);
+ cancel = buttons->addButton(QDialogButtonBox::Cancel);
+ QObject::connect(cancel, SIGNAL(clicked()), q, SLOT(reject()));
+
+ retranslateStrings();
+
+#ifdef Q_WS_MAC
+ delegate = 0;
+#endif
+
+ q->setCurrentColor(initial);
+}
+
+void QColorDialogPrivate::_q_addCustom()
+{
+ cusrgb[nextCust] = cs->currentColor();
+ if (custom)
+ custom->update();
+ nextCust = (nextCust+1) % 16;
+}
+
+void QColorDialogPrivate::retranslateStrings()
+{
+ if (!smallDisplay) {
+ lblBasicColors->setText(QColorDialog::tr("&Basic colors"));
+ lblCustomColors->setText(QColorDialog::tr("&Custom colors"));
+ addCusBt->setText(QColorDialog::tr("&Add to Custom Colors"));
+ }
+
+ cs->retranslateStrings();
+}
+
+static const Qt::WindowFlags DefaultWindowFlags =
+ Qt::Dialog | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint
+ | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
+
+/*!
+ \class QColorDialog
+ \brief The QColorDialog class provides a dialog widget for specifying colors.
+
+ \ingroup standard-dialogs
+
+ The color dialog's function is to allow users to choose colors.
+ For example, you might use this in a drawing program to allow the
+ user to set the brush color.
+
+ The static functions provide modal color dialogs.
+ \omit
+ If you require a modeless dialog, use the QColorDialog constructor.
+ \endomit
+
+ The static getColor() function shows the dialog, and allows the user to
+ specify a color. This function can also be used to let users choose a
+ color with a level of transparency: pass the ShowAlphaChannel option as
+ an additional argument.
+
+ The user can store customCount() different custom colors. The
+ custom colors are shared by all color dialogs, and remembered
+ during the execution of the program. Use setCustomColor() to set
+ the custom colors, and use customColor() to get them.
+
+ Additional widgets that allow users to pick colors are available
+ as \l{Qt Solutions}.
+
+ The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
+ how to use QColorDialog as well as other built-in Qt dialogs.
+
+ \image plastique-colordialog.png A color dialog in the Plastique widget style.
+
+ \sa QColor, QFileDialog, QPrintDialog, QFontDialog, {Standard Dialogs Example}
+*/
+
+/*!
+ \since 4.5
+
+ Constructs a color dialog with the given \a parent.
+*/
+QColorDialog::QColorDialog(QWidget *parent)
+ : QDialog(*new QColorDialogPrivate, parent, DefaultWindowFlags)
+{
+ Q_D(QColorDialog);
+ d->init(Qt::white);
+}
+
+/*!
+ \since 4.5
+
+ Constructs a color dialog with the given \a parent and specified
+ \a initial color.
+*/
+QColorDialog::QColorDialog(const QColor &initial, QWidget *parent)
+ : QDialog(*new QColorDialogPrivate, parent, DefaultWindowFlags)
+{
+ Q_D(QColorDialog);
+ d->init(initial);
+}
+
+/*!
+ \property QColorDialog::currentColor
+ \brief the currently selected color in the dialog
+*/
+
+void QColorDialog::setCurrentColor(const QColor &color)
+{
+ Q_D(QColorDialog);
+ d->setCurrentColor(color.rgb());
+ d->selectColor(color);
+ d->setCurrentAlpha(color.alpha());
+
+#ifdef Q_WS_MAC
+ d->setCurrentQColor(color);
+ d->setCocoaPanelColor(color);
+#endif
+ if (d->nativeDialogInUse)
+ qt_guiPlatformPlugin()->colorDialogSetCurrentColor(this, color);
+}
+
+QColor QColorDialog::currentColor() const
+{
+ Q_D(const QColorDialog);
+ return d->currentQColor();
+}
+
+
+/*!
+ Returns the color that the user selected by clicking the \gui{OK}
+ or equivalent button.
+
+ \note This color is not always the same as the color held by the
+ \l currentColor property since the user can choose different colors
+ before finally selecting the one to use.
+*/
+QColor QColorDialog::selectedColor() const
+{
+ Q_D(const QColorDialog);
+ return d->selectedQColor;
+}
+
+/*!
+ Sets the given \a option to be enabled if \a on is true;
+ otherwise, clears the given \a option.
+
+ \sa options, testOption()
+*/
+void QColorDialog::setOption(ColorDialogOption option, bool on)
+{
+ Q_D(QColorDialog);
+ if (!(d->opts & option) != !on)
+ setOptions(d->opts ^ option);
+}
+
+/*!
+ \since 4.5
+
+ Returns true if the given \a option is enabled; otherwise, returns
+ false.
+
+ \sa options, setOption()
+*/
+bool QColorDialog::testOption(ColorDialogOption option) const
+{
+ Q_D(const QColorDialog);
+ return (d->opts & option) != 0;
+}
+
+/*!
+ \property QColorDialog::options
+ \brief the various options that affect the look and feel of the dialog
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the
+ dialog is visible is not guaranteed to have an immediate effect on the
+ dialog (depending on the option and on the platform).
+
+ \sa setOption(), testOption()
+*/
+void QColorDialog::setOptions(ColorDialogOptions options)
+{
+ Q_D(QColorDialog);
+
+ ColorDialogOptions changed = (options ^ d->opts);
+ if (!changed)
+ return;
+
+ d->opts = options;
+ d->buttons->setVisible(!(options & NoButtons));
+ d->showAlpha(options & ShowAlphaChannel);
+}
+
+QColorDialog::ColorDialogOptions QColorDialog::options() const
+{
+ Q_D(const QColorDialog);
+ return d->opts;
+}
+
+/*!
+ \enum QColorDialog::ColorDialogOption
+
+ \since 4.5
+
+ This enum specifies various options that affect the look and feel
+ of a color dialog.
+
+ \value ShowAlphaChannel Allow the user to select the alpha component of a color.
+ \value NoButtons Don't display \gui{OK} and \gui{Cancel} buttons. (Useful for "live dialogs".)
+ \value DontUseNativeDialog Use Qt's standard color dialog on the Mac instead of Apple's
+ native color panel.
+
+ \sa options, setOption(), testOption(), windowModality()
+*/
+
+/*!
+ \fn void QColorDialog::currentColorChanged(const QColor &color)
+
+ This signal is emitted whenever the current color changes in the dialog.
+ The current color is specified by \a color.
+
+ \sa color, colorSelected()
+*/
+
+#ifdef Q_WS_MAC
+// can only have one Cocoa color panel active
+bool QColorDialogPrivate::sharedColorPanelAvailable = true;
+#endif
+
+/*!
+ \fn void QColorDialog::colorSelected(const QColor &color);
+
+ This signal is emitted just after the user has clicked \gui{OK} to
+ select a color to use. The chosen color is specified by \a color.
+
+ \sa color, currentColorChanged()
+*/
+
+/*!
+ Changes the visibility of the dialog. If \a visible is true, the dialog
+ is shown; otherwise, it is hidden.
+*/
+void QColorDialog::setVisible(bool visible)
+{
+ Q_D(QColorDialog);
+
+ if (visible){
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
+ return;
+ } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
+ return;
+
+ if (visible)
+ d->selectedQColor = QColor();
+
+#if defined(Q_WS_MAC)
+ if (visible) {
+ if (d->delegate || (QColorDialogPrivate::sharedColorPanelAvailable &&
+ !(testAttribute(Qt::WA_DontShowOnScreen) || (d->opts & DontUseNativeDialog)))){
+ d->openCocoaColorPanel(currentColor(), parentWidget(), windowTitle(), options());
+ QColorDialogPrivate::sharedColorPanelAvailable = false;
+ setAttribute(Qt::WA_DontShowOnScreen);
+ }
+ setWindowFlags(windowModality() == Qt::WindowModal ? Qt::Sheet : DefaultWindowFlags);
+ } else {
+ if (d->delegate) {
+ d->closeCocoaColorPanel();
+ setAttribute(Qt::WA_DontShowOnScreen, false);
+ }
+ }
+#else
+
+ if (!(d->opts & DontUseNativeDialog) && qt_guiPlatformPlugin()->colorDialogSetVisible(this, visible)) {
+ d->nativeDialogInUse = true;
+ // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+ // updates the state correctly, but skips showing the non-native version:
+ setAttribute(Qt::WA_DontShowOnScreen);
+ } else {
+ d->nativeDialogInUse = false;
+ setAttribute(Qt::WA_DontShowOnScreen, false);
+ }
+#endif
+
+ QDialog::setVisible(visible);
+}
+
+/*!
+ \overload
+ \since 4.5
+
+ Opens the dialog and connects its colorSelected() signal to the slot specified
+ by \a receiver and \a member.
+
+ The signal will be disconnected from the slot when the dialog is closed.
+*/
+void QColorDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QColorDialog);
+ connect(this, SIGNAL(colorSelected(QColor)), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+/*!
+ \fn QColorDialog::open()
+
+ \since 4.5
+ Shows the dialog as a \l{QDialog#Modal Dialogs}{window modal dialog},
+ returning immediately.
+
+ \sa QDialog::open()
+*/
+
+/*
+ For Symbian color dialogs
+*/
+#ifdef Q_WS_S60
+extern QColor qtSymbianGetColor(const QColor &initial);
+#endif
+/*!
+ \since 4.5
+
+ Pops up a modal color dialog with the given window \a title (or "Select Color" if none is
+ specified), lets the user choose a color, and returns that color. The color is initially set
+ to \a initial. The dialog is a child of \a parent. It returns an invalid (see
+ QColor::isValid()) color if the user cancels the dialog.
+
+ The \a options argument allows you to customize the dialog.
+
+ On Symbian, this static function will use the native color dialog and not a QColorDialog.
+ On Symbian the parameters \a title and \a parent has no relevance and the
+ \a options parameter is only used to define if the native color dialog is
+ used or not.
+*/
+QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QString &title,
+ ColorDialogOptions options)
+{
+#ifdef Q_WS_S60
+ if (!(options & DontUseNativeDialog))
+ return qtSymbianGetColor(initial);
+#endif
+ QColorDialog dlg(parent);
+ if (!title.isEmpty())
+ dlg.setWindowTitle(title);
+ dlg.setOptions(options);
+ dlg.setCurrentColor(initial);
+ dlg.exec();
+ return dlg.selectedColor();
+}
+
+/*!
+ Pops up a modal color dialog, lets the user choose a color, and
+ returns that color. The color is initially set to \a initial. The
+ dialog is a child of \a parent. It returns an invalid (see
+ QColor::isValid()) color if the user cancels the dialog.
+
+ On Symbian, this static function will use the native
+ color dialog and not a QColorDialog.
+*/
+
+QColor QColorDialog::getColor(const QColor &initial, QWidget *parent)
+{
+#ifdef Q_WS_S60
+ return qtSymbianGetColor(initial);
+#endif
+ return getColor(initial, parent, QString(), ColorDialogOptions(0));
+}
+
+
+/*!
+ \obsolete
+
+ Pops up a modal color dialog to allow the user to choose a color
+ and an alpha channel (transparency) value. The color+alpha is
+ initially set to \a initial. The dialog is a child of \a parent.
+
+ If \a ok is non-null, \e *\a ok is set to true if the user clicked
+ \gui{OK}, and to false if the user clicked Cancel.
+
+ If the user clicks Cancel, the \a initial value is returned.
+
+ Use QColorDialog::getColor() instead, passing the
+ QColorDialog::ShowAlphaChannel option.
+*/
+
+QRgb QColorDialog::getRgba(QRgb initial, bool *ok, QWidget *parent)
+{
+ QColor color(getColor(QColor(initial), parent, QString(), ShowAlphaChannel));
+ QRgb result = color.isValid() ? color.rgba() : initial;
+ if (ok)
+ *ok = color.isValid();
+ return result;
+}
+
+/*!
+ Destroys the color dialog.
+*/
+
+QColorDialog::~QColorDialog()
+{
+ Q_D(QColorDialog);
+#if defined(Q_WS_MAC)
+ if (d->delegate) {
+ d->releaseCocoaColorPanelDelegate();
+ QColorDialogPrivate::sharedColorPanelAvailable = true;
+ }
+#endif
+
+#ifndef QT_NO_SETTINGS
+ if (!customSet) {
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ for (int i = 0; i < 2*8; ++i)
+ settings.setValue(QLatin1String("Qt/customColors/") + QString::number(i), cusrgb[i]);
+ }
+#endif
+ if (d->nativeDialogInUse)
+ qt_guiPlatformPlugin()->colorDialogDelete(this);
+
+}
+
+
+/*!
+ \reimp
+*/
+void QColorDialog::changeEvent(QEvent *e)
+{
+ Q_D(QColorDialog);
+ if (e->type() == QEvent::LanguageChange)
+ d->retranslateStrings();
+ QDialog::changeEvent(e);
+}
+
+/*!
+ Closes the dialog and sets its result code to \a result. If this dialog
+ is shown with exec(), done() causes the local event loop to finish,
+ and exec() to return \a result.
+
+ \sa QDialog::done()
+*/
+void QColorDialog::done(int result)
+{
+ Q_D(QColorDialog);
+ QDialog::done(result);
+ if (result == Accepted) {
+ d->selectedQColor = d->currentQColor();
+ emit colorSelected(d->selectedQColor);
+ } else {
+ d->selectedQColor = QColor();
+ }
+ if (d->receiverToDisconnectOnClose) {
+ disconnect(this, SIGNAL(colorSelected(QColor)),
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+}
+
+QT_END_NAMESPACE
+
+#include "qcolordialog.moc"
+#include "moc_qcolordialog.cpp"
+
+#endif // QT_NO_COLORDIALOG
+
+/*!
+ \fn QColor QColorDialog::getColor(const QColor &init, QWidget *parent, const char *name)
+ \compat
+*/
+
+/*!
+ \fn QRgb QColorDialog::getRgba(QRgb rgba, bool *ok, QWidget *parent, const char *name)
+ \compat
+*/
diff --git a/src/widgets/dialogs/qcolordialog.h b/src/widgets/dialogs/qcolordialog.h
new file mode 100644
index 0000000000..2eb4658634
--- /dev/null
+++ b/src/widgets/dialogs/qcolordialog.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOLORDIALOG_H
+#define QCOLORDIALOG_H
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_COLORDIALOG
+
+class QColorDialogPrivate;
+
+class Q_WIDGETS_EXPORT QColorDialog : public QDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QColorDialog)
+ Q_ENUMS(ColorDialogOption)
+ Q_PROPERTY(QColor currentColor READ currentColor WRITE setCurrentColor
+ NOTIFY currentColorChanged)
+ Q_PROPERTY(ColorDialogOptions options READ options WRITE setOptions)
+
+public:
+ enum ColorDialogOption {
+ ShowAlphaChannel = 0x00000001,
+ NoButtons = 0x00000002,
+ DontUseNativeDialog = 0x00000004
+ };
+
+ Q_DECLARE_FLAGS(ColorDialogOptions, ColorDialogOption)
+
+ explicit QColorDialog(QWidget *parent = 0);
+ explicit QColorDialog(const QColor &initial, QWidget *parent = 0);
+ ~QColorDialog();
+
+ void setCurrentColor(const QColor &color);
+ QColor currentColor() const;
+
+ QColor selectedColor() const;
+
+ void setOption(ColorDialogOption option, bool on = true);
+ bool testOption(ColorDialogOption option) const;
+ void setOptions(ColorDialogOptions options);
+ ColorDialogOptions options() const;
+
+#ifdef Q_NO_USING_KEYWORD
+ void open() { QDialog::open(); }
+#else
+ using QDialog::open;
+#endif
+ void open(QObject *receiver, const char *member);
+
+ void setVisible(bool visible);
+
+ // ### Qt 5: merge overloads with title = QString()
+ static QColor getColor(const QColor &initial, QWidget *parent, const QString &title,
+ ColorDialogOptions options = 0);
+ static QColor getColor(const QColor &initial = Qt::white, QWidget *parent = 0);
+
+ // obsolete
+ static QRgb getRgba(QRgb rgba = 0xffffffff, bool *ok = 0, QWidget *parent = 0);
+
+ // ### Qt 5: use QColor in signatures
+ static int customCount();
+ static QRgb customColor(int index);
+ static void setCustomColor(int index, QRgb color);
+ static void setStandardColor(int index, QRgb color);
+
+#ifdef QT3_SUPPORT
+ static QColor getColor(const QColor &init, QWidget *parent, const char *name)
+ { Q_UNUSED(name); return getColor(init, parent); }
+ static QRgb getRgba(QRgb rgba, bool *ok, QWidget *parent, const char *name)
+ { Q_UNUSED(name); return getRgba(rgba, ok, parent); }
+#endif
+
+Q_SIGNALS:
+ void currentColorChanged(const QColor &color);
+ void colorSelected(const QColor &color);
+
+protected:
+ void changeEvent(QEvent *event);
+ void done(int result);
+
+private:
+ Q_DISABLE_COPY(QColorDialog)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_addCustom())
+ Q_PRIVATE_SLOT(d_func(), void _q_newHsv(int h, int s, int v))
+ Q_PRIVATE_SLOT(d_func(), void _q_newColorTypedIn(QRgb rgb))
+ Q_PRIVATE_SLOT(d_func(), void _q_newCustom(int, int))
+ Q_PRIVATE_SLOT(d_func(), void _q_newStandard(int, int))
+#if defined(Q_WS_MAC)
+ Q_PRIVATE_SLOT(d_func(), void _q_macRunNativeAppModalPanel())
+#endif
+
+ friend class QColorShower;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QColorDialog::ColorDialogOptions)
+
+#endif // QT_NO_COLORDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCOLORDIALOG_H
diff --git a/src/widgets/dialogs/qcolordialog_mac.mm b/src/widgets/dialogs/qcolordialog_mac.mm
new file mode 100644
index 0000000000..1d77751e2b
--- /dev/null
+++ b/src/widgets/dialogs/qcolordialog_mac.mm
@@ -0,0 +1,505 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcolordialog_p.h"
+#if !defined(QT_NO_COLORDIALOG) && defined(Q_WS_MAC)
+#include <qapplication.h>
+#include <qtimer.h>
+#include <qdialogbuttonbox.h>
+#include <qabstracteventdispatcher.h>
+#include <private/qapplication_p.h>
+#include <private/qt_mac_p.h>
+#include <qdebug.h>
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+#if !CGFLOAT_DEFINED
+typedef float CGFloat; // Should only not be defined on 32-bit platforms
+#endif
+
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
+@protocol NSWindowDelegate <NSObject>
+- (void)windowDidResize:(NSNotification *)notification;
+- (BOOL)windowShouldClose:(id)window;
+@end
+#endif
+
+QT_USE_NAMESPACE
+
+@class QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate);
+
+@interface QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) : NSObject<NSWindowDelegate> {
+ NSColorPanel *mColorPanel;
+ NSView *mStolenContentView;
+ NSButton *mOkButton;
+ NSButton *mCancelButton;
+ QColorDialogPrivate *mPriv;
+ QColor *mQtColor;
+ CGFloat mMinWidth; // currently unused
+ CGFloat mExtraHeight; // currently unused
+ BOOL mHackedPanel;
+ NSInteger mResultCode;
+ BOOL mDialogIsExecuting;
+ BOOL mResultSet;
+}
+- (id)initWithColorPanel:(NSColorPanel *)panel
+ stolenContentView:(NSView *)stolenContentView
+ okButton:(NSButton *)okButton
+ cancelButton:(NSButton *)cancelButton
+ priv:(QColorDialogPrivate *)priv;
+- (void)colorChanged:(NSNotification *)notification;
+- (void)relayout;
+- (void)onOkClicked;
+- (void)onCancelClicked;
+- (void)updateQtColor;
+- (NSColorPanel *)colorPanel;
+- (QColor)qtColor;
+- (void)finishOffWithCode:(NSInteger)result;
+- (void)showColorPanel;
+- (void)exec;
+- (void)setResultSet:(BOOL)result;
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate)
+- (id)initWithColorPanel:(NSColorPanel *)panel
+ stolenContentView:(NSView *)stolenContentView
+ okButton:(NSButton *)okButton
+ cancelButton:(NSButton *)cancelButton
+ priv:(QColorDialogPrivate *)priv
+{
+ self = [super init];
+
+ mColorPanel = panel;
+ mStolenContentView = stolenContentView;
+ mOkButton = okButton;
+ mCancelButton = cancelButton;
+ mPriv = priv;
+ mMinWidth = 0.0;
+ mExtraHeight = 0.0;
+ mHackedPanel = (okButton != 0);
+ mResultCode = NSCancelButton;
+ mDialogIsExecuting = false;
+ mResultSet = false;
+
+ if (mHackedPanel) {
+ [self relayout];
+
+ [okButton setAction:@selector(onOkClicked)];
+ [okButton setTarget:self];
+
+ [cancelButton setAction:@selector(onCancelClicked)];
+ [cancelButton setTarget:self];
+ }
+
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(colorChanged:)
+ name:NSColorPanelColorDidChangeNotification
+ object:mColorPanel];
+
+ mQtColor = new QColor();
+ return self;
+}
+
+- (void)dealloc
+{
+ QMacCocoaAutoReleasePool pool;
+ if (mHackedPanel) {
+ NSView *ourContentView = [mColorPanel contentView];
+
+ // return stolen stuff to its rightful owner
+ [mStolenContentView removeFromSuperview];
+ [mColorPanel setContentView:mStolenContentView];
+
+ [mOkButton release];
+ [mCancelButton release];
+ [ourContentView release];
+ }
+ [mColorPanel setDelegate:nil];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ delete mQtColor;
+ [super dealloc];
+}
+
+- (void)setResultSet:(BOOL)result
+{
+ mResultSet = result;
+}
+
+- (BOOL)windowShouldClose:(id)window
+{
+ Q_UNUSED(window);
+ if (!mHackedPanel)
+ [self updateQtColor];
+ if (mDialogIsExecuting) {
+ [self finishOffWithCode:NSCancelButton];
+ } else {
+ mResultSet = true;
+ mPriv->colorDialog()->reject();
+ }
+ return true;
+}
+
+- (void)windowDidResize:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ if (mHackedPanel)
+ [self relayout];
+}
+
+- (void)colorChanged:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ [self updateQtColor];
+}
+
+- (void)relayout
+{
+ Q_ASSERT(mHackedPanel);
+
+ NSRect rect = [[mStolenContentView superview] frame];
+
+ // should a priori be kept in sync with qfontdialog_mac.mm
+ const CGFloat ButtonMinWidth = 78.0; // 84.0 for Carbon
+ const CGFloat ButtonMinHeight = 32.0;
+ const CGFloat ButtonSpacing = 0.0;
+ const CGFloat ButtonTopMargin = 0.0;
+ const CGFloat ButtonBottomMargin = 7.0;
+ const CGFloat ButtonSideMargin = 9.0;
+
+ [mOkButton sizeToFit];
+ NSSize okSizeHint = [mOkButton frame].size;
+
+ [mCancelButton sizeToFit];
+ NSSize cancelSizeHint = [mCancelButton frame].size;
+
+ const CGFloat ButtonWidth = qMin(qMax(ButtonMinWidth,
+ qMax(okSizeHint.width, cancelSizeHint.width)),
+ CGFloat((rect.size.width - 2.0 * ButtonSideMargin - ButtonSpacing) * 0.5));
+ const CGFloat ButtonHeight = qMax(ButtonMinHeight,
+ qMax(okSizeHint.height, cancelSizeHint.height));
+
+ NSRect okRect = { { rect.size.width - ButtonSideMargin - ButtonWidth,
+ ButtonBottomMargin },
+ { ButtonWidth, ButtonHeight } };
+ [mOkButton setFrame:okRect];
+ [mOkButton setNeedsDisplay:YES];
+
+ NSRect cancelRect = { { okRect.origin.x - ButtonSpacing - ButtonWidth,
+ ButtonBottomMargin },
+ { ButtonWidth, ButtonHeight } };
+ [mCancelButton setFrame:cancelRect];
+ [mCancelButton setNeedsDisplay:YES];
+
+ const CGFloat Y = ButtonBottomMargin + ButtonHeight + ButtonTopMargin;
+ NSRect stolenCVRect = { { 0.0, Y },
+ { rect.size.width, rect.size.height - Y } };
+ [mStolenContentView setFrame:stolenCVRect];
+ [mStolenContentView setNeedsDisplay:YES];
+
+ [[mStolenContentView superview] setNeedsDisplay:YES];
+ mMinWidth = 2 * ButtonSideMargin + ButtonSpacing + 2 * ButtonWidth;
+ mExtraHeight = Y;
+}
+
+- (void)onOkClicked
+{
+ Q_ASSERT(mHackedPanel);
+ [[mStolenContentView window] close];
+ [self updateQtColor];
+ [self finishOffWithCode:NSOKButton];
+}
+
+- (void)onCancelClicked
+{
+ if (mHackedPanel) {
+ [[mStolenContentView window] close];
+ delete mQtColor;
+ mQtColor = new QColor();
+ [self finishOffWithCode:NSCancelButton];
+ }
+}
+
+- (void)updateQtColor
+{
+ delete mQtColor;
+ mQtColor = new QColor();
+ NSColor *color = [mColorPanel color];
+ NSString *colorSpaceName = [color colorSpaceName];
+ if (colorSpaceName == NSDeviceCMYKColorSpace) {
+ CGFloat cyan = 0, magenta = 0, yellow = 0, black = 0, alpha = 0;
+ [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
+ mQtColor->setCmykF(cyan, magenta, yellow, black, alpha);
+ } else if (colorSpaceName == NSCalibratedRGBColorSpace || colorSpaceName == NSDeviceRGBColorSpace) {
+ CGFloat red = 0, green = 0, blue = 0, alpha = 0;
+ [color getRed:&red green:&green blue:&blue alpha:&alpha];
+ mQtColor->setRgbF(red, green, blue, alpha);
+ } else if (colorSpaceName == NSNamedColorSpace) {
+ NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+ CGFloat red = 0, green = 0, blue = 0, alpha = 0;
+ [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
+ mQtColor->setRgbF(red, green, blue, alpha);
+ } else {
+ NSColorSpace *colorSpace = [color colorSpace];
+ if ([colorSpace colorSpaceModel] == NSCMYKColorSpaceModel && [color numberOfComponents] == 5){
+ CGFloat components[5];
+ [color getComponents:components];
+ mQtColor->setCmykF(components[0], components[1], components[2], components[3], components[4]);
+ } else {
+ NSColor *tmpColor = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
+ CGFloat red = 0, green = 0, blue = 0, alpha = 0;
+ [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
+ mQtColor->setRgbF(red, green, blue, alpha);
+ }
+ }
+
+ mPriv->setCurrentQColor(*mQtColor);
+}
+
+- (NSColorPanel *)colorPanel
+{
+ return mColorPanel;
+}
+
+- (QColor)qtColor
+{
+ return *mQtColor;
+}
+
+- (void)finishOffWithCode:(NSInteger)code
+{
+ mResultCode = code;
+ if (mDialogIsExecuting) {
+ // We stop the current modal event loop. The control
+ // will then return inside -(void)exec below.
+ // It's important that the modal event loop is stopped before
+ // we accept/reject QColorDialog, since QColorDialog has its
+ // own event loop that needs to be stopped last.
+ [NSApp stopModalWithCode:code];
+ } else {
+ // Since we are not in a modal event loop, we can safely close
+ // down QColorDialog
+ // Calling accept() or reject() can in turn call closeCocoaColorPanel.
+ // This check will prevent any such recursion.
+ if (!mResultSet) {
+ mResultSet = true;
+ if (mResultCode == NSCancelButton) {
+ mPriv->colorDialog()->reject();
+ } else {
+ mPriv->colorDialog()->accept();
+ }
+ }
+ }
+}
+
+- (void)showColorPanel
+{
+ mDialogIsExecuting = false;
+ [mColorPanel makeKeyAndOrderFront:mColorPanel];
+}
+
+- (void)exec
+{
+ QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
+ QMacCocoaAutoReleasePool pool;
+ mDialogIsExecuting = true;
+ bool modalEnded = false;
+ while (!modalEnded) {
+#ifndef QT_NO_EXCEPTIONS
+ @try {
+ [NSApp runModalForWindow:mColorPanel];
+ modalEnded = true;
+ } @catch (NSException *) {
+ // For some reason, NSColorPanel throws an exception when
+ // clicking on 'SelectedMenuItemColor' from the 'Developer'
+ // palette (tab three).
+ }
+#else
+ [NSApp runModalForWindow:mColorPanel];
+ modalEnded = true;
+#endif
+ }
+
+ QAbstractEventDispatcher::instance()->interrupt();
+ if (mResultCode == NSCancelButton)
+ mPriv->colorDialog()->reject();
+ else
+ mPriv->colorDialog()->accept();
+}
+
+@end
+
+QT_BEGIN_NAMESPACE
+
+extern void macStartInterceptNSPanelCtor();
+extern void macStopInterceptNSPanelCtor();
+extern NSButton *macCreateButton(const char *text, NSView *superview);
+
+void QColorDialogPrivate::openCocoaColorPanel(const QColor &initial,
+ QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options)
+{
+ Q_UNUSED(parent); // we would use the parent if only NSColorPanel could be a sheet
+ QMacCocoaAutoReleasePool pool;
+
+ if (!delegate) {
+ /*
+ The standard Cocoa color panel has no OK or Cancel button and
+ is created as a utility window, whereas we want something like
+ the Carbon color panel. We need to take the following steps:
+
+ 1. Intercept the color panel constructor to turn off the
+ NSUtilityWindowMask flag. This is done by temporarily
+ replacing initWithContentRect:styleMask:backing:defer:
+ in NSPanel by our own method.
+
+ 2. Modify the color panel so that its content view is part
+ of a new content view that contains it as well as two
+ buttons (OK and Cancel).
+
+ 3. Lay out the original content view and the buttons when
+ the color panel is shown and whenever it is resized.
+
+ 4. Clean up after ourselves.
+ */
+
+ bool hackColorPanel = !(options & QColorDialog::NoButtons);
+
+ if (hackColorPanel)
+ macStartInterceptNSPanelCtor();
+ NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];
+ if (hackColorPanel)
+ macStopInterceptNSPanelCtor();
+
+ [colorPanel setHidesOnDeactivate:false];
+
+ // set up the Cocoa color panel
+ [colorPanel setShowsAlpha:options & QColorDialog::ShowAlphaChannel];
+ [colorPanel setTitle:(NSString*)(CFStringRef)QCFString(title)];
+
+ NSView *stolenContentView = 0;
+ NSButton *okButton = 0;
+ NSButton *cancelButton = 0;
+
+ if (hackColorPanel) {
+ // steal the color panel's contents view
+ stolenContentView = [colorPanel contentView];
+ [stolenContentView retain];
+ [colorPanel setContentView:0];
+
+ // create a new content view and add the stolen one as a subview
+ NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } };
+ NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect];
+ [ourContentView addSubview:stolenContentView];
+
+ // create OK and Cancel buttons and add these as subviews
+ okButton = macCreateButton("&OK", ourContentView);
+ cancelButton = macCreateButton("Cancel", ourContentView);
+
+ [colorPanel setContentView:ourContentView];
+ [colorPanel setDefaultButtonCell:[okButton cell]];
+ }
+
+ delegate = [[QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) alloc] initWithColorPanel:colorPanel
+ stolenContentView:stolenContentView
+ okButton:okButton
+ cancelButton:cancelButton
+ priv:this];
+ [colorPanel setDelegate:static_cast<QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *>(delegate)];
+ }
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *>(delegate) setResultSet:NO];
+ setCocoaPanelColor(initial);
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *>(delegate) showColorPanel];
+}
+
+void QColorDialogPrivate::closeCocoaColorPanel()
+{
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *>(delegate) onCancelClicked];
+}
+
+void QColorDialogPrivate::releaseCocoaColorPanelDelegate()
+{
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *>(delegate) release];
+}
+
+void QColorDialogPrivate::mac_nativeDialogModalHelp()
+{
+ // Do a queued meta-call to open the native modal dialog so it opens after the new
+ // event loop has started to execute (in QDialog::exec). Using a timer rather than
+ // a queued meta call is intentional to ensure that the call is only delivered when
+ // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
+ // running (which is the case if e.g a top-most QEventLoop has been
+ // interrupted, and the second-most event loop has not yet been reactivated (regardless
+ // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
+ if (delegate){
+ Q_Q(QColorDialog);
+ QTimer::singleShot(1, q, SLOT(_q_macRunNativeAppModalPanel()));
+ }
+}
+
+void QColorDialogPrivate::_q_macRunNativeAppModalPanel()
+{
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *>(delegate) exec];
+}
+
+void QColorDialogPrivate::setCocoaPanelColor(const QColor &color)
+{
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *theDelegate = static_cast<QT_MANGLE_NAMESPACE(QCocoaColorPanelDelegate) *>(delegate);
+ NSColor *nsColor;
+ const QColor::Spec spec = color.spec();
+ if (spec == QColor::Cmyk) {
+ nsColor = [NSColor colorWithDeviceCyan:color.cyanF()
+ magenta:color.magentaF()
+ yellow:color.yellowF()
+ black:color.blackF()
+ alpha:color.alphaF()];
+ } else {
+ nsColor = [NSColor colorWithCalibratedRed:color.redF()
+ green:color.greenF()
+ blue:color.blueF()
+ alpha:color.alphaF()];
+ }
+ [[theDelegate colorPanel] setColor:nsColor];
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qcolordialog_p.h b/src/widgets/dialogs/qcolordialog_p.h
new file mode 100644
index 0000000000..f1865e66ec
--- /dev/null
+++ b/src/widgets/dialogs/qcolordialog_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOLORDIALOG_P_H
+#define QCOLORDIALOG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// to version without notice, or even be removed.
+//
+// We mean it.
+//
+//
+
+#include "private/qdialog_p.h"
+#include "qcolordialog.h"
+
+#ifndef QT_NO_COLORDIALOG
+
+QT_BEGIN_NAMESPACE
+
+class QColorLuminancePicker;
+class QColorPicker;
+class QColorShower;
+class QDialogButtonBox;
+class QLabel;
+class QVBoxLayout;
+class QPushButton;
+class QWellArray;
+
+class QColorDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QColorDialog)
+
+public:
+ void init(const QColor &initial);
+ QRgb currentColor() const;
+ QColor currentQColor() const;
+ void setCurrentColor(QRgb rgb);
+ void setCurrentQColor(const QColor &color);
+ bool selectColor(const QColor &color);
+
+ int currentAlpha() const;
+ void setCurrentAlpha(int a);
+ void showAlpha(bool b);
+ bool isAlphaVisible() const;
+ void retranslateStrings();
+
+ void _q_addCustom();
+
+ void _q_newHsv(int h, int s, int v);
+ void _q_newColorTypedIn(QRgb rgb);
+ void _q_newCustom(int, int);
+ void _q_newStandard(int, int);
+
+ QWellArray *custom;
+ QWellArray *standard;
+
+ QDialogButtonBox *buttons;
+ QVBoxLayout *leftLay;
+ QColorPicker *cp;
+ QColorLuminancePicker *lp;
+ QColorShower *cs;
+ QLabel *lblBasicColors;
+ QLabel *lblCustomColors;
+ QPushButton *ok;
+ QPushButton *cancel;
+ QPushButton *addCusBt;
+ QColor selectedQColor;
+ int nextCust;
+ bool smallDisplay;
+ QColorDialog::ColorDialogOptions opts;
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+ bool nativeDialogInUse;
+
+#ifdef Q_WS_MAC
+ void openCocoaColorPanel(const QColor &initial,
+ QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options);
+ void closeCocoaColorPanel();
+ void releaseCocoaColorPanelDelegate();
+ void setCocoaPanelColor(const QColor &color);
+
+ inline void done(int result) { q_func()->done(result); }
+ inline QColorDialog *colorDialog() { return q_func(); }
+
+ void *delegate;
+
+ static bool sharedColorPanelAvailable;
+
+ void _q_macRunNativeAppModalPanel();
+ void mac_nativeDialogModalHelp();
+#endif
+};
+
+#endif // QT_NO_COLORDIALOG
+
+QT_END_NAMESPACE
+
+#endif // QCOLORDIALOG_P_H
diff --git a/src/widgets/dialogs/qcolordialog_symbian.cpp b/src/widgets/dialogs/qcolordialog_symbian.cpp
new file mode 100644
index 0000000000..eab35f5ac8
--- /dev/null
+++ b/src/widgets/dialogs/qcolordialog_symbian.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcolordialog_p.h"
+
+#ifndef QT_NO_COLORDIALOG
+
+
+#include "qcolor.h"
+#include "private/qguiplatformplugin_p.h"
+
+#ifdef Q_WS_S60
+#include <AknColourSelectionGrid.h>
+#endif
+
+#include "private/qt_s60_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QColor launchSymbianColorDialog(QColor initial)
+{
+ QColor currentColor = QColor::Invalid;
+#ifdef Q_WS_S60
+ QT_TRAP_THROWING(
+ CArrayFixFlat<TRgb>* array = new( ELeave ) CArrayFixFlat<TRgb>(17);
+ CleanupStack::PushL(array);
+ array->AppendL(KRgbBlack);
+ array->AppendL(KRgbDarkGray);
+ array->AppendL(KRgbDarkRed);
+ array->AppendL(KRgbDarkGreen);
+ array->AppendL(KRgbDarkYellow);
+ array->AppendL(KRgbDarkBlue);
+ array->AppendL(KRgbDarkMagenta);
+ array->AppendL(KRgbDarkCyan);
+ array->AppendL(KRgbRed);
+ array->AppendL(KRgbGreen);
+ array->AppendL(KRgbYellow);
+ array->AppendL(KRgbBlue);
+ array->AppendL(KRgbMagenta);
+ array->AppendL(KRgbCyan);
+ array->AppendL(KRgbGray);
+ array->AppendL(KRgbWhite);
+
+ TRgb initialColour(initial.red(), initial.green(), initial.blue(), initial.alpha());
+
+ TBool noneChosen = EFalse; // If true shows the default colour button
+ CAknColourSelectionGrid* colourSelectionGrid =
+ CAknColourSelectionGrid::NewL(array, EFalse, noneChosen, initialColour);
+ CleanupStack::PushL(colourSelectionGrid);
+
+ if (colourSelectionGrid->ExecuteLD()) {
+ currentColor.setRgb(initialColour.Red(), initialColour.Green(),
+ initialColour.Blue(), initialColour.Alpha());
+ }
+ CleanupStack::Pop(colourSelectionGrid);
+ CleanupStack::PopAndDestroy(array);
+ );
+#endif
+ return currentColor;
+}
+
+QColor qtSymbianGetColor(const QColor &initial)
+{
+ return launchSymbianColorDialog(initial);
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_COLORDIALOG
diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp
new file mode 100644
index 0000000000..2fb6c67e50
--- /dev/null
+++ b/src/widgets/dialogs/qdialog.cpp
@@ -0,0 +1,1272 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdialog.h"
+
+
+#include "qevent.h"
+#include "qdesktopwidget.h"
+#include "qpushbutton.h"
+#include "qapplication.h"
+#include "qlayout.h"
+#include "qsizegrip.h"
+#include "qwhatsthis.h"
+#include "qmenu.h"
+#include "qcursor.h"
+#include "private/qdialog_p.h"
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#if defined(Q_WS_WINCE)
+#include "qt_windows.h"
+#include "qmenubar.h"
+#include "qpointer.h"
+#include "qguifunctions_wince.h"
+extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp
+extern bool qt_wince_is_smartphone(); //is defined in qguifunctions_wce.cpp
+#elif defined(Q_WS_X11)
+# include "../kernel/qt_x11_p.h"
+#elif defined(Q_OS_SYMBIAN)
+# include "qfiledialog.h"
+# include "qfontdialog.h"
+# include "qwizard.h"
+# include "private/qt_s60_p.h"
+#endif
+
+#if defined(Q_WS_S60)
+#include <AknUtils.h> // AknLayoutUtils
+#endif
+
+#ifndef SPI_GETSNAPTODEFBUTTON
+# define SPI_GETSNAPTODEFBUTTON 95
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QDialog
+ \brief The QDialog class is the base class of dialog windows.
+
+ \ingroup dialog-classes
+ \ingroup abstractwidgets
+
+
+ A dialog window is a top-level window mostly used for short-term
+ tasks and brief communications with the user. QDialogs may be
+ modal or modeless. QDialogs can
+ provide a \link #return return
+ value\endlink, and they can have \link #default default
+ buttons\endlink. QDialogs can also have a QSizeGrip in their
+ lower-right corner, using setSizeGripEnabled().
+
+ Note that QDialog (an any other widget that has type Qt::Dialog) uses
+ the parent widget slightly differently from other classes in Qt. A
+ dialog is always a top-level widget, but if it has a parent, its
+ default location is centered on top of the parent's top-level widget
+ (if it is not top-level itself). It will also share the parent's
+ taskbar entry.
+
+ Use the overload of the QWidget::setParent() function to change
+ the ownership of a QDialog widget. This function allows you to
+ explicitly set the window flags of the reparented widget; using
+ the overloaded function will clear the window flags specifying the
+ window-system properties for the widget (in particular it will
+ reset the Qt::Dialog flag).
+
+ \section1 Modal Dialogs
+
+ A \bold{modal} dialog is a dialog that blocks input to other
+ visible windows in the same application. Dialogs that are used to
+ request a file name from the user or that are used to set
+ application preferences are usually modal. Dialogs can be
+ \l{Qt::ApplicationModal}{application modal} (the default) or
+ \l{Qt::WindowModal}{window modal}.
+
+ When an application modal dialog is opened, the user must finish
+ interacting with the dialog and close it before they can access
+ any other window in the application. Window modal dialogs only
+ block access to the window associated with the dialog, allowing
+ the user to continue to use other windows in an application.
+
+ The most common way to display a modal dialog is to call its
+ exec() function. When the user closes the dialog, exec() will
+ provide a useful \link #return return value\endlink. Typically,
+ to get the dialog to close and return the appropriate value, we
+ connect a default button, e.g. \gui OK, to the accept() slot and a
+ \gui Cancel button to the reject() slot.
+ Alternatively you can call the done() slot with \c Accepted or
+ \c Rejected.
+
+ An alternative is to call setModal(true) or setWindowModality(),
+ then show(). Unlike exec(), show() returns control to the caller
+ immediately. Calling setModal(true) is especially useful for
+ progress dialogs, where the user must have the ability to interact
+ with the dialog, e.g. to cancel a long running operation. If you
+ use show() and setModal(true) together to perform a long operation,
+ you must call QApplication::processEvents() periodically during
+ processing to enable the user to interact with the dialog. (See
+ QProgressDialog.)
+
+ \section1 Modeless Dialogs
+
+ A \bold{modeless} dialog is a dialog that operates
+ independently of other windows in the same application. Find and
+ replace dialogs in word-processors are often modeless to allow the
+ user to interact with both the application's main window and with
+ the dialog.
+
+ Modeless dialogs are displayed using show(), which returns control
+ to the caller immediately.
+
+ If you invoke the \l{QWidget::show()}{show()} function after hiding
+ a dialog, the dialog will be displayed in its original position. This is
+ because the window manager decides the position for windows that
+ have not been explicitly placed by the programmer. To preserve the
+ position of a dialog that has been moved by the user, save its position
+ in your \l{QWidget::closeEvent()}{closeEvent()} handler and then
+ move the dialog to that position, before showing it again.
+
+ \target default
+ \section1 Default Button
+
+ A dialog's \e default button is the button that's pressed when the
+ user presses Enter (Return). This button is used to signify that
+ the user accepts the dialog's settings and wants to close the
+ dialog. Use QPushButton::setDefault(), QPushButton::isDefault()
+ and QPushButton::autoDefault() to set and control the dialog's
+ default button.
+
+ \target escapekey
+ \section1 Escape Key
+
+ If the user presses the Esc key in a dialog, QDialog::reject()
+ will be called. This will cause the window to close: The \link
+ QCloseEvent close event \endlink cannot be \link
+ QCloseEvent::ignore() ignored \endlink.
+
+ \section1 Extensibility
+
+ Extensibility is the ability to show the dialog in two ways: a
+ partial dialog that shows the most commonly used options, and a
+ full dialog that shows all the options. Typically an extensible
+ dialog will initially appear as a partial dialog, but with a
+ \gui More toggle button. If the user presses the \gui More button down,
+ the dialog is expanded. The \l{Extension Example} shows how to achieve
+ extensible dialogs using Qt.
+
+ \target return
+ \section1 Return Value (Modal Dialogs)
+
+ Modal dialogs are often used in situations where a return value is
+ required, e.g. to indicate whether the user pressed \gui OK or
+ \gui Cancel. A dialog can be closed by calling the accept() or the
+ reject() slots, and exec() will return \c Accepted or \c Rejected
+ as appropriate. The exec() call returns the result of the dialog.
+ The result is also available from result() if the dialog has not
+ been destroyed.
+
+ In order to modify your dialog's close behavior, you can reimplement
+ the functions accept(), reject() or done(). The
+ \l{QWidget::closeEvent()}{closeEvent()} function should only be
+ reimplemented to preserve the dialog's position or to override the
+ standard close or reject behavior.
+
+ \target examples
+ \section1 Code Examples
+
+ A modal dialog:
+
+ \snippet doc/src/snippets/dialogs/dialogs.cpp 1
+
+ A modeless dialog:
+
+ \snippet doc/src/snippets/dialogs/dialogs.cpp 0
+
+ \sa QDialogButtonBox, QTabWidget, QWidget, QProgressDialog,
+ {fowler}{GUI Design Handbook: Dialogs, Standard}, {Extension Example},
+ {Standard Dialogs Example}
+*/
+
+/*! \enum QDialog::DialogCode
+
+ The value returned by a modal dialog.
+
+ \value Accepted
+ \value Rejected
+*/
+
+/*!
+ \property QDialog::sizeGripEnabled
+ \brief whether the size grip is enabled
+
+ A QSizeGrip is placed in the bottom-right corner of the dialog when this
+ property is enabled. By default, the size grip is disabled.
+*/
+
+
+/*!
+ Constructs a dialog with parent \a parent.
+
+ A dialog is always a top-level widget, but if it has a parent, its
+ default location is centered on top of the parent. It will also
+ share the parent's taskbar entry.
+
+ The widget flags \a f are passed on to the QWidget constructor.
+ If, for example, you don't want a What's This button in the title bar
+ of the dialog, pass Qt::WindowTitleHint | Qt::WindowSystemMenuHint in \a f.
+
+ \sa QWidget::setWindowFlags()
+*/
+
+QDialog::QDialog(QWidget *parent, Qt::WindowFlags f)
+ : QWidget(*new QDialogPrivate, parent,
+ f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
+{
+#ifdef Q_WS_WINCE
+ if (!qt_wince_is_smartphone())
+ setWindowFlags(windowFlags() | Qt::WindowOkButtonHint | QFlag(qt_wince_is_mobile() ? 0 : Qt::WindowCancelButtonHint));
+#endif
+
+#ifdef Q_WS_S60
+ if (S60->avkonComponentsSupportTransparency) {
+ bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
+ setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
+ setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
+ }
+#endif
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \overload
+ \obsolete
+*/
+QDialog::QDialog(QWidget *parent, const char *name, bool modal, Qt::WindowFlags f)
+ : QWidget(*new QDialogPrivate, parent,
+ f
+ | QFlag(modal ? Qt::WShowModal : Qt::WindowType(0))
+ | QFlag((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0))
+ )
+{
+ setObjectName(QString::fromAscii(name));
+}
+#endif
+
+/*!
+ \overload
+ \internal
+*/
+QDialog::QDialog(QDialogPrivate &dd, QWidget *parent, Qt::WindowFlags f)
+ : QWidget(dd, parent, f | ((f & Qt::WindowType_Mask) == 0 ? Qt::Dialog : Qt::WindowType(0)))
+{
+#ifdef Q_WS_WINCE
+ if (!qt_wince_is_smartphone())
+ setWindowFlags(windowFlags() | Qt::WindowOkButtonHint | QFlag(qt_wince_is_mobile() ? 0 : Qt::WindowCancelButtonHint));
+#endif
+
+#ifdef Q_WS_S60
+ if (S60->avkonComponentsSupportTransparency) {
+ bool noSystemBackground = testAttribute(Qt::WA_NoSystemBackground);
+ setAttribute(Qt::WA_TranslucentBackground); // also sets WA_NoSystemBackground
+ setAttribute(Qt::WA_NoSystemBackground, noSystemBackground); // restore system background attribute
+ }
+#endif
+}
+
+/*!
+ Destroys the QDialog, deleting all its children.
+*/
+
+QDialog::~QDialog()
+{
+ QT_TRY {
+ // Need to hide() here, as our (to-be) overridden hide()
+ // will not be called in ~QWidget.
+ hide();
+ } QT_CATCH(...) {
+ // we're in the destructor - just swallow the exception
+ }
+}
+
+/*!
+ \internal
+ This function is called by the push button \a pushButton when it
+ becomes the default button. If \a pushButton is 0, the dialogs
+ default default button becomes the default button. This is what a
+ push button calls when it loses focus.
+*/
+void QDialogPrivate::setDefault(QPushButton *pushButton)
+{
+ Q_Q(QDialog);
+ bool hasMain = false;
+ QList<QPushButton*> list = q->findChildren<QPushButton*>();
+ for (int i=0; i<list.size(); ++i) {
+ QPushButton *pb = list.at(i);
+ if (pb->window() == q) {
+ if (pb == mainDef)
+ hasMain = true;
+ if (pb != pushButton)
+ pb->setDefault(false);
+ }
+ }
+ if (!pushButton && hasMain)
+ mainDef->setDefault(true);
+ if (!hasMain)
+ mainDef = pushButton;
+}
+
+/*!
+ \internal
+ This function sets the default default push button to \a pushButton.
+ This function is called by QPushButton::setDefault().
+*/
+void QDialogPrivate::setMainDefault(QPushButton *pushButton)
+{
+ mainDef = 0;
+ setDefault(pushButton);
+}
+
+/*!
+ \internal
+ Hides the default button indicator. Called when non auto-default
+ push button get focus.
+ */
+void QDialogPrivate::hideDefault()
+{
+ Q_Q(QDialog);
+ QList<QPushButton*> list = q->findChildren<QPushButton*>();
+ for (int i=0; i<list.size(); ++i) {
+ list.at(i)->setDefault(false);
+ }
+}
+
+void QDialogPrivate::resetModalitySetByOpen()
+{
+ Q_Q(QDialog);
+ if (resetModalityTo != -1 && !q->testAttribute(Qt::WA_SetWindowModality)) {
+ // open() changed the window modality and the user didn't touch it afterwards; restore it
+ q->setWindowModality(Qt::WindowModality(resetModalityTo));
+ q->setAttribute(Qt::WA_SetWindowModality, wasModalitySet);
+#ifdef Q_WS_MAC
+ Q_ASSERT(resetModalityTo != Qt::WindowModal);
+ q->setParent(q->parentWidget(), Qt::Dialog);
+#endif
+ }
+ resetModalityTo = -1;
+}
+
+#if defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
+#ifdef Q_WS_WINCE_WM
+void QDialogPrivate::_q_doneAction()
+{
+ //Done...
+ QApplication::postEvent(q_func(), new QEvent(QEvent::OkRequest));
+}
+#endif
+
+/*!
+ \reimp
+*/
+bool QDialog::event(QEvent *e)
+{
+ bool result = QWidget::event(e);
+#ifdef Q_WS_WINCE
+ if (e->type() == QEvent::OkRequest) {
+ accept();
+ result = true;
+ }
+#elif defined(Q_WS_S60)
+ if ((e->type() == QEvent::StyleChange) || (e->type() == QEvent::Resize )) {
+ if (!testAttribute(Qt::WA_Moved)) {
+ Qt::WindowStates state = windowState();
+ adjustPosition(parentWidget());
+ setAttribute(Qt::WA_Moved, false); // not really an explicit position
+ if (state != windowState())
+ setWindowState(state);
+ }
+ }
+ // TODO is Symbian, non-S60 behaviour required?
+#endif
+ return result;
+}
+#endif
+
+/*!
+ Returns the modal dialog's result code, \c Accepted or \c Rejected.
+
+ Do not call this function if the dialog was constructed with the
+ Qt::WA_DeleteOnClose attribute.
+*/
+int QDialog::result() const
+{
+ Q_D(const QDialog);
+ return d->rescode;
+}
+
+/*!
+ \fn void QDialog::setResult(int i)
+
+ Sets the modal dialog's result code to \a i.
+
+ \note We recommend that you use one of the values defined by
+ QDialog::DialogCode.
+*/
+void QDialog::setResult(int r)
+{
+ Q_D(QDialog);
+ d->rescode = r;
+}
+
+/*!
+ \since 4.5
+
+ Shows the dialog as a \l{QDialog#Modal Dialogs}{window modal dialog},
+ returning immediately.
+
+ \sa exec(), show(), result(), setWindowModality()
+*/
+void QDialog::open()
+{
+ Q_D(QDialog);
+
+ Qt::WindowModality modality = windowModality();
+ if (modality != Qt::WindowModal) {
+ d->resetModalityTo = modality;
+ d->wasModalitySet = testAttribute(Qt::WA_SetWindowModality);
+ setWindowModality(Qt::WindowModal);
+ setAttribute(Qt::WA_SetWindowModality, false);
+#ifdef Q_WS_MAC
+ setParent(parentWidget(), Qt::Sheet);
+#endif
+ }
+
+ setResult(0);
+ show();
+}
+
+/*!
+ Shows the dialog as a \l{QDialog#Modal Dialogs}{modal dialog},
+ blocking until the user closes it. The function returns a \l
+ DialogCode result.
+
+ If the dialog is \l{Qt::ApplicationModal}{application modal}, users cannot
+ interact with any other window in the same application until they close
+ the dialog. If the dialog is \l{Qt::ApplicationModal}{window modal}, only
+ interaction with the parent window is blocked while the dialog is open.
+ By default, the dialog is application modal.
+
+ \sa open(), show(), result(), setWindowModality()
+*/
+
+int QDialog::exec()
+{
+ Q_D(QDialog);
+
+ if (d->eventLoop) {
+ qWarning("QDialog::exec: Recursive call detected");
+ return -1;
+ }
+
+ bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
+ setAttribute(Qt::WA_DeleteOnClose, false);
+
+ d->resetModalitySetByOpen();
+
+ bool wasShowModal = testAttribute(Qt::WA_ShowModal);
+ setAttribute(Qt::WA_ShowModal, true);
+ setResult(0);
+
+//On Windows Mobile we create an empty menu to hide the current menu
+#ifdef Q_WS_WINCE_WM
+#ifndef QT_NO_MENUBAR
+ QMenuBar *menuBar = 0;
+ if (!findChild<QMenuBar *>())
+ menuBar = new QMenuBar(this);
+ if (qt_wince_is_smartphone()) {
+ QAction *doneAction = new QAction(tr("Done"), this);
+ menuBar->setDefaultAction(doneAction);
+ connect(doneAction, SIGNAL(triggered()), this, SLOT(_q_doneAction()));
+ }
+#endif //QT_NO_MENUBAR
+#endif //Q_WS_WINCE_WM
+
+ bool showSystemDialogFullScreen = false;
+#ifdef Q_OS_SYMBIAN
+ if (qobject_cast<QFileDialog *>(this) || qobject_cast<QFontDialog *>(this) ||
+ qobject_cast<QWizard *>(this)) {
+ showSystemDialogFullScreen = true;
+ }
+#endif // Q_OS_SYMBIAN
+
+ if (showSystemDialogFullScreen) {
+ setWindowFlags(windowFlags() | Qt::WindowSoftkeysVisibleHint);
+ setWindowState(Qt::WindowFullScreen);
+ }
+ show();
+
+#ifdef Q_WS_MAC
+ d->mac_nativeDialogModalHelp();
+#endif
+
+ QEventLoop eventLoop;
+ d->eventLoop = &eventLoop;
+ QPointer<QDialog> guard = this;
+ (void) eventLoop.exec(QEventLoop::DialogExec);
+ if (guard.isNull())
+ return QDialog::Rejected;
+ d->eventLoop = 0;
+
+ setAttribute(Qt::WA_ShowModal, wasShowModal);
+
+ int res = result();
+ if (deleteOnClose)
+ delete this;
+#ifdef Q_WS_WINCE_WM
+#ifndef QT_NO_MENUBAR
+ else if (menuBar)
+ delete menuBar;
+#endif //QT_NO_MENUBAR
+#endif //Q_WS_WINCE_WM
+ return res;
+}
+
+
+/*!
+ Closes the dialog and sets its result code to \a r. If this dialog
+ is shown with exec(), done() causes the local event loop to finish,
+ and exec() to return \a r.
+
+ As with QWidget::close(), done() deletes the dialog if the
+ Qt::WA_DeleteOnClose flag is set. If the dialog is the application's
+ main widget, the application terminates. If the dialog is the
+ last window closed, the QApplication::lastWindowClosed() signal is
+ emitted.
+
+ \sa accept(), reject(), QApplication::activeWindow(), QApplication::quit()
+*/
+
+void QDialog::done(int r)
+{
+ Q_D(QDialog);
+ hide();
+ setResult(r);
+
+ d->close_helper(QWidgetPrivate::CloseNoEvent);
+ d->resetModalitySetByOpen();
+
+ emit finished(r);
+ if (r == Accepted)
+ emit accepted();
+ else if (r == Rejected)
+ emit rejected();
+}
+
+/*!
+ Hides the modal dialog and sets the result code to \c Accepted.
+
+ \sa reject() done()
+*/
+
+void QDialog::accept()
+{
+ done(Accepted);
+}
+
+/*!
+ Hides the modal dialog and sets the result code to \c Rejected.
+
+ \sa accept() done()
+*/
+
+void QDialog::reject()
+{
+ done(Rejected);
+}
+
+/*! \reimp */
+bool QDialog::eventFilter(QObject *o, QEvent *e)
+{
+ return QWidget::eventFilter(o, e);
+}
+
+/*****************************************************************************
+ Event handlers
+ *****************************************************************************/
+
+#ifndef QT_NO_CONTEXTMENU
+/*! \reimp */
+void QDialog::contextMenuEvent(QContextMenuEvent *e)
+{
+#if defined(QT_NO_WHATSTHIS) || defined(QT_NO_MENU)
+ Q_UNUSED(e);
+#else
+ QWidget *w = childAt(e->pos());
+ if (!w) {
+ w = rect().contains(e->pos()) ? this : 0;
+ if (!w)
+ return;
+ }
+ while (w && w->whatsThis().size() == 0 && !w->testAttribute(Qt::WA_CustomWhatsThis))
+ w = w->isWindow() ? 0 : w->parentWidget();
+ if (w) {
+ QWeakPointer<QMenu> p = new QMenu(this);
+ QAction *wt = p.data()->addAction(tr("What's This?"));
+ if (p.data()->exec(e->globalPos()) == wt) {
+ QHelpEvent e(QEvent::WhatsThis, w->rect().center(),
+ w->mapToGlobal(w->rect().center()));
+ QApplication::sendEvent(w, &e);
+ }
+ delete p.data();
+ }
+#endif
+}
+#endif // QT_NO_CONTEXTMENU
+
+/*! \reimp */
+void QDialog::keyPressEvent(QKeyEvent *e)
+{
+ // Calls reject() if Escape is pressed. Simulates a button
+ // click for the default button if Enter is pressed. Move focus
+ // for the arrow keys. Ignore the rest.
+#ifdef Q_WS_MAC
+ if(e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period) {
+ reject();
+ } else
+#endif
+ if (!e->modifiers() || (e->modifiers() & Qt::KeypadModifier && e->key() == Qt::Key_Enter)) {
+ switch (e->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return: {
+ QList<QPushButton*> list = findChildren<QPushButton*>();
+ for (int i=0; i<list.size(); ++i) {
+ QPushButton *pb = list.at(i);
+ if (pb->isDefault() && pb->isVisible()) {
+ if (pb->isEnabled())
+ pb->click();
+ return;
+ }
+ }
+ }
+ break;
+ case Qt::Key_Escape:
+ reject();
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ } else {
+ e->ignore();
+ }
+}
+
+/*! \reimp */
+void QDialog::closeEvent(QCloseEvent *e)
+{
+#ifndef QT_NO_WHATSTHIS
+ if (isModal() && QWhatsThis::inWhatsThisMode())
+ QWhatsThis::leaveWhatsThisMode();
+#endif
+ if (isVisible()) {
+ QPointer<QObject> that = this;
+ reject();
+ if (that && isVisible())
+ e->ignore();
+ } else {
+ e->accept();
+ }
+}
+
+/*****************************************************************************
+ Geometry management.
+ *****************************************************************************/
+
+/*! \reimp
+*/
+
+void QDialog::setVisible(bool visible)
+{
+ Q_D(QDialog);
+ if (visible) {
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
+ return;
+
+ if (!testAttribute(Qt::WA_Moved)) {
+ Qt::WindowStates state = windowState();
+ adjustPosition(parentWidget());
+ setAttribute(Qt::WA_Moved, false); // not really an explicit position
+ if (state != windowState())
+ setWindowState(state);
+ }
+ QWidget::setVisible(visible);
+ showExtension(d->doShowExtension);
+ QWidget *fw = window()->focusWidget();
+ if (!fw)
+ fw = this;
+
+ /*
+ The following block is to handle a special case, and does not
+ really follow propper logic in concern of autoDefault and TAB
+ order. However, it's here to ease usage for the users. If a
+ dialog has a default QPushButton, and first widget in the TAB
+ order also is a QPushButton, then we give focus to the main
+ default QPushButton. This simplifies code for the developers,
+ and actually catches most cases... If not, then they simply
+ have to use [widget*]->setFocus() themselves...
+ */
+ if (d->mainDef && fw->focusPolicy() == Qt::NoFocus) {
+ QWidget *first = fw;
+ while ((first = first->nextInFocusChain()) != fw && first->focusPolicy() == Qt::NoFocus)
+ ;
+ if (first != d->mainDef && qobject_cast<QPushButton*>(first))
+ d->mainDef->setFocus();
+ }
+ if (!d->mainDef && isWindow()) {
+ QWidget *w = fw;
+ while ((w = w->nextInFocusChain()) != fw) {
+ QPushButton *pb = qobject_cast<QPushButton *>(w);
+ if (pb && pb->autoDefault() && pb->focusPolicy() != Qt::NoFocus) {
+ pb->setDefault(true);
+ break;
+ }
+ }
+ }
+ if (fw && !fw->hasFocus()) {
+ QFocusEvent e(QEvent::FocusIn, Qt::TabFocusReason);
+ QApplication::sendEvent(fw, &e);
+ }
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::DialogStart);
+#endif
+
+ } else {
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
+ return;
+
+#ifndef QT_NO_ACCESSIBILITY
+ if (isVisible())
+ QAccessible::updateAccessibility(this, 0, QAccessible::DialogEnd);
+#endif
+
+ // Reimplemented to exit a modal event loop when the dialog is hidden.
+ QWidget::setVisible(visible);
+ if (d->eventLoop)
+ d->eventLoop->exit();
+ }
+#ifdef Q_WS_WIN
+ if (d->mainDef && isActiveWindow()) {
+ BOOL snapToDefault = false;
+ if (SystemParametersInfo(SPI_GETSNAPTODEFBUTTON, 0, &snapToDefault, 0)) {
+ if (snapToDefault)
+ QCursor::setPos(d->mainDef->mapToGlobal(d->mainDef->rect().center()));
+ }
+ }
+#endif
+}
+
+/*!\reimp */
+void QDialog::showEvent(QShowEvent *event)
+{
+ if (!event->spontaneous() && !testAttribute(Qt::WA_Moved)) {
+ Qt::WindowStates state = windowState();
+ adjustPosition(parentWidget());
+ setAttribute(Qt::WA_Moved, false); // not really an explicit position
+ if (state != windowState())
+ setWindowState(state);
+ }
+}
+
+/*! \internal */
+void QDialog::adjustPosition(QWidget* w)
+{
+#ifdef Q_WS_X11
+ // if the WM advertises that it will place the windows properly for us, let it do it :)
+ if (X11->isSupportedByWM(ATOM(_NET_WM_FULL_PLACEMENT)))
+ return;
+#endif
+
+#ifdef Q_OS_SYMBIAN
+ if (symbianAdjustedPosition())
+ //dialog has already been positioned
+ return;
+#endif
+
+ QPoint p(0, 0);
+ int extraw = 0, extrah = 0, scrn = 0;
+ if (w)
+ w = w->window();
+ QRect desk;
+ if (w) {
+ scrn = QApplication::desktop()->screenNumber(w);
+ } else if (QApplication::desktop()->isVirtualDesktop()) {
+ scrn = QApplication::desktop()->screenNumber(QCursor::pos());
+ } else {
+ scrn = QApplication::desktop()->screenNumber(this);
+ }
+ desk = QApplication::desktop()->availableGeometry(scrn);
+
+ QWidgetList list = QApplication::topLevelWidgets();
+ for (int i = 0; (extraw == 0 || extrah == 0) && i < list.size(); ++i) {
+ QWidget * current = list.at(i);
+ if (current->isVisible()) {
+ int framew = current->geometry().x() - current->x();
+ int frameh = current->geometry().y() - current->y();
+
+ extraw = qMax(extraw, framew);
+ extrah = qMax(extrah, frameh);
+ }
+ }
+
+ // sanity check for decoration frames. With embedding, we
+ // might get extraordinary values
+ if (extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40) {
+ extrah = 40;
+ extraw = 10;
+ }
+
+
+ if (w) {
+ // Use mapToGlobal rather than geometry() in case w might
+ // be embedded in another application
+ QPoint pp = w->mapToGlobal(QPoint(0,0));
+ p = QPoint(pp.x() + w->width()/2,
+ pp.y() + w->height()/ 2);
+ } else {
+ // p = middle of the desktop
+ p = QPoint(desk.x() + desk.width()/2, desk.y() + desk.height()/2);
+ }
+
+ // p = origin of this
+ p = QPoint(p.x()-width()/2 - extraw,
+ p.y()-height()/2 - extrah);
+
+
+ if (p.x() + extraw + width() > desk.x() + desk.width())
+ p.setX(desk.x() + desk.width() - width() - extraw);
+ if (p.x() < desk.x())
+ p.setX(desk.x());
+
+ if (p.y() + extrah + height() > desk.y() + desk.height())
+ p.setY(desk.y() + desk.height() - height() - extrah);
+ if (p.y() < desk.y())
+ p.setY(desk.y());
+
+ move(p);
+}
+
+#if defined(Q_OS_SYMBIAN)
+/*! \internal */
+bool QDialog::symbianAdjustedPosition()
+{
+#if defined(Q_WS_S60)
+ QPoint p;
+ QPoint oldPos = pos();
+ if (isFullScreen()) {
+ p.setX(0);
+ p.setY(0);
+ } else if (isMaximized()) {
+ TRect statusPaneRect = TRect();
+ if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStatusPane, statusPaneRect);
+ } else {
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, statusPaneRect);
+ }
+
+ p.setX(0);
+ p.setY(statusPaneRect.Height());
+ } else {
+ // naive way to deduce screen orientation
+ if (S60->screenHeightInPixels > S60->screenWidthInPixels) {
+ int cbaHeight;
+ TRect rect;
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, rect);
+ cbaHeight = rect.Height();
+ p.setY(S60->screenHeightInPixels - height() - cbaHeight);
+ p.setX(0);
+ } else {
+ const int scrollbarWidth = style()->pixelMetric(QStyle::PM_ScrollBarExtent);
+ TRect staConTopRect = TRect();
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, staConTopRect);
+ if (staConTopRect.IsEmpty()) {
+ TRect cbaRect = TRect();
+ AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EControlPane, cbaRect);
+ AknLayoutUtils::TAknCbaLocation cbaLocation = AknLayoutUtils::CbaLocation();
+ switch (cbaLocation) {
+ case AknLayoutUtils::EAknCbaLocationBottom:
+ p.setY(S60->screenHeightInPixels - height() - cbaRect.Height());
+ p.setX((S60->screenWidthInPixels - width()) >> 1);
+ break;
+ case AknLayoutUtils::EAknCbaLocationRight:
+ p.setY((S60->screenHeightInPixels - height()) >> 1);
+ p.setX(qMax(0,S60->screenWidthInPixels - width() - scrollbarWidth - cbaRect.Width()));
+ break;
+ case AknLayoutUtils::EAknCbaLocationLeft:
+ p.setY((S60->screenHeightInPixels - height()) >> 1);
+ p.setX(qMax(0,scrollbarWidth + cbaRect.Width()));
+ break;
+ }
+ } else {
+ p.setY((S60->screenHeightInPixels - height()) >> 1);
+ p.setX(qMax(0,S60->screenWidthInPixels - width()));
+ }
+ }
+ }
+ if (oldPos != p || p.y() < 0)
+ move(p);
+ return true;
+#else
+ // TODO - check positioning requirement for Symbian, non-s60
+ return false;
+#endif
+}
+#endif
+
+/*!
+ \obsolete
+
+ If \a orientation is Qt::Horizontal, the extension will be displayed
+ to the right of the dialog's main area. If \a orientation is
+ Qt::Vertical, the extension will be displayed below the dialog's main
+ area.
+
+ Instead of using this functionality, we recommend that you simply call
+ show() or hide() on the part of the dialog that you want to use as an
+ extension. See the \l{Extension Example} for details.
+
+ \sa setExtension()
+*/
+void QDialog::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QDialog);
+ d->orientation = orientation;
+}
+
+/*!
+ \obsolete
+
+ Returns the dialog's extension orientation.
+
+ Instead of using this functionality, we recommend that you simply call
+ show() or hide() on the part of the dialog that you want to use as an
+ extension. See the \l{Extension Example} for details.
+
+ \sa extension()
+*/
+Qt::Orientation QDialog::orientation() const
+{
+ Q_D(const QDialog);
+ return d->orientation;
+}
+
+/*!
+ \obsolete
+
+ Sets the widget, \a extension, to be the dialog's extension,
+ deleting any previous extension. The dialog takes ownership of the
+ extension. Note that if 0 is passed any existing extension will be
+ deleted. This function must only be called while the dialog is hidden.
+
+ Instead of using this functionality, we recommend that you simply call
+ show() or hide() on the part of the dialog that you want to use as an
+ extension. See the \l{Extension Example} for details.
+
+ \sa showExtension(), setOrientation()
+*/
+void QDialog::setExtension(QWidget* extension)
+{
+ Q_D(QDialog);
+ delete d->extension;
+ d->extension = extension;
+
+ if (!extension)
+ return;
+
+ if (extension->parentWidget() != this)
+ extension->setParent(this);
+ extension->hide();
+}
+
+/*!
+ \obsolete
+
+ Returns the dialog's extension or 0 if no extension has been
+ defined.
+
+ Instead of using this functionality, we recommend that you simply call
+ show() or hide() on the part of the dialog that you want to use as an
+ extension. See the \l{Extension Example} for details.
+
+ \sa showExtension(), setOrientation()
+*/
+QWidget* QDialog::extension() const
+{
+ Q_D(const QDialog);
+ return d->extension;
+}
+
+
+/*!
+ \obsolete
+
+ If \a showIt is true, the dialog's extension is shown; otherwise the
+ extension is hidden.
+
+ Instead of using this functionality, we recommend that you simply call
+ show() or hide() on the part of the dialog that you want to use as an
+ extension. See the \l{Extension Example} for details.
+
+ \sa show(), setExtension(), setOrientation()
+*/
+void QDialog::showExtension(bool showIt)
+{
+ Q_D(QDialog);
+ d->doShowExtension = showIt;
+ if (!d->extension)
+ return;
+ if (!testAttribute(Qt::WA_WState_Visible))
+ return;
+ if (d->extension->isVisible() == showIt)
+ return;
+
+ if (showIt) {
+ d->size = size();
+ d->min = minimumSize();
+ d->max = maximumSize();
+ if (layout())
+ layout()->setEnabled(false);
+ QSize s(d->extension->sizeHint()
+ .expandedTo(d->extension->minimumSize())
+ .boundedTo(d->extension->maximumSize()));
+ if (d->orientation == Qt::Horizontal) {
+ int h = qMax(height(), s.height());
+ d->extension->setGeometry(width(), 0, s.width(), h);
+ setFixedSize(width() + s.width(), h);
+ } else {
+ int w = qMax(width(), s.width());
+ d->extension->setGeometry(0, height(), w, s.height());
+ setFixedSize(w, height() + s.height());
+ }
+ d->extension->show();
+#ifndef QT_NO_SIZEGRIP
+ const bool sizeGripEnabled = isSizeGripEnabled();
+ setSizeGripEnabled(false);
+ d->sizeGripEnabled = sizeGripEnabled;
+#endif
+ } else {
+ d->extension->hide();
+ // workaround for CDE window manager that won't shrink with (-1,-1)
+ setMinimumSize(d->min.expandedTo(QSize(1, 1)));
+ setMaximumSize(d->max);
+ resize(d->size);
+ if (layout())
+ layout()->setEnabled(true);
+#ifndef QT_NO_SIZEGRIP
+ setSizeGripEnabled(d->sizeGripEnabled);
+#endif
+ }
+}
+
+
+/*! \reimp */
+QSize QDialog::sizeHint() const
+{
+ Q_D(const QDialog);
+ if (d->extension) {
+ if (d->orientation == Qt::Horizontal)
+ return QSize(QWidget::sizeHint().width(),
+ qMax(QWidget::sizeHint().height(),d->extension->sizeHint().height()));
+ else
+ return QSize(qMax(QWidget::sizeHint().width(), d->extension->sizeHint().width()),
+ QWidget::sizeHint().height());
+ }
+#if defined(Q_WS_S60)
+ // if size is not fixed, try to adjust it according to S60 layoutting
+ if (minimumSize() != maximumSize()) {
+ // In S60, dialogs are always the width of screen (in portrait, regardless of current layout)
+ return QSize(qMin(S60->screenHeightInPixels, S60->screenWidthInPixels), QWidget::sizeHint().height());
+ } else {
+ return QWidget::sizeHint();
+ }
+#else
+ return QWidget::sizeHint();
+#endif //Q_WS_S60
+}
+
+
+/*! \reimp */
+QSize QDialog::minimumSizeHint() const
+{
+ Q_D(const QDialog);
+ if (d->extension) {
+ if (d->orientation == Qt::Horizontal)
+ return QSize(QWidget::minimumSizeHint().width(),
+ qMax(QWidget::minimumSizeHint().height(), d->extension->minimumSizeHint().height()));
+ else
+ return QSize(qMax(QWidget::minimumSizeHint().width(), d->extension->minimumSizeHint().width()),
+ QWidget::minimumSizeHint().height());
+ }
+
+ return QWidget::minimumSizeHint();
+}
+
+/*!
+ \property QDialog::modal
+ \brief whether show() should pop up the dialog as modal or modeless
+
+ By default, this property is false and show() pops up the dialog
+ as modeless. Setting his property to true is equivalent to setting
+ QWidget::windowModality to Qt::ApplicationModal.
+
+ exec() ignores the value of this property and always pops up the
+ dialog as modal.
+
+ \sa QWidget::windowModality, show(), exec()
+*/
+
+void QDialog::setModal(bool modal)
+{
+ setAttribute(Qt::WA_ShowModal, modal);
+}
+
+
+bool QDialog::isSizeGripEnabled() const
+{
+#ifndef QT_NO_SIZEGRIP
+ Q_D(const QDialog);
+ return !!d->resizer;
+#else
+ return false;
+#endif
+}
+
+
+void QDialog::setSizeGripEnabled(bool enabled)
+{
+#ifdef QT_NO_SIZEGRIP
+ Q_UNUSED(enabled);
+#else
+ Q_D(QDialog);
+#ifndef QT_NO_SIZEGRIP
+ d->sizeGripEnabled = enabled;
+ if (enabled && d->doShowExtension)
+ return;
+#endif
+ if (!enabled != !d->resizer) {
+ if (enabled) {
+ d->resizer = new QSizeGrip(this);
+ // adjustSize() processes all events, which is suboptimal
+ d->resizer->resize(d->resizer->sizeHint());
+ if (isRightToLeft())
+ d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
+ else
+ d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
+ d->resizer->raise();
+ d->resizer->show();
+ } else {
+ delete d->resizer;
+ d->resizer = 0;
+ }
+ }
+#endif //QT_NO_SIZEGRIP
+}
+
+
+
+/*! \reimp */
+void QDialog::resizeEvent(QResizeEvent *)
+{
+#ifndef QT_NO_SIZEGRIP
+ Q_D(QDialog);
+ if (d->resizer) {
+ if (isRightToLeft())
+ d->resizer->move(rect().bottomLeft() -d->resizer->rect().bottomLeft());
+ else
+ d->resizer->move(rect().bottomRight() -d->resizer->rect().bottomRight());
+ d->resizer->raise();
+ }
+#endif
+}
+
+/*! \fn void QDialog::finished(int result)
+ \since 4.1
+
+ This signal is emitted when the dialog's \a result code has been
+ set, either by the user or by calling done(), accept(), or
+ reject().
+
+ Note that this signal is \e not emitted when hiding the dialog
+ with hide() or setVisible(false). This includes deleting the
+ dialog while it is visible.
+
+ \sa accepted(), rejected()
+*/
+
+/*! \fn void QDialog::accepted()
+ \since 4.1
+
+ This signal is emitted when the dialog has been accepted either by
+ the user or by calling accept() or done() with the
+ QDialog::Accepted argument.
+
+ Note that this signal is \e not emitted when hiding the dialog
+ with hide() or setVisible(false). This includes deleting the
+ dialog while it is visible.
+
+ \sa finished(), rejected()
+*/
+
+/*! \fn void QDialog::rejected()
+ \since 4.1
+
+ This signal is emitted when the dialog has been rejected either by
+ the user or by calling reject() or done() with the
+ QDialog::Rejected argument.
+
+ Note that this signal is \e not emitted when hiding the dialog
+ with hide() or setVisible(false). This includes deleting the
+ dialog while it is visible.
+
+ \sa finished(), accepted()
+*/
+
+QT_END_NAMESPACE
+#include "moc_qdialog.cpp"
diff --git a/src/widgets/dialogs/qdialog.h b/src/widgets/dialogs/qdialog.h
new file mode 100644
index 0000000000..ce8aa91bc7
--- /dev/null
+++ b/src/widgets/dialogs/qdialog.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIALOG_H
+#define QDIALOG_H
+
+#include <QtWidgets/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QPushButton;
+class QDialogPrivate;
+
+class Q_WIDGETS_EXPORT QDialog : public QWidget
+{
+ Q_OBJECT
+ friend class QPushButton;
+
+ Q_PROPERTY(bool sizeGripEnabled READ isSizeGripEnabled WRITE setSizeGripEnabled)
+ Q_PROPERTY(bool modal READ isModal WRITE setModal)
+
+public:
+ explicit QDialog(QWidget *parent = 0, Qt::WindowFlags f = 0);
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QDialog(QWidget *parent, const char *name, bool modal = false,
+ Qt::WindowFlags f = 0);
+#endif
+ ~QDialog();
+
+ enum DialogCode { Rejected, Accepted };
+
+ int result() const;
+
+ void setVisible(bool visible);
+
+ void setOrientation(Qt::Orientation orientation);
+ Qt::Orientation orientation() const;
+
+ void setExtension(QWidget* extension);
+ QWidget* extension() const;
+
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+ void setSizeGripEnabled(bool);
+ bool isSizeGripEnabled() const;
+
+ void setModal(bool modal);
+ void setResult(int r);
+
+Q_SIGNALS:
+ void finished(int result);
+ void accepted();
+ void rejected();
+
+public Q_SLOTS:
+ void open();
+ int exec();
+ virtual void done(int);
+ virtual void accept();
+ virtual void reject();
+
+ void showExtension(bool);
+
+protected:
+ QDialog(QDialogPrivate &, QWidget *parent, Qt::WindowFlags f = 0);
+
+#if defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
+ bool event(QEvent *e);
+#endif
+ void keyPressEvent(QKeyEvent *);
+ void closeEvent(QCloseEvent *);
+ void showEvent(QShowEvent *);
+ void resizeEvent(QResizeEvent *);
+#ifndef QT_NO_CONTEXTMENU
+ void contextMenuEvent(QContextMenuEvent *);
+#endif
+ bool eventFilter(QObject *, QEvent *);
+ void adjustPosition(QWidget*);
+private:
+ Q_DECLARE_PRIVATE(QDialog)
+ Q_DISABLE_COPY(QDialog)
+
+#if defined(Q_OS_SYMBIAN)
+ bool symbianAdjustedPosition();
+#endif
+
+
+#ifdef Q_WS_WINCE_WM
+ Q_PRIVATE_SLOT(d_func(), void _q_doneAction())
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDIALOG_H
diff --git a/src/widgets/dialogs/qdialog_p.h b/src/widgets/dialogs/qdialog_p.h
new file mode 100644
index 0000000000..3ee88f4703
--- /dev/null
+++ b/src/widgets/dialogs/qdialog_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIALOG_P_H
+#define QDIALOG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qwidget_p.h"
+#include "QtCore/qeventloop.h"
+#include "QtCore/qpointer.h"
+#include "QtWidgets/qdialog.h"
+#include "QtWidgets/qpushbutton.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSizeGrip;
+
+class QDialogPrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QDialog)
+public:
+
+ QDialogPrivate()
+ : mainDef(0), orientation(Qt::Horizontal),extension(0), doShowExtension(false),
+#ifndef QT_NO_SIZEGRIP
+ resizer(0),
+ sizeGripEnabled(false),
+#endif
+ rescode(0), resetModalityTo(-1), wasModalitySet(true), eventLoop(0)
+ {}
+
+ QPointer<QPushButton> mainDef;
+ Qt::Orientation orientation;
+ QWidget *extension;
+ bool doShowExtension;
+ QSize size, min, max;
+#ifndef QT_NO_SIZEGRIP
+ QSizeGrip *resizer;
+ bool sizeGripEnabled;
+#endif
+ QPoint lastRMBPress;
+
+ void setDefault(QPushButton *);
+ void setMainDefault(QPushButton *);
+ void hideDefault();
+ void resetModalitySetByOpen();
+
+#ifdef Q_WS_WINCE_WM
+ void _q_doneAction();
+#endif
+
+#ifdef Q_WS_MAC
+ virtual void mac_nativeDialogModalHelp() {}
+#endif
+
+ int rescode;
+ int resetModalityTo;
+ bool wasModalitySet;
+
+ QPointer<QEventLoop> eventLoop;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDIALOG_P_H
diff --git a/src/widgets/dialogs/qdialogsbinarycompat_win.cpp b/src/widgets/dialogs/qdialogsbinarycompat_win.cpp
new file mode 100644
index 0000000000..09c96eaafd
--- /dev/null
+++ b/src/widgets/dialogs/qdialogsbinarycompat_win.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qglobal.h>
+
+// ### Qt 5: eliminate this file
+
+/*
+ This is evil. MSVC doesn't let us remove private symbols, nor change their
+ visibility; yet there are some symbols we really needed to make public, e.g.,
+ ~QColorDialog(), and then there were some totally needless symbols in our
+ header files, e.g., setSelectedAlpha(). So we define a new version of
+ QColorDialog & Co. with only the private symbols that we removed from the
+ public header files. The friends are there only to prevent potential compiler
+ warnings.
+
+ It would have been nicer to export the missing symbols as mangled "C" symbols
+ instead but unfortunately MSVC uses out-of-reach characters like @ and . in
+ their mangled C++ symbols.
+*/
+
+#if QT_VERSION < 0x050000 && defined(Q_CC_MSVC)
+
+QT_BEGIN_NAMESPACE
+
+#include <QtGui/QColor>
+#include <QtGui/QFont>
+
+class QColorDialogPrivate;
+class QFontDialogPrivate;
+class QInputDialogPrivate;
+class QWidget;
+
+class Q_WIDGETS_EXPORT QColorDialog
+{
+private:
+ explicit QColorDialog(QWidget *, bool);
+ ~QColorDialog();
+
+ void setColor(const QColor &);
+ QColor color() const;
+ bool selectColor(const QColor &);
+ void setSelectedAlpha(int);
+ int selectedAlpha() const;
+
+ friend class QColorDialogPrivate;
+};
+
+QColorDialog::QColorDialog(QWidget *, bool) {}
+QColorDialog::~QColorDialog() {}
+void QColorDialog::setColor(const QColor &) {}
+QColor QColorDialog::color() const { return QColor(); }
+bool QColorDialog::selectColor(const QColor &) { return false; }
+void QColorDialog::setSelectedAlpha(int) {}
+int QColorDialog::selectedAlpha() const { return 0; }
+
+class Q_WIDGETS_EXPORT QFontDialog
+{
+private:
+ explicit QFontDialog(QWidget *, bool, Qt::WindowFlags);
+ ~QFontDialog();
+
+ QFont font() const;
+ void setFont(const QFont &);
+ void updateFamilies();
+ void updateStyles();
+ void updateSizes();
+
+ static QFont getFont(bool *, const QFont *, QWidget *);
+
+ friend class QFontDialogPrivate;
+};
+
+QFontDialog::QFontDialog(QWidget *, bool, Qt::WindowFlags) {}
+QFontDialog::~QFontDialog() {}
+QFont QFontDialog::font() const { return QFont(); }
+void QFontDialog::setFont(const QFont &) { }
+void QFontDialog::updateFamilies() {}
+void QFontDialog::updateStyles() {}
+void QFontDialog::updateSizes() {}
+QFont QFontDialog::getFont(bool *, const QFont *, QWidget *) { return QFont(); }
+
+class Q_WIDGETS_EXPORT QInputDialog
+{
+private:
+ enum Type { LineEdit, SpinBox, DoubleSpinBox, ComboBox, EditableComboBox };
+
+ QInputDialog(const QString &, QWidget *, Type, Qt::WindowFlags);
+ QInputDialog(const QString &, const QString &, QWidget *, QWidget *, Qt::WindowFlags);
+ ~QInputDialog();
+};
+
+QInputDialog::QInputDialog(const QString &, QWidget *, Type, Qt::WindowFlags) {}
+QInputDialog::QInputDialog(const QString &, const QString &, QWidget *, QWidget *, Qt::WindowFlags) {}
+QInputDialog::~QInputDialog() {}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qerrormessage.cpp b/src/widgets/dialogs/qerrormessage.cpp
new file mode 100644
index 0000000000..890e6ca6b7
--- /dev/null
+++ b/src/widgets/dialogs/qerrormessage.cpp
@@ -0,0 +1,429 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $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>
+#endif
+#ifdef Q_WS_S60
+#include "private/qt_s60_p.h"
+#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
diff --git a/src/widgets/dialogs/qerrormessage.h b/src/widgets/dialogs/qerrormessage.h
new file mode 100644
index 0000000000..a8805a2372
--- /dev/null
+++ b/src/widgets/dialogs/qerrormessage.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QERRORMESSAGE_H
+#define QERRORMESSAGE_H
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ERRORMESSAGE
+
+class QErrorMessagePrivate;
+
+class Q_WIDGETS_EXPORT QErrorMessage: public QDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QErrorMessage)
+public:
+ explicit QErrorMessage(QWidget* parent = 0);
+ ~QErrorMessage();
+
+ static QErrorMessage * qtHandler();
+
+public Q_SLOTS:
+ void showMessage(const QString &message);
+ void showMessage(const QString &message, const QString &type);
+#ifdef QT3_SUPPORT
+ inline QT_MOC_COMPAT void message(const QString &text) { showMessage(text); }
+#endif
+
+protected:
+ void done(int);
+ void changeEvent(QEvent *e);
+
+private:
+ Q_DISABLE_COPY(QErrorMessage)
+};
+
+#endif // QT_NO_ERRORMESSAGE
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QERRORMESSAGE_H
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
new file mode 100644
index 0000000000..9d6e348b0d
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -0,0 +1,3555 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qvariant.h>
+#include <private/qwidgetitemdata_p.h>
+#include "qfiledialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+#include "qfiledialog_p.h"
+#include <qfontmetrics.h>
+#include <qaction.h>
+#include <qheaderview.h>
+#include <qshortcut.h>
+#include <qgridlayout.h>
+#include <qmenu.h>
+#include <qmessagebox.h>
+#include <qinputdialog.h>
+#include <stdlib.h>
+#include <qsettings.h>
+#include <qdebug.h>
+#include <qapplication.h>
+#include <qstylepainter.h>
+#if !defined(Q_WS_WINCE) && !defined(Q_OS_SYMBIAN)
+#include "ui_qfiledialog.h"
+#else
+#define Q_EMBEDDED_SMALLSCREEN
+#include "ui_qfiledialog_embedded.h"
+#if defined(Q_OS_WINCE)
+extern bool qt_priv_ptr_valid;
+#endif
+#if defined(Q_OS_UNIX)
+#include <pwd.h>
+#endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QString, lastVisitedDir)
+
+/*
+ \internal
+
+ Exported hooks that can be used to customize the static functions.
+ */
+typedef QString (*_qt_filedialog_existing_directory_hook)(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options);
+Q_WIDGETS_EXPORT _qt_filedialog_existing_directory_hook qt_filedialog_existing_directory_hook = 0;
+
+typedef QString (*_qt_filedialog_open_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
+Q_WIDGETS_EXPORT _qt_filedialog_open_filename_hook qt_filedialog_open_filename_hook = 0;
+
+typedef QStringList (*_qt_filedialog_open_filenames_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
+Q_WIDGETS_EXPORT _qt_filedialog_open_filenames_hook qt_filedialog_open_filenames_hook = 0;
+
+typedef QString (*_qt_filedialog_save_filename_hook)(QWidget * parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options);
+Q_WIDGETS_EXPORT _qt_filedialog_save_filename_hook qt_filedialog_save_filename_hook = 0;
+
+/*!
+ \class QFileDialog
+ \brief The QFileDialog class provides a dialog that allow users to select files or directories.
+ \ingroup standard-dialogs
+
+
+ The QFileDialog class enables a user to traverse the file system in
+ order to select one or many files or a directory.
+
+ The easiest way to create a QFileDialog is to use the static
+ functions. On Windows, Mac OS X, KDE and GNOME, these static functions will
+ call the native file dialog when possible.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 0
+
+ In the above example, a modal QFileDialog is created using a static
+ function. The dialog initially displays the contents of the "/home/jana"
+ directory, and displays files matching the patterns given in the
+ string "Image Files (*.png *.jpg *.bmp)". The parent of the file dialog
+ is set to \e this, and the window title is set to "Open Image".
+
+ If you want to use multiple filters, separate each one with
+ \e two semicolons. For example:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 1
+
+ You can create your own QFileDialog without using the static
+ functions. By calling setFileMode(), you can specify what the user must
+ select in the dialog:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 2
+
+ In the above example, the mode of the file dialog is set to
+ AnyFile, meaning that the user can select any file, or even specify a
+ file that doesn't exist. This mode is useful for creating a
+ "Save As" file dialog. Use ExistingFile if the user must select an
+ existing file, or \l Directory if only a directory may be selected.
+ See the \l QFileDialog::FileMode enum for the complete list of modes.
+
+ The fileMode property contains the mode of operation for the dialog;
+ this indicates what types of objects the user is expected to select.
+ Use setNameFilter() to set the dialog's file filter. For example:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 3
+
+ In the above example, the filter is set to \c{"Images (*.png *.xpm *.jpg)"},
+ this means that only files with the extension \c png, \c xpm,
+ or \c jpg will be shown in the QFileDialog. You can apply
+ several filters by using setNameFilters(). Use selectNameFilter() to select
+ one of the filters you've given as the file dialog's default filter.
+
+ The file dialog has two view modes: \l{QFileDialog::}{List} and
+ \l{QFileDialog::}{Detail}.
+ \l{QFileDialog::}{List} presents the contents of the current directory
+ as a list of file and directory names. \l{QFileDialog::}{Detail} also
+ displays a list of file and directory names, but provides additional
+ information alongside each name, such as the file size and modification
+ date. Set the mode with setViewMode():
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 4
+
+ The last important function you will need to use when creating your
+ own file dialog is selectedFiles().
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 5
+
+ In the above example, a modal file dialog is created and shown. If
+ the user clicked OK, the file they selected is put in \c fileName.
+
+ The dialog's working directory can be set with setDirectory().
+ Each file in the current directory can be selected using
+ the selectFile() function.
+
+ The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
+ how to use QFileDialog as well as other built-in Qt dialogs.
+
+ \sa QDir, QFileInfo, QFile, QPrintDialog, QColorDialog, QFontDialog, {Standard Dialogs Example},
+ {Application Example}
+*/
+
+/*!
+ \enum QFileDialog::AcceptMode
+
+ \value AcceptOpen
+ \value AcceptSave
+*/
+
+/*!
+ \enum QFileDialog::ViewMode
+
+ This enum describes the view mode of the file dialog; i.e. what
+ information about each file will be displayed.
+
+ \value Detail Displays an icon, a name, and details for each item in
+ the directory.
+ \value List Displays only an icon and a name for each item in the
+ directory.
+
+ \sa setViewMode()
+*/
+
+/*!
+ \enum QFileDialog::FileMode
+
+ This enum is used to indicate what the user may select in the file
+ dialog; i.e. what the dialog will return if the user clicks OK.
+
+ \value AnyFile The name of a file, whether it exists or not.
+ \value ExistingFile The name of a single existing file.
+ \value Directory The name of a directory. Both files and
+ directories are displayed.
+ \value ExistingFiles The names of zero or more existing files.
+
+ This value is obsolete since Qt 4.5:
+
+ \value DirectoryOnly Use \c Directory and setOption(ShowDirsOnly, true) instead.
+
+ \sa setFileMode()
+*/
+
+/*!
+ \enum QFileDialog::Option
+
+ \value ShowDirsOnly Only show directories in the file dialog. By
+ default both files and directories are shown. (Valid only in the
+ \l Directory file mode.)
+
+ \value DontResolveSymlinks Don't resolve symlinks in the file
+ dialog. By default symlinks are resolved.
+
+ \value DontConfirmOverwrite Don't ask for confirmation if an
+ existing file is selected. By default confirmation is requested.
+
+ \value DontUseNativeDialog Don't use the native file dialog. By
+ default, the native file dialog is used unless you use a subclass
+ of QFileDialog that contains the Q_OBJECT macro.
+
+ \value ReadOnly Indicates that the model is readonly.
+
+ \value HideNameFilterDetails Indicates if the file name filter details are
+ hidden or not.
+
+ \value DontUseSheet In previous versions of Qt, the static
+ functions would create a sheet by default if the static function
+ was given a parent. This is no longer supported and does nothing in Qt 4.5, The
+ static functions will always be an application modal dialog. If
+ you want to use sheets, use QFileDialog::open() instead.
+
+*/
+
+/*!
+ \enum QFileDialog::DialogLabel
+
+ \value LookIn
+ \value FileName
+ \value FileType
+ \value Accept
+ \value Reject
+*/
+
+/*!
+ \fn void QFileDialog::filesSelected(const QStringList &selected)
+
+ When the selection changes and the dialog is accepted, this signal is
+ emitted with the (possibly empty) list of \a selected files.
+
+ \sa currentChanged(), QDialog::Accepted
+*/
+
+
+/*!
+ \fn void QFileDialog::fileSelected(const QString &file)
+
+ When the selection changes and the dialog is accepted, this signal is
+ emitted with the (possibly empty) selected \a file.
+
+ \sa currentChanged(), QDialog::Accepted
+*/
+
+
+/*!
+ \fn void QFileDialog::currentChanged(const QString &path)
+
+ When the current file changes, this signal is emitted with the
+ new file name as the \a path parameter.
+
+ \sa filesSelected()
+*/
+
+/*!
+ \fn void QFileDialog::directoryEntered(const QString &directory)
+ \since 4.3
+
+ This signal is emitted when the user enters a \a directory.
+*/
+
+/*!
+ \fn void QFileDialog::filterSelected(const QString &filter)
+ \since 4.3
+
+ This signal is emitted when the user selects a \a filter.
+*/
+
+#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
+bool Q_WIDGETS_EXPORT qt_use_native_dialogs = true; // for the benefit of testing tools, until we have a proper API
+#endif
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#ifdef Q_WS_WIN
+#include <qwindowsstyle.h>
+#endif
+#include <qshortcut.h>
+#ifdef Q_WS_MAC
+#include <qmacstyle_mac.h>
+#endif
+QT_END_INCLUDE_NAMESPACE
+
+/*!
+ \fn QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags flags)
+
+ Constructs a file dialog with the given \a parent and widget \a flags.
+*/
+QFileDialog::QFileDialog(QWidget *parent, Qt::WindowFlags f)
+ : QDialog(*new QFileDialogPrivate, parent, f)
+{
+ Q_D(QFileDialog);
+ d->init();
+ d->lineEdit()->selectAll();
+}
+
+/*!
+ Constructs a file dialog with the given \a parent and \a caption that
+ initially displays the contents of the specified \a directory.
+ The contents of the directory are filtered before being shown in the
+ dialog, using a semicolon-separated list of filters specified by
+ \a filter.
+*/
+QFileDialog::QFileDialog(QWidget *parent,
+ const QString &caption,
+ const QString &directory,
+ const QString &filter)
+ : QDialog(*new QFileDialogPrivate, parent, 0)
+{
+ Q_D(QFileDialog);
+ d->init(directory, filter, caption);
+ d->lineEdit()->selectAll();
+}
+
+/*!
+ \internal
+*/
+QFileDialog::QFileDialog(const QFileDialogArgs &args)
+ : QDialog(*new QFileDialogPrivate, args.parent, 0)
+{
+ Q_D(QFileDialog);
+ d->init(args.directory, args.filter, args.caption);
+ setFileMode(args.mode);
+ setOptions(args.options);
+ selectFile(args.selection);
+ d->lineEdit()->selectAll();
+}
+
+/*!
+ Destroys the file dialog.
+*/
+QFileDialog::~QFileDialog()
+{
+ Q_D(QFileDialog);
+#ifndef QT_NO_SETTINGS
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ settings.beginGroup(QLatin1String("Qt"));
+ settings.setValue(QLatin1String("filedialog"), saveState());
+#endif
+ d->deleteNativeDialog_sys();
+}
+
+/*!
+ \since 4.3
+ Sets the \a urls that are located in the sidebar.
+
+ For instance:
+
+ \snippet doc/src/snippets/filedialogurls.cpp 0
+
+ The file dialog will then look like this:
+
+ \image filedialogurls.png
+
+ \sa sidebarUrls()
+*/
+void QFileDialog::setSidebarUrls(const QList<QUrl> &urls)
+{
+ Q_D(QFileDialog);
+ d->qFileDialogUi->sidebar->setUrls(urls);
+}
+
+/*!
+ \since 4.3
+ Returns a list of urls that are currently in the sidebar
+*/
+QList<QUrl> QFileDialog::sidebarUrls() const
+{
+ Q_D(const QFileDialog);
+ return d->qFileDialogUi->sidebar->urls();
+}
+
+static const qint32 QFileDialogMagic = 0xbe;
+
+const char *qt_file_dialog_filter_reg_exp =
+"^(.*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$";
+
+/*!
+ \since 4.3
+ Saves the state of the dialog's layout, history and current directory.
+
+ Typically this is used in conjunction with QSettings to remember the size
+ for a future session. A version number is stored as part of the data.
+*/
+QByteArray QFileDialog::saveState() const
+{
+ Q_D(const QFileDialog);
+ int version = 3;
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly);
+
+ stream << qint32(QFileDialogMagic);
+ stream << qint32(version);
+ stream << d->qFileDialogUi->splitter->saveState();
+ stream << d->qFileDialogUi->sidebar->urls();
+ stream << history();
+ stream << *lastVisitedDir();
+ stream << d->qFileDialogUi->treeView->header()->saveState();
+ stream << qint32(viewMode());
+ return data;
+}
+
+/*!
+ \since 4.3
+ Restores the dialogs's layout, history and current directory to the \a state specified.
+
+ Typically this is used in conjunction with QSettings to restore the size
+ from a past session.
+
+ Returns false if there are errors
+*/
+bool QFileDialog::restoreState(const QByteArray &state)
+{
+ Q_D(QFileDialog);
+ int version = 3;
+ QByteArray sd = state;
+ QDataStream stream(&sd, QIODevice::ReadOnly);
+ if (stream.atEnd())
+ return false;
+ QByteArray splitterState;
+ QByteArray headerData;
+ QList<QUrl> bookmarks;
+ QStringList history;
+ QString currentDirectory;
+ qint32 marker;
+ qint32 v;
+ qint32 viewMode;
+ stream >> marker;
+ stream >> v;
+ if (marker != QFileDialogMagic || v != version)
+ return false;
+
+ stream >> splitterState
+ >> bookmarks
+ >> history
+ >> currentDirectory
+ >> headerData
+ >> viewMode;
+
+ if (!d->qFileDialogUi->splitter->restoreState(splitterState))
+ return false;
+ QList<int> list = d->qFileDialogUi->splitter->sizes();
+ if (list.count() >= 2 && list.at(0) == 0 && list.at(1) == 0) {
+ for (int i = 0; i < list.count(); ++i)
+ list[i] = d->qFileDialogUi->splitter->widget(i)->sizeHint().width();
+ d->qFileDialogUi->splitter->setSizes(list);
+ }
+
+ d->qFileDialogUi->sidebar->setUrls(bookmarks);
+ while (history.count() > 5)
+ history.pop_front();
+ setHistory(history);
+ setDirectory(lastVisitedDir()->isEmpty() ? currentDirectory : *lastVisitedDir());
+ if (!d->qFileDialogUi->treeView->header()->restoreState(headerData))
+ return false;
+
+ setViewMode(ViewMode(viewMode));
+ return true;
+}
+
+/*!
+ \reimp
+*/
+void QFileDialog::changeEvent(QEvent *e)
+{
+ Q_D(QFileDialog);
+ if (e->type() == QEvent::LanguageChange) {
+ d->retranslateWindowTitle();
+ d->retranslateStrings();
+ }
+ QDialog::changeEvent(e);
+}
+
+QFileDialogPrivate::QFileDialogPrivate()
+ :
+#ifndef QT_NO_PROXYMODEL
+ proxyModel(0),
+#endif
+ model(0),
+ fileMode(QFileDialog::AnyFile),
+ acceptMode(QFileDialog::AcceptOpen),
+ currentHistoryLocation(-1),
+ renameAction(0),
+ deleteAction(0),
+ showHiddenAction(0),
+ useDefaultCaption(true),
+ defaultFileTypes(true),
+ fileNameLabelExplicitlySat(false),
+ nativeDialogInUse(false),
+#ifdef Q_WS_MAC
+ mDelegate(0),
+#ifndef QT_MAC_USE_COCOA
+ mDialog(0),
+ mDialogStarted(false),
+ mDialogClosed(true),
+#endif
+#endif
+ qFileDialogUi(0)
+{
+}
+
+QFileDialogPrivate::~QFileDialogPrivate()
+{
+}
+
+void QFileDialogPrivate::retranslateWindowTitle()
+{
+ Q_Q(QFileDialog);
+ if (!useDefaultCaption || setWindowTitle != q->windowTitle())
+ return;
+ if (acceptMode == QFileDialog::AcceptOpen) {
+ if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory)
+ q->setWindowTitle(QFileDialog::tr("Find Directory"));
+ else
+ q->setWindowTitle(QFileDialog::tr("Open"));
+ } else
+ q->setWindowTitle(QFileDialog::tr("Save As"));
+
+ setWindowTitle = q->windowTitle();
+}
+
+void QFileDialogPrivate::setLastVisitedDirectory(const QString &dir)
+{
+ *lastVisitedDir() = dir;
+}
+
+void QFileDialogPrivate::retranslateStrings()
+{
+ Q_Q(QFileDialog);
+ /* WIDGETS */
+ if (defaultFileTypes)
+ q->setNameFilter(QFileDialog::tr("All Files (*)"));
+
+ QList<QAction*> actions = qFileDialogUi->treeView->header()->actions();
+ QAbstractItemModel *abstractModel = model;
+#ifndef QT_NO_PROXYMODEL
+ if (proxyModel)
+ abstractModel = proxyModel;
+#endif
+ int total = qMin(abstractModel->columnCount(QModelIndex()), actions.count() + 1);
+ for (int i = 1; i < total; ++i) {
+ actions.at(i - 1)->setText(QFileDialog::tr("Show ") + abstractModel->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString());
+ }
+
+ /* MENU ACTIONS */
+ renameAction->setText(QFileDialog::tr("&Rename"));
+ deleteAction->setText(QFileDialog::tr("&Delete"));
+ showHiddenAction->setText(QFileDialog::tr("Show &hidden files"));
+ newFolderAction->setText(QFileDialog::tr("&New Folder"));
+ qFileDialogUi->retranslateUi(q);
+
+ if (!fileNameLabelExplicitlySat){
+ if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory) {
+ q->setLabelText(QFileDialog::FileName, QFileDialog::tr("Directory:"));
+ } else {
+ q->setLabelText(QFileDialog::FileName, QFileDialog::tr("File &name:"));
+ }
+ fileNameLabelExplicitlySat = false;
+ }
+}
+
+void QFileDialogPrivate::emitFilesSelected(const QStringList &files)
+{
+ Q_Q(QFileDialog);
+ emit q->filesSelected(files);
+ if (files.count() == 1)
+ emit q->fileSelected(files.first());
+}
+
+bool QFileDialogPrivate::canBeNativeDialog()
+{
+ Q_Q(QFileDialog);
+ if (nativeDialogInUse)
+ return true;
+ if (q->testAttribute(Qt::WA_DontShowOnScreen))
+ return false;
+ if (opts & QFileDialog::DontUseNativeDialog)
+ return false;
+
+ QLatin1String staticName(QFileDialog::staticMetaObject.className());
+ QLatin1String dynamicName(q->metaObject()->className());
+ return (staticName == dynamicName);
+}
+
+/*!
+ \since 4.5
+ Sets the given \a option to be enabled if \a on is true; otherwise,
+ clears the given \a option.
+
+ \sa options, testOption()
+*/
+void QFileDialog::setOption(Option option, bool on)
+{
+ Q_D(QFileDialog);
+ if (!(d->opts & option) != !on)
+ setOptions(d->opts ^ option);
+}
+
+/*!
+ \since 4.5
+
+ Returns true if the given \a option is enabled; otherwise, returns
+ false.
+
+ \sa options, setOption()
+*/
+bool QFileDialog::testOption(Option option) const
+{
+ Q_D(const QFileDialog);
+ return (d->opts & option) != 0;
+}
+
+/*!
+ \property QFileDialog::options
+ \brief the various options that affect the look and feel of the dialog
+ \since 4.5
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the
+ dialog is visible is not guaranteed to have an immediate effect on the
+ dialog (depending on the option and on the platform).
+
+ \sa setOption(), testOption()
+*/
+void QFileDialog::setOptions(Options options)
+{
+ Q_D(QFileDialog);
+
+ Options changed = (options ^ d->opts);
+ if (!changed)
+ return;
+
+ d->opts = options;
+ if (changed & DontResolveSymlinks)
+ d->model->setResolveSymlinks(!(options & DontResolveSymlinks));
+ if (changed & ReadOnly) {
+ bool ro = (options & ReadOnly);
+ d->model->setReadOnly(ro);
+ d->qFileDialogUi->newFolderButton->setEnabled(!ro);
+ d->renameAction->setEnabled(!ro);
+ d->deleteAction->setEnabled(!ro);
+ }
+ if (changed & HideNameFilterDetails)
+ setNameFilters(d->nameFilters);
+
+ if (changed & ShowDirsOnly)
+ setFilter((options & ShowDirsOnly) ? filter() & ~QDir::Files : filter() | QDir::Files);
+}
+
+QFileDialog::Options QFileDialog::options() const
+{
+ Q_D(const QFileDialog);
+ return d->opts;
+}
+
+/*!
+ \overload
+
+ \since 4.5
+
+ This function connects one of its signals to the slot specified by \a receiver
+ and \a member. The specific signal depends is filesSelected() if fileMode is
+ ExistingFiles and fileSelected() if fileMode is anything else.
+
+ The signal will be disconnected from the slot when the dialog is closed.
+*/
+void QFileDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QFileDialog);
+ const char *signal = (fileMode() == ExistingFiles) ? SIGNAL(filesSelected(QStringList))
+ : SIGNAL(fileSelected(QString));
+ connect(this, signal, receiver, member);
+ d->signalToDisconnectOnClose = signal;
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+
+ QDialog::open();
+}
+
+
+/*!
+ \reimp
+*/
+void QFileDialog::setVisible(bool visible)
+{
+ Q_D(QFileDialog);
+ if (visible){
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
+ return;
+ } else if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
+ return;
+
+ if (d->canBeNativeDialog()){
+ if (d->setVisible_sys(visible)){
+ d->nativeDialogInUse = true;
+ // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+ // updates the state correctly, but skips showing the non-native version:
+ setAttribute(Qt::WA_DontShowOnScreen);
+#ifndef QT_NO_FSCOMPLETER
+ //So the completer don't try to complete and therefore to show a popup
+ d->completer->setModel(0);
+#endif
+ } else {
+ d->nativeDialogInUse = false;
+ setAttribute(Qt::WA_DontShowOnScreen, false);
+#ifndef QT_NO_FSCOMPLETER
+ if (d->proxyModel != 0)
+ d->completer->setModel(d->proxyModel);
+ else
+ d->completer->setModel(d->model);
+#endif
+ }
+ }
+
+ if (!d->nativeDialogInUse)
+ d->qFileDialogUi->fileNameEdit->setFocus();
+
+ QDialog::setVisible(visible);
+}
+
+/*!
+ \internal
+ set the directory to url
+*/
+void QFileDialogPrivate::_q_goToUrl(const QUrl &url)
+{
+ //The shortcut in the side bar may have a parent that is not fetched yet (e.g. an hidden file)
+ //so we force the fetching
+ QFileSystemModelPrivate::QFileSystemNode *node = model->d_func()->node(url.toLocalFile(), true);
+ QModelIndex idx = model->d_func()->index(node);
+ _q_enterDirectory(idx);
+}
+
+/*!
+ \fn void QFileDialog::setDirectory(const QDir &directory)
+
+ \overload
+*/
+
+/*!
+ Sets the file dialog's current \a directory.
+*/
+void QFileDialog::setDirectory(const QString &directory)
+{
+ Q_D(QFileDialog);
+ QString newDirectory = directory;
+ QFileInfo info(directory);
+ //we remove .. and . from the given path if exist
+ if (!directory.isEmpty())
+ newDirectory = QDir::cleanPath(directory);
+
+ if (!directory.isEmpty() && newDirectory.isEmpty())
+ return;
+
+ d->setLastVisitedDirectory(newDirectory);
+
+ if (d->nativeDialogInUse){
+ d->setDirectory_sys(newDirectory);
+ return;
+ }
+ if (d->rootPath() == newDirectory)
+ return;
+ QModelIndex root = d->model->setRootPath(newDirectory);
+ d->qFileDialogUi->newFolderButton->setEnabled(d->model->flags(root) & Qt::ItemIsDropEnabled);
+ if (root != d->rootIndex()) {
+#ifndef QT_NO_FSCOMPLETER
+ if (directory.endsWith(QLatin1Char('/')))
+ d->completer->setCompletionPrefix(newDirectory);
+ else
+ d->completer->setCompletionPrefix(newDirectory + QLatin1Char('/'));
+#endif
+ d->setRootIndex(root);
+ }
+ d->qFileDialogUi->listView->selectionModel()->clear();
+}
+
+/*!
+ Returns the directory currently being displayed in the dialog.
+*/
+QDir QFileDialog::directory() const
+{
+ Q_D(const QFileDialog);
+ return QDir(d->nativeDialogInUse ? d->directory_sys() : d->rootPath());
+}
+
+/*!
+ Selects the given \a filename in the file dialog.
+
+ \sa selectedFiles()
+*/
+void QFileDialog::selectFile(const QString &filename)
+{
+ Q_D(QFileDialog);
+ if (filename.isEmpty())
+ return;
+
+ if (d->nativeDialogInUse){
+ d->selectFile_sys(filename);
+ return;
+ }
+
+ if (!QDir::isRelativePath(filename)) {
+ QFileInfo info(filename);
+ QString filenamePath = info.absoluteDir().path();
+
+ if (d->model->rootPath() != filenamePath)
+ setDirectory(filenamePath);
+ }
+
+ QModelIndex index = d->model->index(filename);
+ QString file;
+ if (!index.isValid()) {
+ // save as dialog where we want to input a default value
+ QString text = filename;
+ if (QFileInfo(filename).isAbsolute()) {
+ QString current = d->rootPath();
+ text.remove(current);
+ if (text.at(0) == QDir::separator()
+#ifdef Q_OS_WIN
+ //On Windows both cases can happen
+ || text.at(0) == QLatin1Char('/')
+#endif
+ )
+ text = text.remove(0,1);
+ }
+ file = text;
+ } else {
+ file = index.data().toString();
+ }
+ d->qFileDialogUi->listView->selectionModel()->clear();
+ if (!isVisible() || !d->lineEdit()->hasFocus())
+ d->lineEdit()->setText(file);
+}
+
+#ifdef Q_OS_UNIX
+Q_AUTOTEST_EXPORT QString qt_tildeExpansion(const QString &path, bool *expanded = 0)
+{
+ if (expanded != 0)
+ *expanded = false;
+ if (!path.startsWith(QLatin1Char('~')))
+ return path;
+ QString ret = path;
+ QStringList tokens = ret.split(QDir::separator());
+ if (tokens.first() == QLatin1String("~")) {
+ ret.replace(0, 1, QDir::homePath());
+ } else {
+ QString userName = tokens.first();
+ userName.remove(0, 1);
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
+ passwd pw;
+ passwd *tmpPw;
+ char buf[200];
+ const int bufSize = sizeof(buf);
+ int err = getpwnam_r(userName.toLocal8Bit().constData(), &pw, buf, bufSize, &tmpPw);
+ if (err || !tmpPw)
+ return ret;
+ const QString homePath = QString::fromLocal8Bit(pw.pw_dir);
+#else
+ passwd *pw = getpwnam(userName.toLocal8Bit().constData());
+ if (!pw)
+ return ret;
+ const QString homePath = QString::fromLocal8Bit(pw->pw_dir);
+#endif
+ ret.replace(0, tokens.first().length(), homePath);
+ }
+ if (expanded != 0)
+ *expanded = true;
+ return ret;
+}
+#endif
+
+/**
+ Returns the text in the line edit which can be one or more file names
+ */
+QStringList QFileDialogPrivate::typedFiles() const
+{
+ Q_Q(const QFileDialog);
+ QStringList files;
+ QString editText = lineEdit()->text();
+ if (!editText.contains(QLatin1Char('"'))) {
+#ifdef Q_OS_UNIX
+ const QString prefix = q->directory().absolutePath() + QDir::separator();
+ if (QFile::exists(prefix + editText))
+ files << editText;
+ else
+ files << qt_tildeExpansion(editText);
+#else
+ files << editText;
+#endif
+ } else {
+ // " is used to separate files like so: "file1" "file2" "file3" ...
+ // ### need escape character for filenames with quotes (")
+ QStringList tokens = editText.split(QLatin1Char('\"'));
+ for (int i=0; i<tokens.size(); ++i) {
+ if ((i % 2) == 0)
+ continue; // Every even token is a separator
+#ifdef Q_OS_UNIX
+ const QString token = tokens.at(i);
+ const QString prefix = q->directory().absolutePath() + QDir::separator();
+ if (QFile::exists(prefix + token))
+ files << token;
+ else
+ files << qt_tildeExpansion(token);
+#else
+ files << toInternal(tokens.at(i));
+#endif
+ }
+ }
+ return addDefaultSuffixToFiles(files);
+}
+
+QStringList QFileDialogPrivate::addDefaultSuffixToFiles(const QStringList filesToFix) const
+{
+ QStringList files;
+ for (int i=0; i<filesToFix.size(); ++i) {
+ QString name = toInternal(filesToFix.at(i));
+ QFileInfo info(name);
+ // if the filename has no suffix, add the default suffix
+ if (!defaultSuffix.isEmpty() && !info.isDir() && name.lastIndexOf(QLatin1Char('.')) == -1)
+ name += QLatin1Char('.') + defaultSuffix;
+ if (info.isAbsolute()) {
+ files.append(name);
+ } else {
+ // at this point the path should only have Qt path separators.
+ // This check is needed since we might be at the root directory
+ // and on Windows it already ends with slash.
+ QString path = rootPath();
+ if (!path.endsWith(QLatin1Char('/')))
+ path += QLatin1Char('/');
+ path += name;
+ files.append(path);
+ }
+ }
+ return files;
+}
+
+
+/*!
+ Returns a list of strings containing the absolute paths of the
+ selected files in the dialog. If no files are selected, or
+ the mode is not ExistingFiles or ExistingFile, selectedFiles() contains the current path in the viewport.
+
+ \sa selectedNameFilter(), selectFile()
+*/
+QStringList QFileDialog::selectedFiles() const
+{
+ Q_D(const QFileDialog);
+ if (d->nativeDialogInUse)
+ return d->addDefaultSuffixToFiles(d->selectedFiles_sys());
+
+ QModelIndexList indexes = d->qFileDialogUi->listView->selectionModel()->selectedRows();
+ QStringList files;
+ for (int i = 0; i < indexes.count(); ++i)
+ files.append(indexes.at(i).data(QFileSystemModel::FilePathRole).toString());
+
+ if (files.isEmpty() && !d->lineEdit()->text().isEmpty())
+ files = d->typedFiles();
+
+ if (files.isEmpty() && !(d->fileMode == ExistingFile || d->fileMode == ExistingFiles))
+ files.append(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
+ return files;
+}
+
+/*
+ Makes a list of filters from ;;-separated text.
+ Used by the mac and windows implementations
+*/
+QStringList qt_make_filter_list(const QString &filter)
+{
+ QString f(filter);
+
+ if (f.isEmpty())
+ return QStringList();
+
+ QString sep(QLatin1String(";;"));
+ int i = f.indexOf(sep, 0);
+ if (i == -1) {
+ if (f.indexOf(QLatin1Char('\n'), 0) != -1) {
+ sep = QLatin1Char('\n');
+ i = f.indexOf(sep, 0);
+ }
+ }
+
+ return f.split(sep);
+}
+
+/*!
+ \since 4.4
+
+ Sets the filter used in the file dialog to the given \a filter.
+
+ If \a filter contains a pair of parentheses containing one or more
+ of \bold{anything*something}, separated by spaces, then only the
+ text contained in the parentheses is used as the filter. This means
+ that these calls are all equivalent:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 6
+
+ \sa setNameFilters()
+*/
+void QFileDialog::setNameFilter(const QString &filter)
+{
+ setNameFilters(qt_make_filter_list(filter));
+}
+
+/*!
+ \obsolete
+
+ Use setNameFilter() instead.
+*/
+void QFileDialog::setFilter(const QString &filter)
+{
+ setNameFilter(filter);
+}
+
+/*!
+ \property QFileDialog::nameFilterDetailsVisible
+ \obsolete
+ \brief This property holds whether the filter details is shown or not.
+ \since 4.4
+
+ When this property is true (the default), the filter details are shown
+ in the combo box. When the property is set to false, these are hidden.
+
+ Use setOption(HideNameFilterDetails, !\e enabled) or
+ !testOption(HideNameFilterDetails).
+*/
+void QFileDialog::setNameFilterDetailsVisible(bool enabled)
+{
+ setOption(HideNameFilterDetails, !enabled);
+}
+
+bool QFileDialog::isNameFilterDetailsVisible() const
+{
+ return !testOption(HideNameFilterDetails);
+}
+
+
+/*
+ Strip the filters by removing the details, e.g. (*.*).
+*/
+QStringList qt_strip_filters(const QStringList &filters)
+{
+ QStringList strippedFilters;
+ QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
+ for (int i = 0; i < filters.count(); ++i) {
+ QString filterName;
+ int index = r.indexIn(filters[i]);
+ if (index >= 0)
+ filterName = r.cap(1);
+ strippedFilters.append(filterName.simplified());
+ }
+ return strippedFilters;
+}
+
+
+/*!
+ \since 4.4
+
+ Sets the \a filters used in the file dialog.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 7
+*/
+void QFileDialog::setNameFilters(const QStringList &filters)
+{
+ Q_D(QFileDialog);
+ d->defaultFileTypes = (filters == QStringList(QFileDialog::tr("All Files (*)")));
+ QStringList cleanedFilters;
+ for (int i = 0; i < filters.count(); ++i) {
+ cleanedFilters << filters[i].simplified();
+ }
+ d->nameFilters = cleanedFilters;
+
+ if (d->nativeDialogInUse){
+ d->setNameFilters_sys(cleanedFilters);
+ return;
+ }
+
+ d->qFileDialogUi->fileTypeCombo->clear();
+ if (cleanedFilters.isEmpty())
+ return;
+
+ if (testOption(HideNameFilterDetails))
+ d->qFileDialogUi->fileTypeCombo->addItems(qt_strip_filters(cleanedFilters));
+ else
+ d->qFileDialogUi->fileTypeCombo->addItems(cleanedFilters);
+
+ d->_q_useNameFilter(0);
+}
+
+/*!
+ \obsolete
+
+ Use setNameFilters() instead.
+*/
+void QFileDialog::setFilters(const QStringList &filters)
+{
+ setNameFilters(filters);
+}
+
+/*!
+ \since 4.4
+
+ Returns the file type filters that are in operation on this file
+ dialog.
+*/
+QStringList QFileDialog::nameFilters() const
+{
+ return d_func()->nameFilters;
+}
+
+/*!
+ \obsolete
+
+ Use nameFilters() instead.
+*/
+
+QStringList QFileDialog::filters() const
+{
+ return nameFilters();
+}
+
+/*!
+ \since 4.4
+
+ Sets the current file type \a filter. Multiple filters can be
+ passed in \a filter by separating them with semicolons or spaces.
+
+ \sa setNameFilter(), setNameFilters(), selectedNameFilter()
+*/
+void QFileDialog::selectNameFilter(const QString &filter)
+{
+ Q_D(QFileDialog);
+ if (d->nativeDialogInUse) {
+ d->selectNameFilter_sys(filter);
+ return;
+ }
+ int i;
+ if (testOption(HideNameFilterDetails)) {
+ i = d->qFileDialogUi->fileTypeCombo->findText(qt_strip_filters(qt_make_filter_list(filter)).first());
+ } else {
+ i = d->qFileDialogUi->fileTypeCombo->findText(filter);
+ }
+ if (i >= 0) {
+ d->qFileDialogUi->fileTypeCombo->setCurrentIndex(i);
+ d->_q_useNameFilter(d->qFileDialogUi->fileTypeCombo->currentIndex());
+ }
+}
+
+/*!
+ \obsolete
+
+ Use selectNameFilter() instead.
+*/
+
+void QFileDialog::selectFilter(const QString &filter)
+{
+ selectNameFilter(filter);
+}
+
+/*!
+ \since 4.4
+
+ Returns the filter that the user selected in the file dialog.
+
+ \sa selectedFiles()
+*/
+QString QFileDialog::selectedNameFilter() const
+{
+ Q_D(const QFileDialog);
+ if (d->nativeDialogInUse)
+ return d->selectedNameFilter_sys();
+
+ return d->qFileDialogUi->fileTypeCombo->currentText();
+}
+
+/*!
+ \obsolete
+
+ Use selectedNameFilter() instead.
+*/
+QString QFileDialog::selectedFilter() const
+{
+ return selectedNameFilter();
+}
+
+/*!
+ \since 4.4
+
+ Returns the filter that is used when displaying files.
+
+ \sa setFilter()
+*/
+QDir::Filters QFileDialog::filter() const
+{
+ Q_D(const QFileDialog);
+ return d->model->filter();
+}
+
+/*!
+ \since 4.4
+
+ Sets the filter used by the model to \a filters. The filter is used
+ to specify the kind of files that should be shown.
+
+ \sa filter()
+*/
+
+void QFileDialog::setFilter(QDir::Filters filters)
+{
+ Q_D(QFileDialog);
+ d->model->setFilter(filters);
+ if (d->nativeDialogInUse){
+ d->setFilter_sys();
+ return;
+ }
+
+ d->showHiddenAction->setChecked((filters & QDir::Hidden));
+}
+
+/*!
+ \property QFileDialog::viewMode
+ \brief the way files and directories are displayed in the dialog
+
+ By default, the \c Detail mode is used to display information about
+ files and directories.
+
+ \sa ViewMode
+*/
+void QFileDialog::setViewMode(QFileDialog::ViewMode mode)
+{
+ Q_D(QFileDialog);
+ if (mode == Detail)
+ d->_q_showDetailsView();
+ else
+ d->_q_showListView();
+}
+
+QFileDialog::ViewMode QFileDialog::viewMode() const
+{
+ Q_D(const QFileDialog);
+ return (d->qFileDialogUi->stackedWidget->currentWidget() == d->qFileDialogUi->listView->parent() ? QFileDialog::List : QFileDialog::Detail);
+}
+
+/*!
+ \property QFileDialog::fileMode
+ \brief the file mode of the dialog
+
+ The file mode defines the number and type of items that the user is
+ expected to select in the dialog.
+
+ By default, this property is set to AnyFile.
+
+ This function will set the labels for the FileName and
+ \l{QFileDialog::}{Accept} \l{DialogLabel}s. It is possible to set
+ custom text after the call to setFileMode().
+
+ \sa FileMode
+*/
+void QFileDialog::setFileMode(QFileDialog::FileMode mode)
+{
+ Q_D(QFileDialog);
+ d->fileMode = mode;
+ d->retranslateWindowTitle();
+
+ // keep ShowDirsOnly option in sync with fileMode (BTW, DirectoryOnly is obsolete)
+ setOption(ShowDirsOnly, mode == DirectoryOnly);
+
+ // set selection mode and behavior
+ QAbstractItemView::SelectionMode selectionMode;
+ if (mode == QFileDialog::ExistingFiles)
+ selectionMode = QAbstractItemView::ExtendedSelection;
+ else
+ selectionMode = QAbstractItemView::SingleSelection;
+ d->qFileDialogUi->listView->setSelectionMode(selectionMode);
+ d->qFileDialogUi->treeView->setSelectionMode(selectionMode);
+ // set filter
+ d->model->setFilter(d->filterForMode(filter()));
+ // setup file type for directory
+ QString buttonText = (d->acceptMode == AcceptOpen ? tr("&Open") : tr("&Save"));
+ if (mode == DirectoryOnly || mode == Directory) {
+ d->qFileDialogUi->fileTypeCombo->clear();
+ d->qFileDialogUi->fileTypeCombo->addItem(tr("Directories"));
+ d->qFileDialogUi->fileTypeCombo->setEnabled(false);
+
+ if (!d->fileNameLabelExplicitlySat){
+ setLabelText(FileName, tr("Directory:"));
+ d->fileNameLabelExplicitlySat = false;
+ }
+ buttonText = tr("&Choose");
+ } else {
+ if (!d->fileNameLabelExplicitlySat){
+ setLabelText(FileName, tr("File &name:"));
+ d->fileNameLabelExplicitlySat = false;
+ }
+ }
+ setLabelText(Accept, buttonText);
+ if (d->nativeDialogInUse){
+ d->setFilter_sys();
+ return;
+ }
+
+ d->qFileDialogUi->fileTypeCombo->setEnabled(!testOption(ShowDirsOnly));
+ d->_q_updateOkButton();
+}
+
+QFileDialog::FileMode QFileDialog::fileMode() const
+{
+ Q_D(const QFileDialog);
+ return d->fileMode;
+}
+
+/*!
+ \property QFileDialog::acceptMode
+ \brief the accept mode of the dialog
+
+ The action mode defines whether the dialog is for opening or saving files.
+
+ By default, this property is set to \l{AcceptOpen}.
+
+ \sa AcceptMode
+*/
+void QFileDialog::setAcceptMode(QFileDialog::AcceptMode mode)
+{
+ Q_D(QFileDialog);
+ d->acceptMode = mode;
+ bool directoryMode = (d->fileMode == Directory || d->fileMode == DirectoryOnly);
+ QDialogButtonBox::StandardButton button = (mode == AcceptOpen ? QDialogButtonBox::Open : QDialogButtonBox::Save);
+ d->qFileDialogUi->buttonBox->setStandardButtons(button | QDialogButtonBox::Cancel);
+ d->qFileDialogUi->buttonBox->button(button)->setEnabled(false);
+ d->_q_updateOkButton();
+ if (mode == AcceptOpen && directoryMode)
+ setLabelText(Accept, tr("&Choose"));
+ else
+ setLabelText(Accept, (mode == AcceptOpen ? tr("&Open") : tr("&Save")));
+ if (mode == AcceptSave) {
+ d->qFileDialogUi->lookInCombo->setEditable(false);
+ }
+ d->retranslateWindowTitle();
+#if defined(Q_WS_MAC)
+ d->deleteNativeDialog_sys();
+ setAttribute(Qt::WA_DontShowOnScreen, false);
+#endif
+}
+
+/*
+ Returns the file system model index that is the root index in the
+ views
+*/
+QModelIndex QFileDialogPrivate::rootIndex() const {
+ return mapToSource(qFileDialogUi->listView->rootIndex());
+}
+
+QAbstractItemView *QFileDialogPrivate::currentView() const {
+ if (!qFileDialogUi->stackedWidget)
+ return 0;
+ if (qFileDialogUi->stackedWidget->currentWidget() == qFileDialogUi->listView->parent())
+ return qFileDialogUi->listView;
+ return qFileDialogUi->treeView;
+}
+
+QLineEdit *QFileDialogPrivate::lineEdit() const {
+ return (QLineEdit*)qFileDialogUi->fileNameEdit;
+}
+
+/*
+ Sets the view root index to be the file system model index
+*/
+void QFileDialogPrivate::setRootIndex(const QModelIndex &index) const {
+ Q_ASSERT(index.isValid() ? index.model() == model : true);
+ QModelIndex idx = mapFromSource(index);
+ qFileDialogUi->treeView->setRootIndex(idx);
+ qFileDialogUi->listView->setRootIndex(idx);
+}
+/*
+ Select a file system model index
+ returns the index that was selected (or not depending upon sortfilterproxymodel)
+*/
+QModelIndex QFileDialogPrivate::select(const QModelIndex &index) const {
+ Q_ASSERT(index.isValid() ? index.model() == model : true);
+
+ QModelIndex idx = mapFromSource(index);
+ if (idx.isValid() && !qFileDialogUi->listView->selectionModel()->isSelected(idx))
+ qFileDialogUi->listView->selectionModel()->select(idx,
+ QItemSelectionModel::Select | QItemSelectionModel::Rows);
+ return idx;
+}
+
+QFileDialog::AcceptMode QFileDialog::acceptMode() const
+{
+ Q_D(const QFileDialog);
+ return d->acceptMode;
+}
+
+/*!
+ \property QFileDialog::readOnly
+ \obsolete
+ \brief Whether the filedialog is read-only
+
+ If this property is set to false, the file dialog will allow renaming,
+ and deleting of files and directories and creating directories.
+
+ Use setOption(ReadOnly, \e enabled) or testOption(ReadOnly) instead.
+*/
+void QFileDialog::setReadOnly(bool enabled)
+{
+ setOption(ReadOnly, enabled);
+}
+
+bool QFileDialog::isReadOnly() const
+{
+ return testOption(ReadOnly);
+}
+
+/*!
+ \property QFileDialog::resolveSymlinks
+ \obsolete
+ \brief whether the filedialog should resolve shortcuts
+
+ If this property is set to true, the file dialog will resolve
+ shortcuts or symbolic links.
+
+ Use setOption(DontResolveSymlinks, !\a enabled) or
+ !testOption(DontResolveSymlinks).
+*/
+void QFileDialog::setResolveSymlinks(bool enabled)
+{
+ setOption(DontResolveSymlinks, !enabled);
+}
+
+bool QFileDialog::resolveSymlinks() const
+{
+ return !testOption(DontResolveSymlinks);
+}
+
+/*!
+ \property QFileDialog::confirmOverwrite
+ \obsolete
+ \brief whether the filedialog should ask before accepting a selected file,
+ when the accept mode is AcceptSave
+
+ Use setOption(DontConfirmOverwrite, !\e enabled) or
+ !testOption(DontConfirmOverwrite) instead.
+*/
+void QFileDialog::setConfirmOverwrite(bool enabled)
+{
+ setOption(DontConfirmOverwrite, !enabled);
+}
+
+bool QFileDialog::confirmOverwrite() const
+{
+ return !testOption(DontConfirmOverwrite);
+}
+
+/*!
+ \property QFileDialog::defaultSuffix
+ \brief suffix added to the filename if no other suffix was specified
+
+ This property specifies a string that will be added to the
+ filename if it has no suffix already. The suffix is typically
+ used to indicate the file type (e.g. "txt" indicates a text
+ file).
+*/
+void QFileDialog::setDefaultSuffix(const QString &suffix)
+{
+ Q_D(QFileDialog);
+ d->defaultSuffix = suffix;
+}
+
+QString QFileDialog::defaultSuffix() const
+{
+ Q_D(const QFileDialog);
+ return d->defaultSuffix;
+}
+
+/*!
+ Sets the browsing history of the filedialog to contain the given
+ \a paths.
+*/
+void QFileDialog::setHistory(const QStringList &paths)
+{
+ Q_D(QFileDialog);
+ d->qFileDialogUi->lookInCombo->setHistory(paths);
+}
+
+void QFileDialogComboBox::setHistory(const QStringList &paths)
+{
+ m_history = paths;
+ // Only populate the first item, showPopup will populate the rest if needed
+ QList<QUrl> list;
+ QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
+ //On windows the popup display the "C:\", convert to nativeSeparators
+ QUrl url = QUrl::fromLocalFile(QDir::toNativeSeparators(idx.data(QFileSystemModel::FilePathRole).toString()));
+ if (url.isValid())
+ list.append(url);
+ urlModel->setUrls(list);
+}
+
+/*!
+ Returns the browsing history of the filedialog as a list of paths.
+*/
+QStringList QFileDialog::history() const
+{
+ Q_D(const QFileDialog);
+ QStringList currentHistory = d->qFileDialogUi->lookInCombo->history();
+ //On windows the popup display the "C:\", convert to nativeSeparators
+ QString newHistory = QDir::toNativeSeparators(d->rootIndex().data(QFileSystemModel::FilePathRole).toString());
+ if (!currentHistory.contains(newHistory))
+ currentHistory << newHistory;
+ return currentHistory;
+}
+
+/*!
+ Sets the item delegate used to render items in the views in the
+ file dialog to the given \a delegate.
+
+ \warning You should not share the same instance of a delegate between views.
+ Doing so can cause incorrect or unintuitive editing behavior since each
+ view connected to a given delegate may receive the \l{QAbstractItemDelegate::}{closeEditor()}
+ signal, and attempt to access, modify or close an editor that has already been closed.
+
+ Note that the model used is QFileSystemModel. It has custom item data roles, which is
+ described by the \l{QFileSystemModel::}{Roles} enum. You can use a QFileIconProvider if
+ you only want custom icons.
+
+ \sa itemDelegate(), setIconProvider(), QFileSystemModel
+*/
+void QFileDialog::setItemDelegate(QAbstractItemDelegate *delegate)
+{
+ Q_D(QFileDialog);
+ d->qFileDialogUi->listView->setItemDelegate(delegate);
+ d->qFileDialogUi->treeView->setItemDelegate(delegate);
+}
+
+/*!
+ Returns the item delegate used to render the items in the views in the filedialog.
+*/
+QAbstractItemDelegate *QFileDialog::itemDelegate() const
+{
+ Q_D(const QFileDialog);
+ return d->qFileDialogUi->listView->itemDelegate();
+}
+
+/*!
+ Sets the icon provider used by the filedialog to the specified \a provider.
+*/
+void QFileDialog::setIconProvider(QFileIconProvider *provider)
+{
+ Q_D(QFileDialog);
+ d->model->setIconProvider(provider);
+ //It forces the refresh of all entries in the side bar, then we can get new icons
+ d->qFileDialogUi->sidebar->setUrls(d->qFileDialogUi->sidebar->urls());
+}
+
+/*!
+ Returns the icon provider used by the filedialog.
+*/
+QFileIconProvider *QFileDialog::iconProvider() const
+{
+ Q_D(const QFileDialog);
+ return d->model->iconProvider();
+}
+
+/*!
+ Sets the \a text shown in the filedialog in the specified \a label.
+*/
+void QFileDialog::setLabelText(DialogLabel label, const QString &text)
+{
+ Q_D(QFileDialog);
+ QPushButton *button;
+ switch (label) {
+ case LookIn:
+ d->qFileDialogUi->lookInLabel->setText(text);
+ break;
+ case FileName:
+ d->qFileDialogUi->fileNameLabel->setText(text);
+ d->fileNameLabelExplicitlySat = true;
+ break;
+ case FileType:
+ d->qFileDialogUi->fileTypeLabel->setText(text);
+ break;
+ case Accept:
+ d->acceptLabel = text;
+ if (acceptMode() == AcceptOpen)
+ button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open);
+ else
+ button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
+ if (button)
+ button->setText(text);
+ break;
+ case Reject:
+ button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
+ if (button)
+ button->setText(text);
+ break;
+ }
+}
+
+/*!
+ Returns the text shown in the filedialog in the specified \a label.
+*/
+QString QFileDialog::labelText(DialogLabel label) const
+{
+ QPushButton *button;
+ Q_D(const QFileDialog);
+ switch (label) {
+ case LookIn:
+ return d->qFileDialogUi->lookInLabel->text();
+ case FileName:
+ return d->qFileDialogUi->fileNameLabel->text();
+ case FileType:
+ return d->qFileDialogUi->fileTypeLabel->text();
+ case Accept:
+ if (acceptMode() == AcceptOpen)
+ button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Open);
+ else
+ button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Save);
+ if (button)
+ return button->text();
+ case Reject:
+ button = d->qFileDialogUi->buttonBox->button(QDialogButtonBox::Cancel);
+ if (button)
+ return button->text();
+ }
+ return QString();
+}
+
+/*
+ For the native file dialogs
+*/
+
+#if defined(Q_WS_WIN)
+extern QString qt_win_get_open_file_name(const QFileDialogArgs &args,
+ QString *initialDirectory,
+ QString *selectedFilter);
+
+extern QString qt_win_get_save_file_name(const QFileDialogArgs &args,
+ QString *initialDirectory,
+ QString *selectedFilter);
+
+extern QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
+ QString *initialDirectory,
+ QString *selectedFilter);
+
+extern QString qt_win_get_existing_directory(const QFileDialogArgs &args);
+#endif
+
+/*
+ For Symbian file dialogs
+*/
+#if defined(Q_WS_S60)
+extern QString qtSymbianGetOpenFileName(const QString &caption,
+ const QString &dir,
+ const QString &filter);
+
+extern QStringList qtSymbianGetOpenFileNames(const QString &caption,
+ const QString &dir,
+ const QString &filter);
+
+extern QString qtSymbianGetSaveFileName(const QString &caption,
+ const QString &dir);
+
+extern QString qtSymbianGetExistingDirectory(const QString &caption,
+ const QString &dir);
+#endif
+
+/*!
+ This is a convenience static function that returns an existing file
+ selected by the user. If the user presses Cancel, it returns a null string.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 8
+
+ The function creates a modal file dialog with the given \a parent widget.
+ If \a parent is not 0, the dialog will be shown centered over the parent
+ widget.
+
+ The file dialog's working directory will be set to \a dir. If \a dir
+ includes a file name, the file will be selected. Only files that match the
+ given \a filter are shown. The filter selected is set to \a selectedFilter.
+ The parameters \a dir, \a selectedFilter, and \a filter may be empty
+ strings. If you want multiple filters, separate them with ';;', for
+ example:
+
+ \code
+ "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
+ \endcode
+
+ The \a options argument holds various options about how to run the dialog,
+ see the QFileDialog::Option enum for more information on the flags you can
+ pass.
+
+ The dialog's caption is set to \a caption. If \a caption is not specified
+ then a default caption will be used.
+
+ On Windows, Mac OS X and Symbian^3, this static function will use the
+ native file dialog and not a QFileDialog.
+
+ On Windows the dialog will spin a blocking modal event loop that will not
+ dispatch any QTimers, and if \a parent is not 0 then it will position the
+ dialog just below the parent's title bar.
+
+ On Unix/X11, the normal behavior of the file dialog is to resolve and
+ follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
+ the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
+ \a options includes DontResolveSymlinks, the file dialog will treat
+ symlinks as regular directories.
+
+ On Symbian^3 the parameter \a selectedFilter has no meaning and the
+ \a options parameter is only used to define if the native file dialog is
+ used.
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QFileDialog constructors.
+
+ \sa getOpenFileNames(), getSaveFileName(), getExistingDirectory()
+*/
+QString QFileDialog::getOpenFileName(QWidget *parent,
+ const QString &caption,
+ const QString &dir,
+ const QString &filter,
+ QString *selectedFilter,
+ Options options)
+{
+ if (qt_filedialog_open_filename_hook && !(options & DontUseNativeDialog))
+ return qt_filedialog_open_filename_hook(parent, caption, dir, filter, selectedFilter, options);
+#if defined(Q_WS_S60)
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
+ return qtSymbianGetOpenFileName(caption, dir, filter);
+#endif
+ QFileDialogArgs args;
+ args.parent = parent;
+ args.caption = caption;
+ args.directory = QFileDialogPrivate::workingDirectory(dir);
+ args.selection = QFileDialogPrivate::initialSelection(dir);
+ args.filter = filter;
+ args.mode = ExistingFile;
+ args.options = options;
+#if defined(Q_WS_WIN)
+ if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
+ return qt_win_get_open_file_name(args, &(args.directory), selectedFilter);
+ }
+#endif
+
+ // create a qt dialog
+ QFileDialog dialog(args);
+ if (selectedFilter)
+ dialog.selectNameFilter(*selectedFilter);
+ if (dialog.exec() == QDialog::Accepted) {
+ if (selectedFilter)
+ *selectedFilter = dialog.selectedFilter();
+ return dialog.selectedFiles().value(0);
+ }
+ return QString();
+}
+
+/*!
+ This is a convenience static function that will return one or more existing
+ files selected by the user.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 9
+
+ This function creates a modal file dialog with the given \a parent widget.
+ If \a parent is not 0, the dialog will be shown centered over the parent
+ widget.
+
+ The file dialog's working directory will be set to \a dir. If \a dir
+ includes a file name, the file will be selected. The filter is set to
+ \a filter so that only those files which match the filter are shown. The
+ filter selected is set to \a selectedFilter. The parameters \a dir,
+ \a selectedFilter and \a filter may be empty strings. If you need multiple
+ filters, separate them with ';;', for instance:
+
+ \code
+ "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
+ \endcode
+
+ The dialog's caption is set to \a caption. If \a caption is not specified
+ then a default caption will be used.
+
+ On Windows, Mac OS X and Symbian^3, this static function will use the
+ native file dialog and not a QFileDialog.
+
+ On Windows the dialog will spin a blocking modal event loop that will not
+ dispatch any QTimers, and if \a parent is not 0 then it will position the
+ dialog just below the parent's title bar.
+
+ On Unix/X11, the normal behavior of the file dialog is to resolve and
+ follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
+ the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}.
+ The \a options argument holds various options about how to run the dialog,
+ see the QFileDialog::Option enum for more information on the flags you can
+ pass.
+
+ \note If you want to iterate over the list of files, you should iterate
+ over a copy. For example:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 10
+
+ On Symbian^3 the parameter \a selectedFilter has no meaning and the
+ \a options parameter is only used to define if the native file dialog is
+ used. On Symbian^3, this function can only return a single filename.
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QFileDialog constructors.
+
+ \sa getOpenFileName(), getSaveFileName(), getExistingDirectory()
+*/
+QStringList QFileDialog::getOpenFileNames(QWidget *parent,
+ const QString &caption,
+ const QString &dir,
+ const QString &filter,
+ QString *selectedFilter,
+ Options options)
+{
+ if (qt_filedialog_open_filenames_hook && !(options & DontUseNativeDialog))
+ return qt_filedialog_open_filenames_hook(parent, caption, dir, filter, selectedFilter, options);
+#if defined(Q_WS_S60)
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
+ return qtSymbianGetOpenFileNames(caption, dir, filter);
+#endif
+ QFileDialogArgs args;
+ args.parent = parent;
+ args.caption = caption;
+ args.directory = QFileDialogPrivate::workingDirectory(dir);
+ args.selection = QFileDialogPrivate::initialSelection(dir);
+ args.filter = filter;
+ args.mode = ExistingFiles;
+ args.options = options;
+
+#if defined(Q_WS_WIN)
+ if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
+ return qt_win_get_open_file_names(args, &(args.directory), selectedFilter);
+ }
+#endif
+
+ // create a qt dialog
+ QFileDialog dialog(args);
+ if (selectedFilter)
+ dialog.selectNameFilter(*selectedFilter);
+ if (dialog.exec() == QDialog::Accepted) {
+ if (selectedFilter)
+ *selectedFilter = dialog.selectedFilter();
+ return dialog.selectedFiles();
+ }
+ return QStringList();
+}
+
+/*!
+ This is a convenience static function that will return a file name selected
+ by the user. The file does not have to exist.
+
+ It creates a modal file dialog with the given \a parent widget. If
+ \a parent is not 0, the dialog will be shown centered over the parent
+ widget.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 11
+
+ The file dialog's working directory will be set to \a dir. If \a dir
+ includes a file name, the file will be selected. Only files that match the
+ \a filter are shown. The filter selected is set to \a selectedFilter. The
+ parameters \a dir, \a selectedFilter, and \a filter may be empty strings.
+ Multiple filters are separated with ';;'. For instance:
+
+ \code
+ "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
+ \endcode
+
+ The \a options argument holds various options about how to run the dialog,
+ see the QFileDialog::Option enum for more information on the flags you can
+ pass.
+
+ The default filter can be chosen by setting \a selectedFilter to the
+ desired value.
+
+ The dialog's caption is set to \a caption. If \a caption is not specified,
+ a default caption will be used.
+
+ On Windows, Mac OS X and Symbian^3, this static function will use the
+ native file dialog and not a QFileDialog.
+
+ On Windows the dialog will spin a blocking modal event loop that will not
+ dispatch any QTimers, and if \a parent is not 0 then it will position the
+ dialog just below the parent's title bar. On Mac OS X, with its native file
+ dialog, the filter argument is ignored.
+
+ On Unix/X11, the normal behavior of the file dialog is to resolve and
+ follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
+ the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
+ \a options includes DontResolveSymlinks the file dialog will treat symlinks
+ as regular directories.
+
+ On Symbian^3 the parameters \a filter and \a selectedFilter have no
+ meaning. The \a options parameter is only used to define if the native file
+ dialog is used.
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QFileDialog constructors.
+
+ \sa getOpenFileName(), getOpenFileNames(), getExistingDirectory()
+*/
+QString QFileDialog::getSaveFileName(QWidget *parent,
+ const QString &caption,
+ const QString &dir,
+ const QString &filter,
+ QString *selectedFilter,
+ Options options)
+{
+ if (qt_filedialog_save_filename_hook && !(options & DontUseNativeDialog))
+ return qt_filedialog_save_filename_hook(parent, caption, dir, filter, selectedFilter, options);
+#if defined(Q_WS_S60)
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
+ return qtSymbianGetSaveFileName(caption, dir);
+#endif
+ QFileDialogArgs args;
+ args.parent = parent;
+ args.caption = caption;
+ args.directory = QFileDialogPrivate::workingDirectory(dir);
+ args.selection = QFileDialogPrivate::initialSelection(dir);
+ args.filter = filter;
+ args.mode = AnyFile;
+ args.options = options;
+
+#if defined(Q_WS_WIN)
+ if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog)) {
+ return qt_win_get_save_file_name(args, &(args.directory), selectedFilter);
+ }
+#endif
+
+ // create a qt dialog
+ QFileDialog dialog(args);
+ dialog.setAcceptMode(AcceptSave);
+ if (selectedFilter)
+ dialog.selectNameFilter(*selectedFilter);
+ if (dialog.exec() == QDialog::Accepted) {
+ if (selectedFilter)
+ *selectedFilter = dialog.selectedFilter();
+ return dialog.selectedFiles().value(0);
+ }
+
+ return QString();
+}
+
+/*!
+ This is a convenience static function that will return an existing
+ directory selected by the user.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfiledialog.cpp 12
+
+ This function creates a modal file dialog with the given \a parent widget.
+ If \a parent is not 0, the dialog will be shown centered over the parent
+ widget.
+
+ The dialog's working directory is set to \a dir, and the caption is set to
+ \a caption. Either of these may be an empty string in which case the
+ current directory and a default caption will be used respectively.
+
+ The \a options argument holds various options about how to run the dialog,
+ see the QFileDialog::Option enum for more information on the flags you can
+ pass. To ensure a native file dialog, \l{QFileDialog::}{ShowDirsOnly} must
+ be set.
+
+ On Windows, Mac OS X and Symbian^3, this static function will use the
+ native file dialog and not a QFileDialog. On Windows CE, if the device has
+ no native file dialog, a QFileDialog will be used.
+
+ On Unix/X11, the normal behavior of the file dialog is to resolve and
+ follow symlinks. For example, if \c{/usr/tmp} is a symlink to \c{/var/tmp},
+ the file dialog will change to \c{/var/tmp} after entering \c{/usr/tmp}. If
+ \a options includes DontResolveSymlinks, the file dialog will treat
+ symlinks as regular directories.
+
+ On Windows the dialog will spin a blocking modal event loop that will not
+ dispatch any QTimers, and if \a parent is not 0 then it will position the
+ dialog just below the parent's title bar.
+
+ On Symbian^3 the \a options parameter is only used to define if the native
+ file dialog is used.
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QFileDialog constructors.
+
+ \sa getOpenFileName(), getOpenFileNames(), getSaveFileName()
+*/
+QString QFileDialog::getExistingDirectory(QWidget *parent,
+ const QString &caption,
+ const QString &dir,
+ Options options)
+{
+ if (qt_filedialog_existing_directory_hook && !(options & DontUseNativeDialog))
+ return qt_filedialog_existing_directory_hook(parent, caption, dir, options);
+#if defined(Q_WS_S60)
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0 && !(options & DontUseNativeDialog))
+ return qtSymbianGetExistingDirectory(caption, dir);
+#endif
+ QFileDialogArgs args;
+ args.parent = parent;
+ args.caption = caption;
+ args.directory = QFileDialogPrivate::workingDirectory(dir);
+ args.mode = (options & ShowDirsOnly ? DirectoryOnly : Directory);
+ args.options = options;
+
+#if defined(Q_WS_WIN)
+ if (qt_use_native_dialogs && !(args.options & DontUseNativeDialog) && (options & ShowDirsOnly)
+#if defined(Q_WS_WINCE)
+ && qt_priv_ptr_valid
+#endif
+ ) {
+ return qt_win_get_existing_directory(args);
+ }
+#endif
+
+ // create a qt dialog
+ QFileDialog dialog(args);
+ if (dialog.exec() == QDialog::Accepted) {
+ return dialog.selectedFiles().value(0);
+ }
+ return QString();
+}
+
+inline static QString _qt_get_directory(const QString &path)
+{
+ QFileInfo info = QFileInfo(QDir::current(), path);
+ if (info.exists() && info.isDir())
+ return QDir::cleanPath(info.absoluteFilePath());
+ info.setFile(info.absolutePath());
+ if (info.exists() && info.isDir())
+ return info.absoluteFilePath();
+ return QString();
+}
+/*
+ Get the initial directory path
+
+ \sa initialSelection()
+ */
+QString QFileDialogPrivate::workingDirectory(const QString &path)
+{
+ if (!path.isEmpty()) {
+ QString directory = _qt_get_directory(path);
+ if (!directory.isEmpty())
+ return directory;
+ }
+ QString directory = _qt_get_directory(*lastVisitedDir());
+ if (!directory.isEmpty())
+ return directory;
+ return QDir::currentPath();
+}
+
+/*
+ Get the initial selection given a path. The initial directory
+ can contain both the initial directory and initial selection
+ /home/user/foo.txt
+
+ \sa workingDirectory()
+ */
+QString QFileDialogPrivate::initialSelection(const QString &path)
+{
+ if (!path.isEmpty()) {
+ QFileInfo info(path);
+ if (!info.isDir())
+ return info.fileName();
+ }
+ return QString();
+}
+
+/*!
+ \reimp
+*/
+void QFileDialog::done(int result)
+{
+ Q_D(QFileDialog);
+
+ QDialog::done(result);
+
+ if (d->receiverToDisconnectOnClose) {
+ disconnect(this, d->signalToDisconnectOnClose,
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+ d->signalToDisconnectOnClose.clear();
+}
+
+/*!
+ \reimp
+*/
+void QFileDialog::accept()
+{
+ Q_D(QFileDialog);
+ QStringList files = selectedFiles();
+ if (files.isEmpty())
+ return;
+ if (d->nativeDialogInUse){
+ d->emitFilesSelected(files);
+ QDialog::accept();
+ return;
+ }
+
+ QString lineEditText = d->lineEdit()->text();
+ // "hidden feature" type .. and then enter, and it will move up a dir
+ // special case for ".."
+ if (lineEditText == QLatin1String("..")) {
+ d->_q_navigateToParent();
+ bool block = d->qFileDialogUi->fileNameEdit->blockSignals(true);
+ d->lineEdit()->selectAll();
+ d->qFileDialogUi->fileNameEdit->blockSignals(block);
+ return;
+ }
+
+ switch (d->fileMode) {
+ case DirectoryOnly:
+ case Directory: {
+ QString fn = files.first();
+ QFileInfo info(fn);
+ if (!info.exists())
+ info = QFileInfo(d->getEnvironmentVariable(fn));
+ if (!info.exists()) {
+#ifndef QT_NO_MESSAGEBOX
+ QString message = tr("%1\nDirectory not found.\nPlease verify the "
+ "correct directory name was given.");
+ QMessageBox::warning(this, windowTitle(), message.arg(info.fileName()));
+#endif // QT_NO_MESSAGEBOX
+ return;
+ }
+ if (info.isDir()) {
+ d->emitFilesSelected(files);
+ QDialog::accept();
+ }
+ return;
+ }
+
+ case AnyFile: {
+ QString fn = files.first();
+ QFileInfo info(fn);
+ if (info.isDir()) {
+ setDirectory(info.absoluteFilePath());
+ return;
+ }
+
+ if (!info.exists()) {
+ int maxNameLength = d->maxNameLength(info.path());
+ if (maxNameLength >= 0 && info.fileName().length() > maxNameLength)
+ return;
+ }
+
+ // check if we have to ask for permission to overwrite the file
+ if (!info.exists() || !confirmOverwrite() || acceptMode() == AcceptOpen) {
+ d->emitFilesSelected(QStringList(fn));
+ QDialog::accept();
+#ifndef QT_NO_MESSAGEBOX
+ } else {
+ if (QMessageBox::warning(this, windowTitle(),
+ tr("%1 already exists.\nDo you want to replace it?")
+ .arg(info.fileName()),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
+ == QMessageBox::Yes) {
+ d->emitFilesSelected(QStringList(fn));
+ QDialog::accept();
+ }
+#endif
+ }
+ return;
+ }
+
+ case ExistingFile:
+ case ExistingFiles:
+ for (int i = 0; i < files.count(); ++i) {
+ QFileInfo info(files.at(i));
+ if (!info.exists())
+ info = QFileInfo(d->getEnvironmentVariable(files.at(i)));
+ if (!info.exists()) {
+#ifndef QT_NO_MESSAGEBOX
+ QString message = tr("%1\nFile not found.\nPlease verify the "
+ "correct file name was given.");
+ QMessageBox::warning(this, windowTitle(), message.arg(info.fileName()));
+#endif // QT_NO_MESSAGEBOX
+ return;
+ }
+ if (info.isDir()) {
+ setDirectory(info.absoluteFilePath());
+ d->lineEdit()->clear();
+ return;
+ }
+ }
+ d->emitFilesSelected(files);
+ QDialog::accept();
+ return;
+ }
+}
+
+/*!
+ \internal
+
+ Create widgets, layout and set default values
+*/
+void QFileDialogPrivate::init(const QString &directory, const QString &nameFilter,
+ const QString &caption)
+{
+ Q_Q(QFileDialog);
+ if (!caption.isEmpty()) {
+ useDefaultCaption = false;
+ setWindowTitle = caption;
+ q->setWindowTitle(caption);
+ }
+
+ createWidgets();
+ createMenuActions();
+ retranslateStrings();
+ q->setFileMode(fileMode);
+
+#ifndef QT_NO_SETTINGS
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ settings.beginGroup(QLatin1String("Qt"));
+ if (!directory.isEmpty())
+ setLastVisitedDirectory(workingDirectory(directory));
+ q->restoreState(settings.value(QLatin1String("filedialog")).toByteArray());
+#endif
+
+#if defined(Q_EMBEDDED_SMALLSCREEN)
+ qFileDialogUi->lookInLabel->setVisible(false);
+ qFileDialogUi->fileNameLabel->setVisible(false);
+ qFileDialogUi->fileTypeLabel->setVisible(false);
+ qFileDialogUi->sidebar->hide();
+#endif
+ // Default case
+ if (!nameFilter.isEmpty())
+ q->setNameFilter(nameFilter);
+ q->setAcceptMode(QFileDialog::AcceptOpen);
+ q->setDirectory(workingDirectory(directory));
+ q->selectFile(initialSelection(directory));
+
+ _q_updateOkButton();
+ q->resize(q->sizeHint());
+}
+
+/*!
+ \internal
+
+ Create the widgets, set properties and connections
+*/
+void QFileDialogPrivate::createWidgets()
+{
+ Q_Q(QFileDialog);
+ model = new QFileSystemModel(q);
+ model->setObjectName(QLatin1String("qt_filesystem_model"));
+#ifdef Q_WS_MAC
+ model->setNameFilterDisables(true);
+#else
+ model->setNameFilterDisables(false);
+#endif
+ model->d_func()->disableRecursiveSort = true;
+ QFileDialog::connect(model, SIGNAL(fileRenamed(QString,QString,QString)), q, SLOT(_q_fileRenamed(QString,QString,QString)));
+ QFileDialog::connect(model, SIGNAL(rootPathChanged(QString)),
+ q, SLOT(_q_pathChanged(QString)));
+ QFileDialog::connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ q, SLOT(_q_rowsInserted(QModelIndex)));
+ model->setReadOnly(false);
+
+ qFileDialogUi.reset(new Ui_QFileDialog());
+ qFileDialogUi->setupUi(q);
+
+ QList<QUrl> initialBookmarks;
+ initialBookmarks << QUrl::fromLocalFile(QLatin1String(""))
+ << QUrl::fromLocalFile(QDir::homePath());
+ qFileDialogUi->sidebar->init(model, initialBookmarks);
+ QFileDialog::connect(qFileDialogUi->sidebar, SIGNAL(goToUrl(QUrl)),
+ q, SLOT(_q_goToUrl(QUrl)));
+
+ QObject::connect(qFileDialogUi->buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
+ QObject::connect(qFileDialogUi->buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
+
+
+ qFileDialogUi->lookInCombo->init(this);
+ QObject::connect(qFileDialogUi->lookInCombo, SIGNAL(activated(QString)), q, SLOT(_q_goToDirectory(QString)));
+
+ qFileDialogUi->lookInCombo->setInsertPolicy(QComboBox::NoInsert);
+ qFileDialogUi->lookInCombo->setDuplicatesEnabled(false);
+
+ // filename
+ qFileDialogUi->fileNameEdit->init(this);
+#ifndef QT_NO_SHORTCUT
+ qFileDialogUi->fileNameLabel->setBuddy(qFileDialogUi->fileNameEdit);
+#endif
+#ifndef QT_NO_FSCOMPLETER
+ completer = new QFSCompleter(model, q);
+ qFileDialogUi->fileNameEdit->setCompleter(completer);
+#endif // QT_NO_FSCOMPLETER
+ QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
+ q, SLOT(_q_autoCompleteFileName(QString)));
+ QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)),
+ q, SLOT(_q_updateOkButton()));
+
+ QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(returnPressed()), q, SLOT(accept()));
+
+ // filetype
+ qFileDialogUi->fileTypeCombo->setDuplicatesEnabled(false);
+ qFileDialogUi->fileTypeCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
+ qFileDialogUi->fileTypeCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(int)),
+ q, SLOT(_q_useNameFilter(int)));
+ QObject::connect(qFileDialogUi->fileTypeCombo, SIGNAL(activated(QString)),
+ q, SIGNAL(filterSelected(QString)));
+
+ qFileDialogUi->listView->init(this);
+ qFileDialogUi->listView->setModel(model);
+ QObject::connect(qFileDialogUi->listView, SIGNAL(activated(QModelIndex)),
+ q, SLOT(_q_enterDirectory(QModelIndex)));
+ QObject::connect(qFileDialogUi->listView, SIGNAL(customContextMenuRequested(QPoint)),
+ q, SLOT(_q_showContextMenu(QPoint)));
+#ifndef QT_NO_SHORTCUT
+ QShortcut *shortcut = new QShortcut(qFileDialogUi->listView);
+ shortcut->setKey(QKeySequence(QLatin1String("Delete")));
+ QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
+#endif
+
+ qFileDialogUi->treeView->init(this);
+ qFileDialogUi->treeView->setModel(model);
+ QHeaderView *treeHeader = qFileDialogUi->treeView->header();
+ QFontMetrics fm(q->font());
+ treeHeader->resizeSection(0, fm.width(QLatin1String("wwwwwwwwwwwwwwwwwwwwwwwwww")));
+ treeHeader->resizeSection(1, fm.width(QLatin1String("128.88 GB")));
+ treeHeader->resizeSection(2, fm.width(QLatin1String("mp3Folder")));
+ treeHeader->resizeSection(3, fm.width(QLatin1String("10/29/81 02:02PM")));
+ treeHeader->setContextMenuPolicy(Qt::ActionsContextMenu);
+
+ QActionGroup *showActionGroup = new QActionGroup(q);
+ showActionGroup->setExclusive(false);
+ QObject::connect(showActionGroup, SIGNAL(triggered(QAction*)),
+ q, SLOT(_q_showHeader(QAction*)));;
+
+ QAbstractItemModel *abstractModel = model;
+#ifndef QT_NO_PROXYMODEL
+ if (proxyModel)
+ abstractModel = proxyModel;
+#endif
+ for (int i = 1; i < abstractModel->columnCount(QModelIndex()); ++i) {
+ QAction *showHeader = new QAction(showActionGroup);
+ showHeader->setCheckable(true);
+ showHeader->setChecked(true);
+ treeHeader->addAction(showHeader);
+ }
+
+ QScopedPointer<QItemSelectionModel> selModel(qFileDialogUi->treeView->selectionModel());
+ qFileDialogUi->treeView->setSelectionModel(qFileDialogUi->listView->selectionModel());
+
+ QObject::connect(qFileDialogUi->treeView, SIGNAL(activated(QModelIndex)),
+ q, SLOT(_q_enterDirectory(QModelIndex)));
+ QObject::connect(qFileDialogUi->treeView, SIGNAL(customContextMenuRequested(QPoint)),
+ q, SLOT(_q_showContextMenu(QPoint)));
+#ifndef QT_NO_SHORTCUT
+ shortcut = new QShortcut(qFileDialogUi->treeView);
+ shortcut->setKey(QKeySequence(QLatin1String("Delete")));
+ QObject::connect(shortcut, SIGNAL(activated()), q, SLOT(_q_deleteCurrent()));
+#endif
+
+ // Selections
+ QItemSelectionModel *selections = qFileDialogUi->listView->selectionModel();
+ QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ q, SLOT(_q_selectionChanged()));
+ QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ q, SLOT(_q_currentChanged(QModelIndex)));
+ qFileDialogUi->splitter->setStretchFactor(qFileDialogUi->splitter->indexOf(qFileDialogUi->splitter->widget(1)), QSizePolicy::Expanding);
+
+ createToolButtons();
+}
+
+void QFileDialogPrivate::_q_showHeader(QAction *action)
+{
+ Q_Q(QFileDialog);
+ QActionGroup *actionGroup = qobject_cast<QActionGroup*>(q->sender());
+ qFileDialogUi->treeView->header()->setSectionHidden(actionGroup->actions().indexOf(action) + 1, !action->isChecked());
+}
+
+#ifndef QT_NO_PROXYMODEL
+/*!
+ \since 4.3
+
+ Sets the model for the views to the given \a proxyModel. This is useful if you
+ want to modify the underlying model; for example, to add columns, filter
+ data or add drives.
+
+ Any existing proxy model will be removed, but not deleted. The file dialog
+ will take ownership of the \a proxyModel.
+
+ \sa proxyModel()
+*/
+void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel)
+{
+ Q_D(QFileDialog);
+ if ((!proxyModel && !d->proxyModel)
+ || (proxyModel == d->proxyModel))
+ return;
+
+ QModelIndex idx = d->rootIndex();
+ if (d->proxyModel) {
+ disconnect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex)));
+ } else {
+ disconnect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex)));
+ }
+
+ if (proxyModel != 0) {
+ proxyModel->setParent(this);
+ d->proxyModel = proxyModel;
+ proxyModel->setSourceModel(d->model);
+ d->qFileDialogUi->listView->setModel(d->proxyModel);
+ d->qFileDialogUi->treeView->setModel(d->proxyModel);
+#ifndef QT_NO_FSCOMPLETER
+ d->completer->setModel(d->proxyModel);
+ d->completer->proxyModel = d->proxyModel;
+#endif
+ connect(d->proxyModel, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex)));
+ } else {
+ d->proxyModel = 0;
+ d->qFileDialogUi->listView->setModel(d->model);
+ d->qFileDialogUi->treeView->setModel(d->model);
+#ifndef QT_NO_FSCOMPLETER
+ d->completer->setModel(d->model);
+ d->completer->sourceModel = d->model;
+ d->completer->proxyModel = 0;
+#endif
+ connect(d->model, SIGNAL(rowsInserted(QModelIndex,int,int)),
+ this, SLOT(_q_rowsInserted(QModelIndex)));
+ }
+ QScopedPointer<QItemSelectionModel> selModel(d->qFileDialogUi->treeView->selectionModel());
+ d->qFileDialogUi->treeView->setSelectionModel(d->qFileDialogUi->listView->selectionModel());
+
+ d->setRootIndex(idx);
+
+ // reconnect selection
+ QItemSelectionModel *selections = d->qFileDialogUi->listView->selectionModel();
+ QObject::connect(selections, SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+ this, SLOT(_q_selectionChanged()));
+ QObject::connect(selections, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this, SLOT(_q_currentChanged(QModelIndex)));
+}
+
+/*!
+ Returns the proxy model used by the file dialog. By default no proxy is set.
+
+ \sa setProxyModel()
+*/
+QAbstractProxyModel *QFileDialog::proxyModel() const
+{
+ Q_D(const QFileDialog);
+ return d->proxyModel;
+}
+#endif // QT_NO_PROXYMODEL
+
+/*!
+ \internal
+
+ Create tool buttons, set properties and connections
+*/
+void QFileDialogPrivate::createToolButtons()
+{
+ Q_Q(QFileDialog);
+ qFileDialogUi->backButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowBack, 0, q));
+ qFileDialogUi->backButton->setAutoRaise(true);
+ qFileDialogUi->backButton->setEnabled(false);
+ QObject::connect(qFileDialogUi->backButton, SIGNAL(clicked()), q, SLOT(_q_navigateBackward()));
+
+ qFileDialogUi->forwardButton->setIcon(q->style()->standardIcon(QStyle::SP_ArrowForward, 0, q));
+ qFileDialogUi->forwardButton->setAutoRaise(true);
+ qFileDialogUi->forwardButton->setEnabled(false);
+ QObject::connect(qFileDialogUi->forwardButton, SIGNAL(clicked()), q, SLOT(_q_navigateForward()));
+
+ qFileDialogUi->toParentButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogToParent, 0, q));
+ qFileDialogUi->toParentButton->setAutoRaise(true);
+ qFileDialogUi->toParentButton->setEnabled(false);
+ QObject::connect(qFileDialogUi->toParentButton, SIGNAL(clicked()), q, SLOT(_q_navigateToParent()));
+
+ qFileDialogUi->listModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogListView, 0, q));
+ qFileDialogUi->listModeButton->setAutoRaise(true);
+ qFileDialogUi->listModeButton->setDown(true);
+ QObject::connect(qFileDialogUi->listModeButton, SIGNAL(clicked()), q, SLOT(_q_showListView()));
+
+ qFileDialogUi->detailModeButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogDetailedView, 0, q));
+ qFileDialogUi->detailModeButton->setAutoRaise(true);
+ QObject::connect(qFileDialogUi->detailModeButton, SIGNAL(clicked()), q, SLOT(_q_showDetailsView()));
+
+ QSize toolSize(qFileDialogUi->fileNameEdit->sizeHint().height(), qFileDialogUi->fileNameEdit->sizeHint().height());
+ qFileDialogUi->backButton->setFixedSize(toolSize);
+ qFileDialogUi->listModeButton->setFixedSize(toolSize);
+ qFileDialogUi->detailModeButton->setFixedSize(toolSize);
+ qFileDialogUi->forwardButton->setFixedSize(toolSize);
+ qFileDialogUi->toParentButton->setFixedSize(toolSize);
+
+ qFileDialogUi->newFolderButton->setIcon(q->style()->standardIcon(QStyle::SP_FileDialogNewFolder, 0, q));
+ qFileDialogUi->newFolderButton->setFixedSize(toolSize);
+ qFileDialogUi->newFolderButton->setAutoRaise(true);
+ qFileDialogUi->newFolderButton->setEnabled(false);
+ QObject::connect(qFileDialogUi->newFolderButton, SIGNAL(clicked()), q, SLOT(_q_createDirectory()));
+}
+
+/*!
+ \internal
+
+ Create actions which will be used in the right click.
+*/
+void QFileDialogPrivate::createMenuActions()
+{
+ Q_Q(QFileDialog);
+
+ QAction *goHomeAction = new QAction(q);
+#ifndef QT_NO_SHORTCUT
+ goHomeAction->setShortcut(Qt::CTRL + Qt::Key_H + Qt::SHIFT);
+#endif
+ QObject::connect(goHomeAction, SIGNAL(triggered()), q, SLOT(_q_goHome()));
+ q->addAction(goHomeAction);
+
+ // ### TODO add Desktop & Computer actions
+
+ QAction *goToParent = new QAction(q);
+ goToParent->setObjectName(QLatin1String("qt_goto_parent_action"));
+#ifndef QT_NO_SHORTCUT
+ goToParent->setShortcut(Qt::CTRL + Qt::UpArrow);
+#endif
+ QObject::connect(goToParent, SIGNAL(triggered()), q, SLOT(_q_navigateToParent()));
+ q->addAction(goToParent);
+
+ renameAction = new QAction(q);
+ renameAction->setEnabled(false);
+ renameAction->setObjectName(QLatin1String("qt_rename_action"));
+ QObject::connect(renameAction, SIGNAL(triggered()), q, SLOT(_q_renameCurrent()));
+
+ deleteAction = new QAction(q);
+ deleteAction->setEnabled(false);
+ deleteAction->setObjectName(QLatin1String("qt_delete_action"));
+ QObject::connect(deleteAction, SIGNAL(triggered()), q, SLOT(_q_deleteCurrent()));
+
+ showHiddenAction = new QAction(q);
+ showHiddenAction->setObjectName(QLatin1String("qt_show_hidden_action"));
+ showHiddenAction->setCheckable(true);
+ QObject::connect(showHiddenAction, SIGNAL(triggered()), q, SLOT(_q_showHidden()));
+
+ newFolderAction = new QAction(q);
+ newFolderAction->setObjectName(QLatin1String("qt_new_folder_action"));
+ QObject::connect(newFolderAction, SIGNAL(triggered()), q, SLOT(_q_createDirectory()));
+}
+
+void QFileDialogPrivate::_q_goHome()
+{
+ Q_Q(QFileDialog);
+ q->setDirectory(QDir::homePath());
+}
+
+/*!
+ \internal
+
+ Update history with new path, buttons, and combo
+*/
+void QFileDialogPrivate::_q_pathChanged(const QString &newPath)
+{
+ Q_Q(QFileDialog);
+ QDir dir(model->rootDirectory());
+ qFileDialogUi->toParentButton->setEnabled(dir.exists());
+ qFileDialogUi->sidebar->selectUrl(QUrl::fromLocalFile(newPath));
+ q->setHistory(qFileDialogUi->lookInCombo->history());
+
+ if (currentHistoryLocation < 0 || currentHistory.value(currentHistoryLocation) != QDir::toNativeSeparators(newPath)) {
+ while (currentHistoryLocation >= 0 && currentHistoryLocation + 1 < currentHistory.count()) {
+ currentHistory.removeLast();
+ }
+ currentHistory.append(QDir::toNativeSeparators(newPath));
+ ++currentHistoryLocation;
+ }
+ qFileDialogUi->forwardButton->setEnabled(currentHistory.size() - currentHistoryLocation > 1);
+ qFileDialogUi->backButton->setEnabled(currentHistoryLocation > 0);
+}
+
+/*!
+ \internal
+
+ Navigates to the last directory viewed in the dialog.
+*/
+void QFileDialogPrivate::_q_navigateBackward()
+{
+ Q_Q(QFileDialog);
+ if (!currentHistory.isEmpty() && currentHistoryLocation > 0) {
+ --currentHistoryLocation;
+ QString previousHistory = currentHistory.at(currentHistoryLocation);
+ q->setDirectory(previousHistory);
+ }
+}
+
+/*!
+ \internal
+
+ Navigates to the last directory viewed in the dialog.
+*/
+void QFileDialogPrivate::_q_navigateForward()
+{
+ Q_Q(QFileDialog);
+ if (!currentHistory.isEmpty() && currentHistoryLocation < currentHistory.size() - 1) {
+ ++currentHistoryLocation;
+ QString nextHistory = currentHistory.at(currentHistoryLocation);
+ q->setDirectory(nextHistory);
+ }
+}
+
+/*!
+ \internal
+
+ Navigates to the parent directory of the currently displayed directory
+ in the dialog.
+*/
+void QFileDialogPrivate::_q_navigateToParent()
+{
+ Q_Q(QFileDialog);
+ QDir dir(model->rootDirectory());
+ QString newDirectory;
+ if (dir.isRoot()) {
+ newDirectory = model->myComputer().toString();
+ } else {
+ dir.cdUp();
+ newDirectory = dir.absolutePath();
+ }
+ q->setDirectory(newDirectory);
+ emit q->directoryEntered(newDirectory);
+}
+
+/*!
+ \internal
+
+ Creates a new directory, first asking the user for a suitable name.
+*/
+void QFileDialogPrivate::_q_createDirectory()
+{
+ Q_Q(QFileDialog);
+ qFileDialogUi->listView->clearSelection();
+
+ QString newFolderString = QFileDialog::tr("New Folder");
+ QString folderName = newFolderString;
+ QString prefix = q->directory().absolutePath() + QDir::separator();
+ if (QFile::exists(prefix + folderName)) {
+ qlonglong suffix = 2;
+ while (QFile::exists(prefix + folderName)) {
+ folderName = newFolderString + QString::number(suffix++);
+ }
+ }
+
+ QModelIndex parent = rootIndex();
+ QModelIndex index = model->mkdir(parent, folderName);
+ if (!index.isValid())
+ return;
+
+ index = select(index);
+ if (index.isValid()) {
+ qFileDialogUi->treeView->setCurrentIndex(index);
+ currentView()->edit(index);
+ }
+}
+
+void QFileDialogPrivate::_q_showListView()
+{
+ qFileDialogUi->listModeButton->setDown(true);
+ qFileDialogUi->detailModeButton->setDown(false);
+ qFileDialogUi->treeView->hide();
+ qFileDialogUi->listView->show();
+ qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->listView->parentWidget());
+ qFileDialogUi->listView->doItemsLayout();
+}
+
+void QFileDialogPrivate::_q_showDetailsView()
+{
+ qFileDialogUi->listModeButton->setDown(false);
+ qFileDialogUi->detailModeButton->setDown(true);
+ qFileDialogUi->listView->hide();
+ qFileDialogUi->treeView->show();
+ qFileDialogUi->stackedWidget->setCurrentWidget(qFileDialogUi->treeView->parentWidget());
+ qFileDialogUi->treeView->doItemsLayout();
+}
+
+/*!
+ \internal
+
+ Show the context menu for the file/dir under position
+*/
+void QFileDialogPrivate::_q_showContextMenu(const QPoint &position)
+{
+#ifdef QT_NO_MENU
+ Q_UNUSED(position);
+#else
+ Q_Q(QFileDialog);
+ QAbstractItemView *view = 0;
+ if (q->viewMode() == QFileDialog::Detail)
+ view = qFileDialogUi->treeView;
+ else
+ view = qFileDialogUi->listView;
+ QModelIndex index = view->indexAt(position);
+ index = mapToSource(index.sibling(index.row(), 0));
+
+ QMenu menu(view);
+ if (index.isValid()) {
+ // file context menu
+ QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
+ renameAction->setEnabled(p & QFile::WriteUser);
+ menu.addAction(renameAction);
+ deleteAction->setEnabled(p & QFile::WriteUser);
+ menu.addAction(deleteAction);
+ menu.addSeparator();
+ }
+ menu.addAction(showHiddenAction);
+ if (qFileDialogUi->newFolderButton->isVisible()) {
+ newFolderAction->setEnabled(qFileDialogUi->newFolderButton->isEnabled());
+ menu.addAction(newFolderAction);
+ }
+ menu.exec(view->viewport()->mapToGlobal(position));
+#endif // QT_NO_MENU
+}
+
+/*!
+ \internal
+*/
+void QFileDialogPrivate::_q_renameCurrent()
+{
+ Q_Q(QFileDialog);
+ QModelIndex index = qFileDialogUi->listView->currentIndex();
+ index = index.sibling(index.row(), 0);
+ if (q->viewMode() == QFileDialog::List)
+ qFileDialogUi->listView->edit(index);
+ else
+ qFileDialogUi->treeView->edit(index);
+}
+
+bool QFileDialogPrivate::removeDirectory(const QString &path)
+{
+ QModelIndex modelIndex = model->index(path);
+ return model->remove(modelIndex);
+}
+
+/*!
+ \internal
+
+ Deletes the currently selected item in the dialog.
+*/
+void QFileDialogPrivate::_q_deleteCurrent()
+{
+ if (model->isReadOnly())
+ return;
+
+ QModelIndexList list = qFileDialogUi->listView->selectionModel()->selectedRows();
+ for (int i = list.count() - 1; i >= 0; --i) {
+ QModelIndex index = list.at(i);
+ if (index == qFileDialogUi->listView->rootIndex())
+ continue;
+
+ index = mapToSource(index.sibling(index.row(), 0));
+ if (!index.isValid())
+ continue;
+
+ QString fileName = index.data(QFileSystemModel::FileNameRole).toString();
+ QString filePath = index.data(QFileSystemModel::FilePathRole).toString();
+ bool isDir = model->isDir(index);
+
+ QFile::Permissions p(index.parent().data(QFileSystemModel::FilePermissions).toInt());
+#ifndef QT_NO_MESSAGEBOX
+ Q_Q(QFileDialog);
+ if (!(p & QFile::WriteUser) && (QMessageBox::warning(q_func(), q_func()->windowTitle(),
+ QFileDialog::tr("'%1' is write protected.\nDo you want to delete it anyway?")
+ .arg(fileName),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No))
+ return;
+ else if (QMessageBox::warning(q_func(), q_func()->windowTitle(),
+ QFileDialog::tr("Are sure you want to delete '%1'?")
+ .arg(fileName),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No)
+ return;
+
+#else
+ if (!(p & QFile::WriteUser))
+ return;
+#endif // QT_NO_MESSAGEBOX
+
+ // the event loop has run, we can NOT reuse index because the model might have removed it.
+ if (isDir) {
+ if (!removeDirectory(filePath)) {
+#ifndef QT_NO_MESSAGEBOX
+ QMessageBox::warning(q, q->windowTitle(),
+ QFileDialog::tr("Could not delete directory."));
+#endif
+ }
+ } else {
+ model->remove(index);
+ }
+ }
+}
+
+void QFileDialogPrivate::_q_autoCompleteFileName(const QString &text)
+{
+ if (text.startsWith(QLatin1String("//")) || text.startsWith(QLatin1Char('\\'))) {
+ qFileDialogUi->listView->selectionModel()->clearSelection();
+ return;
+ }
+
+ QStringList multipleFiles = typedFiles();
+ if (multipleFiles.count() > 0) {
+ QModelIndexList oldFiles = qFileDialogUi->listView->selectionModel()->selectedRows();
+ QModelIndexList newFiles;
+ for (int i = 0; i < multipleFiles.count(); ++i) {
+ QModelIndex idx = model->index(multipleFiles.at(i));
+ if (oldFiles.contains(idx))
+ oldFiles.removeAll(idx);
+ else
+ newFiles.append(idx);
+ }
+ for (int i = 0; i < newFiles.count(); ++i)
+ select(newFiles.at(i));
+ if (lineEdit()->hasFocus())
+ for (int i = 0; i < oldFiles.count(); ++i)
+ qFileDialogUi->listView->selectionModel()->select(oldFiles.at(i),
+ QItemSelectionModel::Toggle | QItemSelectionModel::Rows);
+ }
+}
+
+/*!
+ \internal
+*/
+void QFileDialogPrivate::_q_updateOkButton()
+{
+ Q_Q(QFileDialog);
+ QPushButton *button = qFileDialogUi->buttonBox->button((acceptMode == QFileDialog::AcceptOpen)
+ ? QDialogButtonBox::Open : QDialogButtonBox::Save);
+ if (!button)
+ return;
+
+ bool enableButton = true;
+ bool isOpenDirectory = false;
+
+ QStringList files = q->selectedFiles();
+ QString lineEditText = lineEdit()->text();
+
+ if (lineEditText.startsWith(QLatin1String("//")) || lineEditText.startsWith(QLatin1Char('\\'))) {
+ button->setEnabled(true);
+ if (acceptMode == QFileDialog::AcceptSave)
+ button->setText(acceptLabel);
+ return;
+ }
+
+ if (files.isEmpty()) {
+ enableButton = false;
+ } else if (lineEditText == QLatin1String("..")) {
+ isOpenDirectory = true;
+ } else {
+ switch (fileMode) {
+ case QFileDialog::DirectoryOnly:
+ case QFileDialog::Directory: {
+ QString fn = files.first();
+ QModelIndex idx = model->index(fn);
+ if (!idx.isValid())
+ idx = model->index(getEnvironmentVariable(fn));
+ if (!idx.isValid() || !model->isDir(idx))
+ enableButton = false;
+ break;
+ }
+ case QFileDialog::AnyFile: {
+ QString fn = files.first();
+ QFileInfo info(fn);
+ QModelIndex idx = model->index(fn);
+ QString fileDir;
+ QString fileName;
+ if (info.isDir()) {
+ fileDir = info.canonicalFilePath();
+ } else {
+ fileDir = fn.mid(0, fn.lastIndexOf(QLatin1Char('/')));
+ fileName = fn.mid(fileDir.length() + 1);
+ }
+ if (lineEditText.contains(QLatin1String(".."))) {
+ fileDir = info.canonicalFilePath();
+ fileName = info.fileName();
+ }
+
+ if (fileDir == q->directory().canonicalPath() && fileName.isEmpty()) {
+ enableButton = false;
+ break;
+ }
+ if (idx.isValid() && model->isDir(idx)) {
+ isOpenDirectory = true;
+ enableButton = true;
+ break;
+ }
+ if (!idx.isValid()) {
+ int maxLength = maxNameLength(fileDir);
+ enableButton = maxLength < 0 || fileName.length() <= maxLength;
+ }
+ break;
+ }
+ case QFileDialog::ExistingFile:
+ case QFileDialog::ExistingFiles:
+ for (int i = 0; i < files.count(); ++i) {
+ QModelIndex idx = model->index(files.at(i));
+ if (!idx.isValid())
+ idx = model->index(getEnvironmentVariable(files.at(i)));
+ if (!idx.isValid()) {
+ enableButton = false;
+ break;
+ }
+ if (idx.isValid() && model->isDir(idx)) {
+ isOpenDirectory = true;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ button->setEnabled(enableButton);
+ if (acceptMode == QFileDialog::AcceptSave)
+ button->setText(isOpenDirectory ? QFileDialog::tr("&Open") : acceptLabel);
+}
+
+/*!
+ \internal
+*/
+void QFileDialogPrivate::_q_currentChanged(const QModelIndex &index)
+{
+ _q_updateOkButton();
+ emit q_func()->currentChanged(index.data(QFileSystemModel::FilePathRole).toString());
+}
+
+/*!
+ \internal
+
+ This is called when the user double clicks on a file with the corresponding
+ model item \a index.
+*/
+void QFileDialogPrivate::_q_enterDirectory(const QModelIndex &index)
+{
+ Q_Q(QFileDialog);
+ // My Computer or a directory
+ QModelIndex sourceIndex = index.model() == proxyModel ? mapToSource(index) : index;
+ QString path = sourceIndex.data(QFileSystemModel::FilePathRole).toString();
+ if (path.isEmpty() || model->isDir(sourceIndex)) {
+ q->setDirectory(path);
+ emit q->directoryEntered(path);
+ if (fileMode == QFileDialog::Directory
+ || fileMode == QFileDialog::DirectoryOnly) {
+ // ### find out why you have to do both of these.
+ lineEdit()->setText(QString());
+ lineEdit()->clear();
+ }
+ } else {
+ q->accept();
+ }
+}
+
+/*!
+ \internal
+
+ Changes the file dialog's current directory to the one specified
+ by \a path.
+*/
+void QFileDialogPrivate::_q_goToDirectory(const QString &path)
+{
+ #ifndef QT_NO_MESSAGEBOX
+ Q_Q(QFileDialog);
+#endif
+ QModelIndex index = qFileDialogUi->lookInCombo->model()->index(qFileDialogUi->lookInCombo->currentIndex(),
+ qFileDialogUi->lookInCombo->modelColumn(),
+ qFileDialogUi->lookInCombo->rootModelIndex());
+ QString path2 = path;
+ if (!index.isValid())
+ index = mapFromSource(model->index(getEnvironmentVariable(path)));
+ else {
+ path2 = index.data(UrlRole).toUrl().toLocalFile();
+ index = mapFromSource(model->index(path2));
+ }
+ QDir dir(path2);
+ if (!dir.exists())
+ dir = getEnvironmentVariable(path2);
+
+ if (dir.exists() || path2.isEmpty() || path2 == model->myComputer().toString()) {
+ _q_enterDirectory(index);
+#ifndef QT_NO_MESSAGEBOX
+ } else {
+ QString message = QFileDialog::tr("%1\nDirectory not found.\nPlease verify the "
+ "correct directory name was given.");
+ QMessageBox::warning(q, q->windowTitle(), message.arg(path2));
+#endif // QT_NO_MESSAGEBOX
+ }
+}
+
+// Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)"
+QStringList qt_clean_filter_list(const QString &filter)
+{
+ QRegExp regexp(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
+ QString f = filter;
+ int i = regexp.indexIn(f);
+ if (i >= 0)
+ f = regexp.cap(2);
+ return f.split(QLatin1Char(' '), QString::SkipEmptyParts);
+}
+
+/*!
+ \internal
+
+ Sets the current name filter to be nameFilter and
+ update the qFileDialogUi->fileNameEdit when in AcceptSave mode with the new extension.
+*/
+void QFileDialogPrivate::_q_useNameFilter(int index)
+{
+ if (index == nameFilters.size()) {
+ QAbstractItemModel *comboModel = qFileDialogUi->fileTypeCombo->model();
+ nameFilters.append(comboModel->index(comboModel->rowCount() - 1, 0).data().toString());
+ }
+
+ QString nameFilter = nameFilters.at(index);
+ QStringList newNameFilters = qt_clean_filter_list(nameFilter);
+ if (acceptMode == QFileDialog::AcceptSave) {
+ QString newNameFilterExtension;
+ if (newNameFilters.count() > 0)
+ newNameFilterExtension = QFileInfo(newNameFilters.at(0)).suffix();
+
+ QString fileName = lineEdit()->text();
+ const QString fileNameExtension = QFileInfo(fileName).suffix();
+ if (!fileNameExtension.isEmpty() && !newNameFilterExtension.isEmpty()) {
+ const int fileNameExtensionLength = fileNameExtension.count();
+ fileName.replace(fileName.count() - fileNameExtensionLength,
+ fileNameExtensionLength, newNameFilterExtension);
+ qFileDialogUi->listView->clearSelection();
+ lineEdit()->setText(fileName);
+ }
+ }
+
+ model->setNameFilters(newNameFilters);
+}
+
+/*!
+ \internal
+
+ This is called when the model index corresponding to the current file is changed
+ from \a index to \a current.
+*/
+void QFileDialogPrivate::_q_selectionChanged()
+{
+ QModelIndexList indexes = qFileDialogUi->listView->selectionModel()->selectedRows();
+ bool stripDirs = (fileMode != QFileDialog::DirectoryOnly && fileMode != QFileDialog::Directory);
+
+ QStringList allFiles;
+ for (int i = 0; i < indexes.count(); ++i) {
+ if (stripDirs && model->isDir(mapToSource(indexes.at(i))))
+ continue;
+ allFiles.append(indexes.at(i).data().toString());
+ }
+ if (allFiles.count() > 1)
+ for (int i = 0; i < allFiles.count(); ++i) {
+ allFiles.replace(i, QString(QLatin1Char('"') + allFiles.at(i) + QLatin1Char('"')));
+ }
+
+ QString finalFiles = allFiles.join(QLatin1String(" "));
+ if (!finalFiles.isEmpty() && !lineEdit()->hasFocus() && lineEdit()->isVisible())
+ lineEdit()->setText(finalFiles);
+ else
+ _q_updateOkButton();
+}
+
+/*!
+ \internal
+
+ Includes hidden files and directories in the items displayed in the dialog.
+*/
+void QFileDialogPrivate::_q_showHidden()
+{
+ Q_Q(QFileDialog);
+ QDir::Filters dirFilters = q->filter();
+ if (showHiddenAction->isChecked())
+ dirFilters |= QDir::Hidden;
+ else
+ dirFilters &= ~QDir::Hidden;
+ q->setFilter(dirFilters);
+}
+
+/*!
+ \internal
+
+ When parent is root and rows have been inserted when none was there before
+ then select the first one.
+*/
+void QFileDialogPrivate::_q_rowsInserted(const QModelIndex &parent)
+{
+ if (!qFileDialogUi->treeView
+ || parent != qFileDialogUi->treeView->rootIndex()
+ || !qFileDialogUi->treeView->selectionModel()
+ || qFileDialogUi->treeView->selectionModel()->hasSelection()
+ || qFileDialogUi->treeView->model()->rowCount(parent) == 0)
+ return;
+}
+
+void QFileDialogPrivate::_q_fileRenamed(const QString &path, const QString oldName, const QString newName)
+{
+ if (fileMode == QFileDialog::Directory || fileMode == QFileDialog::DirectoryOnly) {
+ if (path == rootPath() && lineEdit()->text() == oldName)
+ lineEdit()->setText(newName);
+ }
+}
+
+/*!
+ \internal
+
+ For the list and tree view watch keys to goto parent and back in the history
+
+ returns true if handled
+*/
+bool QFileDialogPrivate::itemViewKeyboardEvent(QKeyEvent *event) {
+
+ Q_Q(QFileDialog);
+ switch (event->key()) {
+ case Qt::Key_Backspace:
+ _q_navigateToParent();
+ return true;
+ case Qt::Key_Back:
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::keypadNavigationEnabled())
+ return false;
+#endif
+ case Qt::Key_Left:
+ if (event->key() == Qt::Key_Back || event->modifiers() == Qt::AltModifier) {
+ _q_navigateBackward();
+ return true;
+ }
+ break;
+ case Qt::Key_Escape:
+ q->hide();
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+QString QFileDialogPrivate::getEnvironmentVariable(const QString &string)
+{
+#ifdef Q_OS_UNIX
+ if (string.size() > 1 && string.startsWith(QLatin1Char('$'))) {
+ return QString::fromLocal8Bit(getenv(string.mid(1).toLatin1().constData()));
+ }
+#else
+ if (string.size() > 2 && string.startsWith(QLatin1Char('%')) && string.endsWith(QLatin1Char('%'))) {
+ return QString::fromLocal8Bit(qgetenv(string.mid(1, string.size() - 2).toLatin1().constData()));
+ }
+#endif
+ return string;
+}
+
+void QFileDialogComboBox::init(QFileDialogPrivate *d_pointer) {
+ d_ptr = d_pointer;
+ urlModel = new QUrlModel(this);
+ urlModel->showFullPath = true;
+ urlModel->setFileSystemModel(d_ptr->model);
+ setModel(urlModel);
+}
+
+void QFileDialogComboBox::showPopup()
+{
+ if (model()->rowCount() > 1)
+ QComboBox::showPopup();
+
+ urlModel->setUrls(QList<QUrl>());
+ QList<QUrl> list;
+ QModelIndex idx = d_ptr->model->index(d_ptr->rootPath());
+ while (idx.isValid()) {
+ QUrl url = QUrl::fromLocalFile(idx.data(QFileSystemModel::FilePathRole).toString());
+ if (url.isValid())
+ list.append(url);
+ idx = idx.parent();
+ }
+ // add "my computer"
+ list.append(QUrl::fromLocalFile(QLatin1String("")));
+ urlModel->addUrls(list, 0);
+ idx = model()->index(model()->rowCount() - 1, 0);
+
+ // append history
+ QList<QUrl> urls;
+ for (int i = 0; i < m_history.count(); ++i) {
+ QUrl path = QUrl::fromLocalFile(m_history.at(i));
+ if (!urls.contains(path))
+ urls.prepend(path);
+ }
+ if (urls.count() > 0) {
+ model()->insertRow(model()->rowCount());
+ idx = model()->index(model()->rowCount()-1, 0);
+ // ### TODO maybe add a horizontal line before this
+ model()->setData(idx, QFileDialog::tr("Recent Places"));
+ QStandardItemModel *m = qobject_cast<QStandardItemModel*>(model());
+ if (m) {
+ Qt::ItemFlags flags = m->flags(idx);
+ flags &= ~Qt::ItemIsEnabled;
+ m->item(idx.row(), idx.column())->setFlags(flags);
+ }
+ urlModel->addUrls(urls, -1, false);
+ }
+ setCurrentIndex(0);
+
+ QComboBox::showPopup();
+}
+
+// Exact same as QComboBox::paintEvent(), except we elide the text.
+void QFileDialogComboBox::paintEvent(QPaintEvent *)
+{
+ QStylePainter painter(this);
+ painter.setPen(palette().color(QPalette::Text));
+
+ // draw the combobox frame, focusrect and selected etc.
+ QStyleOptionComboBox opt;
+ initStyleOption(&opt);
+
+ QRect editRect = style()->subControlRect(QStyle::CC_ComboBox, &opt,
+ QStyle::SC_ComboBoxEditField, this);
+ int size = editRect.width() - opt.iconSize.width() - 4;
+ opt.currentText = opt.fontMetrics.elidedText(opt.currentText, Qt::ElideMiddle, size);
+ painter.drawComplexControl(QStyle::CC_ComboBox, opt);
+
+ // draw the icon and text
+ painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
+}
+
+QFileDialogListView::QFileDialogListView(QWidget *parent) : QListView(parent)
+{
+}
+
+void QFileDialogListView::init(QFileDialogPrivate *d_pointer)
+{
+ d_ptr = d_pointer;
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setWrapping(true);
+ setResizeMode(QListView::Adjust);
+ setEditTriggers(QAbstractItemView::EditKeyPressed);
+ setContextMenuPolicy(Qt::CustomContextMenu);
+#ifndef QT_NO_DRAGANDDROP
+ setDragDropMode(QAbstractItemView::InternalMove);
+#endif
+}
+
+QSize QFileDialogListView::sizeHint() const
+{
+ int height = qMax(10, sizeHintForRow(0));
+ return QSize(QListView::sizeHint().width() * 2, height * 30);
+}
+
+void QFileDialogListView::keyPressEvent(QKeyEvent *e)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
+ QListView::keyPressEvent(e);
+ return;
+ }
+#endif // QT_KEYPAD_NAVIGATION
+
+ if (!d_ptr->itemViewKeyboardEvent(e))
+ QListView::keyPressEvent(e);
+ e->accept();
+}
+
+QFileDialogTreeView::QFileDialogTreeView(QWidget *parent) : QTreeView(parent)
+{
+}
+
+void QFileDialogTreeView::init(QFileDialogPrivate *d_pointer)
+{
+ d_ptr = d_pointer;
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setRootIsDecorated(false);
+ setItemsExpandable(false);
+ setSortingEnabled(true);
+ header()->setSortIndicator(0, Qt::AscendingOrder);
+ header()->setStretchLastSection(false);
+ setTextElideMode(Qt::ElideMiddle);
+ setEditTriggers(QAbstractItemView::EditKeyPressed);
+ setContextMenuPolicy(Qt::CustomContextMenu);
+#ifndef QT_NO_DRAGANDDROP
+ setDragDropMode(QAbstractItemView::InternalMove);
+#endif
+}
+
+void QFileDialogTreeView::keyPressEvent(QKeyEvent *e)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
+ QTreeView::keyPressEvent(e);
+ return;
+ }
+#endif // QT_KEYPAD_NAVIGATION
+
+ if (!d_ptr->itemViewKeyboardEvent(e))
+ QTreeView::keyPressEvent(e);
+ e->accept();
+}
+
+QSize QFileDialogTreeView::sizeHint() const
+{
+ int height = qMax(10, sizeHintForRow(0));
+ QSize sizeHint = header()->sizeHint();
+ return QSize(sizeHint.width() * 4, height * 30);
+}
+
+/*!
+ // FIXME: this is a hack to avoid propagating key press events
+ // to the dialog and from there to the "Ok" button
+*/
+void QFileDialogLineEdit::keyPressEvent(QKeyEvent *e)
+{
+#ifdef QT_KEYPAD_NAVIGATION
+ if (QApplication::navigationMode() == Qt::NavigationModeKeypadDirectional) {
+ QLineEdit::keyPressEvent(e);
+ return;
+ }
+#endif // QT_KEYPAD_NAVIGATION
+
+ int key = e->key();
+ QLineEdit::keyPressEvent(e);
+ if (key != Qt::Key_Escape)
+ e->accept();
+ if (hideOnEsc && (key == Qt::Key_Escape || key == Qt::Key_Return || key == Qt::Key_Enter)) {
+ e->accept();
+ hide();
+ d_ptr->currentView()->setFocus(Qt::ShortcutFocusReason);
+ }
+}
+
+#ifndef QT_NO_FSCOMPLETER
+
+QString QFSCompleter::pathFromIndex(const QModelIndex &index) const
+{
+ const QFileSystemModel *dirModel;
+ if (proxyModel)
+ dirModel = qobject_cast<const QFileSystemModel *>(proxyModel->sourceModel());
+ else
+ dirModel = sourceModel;
+ QString currentLocation = dirModel->rootPath();
+ QString path = index.data(QFileSystemModel::FilePathRole).toString();
+ if (!currentLocation.isEmpty() && path.startsWith(currentLocation)) {
+#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE)
+ if (currentLocation == QDir::separator())
+ return path.mid(currentLocation.length());
+#endif
+ if (currentLocation.endsWith(QLatin1Char('/')))
+ return path.mid(currentLocation.length());
+ else
+ return path.mid(currentLocation.length()+1);
+ }
+ return index.data(QFileSystemModel::FilePathRole).toString();
+}
+
+QStringList QFSCompleter::splitPath(const QString &path) const
+{
+ if (path.isEmpty())
+ return QStringList(completionPrefix());
+
+ QString pathCopy = QDir::toNativeSeparators(path);
+ QString sep = QDir::separator();
+#if defined(Q_OS_SYMBIAN)
+ if (pathCopy == QLatin1String("\\"))
+ return QStringList(pathCopy);
+#elif defined(Q_OS_WIN)
+ if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\"))
+ return QStringList(pathCopy);
+ QString doubleSlash(QLatin1String("\\\\"));
+ if (pathCopy.startsWith(doubleSlash))
+ pathCopy = pathCopy.mid(2);
+ else
+ doubleSlash.clear();
+#elif defined(Q_OS_UNIX)
+ bool expanded;
+ pathCopy = qt_tildeExpansion(pathCopy, &expanded);
+ if (expanded) {
+ QFileSystemModel *dirModel;
+ if (proxyModel)
+ dirModel = qobject_cast<QFileSystemModel *>(proxyModel->sourceModel());
+ else
+ dirModel = sourceModel;
+ dirModel->fetchMore(dirModel->index(pathCopy));
+ }
+#endif
+
+ QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']'));
+
+#if defined(Q_OS_SYMBIAN)
+ QStringList parts = pathCopy.split(re, QString::SkipEmptyParts);
+ if (pathCopy.endsWith(sep))
+ parts.append(QString());
+#elif defined(Q_OS_WIN)
+ QStringList parts = pathCopy.split(re, QString::SkipEmptyParts);
+ if (!doubleSlash.isEmpty() && !parts.isEmpty())
+ parts[0].prepend(doubleSlash);
+ if (pathCopy.endsWith(sep))
+ parts.append(QString());
+#else
+ QStringList parts = pathCopy.split(re);
+ if (pathCopy[0] == sep[0]) // read the "/" at the beginning as the split removed it
+ parts[0] = sep[0];
+#endif
+
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(QLatin1Char(':'));
+#else
+ bool startsFromRoot = pathCopy[0] == sep[0];
+#endif
+ if (parts.count() == 1 || (parts.count() > 1 && !startsFromRoot)) {
+ const QFileSystemModel *dirModel;
+ if (proxyModel)
+ dirModel = qobject_cast<const QFileSystemModel *>(proxyModel->sourceModel());
+ else
+ dirModel = sourceModel;
+ QString currentLocation = QDir::toNativeSeparators(dirModel->rootPath());
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (currentLocation.endsWith(QLatin1Char(':')))
+ currentLocation.append(sep);
+#endif
+ if (currentLocation.contains(sep) && path != currentLocation) {
+ QStringList currentLocationList = splitPath(currentLocation);
+ while (!currentLocationList.isEmpty()
+ && parts.count() > 0
+ && parts.at(0) == QLatin1String("..")) {
+ parts.removeFirst();
+ currentLocationList.removeLast();
+ }
+ if (!currentLocationList.isEmpty() && currentLocationList.last().isEmpty())
+ currentLocationList.removeLast();
+ return currentLocationList + parts;
+ }
+ }
+ return parts;
+}
+
+#endif // QT_NO_COMPLETER
+
+#ifdef QT3_SUPPORT
+/*!
+ Use selectedFiles() instead.
+
+ \oldcode
+ QString selected = dialog->selectedFile();
+ \newcode
+ QStringList files = dialog->selectedFiles();
+ QString selected;
+ if (!files.isEmpty())
+ selected = files[0];
+ \endcode
+*/
+QString QFileDialog::selectedFile() const
+{
+ QStringList files = selectedFiles();
+ return files.size() ? files.at(0) : QString();
+}
+
+/*!
+ \typedef QFileDialog::Mode
+
+ Use QFileDialog::FileMode instead.
+*/
+
+/*!
+ \fn void QFileDialog::setMode(FileMode m)
+
+ Use setFileMode() instead.
+*/
+
+/*!
+ \fn FileMode QFileDialog::mode() const
+
+ Use fileMode() instead.
+*/
+
+/*!
+ \fn void QFileDialog::setDir(const QString &directory)
+
+ Use setDirectory() instead.
+*/
+
+/*!
+ \fn void QFileDialog::setDir( const QDir &directory )
+
+ Use setDirectory() instead.
+*/
+
+/*!
+ \fn QStringList QFileDialog::getOpenFileNames(const QString &filter,
+ const QString &dir, QWidget *parent, const char* name,
+ const QString &caption, QString *selectedFilter, bool resolveSymlinks)
+
+ Use the getOpenFileNames() overload that takes \a parent as the first
+ argument instead.
+*/
+
+/*!
+ \fn QString QFileDialog::getOpenFileName(const QString &dir,
+ const QString &filter, QWidget *parent = 0, const char *name,
+ const QString &caption, QString *selectedFilter, bool resolveSymlinks)
+
+ Use the getOpenFileName() overload that takes \a parent as the first
+ argument instead.
+*/
+
+/*!
+ \fn QString QFileDialog::getSaveFileName(const QString &dir,
+ const QString &filter, QWidget *parent, const char *name,
+ const QString &caption, QString *selectedFilter, bool resolveSymlinks)
+
+ Use the getSaveFileName() overload that takes \a parent as the first
+ argument instead.
+*/
+
+/*!
+ \fn QString QFileDialog::getExistingDirectory(const QString &dir,
+ QWidget *parent, const char *name, const QString &caption,
+ bool dirOnly, bool resolveSymlinks)
+
+ Use the getExistingDirectory() overload that takes \a parent as
+ the first argument instead.
+*/
+
+#endif // QT3_SUPPORT
+
+QT_END_NAMESPACE
+
+#include "moc_qfiledialog.cpp"
+
+#endif // QT_NO_FILEDIALOG
diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h
new file mode 100644
index 0000000000..1fd7c25255
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog.h
@@ -0,0 +1,331 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILEDIALOG_H
+#define QFILEDIALOG_H
+
+#include <QtCore/qdir.h>
+#include <QtCore/qstring.h>
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_FILEDIALOG
+
+class QModelIndex;
+class QItemSelection;
+struct QFileDialogArgs;
+class QFileIconProvider;
+class QFileDialogPrivate;
+class QAbstractItemDelegate;
+class QAbstractProxyModel;
+class QUrl;
+
+class Q_WIDGETS_EXPORT QFileDialog : public QDialog
+{
+ Q_OBJECT
+ Q_ENUMS(ViewMode FileMode AcceptMode Option)
+ Q_FLAGS(Options)
+ Q_PROPERTY(ViewMode viewMode READ viewMode WRITE setViewMode)
+ Q_PROPERTY(FileMode fileMode READ fileMode WRITE setFileMode)
+ Q_PROPERTY(AcceptMode acceptMode READ acceptMode WRITE setAcceptMode)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly DESIGNABLE false)
+ Q_PROPERTY(bool resolveSymlinks READ resolveSymlinks WRITE setResolveSymlinks DESIGNABLE false)
+ Q_PROPERTY(bool confirmOverwrite READ confirmOverwrite WRITE setConfirmOverwrite DESIGNABLE false)
+ Q_PROPERTY(QString defaultSuffix READ defaultSuffix WRITE setDefaultSuffix)
+ Q_PROPERTY(bool nameFilterDetailsVisible READ isNameFilterDetailsVisible
+ WRITE setNameFilterDetailsVisible DESIGNABLE false)
+ Q_PROPERTY(Options options READ options WRITE setOptions)
+
+public:
+ enum ViewMode { Detail, List };
+ enum FileMode { AnyFile, ExistingFile, Directory, ExistingFiles, DirectoryOnly };
+ enum AcceptMode { AcceptOpen, AcceptSave };
+ enum DialogLabel { LookIn, FileName, FileType, Accept, Reject };
+
+ // ### Rename to FileDialogOption and FileDialogOptions for Qt 5.0
+ enum Option
+ {
+ ShowDirsOnly = 0x00000001,
+ DontResolveSymlinks = 0x00000002,
+ DontConfirmOverwrite = 0x00000004,
+ DontUseSheet = 0x00000008,
+ DontUseNativeDialog = 0x00000010,
+ ReadOnly = 0x00000020,
+ HideNameFilterDetails = 0x00000040
+ };
+ Q_DECLARE_FLAGS(Options, Option)
+
+ QFileDialog(QWidget *parent, Qt::WindowFlags f);
+ explicit QFileDialog(QWidget *parent = 0,
+ const QString &caption = QString(),
+ const QString &directory = QString(),
+ const QString &filter = QString());
+ ~QFileDialog();
+
+ void setDirectory(const QString &directory);
+ inline void setDirectory(const QDir &directory);
+ QDir directory() const;
+
+ void selectFile(const QString &filename);
+ QStringList selectedFiles() const;
+
+#ifdef QT_DEPRECATED
+ QT_DEPRECATED void setFilter(const QString &filter);
+ QT_DEPRECATED void setFilters(const QStringList &filters);
+ QT_DEPRECATED QStringList filters() const;
+ QT_DEPRECATED void selectFilter(const QString &filter);
+ QT_DEPRECATED QString selectedFilter() const;
+#endif
+ void setNameFilterDetailsVisible(bool enabled);
+ bool isNameFilterDetailsVisible() const;
+
+ void setNameFilter(const QString &filter);
+ void setNameFilters(const QStringList &filters);
+ QStringList nameFilters() const;
+ void selectNameFilter(const QString &filter);
+ QString selectedNameFilter() const;
+
+ QDir::Filters filter() const;
+ void setFilter(QDir::Filters filters);
+
+ void setViewMode(ViewMode mode);
+ ViewMode viewMode() const;
+
+ void setFileMode(FileMode mode);
+ FileMode fileMode() const;
+
+ void setAcceptMode(AcceptMode mode);
+ AcceptMode acceptMode() const;
+
+ void setReadOnly(bool enabled);
+ bool isReadOnly() const;
+
+ void setResolveSymlinks(bool enabled);
+ bool resolveSymlinks() const;
+
+ void setSidebarUrls(const QList<QUrl> &urls);
+ QList<QUrl> sidebarUrls() const;
+
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+
+ void setConfirmOverwrite(bool enabled);
+ bool confirmOverwrite() const;
+
+ void setDefaultSuffix(const QString &suffix);
+ QString defaultSuffix() const;
+
+ void setHistory(const QStringList &paths);
+ QStringList history() const;
+
+ void setItemDelegate(QAbstractItemDelegate *delegate);
+ QAbstractItemDelegate *itemDelegate() const;
+
+ void setIconProvider(QFileIconProvider *provider);
+ QFileIconProvider *iconProvider() const;
+
+ void setLabelText(DialogLabel label, const QString &text);
+ QString labelText(DialogLabel label) const;
+
+#ifndef QT_NO_PROXYMODEL
+ void setProxyModel(QAbstractProxyModel *model);
+ QAbstractProxyModel *proxyModel() const;
+#endif
+
+ void setOption(Option option, bool on = true);
+ bool testOption(Option option) const;
+ void setOptions(Options options);
+ Options options() const;
+
+#ifdef Q_NO_USING_KEYWORD
+#ifndef Q_QDOC
+ void open() { QDialog::open(); }
+#endif
+#else
+ using QDialog::open;
+#endif
+ void open(QObject *receiver, const char *member);
+ void setVisible(bool visible);
+
+Q_SIGNALS:
+ void fileSelected(const QString &file);
+ void filesSelected(const QStringList &files);
+ void currentChanged(const QString &path);
+ void directoryEntered(const QString &directory);
+ void filterSelected(const QString &filter);
+
+public:
+#ifdef QT3_SUPPORT
+ typedef FileMode Mode;
+ inline QT3_SUPPORT void setMode(FileMode m) { setFileMode(m); }
+ inline QT3_SUPPORT FileMode mode() const { return fileMode(); }
+ inline QT3_SUPPORT void setDir(const QString &directory) { setDirectory(directory); }
+ inline QT3_SUPPORT void setDir( const QDir &directory ) { setDirectory(directory); }
+ QT3_SUPPORT QString selectedFile() const;
+#endif
+
+ static QString getOpenFileName(QWidget *parent = 0,
+ const QString &caption = QString(),
+ const QString &dir = QString(),
+ const QString &filter = QString(),
+ QString *selectedFilter = 0,
+ Options options = 0);
+
+ static QString getSaveFileName(QWidget *parent = 0,
+ const QString &caption = QString(),
+ const QString &dir = QString(),
+ const QString &filter = QString(),
+ QString *selectedFilter = 0,
+ Options options = 0);
+
+ static QString getExistingDirectory(QWidget *parent = 0,
+ const QString &caption = QString(),
+ const QString &dir = QString(),
+ Options options = ShowDirsOnly);
+
+ static QStringList getOpenFileNames(QWidget *parent = 0,
+ const QString &caption = QString(),
+ const QString &dir = QString(),
+ const QString &filter = QString(),
+ QString *selectedFilter = 0,
+ Options options = 0);
+
+#ifdef QT3_SUPPORT
+ inline static QString QT3_SUPPORT getOpenFileName(const QString &dir,
+ const QString &filter = QString(),
+ QWidget *parent = 0, const char* name = 0,
+ const QString &caption = QString(),
+ QString *selectedFilter = 0,
+ bool resolveSymlinks = true)
+ { Q_UNUSED(name);
+ return getOpenFileName(parent, caption, dir, filter, selectedFilter,
+ resolveSymlinks ? Option(0) : DontResolveSymlinks); }
+
+ inline static QString QT3_SUPPORT getSaveFileName(const QString &dir,
+ const QString &filter = QString(),
+ QWidget *parent = 0, const char* name = 0,
+ const QString &caption = QString(),
+ QString *selectedFilter = 0,
+ bool resolveSymlinks = true)
+ { Q_UNUSED(name);
+ return getSaveFileName(parent, caption, dir, filter, selectedFilter,
+ resolveSymlinks ? Option(0) : DontResolveSymlinks); }
+
+ inline static QString QT3_SUPPORT getExistingDirectory(const QString &dir,
+ QWidget *parent = 0,
+ const char* name = 0,
+ const QString &caption = QString(),
+ bool dirOnly = true,
+ bool resolveSymlinks = true)
+ { Q_UNUSED(name);
+ return getExistingDirectory(parent, caption, dir,
+ Options((resolveSymlinks ? Option(0) : DontResolveSymlinks)
+ | (dirOnly ? ShowDirsOnly : Option(0)))); }
+
+ inline static QStringList QT3_SUPPORT getOpenFileNames(const QString &filter,
+ const QString &dir = QString(),
+ QWidget *parent = 0,
+ const char* name = 0,
+ const QString &caption = QString(),
+ QString *selectedFilter = 0,
+ bool resolveSymlinks = true)
+ { Q_UNUSED(name);
+ return getOpenFileNames(parent, caption, dir, filter, selectedFilter,
+ resolveSymlinks ? Option(0) : DontResolveSymlinks); }
+#endif // QT3_SUPPORT
+
+protected:
+ QFileDialog(const QFileDialogArgs &args);
+ void done(int result);
+ void accept();
+ void changeEvent(QEvent *e);
+
+private:
+ Q_DECLARE_PRIVATE(QFileDialog)
+ Q_DISABLE_COPY(QFileDialog)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_pathChanged(const QString &))
+
+ Q_PRIVATE_SLOT(d_func(), void _q_navigateBackward())
+ Q_PRIVATE_SLOT(d_func(), void _q_navigateForward())
+ Q_PRIVATE_SLOT(d_func(), void _q_navigateToParent())
+ Q_PRIVATE_SLOT(d_func(), void _q_createDirectory())
+ Q_PRIVATE_SLOT(d_func(), void _q_showListView())
+ Q_PRIVATE_SLOT(d_func(), void _q_showDetailsView())
+ Q_PRIVATE_SLOT(d_func(), void _q_showContextMenu(const QPoint &))
+ Q_PRIVATE_SLOT(d_func(), void _q_renameCurrent())
+ Q_PRIVATE_SLOT(d_func(), void _q_deleteCurrent())
+ Q_PRIVATE_SLOT(d_func(), void _q_showHidden())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateOkButton())
+ Q_PRIVATE_SLOT(d_func(), void _q_currentChanged(const QModelIndex &index))
+ Q_PRIVATE_SLOT(d_func(), void _q_enterDirectory(const QModelIndex &index))
+ Q_PRIVATE_SLOT(d_func(), void _q_goToDirectory(const QString &path))
+ Q_PRIVATE_SLOT(d_func(), void _q_useNameFilter(int index))
+ Q_PRIVATE_SLOT(d_func(), void _q_selectionChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_goToUrl(const QUrl &url))
+ Q_PRIVATE_SLOT(d_func(), void _q_goHome())
+ Q_PRIVATE_SLOT(d_func(), void _q_showHeader(QAction *))
+ Q_PRIVATE_SLOT(d_func(), void _q_autoCompleteFileName(const QString &text))
+ Q_PRIVATE_SLOT(d_func(), void _q_rowsInserted(const QModelIndex & parent))
+ Q_PRIVATE_SLOT(d_func(), void _q_fileRenamed(const QString &path,
+ const QString oldName, const QString newName))
+#if defined(Q_WS_MAC)
+ Q_PRIVATE_SLOT(d_func(), void _q_macRunNativeAppModalPanel())
+#endif
+};
+
+inline void QFileDialog::setDirectory(const QDir &adirectory)
+{ setDirectory(adirectory.absolutePath()); }
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFileDialog::Options)
+
+#endif // QT_NO_FILEDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFILEDIALOG_H
diff --git a/src/widgets/dialogs/qfiledialog.ui b/src/widgets/dialogs/qfiledialog.ui
new file mode 100644
index 0000000000..01a49f975e
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog.ui
@@ -0,0 +1,356 @@
+<ui version="4.0" >
+ <comment>*********************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+*********************************************************************</comment>
+ <class>QFileDialog</class>
+ <widget class="QDialog" name="QFileDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>521</width>
+ <height>316</height>
+ </rect>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="lookInLabel" >
+ <property name="text" >
+ <string>Look in:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2" >
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QFileDialogComboBox" name="lookInCombo" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Ignored" >
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>50</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="backButton" >
+ <property name="toolTip" >
+ <string>Back</string>
+ </property>
+ <property name="accessibleName">
+ <string>Back</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Go back</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="forwardButton" >
+ <property name="toolTip" >
+ <string>Forward</string>
+ </property>
+ <property name="accessibleName">
+ <string>Forward</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Go forward</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="toParentButton" >
+ <property name="toolTip" >
+ <string>Parent Directory</string>
+ </property>
+ <property name="accessibleName">
+ <string>Parent Directory</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Go to the parent directory</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="newFolderButton" >
+ <property name="toolTip" >
+ <string>Create New Folder</string>
+ </property>
+ <property name="accessibleName">
+ <string>Create New Folder</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Create a New Folder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="listModeButton" >
+ <property name="toolTip" >
+ <string>List View</string>
+ </property>
+ <property name="accessibleName">
+ <string>List View</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Change to list view mode</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="detailModeButton" >
+ <property name="toolTip" >
+ <string>Detail View</string>
+ </property>
+ <property name="accessibleName">
+ <string>Detail View</string>
+ </property>
+ <property name="accessibleDescription">
+ <string>Change to detail view mode</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" colspan="3" >
+ <widget class="QSplitter" name="splitter" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QSidebar" name="sidebar" />
+ <widget class="QFrame" name="frame" >
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="page" >
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QFileDialogListView" name="listView" />
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_2" >
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="leftMargin" >
+ <number>0</number>
+ </property>
+ <property name="topMargin" >
+ <number>0</number>
+ </property>
+ <property name="rightMargin" >
+ <number>0</number>
+ </property>
+ <property name="bottomMargin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QFileDialogTreeView" name="treeView" />
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="fileNameLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QFileDialogLineEdit" name="fileNameEdit" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item rowspan="2" row="2" column="2" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="fileTypeLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Files of type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QComboBox" name="fileTypeCombo" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QFileDialogTreeView</class>
+ <extends>QTreeView</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QFileDialogListView</class>
+ <extends>QListView</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QSidebar</class>
+ <extends>QListWidget</extends>
+ <header>qsidebar_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QFileDialogLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QFileDialogComboBox</class>
+ <extends>QComboBox</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>lookInCombo</tabstop>
+ <tabstop>backButton</tabstop>
+ <tabstop>forwardButton</tabstop>
+ <tabstop>toParentButton</tabstop>
+ <tabstop>newFolderButton</tabstop>
+ <tabstop>listModeButton</tabstop>
+ <tabstop>detailModeButton</tabstop>
+ <tabstop>sidebar</tabstop>
+ <tabstop>listView</tabstop>
+ <tabstop>fileNameEdit</tabstop>
+ <tabstop>fileTypeCombo</tabstop>
+ <tabstop>buttonBox</tabstop>
+ <tabstop>treeView</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/widgets/dialogs/qfiledialog_embedded.ui b/src/widgets/dialogs/qfiledialog_embedded.ui
new file mode 100644
index 0000000000..f067d31f62
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog_embedded.ui
@@ -0,0 +1,340 @@
+<ui version="4.0" >
+ <comment>*********************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+*********************************************************************</comment>
+ <class>QFileDialog</class>
+ <widget class="QDialog" name="QFileDialog" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>240</width>
+ <height>320</height>
+ </rect>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QFileDialogComboBox" name="lookInCombo" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QToolButton" name="backButton" >
+ <property name="toolTip" >
+ <string>Back</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="forwardButton" >
+ <property name="toolTip" >
+ <string>Forward</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="toParentButton" >
+ <property name="toolTip" >
+ <string>Parent Directory</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="newFolderButton" >
+ <property name="toolTip" >
+ <string>Create New Folder</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="listModeButton" >
+ <property name="toolTip" >
+ <string>List View</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="detailModeButton" >
+ <property name="toolTip" >
+ <string>Detail View</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QSplitter" name="splitter" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QSidebar" name="sidebar" />
+ <widget class="QFrame" name="frame" >
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QStackedWidget" name="stackedWidget" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="page" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>108</width>
+ <height>164</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QFileDialogListView" name="listView" />
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="page_2" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>100</width>
+ <height>30</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" >
+ <property name="spacing" >
+ <number>0</number>
+ </property>
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QFileDialogTreeView" name="treeView" />
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QFileDialogLineEdit" name="fileNameEdit" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item rowspan="2" row="0" column="1" >
+ <widget class="QDialogButtonBox" name="buttonBox" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="standardButtons" >
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QComboBox" name="fileTypeCombo" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="fileNameLabel" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="fileTypeLabel" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Files of type:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lookInLabel" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text" >
+ <string>Look in:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QFileDialogTreeView</class>
+ <extends>QTreeView</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QFileDialogListView</class>
+ <extends>QListView</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QSidebar</class>
+ <extends>QListWidget</extends>
+ <header>qsidebar_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QFileDialogLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ <customwidget>
+ <class>QFileDialogComboBox</class>
+ <extends>QComboBox</extends>
+ <header>qfiledialog_p.h</header>
+ </customwidget>
+ </customwidgets>
+ <tabstops>
+ <tabstop>lookInCombo</tabstop>
+ <tabstop>backButton</tabstop>
+ <tabstop>forwardButton</tabstop>
+ <tabstop>toParentButton</tabstop>
+ <tabstop>newFolderButton</tabstop>
+ <tabstop>listModeButton</tabstop>
+ <tabstop>detailModeButton</tabstop>
+ <tabstop>sidebar</tabstop>
+ <tabstop>listView</tabstop>
+ <tabstop>fileNameEdit</tabstop>
+ <tabstop>fileTypeCombo</tabstop>
+ <tabstop>buttonBox</tabstop>
+ <tabstop>treeView</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/widgets/dialogs/qfiledialog_mac.mm b/src/widgets/dialogs/qfiledialog_mac.mm
new file mode 100644
index 0000000000..885ce77c52
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog_mac.mm
@@ -0,0 +1,1157 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfiledialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+/*****************************************************************************
+ QFileDialog debug facilities
+ *****************************************************************************/
+//#define DEBUG_FILEDIALOG_FILTERS
+
+#include <qapplication.h>
+#include <private/qapplication_p.h>
+#include <private/qfiledialog_p.h>
+#include <private/qt_mac_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#include <qregexp.h>
+#include <qbuffer.h>
+#include <qdebug.h>
+#include <qstringlist.h>
+#include <qaction.h>
+#include <qtextcodec.h>
+#include <qvarlengtharray.h>
+#include <qdesktopwidget.h>
+#include <stdlib.h>
+#include <qabstracteventdispatcher.h>
+#import <AppKit/NSSavePanel.h>
+#include "ui_qfiledialog.h"
+
+QT_BEGIN_NAMESPACE
+
+extern QStringList qt_make_filter_list(const QString &filter); // qfiledialog.cpp
+extern QStringList qt_clean_filter_list(const QString &filter); // qfiledialog.cpp
+extern const char *qt_file_dialog_filter_reg_exp; // qfiledialog.cpp
+extern bool qt_mac_is_macsheet(const QWidget *w); // qwidget_mac.mm
+
+QT_END_NAMESPACE
+
+QT_FORWARD_DECLARE_CLASS(QFileDialogPrivate)
+QT_FORWARD_DECLARE_CLASS(QString)
+QT_FORWARD_DECLARE_CLASS(QStringList)
+QT_FORWARD_DECLARE_CLASS(QWidget)
+QT_FORWARD_DECLARE_CLASS(QAction)
+QT_FORWARD_DECLARE_CLASS(QFileInfo)
+QT_USE_NAMESPACE
+
+@class QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate);
+
+@interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+ : NSObject<NSOpenSavePanelDelegate>
+#else
+ : NSObject
+#endif
+{
+ @public
+ NSOpenPanel *mOpenPanel;
+ NSSavePanel *mSavePanel;
+ NSView *mAccessoryView;
+ NSPopUpButton *mPopUpButton;
+ NSTextField *mTextField;
+ QFileDialogPrivate *mPriv;
+ NSString *mCurrentDir;
+ bool mConfirmOverwrite;
+ int mReturnCode;
+
+ QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode) mAcceptMode;
+ QT_PREPEND_NAMESPACE(QDir::Filters) *mQDirFilter;
+ QT_PREPEND_NAMESPACE(QFileDialog::FileMode) mFileMode;
+ QT_PREPEND_NAMESPACE(QFileDialog::Options) *mFileOptions;
+
+ QString *mLastFilterCheckPath;
+ QString *mCurrentSelection;
+ QStringList *mQDirFilterEntryList;
+ QStringList *mNameFilterDropDownList;
+ QStringList *mSelectedNameFilter;
+}
+
+- (NSString *)strip:(const QString &)label;
+- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename;
+- (void)filterChanged:(id)sender;
+- (void)showModelessPanel;
+- (BOOL)runApplicationModalPanel;
+- (void)showWindowModalSheet:(QWidget *)docWidget;
+- (void)updateProperties;
+- (QStringList)acceptableExtensionsForSave;
+- (QString)removeExtensions:(const QString &)filter;
+- (void)createTextField;
+- (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails;
+- (QStringList)findStrippedFilterWithVisualFilterName:(QString)name;
+- (void)createAccessory;
+
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
+
+- (id)initWithAcceptMode:(QT_PREPEND_NAMESPACE(QFileDialog::AcceptMode))acceptMode
+ title:(const QString &)title
+ hideNameFilterDetails:(bool)hideNameFilterDetails
+ qDirFilter:(QT_PREPEND_NAMESPACE(QDir::Filters))qDirFilter
+ fileOptions:(QT_PREPEND_NAMESPACE(QFileDialog::Options))fileOptions
+ fileMode:(QT_PREPEND_NAMESPACE(QFileDialog::FileMode))fileMode
+ selectFile:(const QString &)selectFile
+ confirmOverwrite:(bool)confirm
+ priv:(QFileDialogPrivate *)priv
+{
+ self = [super init];
+
+ mAcceptMode = acceptMode;
+ if (mAcceptMode == QT_PREPEND_NAMESPACE(QFileDialog::AcceptOpen)){
+ mOpenPanel = [NSOpenPanel openPanel];
+ mSavePanel = mOpenPanel;
+ } else {
+ mSavePanel = [NSSavePanel savePanel];
+ mOpenPanel = 0;
+ }
+
+ [mSavePanel setLevel:NSModalPanelWindowLevel];
+ [mSavePanel setDelegate:self];
+ mQDirFilter = new QT_PREPEND_NAMESPACE(QDir::Filters)(qDirFilter);
+ mFileOptions = new QT_PREPEND_NAMESPACE(QFileDialog::Options)(fileOptions);
+ mFileMode = fileMode;
+ mConfirmOverwrite = confirm;
+ mReturnCode = -1;
+ mPriv = priv;
+ mLastFilterCheckPath = new QString;
+ mQDirFilterEntryList = new QStringList;
+ mNameFilterDropDownList = new QStringList(priv->nameFilters);
+ QString selectedVisualNameFilter = priv->qFileDialogUi->fileTypeCombo->currentText();
+ mSelectedNameFilter = new QStringList([self findStrippedFilterWithVisualFilterName:selectedVisualNameFilter]);
+
+ QFileInfo sel(selectFile);
+ if (sel.isDir()){
+ mCurrentDir = [qt_mac_QStringToNSString(sel.absoluteFilePath()) retain];
+ mCurrentSelection = new QString;
+ } else {
+ mCurrentDir = [qt_mac_QStringToNSString(sel.absolutePath()) retain];
+ mCurrentSelection = new QString(sel.absoluteFilePath());
+ }
+
+ [mSavePanel setTitle:qt_mac_QStringToNSString(title)];
+ [self createPopUpButton:selectedVisualNameFilter hideDetails:hideNameFilterDetails];
+ [self createTextField];
+ [self createAccessory];
+ [mSavePanel setAccessoryView:mNameFilterDropDownList->size() > 1 ? mAccessoryView : nil];
+
+ if (mPriv){
+ [mSavePanel setPrompt:[self strip:mPriv->acceptLabel]];
+ if (mPriv->fileNameLabelExplicitlySat)
+ [mSavePanel setNameFieldLabel:[self strip:mPriv->qFileDialogUi->fileNameLabel->text()]];
+ }
+
+ [self updateProperties];
+ [mSavePanel retain];
+ return self;
+}
+
+- (void)dealloc
+{
+ delete mQDirFilter;
+ delete mFileOptions;
+ delete mLastFilterCheckPath;
+ delete mQDirFilterEntryList;
+ delete mNameFilterDropDownList;
+ delete mSelectedNameFilter;
+ delete mCurrentSelection;
+
+ [mSavePanel orderOut:mSavePanel];
+ [mSavePanel setAccessoryView:nil];
+ [mPopUpButton release];
+ [mTextField release];
+ [mAccessoryView release];
+ [mSavePanel setDelegate:nil];
+ [mSavePanel release];
+ [mCurrentDir release];
+ [super dealloc];
+}
+
+- (NSString *)strip:(const QString &)label
+{
+ QAction a(label, 0);
+ return qt_mac_QStringToNSString(a.iconText());
+}
+
+- (void)closePanel
+{
+ *mCurrentSelection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
+ [mSavePanel close];
+}
+
+- (void)showModelessPanel
+{
+ if (mOpenPanel){
+ QFileInfo info(*mCurrentSelection);
+ NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
+ NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
+ bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
+ || [self panel:nil shouldShowFilename:filepath];
+ [mOpenPanel
+ beginForDirectory:mCurrentDir
+ file:selectable ? filename : nil
+ types:nil
+ modelessDelegate:self
+ didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+ }
+}
+
+- (BOOL)runApplicationModalPanel
+{
+ QFileInfo info(*mCurrentSelection);
+ NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
+ NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
+ bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
+ || [self panel:nil shouldShowFilename:filepath];
+ mReturnCode = [mSavePanel
+ runModalForDirectory:mCurrentDir
+ file:selectable ? filename : @"untitled"];
+
+ QAbstractEventDispatcher::instance()->interrupt();
+ return (mReturnCode == NSOKButton);
+}
+
+- (QT_PREPEND_NAMESPACE(QDialog::DialogCode))dialogResultCode
+{
+ return (mReturnCode == NSOKButton) ? QT_PREPEND_NAMESPACE(QDialog::Accepted) : QT_PREPEND_NAMESPACE(QDialog::Rejected);
+}
+
+- (void)showWindowModalSheet:(QWidget *)docWidget
+{
+ Q_UNUSED(docWidget);
+ QFileInfo info(*mCurrentSelection);
+ NSString *filename = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.fileName());
+ NSString *filepath = QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(info.filePath());
+ bool selectable = (mAcceptMode == QFileDialog::AcceptSave)
+ || [self panel:nil shouldShowFilename:filepath];
+ [mSavePanel
+ beginSheetForDirectory:mCurrentDir
+ file:selectable ? filename : nil
+#ifdef QT_MAC_USE_COCOA
+ modalForWindow:QT_PREPEND_NAMESPACE(qt_mac_window_for)(docWidget)
+#else
+ modalForWindow:nil
+#endif
+ modalDelegate:self
+ didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
+ contextInfo:nil];
+}
+
+- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename
+{
+ Q_UNUSED(sender);
+
+ if ([filename length] == 0)
+ return NO;
+
+ // Always accept directories regardless of their names (unless it is a bundle):
+ BOOL isDir;
+ if ([[NSFileManager defaultManager] fileExistsAtPath:filename isDirectory:&isDir] && isDir) {
+ if ([mSavePanel treatsFilePackagesAsDirectories] == NO) {
+ if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:filename] == NO)
+ return YES;
+ }
+ }
+
+ QString qtFileName = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)(filename);
+ QFileInfo info(qtFileName.normalized(QT_PREPEND_NAMESPACE(QString::NormalizationForm_C)));
+ QString path = info.absolutePath();
+ if (path != *mLastFilterCheckPath){
+ *mLastFilterCheckPath = path;
+ *mQDirFilterEntryList = info.dir().entryList(*mQDirFilter);
+ }
+ // Check if the QDir filter accepts the file:
+ if (!mQDirFilterEntryList->contains(info.fileName()))
+ return NO;
+
+ // No filter means accept everything
+ if (mSelectedNameFilter->isEmpty())
+ return YES;
+ // Check if the current file name filter accepts the file:
+ for (int i=0; i<mSelectedNameFilter->size(); ++i) {
+ if (QDir::match(mSelectedNameFilter->at(i), qtFileName))
+ return YES;
+ }
+ return NO;
+}
+
+- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
+{
+ Q_UNUSED(sender);
+ if (!okFlag)
+ return filename;
+ if (mConfirmOverwrite)
+ return filename;
+
+ // User has clicked save, and no overwrite confirmation should occur.
+ // To get the latter, we need to change the name we return (hence the prefix):
+ return [@"___qt_very_unlikely_prefix_" stringByAppendingString:filename];
+}
+
+- (void)setNameFilters:(const QStringList &)filters hideDetails:(BOOL)hideDetails
+{
+ [mPopUpButton removeAllItems];
+ *mNameFilterDropDownList = filters;
+ if (filters.size() > 0){
+ for (int i=0; i<filters.size(); ++i) {
+ QString filter = hideDetails ? [self removeExtensions:filters.at(i)] : filters.at(i);
+ [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
+ }
+ [mPopUpButton selectItemAtIndex:0];
+ [mSavePanel setAccessoryView:mAccessoryView];
+ } else
+ [mSavePanel setAccessoryView:nil];
+
+ [self filterChanged:self];
+}
+
+- (void)filterChanged:(id)sender
+{
+ // This mDelegate function is called when the _name_ filter changes.
+ Q_UNUSED(sender);
+ QString selection = mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
+ *mSelectedNameFilter = [self findStrippedFilterWithVisualFilterName:selection];
+ [mSavePanel validateVisibleColumns];
+ [self updateProperties];
+ if (mPriv)
+ mPriv->QNSOpenSavePanelDelegate_filterSelected([mPopUpButton indexOfSelectedItem]);
+}
+
+- (QString)currentNameFilter
+{
+ return mNameFilterDropDownList->value([mPopUpButton indexOfSelectedItem]);
+}
+
+- (QStringList)selectedFiles
+{
+ if (mOpenPanel)
+ return QT_PREPEND_NAMESPACE(qt_mac_NSArrayToQStringList)([mOpenPanel filenames]);
+ else{
+ QStringList result;
+ QString filename = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString)([mSavePanel filename]);
+ result << filename.remove(QLatin1String("___qt_very_unlikely_prefix_"));
+ return result;
+ }
+}
+
+- (void)updateProperties
+{
+ // Call this functions if mFileMode, mFileOptions,
+ // mNameFilterDropDownList or mQDirFilter changes.
+ // The savepanel does not contain the neccessary functions for this.
+ bool chooseFilesOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFile)
+ || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles);
+ bool chooseDirsOnly = mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::Directory)
+ || mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::DirectoryOnly)
+ || *mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ShowDirsOnly);
+
+ [mOpenPanel setCanChooseFiles:!chooseDirsOnly];
+ [mOpenPanel setCanChooseDirectories:!chooseFilesOnly];
+ [mSavePanel setCanCreateDirectories:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::ReadOnly))];
+ [mOpenPanel setAllowsMultipleSelection:(mFileMode == QT_PREPEND_NAMESPACE(QFileDialog::ExistingFiles))];
+ [mOpenPanel setResolvesAliases:!(*mFileOptions & QT_PREPEND_NAMESPACE(QFileDialog::DontResolveSymlinks))];
+
+ QStringList ext = [self acceptableExtensionsForSave];
+ if (mPriv && !ext.isEmpty() && !mPriv->defaultSuffix.isEmpty())
+ ext.prepend(mPriv->defaultSuffix);
+ [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : QT_PREPEND_NAMESPACE(qt_mac_QStringListToNSMutableArray(ext))];
+
+ if ([mSavePanel isVisible])
+ [mOpenPanel validateVisibleColumns];
+}
+
+- (void)panelSelectionDidChange:(id)sender
+{
+ Q_UNUSED(sender);
+ if (mPriv) {
+ QString selection = QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString([mSavePanel filename]));
+ if (selection != mCurrentSelection) {
+ *mCurrentSelection = selection;
+ mPriv->QNSOpenSavePanelDelegate_selectionChanged(selection);
+ }
+ }
+}
+
+- (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ Q_UNUSED(panel);
+ Q_UNUSED(contextInfo);
+ mReturnCode = returnCode;
+ if (mPriv)
+ mPriv->QNSOpenSavePanelDelegate_panelClosed(returnCode == NSOKButton);
+}
+
+- (void)panel:(id)sender directoryDidChange:(NSString *)path
+{
+ Q_UNUSED(sender);
+ if (!mPriv)
+ return;
+ if ([path isEqualToString:mCurrentDir])
+ return;
+
+ [mCurrentDir release];
+ mCurrentDir = [path retain];
+ mPriv->QNSOpenSavePanelDelegate_directoryEntered(QT_PREPEND_NAMESPACE(qt_mac_NSStringToQString(mCurrentDir)));
+}
+
+/*
+ Returns a list of extensions (e.g. "png", "jpg", "gif")
+ for the current name filter. If a filter do not conform
+ to the format *.xyz or * or *.*, an empty list
+ is returned meaning accept everything.
+*/
+- (QStringList)acceptableExtensionsForSave
+{
+ QStringList result;
+ for (int i=0; i<mSelectedNameFilter->count(); ++i) {
+ const QString &filter = mSelectedNameFilter->at(i);
+ if (filter.startsWith(QLatin1String("*."))
+ && !filter.contains(QLatin1Char('?'))
+ && filter.count(QLatin1Char('*')) == 1) {
+ result += filter.mid(2);
+ } else {
+ return QStringList(); // Accept everything
+ }
+ }
+ return result;
+}
+
+- (QString)removeExtensions:(const QString &)filter
+{
+ QRegExp regExp(QT_PREPEND_NAMESPACE(QString::fromLatin1)(QT_PREPEND_NAMESPACE(qt_file_dialog_filter_reg_exp)));
+ if (regExp.indexIn(filter) != -1)
+ return regExp.cap(1).trimmed();
+ return filter;
+}
+
+- (void)createTextField
+{
+ NSRect textRect = { { 0.0, 3.0 }, { 100.0, 25.0 } };
+ mTextField = [[NSTextField alloc] initWithFrame:textRect];
+ [[mTextField cell] setFont:[NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
+ [mTextField setAlignment:NSRightTextAlignment];
+ [mTextField setEditable:false];
+ [mTextField setSelectable:false];
+ [mTextField setBordered:false];
+ [mTextField setDrawsBackground:false];
+ if (mPriv){
+ [mTextField setStringValue:[self strip:mPriv->qFileDialogUi->fileTypeLabel->text()]];
+ } else
+ [mTextField setStringValue:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(QT_PREPEND_NAMESPACE(QFileDialog::tr)("Files of type:"))];
+}
+
+- (void)createPopUpButton:(const QString &)selectedFilter hideDetails:(BOOL)hideDetails
+{
+ NSRect popUpRect = { { 100.0, 5.0 }, { 250.0, 25.0 } };
+ mPopUpButton = [[NSPopUpButton alloc] initWithFrame:popUpRect pullsDown:NO];
+ [mPopUpButton setTarget:self];
+ [mPopUpButton setAction:@selector(filterChanged:)];
+
+ QStringList *filters = mNameFilterDropDownList;
+ if (filters->size() > 0){
+ for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
+ QString filter = hideDetails ? [self removeExtensions:filters->at(i)] : filters->at(i);
+ [mPopUpButton addItemWithTitle:QT_PREPEND_NAMESPACE(qt_mac_QStringToNSString)(filter)];
+ if (filters->at(i).startsWith(selectedFilter))
+ [mPopUpButton selectItemAtIndex:i];
+ }
+ }
+}
+
+- (QStringList) findStrippedFilterWithVisualFilterName:(QString)name
+{
+ for (int i=0; i<mNameFilterDropDownList->size(); ++i) {
+ if (mNameFilterDropDownList->at(i).startsWith(name))
+ return qt_clean_filter_list(mNameFilterDropDownList->at(i));
+ }
+ return QStringList();
+}
+
+- (void)createAccessory
+{
+ NSRect accessoryRect = { { 0.0, 0.0 }, { 450.0, 33.0 } };
+ mAccessoryView = [[NSView alloc] initWithFrame:accessoryRect];
+ [mAccessoryView addSubview:mTextField];
+ [mAccessoryView addSubview:mPopUpButton];
+}
+
+@end
+
+QT_BEGIN_NAMESPACE
+
+void QFileDialogPrivate::QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath)
+{
+ emit q_func()->currentChanged(newPath);
+}
+
+void QFileDialogPrivate::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
+{
+ if (accepted)
+ q_func()->accept();
+ else
+ q_func()->reject();
+}
+
+void QFileDialogPrivate::QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir)
+{
+ setLastVisitedDirectory(newDir);
+ emit q_func()->directoryEntered(newDir);
+}
+
+void QFileDialogPrivate::QNSOpenSavePanelDelegate_filterSelected(int menuIndex)
+{
+ emit q_func()->filterSelected(nameFilters.at(menuIndex));
+}
+
+extern OSErr qt_mac_create_fsref(const QString &, FSRef *); // qglobal.cpp
+extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding=0, int len=-1); // qglobal.cpp
+
+void QFileDialogPrivate::setDirectory_sys(const QString &directory)
+{
+#ifndef QT_MAC_USE_COCOA
+ if (directory == mCurrentLocation)
+ return;
+ mCurrentLocation = directory;
+ emit q_func()->directoryEntered(mCurrentLocation);
+
+ FSRef fsRef;
+ if (qt_mac_create_fsref(directory, &fsRef) == noErr) {
+ AEDesc desc;
+ if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr)
+ NavCustomControl(mDialog, kNavCtlSetLocation, (void*)&desc);
+ }
+#else
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ [delegate->mSavePanel setDirectory:qt_mac_QStringToNSString(directory)];
+#endif
+}
+
+QString QFileDialogPrivate::directory_sys() const
+{
+#ifndef QT_MAC_USE_COCOA
+ return mCurrentLocation;
+#else
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ return qt_mac_NSStringToQString([delegate->mSavePanel directory]);
+#endif
+}
+
+void QFileDialogPrivate::selectFile_sys(const QString &filename)
+{
+ QString filePath = filename;
+ if (QDir::isRelativePath(filePath))
+ filePath = QFileInfo(directory_sys(), filePath).filePath();
+
+#ifndef QT_MAC_USE_COCOA
+ // Update the selection list immidiatly, so
+ // subsequent calls to selectedFiles() gets correct:
+ mCurrentSelectionList.clear();
+ mCurrentSelectionList << filename;
+ if (mCurrentSelection != filename){
+ mCurrentSelection = filename;
+ emit q_func()->currentChanged(mCurrentSelection);
+ }
+
+ AEDescList descList;
+ if (AECreateList(0, 0, false, &descList) != noErr)
+ return;
+
+ FSRef fsRef;
+ if (qt_mac_create_fsref(filePath, &fsRef) == noErr) {
+ AEDesc desc;
+ if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr){
+ if (AEPutDesc(&descList, 0, &desc) == noErr)
+ NavCustomControl(mDialog, kNavCtlSetSelection, (void*)&descList);
+ }
+ }
+
+ // Type the file name into the save dialog's text field:
+ UInt8 *strBuffer = (UInt8 *)malloc(1024);
+ qt_mac_to_pascal_string(QFileInfo(filename).fileName(), strBuffer);
+ NavCustomControl(mDialog, kNavCtlSetEditFileName, strBuffer);
+ free(strBuffer);
+#else
+ // There seems to no way to select a file once the dialog is running.
+ // So do the next best thing, set the file's directory:
+ setDirectory_sys(QFileInfo(filePath).absolutePath());
+#endif
+}
+
+QStringList QFileDialogPrivate::selectedFiles_sys() const
+{
+#ifndef QT_MAC_USE_COCOA
+ if (q_func()->acceptMode() == QFileDialog::AcceptOpen){
+ return mCurrentSelectionList;
+ } else {
+ return QStringList() << mCurrentLocation + QLatin1Char('/')
+ + QCFString::toQString(NavDialogGetSaveFileName(mDialog));
+ }
+#else
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ return [delegate selectedFiles];
+#endif
+}
+
+void QFileDialogPrivate::setNameFilters_sys(const QStringList &filters)
+{
+#ifndef QT_MAC_USE_COCOA
+ Q_UNUSED(filters);
+#else
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ bool hideDetails = q_func()->testOption(QFileDialog::HideNameFilterDetails);
+ [delegate setNameFilters:filters hideDetails:hideDetails];
+#endif
+}
+
+void QFileDialogPrivate::setFilter_sys()
+{
+#ifndef QT_MAC_USE_COCOA
+#else
+ Q_Q(QFileDialog);
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ *(delegate->mQDirFilter) = model->filter();
+ delegate->mFileMode = fileMode;
+ [delegate->mSavePanel setTitle:qt_mac_QStringToNSString(q->windowTitle())];
+ [delegate->mSavePanel setPrompt:[delegate strip:acceptLabel]];
+ if (fileNameLabelExplicitlySat)
+ [delegate->mSavePanel setNameFieldLabel:[delegate strip:qFileDialogUi->fileNameLabel->text()]];
+
+ [delegate updateProperties];
+#endif
+}
+
+void QFileDialogPrivate::selectNameFilter_sys(const QString &filter)
+{
+ int index = nameFilters.indexOf(filter);
+ if (index != -1) {
+#ifndef QT_MAC_USE_COCOA
+ NavMenuItemSpec navSpec;
+ bzero(&navSpec, sizeof(NavMenuItemSpec));
+ navSpec.menuType = index;
+ NavCustomControl(mDialog, kNavCtlSelectCustomType, &navSpec);
+#else
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ [delegate->mPopUpButton selectItemAtIndex:index];
+ [delegate filterChanged:nil];
+#endif
+ }
+}
+
+QString QFileDialogPrivate::selectedNameFilter_sys() const
+{
+#ifndef QT_MAC_USE_COCOA
+ int index = filterInfo.currentSelection;
+#else
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ int index = [delegate->mPopUpButton indexOfSelectedItem];
+#endif
+ return index != -1 ? nameFilters.at(index) : QString();
+}
+
+void QFileDialogPrivate::deleteNativeDialog_sys()
+{
+#ifndef QT_MAC_USE_COCOA
+ if (mDialog)
+ NavDialogDispose(mDialog);
+ mDialog = 0;
+ mDialogStarted = false;
+#else
+ QMacCocoaAutoReleasePool pool;
+ [reinterpret_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate) release];
+ mDelegate = 0;
+#endif
+ nativeDialogInUse = false;
+}
+
+bool QFileDialogPrivate::setVisible_sys(bool visible)
+{
+ Q_Q(QFileDialog);
+ if (!visible == q->isHidden())
+ return false;
+
+ if (q->windowFlags() & Qt::WindowStaysOnTopHint) {
+ // The native file dialog tries all it can to stay
+ // on the NSModalPanel level. And it might also show
+ // its own "create directory" dialog that we cannot control.
+ // So we need to use the non-native version in this case...
+ return false;
+ }
+
+#ifndef QT_MAC_USE_COCOA
+ return visible ? showCarbonNavServicesDialog() : hideCarbonNavServicesDialog();
+#else
+ return visible ? showCocoaFilePanel() : hideCocoaFilePanel();
+#endif
+}
+
+#ifndef QT_MAC_USE_COCOA
+Boolean QFileDialogPrivate::qt_mac_filedialog_filter_proc(AEDesc *theItem, void *info,
+ void *data, NavFilterModes)
+{
+ QFileDialogPrivate *fileDialogPrivate = static_cast<QFileDialogPrivate *>(data);
+
+ if (!fileDialogPrivate || fileDialogPrivate->filterInfo.filters.isEmpty()
+ || (fileDialogPrivate->filterInfo.currentSelection < 0
+ && fileDialogPrivate->filterInfo.currentSelection
+ >= fileDialogPrivate->filterInfo.filters.size()))
+ return true;
+
+ NavFileOrFolderInfo *theInfo = static_cast<NavFileOrFolderInfo *>(info);
+ QString file;
+ QString path;
+ const QtMacFilterName &fn
+ = fileDialogPrivate->filterInfo.filters.at(fileDialogPrivate->filterInfo.currentSelection);
+ if (theItem->descriptorType == typeFSRef) {
+ FSRef ref;
+ AEGetDescData(theItem, &ref, sizeof(ref));
+ UInt8 str_buffer[1024];
+ FSRefMakePath(&ref, str_buffer, 1024);
+ path = QString::fromUtf8(reinterpret_cast<const char *>(str_buffer));
+ int slsh = path.lastIndexOf(QLatin1Char('/'));
+ if (slsh != -1)
+ file = path.right(path.length() - slsh - 1);
+ else
+ file = path;
+ }
+ QStringList reg = fn.regexp.split(QLatin1String(";"));
+ for (QStringList::const_iterator it = reg.constBegin(); it != reg.constEnd(); ++it) {
+ QRegExp rg(*it, Qt::CaseInsensitive, QRegExp::Wildcard);
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("QFileDialogPrivate::qt_mac_filedialog_filter_proc:%d, asked to filter.. %s (%s)", __LINE__,
+ qPrintable(file), qPrintable(*it));
+#endif
+ if (rg.exactMatch(file))
+ return true;
+ }
+
+ if (theInfo->isFolder) {
+ if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:qt_mac_QStringToNSString(path)])
+ return false;
+ return true;
+ }
+ return false;
+}
+
+void QFileDialogPrivate::qt_mac_filedialog_event_proc(const NavEventCallbackMessage msg,
+ NavCBRecPtr p, NavCallBackUserData data)
+{
+ QFileDialogPrivate *fileDialogPrivate = static_cast<QFileDialogPrivate *>(data);
+
+ switch(msg) {
+ case kNavCBPopupMenuSelect: {
+ NavMenuItemSpec *s = static_cast<NavMenuItemSpec *>(p->eventData.eventDataParms.param);
+ if (int(s->menuType) != fileDialogPrivate->filterInfo.currentSelection) {
+ fileDialogPrivate->filterInfo.currentSelection = s->menuType;
+ emit fileDialogPrivate->q_func()->filterSelected(fileDialogPrivate->nameFilters.at(s->menuType));
+ }
+ if (fileDialogPrivate->acceptMode == QFileDialog::AcceptSave) {
+ QString base = QCFString::toQString(NavDialogGetSaveFileName(p->context));
+ QFileInfo fi(base);
+ base = fi.completeBaseName();
+ const QtMacFilterName &fn = fileDialogPrivate->filterInfo.filters.at(
+ fileDialogPrivate->filterInfo.currentSelection);
+ QStringList reg = fn.regexp.split(QLatin1String(";"), QString::SkipEmptyParts);
+ if (reg.count()) {
+ QString r = reg.first();
+ r = r.right(r.length()-1); // Strip the *
+ base += r; //"." + QString::number(s->menuType);
+ }
+ NavDialogSetSaveFileName(p->context, QCFString::toCFStringRef(base));
+ }
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("QFileDialogPrivate::qt_mac_filedialog_event_proc:%d - Selected a filter: %ld", __LINE__, s->menuType);
+#endif
+ break; }
+ case kNavCBStart:{
+ fileDialogPrivate->mDialogStarted = true;
+ // Set selected file:
+ QModelIndexList indexes = fileDialogPrivate->qFileDialogUi->listView->selectionModel()->selectedRows();
+ QString selected;
+ if (!indexes.isEmpty())
+ selected = indexes.at(0).data(QFileSystemModel::FilePathRole).toString();
+ else
+ selected = fileDialogPrivate->typedFiles().value(0);
+ fileDialogPrivate->selectFile_sys(selected);
+ fileDialogPrivate->selectNameFilter_sys(fileDialogPrivate->qFileDialogUi->fileTypeCombo->currentText());
+ break; }
+ case kNavCBSelectEntry:{
+ // Event: Current selection has changed.
+ QStringList prevSelectionList = fileDialogPrivate->mCurrentSelectionList;
+ fileDialogPrivate->mCurrentSelectionList.clear();
+ QString fileNameToEmit;
+
+ AEDescList *descList = (AEDescList *)p->eventData.eventDataParms.param;
+ // Get the number of files selected:
+ UInt8 strBuffer[1024];
+ long count;
+ OSErr err = AECountItems(descList, &count);
+ if (err != noErr || !count)
+ break;
+
+ for (long index=1; index<=count; ++index) {
+ FSRef ref;
+ err = AEGetNthPtr(descList, index, typeFSRef, 0, 0, &ref, sizeof(ref), 0);
+ if (err != noErr)
+ break;
+ FSRefMakePath(&ref, strBuffer, 1024);
+ QString selected = QString::fromUtf8((const char *)strBuffer);
+ fileDialogPrivate->mCurrentSelectionList << selected;
+ if (!prevSelectionList.contains(selected))
+ fileNameToEmit = selected;
+ }
+
+ if (!fileNameToEmit.isEmpty() && fileNameToEmit != fileDialogPrivate->mCurrentSelection)
+ emit fileDialogPrivate->q_func()->currentChanged(fileNameToEmit);
+ fileDialogPrivate->mCurrentSelection = fileNameToEmit;
+ break; }
+ case kNavCBShowDesktop:
+ case kNavCBNewLocation:{
+ // Event: Current directory has changed.
+ AEDesc *desc = (AEDesc *)p->eventData.eventDataParms.param;
+ FSRef ref;
+ AEGetDescData(desc, &ref, sizeof(ref));
+ UInt8 *strBuffer = (UInt8 *)malloc(1024);
+ FSRefMakePath(&ref, strBuffer, 1024);
+ QString newLocation = QString::fromUtf8((const char *)strBuffer);
+ free(strBuffer);
+ if (fileDialogPrivate->mCurrentLocation != newLocation){
+ fileDialogPrivate->mCurrentLocation = newLocation;
+ QFileDialog::FileMode mode = fileDialogPrivate->fileMode;
+ if (mode == QFileDialog::AnyFile || mode == QFileDialog::ExistingFile
+ || mode == QFileDialog::ExistingFiles){
+ // When changing directory, the current selection is cleared if
+ // we are supposed to be selecting files only:
+ if (!fileDialogPrivate->mCurrentSelection.isEmpty()){
+ fileDialogPrivate->mCurrentSelectionList.clear();
+ fileDialogPrivate->mCurrentSelection.clear();
+ emit fileDialogPrivate->q_func()->currentChanged(fileDialogPrivate->mCurrentSelection);
+ }
+ }
+ fileDialogPrivate->setLastVisitedDirectory(newLocation);
+ emit fileDialogPrivate->q_func()->directoryEntered(newLocation);
+ }
+ break; }
+ case kNavCBAccept:
+ fileDialogPrivate->mDialogClosed = true;
+ fileDialogPrivate->q_func()->accept();
+ break;
+ case kNavCBCancel:
+ fileDialogPrivate->mDialogClosed = true;
+ fileDialogPrivate->q_func()->reject();
+ break;
+ }
+}
+
+static QFileDialogPrivate::QtMacFilterName qt_mac_extract_filter(const QString &rawFilter, bool showDetails)
+{
+ QFileDialogPrivate::QtMacFilterName ret;
+ ret.filter = rawFilter;
+ QString result = rawFilter;
+ QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
+ int index = r.indexIn(result);
+ if (index >= 0)
+ result = r.cap(2);
+
+ if (showDetails) {
+ ret.description = rawFilter;
+ } else {
+ if (index >= 0)
+ ret.description = r.cap(1).trimmed();
+ if (ret.description.isEmpty())
+ ret.description = result;
+ }
+ ret.regexp = result.replace(QLatin1Char(' '), QLatin1Char(';'));
+ return ret;
+}
+
+static QList<QFileDialogPrivate::QtMacFilterName> qt_mac_make_filters_list(const QString &filter, bool showDetails)
+{
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("QFileDialog:%d - Got filter (%s)", __LINE__, filter.latin1());
+#endif
+
+ QList<QFileDialogPrivate::QtMacFilterName> ret;
+ QString f(filter);
+ if (f.isEmpty())
+ f = QFileDialog::tr("All Files (*)");
+ if (f.isEmpty())
+ return ret;
+ QStringList filts = qt_make_filter_list(f);
+ for (QStringList::const_iterator it = filts.constBegin(); it != filts.constEnd(); ++it) {
+ QFileDialogPrivate::QtMacFilterName filter = qt_mac_extract_filter(*it, showDetails);
+#ifdef DEBUG_FILEDIALOG_FILTERS
+ qDebug("QFileDialog:%d Split out filter (%d) '%s' '%s' [%s]", __LINE__, ret.count(),
+ filter->regxp.latin1(), filter->description.latin1(), (*it).latin1());
+#endif
+ ret.append(filter);
+ }
+ return ret;
+}
+
+void QFileDialogPrivate::createNavServicesDialog()
+{
+ Q_Q(QFileDialog);
+ if (mDialog)
+ deleteNativeDialog_sys();
+
+ NavDialogCreationOptions navOptions;
+ NavGetDefaultDialogCreationOptions(&navOptions);
+
+ // Translate QFileDialog settings into NavDialog options:
+ if (qt_mac_is_macsheet(q)) {
+ navOptions.modality = kWindowModalityWindowModal;
+ navOptions.parentWindow = qt_mac_window_for(q->parentWidget());
+ } else if (q->windowModality() == Qt::ApplicationModal)
+ navOptions.modality = kWindowModalityAppModal;
+ else
+ navOptions.modality = kWindowModalityNone;
+ navOptions.optionFlags |= kNavSupportPackages;
+ if (q->testOption(QFileDialog::DontConfirmOverwrite))
+ navOptions.optionFlags |= kNavDontConfirmReplacement;
+ if (fileMode != QFileDialog::ExistingFiles)
+ navOptions.optionFlags &= ~kNavAllowMultipleFiles;
+
+ navOptions.windowTitle = QCFString::toCFStringRef(q->windowTitle());
+
+ navOptions.location.h = -1;
+ navOptions.location.v = -1;
+
+ QWidget *parent = q->parentWidget();
+ if (parent && parent->isVisible()) {
+ WindowClass wclass;
+ GetWindowClass(qt_mac_window_for(parent), &wclass);
+ parent = parent->window();
+ QString s = parent->windowTitle();
+ navOptions.clientName = QCFString::toCFStringRef(s);
+ }
+
+ filterInfo.currentSelection = 0;
+ filterInfo.filters = qt_mac_make_filters_list(nameFilters.join(QLatin1String(";;")), q->isNameFilterDetailsVisible());
+ QCFType<CFArrayRef> filterArray;
+ if (filterInfo.filters.size() > 1) {
+ int i = 0;
+ CFStringRef *cfstringArray = static_cast<CFStringRef *>(malloc(sizeof(CFStringRef)
+ * filterInfo.filters.size()));
+ for (i = 0; i < filterInfo.filters.size(); ++i) {
+ cfstringArray[i] = QCFString::toCFStringRef(filterInfo.filters.at(i).description);
+ }
+ filterArray = CFArrayCreate(kCFAllocatorDefault,
+ reinterpret_cast<const void **>(cfstringArray), filterInfo.filters.size(),
+ &kCFTypeArrayCallBacks);
+ navOptions.popupExtension = filterArray;
+ free(cfstringArray);
+ }
+
+ if (q->acceptMode() == QFileDialog::AcceptSave) {
+ if (NavCreatePutFileDialog(&navOptions, 'cute', kNavGenericSignature,
+ QFileDialogPrivate::qt_mac_filedialog_event_proc, this, &mDialog)) {
+ qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
+ return;
+ }
+ } else if (fileMode == QFileDialog::DirectoryOnly || fileMode == QFileDialog::Directory) {
+ if (NavCreateChooseFolderDialog(&navOptions,
+ QFileDialogPrivate::qt_mac_filedialog_event_proc, 0, this, &mDialog)) {
+ qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
+ return;
+ }
+ } else {
+ if (NavCreateGetFileDialog(&navOptions, 0,
+ QFileDialogPrivate::qt_mac_filedialog_event_proc, 0,
+ QFileDialogPrivate::qt_mac_filedialog_filter_proc, this, &mDialog)) {
+ qDebug("Shouldn't happen %s:%d", __FILE__, __LINE__);
+ return;
+ }
+ }
+
+ // Set start-up directory:
+ if (mCurrentLocation.isEmpty())
+ mCurrentLocation = rootPath();
+ FSRef fsRef;
+ if (qt_mac_create_fsref(mCurrentLocation, &fsRef) == noErr) {
+ AEDesc desc;
+ if (AECreateDesc(typeFSRef, &fsRef, sizeof(FSRef), &desc) == noErr)
+ NavCustomControl(mDialog, kNavCtlSetLocation, (void*)&desc);
+ }
+}
+
+bool QFileDialogPrivate::showCarbonNavServicesDialog()
+{
+ Q_Q(QFileDialog);
+ if (q->acceptMode() == QFileDialog::AcceptSave && q->windowModality() == Qt::NonModal)
+ return false; // cannot do native no-modal save dialogs.
+ createNavServicesDialog();
+ mDialogClosed = false;
+ if (q->windowModality() != Qt::ApplicationModal)
+ NavDialogRun(mDialog);
+ return true;
+}
+
+bool QFileDialogPrivate::hideCarbonNavServicesDialog()
+{
+ if (!mDialogClosed){
+ mDialogClosed = true;
+ NavCustomControl(mDialog, kNavCtlCancel, 0);
+ }
+ return true;
+}
+
+#else // Cocoa
+
+void QFileDialogPrivate::createNSOpenSavePanelDelegate()
+{
+ Q_Q(QFileDialog);
+ if (mDelegate)
+ return;
+
+ bool selectDir = q->selectedFiles().isEmpty();
+ QString selection(selectDir ? q->directory().absolutePath() : q->selectedFiles().value(0));
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) alloc]
+ initWithAcceptMode:acceptMode
+ title:q->windowTitle()
+ hideNameFilterDetails:q->testOption(QFileDialog::HideNameFilterDetails)
+ qDirFilter:model->filter()
+ fileOptions:opts
+ fileMode:fileMode
+ selectFile:selection
+ confirmOverwrite:!q->testOption(QFileDialog::DontConfirmOverwrite)
+ priv:this];
+
+ mDelegate = delegate;
+}
+
+bool QFileDialogPrivate::showCocoaFilePanel()
+{
+ Q_Q(QFileDialog);
+ QMacCocoaAutoReleasePool pool;
+ createNSOpenSavePanelDelegate();
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (qt_mac_is_macsheet(q))
+ [delegate showWindowModalSheet:q->parentWidget()];
+ else
+ [delegate showModelessPanel];
+ return true;
+}
+
+bool QFileDialogPrivate::hideCocoaFilePanel()
+{
+ if (!mDelegate){
+ // Nothing to do. We return false to leave the question
+ // open regarding whether or not to go native:
+ return false;
+ } else {
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ [delegate closePanel];
+ // Even when we hide it, we are still using a
+ // native dialog, so return true:
+ return true;
+ }
+}
+
+#endif
+
+void QFileDialogPrivate::mac_nativeDialogModalHelp()
+{
+ // Do a queued meta-call to open the native modal dialog so it opens after the new
+ // event loop has started to execute (in QDialog::exec). Using a timer rather than
+ // a queued meta call is intentional to ensure that the call is only delivered when
+ // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
+ // running (which is the case if e.g a top-most QEventLoop has been
+ // interrupted, and the second-most event loop has not yet been reactivated (regardless
+ // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
+ if (nativeDialogInUse){
+ Q_Q(QFileDialog);
+ QTimer::singleShot(1, q, SLOT(_q_macRunNativeAppModalPanel()));
+ }
+}
+
+void QFileDialogPrivate::_q_macRunNativeAppModalPanel()
+{
+ QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
+#ifndef QT_MAC_USE_COCOA
+ NavDialogRun(mDialog);
+#else
+ Q_Q(QFileDialog);
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ [delegate runApplicationModalPanel];
+ dialogResultCode_sys() == QDialog::Accepted ? q->accept() : q->reject();
+#endif
+}
+
+QDialog::DialogCode QFileDialogPrivate::dialogResultCode_sys()
+{
+#ifndef QT_MAC_USE_COCOA
+ NavUserAction result = NavDialogGetUserAction(mDialog);
+ if (result == kNavUserActionCancel || result == kNavUserActionNone)
+ return QDialog::Rejected;
+ else
+ return QDialog::Accepted;
+#else
+ QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ return [delegate dialogResultCode];
+#endif
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FILEDIALOG
+
diff --git a/src/widgets/dialogs/qfiledialog_p.h b/src/widgets/dialogs/qfiledialog_p.h
new file mode 100644
index 0000000000..6a534bb60f
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog_p.h
@@ -0,0 +1,427 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILEDIALOG_P_H
+#define QFILEDIALOG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_FILEDIALOG
+
+#include "qfiledialog.h"
+#include "private/qdialog_p.h"
+#include "qplatformdefs.h"
+
+#include "qfilesystemmodel_p.h"
+#include <qlistview.h>
+#include <qtreeview.h>
+#include <qcombobox.h>
+#include <qtoolbutton.h>
+#include <qlabel.h>
+#include <qevent.h>
+#include <qlineedit.h>
+#include <qurl.h>
+#include <qstackedwidget.h>
+#include <qdialogbuttonbox.h>
+#include <qabstractproxymodel.h>
+#include <qcompleter.h>
+#include <qpointer.h>
+#include <qdebug.h>
+#include "qsidebar_p.h"
+#include "qfscompleter_p.h"
+#include "private/qguiplatformplugin_p.h"
+
+
+#if defined (Q_OS_UNIX)
+#include <unistd.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFileDialogListView;
+class QFileDialogTreeView;
+class QFileDialogLineEdit;
+class QGridLayout;
+class QCompleter;
+class QHBoxLayout;
+class Ui_QFileDialog;
+
+
+struct QFileDialogArgs
+{
+ QFileDialogArgs() : parent(0), mode(QFileDialog::AnyFile) {}
+
+ QWidget *parent;
+ QString caption;
+ QString directory;
+ QString selection;
+ QString filter;
+ QFileDialog::FileMode mode;
+ QFileDialog::Options options;
+};
+
+#define UrlRole (Qt::UserRole + 1)
+
+class Q_AUTOTEST_EXPORT QFileDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QFileDialog)
+
+public:
+ QFileDialogPrivate();
+
+ void createToolButtons();
+ void createMenuActions();
+ void createWidgets();
+
+ void init(const QString &directory = QString(), const QString &nameFilter = QString(),
+ const QString &caption = QString());
+ bool itemViewKeyboardEvent(QKeyEvent *event);
+ QString getEnvironmentVariable(const QString &string);
+ static QString workingDirectory(const QString &path);
+ static QString initialSelection(const QString &path);
+ QStringList typedFiles() const;
+ QStringList addDefaultSuffixToFiles(const QStringList filesToFix) const;
+ bool removeDirectory(const QString &path);
+
+ inline QModelIndex mapToSource(const QModelIndex &index) const;
+ inline QModelIndex mapFromSource(const QModelIndex &index) const;
+ inline QModelIndex rootIndex() const;
+ inline void setRootIndex(const QModelIndex &index) const;
+ inline QModelIndex select(const QModelIndex &index) const;
+ inline QString rootPath() const;
+
+ QLineEdit *lineEdit() const;
+
+ int maxNameLength(const QString &path) {
+#if defined(Q_OS_UNIX)
+ return ::pathconf(QFile::encodeName(path).data(), _PC_NAME_MAX);
+#elif defined(Q_OS_WIN)
+#ifndef Q_OS_WINCE
+ DWORD maxLength;
+ QString drive = path.left(3);
+ if (::GetVolumeInformation(reinterpret_cast<const wchar_t *>(drive.utf16()), NULL, 0, NULL, &maxLength, NULL, NULL, 0) == FALSE)
+ return -1;
+ return maxLength;
+#else
+ Q_UNUSED(path);
+ return MAX_PATH;
+#endif //Q_OS_WINCE
+#else
+ Q_UNUSED(path);
+#endif
+ return -1;
+ }
+
+ QString basename(const QString &path) const
+ {
+ int separator = QDir::toNativeSeparators(path).lastIndexOf(QDir::separator());
+ if (separator != -1)
+ return path.mid(separator + 1);
+ return path;
+ }
+
+ QDir::Filters filterForMode(QDir::Filters filters) const
+ {
+ if (fileMode == QFileDialog::DirectoryOnly) {
+ filters |= QDir::Drives | QDir::AllDirs | QDir::Dirs;
+ filters &= ~QDir::Files;
+ } else {
+ filters |= QDir::Drives | QDir::AllDirs | QDir::Files | QDir::Dirs;
+ }
+ return filters;
+ }
+
+ QAbstractItemView *currentView() const;
+
+ static inline QString toInternal(const QString &path)
+ {
+#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN)
+ QString n(path);
+ for (int i = 0; i < (int)n.length(); ++i)
+ if (n[i] == QLatin1Char('\\')) n[i] = QLatin1Char('/');
+#if defined(Q_OS_WINCE)
+ if ((n.size() > 1) && (n.startsWith(QLatin1String("//"))))
+ n = n.mid(1);
+#endif
+ return n;
+#else // the compile should optimize away this
+ return path;
+#endif
+ }
+
+ void setLastVisitedDirectory(const QString &dir);
+ void retranslateWindowTitle();
+ void retranslateStrings();
+ void emitFilesSelected(const QStringList &files);
+
+ void _q_goHome();
+ void _q_pathChanged(const QString &);
+ void _q_navigateBackward();
+ void _q_navigateForward();
+ void _q_navigateToParent();
+ void _q_createDirectory();
+ void _q_showListView();
+ void _q_showDetailsView();
+ void _q_showContextMenu(const QPoint &position);
+ void _q_renameCurrent();
+ void _q_deleteCurrent();
+ void _q_showHidden();
+ void _q_showHeader(QAction *);
+ void _q_updateOkButton();
+ void _q_currentChanged(const QModelIndex &index);
+ void _q_enterDirectory(const QModelIndex &index);
+ void _q_goToDirectory(const QString &);
+ void _q_useNameFilter(int index);
+ void _q_selectionChanged();
+ void _q_goToUrl(const QUrl &url);
+ void _q_autoCompleteFileName(const QString &);
+ void _q_rowsInserted(const QModelIndex & parent);
+ void _q_fileRenamed(const QString &path, const QString oldName, const QString newName);
+
+ // layout
+#ifndef QT_NO_PROXYMODEL
+ QAbstractProxyModel *proxyModel;
+#endif
+
+ // data
+ QStringList watching;
+ QFileSystemModel *model;
+
+#ifndef QT_NO_FSCOMPLETER
+ QFSCompleter *completer;
+#endif //QT_NO_FSCOMPLETER
+
+ QFileDialog::FileMode fileMode;
+ QFileDialog::AcceptMode acceptMode;
+ bool confirmOverwrite;
+ QString defaultSuffix;
+ QString setWindowTitle;
+
+ QStringList currentHistory;
+ int currentHistoryLocation;
+
+ QAction *renameAction;
+ QAction *deleteAction;
+ QAction *showHiddenAction;
+ QAction *newFolderAction;
+
+ bool useDefaultCaption;
+ bool defaultFileTypes;
+ bool fileNameLabelExplicitlySat;
+ QStringList nameFilters;
+
+ // Members for using native dialogs:
+ bool nativeDialogInUse;
+ // setVisible_sys returns true if it ends up showing a native
+ // dialog. Returning false means that a non-native dialog must be
+ // used instead.
+ bool canBeNativeDialog();
+ bool setVisible_sys(bool visible);
+ void deleteNativeDialog_sys();
+ QDialog::DialogCode dialogResultCode_sys();
+
+ void setDirectory_sys(const QString &directory);
+ QString directory_sys() const;
+ void selectFile_sys(const QString &filename);
+ QStringList selectedFiles_sys() const;
+ void setFilter_sys();
+ void setNameFilters_sys(const QStringList &filters);
+ void selectNameFilter_sys(const QString &filter);
+ QString selectedNameFilter_sys() const;
+ //////////////////////////////////////////////
+
+#if defined(Q_WS_MAC)
+ void *mDelegate;
+#ifndef QT_MAC_USE_COCOA
+ NavDialogRef mDialog;
+ bool mDialogStarted;
+ bool mDialogClosed;
+ QString mCurrentLocation;
+ QString mCurrentSelection;
+ QStringList mCurrentSelectionList;
+
+ struct QtMacFilterName {
+ QString description;
+ QString regexp;
+ QString filter;
+ };
+ struct QtMacNavFilterInfo {
+ QtMacNavFilterInfo() : currentSelection(-1) {}
+ int currentSelection;
+ QList<QtMacFilterName> filters;
+ } filterInfo;
+
+ static void qt_mac_filedialog_event_proc(const NavEventCallbackMessage msg, NavCBRecPtr p,
+ NavCallBackUserData data);
+ static Boolean qt_mac_filedialog_filter_proc(AEDesc *theItem, void *info, void *data,
+ NavFilterModes);
+ bool showCarbonNavServicesDialog();
+ bool hideCarbonNavServicesDialog();
+ void createNavServicesDialog();
+#else
+ bool showCocoaFilePanel();
+ bool hideCocoaFilePanel();
+#endif
+ void createNSOpenSavePanelDelegate();
+ void QNSOpenSavePanelDelegate_selectionChanged(const QString &newPath);
+ void QNSOpenSavePanelDelegate_panelClosed(bool accepted);
+ void QNSOpenSavePanelDelegate_directoryEntered(const QString &newDir);
+ void QNSOpenSavePanelDelegate_filterSelected(int menuIndex);
+ void _q_macRunNativeAppModalPanel();
+ void mac_nativeDialogModalHelp();
+#endif
+
+ QScopedPointer<Ui_QFileDialog> qFileDialogUi;
+
+ QString acceptLabel;
+
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+ QByteArray signalToDisconnectOnClose;
+
+ QFileDialog::Options opts;
+
+ ~QFileDialogPrivate();
+
+private:
+ Q_DISABLE_COPY(QFileDialogPrivate)
+};
+
+class QFileDialogLineEdit : public QLineEdit
+{
+public:
+ QFileDialogLineEdit(QWidget *parent = 0) : QLineEdit(parent), hideOnEsc(false), d_ptr(0){}
+ void init(QFileDialogPrivate *d_pointer) {d_ptr = d_pointer; }
+ void keyPressEvent(QKeyEvent *e);
+ bool hideOnEsc;
+private:
+ QFileDialogPrivate *d_ptr;
+};
+
+class QFileDialogComboBox : public QComboBox
+{
+public:
+ QFileDialogComboBox(QWidget *parent = 0) : QComboBox(parent), urlModel(0) {}
+ void init(QFileDialogPrivate *d_pointer);
+ void showPopup();
+ void setHistory(const QStringList &paths);
+ QStringList history() const { return m_history; }
+ void paintEvent(QPaintEvent *);
+
+private:
+ QUrlModel *urlModel;
+ QFileDialogPrivate *d_ptr;
+ QStringList m_history;
+};
+
+class QFileDialogListView : public QListView
+{
+public:
+ QFileDialogListView(QWidget *parent = 0);
+ void init(QFileDialogPrivate *d_pointer);
+ QSize sizeHint() const;
+protected:
+ void keyPressEvent(QKeyEvent *e);
+private:
+ QFileDialogPrivate *d_ptr;
+};
+
+class QFileDialogTreeView : public QTreeView
+{
+public:
+ QFileDialogTreeView(QWidget *parent);
+ void init(QFileDialogPrivate *d_pointer);
+ QSize sizeHint() const;
+
+protected:
+ void keyPressEvent(QKeyEvent *e);
+private:
+ QFileDialogPrivate *d_ptr;
+};
+
+inline QModelIndex QFileDialogPrivate::mapToSource(const QModelIndex &index) const {
+#ifdef QT_NO_PROXYMODEL
+ return index;
+#else
+ return proxyModel ? proxyModel->mapToSource(index) : index;
+#endif
+}
+inline QModelIndex QFileDialogPrivate::mapFromSource(const QModelIndex &index) const {
+#ifdef QT_NO_PROXYMODEL
+ return index;
+#else
+ return proxyModel ? proxyModel->mapFromSource(index) : index;
+#endif
+}
+
+inline QString QFileDialogPrivate::rootPath() const {
+ return model->rootPath();
+}
+
+#ifndef Q_WS_MAC
+ // Dummies for platforms that don't use native dialogs:
+ inline void QFileDialogPrivate::deleteNativeDialog_sys() { qt_guiPlatformPlugin()->fileDialogDelete(q_func()); }
+ inline bool QFileDialogPrivate::setVisible_sys(bool visible) { return qt_guiPlatformPlugin()->fileDialogSetVisible(q_func(), visible); }
+ inline QDialog::DialogCode QFileDialogPrivate::dialogResultCode_sys(){ return qt_guiPlatformPlugin()->fileDialogResultCode(q_func()); }
+ inline void QFileDialogPrivate::setDirectory_sys(const QString &directory) { qt_guiPlatformPlugin()->fileDialogSetDirectory(q_func(), directory); }
+ inline QString QFileDialogPrivate::directory_sys() const { return qt_guiPlatformPlugin()->fileDialogDirectory(q_func()); }
+ inline void QFileDialogPrivate::selectFile_sys(const QString &filename) { qt_guiPlatformPlugin()->fileDialogSelectFile(q_func(), filename); }
+ inline QStringList QFileDialogPrivate::selectedFiles_sys() const { return qt_guiPlatformPlugin()->fileDialogSelectedFiles(q_func()); }
+ inline void QFileDialogPrivate::setFilter_sys() { qt_guiPlatformPlugin()->fileDialogSetFilter(q_func()); }
+ inline void QFileDialogPrivate::setNameFilters_sys(const QStringList &filters) { qt_guiPlatformPlugin()->fileDialogSetNameFilters(q_func(), filters); }
+ inline void QFileDialogPrivate::selectNameFilter_sys(const QString &filter) { qt_guiPlatformPlugin()->fileDialogSelectNameFilter(q_func(), filter); }
+ inline QString QFileDialogPrivate::selectedNameFilter_sys() const { return qt_guiPlatformPlugin()->fileDialogSelectedNameFilter(q_func()); }
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FILEDIALOG
+
+#endif // QFILEDIALOG_P_H
diff --git a/src/widgets/dialogs/qfiledialog_symbian.cpp b/src/widgets/dialogs/qfiledialog_symbian.cpp
new file mode 100644
index 0000000000..a4a7a228ba
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog_symbian.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfiledialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+#include <private/qfiledialog_p.h>
+#if defined(Q_WS_S60) && defined(SYMBIAN_VERSION_SYMBIAN3)
+#include <driveinfo.h>
+#include <AknCommonDialogsDynMem.h>
+#include <CAknMemorySelectionDialogMultiDrive.h>
+#include <MAknFileFilter.h>
+#endif
+#include "private/qcore_symbian_p.h"
+
+QT_BEGIN_NAMESPACE
+
+extern QStringList qt_make_filter_list(const QString &filter); // defined in qfiledialog.cpp
+extern QStringList qt_clean_filter_list(const QString &filter); // defined in qfiledialog.cpp
+
+enum DialogMode { DialogOpen, DialogSave, DialogFolder };
+#if defined(Q_WS_S60) && defined(SYMBIAN_VERSION_SYMBIAN3)
+class CExtensionFilter : public MAknFileFilter
+{
+public:
+ void setFilter(const QString filter)
+ {
+ QStringList unparsedFiltersList = qt_make_filter_list(filter);
+ QStringList filterList;
+ filterRxList.clear();
+
+ foreach (QString unparsedFilter, unparsedFiltersList) {
+ filterList << qt_clean_filter_list(unparsedFilter);
+ }
+ foreach (QString currentFilter, filterList) {
+ QRegExp filterRx(currentFilter, Qt::CaseInsensitive, QRegExp::Wildcard);
+ filterRxList << filterRx;
+ }
+ }
+
+ TBool Accept(const TDesC &/*aDriveAndPath*/, const TEntry &aEntry) const
+ {
+ //If no filter for files, all can be accepted
+ if (filterRxList.isEmpty())
+ return ETrue;
+
+ if (aEntry.IsDir())
+ return ETrue;
+
+ foreach (QRegExp rx, filterRxList) {
+ QString fileName = qt_TDesC2QString(aEntry.iName);
+ if (rx.exactMatch(fileName))
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+private:
+ QList<QRegExp> filterRxList;
+};
+#endif
+
+static QString launchSymbianDialog(const QString dialogCaption, const QString startDirectory,
+ const QString filter, DialogMode dialogMode)
+{
+ QString selection;
+#if defined(Q_WS_S60) && defined(SYMBIAN_VERSION_SYMBIAN3)
+ TFileName startFolder;
+ if (!startDirectory.isEmpty()) {
+ QString dir = QDir::toNativeSeparators(QFileDialogPrivate::workingDirectory(startDirectory));
+ startFolder = qt_QString2TPtrC(dir);
+ }
+ TInt types = AknCommonDialogsDynMem::EMemoryTypeMMCExternal|
+ AknCommonDialogsDynMem::EMemoryTypeInternalMassStorage|
+ AknCommonDialogsDynMem::EMemoryTypePhone;
+
+ TPtrC titlePtr(qt_QString2TPtrC(dialogCaption));
+ TFileName target;
+ bool select = false;
+ int tryCount = 2;
+ while (tryCount--) {
+ TInt err(KErrNone);
+ TRAP(err,
+ if (dialogMode == DialogOpen) {
+ CExtensionFilter* extensionFilter = new (ELeave) CExtensionFilter;
+ CleanupStack::PushL(extensionFilter);
+ extensionFilter->setFilter(filter);
+ select = AknCommonDialogsDynMem::RunSelectDlgLD(types, target,
+ startFolder, 0, 0, titlePtr, extensionFilter);
+ CleanupStack::Pop(extensionFilter);
+ } else if (dialogMode == DialogSave) {
+ QString defaultFileName = QFileDialogPrivate::initialSelection(startDirectory);
+ target = qt_QString2TPtrC(defaultFileName);
+ select = AknCommonDialogsDynMem::RunSaveDlgLD(types, target,
+ startFolder, 0, 0, titlePtr);
+ } else if (dialogMode == DialogFolder) {
+ select = AknCommonDialogsDynMem::RunFolderSelectDlgLD(types, target, startFolder,
+ 0, 0, titlePtr, NULL, NULL);
+ }
+ );
+
+ if (err == KErrNone) {
+ tryCount = 0;
+ } else {
+ // Symbian native file dialog doesn't allow accessing files outside C:/Data
+ // It will always leave in that case, so default into QDir::rootPath() in error cases.
+ QString dir = QDir::toNativeSeparators(QDir::rootPath());
+ startFolder = qt_QString2TPtrC(dir);
+ }
+ }
+ if (select) {
+ QFileInfo fi(qt_TDesC2QString(target));
+ selection = fi.absoluteFilePath();
+ }
+#endif
+ return selection;
+}
+
+QString qtSymbianGetOpenFileName(const QString &caption,
+ const QString &dir,
+ const QString &filter)
+{
+ return launchSymbianDialog(caption, dir, filter, DialogOpen);
+}
+
+QStringList qtSymbianGetOpenFileNames(const QString &caption,
+ const QString &dir,
+ const QString &filter)
+{
+ QString fileName;
+ fileName.append(launchSymbianDialog(caption, dir, filter, DialogOpen));
+ QStringList fileList;
+ fileList << fileName;
+
+ return fileList;
+}
+
+QString qtSymbianGetSaveFileName(const QString &caption,
+ const QString &dir)
+{
+ return launchSymbianDialog(caption, dir, QString(), DialogSave);
+}
+
+QString qtSymbianGetExistingDirectory(const QString &caption,
+ const QString &dir)
+{
+ QString folderCaption;
+ if (!caption.isEmpty()) {
+ folderCaption.append(caption);
+ } else {
+ // Title for folder selection dialog is mandatory
+ folderCaption.append(QFileDialog::tr("Find Directory"));
+ }
+ return launchSymbianDialog(folderCaption, dir, QString(), DialogFolder);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qfiledialog_win.cpp b/src/widgets/dialogs/qfiledialog_win.cpp
new file mode 100644
index 0000000000..8c3b3cfda7
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog_win.cpp
@@ -0,0 +1,839 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfiledialog.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+#include <private/qfiledialog_p.h>
+#include <qapplication.h>
+#include <private/qapplication_p.h>
+#include <qt_windows.h>
+#include <qglobal.h>
+#include <qregexp.h>
+#include <qbuffer.h>
+#include <qdir.h>
+#include <qstringlist.h>
+#include <private/qsystemlibrary_p.h>
+#include "qfiledialog_win_p.h"
+#include "qplatformnativeinterface_qpa.h"
+
+#ifndef QT_NO_THREAD
+# include <private/qmutexpool_p.h>
+#endif
+
+#ifdef Q_WS_WINCE
+#include <commdlg.h>
+bool qt_priv_ptr_valid = false;
+#else
+//we have to declare them here because they're not present for all SDK/compilers
+static const IID QT_IID_IFileOpenDialog = {0xd57c7288, 0xd4ad, 0x4768, {0xbe, 0x02, 0x9d, 0x96, 0x95, 0x32, 0xd9, 0x60} };
+static const IID QT_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe} };
+static const CLSID QT_CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7} };
+#endif
+
+
+typedef qt_LPITEMIDLIST (WINAPI *PtrSHBrowseForFolder)(qt_BROWSEINFO*);
+static PtrSHBrowseForFolder ptrSHBrowseForFolder = 0;
+typedef BOOL (WINAPI *PtrSHGetPathFromIDList)(qt_LPITEMIDLIST, LPWSTR);
+static PtrSHGetPathFromIDList ptrSHGetPathFromIDList = 0;
+typedef HRESULT (WINAPI *PtrSHGetMalloc)(LPMALLOC *);
+static PtrSHGetMalloc ptrSHGetMalloc = 0;
+
+
+QT_BEGIN_NAMESPACE
+
+static void qt_win_resolve_libs()
+{
+ static bool triedResolve = false;
+
+ if (!triedResolve) {
+#ifndef QT_NO_THREAD
+ // protect initialization
+ QMutexLocker locker(QMutexPool::globalInstanceGet(&triedResolve));
+ // check triedResolve again, since another thread may have already
+ // done the initialization
+ if (triedResolve) {
+ // another thread did initialize the security function pointers,
+ // so we shouldn't do it again.
+ return;
+ }
+#endif
+
+ triedResolve = true;
+#if !defined(Q_WS_WINCE)
+ QSystemLibrary lib(L"shell32");
+ ptrSHBrowseForFolder = (PtrSHBrowseForFolder)lib.resolve("SHBrowseForFolderW");
+ ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)lib.resolve("SHGetPathFromIDListW");
+ ptrSHGetMalloc = (PtrSHGetMalloc)lib.resolve("SHGetMalloc");
+#else
+ // CE stores them in a different lib and does not use unicode version
+ HINSTANCE handle = LoadLibrary(L"Ceshell");
+ ptrSHBrowseForFolder = (PtrSHBrowseForFolder)GetProcAddress(handle, L"SHBrowseForFolder");
+ ptrSHGetPathFromIDList = (PtrSHGetPathFromIDList)GetProcAddress(handle, L"SHGetPathFromIDList");
+ ptrSHGetMalloc = (PtrSHGetMalloc)GetProcAddress(handle, L"SHGetMalloc");
+ if (ptrSHBrowseForFolder && ptrSHGetPathFromIDList && ptrSHGetMalloc)
+ qt_priv_ptr_valid = true;
+#endif
+ }
+}
+
+extern const char* qt_file_dialog_filter_reg_exp; // defined in qfiledialog.cpp
+extern QStringList qt_make_filter_list(const QString &filter);
+
+const int maxNameLen = 1023;
+const int maxMultiLen = 65535;
+
+// Returns the wildcard part of a filter.
+static QString qt_win_extract_filter(const QString &rawFilter)
+{
+ QString result = rawFilter;
+ QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
+ int index = r.indexIn(result);
+ if (index >= 0)
+ result = r.cap(2);
+ QStringList list = result.split(QLatin1Char(' '));
+ for(QStringList::iterator it = list.begin(); it < list.end(); ++it) {
+ if (*it == QLatin1String("*")) {
+ *it = QLatin1String("*.*");
+ break;
+ }
+ }
+ return list.join(QLatin1String(";"));
+}
+
+static QStringList qt_win_make_filters_list(const QString &filter)
+{
+ QString f(filter);
+
+ if (f.isEmpty())
+ f = QFileDialog::tr("All Files (*.*)");
+
+ return qt_make_filter_list(f);
+}
+
+// Makes a NUL-oriented Windows filter from a Qt filter.
+static QString qt_win_filter(const QString &filter, bool hideFiltersDetails)
+{
+ QStringList filterLst = qt_win_make_filters_list(filter);
+ QStringList::Iterator it = filterLst.begin();
+ QString winfilters;
+ QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
+ for (; it != filterLst.end(); ++it) {
+ QString subfilter = *it;
+ if (!subfilter.isEmpty()) {
+ if (hideFiltersDetails) {
+ int index = r.indexIn(subfilter);
+ if (index >= 0)
+ winfilters += r.cap(1);
+ } else {
+ winfilters += subfilter;
+ }
+ winfilters += QChar();
+ winfilters += qt_win_extract_filter(subfilter);
+ winfilters += QChar();
+ }
+ }
+ winfilters += QChar();
+ return winfilters;
+}
+
+static QString qt_win_selected_filter(const QString &filter, DWORD idx)
+{
+ return qt_win_make_filters_list(filter).at((int)idx - 1);
+}
+
+static QString tFilters, tTitle, tInitDir;
+
+static OPENFILENAME* qt_win_make_OFN(QWidget *parent,
+ const QString& initialSelection,
+ const QString& initialDirectory,
+ const QString& title,
+ const QString& filters,
+ QFileDialog::FileMode mode,
+ QFileDialog::Options options)
+{
+ if (parent)
+ parent = parent->window();
+ else
+ parent = QApplication::activeWindow();
+
+ tInitDir = QDir::toNativeSeparators(initialDirectory);
+ tFilters = filters;
+ tTitle = title;
+ QString initSel = QDir::toNativeSeparators(initialSelection);
+ if (!initSel.isEmpty()) {
+ initSel.remove(QLatin1Char('<'));
+ initSel.remove(QLatin1Char('>'));
+ initSel.remove(QLatin1Char('\"'));
+ initSel.remove(QLatin1Char('|'));
+ }
+
+ int maxLen = mode == QFileDialog::ExistingFiles ? maxMultiLen : maxNameLen;
+ wchar_t *tInitSel = new wchar_t[maxLen + 1];
+ if (initSel.length() > 0 && initSel.length() <= maxLen)
+ memcpy(tInitSel, initSel.utf16(), (initSel.length()+1)*sizeof(QChar));
+ else
+ tInitSel[0] = 0;
+
+ OPENFILENAME* ofn = new OPENFILENAME;
+ memset(ofn, 0, sizeof(OPENFILENAME));
+
+ ofn->lStructSize = sizeof(OPENFILENAME);
+ ofn->hwndOwner = QApplicationPrivate::getHWNDForWidget(parent);
+ ofn->lpstrFilter = (wchar_t*)tFilters.utf16();
+ ofn->lpstrFile = tInitSel;
+ ofn->nMaxFile = maxLen;
+ ofn->lpstrInitialDir = (wchar_t*)tInitDir.utf16();
+ ofn->lpstrTitle = (wchar_t*)tTitle.utf16();
+ ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_PATHMUSTEXIST);
+ if (mode == QFileDialog::ExistingFile ||
+ mode == QFileDialog::ExistingFiles)
+ ofn->Flags |= (OFN_FILEMUSTEXIST);
+ if (mode == QFileDialog::ExistingFiles)
+ ofn->Flags |= (OFN_ALLOWMULTISELECT);
+ if (!(options & QFileDialog::DontConfirmOverwrite))
+ ofn->Flags |= OFN_OVERWRITEPROMPT;
+
+ return ofn;
+}
+
+static void qt_win_clean_up_OFN(OPENFILENAME **ofn)
+{
+ delete [] (*ofn)->lpstrFile;
+ delete *ofn;
+ *ofn = 0;
+}
+
+void qt_win_eatMouseMove()
+{
+ // after closing a windows dialog with a double click (i.e. open a file)
+ // the message queue still contains a dubious WM_MOUSEMOVE message where
+ // the left button is reported to be down (wParam != 0).
+ // remove all those messages (usually 1) and post the last one with a
+ // reset button state
+
+ MSG msg = {0, 0, 0, 0, 0, {0, 0} };
+ while (PeekMessage(&msg, 0, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
+ ;
+ if (msg.message == WM_MOUSEMOVE)
+ PostMessage(msg.hwnd, msg.message, 0, msg.lParam);
+}
+
+QString qt_win_get_open_file_name(const QFileDialogArgs &args,
+ QString *initialDirectory,
+ QString *selectedFilter)
+{
+ QString result;
+
+ QString isel = args.selection;
+
+ if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+ initialDirectory->remove(0, 5);
+ QFileInfo fi(*initialDirectory);
+
+ if (initialDirectory && !fi.isDir()) {
+ *initialDirectory = fi.absolutePath();
+ if (isel.isEmpty())
+ isel = fi.fileName();
+ }
+
+ if (!fi.exists())
+ *initialDirectory = QDir::homePath();
+
+ DWORD selFilIdx = 0;
+
+ int idx = 0;
+ if (selectedFilter) {
+ QStringList filterLst = qt_win_make_filters_list(args.filter);
+ idx = filterLst.indexOf(*selectedFilter);
+ }
+
+ QDialog modal_widget;
+ modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+ modal_widget.setParent(args.parent, Qt::Window);
+ QApplicationPrivate::enterModal(&modal_widget);
+
+ bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
+ OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
+ args.directory, args.caption,
+ qt_win_filter(args.filter, hideFiltersDetails),
+ QFileDialog::ExistingFile,
+ args.options);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetOpenFileName(ofn)) {
+ result = QString::fromWCharArray(ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ }
+ qt_win_clean_up_OFN(&ofn);
+
+ QApplicationPrivate::leaveModal(&modal_widget);
+
+ qt_win_eatMouseMove();
+
+ if (result.isEmpty())
+ return result;
+
+ fi = result;
+ *initialDirectory = fi.path();
+ if (selectedFilter)
+ *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
+ return fi.absoluteFilePath();
+}
+
+QString qt_win_get_save_file_name(const QFileDialogArgs &args,
+ QString *initialDirectory,
+ QString *selectedFilter)
+{
+ QString result;
+
+ QString isel = args.selection;
+ if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+ initialDirectory->remove(0, 5);
+ QFileInfo fi(*initialDirectory);
+
+ if (initialDirectory && !fi.isDir()) {
+ *initialDirectory = fi.absolutePath();
+ if (isel.isEmpty())
+ isel = fi.fileName();
+ }
+
+ if (!fi.exists())
+ *initialDirectory = QDir::homePath();
+
+ DWORD selFilIdx = 0;
+
+ int idx = 0;
+ if (selectedFilter) {
+ QStringList filterLst = qt_win_make_filters_list(args.filter);
+ idx = filterLst.indexOf(*selectedFilter);
+ }
+
+ QDialog modal_widget;
+ modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+ modal_widget.setParent(args.parent, Qt::Window);
+ QApplicationPrivate::enterModal(&modal_widget);
+ bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
+ // This block is used below for the lpstrDefExt member.
+ // Note that the current MSDN docs document this member wrong.
+ // It should rather be documented as "the default extension if no extension was given and if the
+ // current filter does not have a extension (e.g (*)). If the current filter have an extension, use
+ // the extension of the current filter"
+ QString defaultSaveExt;
+ if (selectedFilter && !selectedFilter->isEmpty()) {
+ defaultSaveExt = qt_win_extract_filter(*selectedFilter);
+ // make sure we only have the extension
+ int firstDot = defaultSaveExt.indexOf(QLatin1Char('.'));
+ if (firstDot != -1) {
+ defaultSaveExt.remove(0, firstDot + 1);
+ } else {
+ defaultSaveExt.clear();
+ }
+ }
+
+ OPENFILENAME *ofn = qt_win_make_OFN(args.parent, args.selection,
+ args.directory, args.caption,
+ qt_win_filter(args.filter, hideFiltersDetails),
+ QFileDialog::AnyFile,
+ args.options);
+
+ ofn->lpstrDefExt = (wchar_t*)defaultSaveExt.utf16();
+
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetSaveFileName(ofn)) {
+ result = QString::fromWCharArray(ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ }
+ qt_win_clean_up_OFN(&ofn);
+
+#if defined(Q_WS_WINCE)
+ int semIndex = result.indexOf(QLatin1Char(';'));
+ if (semIndex >= 0)
+ result = result.left(semIndex);
+#endif
+
+ QApplicationPrivate::leaveModal(&modal_widget);
+
+ qt_win_eatMouseMove();
+
+ if (result.isEmpty())
+ return result;
+
+ fi = result;
+ *initialDirectory = fi.path();
+ if (selectedFilter)
+ *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
+ return fi.absoluteFilePath();
+}
+
+
+#ifndef Q_WS_WINCE
+
+typedef HRESULT (WINAPI *PtrSHCreateItemFromParsingName)(PCWSTR pszPath, IBindCtx *pbc, REFIID riid, void **ppv);
+static PtrSHCreateItemFromParsingName pSHCreateItemFromParsingName = 0;
+
+static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd,
+ const QString& initialSelection,
+ const QString& initialDirectory,
+ const QString& title,
+ const QStringList& filterLst,
+ QFileDialog::FileMode mode,
+ QFileDialog::Options options)
+{
+ if (!pSHCreateItemFromParsingName) {
+ // This function is available only in Vista & above.
+ QSystemLibrary shellLib(QLatin1String("Shell32"));
+ pSHCreateItemFromParsingName = (PtrSHCreateItemFromParsingName)
+ shellLib.resolve("SHCreateItemFromParsingName");
+ if (!pSHCreateItemFromParsingName)
+ return false;
+ }
+ HRESULT hr;
+ QString winfilters;
+ int numFilters = 0;
+ quint32 currentOffset = 0;
+ QList<quint32> offsets;
+ QStringList::ConstIterator it = filterLst.begin();
+ // Create the native filter string and save offset to each entry.
+ for (; it != filterLst.end(); ++it) {
+ QString subfilter = *it;
+ if (!subfilter.isEmpty()) {
+ offsets<<currentOffset;
+ //Here the COMMON_ITEM_DIALOG API always add the details for the filter (e.g. *.txt)
+ //so we don't need to handle the flag HideNameFilterDetails.
+ winfilters += subfilter; // The name of the filter.
+ winfilters += QChar();
+ currentOffset += subfilter.size()+1;
+ offsets<<currentOffset;
+ QString spec = qt_win_extract_filter(subfilter);
+ winfilters += spec; // The actual filter spec.
+ winfilters += QChar();
+ currentOffset += spec.size()+1;
+ numFilters++;
+ }
+ }
+ // Add the filters to the file dialog.
+ if (numFilters) {
+ wchar_t *szData = (wchar_t*)winfilters.utf16();
+ qt_COMDLG_FILTERSPEC *filterSpec = new qt_COMDLG_FILTERSPEC[numFilters];
+ for(int i = 0; i<numFilters; i++) {
+ filterSpec[i].pszName = szData+offsets[i*2];
+ filterSpec[i].pszSpec = szData+offsets[(i*2)+1];
+ }
+ hr = pfd->SetFileTypes(numFilters, filterSpec);
+ delete []filterSpec;
+ }
+ // Set the starting folder.
+ tInitDir = QDir::toNativeSeparators(initialDirectory);
+ if (!tInitDir.isEmpty()) {
+ IShellItem *psiDefaultFolder;
+ hr = pSHCreateItemFromParsingName((wchar_t*)tInitDir.utf16(), NULL, QT_IID_IShellItem,
+ reinterpret_cast<void**>(&psiDefaultFolder));
+
+ if (SUCCEEDED(hr)) {
+ hr = pfd->SetFolder(psiDefaultFolder);
+ psiDefaultFolder->Release();
+ }
+ }
+ // Set the currently selected file.
+ QString initSel = QDir::toNativeSeparators(initialSelection);
+ if (!initSel.isEmpty()) {
+ initSel.remove(QLatin1Char('<'));
+ initSel.remove(QLatin1Char('>'));
+ initSel.remove(QLatin1Char('\"'));
+ initSel.remove(QLatin1Char('|'));
+ }
+ if (!initSel.isEmpty()) {
+ hr = pfd->SetFileName((wchar_t*)initSel.utf16());
+ }
+ // Set the title for the file dialog.
+ if (!title.isEmpty()) {
+ hr = pfd->SetTitle((wchar_t*)title.utf16());
+ }
+ // Set other flags for the dialog.
+ DWORD newOptions;
+ hr = pfd->GetOptions(&newOptions);
+ if (SUCCEEDED(hr)) {
+ newOptions |= FOS_NOCHANGEDIR;
+ if (mode == QFileDialog::ExistingFile ||
+ mode == QFileDialog::ExistingFiles)
+ newOptions |= (FOS_FILEMUSTEXIST | FOS_PATHMUSTEXIST);
+ if (mode == QFileDialog::ExistingFiles)
+ newOptions |= FOS_ALLOWMULTISELECT;
+ if (!(options & QFileDialog::DontConfirmOverwrite))
+ newOptions |= FOS_OVERWRITEPROMPT;
+ hr = pfd->SetOptions(newOptions);
+ }
+ return SUCCEEDED(hr);
+}
+
+static QStringList qt_win_CID_get_open_file_names(const QFileDialogArgs &args,
+ QString *initialDirectory,
+ const QStringList &filterList,
+ QString *selectedFilter,
+ int selectedFilterIndex)
+{
+ QStringList result;
+ QDialog modal_widget;
+ modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+ modal_widget.setParent(args.parent, Qt::Window);
+ QApplicationPrivate::enterModal(&modal_widget);
+ // Multiple selection is allowed only in IFileOpenDialog.
+ IFileOpenDialog *pfd = 0;
+ HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, QT_IID_IFileOpenDialog,
+ reinterpret_cast<void**>(&pfd));
+
+ if (SUCCEEDED(hr)) {
+ qt_win_set_IFileDialogOptions(pfd, args.selection,
+ args.directory, args.caption,
+ filterList, QFileDialog::ExistingFiles,
+ args.options);
+ // Set the currently selected filter (one-based index).
+ hr = pfd->SetFileTypeIndex(selectedFilterIndex+1);
+ QWidget *parentWindow = args.parent;
+ if (parentWindow)
+ parentWindow = parentWindow->window();
+ else
+ parentWindow = QApplication::activeWindow();
+ // Show the file dialog.
+ hr = pfd->Show(QApplicationPrivate::getHWNDForWidget(parentWindow));
+ if (SUCCEEDED(hr)) {
+ // Retrieve the results.
+ IShellItemArray *psiaResults;
+ hr = pfd->GetResults(&psiaResults);
+ if (SUCCEEDED(hr)) {
+ DWORD numItems = 0;
+ psiaResults->GetCount(&numItems);
+ for (DWORD i = 0; i<numItems; i++) {
+ IShellItem *psi = 0;
+ hr = psiaResults->GetItemAt(i, &psi);
+ if (SUCCEEDED(hr)) {
+ // Retrieve the file name from shell item.
+ wchar_t *pszPath;
+ hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
+ if (SUCCEEDED(hr)) {
+ QString fileName = QString::fromWCharArray(pszPath);
+ result.append(fileName);
+ CoTaskMemFree(pszPath);
+ }
+ psi->Release(); // Free the current item.
+ }
+ }
+ psiaResults->Release(); // Free the array of items.
+ }
+ }
+ }
+ QApplicationPrivate::leaveModal(&modal_widget);
+
+ qt_win_eatMouseMove();
+
+ if (!result.isEmpty()) {
+ // Retrieve the current folder name.
+ IShellItem *psi = 0;
+ hr = pfd->GetFolder(&psi);
+ if (SUCCEEDED(hr)) {
+ wchar_t *pszPath;
+ hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
+ if (SUCCEEDED(hr)) {
+ *initialDirectory = QString::fromWCharArray(pszPath);
+ CoTaskMemFree(pszPath);
+ }
+ psi->Release();
+ }
+ // Retrieve the currently selected filter.
+ if (selectedFilter) {
+ quint32 filetype = 0;
+ hr = pfd->GetFileTypeIndex(&filetype);
+ if (SUCCEEDED(hr) && filetype && filetype <= (quint32)filterList.length()) {
+ // This is a one-based index, not zero-based.
+ *selectedFilter = filterList[filetype-1];
+ }
+ }
+ }
+ if (pfd)
+ pfd->Release();
+ return result;
+}
+
+QString qt_win_CID_get_existing_directory(const QFileDialogArgs &args)
+{
+ QString result;
+ QDialog modal_widget;
+ modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+ modal_widget.setParent(args.parent, Qt::Window);
+ QApplicationPrivate::enterModal(&modal_widget);
+
+ IFileOpenDialog *pfd = 0;
+ HRESULT hr = CoCreateInstance(QT_CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER,
+ QT_IID_IFileOpenDialog, reinterpret_cast<void**>(&pfd));
+
+ if (SUCCEEDED(hr)) {
+ qt_win_set_IFileDialogOptions(pfd, args.selection,
+ args.directory, args.caption,
+ QStringList(), QFileDialog::ExistingFiles,
+ args.options);
+
+ // Set the FOS_PICKFOLDERS flag
+ DWORD newOptions;
+ hr = pfd->GetOptions(&newOptions);
+ newOptions |= (FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM);
+ if (SUCCEEDED(hr) && SUCCEEDED((hr = pfd->SetOptions(newOptions)))) {
+ QWidget *parentWindow = args.parent;
+ if (parentWindow)
+ parentWindow = parentWindow->window();
+ else
+ parentWindow = QApplication::activeWindow();
+
+ // Show the file dialog.
+ hr = pfd->Show(QApplicationPrivate::getHWNDForWidget(parentWindow));
+ if (SUCCEEDED(hr)) {
+ // Retrieve the result
+ IShellItem *psi = 0;
+ hr = pfd->GetResult(&psi);
+ if (SUCCEEDED(hr)) {
+ // Retrieve the file name from shell item.
+ wchar_t *pszPath;
+ hr = psi->GetDisplayName(SIGDN_FILESYSPATH, &pszPath);
+ if (SUCCEEDED(hr)) {
+ result = QString::fromWCharArray(pszPath);
+ CoTaskMemFree(pszPath);
+ }
+ psi->Release(); // Free the current item.
+ }
+ }
+ }
+ }
+ QApplicationPrivate::leaveModal(&modal_widget);
+
+ qt_win_eatMouseMove();
+
+ if (pfd)
+ pfd->Release();
+ return result;
+}
+
+#endif
+
+QStringList qt_win_get_open_file_names(const QFileDialogArgs &args,
+ QString *initialDirectory,
+ QString *selectedFilter)
+{
+ QFileInfo fi;
+ QDir dir;
+
+ if (initialDirectory && initialDirectory->left(5) == QLatin1String("file:"))
+ initialDirectory->remove(0, 5);
+ fi = QFileInfo(*initialDirectory);
+
+ if (initialDirectory && !fi.isDir()) {
+ *initialDirectory = fi.absolutePath();
+ }
+
+ if (!fi.exists())
+ *initialDirectory = QDir::homePath();
+
+ DWORD selFilIdx = 0;
+
+ QStringList filterLst = qt_win_make_filters_list(args.filter);
+ int idx = 0;
+ if (selectedFilter) {
+ idx = filterLst.indexOf(*selectedFilter);
+ }
+ // Windows Vista (& above) allows users to search from file dialogs. If user selects
+ // multiple files belonging to different folders from these search results, the
+ // GetOpenFileName() will return only one folder name for all the files. To retrieve
+ // the correct path for all selected files, we have to use Common Item Dialog interfaces.
+#ifndef Q_WS_WINCE
+ if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
+ return qt_win_CID_get_open_file_names(args, initialDirectory, filterLst, selectedFilter, idx);
+#endif
+
+ QStringList result;
+ QDialog modal_widget;
+ modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+ modal_widget.setParent(args.parent, Qt::Window);
+ QApplicationPrivate::enterModal(&modal_widget);
+
+ bool hideFiltersDetails = args.options & QFileDialog::HideNameFilterDetails;
+ OPENFILENAME* ofn = qt_win_make_OFN(args.parent, args.selection,
+ args.directory, args.caption,
+ qt_win_filter(args.filter, hideFiltersDetails),
+ QFileDialog::ExistingFiles,
+ args.options);
+ if (idx)
+ ofn->nFilterIndex = idx + 1;
+ if (GetOpenFileName(ofn)) {
+ QString fileOrDir = QString::fromWCharArray(ofn->lpstrFile);
+ selFilIdx = ofn->nFilterIndex;
+ int offset = fileOrDir.length() + 1;
+ if (ofn->lpstrFile[offset] == 0) {
+ // Only one file selected; has full path
+ fi.setFile(fileOrDir);
+ QString res = fi.absoluteFilePath();
+ if (!res.isEmpty())
+ result.append(res);
+ }
+ else {
+ // Several files selected; first string is path
+ dir.setPath(fileOrDir);
+ QString f;
+ while(!(f = QString::fromWCharArray(ofn->lpstrFile + offset)).isEmpty()) {
+ fi.setFile(dir, f);
+ QString res = fi.absoluteFilePath();
+ if (!res.isEmpty())
+ result.append(res);
+ offset += f.length() + 1;
+ }
+ }
+ }
+ qt_win_clean_up_OFN(&ofn);
+
+ QApplicationPrivate::leaveModal(&modal_widget);
+
+ qt_win_eatMouseMove();
+
+ if (!result.isEmpty()) {
+ *initialDirectory = fi.path(); // only save the path if there is a result
+ if (selectedFilter)
+ *selectedFilter = qt_win_selected_filter(args.filter, selFilIdx);
+ }
+ return result;
+}
+
+// MFC Directory Dialog. Contrib: Steve Williams (minor parts from Scott Powers)
+
+static int __stdcall winGetExistDirCallbackProc(HWND hwnd,
+ UINT uMsg,
+ LPARAM lParam,
+ LPARAM lpData)
+{
+ if (uMsg == BFFM_INITIALIZED && lpData != 0) {
+ QString *initDir = (QString *)(lpData);
+ if (!initDir->isEmpty()) {
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initDir->utf16()));
+ }
+ } else if (uMsg == BFFM_SELCHANGED) {
+ qt_win_resolve_libs();
+ if (ptrSHGetPathFromIDList) {
+ wchar_t path[MAX_PATH];
+ ptrSHGetPathFromIDList(qt_LPITEMIDLIST(lParam), path);
+ QString tmpStr = QString::fromWCharArray(path);
+ if (!tmpStr.isEmpty())
+ SendMessage(hwnd, BFFM_ENABLEOK, 1, 1);
+ else
+ SendMessage(hwnd, BFFM_ENABLEOK, 0, 0);
+ SendMessage(hwnd, BFFM_SETSTATUSTEXT, 1, LPARAM(path));
+ }
+ }
+ return 0;
+}
+
+QString qt_win_get_existing_directory(const QFileDialogArgs &args)
+{
+#ifndef Q_WS_WINCE
+ if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
+ return qt_win_CID_get_existing_directory(args);
+#endif
+
+ QString currentDir = QDir::currentPath();
+ QString result;
+ QWidget *parent = args.parent;
+ if (parent)
+ parent = parent->window();
+ else
+ parent = QApplication::activeWindow();
+ if (parent)
+ parent->createWinId();
+
+ QDialog modal_widget;
+ modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+ modal_widget.setParent(parent, Qt::Window);
+ QApplicationPrivate::enterModal(&modal_widget);
+
+ QString initDir = QDir::toNativeSeparators(args.directory);
+ wchar_t path[MAX_PATH];
+ wchar_t initPath[MAX_PATH];
+ initPath[0] = 0;
+ path[0] = 0;
+ tTitle = args.caption;
+
+ qt_BROWSEINFO bi;
+
+ Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
+ bi.hwndOwner = QApplicationPrivate::getHWNDForWidget(parent);
+ bi.pidlRoot = NULL;
+ //### This does not seem to be respected? - the dialog always displays "Browse for folder"
+ bi.lpszTitle = (wchar_t*)tTitle.utf16();
+ bi.pszDisplayName = initPath;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT | BIF_NEWDIALOGSTYLE;
+ bi.lpfn = winGetExistDirCallbackProc;
+ bi.lParam = LPARAM(&initDir);
+
+ qt_win_resolve_libs();
+ if (ptrSHBrowseForFolder) {
+ qt_LPITEMIDLIST pItemIDList = ptrSHBrowseForFolder(&bi);
+ if (pItemIDList) {
+ ptrSHGetPathFromIDList(pItemIDList, path);
+ IMalloc *pMalloc;
+ if (ptrSHGetMalloc(&pMalloc) == NOERROR) {
+ pMalloc->Free(pItemIDList);
+ pMalloc->Release();
+ result = QString::fromWCharArray(path);
+ }
+ }
+ }
+ tTitle = QString();
+
+ QApplicationPrivate::leaveModal(&modal_widget);
+
+ qt_win_eatMouseMove();
+
+ if (!result.isEmpty())
+ result.replace(QLatin1Char('\\'), QLatin1Char('/'));
+ return result;
+}
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qfiledialog_win_p.h b/src/widgets/dialogs/qfiledialog_win_p.h
new file mode 100644
index 0000000000..1ff29d2e26
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog_win_p.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <objbase.h>
+#ifndef QFILEDIAG_WIN_P_H
+#define QFILEDIAG_WIN_P_H
+
+//these are the interface declarations needed for the file dialog on Vista and up
+
+//At some point we can hope that all compilers/sdk will support that interface
+//and we won't have to declare it ourselves
+
+//declarations
+#define FOS_OVERWRITEPROMPT 0x2
+#define FOS_STRICTFILETYPES 0x4
+#define FOS_NOCHANGEDIR 0x8
+#define FOS_PICKFOLDERS 0x20
+#define FOS_FORCEFILESYSTEM 0x40
+#define FOS_ALLNONSTORAGEITEMS 0x80
+#define FOS_NOVALIDATE 0x100
+#define FOS_ALLOWMULTISELECT 0x200
+#define FOS_PATHMUSTEXIST 0x800
+#define FOS_FILEMUSTEXIST 0x1000
+#define FOS_CREATEPROMPT 0x2000
+#define FOS_SHAREAWARE 0x4000
+#define FOS_NOREADONLYRETURN 0x8000
+#define FOS_NOTESTFILECREATE 0x10000
+#define FOS_HIDEMRUPLACES 0x20000
+#define FOS_HIDEPINNEDPLACES 0x40000
+#define FOS_NODEREFERENCELINKS 0x100000
+#define FOS_DONTADDTORECENT 0x2000000
+#define FOS_FORCESHOWHIDDEN 0x10000000
+#define FOS_DEFAULTNOMINIMODE 0x20000000
+#define FOS_FORCEPREVIEWPANEON 0x40000000
+
+typedef int GETPROPERTYSTOREFLAGS;
+#define GPS_DEFAULT 0x00000000
+#define GPS_HANDLERPROPERTIESONLY 0x00000001
+#define GPS_READWRITE 0x00000002
+#define GPS_TEMPORARY 0x00000004
+#define GPS_FASTPROPERTIESONLY 0x00000008
+#define GPS_OPENSLOWITEM 0x00000010
+#define GPS_DELAYCREATION 0x00000020
+#define GPS_BESTEFFORT 0x00000040
+#define GPS_MASK_VALID 0x0000007F
+
+typedef int (QT_WIN_CALLBACK* BFFCALLBACK)(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
+// message from browser
+#define BFFM_INITIALIZED 1
+#define BFFM_SELCHANGED 2
+#define BFFM_ENABLEOK (WM_USER + 101)
+#define BFFM_SETSELECTION (WM_USER + 103)
+#define BFFM_SETSTATUSTEXT (WM_USER + 104)
+
+// Browsing for directory.
+#define BIF_RETURNONLYFSDIRS 0x0001
+#define BIF_DONTGOBELOWDOMAIN 0x0002
+#define BIF_STATUSTEXT 0x0004
+#define BIF_RETURNFSANCESTORS 0x0008
+#define BIF_EDITBOX 0x0010
+#define BIF_VALIDATE 0x0020
+#define BIF_NEWDIALOGSTYLE 0x0040
+#define BIF_BROWSEINCLUDEURLS 0x0080
+#define BIF_UAHINT 0x0100
+#define BIF_NONEWFOLDERBUTTON 0x0200
+#define BIF_NOTRANSLATETARGETS 0x0400
+#define BIF_BROWSEFORCOMPUTER 0x1000
+#define BIF_BROWSEFORPRINTER 0x2000
+#define BIF_BROWSEINCLUDEFILES 0x4000
+#define BIF_SHAREABLE 0x8000
+
+//the enums
+typedef enum {
+ SIATTRIBFLAGS_AND = 0x1,
+ SIATTRIBFLAGS_OR = 0x2,
+ SIATTRIBFLAGS_APPCOMPAT = 0x3,
+ SIATTRIBFLAGS_MASK = 0x3
+} SIATTRIBFLAGS;
+typedef enum {
+ SIGDN_NORMALDISPLAY = 0x00000000,
+ SIGDN_PARENTRELATIVEPARSING = 0x80018001,
+ SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
+ SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
+ SIGDN_PARENTRELATIVEEDITING = 0x80031001,
+ SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
+ SIGDN_FILESYSPATH = 0x80058000,
+ SIGDN_URL = 0x80068000
+} SIGDN;
+typedef enum {
+ FDAP_BOTTOM = 0x00000000,
+ FDAP_TOP = 0x00000001
+} FDAP;
+typedef enum {
+ FDESVR_DEFAULT = 0x00000000,
+ FDESVR_ACCEPT = 0x00000001,
+ FDESVR_REFUSE = 0x00000002
+} FDE_SHAREVIOLATION_RESPONSE;
+typedef FDE_SHAREVIOLATION_RESPONSE FDE_OVERWRITE_RESPONSE;
+
+//the structs
+typedef struct {
+ LPCWSTR pszName;
+ LPCWSTR pszSpec;
+} qt_COMDLG_FILTERSPEC;
+typedef struct {
+ GUID fmtid;
+ DWORD pid;
+} qt_PROPERTYKEY;
+
+typedef struct {
+ USHORT cb;
+ BYTE abID[1];
+} qt_SHITEMID, *qt_LPSHITEMID;
+typedef struct {
+ qt_SHITEMID mkid;
+} qt_ITEMIDLIST, *qt_LPITEMIDLIST;
+typedef const qt_ITEMIDLIST *qt_LPCITEMIDLIST;
+typedef struct {
+ HWND hwndOwner;
+ qt_LPCITEMIDLIST pidlRoot;
+ LPWSTR pszDisplayName;
+ LPCWSTR lpszTitle;
+ UINT ulFlags;
+ BFFCALLBACK lpfn;
+ LPARAM lParam;
+ int iImage;
+} qt_BROWSEINFO;
+
+DECLARE_INTERFACE(IFileDialogEvents);
+DECLARE_INTERFACE_(IShellItem, IUnknown)
+{
+ STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppv) PURE;
+ STDMETHOD(GetParent)(THIS_ IShellItem **ppsi) PURE;
+ STDMETHOD(GetDisplayName)(THIS_ SIGDN sigdnName, LPWSTR *ppszName) PURE;
+ STDMETHOD(GetAttributes)(THIS_ ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE;
+ STDMETHOD(Compare)(THIS_ IShellItem *psi, DWORD hint, int *piOrder) PURE;
+};
+DECLARE_INTERFACE_(IShellItemFilter, IUnknown)
+{
+ STDMETHOD(IncludeItem)(THIS_ IShellItem *psi) PURE;
+ STDMETHOD(GetEnumFlagsForItem)(THIS_ IShellItem *psi, DWORD *pgrfFlags) PURE;
+};
+DECLARE_INTERFACE_(IEnumShellItems, IUnknown)
+{
+ STDMETHOD(Next)(THIS_ ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) PURE;
+ STDMETHOD(Skip)(THIS_ ULONG celt) PURE;
+ STDMETHOD(Reset)(THIS_) PURE;
+ STDMETHOD(Clone)(THIS_ IEnumShellItems **ppenum) PURE;
+};
+DECLARE_INTERFACE_(IShellItemArray, IUnknown)
+{
+ STDMETHOD(BindToHandler)(THIS_ IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) PURE;
+ STDMETHOD(GetPropertyStore)(THIS_ GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) PURE;
+ STDMETHOD(GetPropertyDescriptionList)(THIS_ const qt_PROPERTYKEY *keyType, REFIID riid, void **ppv) PURE;
+ STDMETHOD(GetAttributes)(THIS_ SIATTRIBFLAGS dwAttribFlags, ULONG sfgaoMask, ULONG *psfgaoAttribs) PURE;
+ STDMETHOD(GetCount)(THIS_ DWORD *pdwNumItems) PURE;
+ STDMETHOD(GetItemAt)(THIS_ DWORD dwIndex, IShellItem **ppsi) PURE;
+ STDMETHOD(EnumItems)(THIS_ IEnumShellItems **ppenumShellItems) PURE;
+};
+DECLARE_INTERFACE_(IModalWindow, IUnknown)
+{
+ STDMETHOD(Show)(THIS_ HWND hwndParent) PURE;
+};
+DECLARE_INTERFACE_(IFileDialog, IModalWindow)
+{
+ STDMETHOD(SetFileTypes)(THIS_ UINT cFileTypes, const qt_COMDLG_FILTERSPEC *rgFilterSpec) PURE;
+ STDMETHOD(SetFileTypeIndex)(THIS_ UINT iFileType) PURE;
+ STDMETHOD(GetFileTypeIndex)(THIS_ UINT *piFileType) PURE;
+ STDMETHOD(Advise)(THIS_ IFileDialogEvents *pfde, DWORD *pdwCookie) PURE;
+ STDMETHOD(Unadvise)(THIS_ DWORD dwCookie) PURE;
+ STDMETHOD(SetOptions)(THIS_ DWORD fos) PURE;
+ STDMETHOD(GetOptions)(THIS_ DWORD *pfos) PURE;
+ STDMETHOD(SetDefaultFolder)(THIS_ IShellItem *psi) PURE;
+ STDMETHOD(SetFolder)(THIS_ IShellItem *psi) PURE;
+ STDMETHOD(GetFolder)(THIS_ IShellItem **ppsi) PURE;
+ STDMETHOD(GetCurrentSelection)(THIS_ IShellItem **ppsi) PURE;
+ STDMETHOD(SetFileName)(THIS_ LPCWSTR pszName) PURE;
+ STDMETHOD(GetFileName)(THIS_ LPWSTR *pszName) PURE;
+ STDMETHOD(SetTitle)(THIS_ LPCWSTR pszTitle) PURE;
+ STDMETHOD(SetOkButtonLabel)(THIS_ LPCWSTR pszText) PURE;
+ STDMETHOD(SetFileNameLabel)(THIS_ LPCWSTR pszLabel) PURE;
+ STDMETHOD(GetResult)(THIS_ IShellItem **ppsi) PURE;
+ STDMETHOD(AddPlace)(THIS_ IShellItem *psi, FDAP fdap) PURE;
+ STDMETHOD(SetDefaultExtension)(THIS_ LPCWSTR pszDefaultExtension) PURE;
+ STDMETHOD(Close)(THIS_ HRESULT hr) PURE;
+ STDMETHOD(SetClientGuid)(THIS_ REFGUID guid) PURE;
+ STDMETHOD(ClearClientData)(THIS_) PURE;
+ STDMETHOD(SetFilter)(THIS_ IShellItemFilter *pFilter) PURE;
+};
+DECLARE_INTERFACE_(IFileDialogEvents, IUnknown)
+{
+ STDMETHOD(OnFileOk)(THIS_ IFileDialog *pfd) PURE;
+ STDMETHOD(OnFolderChanging)(THIS_ IFileDialog *pfd, IShellItem *psiFolder) PURE;
+ STDMETHOD(OnFolderChange)(THIS_ IFileDialog *pfd) PURE;
+ STDMETHOD(OnSelectionChange)(THIS_ IFileDialog *pfd) PURE;
+ STDMETHOD(OnShareViolation)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse) PURE;
+ STDMETHOD(OnTypeChange)(THIS_ IFileDialog *pfd) PURE;
+ STDMETHOD(OnOverwrite)(THIS_ IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse) PURE;
+};
+DECLARE_INTERFACE_(IFileOpenDialog, IFileDialog)
+{
+ STDMETHOD(GetResults)(THIS_ IShellItemArray **ppenum) PURE;
+ STDMETHOD(GetSelectedItems)(THIS_ IShellItemArray **ppsai) PURE;
+};
+#endif \ No newline at end of file
diff --git a/src/widgets/dialogs/qfileinfogatherer.cpp b/src/widgets/dialogs/qfileinfogatherer.cpp
new file mode 100644
index 0000000000..315b93131f
--- /dev/null
+++ b/src/widgets/dialogs/qfileinfogatherer.cpp
@@ -0,0 +1,355 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfileinfogatherer_p.h"
+#include <qdebug.h>
+#include <qfsfileengine.h>
+#include <qdiriterator.h>
+#ifndef Q_OS_WIN
+# include <unistd.h>
+# include <sys/types.h>
+#endif
+#if defined(Q_OS_VXWORKS)
+# include "qplatformdefs.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_FILESYSTEMMODEL
+
+#ifdef QT_BUILD_INTERNAL
+static bool fetchedRoot = false;
+Q_AUTOTEST_EXPORT void qt_test_resetFetchedRoot()
+{
+ fetchedRoot = false;
+}
+
+Q_AUTOTEST_EXPORT bool qt_test_isFetchedRoot()
+{
+ return fetchedRoot;
+}
+#endif
+
+/*!
+ Creates thread
+*/
+QFileInfoGatherer::QFileInfoGatherer(QObject *parent)
+ : QThread(parent), abort(false),
+#ifndef QT_NO_FILESYSTEMWATCHER
+ watcher(0),
+#endif
+ m_resolveSymlinks(false), m_iconProvider(&defaultProvider)
+{
+#ifdef Q_OS_WIN
+ m_resolveSymlinks = true;
+#elif !defined(Q_OS_INTEGRITY)
+ userId = getuid();
+ groupId = getgid();
+#endif
+#ifndef QT_NO_FILESYSTEMWATCHER
+ watcher = new QFileSystemWatcher(this);
+ connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(list(QString)));
+ connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
+#endif
+ start(LowPriority);
+}
+
+/*!
+ Destroys thread
+*/
+QFileInfoGatherer::~QFileInfoGatherer()
+{
+ QMutexLocker locker(&mutex);
+ abort = true;
+ condition.wakeOne();
+ locker.unlock();
+ wait();
+}
+
+void QFileInfoGatherer::setResolveSymlinks(bool enable)
+{
+ Q_UNUSED(enable);
+#ifdef Q_OS_WIN
+ QMutexLocker locker(&mutex);
+ m_resolveSymlinks = enable;
+#endif
+}
+
+bool QFileInfoGatherer::resolveSymlinks() const
+{
+ return m_resolveSymlinks;
+}
+
+void QFileInfoGatherer::setIconProvider(QFileIconProvider *provider)
+{
+ QMutexLocker locker(&mutex);
+ m_iconProvider = provider;
+}
+
+QFileIconProvider *QFileInfoGatherer::iconProvider() const
+{
+ return m_iconProvider;
+}
+
+/*!
+ Fetch extended information for all \a files in \a path
+
+ \sa updateFile(), update(), resolvedName()
+*/
+void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStringList &files)
+{
+ QMutexLocker locker(&mutex);
+ // See if we already have this dir/file in our que
+ int loc = this->path.lastIndexOf(path);
+ while (loc > 0) {
+ if (this->files.at(loc) == files) {
+ return;
+ }
+ loc = this->path.lastIndexOf(path, loc - 1);
+ }
+ this->path.push(path);
+ this->files.push(files);
+ condition.wakeAll();
+}
+
+/*!
+ Fetch extended information for all \a filePath
+
+ \sa fetchExtendedInformation()
+*/
+void QFileInfoGatherer::updateFile(const QString &filePath)
+{
+ QString dir = filePath.mid(0, filePath.lastIndexOf(QDir::separator()));
+ QString fileName = filePath.mid(dir.length() + 1);
+ fetchExtendedInformation(dir, QStringList(fileName));
+}
+
+/*
+ List all files in \a directoryPath
+
+ \sa listed()
+*/
+void QFileInfoGatherer::clear()
+{
+#ifndef QT_NO_FILESYSTEMWATCHER
+ QMutexLocker locker(&mutex);
+ watcher->removePaths(watcher->files());
+ watcher->removePaths(watcher->directories());
+#endif
+}
+
+/*
+ Remove a \a path from the watcher
+
+ \sa listed()
+*/
+void QFileInfoGatherer::removePath(const QString &path)
+{
+#ifndef QT_NO_FILESYSTEMWATCHER
+ QMutexLocker locker(&mutex);
+ watcher->removePath(path);
+#endif
+}
+
+/*
+ List all files in \a directoryPath
+
+ \sa listed()
+*/
+void QFileInfoGatherer::list(const QString &directoryPath)
+{
+ fetchExtendedInformation(directoryPath, QStringList());
+}
+
+/*
+ Until aborted wait to fetch a directory or files
+*/
+void QFileInfoGatherer::run()
+{
+ forever {
+ bool updateFiles = false;
+ QMutexLocker locker(&mutex);
+ if (abort) {
+ return;
+ }
+ if (this->path.isEmpty())
+ condition.wait(&mutex);
+ QString path;
+ QStringList list;
+ if (!this->path.isEmpty()) {
+ path = this->path.first();
+ list = this->files.first();
+ this->path.pop_front();
+ this->files.pop_front();
+ updateFiles = true;
+ }
+ locker.unlock();
+ if (updateFiles)
+ getFileInfos(path, list);
+ }
+}
+
+QExtendedInformation QFileInfoGatherer::getInfo(const QFileInfo &fileInfo) const
+{
+ QExtendedInformation info(fileInfo);
+ info.icon = m_iconProvider->icon(fileInfo);
+ info.displayType = m_iconProvider->type(fileInfo);
+#ifndef QT_NO_FILESYSTEMWATCHER
+ // ### Not ready to listen all modifications
+ #if 0
+ // Enable the next two commented out lines to get updates when the file sizes change...
+ if (!fileInfo.exists() && !fileInfo.isSymLink()) {
+ info.size = -1;
+ //watcher->removePath(fileInfo.absoluteFilePath());
+ } else {
+ if (!fileInfo.absoluteFilePath().isEmpty() && fileInfo.exists() && fileInfo.isReadable()
+ && !watcher->files().contains(fileInfo.absoluteFilePath())) {
+ //watcher->addPath(fileInfo.absoluteFilePath());
+ }
+ }
+ #endif
+#endif
+
+ if (fileInfo.isSymLink() && m_resolveSymlinks) {
+ QFileInfo resolvedInfo(fileInfo.symLinkTarget());
+ resolvedInfo = resolvedInfo.canonicalFilePath();
+ if (resolvedInfo.exists()) {
+ emit nameResolved(fileInfo.filePath(), resolvedInfo.fileName());
+ }
+ }
+ return info;
+}
+
+QString QFileInfoGatherer::translateDriveName(const QFileInfo &drive) const
+{
+ QString driveName = drive.absoluteFilePath();
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ if (driveName.startsWith(QLatin1Char('/'))) // UNC host
+ return drive.fileName();
+#endif
+#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
+ if (driveName.endsWith(QLatin1Char('/')))
+ driveName.chop(1);
+#endif
+ return driveName;
+}
+
+/*
+ Get specific file info's, batch the files so update when we have 100
+ items and every 200ms after that
+ */
+void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &files)
+{
+#ifndef QT_NO_FILESYSTEMWATCHER
+ if (files.isEmpty()
+ && !watcher->directories().contains(path)
+ && !path.isEmpty()
+ && !path.startsWith(QLatin1String("//")) /*don't watch UNC path*/) {
+ watcher->addPath(path);
+ }
+#endif
+
+ // List drives
+ if (path.isEmpty()) {
+#ifdef QT_BUILD_INTERNAL
+ fetchedRoot = true;
+#endif
+ QFileInfoList infoList;
+ if (files.isEmpty()) {
+ infoList = QDir::drives();
+ } else {
+ for (int i = 0; i < files.count(); ++i)
+ infoList << QFileInfo(files.at(i));
+ }
+ for (int i = infoList.count() - 1; i >= 0; --i) {
+ QString driveName = translateDriveName(infoList.at(i));
+ QList<QPair<QString,QFileInfo> > updatedFiles;
+ updatedFiles.append(QPair<QString,QFileInfo>(driveName, infoList.at(i)));
+ emit updates(path, updatedFiles);
+ }
+ return;
+ }
+
+ QElapsedTimer base;
+ base.start();
+ QFileInfo fileInfo;
+ bool firstTime = true;
+ QList<QPair<QString, QFileInfo> > updatedFiles;
+ QStringList filesToCheck = files;
+
+ QString itPath = QDir::fromNativeSeparators(files.isEmpty() ? path : QLatin1String(""));
+ QDirIterator dirIt(itPath, QDir::AllEntries | QDir::System | QDir::Hidden);
+ QStringList allFiles;
+ while(!abort && dirIt.hasNext()) {
+ dirIt.next();
+ fileInfo = dirIt.fileInfo();
+ allFiles.append(fileInfo.fileName());
+ fetch(fileInfo, base, firstTime, updatedFiles, path);
+ }
+ if (!allFiles.isEmpty())
+ emit newListOfFiles(path, allFiles);
+
+ QStringList::const_iterator filesIt = filesToCheck.constBegin();
+ while(!abort && filesIt != filesToCheck.constEnd()) {
+ fileInfo.setFile(path + QDir::separator() + *filesIt);
+ ++filesIt;
+ fetch(fileInfo, base, firstTime, updatedFiles, path);
+ }
+ if (!updatedFiles.isEmpty())
+ emit updates(path, updatedFiles);
+ emit directoryLoaded(path);
+}
+
+void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QElapsedTimer &base, bool &firstTime, QList<QPair<QString, QFileInfo> > &updatedFiles, const QString &path) {
+ updatedFiles.append(QPair<QString, QFileInfo>(fileInfo.fileName(), fileInfo));
+ QElapsedTimer current;
+ current.start();
+ if ((firstTime && updatedFiles.count() > 100) || base.msecsTo(current) > 1000) {
+ emit updates(path, updatedFiles);
+ updatedFiles.clear();
+ base = current;
+ firstTime = false;
+ }
+}
+
+#endif // QT_NO_FILESYSTEMMODEL
+
+QT_END_NAMESPACE
diff --git a/src/widgets/dialogs/qfileinfogatherer_p.h b/src/widgets/dialogs/qfileinfogatherer_p.h
new file mode 100644
index 0000000000..98217c1dc8
--- /dev/null
+++ b/src/widgets/dialogs/qfileinfogatherer_p.h
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILEINFOGATHERER_H
+#define QFILEINFOGATHERER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qthread.h>
+#include <qmutex.h>
+#include <qwaitcondition.h>
+#include <qfilesystemwatcher.h>
+#include <qfileiconprovider.h>
+#include <qfsfileengine.h>
+#include <qpair.h>
+#include <qstack.h>
+#include <qdatetime.h>
+#include <qdir.h>
+#include <qelapsedtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QExtendedInformation {
+public:
+ enum Type { Dir, File, System };
+
+ QExtendedInformation() {}
+ QExtendedInformation(const QFileInfo &info) : mFileInfo(info) {}
+
+ inline bool isDir() { return type() == Dir; }
+ inline bool isFile() { return type() == File; }
+ inline bool isSystem() { return type() == System; }
+
+ bool operator ==(const QExtendedInformation &fileInfo) const {
+ return mFileInfo == fileInfo.mFileInfo
+ && displayType == fileInfo.displayType
+ && permissions() == fileInfo.permissions();
+ }
+
+#ifndef QT_NO_FSFILEENGINE
+ bool isCaseSensitive() const {
+ QFSFileEngine fe(mFileInfo.absoluteFilePath());
+ return fe.caseSensitive();
+ }
+#endif
+
+ QFile::Permissions permissions() const {
+ return mFileInfo.permissions();
+ }
+
+ Type type() const {
+ if (mFileInfo.isDir()) {
+ return QExtendedInformation::Dir;
+ }
+ if (mFileInfo.isFile()) {
+ return QExtendedInformation::File;
+ }
+ if (!mFileInfo.exists() && mFileInfo.isSymLink()) {
+ return QExtendedInformation::System;
+ }
+ return QExtendedInformation::System;
+ }
+
+ bool isSymLink() const {
+ return mFileInfo.isSymLink();
+ }
+
+ bool isHidden() const {
+ return mFileInfo.isHidden();
+ }
+
+ QFileInfo fileInfo() const {
+ return mFileInfo;
+ }
+
+ QDateTime lastModified() const {
+ return mFileInfo.lastModified();
+ }
+
+ qint64 size() const {
+ qint64 size = -1;
+ if (type() == QExtendedInformation::Dir)
+ size = 0;
+ if (type() == QExtendedInformation::File)
+ size = mFileInfo.size();
+ if (!mFileInfo.exists() && !mFileInfo.isSymLink())
+ size = -1;
+ return size;
+ }
+
+ QString displayType;
+ QIcon icon;
+
+private :
+ QFileInfo mFileInfo;
+};
+
+class QFileIconProvider;
+
+#ifndef QT_NO_FILESYSTEMMODEL
+
+class Q_AUTOTEST_EXPORT QFileInfoGatherer : public QThread
+{
+Q_OBJECT
+
+Q_SIGNALS:
+ void updates(const QString &directory, const QList<QPair<QString, QFileInfo> > &updates);
+ void newListOfFiles(const QString &directory, const QStringList &listOfFiles) const;
+ void nameResolved(const QString &fileName, const QString &resolvedName) const;
+ void directoryLoaded(const QString &path);
+
+public:
+ QFileInfoGatherer(QObject *parent = 0);
+ ~QFileInfoGatherer();
+
+ void clear();
+ void removePath(const QString &path);
+ QExtendedInformation getInfo(const QFileInfo &info) const;
+
+public Q_SLOTS:
+ void list(const QString &directoryPath);
+ void fetchExtendedInformation(const QString &path, const QStringList &files);
+ void updateFile(const QString &path);
+ void setResolveSymlinks(bool enable);
+ bool resolveSymlinks() const;
+ void setIconProvider(QFileIconProvider *provider);
+ QFileIconProvider *iconProvider() const;
+
+protected:
+ void run();
+ void getFileInfos(const QString &path, const QStringList &files);
+
+private:
+ void fetch(const QFileInfo &info, QElapsedTimer &base, bool &firstTime, QList<QPair<QString, QFileInfo> > &updatedFiles, const QString &path);
+ QString translateDriveName(const QFileInfo &drive) const;
+
+ QMutex mutex;
+ QWaitCondition condition;
+ volatile bool abort;
+
+ QStack<QString> path;
+ QStack<QStringList> files;
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+ QFileSystemWatcher *watcher;
+#endif
+ bool m_resolveSymlinks;
+ QFileIconProvider *m_iconProvider;
+ QFileIconProvider defaultProvider;
+#ifndef Q_OS_WIN
+ uint userId;
+ uint groupId;
+#endif
+};
+#endif // QT_NO_FILESYSTEMMODEL
+
+
+QT_END_NAMESPACE
+#endif // QFILEINFOGATHERER_H
+
diff --git a/src/widgets/dialogs/qfilesystemmodel.cpp b/src/widgets/dialogs/qfilesystemmodel.cpp
new file mode 100644
index 0000000000..10d627c594
--- /dev/null
+++ b/src/widgets/dialogs/qfilesystemmodel.cpp
@@ -0,0 +1,2029 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemmodel_p.h"
+#include "qfilesystemmodel.h"
+#include <qlocale.h>
+#include <qmime.h>
+#include <qurl.h>
+#include <qdebug.h>
+#include <qmessagebox.h>
+#include <qapplication.h>
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#endif
+#ifdef Q_OS_WIN32
+#include <QtCore/QVarLengthArray>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_FILESYSTEMMODEL
+
+/*!
+ \enum QFileSystemModel::Roles
+ \value FileIconRole
+ \value FilePathRole
+ \value FileNameRole
+ \value FilePermissions
+*/
+
+/*!
+ \class QFileSystemModel
+ \since 4.4
+
+ \brief The QFileSystemModel class provides a data model for the local filesystem.
+
+ \ingroup model-view
+
+ This class provides access to the local filesystem, providing functions
+ for renaming and removing files and directories, and for creating new
+ directories. In the simplest case, it can be used with a suitable display
+ widget as part of a browser or filter.
+
+ QFileSystemModel can be accessed using the standard interface provided by
+ QAbstractItemModel, but it also provides some convenience functions that are
+ specific to a directory model.
+ The fileInfo(), isDir(), name(), and path() functions provide information
+ about the underlying files and directories related to items in the model.
+ Directories can be created and removed using mkdir(), rmdir().
+
+ \note QFileSystemModel requires an instance of a GUI application.
+
+ \section1 Example Usage
+
+ A directory model that displays the contents of a default directory
+ is usually constructed with a parent object:
+
+ \snippet doc/src/snippets/shareddirmodel/main.cpp 2
+
+ A tree view can be used to display the contents of the model
+
+ \snippet doc/src/snippets/shareddirmodel/main.cpp 4
+
+ and the contents of a particular directory can be displayed by
+ setting the tree view's root index:
+
+ \snippet doc/src/snippets/shareddirmodel/main.cpp 7
+
+ The view's root index can be used to control how much of a
+ hierarchical model is displayed. QDirModel provides a convenience
+ function that returns a suitable model index for a path to a
+ directory within the model.
+
+ \section1 Caching and Performance
+
+ QFileSystemModel will not fetch any files or directories until setRootPath()
+ is called. This will prevent any unnecessary querying on the file system
+ until that point such as listing the drives on Windows.
+
+ Unlike QDirModel, QFileSystemModel uses a separate thread to populate
+ itself so it will not cause the main thread to hang as the file system
+ is being queried. Calls to rowCount() will return 0 until the model
+ populates a directory.
+
+ QFileSystemModel keeps a cache with file information. The cache is
+ automatically kept up to date using the QFileSystemWatcher.
+
+ \sa {Model Classes}
+*/
+
+/*!
+ \fn bool QFileSystemModel::rmdir(const QModelIndex &index) const
+
+ Removes the directory corresponding to the model item \a index in the
+ file system model and \bold{deletes the corresponding directory from the
+ file system}, returning true if successful. If the directory cannot be
+ removed, false is returned.
+
+ \warning This function deletes directories from the file system; it does
+ \bold{not} move them to a location where they can be recovered.
+
+ \sa remove()
+*/
+
+/*!
+ \fn QIcon QFileSystemModel::fileName(const QModelIndex &index) const
+
+ Returns the file name for the item stored in the model under the given
+ \a index.
+*/
+
+/*!
+ \fn QIcon QFileSystemModel::fileIcon(const QModelIndex &index) const
+
+ Returns the icon for the item stored in the model under the given
+ \a index.
+*/
+
+/*!
+ \fn QFileInfo QFileSystemModel::fileInfo(const QModelIndex &index) const
+
+ Returns the QFileInfo for the item stored in the model under the given
+ \a index.
+*/
+
+/*!
+ \fn void QFileSystemModel::rootPathChanged(const QString &newPath);
+
+ This signal is emitted whenever the root path has been changed to a \a newPath.
+*/
+
+/*!
+ \fn void QFileSystemModel::fileRenamed(const QString &path, const QString &oldName, const QString &newName)
+
+ This signal is emitted whenever a file with the \a oldName is successfully
+ renamed to \a newName. The file is located in in the directory \a path.
+*/
+
+/*!
+ \since 4.7
+ \fn void QFileSystemModel::directoryLoaded(const QString &path)
+
+ This signal is emitted when the gatherer thread has finished to load the \a path.
+
+*/
+
+/*!
+ \fn bool QFileSystemModel::remove(const QModelIndex &index) const
+
+ Removes the model item \a index from the file system model and \bold{deletes the
+ corresponding file from the file system}, returning true if successful. If the
+ item cannot be removed, false is returned.
+
+ \warning This function deletes files from the file system; it does \bold{not}
+ move them to a location where they can be recovered.
+
+ \sa rmdir()
+*/
+
+bool QFileSystemModel::remove(const QModelIndex &aindex) const
+{
+ //### TODO optim
+ QString path = filePath(aindex);
+ QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
+ d->fileInfoGatherer.removePath(path);
+ QDirIterator it(path,
+ QDir::AllDirs | QDir:: Files | QDir::NoDotAndDotDot,
+ QDirIterator::Subdirectories);
+ QStringList children;
+ while (it.hasNext())
+ children.prepend(it.next());
+ children.append(path);
+
+ bool error = false;
+ for (int i = 0; i < children.count(); ++i) {
+ QFileInfo info(children.at(i));
+ QModelIndex modelIndex = index(children.at(i));
+ if (info.isDir()) {
+ QDir dir;
+ if (children.at(i) != path)
+ error |= remove(modelIndex);
+ error |= rmdir(modelIndex);
+ } else {
+ error |= QFile::remove(filePath(modelIndex));
+ }
+ }
+ return error;
+}
+
+/*!
+ Constructs a file system model with the given \a parent.
+*/
+QFileSystemModel::QFileSystemModel(QObject *parent)
+ : QAbstractItemModel(*new QFileSystemModelPrivate, parent)
+{
+ Q_D(QFileSystemModel);
+ d->init();
+}
+
+/*!
+ \internal
+*/
+QFileSystemModel::QFileSystemModel(QFileSystemModelPrivate &dd, QObject *parent)
+ : QAbstractItemModel(dd, parent)
+{
+ Q_D(QFileSystemModel);
+ d->init();
+}
+
+/*!
+ Destroys this file system model.
+*/
+QFileSystemModel::~QFileSystemModel()
+{
+}
+
+/*!
+ \reimp
+*/
+QModelIndex QFileSystemModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_D(const QFileSystemModel);
+ if (row < 0 || column < 0 || row >= rowCount(parent) || column >= columnCount(parent))
+ return QModelIndex();
+
+ // get the parent node
+ QFileSystemModelPrivate::QFileSystemNode *parentNode = (d->indexValid(parent) ? d->node(parent) :
+ const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&d->root));
+ Q_ASSERT(parentNode);
+
+ // now get the internal pointer for the index
+ QString childName = parentNode->visibleChildren[d->translateVisibleLocation(parentNode, row)];
+ const QFileSystemModelPrivate::QFileSystemNode *indexNode = parentNode->children.value(childName);
+ Q_ASSERT(indexNode);
+
+ return createIndex(row, column, const_cast<QFileSystemModelPrivate::QFileSystemNode*>(indexNode));
+}
+
+/*!
+ \overload
+
+ Returns the model item index for the given \a path and \a column.
+*/
+QModelIndex QFileSystemModel::index(const QString &path, int column) const
+{
+ Q_D(const QFileSystemModel);
+ QFileSystemModelPrivate::QFileSystemNode *node = d->node(path, false);
+ QModelIndex idx = d->index(node);
+ if (idx.column() != column)
+ idx = idx.sibling(idx.row(), column);
+ return idx;
+}
+
+/*!
+ \internal
+
+ Return the QFileSystemNode that goes to index.
+ */
+QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return const_cast<QFileSystemNode*>(&root);
+ QFileSystemModelPrivate::QFileSystemNode *indexNode = static_cast<QFileSystemModelPrivate::QFileSystemNode*>(index.internalPointer());
+ Q_ASSERT(indexNode);
+ return indexNode;
+}
+
+#ifdef Q_OS_WIN32
+static QString qt_GetLongPathName(const QString &strShortPath)
+{
+ if (strShortPath.isEmpty()
+ || strShortPath == QLatin1String(".") || strShortPath == QLatin1String(".."))
+ return strShortPath;
+ if (strShortPath.length() == 2 && strShortPath.endsWith(QLatin1Char(':')))
+ return strShortPath.toUpper();
+ const QString absPath = QDir(strShortPath).absolutePath();
+ if (absPath.startsWith(QLatin1String("//"))
+ || absPath.startsWith(QLatin1String("\\\\"))) // unc
+ return QDir::fromNativeSeparators(absPath);
+ if (absPath.startsWith(QLatin1Char('/')))
+ return QString();
+ const QString inputString = QLatin1String("\\\\?\\") + QDir::toNativeSeparators(absPath);
+ QVarLengthArray<TCHAR, MAX_PATH> buffer(MAX_PATH);
+ DWORD result = ::GetLongPathName((wchar_t*)inputString.utf16(),
+ buffer.data(),
+ buffer.size());
+ if (result > DWORD(buffer.size())) {
+ buffer.resize(result);
+ result = ::GetLongPathName((wchar_t*)inputString.utf16(),
+ buffer.data(),
+ buffer.size());
+ }
+ if (result > 4) {
+ QString longPath = QString::fromWCharArray(buffer.data() + 4); // ignoring prefix
+ longPath[0] = longPath.at(0).toUpper(); // capital drive letters
+ return QDir::fromNativeSeparators(longPath);
+ } else {
+ return QDir::fromNativeSeparators(strShortPath);
+ }
+}
+#endif
+
+/*!
+ \internal
+
+ Given a path return the matching QFileSystemNode or &root if invalid
+*/
+QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QString &path, bool fetch) const
+{
+ Q_Q(const QFileSystemModel);
+ Q_UNUSED(q);
+ if (path.isEmpty() || path == myComputer() || path.startsWith(QLatin1Char(':')))
+ return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
+
+ // Construct the nodes up to the new root path if they need to be built
+ QString absolutePath;
+#ifdef Q_OS_WIN32
+ QString longPath = qt_GetLongPathName(path);
+#else
+ QString longPath = path;
+#endif
+ if (longPath == rootDir.path())
+ absolutePath = rootDir.absolutePath();
+ else
+ absolutePath = QDir(longPath).absolutePath();
+
+ // ### TODO can we use bool QAbstractFileEngine::caseSensitive() const?
+ QStringList pathElements = absolutePath.split(QLatin1Char('/'), QString::SkipEmptyParts);
+ if ((pathElements.isEmpty())
+#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN)
+ && QDir::fromNativeSeparators(longPath) != QLatin1String("/")
+#endif
+ )
+ return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
+ QModelIndex index = QModelIndex(); // start with "My Computer"
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ if (absolutePath.startsWith(QLatin1String("//"))) { // UNC path
+ QString host = QLatin1String("\\\\") + pathElements.first();
+ if (absolutePath == QDir::fromNativeSeparators(host))
+ absolutePath.append(QLatin1Char('/'));
+ if (longPath.endsWith(QLatin1Char('/')) && !absolutePath.endsWith(QLatin1Char('/')))
+ absolutePath.append(QLatin1Char('/'));
+ int r = 0;
+ QFileSystemModelPrivate::QFileSystemNode *rootNode = const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
+ if (!root.children.contains(host.toLower())) {
+ if (pathElements.count() == 1 && !absolutePath.endsWith(QLatin1Char('/')))
+ return rootNode;
+ QFileInfo info(host);
+ if (!info.exists())
+ return rootNode;
+ QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
+ p->addNode(rootNode, host,info);
+ p->addVisibleFiles(rootNode, QStringList(host));
+ }
+ r = rootNode->visibleLocation(host);
+ r = translateVisibleLocation(rootNode, r);
+ index = q->index(r, 0, QModelIndex());
+ pathElements.pop_front();
+ } else
+#endif
+
+#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN)
+ {
+ if (!pathElements.at(0).contains(QLatin1String(":"))) {
+ // The reason we express it like this instead of with anonymous, temporary
+ // variables, is to workaround a compiler crash with Q_CC_NOKIAX86.
+ QString rootPath = QDir(longPath).rootPath();
+ pathElements.prepend(rootPath);
+ }
+ if (pathElements.at(0).endsWith(QLatin1Char('/')))
+ pathElements[0].chop(1);
+ }
+#else
+ // add the "/" item, since it is a valid path element on Unix
+ if (absolutePath[0] == QLatin1Char('/'))
+ pathElements.prepend(QLatin1String("/"));
+#endif
+
+ QFileSystemModelPrivate::QFileSystemNode *parent = node(index);
+
+ for (int i = 0; i < pathElements.count(); ++i) {
+ QString element = pathElements.at(i);
+#ifdef Q_OS_WIN
+ // On Windows, "filename......." and "filename" are equivalent Task #133928
+ while (element.endsWith(QLatin1Char('.')))
+ element.chop(1);
+#endif
+ bool alreadyExisted = parent->children.contains(element);
+
+ // we couldn't find the path element, we create a new node since we
+ // _know_ that the path is valid
+ if (alreadyExisted) {
+ if ((parent->children.count() == 0)
+ || (parent->caseSensitive()
+ && parent->children.value(element)->fileName != element)
+ || (!parent->caseSensitive()
+ && parent->children.value(element)->fileName.toLower() != element.toLower()))
+ alreadyExisted = false;
+ }
+
+ QFileSystemModelPrivate::QFileSystemNode *node;
+ if (!alreadyExisted) {
+ // Someone might call ::index("file://cookie/monster/doesn't/like/veggies"),
+ // a path that doesn't exists, I.E. don't blindly create directories.
+ QFileInfo info(absolutePath);
+ if (!info.exists())
+ return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
+ QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
+ node = p->addNode(parent, element,info);
+#ifndef QT_NO_FILESYSTEMWATCHER
+ node->populate(fileInfoGatherer.getInfo(info));
+#endif
+ } else {
+ node = parent->children.value(element);
+ }
+
+ Q_ASSERT(node);
+ if (!node->isVisible) {
+ // It has been filtered out
+ if (alreadyExisted && node->hasInformation() && !fetch)
+ return const_cast<QFileSystemModelPrivate::QFileSystemNode*>(&root);
+
+ QFileSystemModelPrivate *p = const_cast<QFileSystemModelPrivate*>(this);
+ p->addVisibleFiles(parent, QStringList(element));
+ if (!p->bypassFilters.contains(node))
+ p->bypassFilters[node] = 1;
+ QString dir = q->filePath(this->index(parent));
+ if (!node->hasInformation() && fetch) {
+ Fetching f;
+ f.dir = dir;
+ f.file = element;
+ f.node = node;
+ p->toFetch.append(f);
+ p->fetchingTimer.start(0, const_cast<QFileSystemModel*>(q));
+ }
+ }
+ parent = node;
+ }
+
+ return parent;
+}
+
+/*!
+ \reimp
+*/
+void QFileSystemModel::timerEvent(QTimerEvent *event)
+{
+ Q_D(QFileSystemModel);
+ if (event->timerId() == d->fetchingTimer.timerId()) {
+ d->fetchingTimer.stop();
+#ifndef QT_NO_FILESYSTEMWATCHER
+ for (int i = 0; i < d->toFetch.count(); ++i) {
+ const QFileSystemModelPrivate::QFileSystemNode *node = d->toFetch.at(i).node;
+ if (!node->hasInformation()) {
+ d->fileInfoGatherer.fetchExtendedInformation(d->toFetch.at(i).dir,
+ QStringList(d->toFetch.at(i).file));
+ } else {
+ // qDebug() << "yah!, you saved a little gerbil soul";
+ }
+ }
+#endif
+ d->toFetch.clear();
+ }
+}
+
+/*!
+ Returns true if the model item \a index represents a directory;
+ otherwise returns false.
+*/
+bool QFileSystemModel::isDir(const QModelIndex &index) const
+{
+ // This function is for public usage only because it could create a file info
+ Q_D(const QFileSystemModel);
+ if (!index.isValid())
+ return true;
+ QFileSystemModelPrivate::QFileSystemNode *n = d->node(index);
+ if (n->hasInformation())
+ return n->isDir();
+ return fileInfo(index).isDir();
+}
+
+/*!
+ Returns the size in bytes of \a index. If the file does not exist, 0 is returned.
+ */
+qint64 QFileSystemModel::size(const QModelIndex &index) const
+{
+ Q_D(const QFileSystemModel);
+ if (!index.isValid())
+ return 0;
+ return d->node(index)->size();
+}
+
+/*!
+ Returns the type of file \a index such as "Directory" or "JPEG file".
+ */
+QString QFileSystemModel::type(const QModelIndex &index) const
+{
+ Q_D(const QFileSystemModel);
+ if (!index.isValid())
+ return QString();
+ return d->node(index)->type();
+}
+
+/*!
+ Returns the date and time when \a index was last modified.
+ */
+QDateTime QFileSystemModel::lastModified(const QModelIndex &index) const
+{
+ Q_D(const QFileSystemModel);
+ if (!index.isValid())
+ return QDateTime();
+ return d->node(index)->lastModified();
+}
+
+/*!
+ \reimp
+*/
+QModelIndex QFileSystemModel::parent(const QModelIndex &index) const
+{
+ Q_D(const QFileSystemModel);
+ if (!d->indexValid(index))
+ return QModelIndex();
+
+ QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index);
+ Q_ASSERT(indexNode != 0);
+ QFileSystemModelPrivate::QFileSystemNode *parentNode = (indexNode ? indexNode->parent : 0);
+ if (parentNode == 0 || parentNode == &d->root)
+ return QModelIndex();
+
+ // get the parent's row
+ QFileSystemModelPrivate::QFileSystemNode *grandParentNode = parentNode->parent;
+ Q_ASSERT(grandParentNode->children.contains(parentNode->fileName));
+ int visualRow = d->translateVisibleLocation(grandParentNode, grandParentNode->visibleLocation(grandParentNode->children.value(parentNode->fileName)->fileName));
+ if (visualRow == -1)
+ return QModelIndex();
+ return createIndex(visualRow, 0, parentNode);
+}
+
+/*
+ \internal
+
+ return the index for node
+*/
+QModelIndex QFileSystemModelPrivate::index(const QFileSystemModelPrivate::QFileSystemNode *node) const
+{
+ Q_Q(const QFileSystemModel);
+ QFileSystemModelPrivate::QFileSystemNode *parentNode = (node ? node->parent : 0);
+ if (node == &root || !parentNode)
+ return QModelIndex();
+
+ // get the parent's row
+ Q_ASSERT(node);
+ if (!node->isVisible)
+ return QModelIndex();
+
+ int visualRow = translateVisibleLocation(parentNode, parentNode->visibleLocation(node->fileName));
+ return q->createIndex(visualRow, 0, const_cast<QFileSystemNode*>(node));
+}
+
+/*!
+ \reimp
+*/
+bool QFileSystemModel::hasChildren(const QModelIndex &parent) const
+{
+ Q_D(const QFileSystemModel);
+ if (parent.column() > 0)
+ return false;
+
+ if (!parent.isValid()) // drives
+ return true;
+
+ const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
+ Q_ASSERT(indexNode);
+ return (indexNode->isDir());
+}
+
+/*!
+ \reimp
+ */
+bool QFileSystemModel::canFetchMore(const QModelIndex &parent) const
+{
+ Q_D(const QFileSystemModel);
+ const QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
+ return (!indexNode->populatedChildren);
+}
+
+/*!
+ \reimp
+ */
+void QFileSystemModel::fetchMore(const QModelIndex &parent)
+{
+ Q_D(QFileSystemModel);
+ if (!d->setRootPath)
+ return;
+ QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(parent);
+ if (indexNode->populatedChildren)
+ return;
+ indexNode->populatedChildren = true;
+ d->fileInfoGatherer.list(filePath(parent));
+}
+
+/*!
+ \reimp
+*/
+int QFileSystemModel::rowCount(const QModelIndex &parent) const
+{
+ Q_D(const QFileSystemModel);
+ if (parent.column() > 0)
+ return 0;
+
+ if (!parent.isValid())
+ return d->root.visibleChildren.count();
+
+ const QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
+ return parentNode->visibleChildren.count();
+}
+
+/*!
+ \reimp
+*/
+int QFileSystemModel::columnCount(const QModelIndex &parent) const
+{
+ return (parent.column() > 0) ? 0 : 4;
+}
+
+/*!
+ Returns the data stored under the given \a role for the item "My Computer".
+
+ \sa Qt::ItemDataRole
+ */
+QVariant QFileSystemModel::myComputer(int role) const
+{
+ Q_D(const QFileSystemModel);
+ switch (role) {
+ case Qt::DisplayRole:
+ return d->myComputer();
+ case Qt::DecorationRole:
+ return d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Computer);
+ }
+ return QVariant();
+}
+
+/*!
+ \reimp
+*/
+QVariant QFileSystemModel::data(const QModelIndex &index, int role) const
+{
+ Q_D(const QFileSystemModel);
+ if (!index.isValid() || index.model() != this)
+ return QVariant();
+
+ switch (role) {
+ case Qt::EditRole:
+ case Qt::DisplayRole:
+ switch (index.column()) {
+ case 0: return d->displayName(index);
+ case 1: return d->size(index);
+ case 2: return d->type(index);
+ case 3: return d->time(index);
+ default:
+ qWarning("data: invalid display value column %d", index.column());
+ break;
+ }
+ break;
+ case FilePathRole:
+ return filePath(index);
+ case FileNameRole:
+ return d->name(index);
+ case Qt::DecorationRole:
+ if (index.column() == 0) {
+ QIcon icon = d->icon(index);
+ if (icon.isNull()) {
+ if (d->node(index)->isDir())
+ icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::Folder);
+ else
+ icon = d->fileInfoGatherer.iconProvider()->icon(QFileIconProvider::File);
+ }
+ return icon;
+ }
+ break;
+ case Qt::TextAlignmentRole:
+ if (index.column() == 1)
+ return Qt::AlignRight;
+ break;
+ case FilePermissions:
+ int p = permissions(index);
+ return p;
+ }
+
+ return QVariant();
+}
+
+/*!
+ \internal
+*/
+QString QFileSystemModelPrivate::size(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QString();
+ const QFileSystemNode *n = node(index);
+ if (n->isDir()) {
+#ifdef Q_OS_MAC
+ return QLatin1String("--");
+#else
+ return QLatin1String("");
+#endif
+ // Windows - ""
+ // OS X - "--"
+ // Konqueror - "4 KB"
+ // Nautilus - "9 items" (the number of children)
+ }
+ return size(n->size());
+}
+
+QString QFileSystemModelPrivate::size(qint64 bytes)
+{
+ // According to the Si standard KB is 1000 bytes, KiB is 1024
+ // but on windows sizes are calculated by dividing by 1024 so we do what they do.
+ const qint64 kb = 1024;
+ const qint64 mb = 1024 * kb;
+ const qint64 gb = 1024 * mb;
+ const qint64 tb = 1024 * gb;
+ if (bytes >= tb)
+ return QFileSystemModel::tr("%1 TB").arg(QLocale().toString(qreal(bytes) / tb, 'f', 3));
+ if (bytes >= gb)
+ return QFileSystemModel::tr("%1 GB").arg(QLocale().toString(qreal(bytes) / gb, 'f', 2));
+ if (bytes >= mb)
+ return QFileSystemModel::tr("%1 MB").arg(QLocale().toString(qreal(bytes) / mb, 'f', 1));
+ if (bytes >= kb)
+ return QFileSystemModel::tr("%1 KB").arg(QLocale().toString(bytes / kb));
+ return QFileSystemModel::tr("%1 bytes").arg(QLocale().toString(bytes));
+}
+
+/*!
+ \internal
+*/
+QString QFileSystemModelPrivate::time(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QString();
+#ifndef QT_NO_DATESTRING
+ return node(index)->lastModified().toString(Qt::SystemLocaleDate);
+#else
+ Q_UNUSED(index);
+ return QString();
+#endif
+}
+
+/*
+ \internal
+*/
+QString QFileSystemModelPrivate::type(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QString();
+ return node(index)->type();
+}
+
+/*!
+ \internal
+*/
+QString QFileSystemModelPrivate::name(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QString();
+ QFileSystemNode *dirNode = node(index);
+ if (dirNode->isSymLink() && fileInfoGatherer.resolveSymlinks()) {
+ QString fullPath = QDir::fromNativeSeparators(filePath(index));
+ if (resolvedSymLinks.contains(fullPath))
+ return resolvedSymLinks[fullPath];
+ }
+ return dirNode->fileName;
+}
+
+/*!
+ \internal
+*/
+QString QFileSystemModelPrivate::displayName(const QModelIndex &index) const
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ QFileSystemNode *dirNode = node(index);
+ if (!dirNode->volumeName.isNull())
+ return dirNode->volumeName + QLatin1String(" (") + name(index) + QLatin1Char(')');
+#endif
+ return name(index);
+}
+
+/*!
+ \internal
+*/
+QIcon QFileSystemModelPrivate::icon(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QIcon();
+ return node(index)->icon();
+}
+
+/*!
+ \reimp
+*/
+bool QFileSystemModel::setData(const QModelIndex &idx, const QVariant &value, int role)
+{
+ Q_D(QFileSystemModel);
+ if (!idx.isValid()
+ || idx.column() != 0
+ || role != Qt::EditRole
+ || (flags(idx) & Qt::ItemIsEditable) == 0) {
+ return false;
+ }
+
+ QString newName = value.toString();
+ QString oldName = idx.data().toString();
+ if (newName == idx.data().toString())
+ return true;
+
+ if (newName.isEmpty()
+ || newName.contains(QDir::separator())
+ || !QDir(filePath(parent(idx))).rename(oldName, newName)) {
+#ifndef QT_NO_MESSAGEBOX
+ QMessageBox::information(0, QFileSystemModel::tr("Invalid filename"),
+ QFileSystemModel::tr("<b>The name \"%1\" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks.")
+ .arg(newName),
+ QMessageBox::Ok);
+#endif // QT_NO_MESSAGEBOX
+ return false;
+ } else {
+ /*
+ *After re-naming something we don't want the selection to change*
+ - can't remove rows and later insert
+ - can't quickly remove and insert
+ - index pointer can't change because treeview doesn't use persistant index's
+
+ - if this get any more complicated think of changing it to just
+ use layoutChanged
+ */
+
+ QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(idx);
+ QFileSystemModelPrivate::QFileSystemNode *parentNode = indexNode->parent;
+ int visibleLocation = parentNode->visibleLocation(parentNode->children.value(indexNode->fileName)->fileName);
+
+ d->addNode(parentNode, newName,indexNode->info->fileInfo());
+ parentNode->visibleChildren.removeAt(visibleLocation);
+ QFileSystemModelPrivate::QFileSystemNode * oldValue = parentNode->children.value(oldName);
+ parentNode->children[newName] = oldValue;
+ QFileInfo info(d->rootDir, newName);
+ oldValue->fileName = newName;
+ oldValue->parent = parentNode;
+ oldValue->populate(d->fileInfoGatherer.getInfo(info));
+ oldValue->isVisible = true;
+
+ parentNode->children.remove(oldName);
+ parentNode->visibleChildren.insert(visibleLocation, newName);
+
+ d->delayedSort();
+ emit fileRenamed(filePath(idx.parent()), oldName, newName);
+ }
+ return true;
+}
+
+/*!
+ \reimp
+*/
+QVariant QFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ switch (role) {
+ case Qt::DecorationRole:
+ if (section == 0) {
+ // ### TODO oh man this is ugly and doesn't even work all the way!
+ // it is still 2 pixels off
+ QImage pixmap(16, 1, QImage::Format_Mono);
+ pixmap.fill(0);
+ pixmap.setAlphaChannel(pixmap.createAlphaMask());
+ return pixmap;
+ }
+ break;
+ case Qt::TextAlignmentRole:
+ return Qt::AlignLeft;
+ }
+
+ if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
+ return QAbstractItemModel::headerData(section, orientation, role);
+
+ QString returnValue;
+ switch (section) {
+ case 0: returnValue = tr("Name");
+ break;
+ case 1: returnValue = tr("Size");
+ break;
+ case 2: returnValue =
+#ifdef Q_OS_MAC
+ tr("Kind", "Match OS X Finder");
+#else
+ tr("Type", "All other platforms");
+#endif
+ break;
+ // Windows - Type
+ // OS X - Kind
+ // Konqueror - File Type
+ // Nautilus - Type
+ case 3: returnValue = tr("Date Modified");
+ break;
+ default: return QVariant();
+ }
+ return returnValue;
+}
+
+/*!
+ \reimp
+*/
+Qt::ItemFlags QFileSystemModel::flags(const QModelIndex &index) const
+{
+ Q_D(const QFileSystemModel);
+ Qt::ItemFlags flags = QAbstractItemModel::flags(index);
+ if (!index.isValid())
+ return flags;
+
+ QFileSystemModelPrivate::QFileSystemNode *indexNode = d->node(index);
+ if (d->nameFilterDisables && !d->passNameFilters(indexNode)) {
+ flags &= ~Qt::ItemIsEnabled;
+ // ### TODO you shouldn't be able to set this as the current item, task 119433
+ return flags;
+ }
+
+ flags |= Qt::ItemIsDragEnabled;
+ if (d->readOnly)
+ return flags;
+ if ((index.column() == 0) && indexNode->permissions() & QFile::WriteUser) {
+ flags |= Qt::ItemIsEditable;
+ if (indexNode->isDir())
+ flags |= Qt::ItemIsDropEnabled;
+ }
+ return flags;
+}
+
+/*!
+ \internal
+*/
+void QFileSystemModelPrivate::_q_performDelayedSort()
+{
+ Q_Q(QFileSystemModel);
+ q->sort(sortColumn, sortOrder);
+}
+
+static inline QChar getNextChar(const QString &s, int location)
+{
+ return (location < s.length()) ? s.at(location) : QChar();
+}
+
+/*!
+ Natural number sort, skips spaces.
+
+ Examples:
+ 1, 2, 10, 55, 100
+ 01.jpg, 2.jpg, 10.jpg
+
+ Note on the algorithm:
+ Only as many characters as necessary are looked at and at most they all
+ are looked at once.
+
+ Slower then QString::compare() (of course)
+ */
+int QFileSystemModelPrivate::naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs)
+{
+ for (int l1 = 0, l2 = 0; l1 <= s1.count() && l2 <= s2.count(); ++l1, ++l2) {
+ // skip spaces, tabs and 0's
+ QChar c1 = getNextChar(s1, l1);
+ while (c1.isSpace())
+ c1 = getNextChar(s1, ++l1);
+ QChar c2 = getNextChar(s2, l2);
+ while (c2.isSpace())
+ c2 = getNextChar(s2, ++l2);
+
+ if (c1.isDigit() && c2.isDigit()) {
+ while (c1.digitValue() == 0)
+ c1 = getNextChar(s1, ++l1);
+ while (c2.digitValue() == 0)
+ c2 = getNextChar(s2, ++l2);
+
+ int lookAheadLocation1 = l1;
+ int lookAheadLocation2 = l2;
+ int currentReturnValue = 0;
+ // find the last digit, setting currentReturnValue as we go if it isn't equal
+ for (
+ QChar lookAhead1 = c1, lookAhead2 = c2;
+ (lookAheadLocation1 <= s1.length() && lookAheadLocation2 <= s2.length());
+ lookAhead1 = getNextChar(s1, ++lookAheadLocation1),
+ lookAhead2 = getNextChar(s2, ++lookAheadLocation2)
+ ) {
+ bool is1ADigit = !lookAhead1.isNull() && lookAhead1.isDigit();
+ bool is2ADigit = !lookAhead2.isNull() && lookAhead2.isDigit();
+ if (!is1ADigit && !is2ADigit)
+ break;
+ if (!is1ADigit)
+ return -1;
+ if (!is2ADigit)
+ return 1;
+ if (currentReturnValue == 0) {
+ if (lookAhead1 < lookAhead2) {
+ currentReturnValue = -1;
+ } else if (lookAhead1 > lookAhead2) {
+ currentReturnValue = 1;
+ }
+ }
+ }
+ if (currentReturnValue != 0)
+ return currentReturnValue;
+ }
+
+ if (cs == Qt::CaseInsensitive) {
+ if (!c1.isLower()) c1 = c1.toLower();
+ if (!c2.isLower()) c2 = c2.toLower();
+ }
+ int r = QString::localeAwareCompare(c1, c2);
+ if (r < 0)
+ return -1;
+ if (r > 0)
+ return 1;
+ }
+ // The two strings are the same (02 == 2) so fall back to the normal sort
+ return QString::compare(s1, s2, cs);
+}
+
+/*
+ \internal
+ Helper functor used by sort()
+*/
+class QFileSystemModelSorter
+{
+public:
+ inline QFileSystemModelSorter(int column) : sortColumn(column) {}
+
+ bool compareNodes(const QFileSystemModelPrivate::QFileSystemNode *l,
+ const QFileSystemModelPrivate::QFileSystemNode *r) const
+ {
+ switch (sortColumn) {
+ case 0: {
+#ifndef Q_OS_MAC
+ // place directories before files
+ bool left = l->isDir();
+ bool right = r->isDir();
+ if (left ^ right)
+ return left;
+#endif
+ return QFileSystemModelPrivate::naturalCompare(l->fileName,
+ r->fileName, Qt::CaseInsensitive) < 0;
+ }
+ case 1:
+ // Directories go first
+ if (l->isDir() && !r->isDir())
+ return true;
+ return l->size() < r->size();
+ case 2:
+ return l->type() < r->type();
+ case 3:
+ return l->lastModified() < r->lastModified();
+ }
+ Q_ASSERT(false);
+ return false;
+ }
+
+ bool operator()(const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &l,
+ const QPair<QFileSystemModelPrivate::QFileSystemNode*, int> &r) const
+ {
+ return compareNodes(l.first, r.first);
+ }
+
+
+private:
+ int sortColumn;
+};
+
+/*
+ \internal
+
+ Sort all of the children of parent
+*/
+void QFileSystemModelPrivate::sortChildren(int column, const QModelIndex &parent)
+{
+ Q_Q(QFileSystemModel);
+ QFileSystemModelPrivate::QFileSystemNode *indexNode = node(parent);
+ if (indexNode->children.count() == 0)
+ return;
+
+ QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > values;
+ QHash<QString, QFileSystemNode *>::const_iterator iterator;
+ int i = 0;
+ for(iterator = indexNode->children.begin() ; iterator != indexNode->children.end() ; ++iterator) {
+ if (filtersAcceptsNode(iterator.value())) {
+ values.append(QPair<QFileSystemModelPrivate::QFileSystemNode*, int>((iterator.value()), i));
+ } else {
+ iterator.value()->isVisible = false;
+ }
+ i++;
+ }
+ QFileSystemModelSorter ms(column);
+ qStableSort(values.begin(), values.end(), ms);
+ // First update the new visible list
+ indexNode->visibleChildren.clear();
+ //No more dirty item we reset our internal dirty index
+ indexNode->dirtyChildrenIndex = -1;
+ for (int i = 0; i < values.count(); ++i) {
+ indexNode->visibleChildren.append(values.at(i).first->fileName);
+ values.at(i).first->isVisible = true;
+ }
+
+ if (!disableRecursiveSort) {
+ for (int i = 0; i < q->rowCount(parent); ++i) {
+ const QModelIndex childIndex = q->index(i, 0, parent);
+ QFileSystemModelPrivate::QFileSystemNode *indexNode = node(childIndex);
+ //Only do a recursive sort on visible nodes
+ if (indexNode->isVisible)
+ sortChildren(column, childIndex);
+ }
+ }
+}
+
+/*!
+ \reimp
+*/
+void QFileSystemModel::sort(int column, Qt::SortOrder order)
+{
+ Q_D(QFileSystemModel);
+ if (d->sortOrder == order && d->sortColumn == column && !d->forceSort)
+ return;
+
+ emit layoutAboutToBeChanged();
+ QModelIndexList oldList = persistentIndexList();
+ QList<QPair<QFileSystemModelPrivate::QFileSystemNode*, int> > oldNodes;
+ for (int i = 0; i < oldList.count(); ++i) {
+ QPair<QFileSystemModelPrivate::QFileSystemNode*, int> pair(d->node(oldList.at(i)), oldList.at(i).column());
+ oldNodes.append(pair);
+ }
+
+ if (!(d->sortColumn == column && d->sortOrder != order && !d->forceSort)) {
+ //we sort only from where we are, don't need to sort all the model
+ d->sortChildren(column, index(rootPath()));
+ d->sortColumn = column;
+ d->forceSort = false;
+ }
+ d->sortOrder = order;
+
+ QModelIndexList newList;
+ for (int i = 0; i < oldNodes.count(); ++i) {
+ QModelIndex idx = d->index(oldNodes.at(i).first);
+ idx = idx.sibling(idx.row(), oldNodes.at(i).second);
+ newList.append(idx);
+ }
+ changePersistentIndexList(oldList, newList);
+ emit layoutChanged();
+}
+
+/*!
+ Returns a list of MIME types that can be used to describe a list of items
+ in the model.
+*/
+QStringList QFileSystemModel::mimeTypes() const
+{
+ return QStringList(QLatin1String("text/uri-list"));
+}
+
+/*!
+ Returns an object that contains a serialized description of the specified
+ \a indexes. The format used to describe the items corresponding to the
+ indexes is obtained from the mimeTypes() function.
+
+ If the list of indexes is empty, 0 is returned rather than a serialized
+ empty list.
+*/
+QMimeData *QFileSystemModel::mimeData(const QModelIndexList &indexes) const
+{
+ QList<QUrl> urls;
+ QList<QModelIndex>::const_iterator it = indexes.begin();
+ for (; it != indexes.end(); ++it)
+ if ((*it).column() == 0)
+ urls << QUrl::fromLocalFile(filePath(*it));
+ QMimeData *data = new QMimeData();
+ data->setUrls(urls);
+ return data;
+}
+
+/*!
+ Handles the \a data supplied by a drag and drop operation that ended with
+ the given \a action over the row in the model specified by the \a row and
+ \a column and by the \a parent index.
+
+ \sa supportedDropActions()
+*/
+bool QFileSystemModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent)
+{
+ Q_UNUSED(row);
+ Q_UNUSED(column);
+ if (!parent.isValid() || isReadOnly())
+ return false;
+
+ bool success = true;
+ QString to = filePath(parent) + QDir::separator();
+
+ QList<QUrl> urls = data->urls();
+ QList<QUrl>::const_iterator it = urls.constBegin();
+
+ switch (action) {
+ case Qt::CopyAction:
+ for (; it != urls.constEnd(); ++it) {
+ QString path = (*it).toLocalFile();
+ success = QFile::copy(path, to + QFileInfo(path).fileName()) && success;
+ }
+ break;
+ case Qt::LinkAction:
+ for (; it != urls.constEnd(); ++it) {
+ QString path = (*it).toLocalFile();
+ success = QFile::link(path, to + QFileInfo(path).fileName()) && success;
+ }
+ break;
+ case Qt::MoveAction:
+ for (; it != urls.constEnd(); ++it) {
+ QString path = (*it).toLocalFile();
+ success = QFile::rename(path, to + QFileInfo(path).fileName()) && success;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return success;
+}
+
+/*!
+ \reimp
+*/
+Qt::DropActions QFileSystemModel::supportedDropActions() const
+{
+ return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
+}
+
+/*!
+ Returns the path of the item stored in the model under the
+ \a index given.
+*/
+QString QFileSystemModel::filePath(const QModelIndex &index) const
+{
+ Q_D(const QFileSystemModel);
+ QString fullPath = d->filePath(index);
+ QFileSystemModelPrivate::QFileSystemNode *dirNode = d->node(index);
+ if (dirNode->isSymLink() && d->fileInfoGatherer.resolveSymlinks()
+ && d->resolvedSymLinks.contains(fullPath)
+ && dirNode->isDir()) {
+ QFileInfo resolvedInfo(fullPath);
+ resolvedInfo = resolvedInfo.canonicalFilePath();
+ if (resolvedInfo.exists())
+ return resolvedInfo.filePath();
+ }
+ return fullPath;
+}
+
+QString QFileSystemModelPrivate::filePath(const QModelIndex &index) const
+{
+ Q_Q(const QFileSystemModel);
+ Q_UNUSED(q);
+ if (!index.isValid())
+ return QString();
+ Q_ASSERT(index.model() == q);
+
+ QStringList path;
+ QModelIndex idx = index;
+ while (idx.isValid()) {
+ QFileSystemModelPrivate::QFileSystemNode *dirNode = node(idx);
+ if (dirNode)
+ path.prepend(dirNode->fileName);
+ idx = idx.parent();
+ }
+ QString fullPath = QDir::fromNativeSeparators(path.join(QDir::separator()));
+#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE)
+ if ((fullPath.length() > 2) && fullPath[0] == QLatin1Char('/') && fullPath[1] == QLatin1Char('/'))
+ fullPath = fullPath.mid(1);
+#endif
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ if (fullPath.length() == 2 && fullPath.endsWith(QLatin1Char(':')))
+ fullPath.append(QLatin1Char('/'));
+#endif
+ return fullPath;
+}
+
+/*!
+ Create a directory with the \a name in the \a parent model index.
+*/
+QModelIndex QFileSystemModel::mkdir(const QModelIndex &parent, const QString &name)
+{
+ Q_D(QFileSystemModel);
+ if (!parent.isValid())
+ return parent;
+
+ QDir dir(filePath(parent));
+ if (!dir.mkdir(name))
+ return QModelIndex();
+ QFileSystemModelPrivate::QFileSystemNode *parentNode = d->node(parent);
+ d->addNode(parentNode, name, QFileInfo());
+ Q_ASSERT(parentNode->children.contains(name));
+ QFileSystemModelPrivate::QFileSystemNode *node = parentNode->children[name];
+ node->populate(d->fileInfoGatherer.getInfo(QFileInfo(dir.absolutePath() + QDir::separator() + name)));
+ d->addVisibleFiles(parentNode, QStringList(name));
+ return d->index(node);
+}
+
+/*!
+ Returns the complete OR-ed together combination of QFile::Permission for the \a index.
+ */
+QFile::Permissions QFileSystemModel::permissions(const QModelIndex &index) const
+{
+ Q_D(const QFileSystemModel);
+ QFile::Permissions p = d->node(index)->permissions();
+ if (d->readOnly) {
+ p ^= (QFile::WriteOwner | QFile::WriteUser
+ | QFile::WriteGroup | QFile::WriteOther);
+ }
+ return p;
+}
+
+/*!
+ Sets the directory that is being watched by the model to \a newPath by
+ installing a \l{QFileSystemWatcher}{file system watcher} on it. Any
+ changes to files and directories within this directory will be
+ reflected in the model.
+
+ If the path is changed, the rootPathChanged() signal will be emitted.
+
+ \note This function does not change the structure of the model or
+ modify the data available to views. In other words, the "root" of
+ the model is \e not changed to include only files and directories
+ within the directory specified by \a newPath in the file system.
+ */
+QModelIndex QFileSystemModel::setRootPath(const QString &newPath)
+{
+ Q_D(QFileSystemModel);
+#ifdef Q_OS_WIN
+#ifdef Q_OS_WIN32
+ QString longNewPath = qt_GetLongPathName(newPath);
+#else
+ QString longNewPath = QDir::fromNativeSeparators(newPath);
+#endif
+#else
+ QString longNewPath = newPath;
+#endif
+ QDir newPathDir(longNewPath);
+ //we remove .. and . from the given path if exist
+ if (!newPath.isEmpty()) {
+ longNewPath = QDir::cleanPath(longNewPath);
+ newPathDir.setPath(longNewPath);
+ }
+
+ d->setRootPath = true;
+
+ //user don't ask for the root path ("") but the conversion failed
+ if (!newPath.isEmpty() && longNewPath.isEmpty())
+ return d->index(rootPath());
+
+ if (d->rootDir.path() == longNewPath)
+ return d->index(rootPath());
+
+ bool showDrives = (longNewPath.isEmpty() || longNewPath == d->myComputer());
+ if (!showDrives && !newPathDir.exists())
+ return d->index(rootPath());
+
+ //We remove the watcher on the previous path
+ if (!rootPath().isEmpty() && rootPath() != QLatin1String(".")) {
+ //This remove the watcher for the old rootPath
+ d->fileInfoGatherer.removePath(rootPath());
+ //This line "marks" the node as dirty, so the next fetchMore
+ //call on the path will ask the gatherer to install a watcher again
+ //But it doesn't re-fetch everything
+ d->node(rootPath())->populatedChildren = false;
+ }
+
+ // We have a new valid root path
+ d->rootDir = newPathDir;
+ QModelIndex newRootIndex;
+ if (showDrives) {
+ // otherwise dir will become '.'
+ d->rootDir.setPath(QLatin1String(""));
+ } else {
+ newRootIndex = d->index(newPathDir.path());
+ }
+ fetchMore(newRootIndex);
+ emit rootPathChanged(longNewPath);
+ d->forceSort = true;
+ d->delayedSort();
+ return newRootIndex;
+}
+
+/*!
+ The currently set root path
+
+ \sa rootDirectory()
+*/
+QString QFileSystemModel::rootPath() const
+{
+ Q_D(const QFileSystemModel);
+ return d->rootDir.path();
+}
+
+/*!
+ The currently set directory
+
+ \sa rootPath()
+*/
+QDir QFileSystemModel::rootDirectory() const
+{
+ Q_D(const QFileSystemModel);
+ QDir dir(d->rootDir);
+ dir.setNameFilters(nameFilters());
+ dir.setFilter(filter());
+ return dir;
+}
+
+/*!
+ Sets the \a provider of file icons for the directory model.
+*/
+void QFileSystemModel::setIconProvider(QFileIconProvider *provider)
+{
+ Q_D(QFileSystemModel);
+ d->fileInfoGatherer.setIconProvider(provider);
+ d->root.updateIcon(provider, QString());
+}
+
+/*!
+ Returns the file icon provider for this directory model.
+*/
+QFileIconProvider *QFileSystemModel::iconProvider() const
+{
+ Q_D(const QFileSystemModel);
+ return d->fileInfoGatherer.iconProvider();
+}
+
+/*!
+ Sets the directory model's filter to that specified by \a filters.
+
+ Note that the filter you set should always include the QDir::AllDirs enum value,
+ otherwise QFileSystemModel won't be able to read the directory structure.
+
+ \sa QDir::Filters
+*/
+void QFileSystemModel::setFilter(QDir::Filters filters)
+{
+ Q_D(QFileSystemModel);
+ if (d->filters == filters)
+ return;
+ d->filters = filters;
+ // CaseSensitivity might have changed
+ setNameFilters(nameFilters());
+ d->forceSort = true;
+ d->delayedSort();
+}
+
+/*!
+ Returns the filter specified for the directory model.
+
+ If a filter has not been set, the default filter is QDir::AllEntries |
+ QDir::NoDotAndDotDot | QDir::AllDirs.
+
+ \sa QDir::Filters
+*/
+QDir::Filters QFileSystemModel::filter() const
+{
+ Q_D(const QFileSystemModel);
+ return d->filters;
+}
+
+/*!
+ \property QFileSystemModel::resolveSymlinks
+ \brief Whether the directory model should resolve symbolic links
+
+ This is only relevant on operating systems that support symbolic links.
+
+ By default, this property is false.
+*/
+void QFileSystemModel::setResolveSymlinks(bool enable)
+{
+ Q_D(QFileSystemModel);
+ d->fileInfoGatherer.setResolveSymlinks(enable);
+}
+
+bool QFileSystemModel::resolveSymlinks() const
+{
+ Q_D(const QFileSystemModel);
+ return d->fileInfoGatherer.resolveSymlinks();
+}
+
+/*!
+ \property QFileSystemModel::readOnly
+ \brief Whether the directory model allows writing to the file system
+
+ If this property is set to false, the directory model will allow renaming, copying
+ and deleting of files and directories.
+
+ This property is true by default
+*/
+void QFileSystemModel::setReadOnly(bool enable)
+{
+ Q_D(QFileSystemModel);
+ d->readOnly = enable;
+}
+
+bool QFileSystemModel::isReadOnly() const
+{
+ Q_D(const QFileSystemModel);
+ return d->readOnly;
+}
+
+/*!
+ \property QFileSystemModel::nameFilterDisables
+ \brief Whether files that don't pass the name filter are hidden or disabled
+
+ This property is true by default
+*/
+void QFileSystemModel::setNameFilterDisables(bool enable)
+{
+ Q_D(QFileSystemModel);
+ if (d->nameFilterDisables == enable)
+ return;
+ d->nameFilterDisables = enable;
+ d->forceSort = true;
+ d->delayedSort();
+}
+
+bool QFileSystemModel::nameFilterDisables() const
+{
+ Q_D(const QFileSystemModel);
+ return d->nameFilterDisables;
+}
+
+/*!
+ Sets the name \a filters to apply against the existing files.
+*/
+void QFileSystemModel::setNameFilters(const QStringList &filters)
+{
+ // Prep the regexp's ahead of time
+#ifndef QT_NO_REGEXP
+ Q_D(QFileSystemModel);
+
+ if (!d->bypassFilters.isEmpty()) {
+ // update the bypass filter to only bypass the stuff that must be kept around
+ d->bypassFilters.clear();
+ // We guarantee that rootPath will stick around
+ QPersistentModelIndex root(index(rootPath()));
+ QModelIndexList persistantList = persistentIndexList();
+ for (int i = 0; i < persistantList.count(); ++i) {
+ QFileSystemModelPrivate::QFileSystemNode *node;
+ node = d->node(persistantList.at(i));
+ while (node) {
+ if (d->bypassFilters.contains(node))
+ break;
+ if (node->isDir())
+ d->bypassFilters[node] = true;
+ node = node->parent;
+ }
+ }
+ }
+
+ d->nameFilters.clear();
+ const Qt::CaseSensitivity caseSensitive =
+ (filter() & QDir::CaseSensitive) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ for (int i = 0; i < filters.size(); ++i) {
+ d->nameFilters << QRegExp(filters.at(i), caseSensitive, QRegExp::Wildcard);
+ }
+ d->forceSort = true;
+ d->delayedSort();
+#endif
+}
+
+/*!
+ Returns a list of filters applied to the names in the model.
+*/
+QStringList QFileSystemModel::nameFilters() const
+{
+ Q_D(const QFileSystemModel);
+ QStringList filters;
+#ifndef QT_NO_REGEXP
+ for (int i = 0; i < d->nameFilters.size(); ++i) {
+ filters << d->nameFilters.at(i).pattern();
+ }
+#endif
+ return filters;
+}
+
+/*!
+ \reimp
+*/
+bool QFileSystemModel::event(QEvent *event)
+{
+ Q_D(QFileSystemModel);
+ if (event->type() == QEvent::LanguageChange) {
+ d->root.retranslateStrings(d->fileInfoGatherer.iconProvider(), QString());
+ return true;
+ }
+ return QAbstractItemModel::event(event);
+}
+
+bool QFileSystemModel::rmdir(const QModelIndex &aindex) const
+{
+ QString path = filePath(aindex);
+ QFileSystemModelPrivate * d = const_cast<QFileSystemModelPrivate*>(d_func());
+ d->fileInfoGatherer.removePath(path);
+ return QDir().rmdir(path);
+}
+
+/*!
+ \internal
+
+ Performed quick listing and see if any files have been added or removed,
+ then fetch more information on visible files.
+ */
+void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, const QStringList &files)
+{
+ QFileSystemModelPrivate::QFileSystemNode *parentNode = node(directory, false);
+ if (parentNode->children.count() == 0)
+ return;
+ QStringList toRemove;
+#if defined(Q_OS_SYMBIAN)
+ // Filename case must be exact in qBinaryFind below, so create a list of all lowercase names.
+ QStringList newFiles;
+ for(int i = 0; i < files.size(); i++) {
+ newFiles << files.at(i).toLower();
+ }
+#else
+ QStringList newFiles = files;
+#endif
+ qSort(newFiles.begin(), newFiles.end());
+ QHash<QString, QFileSystemNode*>::const_iterator i = parentNode->children.constBegin();
+ while (i != parentNode->children.constEnd()) {
+ QStringList::iterator iterator;
+ iterator = qBinaryFind(newFiles.begin(), newFiles.end(),
+#if defined(Q_OS_SYMBIAN)
+ i.value()->fileName.toLower());
+#else
+ i.value()->fileName);
+#endif
+ if (iterator == newFiles.end()) {
+ toRemove.append(i.value()->fileName);
+ }
+ ++i;
+ }
+ for (int i = 0 ; i < toRemove.count() ; ++i )
+ removeNode(parentNode, toRemove[i]);
+}
+
+/*!
+ \internal
+
+ Adds a new file to the children of parentNode
+
+ *WARNING* this will change the count of children
+*/
+QFileSystemModelPrivate::QFileSystemNode* QFileSystemModelPrivate::addNode(QFileSystemNode *parentNode, const QString &fileName, const QFileInfo& info)
+{
+ // In the common case, itemLocation == count() so check there first
+ QFileSystemModelPrivate::QFileSystemNode *node = new QFileSystemModelPrivate::QFileSystemNode(fileName, parentNode);
+#ifndef QT_NO_FILESYSTEMWATCHER
+ node->populate(info);
+#endif
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ //The parentNode is "" so we are listing the drives
+ if (parentNode->fileName.isEmpty()) {
+ wchar_t name[MAX_PATH + 1];
+ //GetVolumeInformation requires to add trailing backslash
+ const QString nodeName = fileName + QLatin1String("\\");
+ BOOL success = ::GetVolumeInformation((wchar_t *)(nodeName.utf16()),
+ name, MAX_PATH + 1, NULL, 0, NULL, NULL, 0);
+ if (success && name[0])
+ node->volumeName = QString::fromWCharArray(name);
+ }
+#endif
+ parentNode->children.insert(fileName, node);
+ return node;
+}
+
+/*!
+ \internal
+
+ File at parentNode->children(itemLocation) has been removed, remove from the lists
+ and emit signals if necessary
+
+ *WARNING* this will change the count of children and could change visibleChildren
+ */
+void QFileSystemModelPrivate::removeNode(QFileSystemModelPrivate::QFileSystemNode *parentNode, const QString& name)
+{
+ Q_Q(QFileSystemModel);
+ QModelIndex parent = index(parentNode);
+ bool indexHidden = isHiddenByFilter(parentNode, parent);
+
+ int vLocation = parentNode->visibleLocation(name);
+ if (vLocation >= 0 && !indexHidden)
+ q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
+ translateVisibleLocation(parentNode, vLocation));
+ QFileSystemNode * node = parentNode->children.take(name);
+ delete node;
+ // cleanup sort files after removing rather then re-sorting which is O(n)
+ if (vLocation >= 0)
+ parentNode->visibleChildren.removeAt(vLocation);
+ if (vLocation >= 0 && !indexHidden)
+ q->endRemoveRows();
+}
+
+/*
+ \internal
+ Helper functor used by addVisibleFiles()
+*/
+class QFileSystemModelVisibleFinder
+{
+public:
+ inline QFileSystemModelVisibleFinder(QFileSystemModelPrivate::QFileSystemNode *node, QFileSystemModelSorter *sorter) : parentNode(node), sorter(sorter) {}
+
+ bool operator()(const QString &, QString r) const
+ {
+ return sorter->compareNodes(parentNode->children.value(name), parentNode->children.value(r));
+ }
+
+ QString name;
+private:
+ QFileSystemModelPrivate::QFileSystemNode *parentNode;
+ QFileSystemModelSorter *sorter;
+};
+
+/*!
+ \internal
+
+ File at parentNode->children(itemLocation) was not visible before, but now should be
+ and emit signals if necessary.
+
+ *WARNING* this will change the visible count
+ */
+void QFileSystemModelPrivate::addVisibleFiles(QFileSystemNode *parentNode, const QStringList &newFiles)
+{
+ Q_Q(QFileSystemModel);
+ QModelIndex parent = index(parentNode);
+ bool indexHidden = isHiddenByFilter(parentNode, parent);
+ if (!indexHidden) {
+ q->beginInsertRows(parent, parentNode->visibleChildren.count() , parentNode->visibleChildren.count() + newFiles.count() - 1);
+ }
+
+ if (parentNode->dirtyChildrenIndex == -1)
+ parentNode->dirtyChildrenIndex = parentNode->visibleChildren.count();
+
+ for (int i = 0; i < newFiles.count(); ++i) {
+ parentNode->visibleChildren.append(newFiles.at(i));
+ parentNode->children[newFiles.at(i)]->isVisible = true;
+ }
+ if (!indexHidden)
+ q->endInsertRows();
+}
+
+/*!
+ \internal
+
+ File was visible before, but now should NOT be
+
+ *WARNING* this will change the visible count
+ */
+void QFileSystemModelPrivate::removeVisibleFile(QFileSystemNode *parentNode, int vLocation)
+{
+ Q_Q(QFileSystemModel);
+ if (vLocation == -1)
+ return;
+ QModelIndex parent = index(parentNode);
+ bool indexHidden = isHiddenByFilter(parentNode, parent);
+ if (!indexHidden)
+ q->beginRemoveRows(parent, translateVisibleLocation(parentNode, vLocation),
+ translateVisibleLocation(parentNode, vLocation));
+ parentNode->children[parentNode->visibleChildren.at(vLocation)]->isVisible = false;
+ parentNode->visibleChildren.removeAt(vLocation);
+ if (!indexHidden)
+ q->endRemoveRows();
+}
+
+/*!
+ \internal
+
+ The thread has received new information about files,
+ update and emit dataChanged if it has actually changed.
+ */
+void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo> > &updates)
+{
+ Q_Q(QFileSystemModel);
+ QVector<QString> rowsToUpdate;
+ QStringList newFiles;
+ QFileSystemModelPrivate::QFileSystemNode *parentNode = node(path, false);
+ QModelIndex parentIndex = index(parentNode);
+ for (int i = 0; i < updates.count(); ++i) {
+ QString fileName = updates.at(i).first;
+ Q_ASSERT(!fileName.isEmpty());
+ QExtendedInformation info = fileInfoGatherer.getInfo(updates.at(i).second);
+ bool previouslyHere = parentNode->children.contains(fileName);
+ if (!previouslyHere) {
+ addNode(parentNode, fileName, info.fileInfo());
+ }
+ QFileSystemModelPrivate::QFileSystemNode * node = parentNode->children.value(fileName);
+ bool isCaseSensitive = parentNode->caseSensitive();
+ if (isCaseSensitive) {
+ if (node->fileName != fileName)
+ continue;
+ } else {
+ if (QString::compare(node->fileName,fileName,Qt::CaseInsensitive) != 0)
+ continue;
+ }
+ if (isCaseSensitive) {
+ Q_ASSERT(node->fileName == fileName);
+ } else {
+ node->fileName = fileName;
+ }
+
+ if (info.size() == -1 && !info.isSymLink()) {
+ removeNode(parentNode, fileName);
+ continue;
+ }
+ if (*node != info ) {
+ node->populate(info);
+ bypassFilters.remove(node);
+ // brand new information.
+ if (filtersAcceptsNode(node)) {
+ if (!node->isVisible) {
+ newFiles.append(fileName);
+ } else {
+ rowsToUpdate.append(fileName);
+ }
+ } else {
+ if (node->isVisible) {
+ int visibleLocation = parentNode->visibleLocation(fileName);
+ removeVisibleFile(parentNode, visibleLocation);
+ } else {
+ // The file is not visible, don't do anything
+ }
+ }
+ }
+ }
+
+ // bundle up all of the changed signals into as few as possible.
+ qSort(rowsToUpdate.begin(), rowsToUpdate.end());
+ QString min;
+ QString max;
+ for (int i = 0; i < rowsToUpdate.count(); ++i) {
+ QString value = rowsToUpdate.at(i);
+ //##TODO is there a way to bundle signals with QString as the content of the list?
+ /*if (min.isEmpty()) {
+ min = value;
+ if (i != rowsToUpdate.count() - 1)
+ continue;
+ }
+ if (i != rowsToUpdate.count() - 1) {
+ if ((value == min + 1 && max.isEmpty()) || value == max + 1) {
+ max = value;
+ continue;
+ }
+ }*/
+ max = value;
+ min = value;
+ int visibleMin = parentNode->visibleLocation(min);
+ int visibleMax = parentNode->visibleLocation(max);
+ if (visibleMin >= 0
+ && visibleMin < parentNode->visibleChildren.count()
+ && parentNode->visibleChildren.at(visibleMin) == min
+ && visibleMax >= 0) {
+ QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex);
+ QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex);
+ emit q->dataChanged(bottom, top);
+ }
+
+ /*min = QString();
+ max = QString();*/
+ }
+
+ if (newFiles.count() > 0) {
+ addVisibleFiles(parentNode, newFiles);
+ }
+
+ if (newFiles.count() > 0 || (sortColumn != 0 && rowsToUpdate.count() > 0)) {
+ forceSort = true;
+ delayedSort();
+ }
+}
+
+/*!
+ \internal
+*/
+void QFileSystemModelPrivate::_q_resolvedName(const QString &fileName, const QString &resolvedName)
+{
+ resolvedSymLinks[fileName] = resolvedName;
+}
+
+/*!
+ \internal
+*/
+void QFileSystemModelPrivate::init()
+{
+ Q_Q(QFileSystemModel);
+ qRegisterMetaType<QList<QPair<QString,QFileInfo> > >("QList<QPair<QString,QFileInfo> >");
+ q->connect(&fileInfoGatherer, SIGNAL(newListOfFiles(QString,QStringList)),
+ q, SLOT(_q_directoryChanged(QString,QStringList)));
+ q->connect(&fileInfoGatherer, SIGNAL(updates(QString,QList<QPair<QString,QFileInfo> >)),
+ q, SLOT(_q_fileSystemChanged(QString,QList<QPair<QString,QFileInfo> >)));
+ q->connect(&fileInfoGatherer, SIGNAL(nameResolved(QString,QString)),
+ q, SLOT(_q_resolvedName(QString,QString)));
+ q->connect(&fileInfoGatherer, SIGNAL(directoryLoaded(QString)),
+ q, SIGNAL(directoryLoaded(QString)));
+ q->connect(&delayedSortTimer, SIGNAL(timeout()), q, SLOT(_q_performDelayedSort()), Qt::QueuedConnection);
+
+ QHash<int, QByteArray> roles = q->roleNames();
+ roles.insertMulti(QFileSystemModel::FileIconRole, "fileIcon"); // == Qt::decoration
+ roles.insert(QFileSystemModel::FilePathRole, "filePath");
+ roles.insert(QFileSystemModel::FileNameRole, "fileName");
+ roles.insert(QFileSystemModel::FilePermissions, "filePermissions");
+ q->setRoleNames(roles);
+}
+
+/*!
+ \internal
+
+ Returns false if node doesn't pass the filters otherwise true
+
+ QDir::Modified is not supported
+ QDir::Drives is not supported
+*/
+bool QFileSystemModelPrivate::filtersAcceptsNode(const QFileSystemNode *node) const
+{
+ // always accept drives
+ if (node->parent == &root || bypassFilters.contains(node))
+ return true;
+
+ // If we don't know anything yet don't accept it
+ if (!node->hasInformation())
+ return false;
+
+ const bool filterPermissions = ((filters & QDir::PermissionMask)
+ && (filters & QDir::PermissionMask) != QDir::PermissionMask);
+ const bool hideDirs = !(filters & (QDir::Dirs | QDir::AllDirs));
+ const bool hideFiles = !(filters & QDir::Files);
+ const bool hideReadable = !(!filterPermissions || (filters & QDir::Readable));
+ const bool hideWritable = !(!filterPermissions || (filters & QDir::Writable));
+ const bool hideExecutable = !(!filterPermissions || (filters & QDir::Executable));
+ const bool hideHidden = !(filters & QDir::Hidden);
+ const bool hideSystem = !(filters & QDir::System);
+ const bool hideSymlinks = (filters & QDir::NoSymLinks);
+ const bool hideDot = (filters & QDir::NoDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot)
+ const bool hideDotDot = (filters & QDir::NoDotDot) || (filters & QDir::NoDotAndDotDot); // ### Qt5: simplify (because NoDotAndDotDot=NoDot|NoDotDot)
+
+ // Note that we match the behavior of entryList and not QFileInfo on this and this
+ // incompatibility won't be fixed until Qt 5 at least
+ bool isDot = (node->fileName == QLatin1String("."));
+ bool isDotDot = (node->fileName == QLatin1String(".."));
+ if ( (hideHidden && !(isDot || isDotDot) && node->isHidden())
+ || (hideSystem && node->isSystem())
+ || (hideDirs && node->isDir())
+ || (hideFiles && node->isFile())
+ || (hideSymlinks && node->isSymLink())
+ || (hideReadable && node->isReadable())
+ || (hideWritable && node->isWritable())
+ || (hideExecutable && node->isExecutable())
+ || (hideDot && isDot)
+ || (hideDotDot && isDotDot))
+ return false;
+
+ return nameFilterDisables || passNameFilters(node);
+}
+
+/*
+ \internal
+
+ Returns true if node passes the name filters and should be visible.
+ */
+bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const
+{
+#ifndef QT_NO_REGEXP
+ if (nameFilters.isEmpty())
+ return true;
+
+ // Check the name regularexpression filters
+ if (!(node->isDir() && (filters & QDir::AllDirs))) {
+ for (int i = 0; i < nameFilters.size(); ++i) {
+ if (nameFilters.at(i).exactMatch(node->fileName))
+ return true;
+ }
+ return false;
+ }
+#endif
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qfilesystemmodel.cpp"
+
+#endif // QT_NO_FILESYSTEMMODEL
diff --git a/src/widgets/dialogs/qfilesystemmodel.h b/src/widgets/dialogs/qfilesystemmodel.h
new file mode 100644
index 0000000000..ce907cd10e
--- /dev/null
+++ b/src/widgets/dialogs/qfilesystemmodel.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMMODEL_H
+#define QFILESYSTEMMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qdir.h>
+#include <QtWidgets/qicon.h>
+#include <QtCore/qdiriterator.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_FILESYSTEMMODEL
+
+class ExtendedInformation;
+class QFileSystemModelPrivate;
+class QFileIconProvider;
+
+class Q_WIDGETS_EXPORT QFileSystemModel : public QAbstractItemModel
+{
+ Q_OBJECT
+ Q_PROPERTY(bool resolveSymlinks READ resolveSymlinks WRITE setResolveSymlinks)
+ Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly)
+ Q_PROPERTY(bool nameFilterDisables READ nameFilterDisables WRITE setNameFilterDisables)
+
+Q_SIGNALS:
+ void rootPathChanged(const QString &newPath);
+ void fileRenamed(const QString &path, const QString &oldName, const QString &newName);
+ void directoryLoaded(const QString &path);
+
+public:
+ enum Roles {
+ FileIconRole = Qt::DecorationRole,
+ FilePathRole = Qt::UserRole + 1,
+ FileNameRole = Qt::UserRole + 2,
+ FilePermissions = Qt::UserRole + 3
+ };
+
+ explicit QFileSystemModel(QObject *parent = 0);
+ ~QFileSystemModel();
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ QModelIndex index(const QString &path, int column = 0) const;
+ QModelIndex parent(const QModelIndex &child) const;
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const;
+ bool canFetchMore(const QModelIndex &parent) const;
+ void fetchMore(const QModelIndex &parent);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ QVariant myComputer(int role = Qt::DisplayRole) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+
+ QStringList mimeTypes() const;
+ QMimeData *mimeData(const QModelIndexList &indexes) const;
+ bool dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent);
+ Qt::DropActions supportedDropActions() const;
+
+ // QFileSystemModel specific API
+ QModelIndex setRootPath(const QString &path);
+ QString rootPath() const;
+ QDir rootDirectory() const;
+
+ void setIconProvider(QFileIconProvider *provider);
+ QFileIconProvider *iconProvider() const;
+
+ void setFilter(QDir::Filters filters);
+ QDir::Filters filter() const;
+
+ void setResolveSymlinks(bool enable);
+ bool resolveSymlinks() const;
+
+ void setReadOnly(bool enable);
+ bool isReadOnly() const;
+
+ void setNameFilterDisables(bool enable);
+ bool nameFilterDisables() const;
+
+ void setNameFilters(const QStringList &filters);
+ QStringList nameFilters() const;
+
+ QString filePath(const QModelIndex &index) const;
+ bool isDir(const QModelIndex &index) const;
+ qint64 size(const QModelIndex &index) const;
+ QString type(const QModelIndex &index) const;
+ QDateTime lastModified(const QModelIndex &index) const;
+
+ QModelIndex mkdir(const QModelIndex &parent, const QString &name);
+ bool rmdir(const QModelIndex &index) const; // ### Qt5: should not be const
+ inline QString fileName(const QModelIndex &index) const;
+ inline QIcon fileIcon(const QModelIndex &index) const;
+ QFile::Permissions permissions(const QModelIndex &index) const;
+ inline QFileInfo fileInfo(const QModelIndex &index) const;
+ bool remove(const QModelIndex &index) const;
+
+protected:
+ QFileSystemModel(QFileSystemModelPrivate &, QObject *parent = 0);
+ void timerEvent(QTimerEvent *event);
+ bool event(QEvent *event);
+
+private:
+ Q_DECLARE_PRIVATE(QFileSystemModel)
+ Q_DISABLE_COPY(QFileSystemModel)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_directoryChanged(const QString &directory, const QStringList &list))
+ Q_PRIVATE_SLOT(d_func(), void _q_performDelayedSort())
+ Q_PRIVATE_SLOT(d_func(), void _q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo> > &))
+ Q_PRIVATE_SLOT(d_func(), void _q_resolvedName(const QString &fileName, const QString &resolvedName))
+
+ friend class QFileDialogPrivate;
+};
+
+inline QString QFileSystemModel::fileName(const QModelIndex &aindex) const
+{ return aindex.data(Qt::DisplayRole).toString(); }
+inline QIcon QFileSystemModel::fileIcon(const QModelIndex &aindex) const
+{ return qvariant_cast<QIcon>(aindex.data(Qt::DecorationRole)); }
+inline QFileInfo QFileSystemModel::fileInfo(const QModelIndex &aindex) const
+{ return QFileInfo(filePath(aindex)); }
+
+#endif // QT_NO_FILESYSTEMMODEL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFILESYSTEMMODEL_H
+
diff --git a/src/widgets/dialogs/qfilesystemmodel_p.h b/src/widgets/dialogs/qfilesystemmodel_p.h
new file mode 100644
index 0000000000..3d5f5b7f00
--- /dev/null
+++ b/src/widgets/dialogs/qfilesystemmodel_p.h
@@ -0,0 +1,337 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMMODEL_P_H
+#define QFILESYSTEMMODEL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfilesystemmodel.h"
+
+#ifndef QT_NO_FILESYSTEMMODEL
+
+#include <private/qabstractitemmodel_p.h>
+#include <qabstractitemmodel.h>
+#include "qfileinfogatherer_p.h"
+#include <qpair.h>
+#include <qdir.h>
+#include <qicon.h>
+#include <qdir.h>
+#include <qicon.h>
+#include <qfileinfo.h>
+#include <qtimer.h>
+#include <qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+class ExtendedInformation;
+class QFileSystemModelPrivate;
+class QFileIconProvider;
+
+class Q_AUTOTEST_EXPORT QFileSystemModelPrivate : public QAbstractItemModelPrivate
+{
+ Q_DECLARE_PUBLIC(QFileSystemModel)
+
+public:
+ class QFileSystemNode
+ {
+ public:
+ QFileSystemNode(const QString &filename = QString(), QFileSystemNode *p = 0)
+ : fileName(filename), populatedChildren(false), isVisible(false), dirtyChildrenIndex(-1), parent(p), info(0) {}
+ ~QFileSystemNode() {
+ QHash<QString, QFileSystemNode*>::const_iterator i = children.constBegin();
+ while (i != children.constEnd()) {
+ delete i.value();
+ ++i;
+ }
+ delete info;
+ info = 0;
+ parent = 0;
+ }
+
+ QString fileName;
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE)
+ QString volumeName;
+#endif
+
+ inline qint64 size() const { if (info && !info->isDir()) return info->size(); return 0; }
+ inline QString type() const { if (info) return info->displayType; return QLatin1String(""); }
+ inline QDateTime lastModified() const { if (info) return info->lastModified(); return QDateTime(); }
+ inline QFile::Permissions permissions() const { if (info) return info->permissions(); return 0; }
+ inline bool isReadable() const { return ((permissions() & QFile::ReadUser) != 0); }
+ inline bool isWritable() const { return ((permissions() & QFile::WriteUser) != 0); }
+ inline bool isExecutable() const { return ((permissions() & QFile::ExeUser) != 0); }
+ inline bool isDir() const {
+ if (info)
+ return info->isDir();
+ if (children.count() > 0)
+ return true;
+ return false;
+ }
+ inline bool isFile() const { if (info) return info->isFile(); return true; }
+ inline bool isSystem() const { if (info) return info->isSystem(); return true; }
+ inline bool isHidden() const { if (info) return info->isHidden(); return false; }
+ inline bool isSymLink() const { if (info) return info->isSymLink(); return false; }
+ inline bool caseSensitive() const { if (info) return info->isCaseSensitive(); return false; }
+ inline QIcon icon() const { if (info) return info->icon; return QIcon(); }
+
+ inline bool operator <(const QFileSystemNode &node) const {
+ if (caseSensitive() || node.caseSensitive())
+ return fileName < node.fileName;
+ return QString::compare(fileName, node.fileName, Qt::CaseInsensitive) < 0;
+ }
+ inline bool operator >(const QString &name) const {
+ if (caseSensitive())
+ return fileName > name;
+ return QString::compare(fileName, name, Qt::CaseInsensitive) > 0;
+ }
+ inline bool operator <(const QString &name) const {
+ if (caseSensitive())
+ return fileName < name;
+ return QString::compare(fileName, name, Qt::CaseInsensitive) < 0;
+ }
+ inline bool operator !=(const QExtendedInformation &fileInfo) const {
+ return !operator==(fileInfo);
+ }
+ bool operator ==(const QString &name) const {
+ if (caseSensitive())
+ return fileName == name;
+ return QString::compare(fileName, name, Qt::CaseInsensitive) == 0;
+ }
+ bool operator ==(const QExtendedInformation &fileInfo) const {
+ return info && (*info == fileInfo);
+ }
+
+ inline bool hasInformation() const { return info != 0; }
+
+ void populate(const QExtendedInformation &fileInfo) {
+ if (!info)
+ info = new QExtendedInformation(fileInfo.fileInfo());
+ (*info) = fileInfo;
+ }
+
+ // children shouldn't normally be accessed directly, use node()
+ inline int visibleLocation(QString childName) {
+ return visibleChildren.indexOf(childName);
+ }
+ void updateIcon(QFileIconProvider *iconProvider, const QString &path) {
+ if (info)
+ info->icon = iconProvider->icon(QFileInfo(path));
+ QHash<QString, QFileSystemNode *>::const_iterator iterator;
+ for(iterator = children.constBegin() ; iterator != children.constEnd() ; ++iterator) {
+ //On windows the root (My computer) has no path so we don't want to add a / for nothing (e.g. /C:/)
+ if (!path.isEmpty()) {
+ if (path.endsWith(QLatin1Char('/')))
+ iterator.value()->updateIcon(iconProvider, path + iterator.value()->fileName);
+ else
+ iterator.value()->updateIcon(iconProvider, path + QLatin1Char('/') + iterator.value()->fileName);
+ } else
+ iterator.value()->updateIcon(iconProvider, iterator.value()->fileName);
+ }
+ }
+
+ void retranslateStrings(QFileIconProvider *iconProvider, const QString &path) {
+ if (info)
+ info->displayType = iconProvider->type(QFileInfo(path));
+ QHash<QString, QFileSystemNode *>::const_iterator iterator;
+ for(iterator = children.constBegin() ; iterator != children.constEnd() ; ++iterator) {
+ //On windows the root (My computer) has no path so we don't want to add a / for nothing (e.g. /C:/)
+ if (!path.isEmpty()) {
+ if (path.endsWith(QLatin1Char('/')))
+ iterator.value()->retranslateStrings(iconProvider, path + iterator.value()->fileName);
+ else
+ iterator.value()->retranslateStrings(iconProvider, path + QLatin1Char('/') + iterator.value()->fileName);
+ } else
+ iterator.value()->retranslateStrings(iconProvider, iterator.value()->fileName);
+ }
+ }
+
+ bool populatedChildren;
+ bool isVisible;
+ QHash<QString,QFileSystemNode *> children;
+ QList<QString> visibleChildren;
+ int dirtyChildrenIndex;
+ QFileSystemNode *parent;
+
+
+ QExtendedInformation *info;
+
+ };
+
+ QFileSystemModelPrivate() :
+ forceSort(true),
+ sortColumn(0),
+ sortOrder(Qt::AscendingOrder),
+ readOnly(true),
+ setRootPath(false),
+ filters(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs),
+ nameFilterDisables(true), // false on windows, true on mac and unix
+ disableRecursiveSort(false)
+ {
+ delayedSortTimer.setSingleShot(true);
+ }
+
+ void init();
+ /*
+ \internal
+
+ Return true if index which is owned by node is hidden by the filter.
+ */
+ inline bool isHiddenByFilter(QFileSystemNode *indexNode, const QModelIndex &index) const
+ {
+ return (indexNode != &root && !index.isValid());
+ }
+ QFileSystemNode *node(const QModelIndex &index) const;
+ QFileSystemNode *node(const QString &path, bool fetch = true) const;
+ inline QModelIndex index(const QString &path) { return index(node(path)); }
+ QModelIndex index(const QFileSystemNode *node) const;
+ bool filtersAcceptsNode(const QFileSystemNode *node) const;
+ bool passNameFilters(const QFileSystemNode *node) const;
+ void removeNode(QFileSystemNode *parentNode, const QString &name);
+ QFileSystemNode* addNode(QFileSystemNode *parentNode, const QString &fileName, const QFileInfo &info);
+ void addVisibleFiles(QFileSystemNode *parentNode, const QStringList &newFiles);
+ void removeVisibleFile(QFileSystemNode *parentNode, int visibleLocation);
+ void sortChildren(int column, const QModelIndex &parent);
+
+ inline int translateVisibleLocation(QFileSystemNode *parent, int row) const {
+ if (sortOrder != Qt::AscendingOrder) {
+ if (parent->dirtyChildrenIndex == -1)
+ return parent->visibleChildren.count() - row - 1;
+
+ if (row < parent->dirtyChildrenIndex)
+ return parent->dirtyChildrenIndex - row - 1;
+ }
+
+ return row;
+ }
+
+ inline static QString myComputer() {
+ // ### TODO We should query the system to find out what the string should be
+ // XP == "My Computer",
+ // Vista == "Computer",
+ // OS X == "Computer" (sometime user generated) "Benjamin's PowerBook G4"
+#ifdef Q_OS_WIN
+ return QFileSystemModel::tr("My Computer");
+#else
+ return QFileSystemModel::tr("Computer");
+#endif
+ }
+
+ inline void delayedSort() {
+ if (!delayedSortTimer.isActive())
+ delayedSortTimer.start(0);
+ }
+
+ static bool caseInsensitiveLessThan(const QString &s1, const QString &s2)
+ {
+ return QString::compare(s1, s2, Qt::CaseInsensitive) < 0;
+ }
+
+ static bool nodeCaseInsensitiveLessThan(const QFileSystemModelPrivate::QFileSystemNode &s1, const QFileSystemModelPrivate::QFileSystemNode &s2)
+ {
+ return QString::compare(s1.fileName, s2.fileName, Qt::CaseInsensitive) < 0;
+ }
+
+ QIcon icon(const QModelIndex &index) const;
+ QString name(const QModelIndex &index) const;
+ QString displayName(const QModelIndex &index) const;
+ QString filePath(const QModelIndex &index) const;
+ QString size(const QModelIndex &index) const;
+ static QString size(qint64 bytes);
+ QString type(const QModelIndex &index) const;
+ QString time(const QModelIndex &index) const;
+
+ void _q_directoryChanged(const QString &directory, const QStringList &list);
+ void _q_performDelayedSort();
+ void _q_fileSystemChanged(const QString &path, const QList<QPair<QString, QFileInfo> > &);
+ void _q_resolvedName(const QString &fileName, const QString &resolvedName);
+
+ static int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs);
+
+ QDir rootDir;
+#ifndef QT_NO_FILESYSTEMWATCHER
+ QFileInfoGatherer fileInfoGatherer;
+#endif
+ QTimer delayedSortTimer;
+ bool forceSort;
+ int sortColumn;
+ Qt::SortOrder sortOrder;
+ bool readOnly;
+ bool setRootPath;
+ QDir::Filters filters;
+ QHash<const QFileSystemNode*, bool> bypassFilters;
+ bool nameFilterDisables;
+ //This flag is an optimization for the QFileDialog
+ //It enable a sort which is not recursive, it means
+ //we sort only what we see.
+ bool disableRecursiveSort;
+#ifndef QT_NO_REGEXP
+ QList<QRegExp> nameFilters;
+#endif
+ // ### Qt 5: resolvedSymLinks goes away
+ QHash<QString, QString> resolvedSymLinks;
+
+ QFileSystemNode root;
+
+ QBasicTimer fetchingTimer;
+ struct Fetching {
+ QString dir;
+ QString file;
+ const QFileSystemNode *node;
+ };
+ QList<Fetching> toFetch;
+
+};
+#endif // QT_NO_FILESYSTEMMODEL
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/widgets/dialogs/qfontdialog.cpp b/src/widgets/dialogs/qfontdialog.cpp
new file mode 100644
index 0000000000..df49fee9bb
--- /dev/null
+++ b/src/widgets/dialogs/qfontdialog.cpp
@@ -0,0 +1,1077 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwindowdefs.h"
+
+#ifndef QT_NO_FONTDIALOG
+
+#include "qfontdialog.h"
+#include "qfontdialog_p.h"
+
+#include <qapplication.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qevent.h>
+#include <qfontdatabase.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qstyle.h>
+#include <qdialogbuttonbox.h>
+#include <qheaderview.h>
+#include <qlistview.h>
+#include <qstringlistmodel.h>
+#include <qvalidator.h>
+#include <private/qdialog_p.h>
+#include <private/qfont_p.h>
+
+#if defined(Q_WS_S60)
+#include <QtWidgets/qdesktopwidget.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFontListView : public QListView
+{
+ Q_OBJECT
+public:
+ QFontListView(QWidget *parent);
+ inline QStringListModel *model() const {
+ return static_cast<QStringListModel *>(QListView::model());
+ }
+ inline void setCurrentItem(int item) {
+ QListView::setCurrentIndex(static_cast<QAbstractListModel*>(model())->index(item));
+ }
+ inline int currentItem() const {
+ return QListView::currentIndex().row();
+ }
+ inline int count() const {
+ return model()->rowCount();
+ }
+ inline QString currentText() const {
+ int row = QListView::currentIndex().row();
+ return row < 0 ? QString() : model()->stringList().at(row);
+ }
+ void currentChanged(const QModelIndex &current, const QModelIndex &previous) {
+ QListView::currentChanged(current, previous);
+ if (current.isValid())
+ emit highlighted(current.row());
+ }
+ QString text(int i) const {
+ return model()->stringList().at(i);
+ }
+signals:
+ void highlighted(int);
+};
+
+QFontListView::QFontListView(QWidget *parent)
+ : QListView(parent)
+{
+ setModel(new QStringListModel(parent));
+ setEditTriggers(NoEditTriggers);
+}
+
+static const Qt::WindowFlags DefaultWindowFlags =
+ Qt::Dialog | Qt::WindowSystemMenuHint;
+
+/*!
+ \class QFontDialog
+ \ingroup standard-dialogs
+
+ \brief The QFontDialog class provides a dialog widget for selecting a font.
+
+ A font dialog is created through one of the static getFont()
+ functions.
+
+ Examples:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 0
+
+ The dialog can also be used to set a widget's font directly:
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 1
+ If the user clicks OK the font they chose will be used for myWidget,
+ and if they click Cancel the original font is used.
+
+ \image plastique-fontdialog.png A font dialog in the Plastique widget style.
+
+ \sa QFont, QFontInfo, QFontMetrics, QColorDialog, QFileDialog, QPrintDialog,
+ {Standard Dialogs Example}
+*/
+
+/*!
+ \since 4.5
+
+ Constructs a standard font dialog.
+
+ Use setCurrentFont() to set the initial font attributes.
+
+ The \a parent parameter is passed to the QDialog constructor.
+
+ \sa getFont()
+*/
+QFontDialog::QFontDialog(QWidget *parent)
+ : QDialog(*new QFontDialogPrivate, parent, DefaultWindowFlags)
+{
+ Q_D(QFontDialog);
+ d->init();
+}
+
+/*!
+ \since 4.5
+
+ Constructs a standard font dialog with the given \a parent and specified
+ \a initial color.
+*/
+QFontDialog::QFontDialog(const QFont &initial, QWidget *parent)
+ : QDialog(*new QFontDialogPrivate, parent, DefaultWindowFlags)
+{
+ Q_D(QFontDialog);
+ d->init();
+ setCurrentFont(initial);
+}
+
+void QFontDialogPrivate::init()
+{
+ Q_Q(QFontDialog);
+
+#ifdef Q_WS_MAC
+ nativeDialogInUse = false;
+ delegate = 0;
+#endif
+
+ q->setSizeGripEnabled(true);
+ q->setWindowTitle(QFontDialog::tr("Select Font"));
+
+ // grid
+ familyEdit = new QLineEdit(q);
+ familyEdit->setReadOnly(true);
+ familyList = new QFontListView(q);
+ familyEdit->setFocusProxy(familyList);
+
+ familyAccel = new QLabel(q);
+#ifndef QT_NO_SHORTCUT
+ familyAccel->setBuddy(familyList);
+#endif
+ familyAccel->setIndent(2);
+
+ styleEdit = new QLineEdit(q);
+ styleEdit->setReadOnly(true);
+ styleList = new QFontListView(q);
+ styleEdit->setFocusProxy(styleList);
+
+ styleAccel = new QLabel(q);
+#ifndef QT_NO_SHORTCUT
+ styleAccel->setBuddy(styleList);
+#endif
+ styleAccel->setIndent(2);
+
+ sizeEdit = new QLineEdit(q);
+ sizeEdit->setFocusPolicy(Qt::ClickFocus);
+ QIntValidator *validator = new QIntValidator(1, 512, q);
+ sizeEdit->setValidator(validator);
+ sizeList = new QFontListView(q);
+
+ sizeAccel = new QLabel(q);
+#ifndef QT_NO_SHORTCUT
+ sizeAccel->setBuddy(sizeEdit);
+#endif
+ sizeAccel->setIndent(2);
+
+ // effects box
+ effects = new QGroupBox(q);
+ QVBoxLayout *vbox = new QVBoxLayout(effects);
+ strikeout = new QCheckBox(effects);
+ vbox->addWidget(strikeout);
+ underline = new QCheckBox(effects);
+ vbox->addWidget(underline);
+
+ sample = new QGroupBox(q);
+ QHBoxLayout *hbox = new QHBoxLayout(sample);
+ sampleEdit = new QLineEdit(sample);
+ sampleEdit->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
+ sampleEdit->setAlignment(Qt::AlignCenter);
+ // Note that the sample text is *not* translated with tr(), as the
+ // characters used depend on the charset encoding.
+ sampleEdit->setText(QLatin1String("AaBbYyZz"));
+ hbox->addWidget(sampleEdit);
+
+ writingSystemCombo = new QComboBox(q);
+
+ writingSystemAccel = new QLabel(q);
+#ifndef QT_NO_SHORTCUT
+ writingSystemAccel->setBuddy(writingSystemCombo);
+#endif
+ writingSystemAccel->setIndent(2);
+
+ size = 0;
+ smoothScalable = false;
+
+ QObject::connect(writingSystemCombo, SIGNAL(activated(int)), q, SLOT(_q_writingSystemHighlighted(int)));
+ QObject::connect(familyList, SIGNAL(highlighted(int)), q, SLOT(_q_familyHighlighted(int)));
+ QObject::connect(styleList, SIGNAL(highlighted(int)), q, SLOT(_q_styleHighlighted(int)));
+ QObject::connect(sizeList, SIGNAL(highlighted(int)), q, SLOT(_q_sizeHighlighted(int)));
+ QObject::connect(sizeEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_sizeChanged(QString)));
+
+ QObject::connect(strikeout, SIGNAL(clicked()), q, SLOT(_q_updateSample()));
+ QObject::connect(underline, SIGNAL(clicked()), q, SLOT(_q_updateSample()));
+
+ for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
+ QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
+ QString writingSystemName = QFontDatabase::writingSystemName(ws);
+ if (writingSystemName.isEmpty())
+ break;
+ writingSystemCombo->addItem(writingSystemName);
+ }
+
+ updateFamilies();
+ if (familyList->count() != 0)
+ familyList->setCurrentItem(0);
+
+ // grid layout
+ QGridLayout *mainGrid = new QGridLayout(q);
+
+ int spacing = mainGrid->spacing();
+ if (spacing >= 0) { // uniform spacing
+ mainGrid->setSpacing(0);
+
+ mainGrid->setColumnMinimumWidth(1, spacing);
+ mainGrid->setColumnMinimumWidth(3, spacing);
+
+ int margin = 0;
+ mainGrid->getContentsMargins(0, 0, 0, &margin);
+
+ mainGrid->setRowMinimumHeight(3, margin);
+ mainGrid->setRowMinimumHeight(6, 2);
+ mainGrid->setRowMinimumHeight(8, margin);
+ }
+
+ mainGrid->addWidget(familyAccel, 0, 0);
+ mainGrid->addWidget(familyEdit, 1, 0);
+ mainGrid->addWidget(familyList, 2, 0);
+
+ mainGrid->addWidget(styleAccel, 0, 2);
+ mainGrid->addWidget(styleEdit, 1, 2);
+ mainGrid->addWidget(styleList, 2, 2);
+
+ mainGrid->addWidget(sizeAccel, 0, 4);
+ mainGrid->addWidget(sizeEdit, 1, 4);
+ mainGrid->addWidget(sizeList, 2, 4);
+
+ mainGrid->setColumnStretch(0, 38);
+ mainGrid->setColumnStretch(2, 24);
+ mainGrid->setColumnStretch(4, 10);
+
+ mainGrid->addWidget(effects, 4, 0);
+
+ mainGrid->addWidget(sample, 4, 2, 4, 3);
+
+ mainGrid->addWidget(writingSystemAccel, 5, 0);
+ mainGrid->addWidget(writingSystemCombo, 7, 0);
+
+ buttonBox = new QDialogButtonBox(q);
+ mainGrid->addWidget(buttonBox, 9, 0, 1, 5);
+
+ QPushButton *button
+ = static_cast<QPushButton *>(buttonBox->addButton(QDialogButtonBox::Ok));
+ QObject::connect(buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
+ button->setDefault(true);
+
+ buttonBox->addButton(QDialogButtonBox::Cancel);
+ QObject::connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
+
+#if defined(Q_WS_WINCE)
+ q->resize(180, 120);
+#elif defined(Q_WS_S60)
+ q->resize(QApplication::desktop()->availableGeometry(QCursor::pos()).size());
+#else
+ q->resize(500, 360);
+#endif // Q_WS_WINCE
+
+ sizeEdit->installEventFilter(q);
+ familyList->installEventFilter(q);
+ styleList->installEventFilter(q);
+ sizeList->installEventFilter(q);
+
+ familyList->setFocus();
+ retranslateStrings();
+}
+
+/*!
+ \internal
+ Destroys the font dialog and frees up its storage.
+*/
+
+QFontDialog::~QFontDialog()
+{
+#ifdef Q_WS_MAC
+ Q_D(QFontDialog);
+ if (d->delegate) {
+ d->closeCocoaFontPanel();
+ return;
+ }
+#endif
+}
+
+/*!
+ Executes a modal font dialog and returns a font.
+
+ If the user clicks \gui OK, the selected font is returned. If the user
+ clicks \gui Cancel, the \a initial font is returned.
+
+ The dialog is constructed with the given \a parent and the options specified
+ in \a options. \a title is shown as the window title of the dialog and \a
+ initial is the initially selected font. If the \a ok parameter is not-null,
+ the value it refers to is set to true if the user clicks \gui OK, and set to
+ false if the user clicks \gui Cancel.
+
+ Examples:
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 2
+
+ The dialog can also be used to set a widget's font directly:
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 3
+ In this example, if the user clicks OK the font they chose will be
+ used, and if they click Cancel the original font is used.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QFontDialog constructors.
+*/
+QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget *parent, const QString &title,
+ FontDialogOptions options)
+{
+ return QFontDialogPrivate::getFont(ok, initial, parent, title, options);
+}
+
+/*!
+ \overload
+ \since 4.5
+*/
+QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget *parent, const QString &title)
+{
+ return QFontDialogPrivate::getFont(ok, initial, parent, title, 0);
+}
+
+/*!
+ \overload
+*/
+QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget *parent)
+{
+ return QFontDialogPrivate::getFont(ok, initial, parent, QString(), 0);
+}
+
+/*!
+ \overload
+
+ Executes a modal font dialog and returns a font.
+
+ If the user clicks \gui OK, the selected font is returned. If the user
+ clicks \gui Cancel, the Qt default font is returned.
+
+ The dialog is constructed with the given \a parent.
+ If the \a ok parameter is not-null, the value it refers to is set
+ to true if the user clicks \gui OK, and false if the user clicks
+ \gui Cancel.
+
+ Example:
+ \snippet doc/src/snippets/code/src_gui_dialogs_qfontdialog.cpp 4
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QFontDialog constructors.
+*/
+QFont QFontDialog::getFont(bool *ok, QWidget *parent)
+{
+ QFont initial;
+ return QFontDialogPrivate::getFont(ok, initial, parent, QString(), 0);
+}
+
+QFont QFontDialogPrivate::getFont(bool *ok, const QFont &initial, QWidget *parent,
+ const QString &title, QFontDialog::FontDialogOptions options)
+{
+ QFontDialog dlg(parent);
+ dlg.setOptions(options);
+ dlg.setCurrentFont(initial);
+ if (!title.isEmpty())
+ dlg.setWindowTitle(title);
+
+ int ret = (dlg.exec() || (options & QFontDialog::NoButtons));
+ if (ok)
+ *ok = !!ret;
+ if (ret) {
+ return dlg.selectedFont();
+ } else {
+ return initial;
+ }
+}
+
+/*!
+ \internal
+ An event filter to make the Up, Down, PageUp and PageDown keys work
+ correctly in the line edits. The source of the event is the object
+ \a o and the event is \a e.
+*/
+
+bool QFontDialog::eventFilter(QObject *o , QEvent *e)
+{
+ Q_D(QFontDialog);
+ if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *k = (QKeyEvent *)e;
+ if (o == d->sizeEdit &&
+ (k->key() == Qt::Key_Up ||
+ k->key() == Qt::Key_Down ||
+ k->key() == Qt::Key_PageUp ||
+ k->key() == Qt::Key_PageDown)) {
+
+ int ci = d->sizeList->currentItem();
+ (void)QApplication::sendEvent(d->sizeList, k);
+
+ if (ci != d->sizeList->currentItem()
+ && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, this))
+ d->sizeEdit->selectAll();
+ return true;
+ } else if ((o == d->familyList || o == d->styleList) &&
+ (k->key() == Qt::Key_Return || k->key() == Qt::Key_Enter)) {
+ k->accept();
+ accept();
+ return true;
+ }
+ } else if (e->type() == QEvent::FocusIn
+ && style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, this)) {
+ if (o == d->familyList)
+ d->familyEdit->selectAll();
+ else if (o == d->styleList)
+ d->styleEdit->selectAll();
+ else if (o == d->sizeList)
+ d->sizeEdit->selectAll();
+ } else if (e->type() == QEvent::MouseButtonPress && o == d->sizeList) {
+ d->sizeEdit->setFocus();
+ }
+ return QDialog::eventFilter(o, e);
+}
+
+/*
+ Updates the contents of the "font family" list box. This
+ function can be reimplemented if you have special requirements.
+*/
+
+void QFontDialogPrivate::updateFamilies()
+{
+ Q_Q(QFontDialog);
+
+ enum match_t { MATCH_NONE = 0, MATCH_LAST_RESORT = 1, MATCH_APP = 2, MATCH_FAMILY = 3 };
+
+ QStringList familyNames = fdb.families(writingSystem);
+
+ familyList->model()->setStringList(familyNames);
+
+ QString foundryName1, familyName1, foundryName2, familyName2;
+ int bestFamilyMatch = -1;
+ match_t bestFamilyType = MATCH_NONE;
+
+ QFont f;
+
+ // ##### do the right thing for a list of family names in the font.
+ QFontDatabase::parseFontName(family, foundryName1, familyName1);
+
+ QStringList::const_iterator it = familyNames.constBegin();
+ int i = 0;
+ for(; it != familyNames.constEnd(); ++it, ++i) {
+ QFontDatabase::parseFontName(*it, foundryName2, familyName2);
+
+ //try to match...
+ if (familyName1 == familyName2) {
+ bestFamilyType = MATCH_FAMILY;
+ if (foundryName1 == foundryName2) {
+ bestFamilyMatch = i;
+ break;
+ }
+ if (bestFamilyMatch < MATCH_FAMILY)
+ bestFamilyMatch = i;
+ }
+
+ //and try some fall backs
+ match_t type = MATCH_NONE;
+ if (bestFamilyType <= MATCH_NONE && familyName2 == f.lastResortFamily())
+ type = MATCH_LAST_RESORT;
+ if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.family())
+ type = MATCH_APP;
+ // ### add fallback for writingSystem
+ if (type != MATCH_NONE) {
+ bestFamilyType = type;
+ bestFamilyMatch = i;
+ }
+ }
+
+ if (i != -1 && bestFamilyType != MATCH_NONE)
+ familyList->setCurrentItem(bestFamilyMatch);
+ else
+ familyList->setCurrentItem(0);
+ familyEdit->setText(familyList->currentText());
+ if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+ && familyList->hasFocus())
+ familyEdit->selectAll();
+
+ updateStyles();
+}
+
+/*
+ Updates the contents of the "font style" list box. This
+ function can be reimplemented if you have special requirements.
+*/
+void QFontDialogPrivate::updateStyles()
+{
+ Q_Q(QFontDialog);
+ QStringList styles = fdb.styles(familyList->currentText());
+ styleList->model()->setStringList(styles);
+
+ if (styles.isEmpty()) {
+ styleEdit->clear();
+ smoothScalable = false;
+ } else {
+ if (!style.isEmpty()) {
+ bool found = false;
+ bool first = true;
+ QString cstyle = style;
+
+ redo:
+ for (int i = 0; i < (int)styleList->count(); i++) {
+ if (cstyle == styleList->text(i)) {
+ styleList->setCurrentItem(i);
+ found = true;
+ break;
+ }
+ }
+ if (!found && first) {
+ if (cstyle.contains(QLatin1String("Italic"))) {
+ cstyle.replace(QLatin1String("Italic"), QLatin1String("Oblique"));
+ first = false;
+ goto redo;
+ } else if (cstyle.contains(QLatin1String("Oblique"))) {
+ cstyle.replace(QLatin1String("Oblique"), QLatin1String("Italic"));
+ first = false;
+ goto redo;
+ }
+ }
+ if (!found)
+ styleList->setCurrentItem(0);
+ } else {
+ styleList->setCurrentItem(0);
+ }
+
+ styleEdit->setText(styleList->currentText());
+ if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+ && styleList->hasFocus())
+ styleEdit->selectAll();
+
+ smoothScalable = fdb.isSmoothlyScalable(familyList->currentText(), styleList->currentText());
+ }
+
+ updateSizes();
+}
+
+/*!
+ \internal
+ Updates the contents of the "font size" list box. This
+ function can be reimplemented if you have special requirements.
+*/
+
+void QFontDialogPrivate::updateSizes()
+{
+ Q_Q(QFontDialog);
+
+ if (!familyList->currentText().isEmpty()) {
+ QList<int> sizes = fdb.pointSizes(familyList->currentText(), styleList->currentText());
+
+ int i = 0;
+ int current = -1;
+ QStringList str_sizes;
+ for(QList<int>::const_iterator it = sizes.constBegin(); it != sizes.constEnd(); ++it) {
+ str_sizes.append(QString::number(*it));
+ if (current == -1 && *it >= size)
+ current = i;
+ ++i;
+ }
+ sizeList->model()->setStringList(str_sizes);
+ if (current == -1) {
+ // we request a size bigger than the ones in the list, select the biggest one
+ current = sizeList->count() - 1;
+ }
+ sizeList->setCurrentItem(current);
+
+ sizeEdit->blockSignals(true);
+ sizeEdit->setText((smoothScalable ? QString::number(size) : sizeList->currentText()));
+ if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+ && sizeList->hasFocus())
+ sizeEdit->selectAll();
+ sizeEdit->blockSignals(false);
+ } else {
+ sizeEdit->clear();
+ }
+
+ _q_updateSample();
+}
+
+void QFontDialogPrivate::_q_updateSample()
+{
+ // compute new font
+ int pSize = sizeEdit->text().toInt();
+ QFont newFont(fdb.font(familyList->currentText(), style, pSize));
+ newFont.setStrikeOut(strikeout->isChecked());
+ newFont.setUnderline(underline->isChecked());
+
+ if (familyList->currentText().isEmpty())
+ sampleEdit->clear();
+
+ updateSampleFont(newFont);
+}
+
+void QFontDialogPrivate::updateSampleFont(const QFont &newFont)
+{
+ Q_Q(QFontDialog);
+ if (newFont != sampleEdit->font()) {
+ sampleEdit->setFont(newFont);
+ emit q->currentFontChanged(newFont);
+ }
+}
+
+/*!
+ \internal
+*/
+void QFontDialogPrivate::_q_writingSystemHighlighted(int index)
+{
+ writingSystem = QFontDatabase::WritingSystem(index);
+ sampleEdit->setText(fdb.writingSystemSample(writingSystem));
+ updateFamilies();
+}
+
+/*!
+ \internal
+*/
+void QFontDialogPrivate::_q_familyHighlighted(int i)
+{
+ Q_Q(QFontDialog);
+ family = familyList->text(i);
+ familyEdit->setText(family);
+ if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+ && familyList->hasFocus())
+ familyEdit->selectAll();
+
+ updateStyles();
+}
+
+
+/*!
+ \internal
+*/
+
+void QFontDialogPrivate::_q_styleHighlighted(int index)
+{
+ Q_Q(QFontDialog);
+ QString s = styleList->text(index);
+ styleEdit->setText(s);
+ if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+ && styleList->hasFocus())
+ styleEdit->selectAll();
+
+ style = s;
+
+ updateSizes();
+}
+
+
+/*!
+ \internal
+*/
+
+void QFontDialogPrivate::_q_sizeHighlighted(int index)
+{
+ Q_Q(QFontDialog);
+ QString s = sizeList->text(index);
+ sizeEdit->setText(s);
+ if (q->style()->styleHint(QStyle::SH_FontDialog_SelectAssociatedText, 0, q)
+ && sizeEdit->hasFocus())
+ sizeEdit->selectAll();
+
+ size = s.toInt();
+ _q_updateSample();
+}
+
+/*!
+ \internal
+ This slot is called if the user changes the font size.
+ The size is passed in the \a s argument as a \e string.
+*/
+
+void QFontDialogPrivate::_q_sizeChanged(const QString &s)
+{
+ // no need to check if the conversion is valid, since we have an QIntValidator in the size edit
+ int size = s.toInt();
+ if (this->size == size)
+ return;
+
+ this->size = size;
+ if (sizeList->count() != 0) {
+ int i;
+ for (i = 0; i < sizeList->count() - 1; i++) {
+ if (sizeList->text(i).toInt() >= this->size)
+ break;
+ }
+ sizeList->blockSignals(true);
+ sizeList->setCurrentItem(i);
+ sizeList->blockSignals(false);
+ }
+ _q_updateSample();
+}
+
+void QFontDialogPrivate::retranslateStrings()
+{
+ familyAccel->setText(QFontDialog::tr("&Font"));
+ styleAccel->setText(QFontDialog::tr("Font st&yle"));
+ sizeAccel->setText(QFontDialog::tr("&Size"));
+#ifndef Q_WS_S60
+ // Removed the title due to lack of screen estate in small S60 screen.
+ // The effects are descriptive without a title (strikeout, underline).
+ effects->setTitle(QFontDialog::tr("Effects"));
+#endif
+ strikeout->setText(QFontDialog::tr("Stri&keout"));
+ underline->setText(QFontDialog::tr("&Underline"));
+ sample->setTitle(QFontDialog::tr("Sample"));
+ writingSystemAccel->setText(QFontDialog::tr("Wr&iting System"));
+}
+
+/*!
+ \reimp
+*/
+void QFontDialog::changeEvent(QEvent *e)
+{
+ Q_D(QFontDialog);
+ if (e->type() == QEvent::LanguageChange) {
+ d->retranslateStrings();
+ }
+ QDialog::changeEvent(e);
+}
+
+/*!
+ \since 4.5
+
+ \property QFontDialog::currentFont
+ \brief the current font of the dialog.
+*/
+
+/*!
+ \since 4.5
+
+ Sets the font highlighted in the QFontDialog to the given \a font.
+
+ \sa selectedFont()
+*/
+void QFontDialog::setCurrentFont(const QFont &font)
+{
+ Q_D(QFontDialog);
+ d->family = font.family();
+ d->style = d->fdb.styleString(font);
+ d->size = font.pointSize();
+ if (d->size == -1) {
+ QFontInfo fi(font);
+ d->size = fi.pointSize();
+ }
+ d->strikeout->setChecked(font.strikeOut());
+ d->underline->setChecked(font.underline());
+ d->updateFamilies();
+
+#ifdef Q_WS_MAC
+ if (d->delegate)
+ QFontDialogPrivate::setFont(d->delegate, font);
+#endif
+}
+
+/*!
+ \since 4.5
+
+ Returns the current font.
+
+ \sa selectedFont()
+*/
+QFont QFontDialog::currentFont() const
+{
+ Q_D(const QFontDialog);
+ return d->sampleEdit->font();
+}
+
+/*!
+ Returns the font that the user selected by clicking the \gui{OK}
+ or equivalent button.
+
+ \note This font is not always the same as the font held by the
+ \l currentFont property since the user can choose different fonts
+ before finally selecting the one to use.
+*/
+QFont QFontDialog::selectedFont() const
+{
+ Q_D(const QFontDialog);
+ return d->selectedFont;
+}
+
+/*!
+ \enum QFontDialog::FontDialogOption
+ \since 4.5
+
+ This enum specifies various options that affect the look and feel
+ of a font dialog.
+
+ \value NoButtons Don't display \gui{OK} and \gui{Cancel} buttons. (Useful for "live dialogs".)
+ \value DontUseNativeDialog Use Qt's standard font dialog on the Mac instead of Apple's
+ native font panel. (Currently, the native dialog is never used,
+ but this is likely to change in future Qt releases.)
+
+ \sa options, setOption(), testOption()
+*/
+
+/*!
+ Sets the given \a option to be enabled if \a on is true;
+ otherwise, clears the given \a option.
+
+ \sa options, testOption()
+*/
+void QFontDialog::setOption(FontDialogOption option, bool on)
+{
+ Q_D(QFontDialog);
+ if (!(d->opts & option) != !on)
+ setOptions(d->opts ^ option);
+}
+
+/*!
+ Returns true if the given \a option is enabled; otherwise, returns
+ false.
+
+ \sa options, setOption()
+*/
+bool QFontDialog::testOption(FontDialogOption option) const
+{
+ Q_D(const QFontDialog);
+ return (d->opts & option) != 0;
+}
+
+/*!
+ \property QFontDialog::options
+ \brief the various options that affect the look and feel of the dialog
+ \since 4.5
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the
+ dialog is visible is not guaranteed to have an immediate effect on the
+ dialog (depending on the option and on the platform).
+
+ \sa setOption(), testOption()
+*/
+void QFontDialog::setOptions(FontDialogOptions options)
+{
+ Q_D(QFontDialog);
+
+ FontDialogOptions changed = (options ^ d->opts);
+ if (!changed)
+ return;
+
+ d->opts = options;
+ d->buttonBox->setVisible(!(options & NoButtons));
+}
+
+QFontDialog::FontDialogOptions QFontDialog::options() const
+{
+ Q_D(const QFontDialog);
+ return d->opts;
+}
+
+#ifdef Q_WS_MAC
+// can only have one Cocoa font panel active
+bool QFontDialogPrivate::sharedFontPanelAvailable = true;
+#endif
+
+/*!
+ \since 4.5
+ \overload
+
+ Opens the dialog and connects its fontSelected() signal to the slot specified
+ by \a receiver and \a member.
+
+ The signal will be disconnected from the slot when the dialog is closed.
+*/
+void QFontDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QFontDialog);
+ connect(this, SIGNAL(fontSelected(QFont)), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+/*!
+ \since 4.5
+
+ \fn void QFontDialog::currentFontChanged(const QFont &font)
+
+ This signal is emitted when the current font is changed. The new font is
+ specified in \a font.
+
+ The signal is emitted while a user is selecting a font. Ultimately, the
+ chosen font may differ from the font currently selected.
+
+ \sa currentFont, fontSelected(), selectedFont()
+*/
+
+/*!
+ \since 4.5
+
+ \fn void QFontDialog::fontSelected(const QFont &font)
+
+ This signal is emitted when a font has been selected. The selected font is
+ specified in \a font.
+
+ The signal is only emitted when a user has chosen the final font to be
+ used. It is not emitted while the user is changing the current font in the
+ font dialog.
+
+ \sa selectedFont(), currentFontChanged(), currentFont
+*/
+
+/*!
+ \reimp
+*/
+void QFontDialog::setVisible(bool visible)
+{
+ if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) != visible)
+ return;
+#ifdef Q_WS_MAC
+ Q_D(QFontDialog);
+ if (d->canBeNativeDialog()){
+ if (d->setVisible_sys(visible)){
+ d->nativeDialogInUse = true;
+ // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
+ // updates the state correctly, but skips showing the non-native version:
+ setAttribute(Qt::WA_DontShowOnScreen, true);
+ } else {
+ d->nativeDialogInUse = false;
+ setAttribute(Qt::WA_DontShowOnScreen, false);
+ }
+ }
+#endif // Q_WS_MAC
+ QDialog::setVisible(visible);
+}
+
+/*!
+ Closes the dialog and sets its result code to \a result. If this dialog
+ is shown with exec(), done() causes the local event loop to finish,
+ and exec() to return \a result.
+
+ \sa QDialog::done()
+*/
+void QFontDialog::done(int result)
+{
+ Q_D(QFontDialog);
+ QDialog::done(result);
+ if (result == Accepted) {
+ // We check if this is the same font we had before, if so we emit currentFontChanged
+ QFont selectedFont = currentFont();
+ if(selectedFont != d->selectedFont)
+ emit(currentFontChanged(selectedFont));
+ d->selectedFont = selectedFont;
+ emit fontSelected(d->selectedFont);
+ } else
+ d->selectedFont = QFont();
+ if (d->receiverToDisconnectOnClose) {
+ disconnect(this, SIGNAL(fontSelected(QFont)),
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+}
+
+#ifdef Q_WS_MAC
+bool QFontDialogPrivate::canBeNativeDialog()
+{
+ Q_Q(QFontDialog);
+ if (nativeDialogInUse)
+ return true;
+ if (q->testAttribute(Qt::WA_DontShowOnScreen))
+ return false;
+ if (opts & QFontDialog::DontUseNativeDialog)
+ return false;
+
+ QLatin1String staticName(QFontDialog::staticMetaObject.className());
+ QLatin1String dynamicName(q->metaObject()->className());
+ return (staticName == dynamicName);
+}
+#endif // Q_WS_MAC
+
+/*!
+ \fn QFont QFontDialog::getFont(bool *ok, const QFont &initial, QWidget* parent, const char* name)
+ \since 4.5
+
+ Call getFont(\a ok, \a initial, \a parent) instead.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QFontDialog constructors.
+
+ The \a name parameter is ignored.
+*/
+
+/*!
+ \fn QFont QFontDialog::getFont(bool *ok, QWidget* parent, const char* name)
+
+ Call getFont(\a ok, \a parent) instead.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QFontDialog constructors.
+
+ The \a name parameter is ignored.
+*/
+
+QT_END_NAMESPACE
+
+#include "qfontdialog.moc"
+#include "moc_qfontdialog.cpp"
+
+#endif // QT_NO_FONTDIALOG
diff --git a/src/widgets/dialogs/qfontdialog.h b/src/widgets/dialogs/qfontdialog.h
new file mode 100644
index 0000000000..03ef2b7e81
--- /dev/null
+++ b/src/widgets/dialogs/qfontdialog.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFONTDIALOG_H
+#define QFONTDIALOG_H
+
+#include <QtGui/qwindowdefs.h>
+#include <QtWidgets/qdialog.h>
+#include <QtGui/qfont.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_FONTDIALOG
+
+class QFontDialogPrivate;
+
+class Q_WIDGETS_EXPORT QFontDialog : public QDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QFontDialog)
+ Q_ENUMS(FontDialogOption)
+ Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont NOTIFY currentFontChanged)
+ Q_PROPERTY(FontDialogOptions options READ options WRITE setOptions)
+
+public:
+ enum FontDialogOption {
+ NoButtons = 0x00000001,
+ DontUseNativeDialog = 0x00000002
+ };
+
+ Q_DECLARE_FLAGS(FontDialogOptions, FontDialogOption)
+
+ explicit QFontDialog(QWidget *parent = 0);
+ explicit QFontDialog(const QFont &initial, QWidget *parent = 0);
+ ~QFontDialog();
+
+ void setCurrentFont(const QFont &font);
+ QFont currentFont() const;
+
+ QFont selectedFont() const;
+
+ void setOption(FontDialogOption option, bool on = true);
+ bool testOption(FontDialogOption option) const;
+ void setOptions(FontDialogOptions options);
+ FontDialogOptions options() const;
+
+#ifdef Q_NO_USING_KEYWORD
+#ifndef Q_QDOC
+ void open() { QDialog::open(); }
+#endif
+#else
+ using QDialog::open;
+#endif
+ void open(QObject *receiver, const char *member);
+
+ void setVisible(bool visible);
+
+ // ### Qt 5: merge overloads
+ static QFont getFont(bool *ok, const QFont &initial, QWidget *parent, const QString &title,
+ FontDialogOptions options);
+ static QFont getFont(bool *ok, const QFont &initial, QWidget *parent, const QString &title);
+ static QFont getFont(bool *ok, const QFont &initial, QWidget *parent = 0);
+ static QFont getFont(bool *ok, QWidget *parent = 0);
+
+#ifdef QT3_SUPPORT
+ static QFont getFont(bool *ok, const QFont &initial, QWidget *parent, const char *name)
+ { Q_UNUSED(name); return getFont(ok, initial, parent); }
+ static QFont getFont(bool *ok, QWidget *parent, const char *name)
+ { Q_UNUSED(name); return getFont(ok, parent); }
+#endif
+
+Q_SIGNALS:
+ void currentFontChanged(const QFont &font);
+ void fontSelected(const QFont &font);
+
+protected:
+ void changeEvent(QEvent *event);
+ void done(int result);
+
+private:
+ // ### Qt 5: make protected
+ bool eventFilter(QObject *object, QEvent *event);
+
+ Q_DISABLE_COPY(QFontDialog)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_sizeChanged(const QString &))
+ Q_PRIVATE_SLOT(d_func(), void _q_familyHighlighted(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_writingSystemHighlighted(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_styleHighlighted(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_sizeHighlighted(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_updateSample())
+#if defined(Q_WS_MAC)
+ Q_PRIVATE_SLOT(d_func(), void _q_macRunNativeAppModalPanel())
+#endif
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QFontDialog::FontDialogOptions)
+
+#endif // QT_NO_FONTDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QFONTDIALOG_H
diff --git a/src/widgets/dialogs/qfontdialog_mac.mm b/src/widgets/dialogs/qfontdialog_mac.mm
new file mode 100644
index 0000000000..088aa52085
--- /dev/null
+++ b/src/widgets/dialogs/qfontdialog_mac.mm
@@ -0,0 +1,699 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfontdialog_p.h"
+#if !defined(QT_NO_FONTDIALOG) && defined(Q_WS_MAC)
+#include <qapplication.h>
+#include <qdialogbuttonbox.h>
+#include <qlineedit.h>
+#include <private/qapplication_p.h>
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qt_cocoa_helpers_mac_p.h>
+#include <private/qt_mac_p.h>
+#include <qabstracteventdispatcher.h>
+#include <qdebug.h>
+#include <private/qfontengine_coretext_p.h>
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+#if !CGFLOAT_DEFINED
+typedef float CGFloat; // Should only not be defined on 32-bit platforms
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern void macStartInterceptNSPanelCtor();
+extern void macStopInterceptNSPanelCtor();
+extern NSButton *macCreateButton(const char *text, NSView *superview);
+extern bool qt_mac_is_macsheet(const QWidget *w); // qwidget_mac.mm
+
+QT_END_NAMESPACE
+QT_USE_NAMESPACE
+
+// should a priori be kept in sync with qcolordialog_mac.mm
+const CGFloat ButtonMinWidth = 78.0;
+const CGFloat ButtonMinHeight = 32.0;
+const CGFloat ButtonSpacing = 0.0;
+const CGFloat ButtonTopMargin = 0.0;
+const CGFloat ButtonBottomMargin = 7.0;
+const CGFloat ButtonSideMargin = 9.0;
+
+// looks better with some margins
+const CGFloat DialogTopMargin = 7.0;
+const CGFloat DialogSideMargin = 9.0;
+
+const int StyleMask = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask;
+
+@class QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate);
+
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
+
+@protocol NSWindowDelegate <NSObject>
+- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize;
+@end
+
+#endif
+
+@interface QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) : NSObject <NSWindowDelegate> {
+ NSFontPanel *mFontPanel;
+ NSView *mStolenContentView;
+ NSButton *mOkButton;
+ NSButton *mCancelButton;
+ QFontDialogPrivate *mPriv;
+ QFont *mQtFont;
+ BOOL mPanelHackedWithButtons;
+ CGFloat mDialogExtraWidth;
+ CGFloat mDialogExtraHeight;
+ int mReturnCode;
+ BOOL mAppModal;
+}
+- (id)initWithFontPanel:(NSFontPanel *)panel
+ stolenContentView:(NSView *)stolenContentView
+ okButton:(NSButton *)okButton
+ cancelButton:(NSButton *)cancelButton
+ priv:(QFontDialogPrivate *)priv
+ extraWidth:(CGFloat)extraWidth
+ extraHeight:(CGFloat)extraHeight;
+- (void)showModelessPanel;
+- (void)showWindowModalSheet:(QWidget *)docWidget;
+- (void)runApplicationModalPanel;
+- (BOOL)isAppModal;
+- (void)changeFont:(id)sender;
+- (void)changeAttributes:(id)sender;
+- (BOOL)windowShouldClose:(id)window;
+- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize;
+- (void)relayout;
+- (void)relayoutToContentSize:(NSSize)frameSize;
+- (void)onOkClicked;
+- (void)onCancelClicked;
+- (NSFontPanel *)fontPanel;
+- (NSWindow *)actualPanel;
+- (NSSize)dialogExtraSize;
+- (void)setQtFont:(const QFont &)newFont;
+- (QFont)qtFont;
+- (void)finishOffWithCode:(NSInteger)result;
+- (void)cleanUpAfterMyself;
+- (void)setSubwindowStacking;
+@end
+
+static QFont qfontForCocoaFont(NSFont *cocoaFont, const QFont &resolveFont)
+{
+ QFont newFont;
+ if (cocoaFont) {
+ int pSize = qRound([cocoaFont pointSize]);
+ QString family(qt_mac_NSStringToQString([cocoaFont familyName]));
+ QString typeface(qt_mac_NSStringToQString([cocoaFont fontName]));
+
+ int hyphenPos = typeface.indexOf(QLatin1Char('-'));
+ if (hyphenPos != -1) {
+ typeface.remove(0, hyphenPos + 1);
+ } else {
+ typeface = QLatin1String("Normal");
+ }
+
+ newFont = QFontDatabase().font(family, typeface, pSize);
+ newFont.setUnderline(resolveFont.underline());
+ newFont.setStrikeOut(resolveFont.strikeOut());
+
+ }
+ return newFont;
+}
+
+@implementation QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate)
+- (id)initWithFontPanel:(NSFontPanel *)panel
+ stolenContentView:(NSView *)stolenContentView
+ okButton:(NSButton *)okButton
+ cancelButton:(NSButton *)cancelButton
+ priv:(QFontDialogPrivate *)priv
+ extraWidth:(CGFloat)extraWidth
+ extraHeight:(CGFloat)extraHeight
+{
+ self = [super init];
+ mFontPanel = panel;
+ mStolenContentView = stolenContentView;
+ mOkButton = okButton;
+ mCancelButton = cancelButton;
+ mPriv = priv;
+ mPanelHackedWithButtons = (okButton != 0);
+ mDialogExtraWidth = extraWidth;
+ mDialogExtraHeight = extraHeight;
+ mReturnCode = -1;
+ mAppModal = false;
+
+ if (mPanelHackedWithButtons) {
+ [self relayout];
+
+ [okButton setAction:@selector(onOkClicked)];
+ [okButton setTarget:self];
+
+ [cancelButton setAction:@selector(onCancelClicked)];
+ [cancelButton setTarget:self];
+ }
+
+ mQtFont = new QFont();
+ return self;
+}
+
+- (void)setSubwindowStacking
+{
+#ifdef QT_MAC_USE_COCOA
+ // Stack the native dialog in front of its parent, if any:
+ QFontDialog *q = mPriv->fontDialog();
+ if (!qt_mac_is_macsheet(q)) {
+ if (QWidget *parent = q->parentWidget()) {
+ if (parent->isWindow()) {
+ [qt_mac_window_for(parent)
+ addChildWindow:[mStolenContentView window] ordered:NSWindowAbove];
+ }
+ }
+ }
+#endif
+}
+
+- (void)dealloc
+{
+ delete mQtFont;
+ [super dealloc];
+}
+
+- (void)showModelessPanel
+{
+ mAppModal = false;
+ NSWindow *ourPanel = [mStolenContentView window];
+ [ourPanel makeKeyAndOrderFront:self];
+}
+
+- (void)runApplicationModalPanel
+{
+ QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
+ mAppModal = true;
+ NSWindow *ourPanel = [mStolenContentView window];
+ [ourPanel setReleasedWhenClosed:NO];
+ [NSApp runModalForWindow:ourPanel];
+ QAbstractEventDispatcher::instance()->interrupt();
+
+ if (mReturnCode == NSOKButton)
+ mPriv->fontDialog()->accept();
+ else
+ mPriv->fontDialog()->reject();
+}
+
+- (BOOL)isAppModal
+{
+ return mAppModal;
+}
+
+- (void)showWindowModalSheet:(QWidget *)docWidget
+{
+#ifdef QT_MAC_USE_COCOA
+ NSWindow *window = qt_mac_window_for(docWidget);
+#else
+ WindowRef hiwindowRef = qt_mac_window_for(docWidget);
+ NSWindow *window = [[NSWindow alloc] initWithWindowRef:hiwindowRef];
+ CFRetain(hiwindowRef);
+#endif
+
+ mAppModal = false;
+ NSWindow *ourPanel = [mStolenContentView window];
+ [NSApp beginSheet:ourPanel
+ modalForWindow:window
+ modalDelegate:0
+ didEndSelector:0
+ contextInfo:0 ];
+
+#ifndef QT_MAC_USE_COCOA
+ CFRelease(hiwindowRef);
+#endif
+}
+
+- (void)changeFont:(id)sender
+{
+ NSFont *dummyFont = [NSFont userFontOfSize:12.0];
+ [self setQtFont:qfontForCocoaFont([sender convertFont:dummyFont], *mQtFont)];
+ if (mPriv)
+ mPriv->updateSampleFont(*mQtFont);
+}
+
+- (void)changeAttributes:(id)sender
+{
+ NSDictionary *dummyAttribs = [NSDictionary dictionary];
+ NSDictionary *attribs = [sender convertAttributes:dummyAttribs];
+
+#ifdef QT_MAC_USE_COCOA
+ for (id key in attribs) {
+#else
+ NSEnumerator *enumerator = [attribs keyEnumerator];
+ id key;
+ while((key = [enumerator nextObject])) {
+#endif
+ NSNumber *number = static_cast<NSNumber *>([attribs objectForKey:key]);
+ if ([key isEqual:NSUnderlineStyleAttributeName]) {
+ mQtFont->setUnderline([number intValue] != NSUnderlineStyleNone);
+ } else if ([key isEqual:NSStrikethroughStyleAttributeName]) {
+ mQtFont->setStrikeOut([number intValue] != NSUnderlineStyleNone);
+ }
+ }
+
+ if (mPriv)
+ mPriv->updateSampleFont(*mQtFont);
+}
+
+- (BOOL)windowShouldClose:(id)window
+{
+ Q_UNUSED(window);
+ if (mPanelHackedWithButtons) {
+ [self onCancelClicked];
+ } else {
+ [self finishOffWithCode:NSCancelButton];
+ }
+ return true;
+}
+
+- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize
+{
+ if (mFontPanel == window) {
+ proposedFrameSize = [static_cast<id <NSWindowDelegate> >(mFontPanel) windowWillResize:mFontPanel toSize:proposedFrameSize];
+ } else {
+ /*
+ Ugly hack: NSFontPanel rearranges the layout of its main
+ component in windowWillResize:toSize:. So we temporarily
+ restore the stolen content view to its rightful owner,
+ call windowWillResize:toSize:, and steal the content view
+ again.
+ */
+ [mStolenContentView removeFromSuperview];
+ [mFontPanel setContentView:mStolenContentView];
+ NSSize extraSize = [self dialogExtraSize];
+ proposedFrameSize.width -= extraSize.width;
+ proposedFrameSize.height -= extraSize.height;
+ proposedFrameSize = [static_cast<id <NSWindowDelegate> >(mFontPanel) windowWillResize:mFontPanel toSize:proposedFrameSize];
+ NSRect frameRect = { { 0.0, 0.0 }, proposedFrameSize };
+ [mFontPanel setFrame:frameRect display:NO];
+ [mFontPanel setContentView:0];
+ [[window contentView] addSubview:mStolenContentView];
+ proposedFrameSize.width += extraSize.width;
+ proposedFrameSize.height += extraSize.height;
+ }
+ if (mPanelHackedWithButtons) {
+ NSRect frameRect = { { 0.0, 0.0 }, proposedFrameSize };
+ NSRect contentRect = [NSWindow contentRectForFrameRect:frameRect styleMask:[window styleMask]];
+ [self relayoutToContentSize:contentRect.size];
+ }
+ return proposedFrameSize;
+}
+
+- (void)relayout
+{
+ [self relayoutToContentSize:[[mStolenContentView superview] frame].size];
+}
+
+- (void)relayoutToContentSize:(NSSize)frameSize
+{
+ Q_ASSERT(mPanelHackedWithButtons);
+
+ [mOkButton sizeToFit];
+ NSSize okSizeHint = [mOkButton frame].size;
+
+ [mCancelButton sizeToFit];
+ NSSize cancelSizeHint = [mCancelButton frame].size;
+
+ const CGFloat ButtonWidth = qMin(qMax(ButtonMinWidth,
+ qMax(okSizeHint.width, cancelSizeHint.width)),
+ CGFloat((frameSize.width - 2.0 * ButtonSideMargin - ButtonSpacing) * 0.5));
+ const CGFloat ButtonHeight = qMax(ButtonMinHeight,
+ qMax(okSizeHint.height, cancelSizeHint.height));
+
+ const CGFloat X = DialogSideMargin;
+ const CGFloat Y = ButtonBottomMargin + ButtonHeight + ButtonTopMargin;
+
+ NSRect okRect = { { frameSize.width - ButtonSideMargin - ButtonWidth,
+ ButtonBottomMargin },
+ { ButtonWidth, ButtonHeight } };
+ [mOkButton setFrame:okRect];
+ [mOkButton setNeedsDisplay:YES];
+
+ NSRect cancelRect = { { okRect.origin.x - ButtonSpacing - ButtonWidth,
+ ButtonBottomMargin },
+ { ButtonWidth, ButtonHeight } };
+ [mCancelButton setFrame:cancelRect];
+ [mCancelButton setNeedsDisplay:YES];
+
+ NSRect stolenCVRect = { { X, Y },
+ { frameSize.width - X - X, frameSize.height - Y - DialogTopMargin } };
+ [mStolenContentView setFrame:stolenCVRect];
+ [mStolenContentView setNeedsDisplay:YES];
+
+ [[mStolenContentView superview] setNeedsDisplay:YES];
+}
+
+- (void)onOkClicked
+{
+ Q_ASSERT(mPanelHackedWithButtons);
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ [self setQtFont:qfontForCocoaFont([fontManager convertFont:[fontManager selectedFont]],
+ *mQtFont)];
+ [self finishOffWithCode:NSOKButton];
+}
+
+- (void)onCancelClicked
+{
+ Q_ASSERT(mPanelHackedWithButtons);
+ [self finishOffWithCode:NSCancelButton];
+}
+
+- (NSFontPanel *)fontPanel
+{
+ return mFontPanel;
+}
+
+- (NSWindow *)actualPanel
+{
+ return [mStolenContentView window];
+}
+
+- (NSSize)dialogExtraSize
+{
+ // this must be recomputed each time, because sometimes the
+ // NSFontPanel has the NSDocModalWindowMask flag set, and sometimes
+ // not -- which affects the frame rect vs. content rect measurements
+
+ // take the different frame rectangles into account for dialogExtra{Width,Height}
+ NSRect someRect = { { 0.0, 0.0 }, { 100000.0, 100000.0 } };
+ NSRect sharedFontPanelContentRect = [mFontPanel contentRectForFrameRect:someRect];
+ NSRect ourPanelContentRect = [NSWindow contentRectForFrameRect:someRect styleMask:StyleMask];
+
+ NSSize result = { mDialogExtraWidth, mDialogExtraHeight };
+ result.width -= ourPanelContentRect.size.width - sharedFontPanelContentRect.size.width;
+ result.height -= ourPanelContentRect.size.height - sharedFontPanelContentRect.size.height;
+ return result;
+}
+
+- (void)setQtFont:(const QFont &)newFont
+{
+ delete mQtFont;
+ mQtFont = new QFont(newFont);
+}
+
+- (QFont)qtFont
+{
+ return *mQtFont;
+}
+
+- (void)finishOffWithCode:(NSInteger)code
+{
+#ifdef QT_MAC_USE_COCOA
+ QFontDialog *q = mPriv->fontDialog();
+ if (QWidget *parent = q->parentWidget()) {
+ if (parent->isWindow()) {
+ [qt_mac_window_for(parent) removeChildWindow:[mStolenContentView window]];
+ }
+ }
+#endif
+
+ if(code == NSOKButton)
+ mPriv->sampleEdit->setFont([self qtFont]);
+
+ if (mAppModal) {
+ mReturnCode = code;
+ [NSApp stopModalWithCode:code];
+ } else {
+ if (code == NSOKButton)
+ mPriv->fontDialog()->accept();
+ else
+ mPriv->fontDialog()->reject();
+ }
+}
+
+- (void)cleanUpAfterMyself
+{
+ if (mPanelHackedWithButtons) {
+ NSView *ourContentView = [mFontPanel contentView];
+
+ // return stolen stuff to its rightful owner
+ [mStolenContentView removeFromSuperview];
+ [mFontPanel setContentView:mStolenContentView];
+
+ [mOkButton release];
+ [mCancelButton release];
+ [ourContentView release];
+ }
+ [mFontPanel setDelegate:nil];
+ [[NSFontManager sharedFontManager] setDelegate:nil];
+#ifdef QT_MAC_USE_COCOA
+ [[NSFontManager sharedFontManager] setTarget:nil];
+#endif
+}
+@end
+
+QT_BEGIN_NAMESPACE
+
+void QFontDialogPrivate::closeCocoaFontPanel()
+{
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *theDelegate = static_cast<QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *>(delegate);
+ NSWindow *ourPanel = [theDelegate actualPanel];
+ [ourPanel close];
+ if ([theDelegate isAppModal])
+ [ourPanel release];
+ [theDelegate cleanUpAfterMyself];
+ [theDelegate release];
+ this->delegate = 0;
+ sharedFontPanelAvailable = true;
+}
+
+void QFontDialogPrivate::setFont(void *delegate, const QFont &font)
+{
+ QMacCocoaAutoReleasePool pool;
+ QFontEngine *fe = font.d->engineForScript(QUnicodeTables::Common);
+ NSFontManager *mgr = [NSFontManager sharedFontManager];
+ const NSFont *nsFont = 0;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ if (qstrcmp(fe->name(), "CoreText") == 0) {
+ nsFont = reinterpret_cast<const NSFont *>(static_cast<QCoreTextFontEngineMulti *>(fe)->ctfont);
+ } else
+#endif
+ {
+ int weight = 5;
+ NSFontTraitMask mask = 0;
+ if (font.style() == QFont::StyleItalic) {
+ mask |= NSItalicFontMask;
+ }
+ if (font.weight() == QFont::Bold) {
+ weight = 9;
+ mask |= NSBoldFontMask;
+ }
+
+ NSFontManager *mgr = [NSFontManager sharedFontManager];
+ QFontInfo fontInfo(font);
+ nsFont = [mgr fontWithFamily:qt_mac_QStringToNSString(fontInfo.family())
+ traits:mask
+ weight:weight
+ size:fontInfo.pointSize()];
+ }
+
+ [mgr setSelectedFont:const_cast<NSFont *>(nsFont) isMultiple:NO];
+ [static_cast<QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *>(delegate) setQtFont:font];
+}
+
+void QFontDialogPrivate::createNSFontPanelDelegate()
+{
+ if (delegate)
+ return;
+
+ sharedFontPanelAvailable = false;
+ QMacCocoaAutoReleasePool pool;
+ bool sharedFontPanelExisted = [NSFontPanel sharedFontPanelExists];
+ NSFontPanel *sharedFontPanel = [NSFontPanel sharedFontPanel];
+ [sharedFontPanel setHidesOnDeactivate:false];
+
+ // hack to ensure that QCocoaApplication's validModesForFontPanel:
+ // implementation is honored
+ if (!sharedFontPanelExisted) {
+ [sharedFontPanel makeKeyAndOrderFront:sharedFontPanel];
+ [sharedFontPanel close];
+ }
+
+ NSPanel *ourPanel = 0;
+ NSView *stolenContentView = 0;
+ NSButton *okButton = 0;
+ NSButton *cancelButton = 0;
+
+ CGFloat dialogExtraWidth = 0.0;
+ CGFloat dialogExtraHeight = 0.0;
+
+ // compute dialogExtra{Width,Height}
+ dialogExtraWidth = 2.0 * DialogSideMargin;
+ dialogExtraHeight = DialogTopMargin + ButtonTopMargin + ButtonMinHeight + ButtonBottomMargin;
+
+ // compute initial contents rectangle
+ NSRect contentRect = [sharedFontPanel contentRectForFrameRect:[sharedFontPanel frame]];
+ contentRect.size.width += dialogExtraWidth;
+ contentRect.size.height += dialogExtraHeight;
+
+ // create the new panel
+ ourPanel = [[NSPanel alloc] initWithContentRect:contentRect
+ styleMask:StyleMask
+ backing:NSBackingStoreBuffered
+ defer:YES];
+ [ourPanel setReleasedWhenClosed:YES];
+ stolenContentView = [sharedFontPanel contentView];
+
+ // steal the font panel's contents view
+ [stolenContentView retain];
+ [sharedFontPanel setContentView:0];
+
+ {
+ // create a new content view and add the stolen one as a subview
+ NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } };
+ NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect];
+ [ourContentView addSubview:stolenContentView];
+
+ // create OK and Cancel buttons and add these as subviews
+ okButton = macCreateButton("&OK", ourContentView);
+ cancelButton = macCreateButton("Cancel", ourContentView);
+
+ [ourPanel setContentView:ourContentView];
+ [ourPanel setDefaultButtonCell:[okButton cell]];
+ }
+
+ // create the delegate and set it
+ QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *del = [[QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) alloc] initWithFontPanel:sharedFontPanel
+ stolenContentView:stolenContentView
+ okButton:okButton
+ cancelButton:cancelButton
+ priv:this
+ extraWidth:dialogExtraWidth
+ extraHeight:dialogExtraHeight];
+ delegate = del;
+ [ourPanel setDelegate:del];
+
+ [[NSFontManager sharedFontManager] setDelegate:del];
+#ifdef QT_MAC_USE_COCOA
+ [[NSFontManager sharedFontManager] setTarget:del];
+#endif
+ setFont(del, q_func()->currentFont());
+
+ {
+ // hack to get correct initial layout
+ NSRect frameRect = [ourPanel frame];
+ frameRect.size.width += 1.0;
+ [ourPanel setFrame:frameRect display:NO];
+ frameRect.size.width -= 1.0;
+ frameRect.size = [del windowWillResize:ourPanel toSize:frameRect.size];
+ [ourPanel setFrame:frameRect display:NO];
+ [ourPanel center];
+ }
+ [del setSubwindowStacking];
+ NSString *title = @"Select font";
+ [ourPanel setTitle:title];
+}
+
+void QFontDialogPrivate::mac_nativeDialogModalHelp()
+{
+ // Copied from QFileDialogPrivate
+ // Do a queued meta-call to open the native modal dialog so it opens after the new
+ // event loop has started to execute (in QDialog::exec). Using a timer rather than
+ // a queued meta call is intentional to ensure that the call is only delivered when
+ // [NSApp run] runs (timers are handeled special in cocoa). If NSApp is not
+ // running (which is the case if e.g a top-most QEventLoop has been
+ // interrupted, and the second-most event loop has not yet been reactivated (regardless
+ // if [NSApp run] is still on the stack)), showing a native modal dialog will fail.
+ if (nativeDialogInUse) {
+ Q_Q(QFontDialog);
+ QTimer::singleShot(1, q, SLOT(_q_macRunNativeAppModalPanel()));
+ }
+}
+
+// The problem with the native font dialog is that OS X does not
+// offer a proper dialog, but a panel (i.e. without Ok and Cancel buttons).
+// This means we need to "construct" a native dialog by taking the panel
+// and "adding" the buttons.
+void QFontDialogPrivate::_q_macRunNativeAppModalPanel()
+{
+ createNSFontPanelDelegate();
+ QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *del = static_cast<QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *>(delegate);
+ [del runApplicationModalPanel];
+}
+
+bool QFontDialogPrivate::showCocoaFontPanel()
+{
+ if (!sharedFontPanelAvailable)
+ return false;
+
+ Q_Q(QFontDialog);
+ QMacCocoaAutoReleasePool pool;
+ createNSFontPanelDelegate();
+ QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *del = static_cast<QT_MANGLE_NAMESPACE(QCocoaFontPanelDelegate) *>(delegate);
+ if (qt_mac_is_macsheet(q))
+ [del showWindowModalSheet:q->parentWidget()];
+ else
+ [del showModelessPanel];
+ return true;
+}
+
+bool QFontDialogPrivate::hideCocoaFontPanel()
+{
+ if (!delegate){
+ // Nothing to do. We return false to leave the question
+ // open regarding whether or not to go native:
+ return false;
+ } else {
+ closeCocoaFontPanel();
+ // Even when we hide it, we are still using a
+ // native dialog, so return true:
+ return true;
+ }
+}
+bool QFontDialogPrivate::setVisible_sys(bool visible)
+{
+ Q_Q(QFontDialog);
+ if (!visible == q->isHidden())
+ return false;
+
+ return visible ? showCocoaFontPanel() : hideCocoaFontPanel();
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qfontdialog_p.h b/src/widgets/dialogs/qfontdialog_p.h
new file mode 100644
index 0000000000..349e2d3fcb
--- /dev/null
+++ b/src/widgets/dialogs/qfontdialog_p.h
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFONTDIALOG_P_H
+#define QFONTDIALOG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+//
+
+#include "private/qdialog_p.h"
+#include "qfontdatabase.h"
+#include "qfontdialog.h"
+
+#ifndef QT_NO_FONTDIALOG
+
+QT_BEGIN_NAMESPACE
+
+class QBoxLayout;
+class QCheckBox;
+class QComboBox;
+class QDialogButtonBox;
+class QFontListView;
+class QGroupBox;
+class QLabel;
+class QLineEdit;
+
+class QFontDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QFontDialog)
+
+public:
+ inline QFontDialogPrivate()
+ : writingSystem(QFontDatabase::Any)
+ { }
+
+ void updateFamilies();
+ void updateStyles();
+ void updateSizes();
+
+ static QFont getFont(bool *ok, const QFont &initial, QWidget *parent,
+ const QString &title, QFontDialog::FontDialogOptions options);
+
+ void init();
+ void _q_sizeChanged(const QString &);
+ void _q_familyHighlighted(int);
+ void _q_writingSystemHighlighted(int);
+ void _q_styleHighlighted(int);
+ void _q_sizeHighlighted(int);
+ void _q_updateSample();
+ void updateSampleFont(const QFont &newFont);
+ void retranslateStrings();
+
+ QLabel *familyAccel;
+ QLineEdit *familyEdit;
+ QFontListView *familyList;
+
+ QLabel *styleAccel;
+ QLineEdit *styleEdit;
+ QFontListView *styleList;
+
+ QLabel *sizeAccel;
+ QLineEdit *sizeEdit;
+ QFontListView *sizeList;
+
+ QGroupBox *effects;
+ QCheckBox *strikeout;
+ QCheckBox *underline;
+ QComboBox *color;
+
+ QGroupBox *sample;
+ QLineEdit *sampleEdit;
+
+ QLabel *writingSystemAccel;
+ QComboBox *writingSystemCombo;
+
+ QBoxLayout *buttonLayout;
+ QBoxLayout *effectsLayout;
+ QBoxLayout *sampleLayout;
+ QBoxLayout *sampleEditLayout;
+
+ QDialogButtonBox *buttonBox;
+
+ QFontDatabase fdb;
+ QString family;
+ QFontDatabase::WritingSystem writingSystem;
+ QString style;
+ int size;
+ bool smoothScalable;
+ QFont selectedFont;
+ QFontDialog::FontDialogOptions opts;
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+
+#ifdef Q_WS_MAC
+ static void setFont(void *delegate, const QFont &font);
+
+ inline void done(int result) { q_func()->done(result); }
+ inline QFontDialog *fontDialog() { return q_func(); }
+
+ void *delegate;
+ void closeCocoaFontPanel();
+ bool nativeDialogInUse;
+ bool canBeNativeDialog();
+ bool setVisible_sys(bool visible);
+ void createNSFontPanelDelegate();
+ void _q_macRunNativeAppModalPanel();
+ void mac_nativeDialogModalHelp();
+ bool showCocoaFontPanel();
+ bool hideCocoaFontPanel();
+
+ static bool sharedFontPanelAvailable;
+#endif
+};
+
+#endif // QT_NO_FONTDIALOG
+
+QT_END_NAMESPACE
+
+#endif // QFONTDIALOG_P_H
diff --git a/src/widgets/dialogs/qfscompleter_p.h b/src/widgets/dialogs/qfscompleter_p.h
new file mode 100644
index 0000000000..e078542cdc
--- /dev/null
+++ b/src/widgets/dialogs/qfscompleter_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFSCOMPLETOR_P_H
+#define QFSCOMPLETOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qcompleter.h"
+#include <QtWidgets/qfilesystemmodel.h>
+QT_BEGIN_NAMESPACE
+#ifndef QT_NO_FSCOMPLETER
+
+/*!
+ QCompleter that can deal with QFileSystemModel
+ */
+class Q_WIDGETS_EXPORT QFSCompleter : public QCompleter {
+public:
+ QFSCompleter(QFileSystemModel *model, QObject *parent = 0)
+ : QCompleter(model, parent), proxyModel(0), sourceModel(model)
+ {
+#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+ setCaseSensitivity(Qt::CaseInsensitive);
+#endif
+ }
+ QString pathFromIndex(const QModelIndex &index) const;
+ QStringList splitPath(const QString& path) const;
+
+ QAbstractProxyModel *proxyModel;
+ QFileSystemModel *sourceModel;
+};
+#endif // QT_NO_FSCOMPLETER
+QT_END_NAMESPACE
+#endif // QFSCOMPLETOR_P_H
+
diff --git a/src/widgets/dialogs/qinputdialog.cpp b/src/widgets/dialogs/qinputdialog.cpp
new file mode 100644
index 0000000000..5ca947ccbd
--- /dev/null
+++ b/src/widgets/dialogs/qinputdialog.cpp
@@ -0,0 +1,1489 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qinputdialog.h"
+
+#ifndef QT_NO_INPUTDIALOG
+
+#include "qapplication.h"
+#include "qcombobox.h"
+#include "qdialogbuttonbox.h"
+#include "qlabel.h"
+#include "qlayout.h"
+#include "qlineedit.h"
+#include "qlistwidget.h"
+#include "qpushbutton.h"
+#include "qspinbox.h"
+#include "qstackedlayout.h"
+#include "qvalidator.h"
+#include "qevent.h"
+#include "qdialog_p.h"
+
+QT_USE_NAMESPACE
+
+static const char *signalForMember(const char *member)
+{
+ static const int NumCandidates = 4;
+ static const char * const candidateSignals[NumCandidates] = {
+ SIGNAL(textValueSelected(QString)),
+ SIGNAL(intValueSelected(int)),
+ SIGNAL(doubleValueSelected(double)),
+ SIGNAL(accepted())
+ };
+
+ QByteArray normalizedMember(QMetaObject::normalizedSignature(member));
+
+ int i = 0;
+ while (i < NumCandidates - 1) { // sic
+ if (QMetaObject::checkConnectArgs(candidateSignals[i], normalizedMember))
+ break;
+ ++i;
+ }
+ return candidateSignals[i];
+}
+
+QT_BEGIN_NAMESPACE
+
+/*
+ These internal classes add extra validation to QSpinBox and QDoubleSpinBox by emitting
+ textChanged(bool) after events that may potentially change the visible text. Return or
+ Enter key presses are not propagated if the visible text is invalid. Instead, the visible
+ text is modified to the last valid value.
+*/
+class QInputDialogSpinBox : public QSpinBox
+{
+ Q_OBJECT
+
+public:
+ QInputDialogSpinBox(QWidget *parent)
+ : QSpinBox(parent) {
+ connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(notifyTextChanged()));
+ connect(this, SIGNAL(editingFinished()), this, SLOT(notifyTextChanged()));
+ }
+
+signals:
+ void textChanged(bool);
+
+private slots:
+ void notifyTextChanged() { emit textChanged(hasAcceptableInput()); }
+
+private:
+ void keyPressEvent(QKeyEvent *event) {
+ if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !hasAcceptableInput()) {
+#ifndef QT_NO_PROPERTIES
+ setProperty("value", property("value"));
+#endif
+ } else {
+ QSpinBox::keyPressEvent(event);
+ }
+ notifyTextChanged();
+ }
+
+ void mousePressEvent(QMouseEvent *event) {
+ QSpinBox::mousePressEvent(event);
+ notifyTextChanged();
+ }
+};
+
+class QInputDialogDoubleSpinBox : public QDoubleSpinBox
+{
+ Q_OBJECT
+
+public:
+ QInputDialogDoubleSpinBox(QWidget *parent = 0)
+ : QDoubleSpinBox(parent) {
+ connect(lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(notifyTextChanged()));
+ connect(this, SIGNAL(editingFinished()), this, SLOT(notifyTextChanged()));
+ }
+
+signals:
+ void textChanged(bool);
+
+private slots:
+ void notifyTextChanged() { emit textChanged(hasAcceptableInput()); }
+
+private:
+ void keyPressEvent(QKeyEvent *event) {
+ if ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && !hasAcceptableInput()) {
+#ifndef QT_NO_PROPERTIES
+ setProperty("value", property("value"));
+#endif
+ } else {
+ QDoubleSpinBox::keyPressEvent(event);
+ }
+ notifyTextChanged();
+ }
+
+ void mousePressEvent(QMouseEvent *event) {
+ QDoubleSpinBox::mousePressEvent(event);
+ notifyTextChanged();
+ }
+};
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "qinputdialog.moc"
+QT_END_INCLUDE_NAMESPACE
+
+class QInputDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QInputDialog)
+
+public:
+ QInputDialogPrivate();
+
+ void ensureLayout();
+ void ensureLineEdit();
+ void ensureComboBox();
+ void ensureListView();
+ void ensureIntSpinBox();
+ void ensureDoubleSpinBox();
+ void ensureEnabledConnection(QAbstractSpinBox *spinBox);
+ void setInputWidget(QWidget *widget);
+ void chooseRightTextInputWidget();
+ void setComboBoxText(const QString &text);
+ void setListViewText(const QString &text);
+ QString listViewText() const;
+ void ensureLayout() const { const_cast<QInputDialogPrivate *>(this)->ensureLayout(); }
+ bool useComboBoxOrListView() const { return comboBox && comboBox->count() > 0; }
+ void _q_textChanged(const QString &text);
+ void _q_currentRowChanged(const QModelIndex &newIndex, const QModelIndex &oldIndex);
+
+ mutable QLabel *label;
+ mutable QDialogButtonBox *buttonBox;
+ mutable QLineEdit *lineEdit;
+ mutable QSpinBox *intSpinBox;
+ mutable QDoubleSpinBox *doubleSpinBox;
+ mutable QComboBox *comboBox;
+ mutable QListView *listView;
+ mutable QWidget *inputWidget;
+ mutable QVBoxLayout *mainLayout;
+ QInputDialog::InputDialogOptions opts;
+ QString textValue;
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+};
+
+QInputDialogPrivate::QInputDialogPrivate()
+ : label(0), buttonBox(0), lineEdit(0), intSpinBox(0), doubleSpinBox(0), comboBox(0), listView(0),
+ inputWidget(0), mainLayout(0)
+{
+}
+
+void QInputDialogPrivate::ensureLayout()
+{
+ Q_Q(QInputDialog);
+
+ if (mainLayout)
+ return;
+
+ if (!inputWidget) {
+ ensureLineEdit();
+ inputWidget = lineEdit;
+ }
+
+ if (!label)
+ label = new QLabel(QInputDialog::tr("Enter a value:"), q);
+#ifndef QT_NO_SHORTCUT
+ label->setBuddy(inputWidget);
+#endif
+ label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+
+ buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, q);
+ QObject::connect(buttonBox, SIGNAL(accepted()), q, SLOT(accept()));
+ QObject::connect(buttonBox, SIGNAL(rejected()), q, SLOT(reject()));
+
+ mainLayout = new QVBoxLayout(q);
+ //we want to let the input dialog grow to available size on Symbian.
+#ifndef Q_OS_SYMBIAN
+ mainLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
+#else
+ label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+#endif
+ mainLayout->addWidget(label);
+ mainLayout->addWidget(inputWidget);
+ mainLayout->addWidget(buttonBox);
+ ensureEnabledConnection(qobject_cast<QAbstractSpinBox *>(inputWidget));
+ inputWidget->show();
+}
+
+void QInputDialogPrivate::ensureLineEdit()
+{
+ Q_Q(QInputDialog);
+ if (!lineEdit) {
+ lineEdit = new QLineEdit(q);
+#ifndef QT_NO_IM
+ qt_widget_private(lineEdit)->inheritsInputMethodHints = 1;
+#endif
+ lineEdit->hide();
+ QObject::connect(lineEdit, SIGNAL(textChanged(QString)),
+ q, SLOT(_q_textChanged(QString)));
+ }
+}
+
+void QInputDialogPrivate::ensureComboBox()
+{
+ Q_Q(QInputDialog);
+ if (!comboBox) {
+ comboBox = new QComboBox(q);
+#ifndef QT_NO_IM
+ qt_widget_private(comboBox)->inheritsInputMethodHints = 1;
+#endif
+ comboBox->hide();
+ QObject::connect(comboBox, SIGNAL(editTextChanged(QString)),
+ q, SLOT(_q_textChanged(QString)));
+ QObject::connect(comboBox, SIGNAL(currentIndexChanged(QString)),
+ q, SLOT(_q_textChanged(QString)));
+ }
+}
+
+void QInputDialogPrivate::ensureListView()
+{
+ Q_Q(QInputDialog);
+ if (!listView) {
+ ensureComboBox();
+
+ listView = new QListView(q);
+ listView->hide();
+ listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ listView->setSelectionMode(QAbstractItemView::SingleSelection);
+ listView->setModel(comboBox->model());
+ listView->setCurrentIndex(QModelIndex()); // ###
+ QObject::connect(listView->selectionModel(),
+ SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
+ q, SLOT(_q_currentRowChanged(QModelIndex,QModelIndex)));
+ }
+}
+
+void QInputDialogPrivate::ensureIntSpinBox()
+{
+ Q_Q(QInputDialog);
+ if (!intSpinBox) {
+ intSpinBox = new QInputDialogSpinBox(q);
+ intSpinBox->hide();
+ QObject::connect(intSpinBox, SIGNAL(valueChanged(int)),
+ q, SIGNAL(intValueChanged(int)));
+ }
+}
+
+void QInputDialogPrivate::ensureDoubleSpinBox()
+{
+ Q_Q(QInputDialog);
+ if (!doubleSpinBox) {
+ doubleSpinBox = new QInputDialogDoubleSpinBox(q);
+ doubleSpinBox->hide();
+ QObject::connect(doubleSpinBox, SIGNAL(valueChanged(double)),
+ q, SIGNAL(doubleValueChanged(double)));
+ }
+}
+
+void QInputDialogPrivate::ensureEnabledConnection(QAbstractSpinBox *spinBox)
+{
+ if (spinBox) {
+ QAbstractButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
+ QObject::connect(spinBox, SIGNAL(textChanged(bool)), okButton, SLOT(setEnabled(bool)), Qt::UniqueConnection);
+ }
+}
+
+void QInputDialogPrivate::setInputWidget(QWidget *widget)
+{
+ Q_ASSERT(widget);
+ if (inputWidget == widget)
+ return;
+
+ if (mainLayout) {
+ Q_ASSERT(inputWidget);
+ mainLayout->removeWidget(inputWidget);
+ inputWidget->hide();
+ mainLayout->insertWidget(1, widget);
+ widget->show();
+
+ // disconnect old input widget
+ QAbstractButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
+ if (QAbstractSpinBox *spinBox = qobject_cast<QAbstractSpinBox *>(inputWidget))
+ QObject::disconnect(spinBox, SIGNAL(textChanged(bool)), okButton, SLOT(setEnabled(bool)));
+
+ // connect new input widget and update enabled state of OK button
+ QAbstractSpinBox *spinBox = qobject_cast<QAbstractSpinBox *>(widget);
+ ensureEnabledConnection(spinBox);
+ okButton->setEnabled(!spinBox || spinBox->hasAcceptableInput());
+ }
+
+ inputWidget = widget;
+
+ // synchronize the text shown in the new text editor with the current
+ // textValue
+ if (widget == lineEdit) {
+ lineEdit->setText(textValue);
+ } else if (widget == comboBox) {
+ setComboBoxText(textValue);
+ } else if (widget == listView) {
+ setListViewText(textValue);
+ ensureLayout();
+ buttonBox->button(QDialogButtonBox::Ok)->setEnabled(listView->selectionModel()->hasSelection());
+ }
+}
+
+void QInputDialogPrivate::chooseRightTextInputWidget()
+{
+ QWidget *widget;
+
+ if (useComboBoxOrListView()) {
+ if ((opts & QInputDialog::UseListViewForComboBoxItems) && !comboBox->isEditable()) {
+ ensureListView();
+ widget = listView;
+ } else {
+ widget = comboBox;
+ }
+ } else {
+ ensureLineEdit();
+ widget = lineEdit;
+ }
+
+ setInputWidget(widget);
+
+ if (inputWidget == comboBox) {
+ _q_textChanged(comboBox->currentText());
+ } else if (inputWidget == listView) {
+ _q_textChanged(listViewText());
+ }
+}
+
+void QInputDialogPrivate::setComboBoxText(const QString &text)
+{
+ int index = comboBox->findText(text);
+ if (index != -1) {
+ comboBox->setCurrentIndex(index);
+ } else if (comboBox->isEditable()) {
+ comboBox->setEditText(text);
+ }
+}
+
+void QInputDialogPrivate::setListViewText(const QString &text)
+{
+ int row = comboBox->findText(text);
+ if (row != -1) {
+ QModelIndex index(comboBox->model()->index(row, 0));
+ listView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::Clear
+ | QItemSelectionModel::SelectCurrent);
+ }
+}
+
+QString QInputDialogPrivate::listViewText() const
+{
+ if (listView->selectionModel()->hasSelection()) {
+ int row = listView->selectionModel()->selectedRows().value(0).row();
+ return comboBox->itemText(row);
+ } else {
+ return QString();
+ }
+}
+
+void QInputDialogPrivate::_q_textChanged(const QString &text)
+{
+ Q_Q(QInputDialog);
+ if (textValue != text) {
+ textValue = text;
+ emit q->textValueChanged(text);
+ }
+}
+
+void QInputDialogPrivate::_q_currentRowChanged(const QModelIndex &newIndex,
+ const QModelIndex & /* oldIndex */)
+{
+ _q_textChanged(comboBox->model()->data(newIndex).toString());
+ buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+}
+
+/*!
+ \class QInputDialog
+ \brief The QInputDialog class provides a simple convenience dialog to get a
+ single value from the user.
+ \ingroup standard-dialogs
+
+
+ The input value can be a string, a number or an item from a list. A label
+ must be set to tell the user what they should enter.
+
+ Four static convenience functions are provided: getText(), getInt(),
+ getDouble(), and getItem(). All the functions can be used in a similar way,
+ for example:
+
+ \snippet examples/dialogs/standarddialogs/dialog.cpp 3
+
+ The \c ok variable is set to true if the user clicks \gui OK; otherwise it
+ is set to false.
+
+ \img inputdialogs.png Input Dialogs
+
+ The \l{dialogs/standarddialogs}{Standard Dialogs} example shows how to use
+ QInputDialog as well as other built-in Qt dialogs.
+
+ \sa QMessageBox, {Standard Dialogs Example}
+*/
+
+/*!
+ \enum QInputDialog::InputMode
+ \since 4.5
+
+ This enum describes the different modes of input that can be selected for
+ the dialog.
+
+ \value TextInput Used to input text strings.
+ \value IntInput Used to input integers.
+ \value DoubleInput Used to input floating point numbers with double
+ precision accuracy.
+
+ \sa inputMode
+*/
+
+/*!
+ \since 4.5
+
+ Constructs a new input dialog with the given \a parent and window \a flags.
+*/
+QInputDialog::QInputDialog(QWidget *parent, Qt::WindowFlags flags)
+ : QDialog(*new QInputDialogPrivate, parent, flags)
+{
+}
+
+/*!
+ \since 4.5
+
+ Destroys the input dialog.
+*/
+QInputDialog::~QInputDialog()
+{
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::inputMode
+
+ \brief the mode used for input
+
+ This property help determines which widget is used for entering input into
+ the dialog.
+*/
+void QInputDialog::setInputMode(InputMode mode)
+{
+ Q_D(QInputDialog);
+
+ QWidget *widget;
+
+ /*
+ Warning: Some functions in QInputDialog rely on implementation details
+ of the code below. Look for the comments that accompany the calls to
+ setInputMode() throughout this file before you change the code below.
+ */
+
+ switch (mode) {
+ case IntInput:
+ d->ensureIntSpinBox();
+ widget = d->intSpinBox;
+ break;
+ case DoubleInput:
+ d->ensureDoubleSpinBox();
+ widget = d->doubleSpinBox;
+ break;
+ default:
+ Q_ASSERT(mode == TextInput);
+ d->chooseRightTextInputWidget();
+ return;
+ }
+
+ d->setInputWidget(widget);
+}
+
+QInputDialog::InputMode QInputDialog::inputMode() const
+{
+ Q_D(const QInputDialog);
+
+ if (d->inputWidget) {
+ if (d->inputWidget == d->intSpinBox) {
+ return IntInput;
+ } else if (d->inputWidget == d->doubleSpinBox) {
+ return DoubleInput;
+ }
+ }
+
+ return TextInput;
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::labelText
+
+ \brief the text to for the label to describe what needs to be input
+*/
+void QInputDialog::setLabelText(const QString &text)
+{
+ Q_D(QInputDialog);
+ if (!d->label) {
+ d->label = new QLabel(text, this);
+ } else {
+ d->label->setText(text);
+ }
+#ifdef Q_OS_SYMBIAN
+ d->label->setWordWrap(true);
+#endif
+}
+
+QString QInputDialog::labelText() const
+{
+ Q_D(const QInputDialog);
+ d->ensureLayout();
+ return d->label->text();
+}
+
+/*!
+ \enum QInputDialog::InputDialogOption
+
+ \since 4.5
+
+ This enum specifies various options that affect the look and feel
+ of an input dialog.
+
+ \value NoButtons Don't display \gui{OK} and \gui{Cancel} buttons. (Useful for "live dialogs".)
+ \value UseListViewForComboBoxItems Use a QListView rather than a non-editable QComboBox for
+ displaying the items set with setComboBoxItems().
+
+ \sa options, setOption(), testOption()
+*/
+
+/*!
+ Sets the given \a option to be enabled if \a on is true;
+ otherwise, clears the given \a option.
+
+ \sa options, testOption()
+*/
+void QInputDialog::setOption(InputDialogOption option, bool on)
+{
+ Q_D(QInputDialog);
+ if (!(d->opts & option) != !on)
+ setOptions(d->opts ^ option);
+}
+
+/*!
+ Returns true if the given \a option is enabled; otherwise, returns
+ false.
+
+ \sa options, setOption()
+*/
+bool QInputDialog::testOption(InputDialogOption option) const
+{
+ Q_D(const QInputDialog);
+ return (d->opts & option) != 0;
+}
+
+/*!
+ \property QInputDialog::options
+ \brief the various options that affect the look and feel of the dialog
+ \since 4.5
+
+ By default, all options are disabled.
+
+ \sa setOption(), testOption()
+*/
+void QInputDialog::setOptions(InputDialogOptions options)
+{
+ Q_D(QInputDialog);
+
+ InputDialogOptions changed = (options ^ d->opts);
+ if (!changed)
+ return;
+
+ d->opts = options;
+ d->ensureLayout();
+
+ if (changed & NoButtons)
+ d->buttonBox->setVisible(!(options & NoButtons));
+ if ((changed & UseListViewForComboBoxItems) && inputMode() == TextInput)
+ d->chooseRightTextInputWidget();
+}
+
+QInputDialog::InputDialogOptions QInputDialog::options() const
+{
+ Q_D(const QInputDialog);
+ return d->opts;
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::textValue
+
+ \brief the text value for the input dialog
+
+ This property is only relevant when the input dialog is used in
+ TextInput mode.
+*/
+void QInputDialog::setTextValue(const QString &text)
+{
+ Q_D(QInputDialog);
+
+ setInputMode(TextInput);
+ if (d->inputWidget == d->lineEdit) {
+ d->lineEdit->setText(text);
+ } else if (d->inputWidget == d->comboBox) {
+ d->setComboBoxText(text);
+ } else {
+ d->setListViewText(text);
+ }
+}
+
+QString QInputDialog::textValue() const
+{
+ Q_D(const QInputDialog);
+ return d->textValue;
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::textEchoMode
+
+ \brief the echo mode for the text value
+
+ This property is only relevant when the input dialog is used in
+ TextInput mode.
+*/
+void QInputDialog::setTextEchoMode(QLineEdit::EchoMode mode)
+{
+ Q_D(QInputDialog);
+ d->ensureLineEdit();
+ d->lineEdit->setEchoMode(mode);
+}
+
+QLineEdit::EchoMode QInputDialog::textEchoMode() const
+{
+ Q_D(const QInputDialog);
+ if (d->lineEdit) {
+ return d->lineEdit->echoMode();
+ } else {
+ return QLineEdit::Normal;
+ }
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::comboBoxEditable
+
+ \brief whether or not the combo box is used in the input dialog is editable
+*/
+void QInputDialog::setComboBoxEditable(bool editable)
+{
+ Q_D(QInputDialog);
+ d->ensureComboBox();
+ d->comboBox->setEditable(editable);
+ if (inputMode() == TextInput)
+ d->chooseRightTextInputWidget();
+}
+
+bool QInputDialog::isComboBoxEditable() const
+{
+ Q_D(const QInputDialog);
+ if (d->comboBox) {
+ return d->comboBox->isEditable();
+ } else {
+ return false;
+ }
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::comboBoxItems
+
+ \brief the items used in the combobox for the input dialog
+*/
+void QInputDialog::setComboBoxItems(const QStringList &items)
+{
+ Q_D(QInputDialog);
+
+ d->ensureComboBox();
+ d->comboBox->blockSignals(true);
+ d->comboBox->clear();
+ d->comboBox->addItems(items);
+ d->comboBox->blockSignals(false);
+
+ if (inputMode() == TextInput)
+ d->chooseRightTextInputWidget();
+}
+
+QStringList QInputDialog::comboBoxItems() const
+{
+ Q_D(const QInputDialog);
+ QStringList result;
+ if (d->comboBox) {
+ const int count = d->comboBox->count();
+ for (int i = 0; i < count; ++i)
+ result.append(d->comboBox->itemText(i));
+ }
+ return result;
+}
+
+/*!
+ \property QInputDialog::intValue
+ \since 4.5
+ \brief the current integer value accepted as input
+
+ This property is only relevant when the input dialog is used in
+ IntInput mode.
+*/
+void QInputDialog::setIntValue(int value)
+{
+ Q_D(QInputDialog);
+ setInputMode(IntInput);
+ d->intSpinBox->setValue(value);
+}
+
+int QInputDialog::intValue() const
+{
+ Q_D(const QInputDialog);
+ if (d->intSpinBox) {
+ return d->intSpinBox->value();
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ \property QInputDialog::intMinimum
+ \since 4.5
+ \brief the minimum integer value accepted as input
+
+ This property is only relevant when the input dialog is used in
+ IntInput mode.
+*/
+void QInputDialog::setIntMinimum(int min)
+{
+ Q_D(QInputDialog);
+ d->ensureIntSpinBox();
+ d->intSpinBox->setMinimum(min);
+}
+
+int QInputDialog::intMinimum() const
+{
+ Q_D(const QInputDialog);
+ if (d->intSpinBox) {
+ return d->intSpinBox->minimum();
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ \property QInputDialog::intMaximum
+ \since 4.5
+ \brief the maximum integer value accepted as input
+
+ This property is only relevant when the input dialog is used in
+ IntInput mode.
+*/
+void QInputDialog::setIntMaximum(int max)
+{
+ Q_D(QInputDialog);
+ d->ensureIntSpinBox();
+ d->intSpinBox->setMaximum(max);
+}
+
+int QInputDialog::intMaximum() const
+{
+ Q_D(const QInputDialog);
+ if (d->intSpinBox) {
+ return d->intSpinBox->maximum();
+ } else {
+ return 99;
+ }
+}
+
+/*!
+ Sets the range of integer values accepted by the dialog when used in
+ IntInput mode, with minimum and maximum values specified by \a min and
+ \a max respectively.
+*/
+void QInputDialog::setIntRange(int min, int max)
+{
+ Q_D(QInputDialog);
+ d->ensureIntSpinBox();
+ d->intSpinBox->setRange(min, max);
+}
+
+/*!
+ \property QInputDialog::intStep
+ \since 4.5
+ \brief the step by which the integer value is increased and decreased
+
+ This property is only relevant when the input dialog is used in
+ IntInput mode.
+*/
+void QInputDialog::setIntStep(int step)
+{
+ Q_D(QInputDialog);
+ d->ensureIntSpinBox();
+ d->intSpinBox->setSingleStep(step);
+}
+
+int QInputDialog::intStep() const
+{
+ Q_D(const QInputDialog);
+ if (d->intSpinBox) {
+ return d->intSpinBox->singleStep();
+ } else {
+ return 1;
+ }
+}
+
+/*!
+ \property QInputDialog::doubleValue
+ \since 4.5
+ \brief the current double precision floating point value accepted as input
+
+ This property is only relevant when the input dialog is used in
+ DoubleInput mode.
+*/
+void QInputDialog::setDoubleValue(double value)
+{
+ Q_D(QInputDialog);
+ setInputMode(DoubleInput);
+ d->doubleSpinBox->setValue(value);
+}
+
+double QInputDialog::doubleValue() const
+{
+ Q_D(const QInputDialog);
+ if (d->doubleSpinBox) {
+ return d->doubleSpinBox->value();
+ } else {
+ return 0.0;
+ }
+}
+
+/*!
+ \property QInputDialog::doubleMinimum
+ \since 4.5
+ \brief the minimum double precision floating point value accepted as input
+
+ This property is only relevant when the input dialog is used in
+ DoubleInput mode.
+*/
+void QInputDialog::setDoubleMinimum(double min)
+{
+ Q_D(QInputDialog);
+ d->ensureDoubleSpinBox();
+ d->doubleSpinBox->setMinimum(min);
+}
+
+double QInputDialog::doubleMinimum() const
+{
+ Q_D(const QInputDialog);
+ if (d->doubleSpinBox) {
+ return d->doubleSpinBox->minimum();
+ } else {
+ return 0.0;
+ }
+}
+
+/*!
+ \property QInputDialog::doubleMaximum
+ \since 4.5
+ \brief the maximum double precision floating point value accepted as input
+
+ This property is only relevant when the input dialog is used in
+ DoubleInput mode.
+*/
+void QInputDialog::setDoubleMaximum(double max)
+{
+ Q_D(QInputDialog);
+ d->ensureDoubleSpinBox();
+ d->doubleSpinBox->setMaximum(max);
+}
+
+double QInputDialog::doubleMaximum() const
+{
+ Q_D(const QInputDialog);
+ if (d->doubleSpinBox) {
+ return d->doubleSpinBox->maximum();
+ } else {
+ return 99.99;
+ }
+}
+
+/*!
+ Sets the range of double precision floating point values accepted by the
+ dialog when used in DoubleInput mode, with minimum and maximum values
+ specified by \a min and \a max respectively.
+*/
+void QInputDialog::setDoubleRange(double min, double max)
+{
+ Q_D(QInputDialog);
+ d->ensureDoubleSpinBox();
+ d->doubleSpinBox->setRange(min, max);
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::doubleDecimals
+
+ \brief sets the percision of the double spinbox in decimals
+
+ \sa QDoubleSpinBox::setDecimals()
+*/
+void QInputDialog::setDoubleDecimals(int decimals)
+{
+ Q_D(QInputDialog);
+ d->ensureDoubleSpinBox();
+ d->doubleSpinBox->setDecimals(decimals);
+}
+
+int QInputDialog::doubleDecimals() const
+{
+ Q_D(const QInputDialog);
+ if (d->doubleSpinBox) {
+ return d->doubleSpinBox->decimals();
+ } else {
+ return 2;
+ }
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::okButtonText
+
+ \brief the text for the button used to accept the entry in the dialog
+*/
+void QInputDialog::setOkButtonText(const QString &text)
+{
+ Q_D(const QInputDialog);
+ d->ensureLayout();
+ d->buttonBox->button(QDialogButtonBox::Ok)->setText(text);
+}
+
+QString QInputDialog::okButtonText() const
+{
+ Q_D(const QInputDialog);
+ d->ensureLayout();
+ return d->buttonBox->button(QDialogButtonBox::Ok)->text();
+}
+
+/*!
+ \since 4.5
+
+ \property QInputDialog::cancelButtonText
+ \brief the text for the button used to cancel the dialog
+*/
+void QInputDialog::setCancelButtonText(const QString &text)
+{
+ Q_D(const QInputDialog);
+ d->ensureLayout();
+ d->buttonBox->button(QDialogButtonBox::Cancel)->setText(text);
+}
+
+QString QInputDialog::cancelButtonText() const
+{
+ Q_D(const QInputDialog);
+ d->ensureLayout();
+ return d->buttonBox->button(QDialogButtonBox::Cancel)->text();
+}
+
+/*!
+ \since 4.5
+ \overload
+
+ This function connects one of its signals to the slot specified by \a receiver
+ and \a member. The specific signal depends on the arguments that are specified
+ in \a member. These are:
+
+ \list
+ \o textValueSelected() if \a member has a QString for its first argument.
+ \o intValueSelected() if \a member has an int for its first argument.
+ \o doubleValueSelected() if \a member has a double for its first argument.
+ \o accepted() if \a member has NO arguments.
+ \endlist
+
+ The signal will be disconnected from the slot when the dialog is closed.
+*/
+void QInputDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QInputDialog);
+ connect(this, signalForMember(member), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+/*!
+ \reimp
+*/
+QSize QInputDialog::minimumSizeHint() const
+{
+ Q_D(const QInputDialog);
+ d->ensureLayout();
+ return QDialog::minimumSizeHint();
+}
+
+/*!
+ \reimp
+*/
+QSize QInputDialog::sizeHint() const
+{
+ Q_D(const QInputDialog);
+ d->ensureLayout();
+ return QDialog::sizeHint();
+}
+
+/*!
+ \reimp
+*/
+void QInputDialog::setVisible(bool visible)
+{
+ Q_D(const QInputDialog);
+ if (visible) {
+ d->ensureLayout();
+ d->inputWidget->setFocus();
+ if (d->inputWidget == d->lineEdit) {
+ d->lineEdit->selectAll();
+ } else if (d->inputWidget == d->intSpinBox) {
+ d->intSpinBox->selectAll();
+ } else if (d->inputWidget == d->doubleSpinBox) {
+ d->doubleSpinBox->selectAll();
+ }
+ }
+ QDialog::setVisible(visible);
+}
+
+/*!
+ Closes the dialog and sets its result code to \a result. If this dialog
+ is shown with exec(), done() causes the local event loop to finish,
+ and exec() to return \a result.
+
+ \sa QDialog::done()
+*/
+void QInputDialog::done(int result)
+{
+ Q_D(QInputDialog);
+ QDialog::done(result);
+ if (result) {
+ InputMode mode = inputMode();
+ switch (mode) {
+ case DoubleInput:
+ emit doubleValueSelected(doubleValue());
+ break;
+ case IntInput:
+ emit intValueSelected(intValue());
+ break;
+ default:
+ Q_ASSERT(mode == TextInput);
+ emit textValueSelected(textValue());
+ }
+ }
+ if (d->receiverToDisconnectOnClose) {
+ disconnect(this, signalForMember(d->memberToDisconnectOnClose),
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+}
+
+/*!
+ Static convenience function to get a string from the user.
+
+ \a title is the text which is displayed in the title bar of the dialog.
+ \a label is the text which is shown to the user (it should say what should
+ be entered).
+ \a text is the default text which is placed in the line edit.
+ \a mode is the echo mode the line edit will use.
+ \a inputMethodHints is the input method hints that will be used in the
+ edit widget if an input method is active.
+
+ If \a ok is nonnull \e *\a ok will be set to true if the user pressed
+ \gui OK and to false if the user pressed \gui Cancel. The dialog's parent
+ is \a parent. The dialog will be modal and uses the specified widget
+ \a flags.
+
+ If the dialog is accepted, this function returns the text in the dialog's
+ line edit. If the dialog is rejected, a null QString is returned.
+
+ Use this static function like this:
+
+ \snippet examples/dialogs/standarddialogs/dialog.cpp 3
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QInputDialog constructors.
+
+ \sa getInt(), getDouble(), getItem()
+*/
+
+QString QInputDialog::getText(QWidget *parent, const QString &title, const QString &label,
+ QLineEdit::EchoMode mode, const QString &text, bool *ok,
+ Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
+{
+ QInputDialog dialog(parent, flags);
+ dialog.setWindowTitle(title);
+ dialog.setLabelText(label);
+ dialog.setTextValue(text);
+ dialog.setTextEchoMode(mode);
+ dialog.setInputMethodHints(inputMethodHints);
+
+ int ret = dialog.exec();
+ if (ok)
+ *ok = !!ret;
+ if (ret) {
+ return dialog.textValue();
+ } else {
+ return QString();
+ }
+}
+
+/*!
+ \internal
+*/
+// ### Qt 5: Use only the version above.
+QString QInputDialog::getText(QWidget *parent, const QString &title, const QString &label,
+ QLineEdit::EchoMode mode, const QString &text, bool *ok,
+ Qt::WindowFlags flags)
+{
+ return getText(parent, title, label, mode, text, ok, flags, Qt::ImhNone);
+}
+
+/*!
+ \since 4.5
+
+ Static convenience function to get an integer input from the user.
+
+ \a title is the text which is displayed in the title bar of the dialog.
+ \a label is the text which is shown to the user (it should say what should
+ be entered).
+ \a value is the default integer which the spinbox will be set to.
+ \a min and \a max are the minimum and maximum values the user may choose.
+ \a step is the amount by which the values change as the user presses the
+ arrow buttons to increment or decrement the value.
+
+ If \a ok is nonnull *\a ok will be set to true if the user pressed \gui OK
+ and to false if the user pressed \gui Cancel. The dialog's parent is
+ \a parent. The dialog will be modal and uses the widget \a flags.
+
+ On success, this function returns the integer which has been entered by the
+ user; on failure, it returns the initial \a value.
+
+ Use this static function like this:
+
+ \snippet examples/dialogs/standarddialogs/dialog.cpp 0
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QInputDialog constructors.
+
+ \sa getText(), getDouble(), getItem()
+*/
+
+int QInputDialog::getInt(QWidget *parent, const QString &title, const QString &label, int value,
+ int min, int max, int step, bool *ok, Qt::WindowFlags flags)
+{
+ QInputDialog dialog(parent, flags);
+ dialog.setWindowTitle(title);
+ dialog.setLabelText(label);
+ dialog.setIntRange(min, max);
+ dialog.setIntValue(value);
+ dialog.setIntStep(step);
+
+ int ret = dialog.exec();
+ if (ok)
+ *ok = !!ret;
+ if (ret) {
+ return dialog.intValue();
+ } else {
+ return value;
+ }
+}
+
+/*!
+ Static convenience function to get a floating point number from the user.
+
+ \a title is the text which is displayed in the title bar of the dialog.
+ \a label is the text which is shown to the user (it should say what should
+ be entered).
+ \a value is the default floating point number that the line edit will be
+ set to.
+ \a min and \a max are the minimum and maximum values the user may choose.
+ \a decimals is the maximum number of decimal places the number may have.
+
+ If \a ok is nonnull, *\a ok will be set to true if the user pressed \gui OK
+ and to false if the user pressed \gui Cancel. The dialog's parent is
+ \a parent. The dialog will be modal and uses the widget \a flags.
+
+ This function returns the floating point number which has been entered by
+ the user.
+
+ Use this static function like this:
+
+ \snippet examples/dialogs/standarddialogs/dialog.cpp 1
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QInputDialog constructors.
+
+ \sa getText(), getInt(), getItem()
+*/
+
+double QInputDialog::getDouble(QWidget *parent, const QString &title, const QString &label,
+ double value, double min, double max, int decimals, bool *ok,
+ Qt::WindowFlags flags)
+{
+ QInputDialog dialog(parent, flags);
+ dialog.setWindowTitle(title);
+ dialog.setLabelText(label);
+ dialog.setDoubleDecimals(decimals);
+ dialog.setDoubleRange(min, max);
+ dialog.setDoubleValue(value);
+
+ int ret = dialog.exec();
+ if (ok)
+ *ok = !!ret;
+ if (ret) {
+ return dialog.doubleValue();
+ } else {
+ return value;
+ }
+}
+
+/*!
+ Static convenience function to let the user select an item from a string
+ list.
+
+ \a title is the text which is displayed in the title bar of the dialog.
+ \a label is the text which is shown to the user (it should say what should
+ be entered).
+ \a items is the string list which is inserted into the combobox.
+ \a current is the number of the item which should be the current item.
+ \a inputMethodHints is the input method hints that will be used if the
+ combobox is editable and an input method is active.
+
+ If \a editable is true the user can enter their own text; otherwise the
+ user may only select one of the existing items.
+
+ If \a ok is nonnull \e *\a ok will be set to true if the user pressed
+ \gui OK and to false if the user pressed \gui Cancel. The dialog's parent
+ is \a parent. The dialog will be modal and uses the widget \a flags.
+
+ This function returns the text of the current item, or if \a editable is
+ true, the current text of the combobox.
+
+ Use this static function like this:
+
+ \snippet examples/dialogs/standarddialogs/dialog.cpp 2
+
+ \warning Do not delete \a parent during the execution of the dialog. If you
+ want to do this, you should create the dialog yourself using one of the
+ QInputDialog constructors.
+
+ \sa getText(), getInt(), getDouble()
+*/
+
+QString QInputDialog::getItem(QWidget *parent, const QString &title, const QString &label,
+ const QStringList &items, int current, bool editable, bool *ok,
+ Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
+{
+ QString text(items.value(current));
+
+ QInputDialog dialog(parent, flags);
+ dialog.setWindowTitle(title);
+ dialog.setLabelText(label);
+ dialog.setComboBoxItems(items);
+ dialog.setTextValue(text);
+ dialog.setComboBoxEditable(editable);
+ dialog.setInputMethodHints(inputMethodHints);
+
+ int ret = dialog.exec();
+ if (ok)
+ *ok = !!ret;
+ if (ret) {
+ return dialog.textValue();
+ } else {
+ return text;
+ }
+}
+
+/*!
+ \internal
+*/
+// ### Qt 5: Use only the version above.
+QString QInputDialog::getItem(QWidget *parent, const QString &title, const QString &label,
+ const QStringList &items, int current, bool editable, bool *ok,
+ Qt::WindowFlags flags)
+{
+ return getItem(parent, title, label, items, current, editable, ok, flags, Qt::ImhNone);
+}
+
+/*!
+ \obsolete
+
+ Use getInt() instead.
+*/
+int QInputDialog::getInteger(QWidget *parent, const QString &title, const QString &label,
+ int value, int min, int max, int step, bool *ok,
+ Qt::WindowFlags flags)
+{
+ return getInt(parent, title, label, value, min, max, step, ok, flags);
+}
+
+/*!
+ \fn QString QInputDialog::getText(const QString &title, const QString &label,
+ QLineEdit::EchoMode echo = QLineEdit::Normal,
+ const QString &text = QString(), bool *ok = 0,
+ QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
+
+ Call getText(\a parent, \a title, \a label, \a echo, \a text, \a
+ ok, \a flags) instead.
+
+ The \a name parameter is ignored.
+*/
+
+/*!
+ \fn int QInputDialog::getInteger(const QString &title, const QString &label, int value = 0,
+ int min = -2147483647, int max = 2147483647,
+ int step = 1, bool *ok = 0,
+ QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
+
+
+ Call getInteger(\a parent, \a title, \a label, \a value, \a
+ min, \a max, \a step, \a ok, \a flags) instead.
+
+ The \a name parameter is ignored.
+*/
+
+/*!
+ \fn double QInputDialog::getDouble(const QString &title, const QString &label, double value = 0,
+ double min = -2147483647, double max = 2147483647,
+ int decimals = 1, bool *ok = 0,
+ QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
+
+ Call getDouble(\a parent, \a title, \a label, \a value, \a
+ min, \a max, \a decimals, \a ok, \a flags).
+
+ The \a name parameter is ignored.
+*/
+
+/*!
+ \fn QString QInputDialog::getItem(const QString &title, const QString &label, const QStringList &list,
+ int current = 0, bool editable = true, bool *ok = 0,
+ QWidget *parent = 0, const char *name = 0, Qt::WindowFlags flags = 0)
+
+ Call getItem(\a parent, \a title, \a label, \a list, \a current,
+ \a editable, \a ok, \a flags) instead.
+
+ The \a name parameter is ignored.
+*/
+
+/*!
+ \fn void QInputDialog::doubleValueChanged(double value)
+
+ This signal is emitted whenever the double value changes in the dialog.
+ The current value is specified by \a value.
+
+ This signal is only relevant when the input dialog is used in
+ DoubleInput mode.
+*/
+
+/*!
+ \fn void QInputDialog::doubleValueSelected(double value)
+
+ This signal is emitted whenever the user selects a double value by
+ accepting the dialog; for example, by clicking the \gui{OK} button.
+ The selected value is specified by \a value.
+
+ This signal is only relevant when the input dialog is used in
+ DoubleInput mode.
+*/
+
+/*!
+ \fn void QInputDialog::intValueChanged(int value)
+
+ This signal is emitted whenever the integer value changes in the dialog.
+ The current value is specified by \a value.
+
+ This signal is only relevant when the input dialog is used in
+ IntInput mode.
+*/
+
+/*!
+ \fn void QInputDialog::intValueSelected(int value)
+
+ This signal is emitted whenever the user selects a integer value by
+ accepting the dialog; for example, by clicking the \gui{OK} button.
+ The selected value is specified by \a value.
+
+ This signal is only relevant when the input dialog is used in
+ IntInput mode.
+*/
+
+/*!
+ \fn void QInputDialog::textValueChanged(const QString &text)
+
+ This signal is emitted whenever the text string changes in the dialog.
+ The current string is specified by \a text.
+
+ This signal is only relevant when the input dialog is used in
+ TextInput mode.
+*/
+
+/*!
+ \fn void QInputDialog::textValueSelected(const QString &text)
+
+ This signal is emitted whenever the user selects a text string by
+ accepting the dialog; for example, by clicking the \gui{OK} button.
+ The selected string is specified by \a text.
+
+ This signal is only relevant when the input dialog is used in
+ TextInput mode.
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qinputdialog.cpp"
+
+#endif // QT_NO_INPUTDIALOG
diff --git a/src/widgets/dialogs/qinputdialog.h b/src/widgets/dialogs/qinputdialog.h
new file mode 100644
index 0000000000..51411c7ae1
--- /dev/null
+++ b/src/widgets/dialogs/qinputdialog.h
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QINPUTDIALOG_H
+#define QINPUTDIALOG_H
+
+#include <QtWidgets/qdialog.h>
+#include <QtCore/qstring.h>
+#include <QtWidgets/qlineedit.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_INPUTDIALOG
+
+class QInputDialogPrivate;
+
+class Q_WIDGETS_EXPORT QInputDialog : public QDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QInputDialog)
+// Q_ENUMS(InputMode InputDialogOption)
+ QDOC_PROPERTY(InputMode inputMode READ inputMode WRITE setInputMode)
+ QDOC_PROPERTY(QString labelText READ labelText WRITE setLabelText)
+ QDOC_PROPERTY(InputDialogOptions options READ options WRITE setOptions)
+ QDOC_PROPERTY(QString textValue READ textValue WRITE setTextValue NOTIFY textValueChanged)
+ QDOC_PROPERTY(int intValue READ intValue WRITE setIntValue NOTIFY intValueChanged)
+ QDOC_PROPERTY(int doubleValue READ doubleValue WRITE setDoubleValue NOTIFY doubleValueChanged)
+ QDOC_PROPERTY(QLineEdit::EchoMode textEchoMode READ textEchoMode WRITE setTextEchoMode)
+ QDOC_PROPERTY(bool comboBoxEditable READ isComboBoxEditable WRITE setComboBoxEditable)
+ QDOC_PROPERTY(QStringList comboBoxItems READ comboBoxItems WRITE setComboBoxItems)
+ QDOC_PROPERTY(int intMinimum READ intMinimum WRITE setIntMinimum)
+ QDOC_PROPERTY(int intMaximum READ intMaximum WRITE setIntMaximum)
+ QDOC_PROPERTY(int intStep READ intStep WRITE setIntStep)
+ QDOC_PROPERTY(double doubleMinimum READ doubleMinimum WRITE setDoubleMinimum)
+ QDOC_PROPERTY(double doubleMaximum READ doubleMaximum WRITE setDoubleMaximum)
+ QDOC_PROPERTY(int doubleDecimals READ doubleDecimals WRITE setDoubleDecimals)
+ QDOC_PROPERTY(QString okButtonText READ okButtonText WRITE setOkButtonText)
+ QDOC_PROPERTY(QString cancelButtonText READ cancelButtonText WRITE setCancelButtonText)
+
+public:
+ enum InputDialogOption {
+ NoButtons = 0x00000001,
+ UseListViewForComboBoxItems = 0x00000002
+ };
+
+ Q_DECLARE_FLAGS(InputDialogOptions, InputDialogOption)
+
+ enum InputMode {
+ TextInput,
+ IntInput,
+ DoubleInput
+ };
+
+ QInputDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~QInputDialog();
+
+ void setInputMode(InputMode mode);
+ InputMode inputMode() const;
+
+ void setLabelText(const QString &text);
+ QString labelText() const;
+
+ void setOption(InputDialogOption option, bool on = true);
+ bool testOption(InputDialogOption option) const;
+ void setOptions(InputDialogOptions options);
+ InputDialogOptions options() const;
+
+ void setTextValue(const QString &text);
+ QString textValue() const;
+
+ void setTextEchoMode(QLineEdit::EchoMode mode);
+ QLineEdit::EchoMode textEchoMode() const;
+
+ void setComboBoxEditable(bool editable);
+ bool isComboBoxEditable() const;
+
+ void setComboBoxItems(const QStringList &items);
+ QStringList comboBoxItems() const;
+
+ void setIntValue(int value);
+ int intValue() const;
+
+ void setIntMinimum(int min);
+ int intMinimum() const;
+
+ void setIntMaximum(int max);
+ int intMaximum() const;
+
+ void setIntRange(int min, int max);
+
+ void setIntStep(int step);
+ int intStep() const;
+
+ void setDoubleValue(double value);
+ double doubleValue() const;
+
+ void setDoubleMinimum(double min);
+ double doubleMinimum() const;
+
+ void setDoubleMaximum(double max);
+ double doubleMaximum() const;
+
+ void setDoubleRange(double min, double max);
+
+ void setDoubleDecimals(int decimals);
+ int doubleDecimals() const;
+
+ void setOkButtonText(const QString &text);
+ QString okButtonText() const;
+
+ void setCancelButtonText(const QString &text);
+ QString cancelButtonText() const;
+
+#ifdef Q_NO_USING_KEYWORD
+#ifndef Q_QDOC
+ void open() { QDialog::open(); }
+#endif
+#else
+ using QDialog::open;
+#endif
+ void open(QObject *receiver, const char *member);
+
+ QSize minimumSizeHint() const;
+ QSize sizeHint() const;
+
+ void setVisible(bool visible);
+
+#ifdef Q_QDOC
+ static QString getText(QWidget *parent, const QString &title, const QString &label,
+ QLineEdit::EchoMode echo = QLineEdit::Normal,
+ const QString &text = QString(), bool *ok = 0, Qt::WindowFlags flags = 0,
+ Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
+ static QString getItem(QWidget *parent, const QString &title, const QString &label,
+ const QStringList &items, int current = 0, bool editable = true,
+ bool *ok = 0, Qt::WindowFlags flags = 0,
+ Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
+#else
+ static QString getText(QWidget *parent, const QString &title, const QString &label,
+ QLineEdit::EchoMode echo = QLineEdit::Normal,
+ const QString &text = QString(), bool *ok = 0, Qt::WindowFlags flags = 0);
+ static QString getItem(QWidget *parent, const QString &title, const QString &label,
+ const QStringList &items, int current = 0, bool editable = true,
+ bool *ok = 0, Qt::WindowFlags flags = 0);
+ static QString getText(QWidget *parent, const QString &title, const QString &label,
+ QLineEdit::EchoMode echo,
+ const QString &text, bool *ok, Qt::WindowFlags flags,
+ Qt::InputMethodHints inputMethodHints);
+ static QString getItem(QWidget *parent, const QString &title, const QString &label,
+ const QStringList &items, int current, bool editable,
+ bool *ok, Qt::WindowFlags flags,
+ Qt::InputMethodHints inputMethodHints);
+#endif
+ static int getInt(QWidget *parent, const QString &title, const QString &label, int value = 0,
+ int minValue = -2147483647, int maxValue = 2147483647,
+ int step = 1, bool *ok = 0, Qt::WindowFlags flags = 0);
+ static double getDouble(QWidget *parent, const QString &title, const QString &label, double value = 0,
+ double minValue = -2147483647, double maxValue = 2147483647,
+ int decimals = 1, bool *ok = 0, Qt::WindowFlags flags = 0);
+
+ // obsolete
+ static int getInteger(QWidget *parent, const QString &title, const QString &label, int value = 0,
+ int minValue = -2147483647, int maxValue = 2147483647,
+ int step = 1, bool *ok = 0, Qt::WindowFlags flags = 0);
+
+#ifdef QT3_SUPPORT
+ inline static QT3_SUPPORT QString getText(const QString &title, const QString &label,
+ QLineEdit::EchoMode echo = QLineEdit::Normal,
+ const QString &text = QString(), bool *ok = 0,
+ QWidget *parent = 0, const char * = 0, Qt::WindowFlags flags = 0)
+ { return getText(parent, title, label, echo, text, ok, flags); }
+ inline static QT3_SUPPORT int getInteger(const QString &title, const QString &label, int value = 0,
+ int minValue = -2147483647, int maxValue = 2147483647,
+ int step = 1, bool *ok = 0,
+ QWidget *parent = 0, const char * = 0, Qt::WindowFlags flags = 0)
+ { return getInteger(parent, title, label, value, minValue, maxValue, step, ok, flags); }
+ inline static QT3_SUPPORT double getDouble(const QString &title, const QString &label, double value = 0,
+ double minValue = -2147483647, double maxValue = 2147483647,
+ int decimals = 1, bool *ok = 0,
+ QWidget *parent = 0, const char * = 0, Qt::WindowFlags flags = 0)
+ { return getDouble(parent, title, label, value, minValue, maxValue, decimals, ok, flags); }
+ inline static QT3_SUPPORT QString getItem(const QString &title, const QString &label, const QStringList &list,
+ int current = 0, bool editable = true, bool *ok = 0,
+ QWidget *parent = 0, const char * = 0, Qt::WindowFlags flags = 0)
+ { return getItem(parent, title, label, list, current, editable, ok, flags); }
+#endif
+
+Q_SIGNALS:
+ // ### emit signals!
+ void textValueChanged(const QString &text);
+ void textValueSelected(const QString &text);
+ void intValueChanged(int value);
+ void intValueSelected(int value);
+ void doubleValueChanged(double value);
+ void doubleValueSelected(double value);
+
+
+public:
+ void done(int result); // ### Qt 5: Make protected.
+
+private:
+ Q_DISABLE_COPY(QInputDialog)
+ Q_PRIVATE_SLOT(d_func(), void _q_textChanged(const QString&))
+ Q_PRIVATE_SLOT(d_func(), void _q_currentRowChanged(const QModelIndex&, const QModelIndex&))
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QInputDialog::InputDialogOptions)
+
+#endif // QT_NO_INPUTDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QINPUTDIALOG_H
diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp
new file mode 100644
index 0000000000..26180ab38b
--- /dev/null
+++ b/src/widgets/dialogs/qmessagebox.cpp
@@ -0,0 +1,2753 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtWidgets/qmessagebox.h>
+
+#ifndef QT_NO_MESSAGEBOX
+
+#include <QtWidgets/qdialogbuttonbox.h>
+#include "private/qlabel_p.h"
+#include "private/qapplication_p.h"
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+#include <QtWidgets/qstyle.h>
+#include <QtWidgets/qstyleoption.h>
+#include <QtWidgets/qgridlayout.h>
+#include <QtWidgets/qdesktopwidget.h>
+#include <QtWidgets/qpushbutton.h>
+#include <QtWidgets/qaccessible.h>
+#include <QtWidgets/qicon.h>
+#include <QtGui/qtextdocument.h>
+#include <QtWidgets/qapplication.h>
+#include <QtWidgets/qtextedit.h>
+#include <QtWidgets/qtextbrowser.h>
+#include <QtWidgets/qmenu.h>
+#include "qdialog_p.h"
+#include <QtGui/qfont.h>
+#include <QtGui/qfontmetrics.h>
+#include <QtGui/qclipboard.h>
+
+#ifndef QT_NO_STYLE_S60
+#include <qs60style.h>
+#endif
+
+#ifdef Q_WS_WINCE
+extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_smartphone();//defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_pocket_pc(); //defined in qguifunctions_wince.cpp
+
+#include "qguifunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+enum Button { Old_Ok = 1, Old_Cancel = 2, Old_Yes = 3, Old_No = 4, Old_Abort = 5, Old_Retry = 6,
+ Old_Ignore = 7, Old_YesAll = 8, Old_NoAll = 9, Old_ButtonMask = 0xFF,
+ NewButtonMask = 0xFFFFFC00 };
+
+enum DetailButtonLabel { ShowLabel = 0, HideLabel = 1 };
+#ifndef QT_NO_TEXTEDIT
+class QMessageBoxDetailsText : public QWidget
+{
+public:
+ class TextEdit : public QTextEdit
+ {
+ public:
+ TextEdit(QWidget *parent=0) : QTextEdit(parent) { }
+ void contextMenuEvent(QContextMenuEvent * e)
+ {
+#ifndef QT_NO_CONTEXTMENU
+ QMenu *menu = createStandardContextMenu();
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+ menu->popup(e->globalPos());
+#else
+ Q_UNUSED(e);
+#endif
+ }
+ };
+
+ QMessageBoxDetailsText(QWidget *parent=0)
+ : QWidget(parent)
+ {
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ QFrame *line = new QFrame(this);
+ line->setFrameShape(QFrame::HLine);
+ line->setFrameShadow(QFrame::Sunken);
+ layout->addWidget(line);
+ textEdit = new TextEdit();
+ textEdit->setFixedHeight(100);
+ textEdit->setFocusPolicy(Qt::NoFocus);
+ textEdit->setReadOnly(true);
+ layout->addWidget(textEdit);
+ setLayout(layout);
+ }
+ void setText(const QString &text) { textEdit->setPlainText(text); }
+ QString text() const { return textEdit->toPlainText(); }
+private:
+ TextEdit *textEdit;
+};
+#endif // QT_NO_TEXTEDIT
+
+class DetailButton : public QPushButton
+{
+public:
+ DetailButton(QWidget *parent) : QPushButton(label(ShowLabel), parent)
+ {
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ }
+
+ QString label(DetailButtonLabel label) const
+ { return label == ShowLabel ? QMessageBox::tr("Show Details...") : QMessageBox::tr("Hide Details..."); }
+
+ void setLabel(DetailButtonLabel lbl)
+ { setText(label(lbl)); }
+
+ QSize sizeHint() const
+ {
+ ensurePolished();
+ QStyleOptionButton opt;
+ initStyleOption(&opt);
+ const QFontMetrics fm = fontMetrics();
+ opt.text = label(ShowLabel);
+ QSize sz = fm.size(Qt::TextShowMnemonic, opt.text);
+ QSize ret = style()->sizeFromContents(QStyle::CT_PushButton, &opt, sz, this).
+ expandedTo(QApplication::globalStrut());
+ opt.text = label(HideLabel);
+ sz = fm.size(Qt::TextShowMnemonic, opt.text);
+ ret.expandedTo(style()->sizeFromContents(QStyle::CT_PushButton, &opt, sz, this).
+ expandedTo(QApplication::globalStrut()));
+ return ret;
+ }
+};
+
+
+class QMessageBoxPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QMessageBox)
+
+public:
+ QMessageBoxPrivate() : escapeButton(0), defaultButton(0), clickedButton(0), detailsButton(0),
+#ifndef QT_NO_TEXTEDIT
+ detailsText(0),
+#endif
+ compatMode(false), autoAddOkButton(true),
+ detectedEscapeButton(0), informativeLabel(0) { }
+
+ void init(const QString &title = QString(), const QString &text = QString());
+ void _q_buttonClicked(QAbstractButton *);
+
+ QAbstractButton *findButton(int button0, int button1, int button2, int flags);
+ void addOldButtons(int button0, int button1, int button2);
+
+ QAbstractButton *abstractButtonForId(int id) const;
+ int execReturnCode(QAbstractButton *button);
+
+ void detectEscapeButton();
+ void updateSize();
+ int layoutMinimumWidth();
+ void retranslateStrings();
+
+#ifdef Q_WS_WINCE
+ void hideSpecial();
+#endif
+
+ static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
+ const QString &title, const QString &text,
+ int button0, int button1, int button2);
+ static int showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
+ const QString &title, const QString &text,
+ const QString &button0Text,
+ const QString &button1Text,
+ const QString &button2Text,
+ int defaultButtonNumber,
+ int escapeButtonNumber);
+
+ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent,
+ QMessageBox::Icon icon, const QString& title, const QString& text,
+ QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton);
+
+ static QPixmap standardIcon(QMessageBox::Icon icon, QMessageBox *mb);
+
+ QLabel *label;
+ QMessageBox::Icon icon;
+ QLabel *iconLabel;
+ QDialogButtonBox *buttonBox;
+ QList<QAbstractButton *> customButtonList;
+ QAbstractButton *escapeButton;
+ QPushButton *defaultButton;
+ QAbstractButton *clickedButton;
+ DetailButton *detailsButton;
+#ifndef QT_NO_TEXTEDIT
+ QMessageBoxDetailsText *detailsText;
+#endif
+ bool compatMode;
+ bool autoAddOkButton;
+ QAbstractButton *detectedEscapeButton;
+ QLabel *informativeLabel;
+#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
+ QTextBrowser *textBrowser;
+#endif
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+ QByteArray signalToDisconnectOnClose;
+};
+
+void QMessageBoxPrivate::init(const QString &title, const QString &text)
+{
+ Q_Q(QMessageBox);
+
+ label = new QLabel;
+ label->setObjectName(QLatin1String("qt_msgbox_label"));
+ label->setTextInteractionFlags(Qt::TextInteractionFlags(q->style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, q)));
+ label->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
+ label->setOpenExternalLinks(true);
+#if defined(Q_WS_MAC)
+ label->setContentsMargins(16, 0, 0, 0);
+#elif !defined(Q_WS_QWS)
+ label->setContentsMargins(2, 0, 0, 0);
+ label->setIndent(9);
+#endif
+ icon = QMessageBox::NoIcon;
+ iconLabel = new QLabel;
+ iconLabel->setObjectName(QLatin1String("qt_msgboxex_icon_label"));
+ iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ buttonBox = new QDialogButtonBox;
+ buttonBox->setObjectName(QLatin1String("qt_msgbox_buttonbox"));
+ buttonBox->setCenterButtons(q->style()->styleHint(QStyle::SH_MessageBox_CenterButtons, 0, q));
+ QObject::connect(buttonBox, SIGNAL(clicked(QAbstractButton*)),
+ q, SLOT(_q_buttonClicked(QAbstractButton*)));
+
+ QGridLayout *grid = new QGridLayout;
+#ifndef Q_WS_MAC
+ grid->addWidget(iconLabel, 0, 0, 2, 1, Qt::AlignTop);
+ grid->addWidget(label, 0, 1, 1, 1);
+ // -- leave space for information label --
+ grid->addWidget(buttonBox, 2, 0, 1, 2);
+#else
+ grid->setMargin(0);
+ grid->setVerticalSpacing(8);
+ grid->setHorizontalSpacing(0);
+ q->setContentsMargins(24, 15, 24, 20);
+ grid->addWidget(iconLabel, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft);
+ grid->addWidget(label, 0, 1, 1, 1);
+ // -- leave space for information label --
+ grid->setRowStretch(1, 100);
+ grid->setRowMinimumHeight(2, 6);
+ grid->addWidget(buttonBox, 3, 1, 1, 1);
+#endif
+
+ grid->setSizeConstraint(QLayout::SetNoConstraint);
+ q->setLayout(grid);
+
+ if (!title.isEmpty() || !text.isEmpty()) {
+ q->setWindowTitle(title);
+ q->setText(text);
+ }
+ q->setModal(true);
+
+#ifdef Q_WS_MAC
+ QFont f = q->font();
+ f.setBold(true);
+ label->setFont(f);
+#endif
+ retranslateStrings();
+}
+
+int QMessageBoxPrivate::layoutMinimumWidth()
+{
+ layout->activate();
+ return layout->totalMinimumSize().width();
+}
+
+void QMessageBoxPrivate::updateSize()
+{
+ Q_Q(QMessageBox);
+
+ if (!q->isVisible())
+ return;
+
+ QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size();
+#if defined(Q_WS_QWS) || defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN)
+ // the width of the screen, less the window border.
+ int hardLimit = screenSize.width() - (q->frameGeometry().width() - q->geometry().width());
+#else
+ int hardLimit = qMin(screenSize.width() - 480, 1000); // can never get bigger than this
+ // on small screens allows the messagebox be the same size as the screen
+ if (screenSize.width() <= 1024)
+ hardLimit = screenSize.width();
+#endif
+#ifdef Q_WS_MAC
+ int softLimit = qMin(screenSize.width()/2, 420);
+#elif defined(Q_WS_QWS)
+ int softLimit = qMin(hardLimit, 500);
+#else
+ // note: ideally on windows, hard and soft limits but it breaks compat
+#ifndef Q_WS_WINCE
+ int softLimit = qMin(screenSize.width()/2, 500);
+#else
+ int softLimit = qMin(screenSize.width() * 3 / 4, 500);
+#endif //Q_WS_WINCE
+#endif
+
+ if (informativeLabel)
+ informativeLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+
+ label->setWordWrap(false); // makes the label return min size
+ int width = layoutMinimumWidth();
+
+ if (width > softLimit) {
+ label->setWordWrap(true);
+ width = qMax(softLimit, layoutMinimumWidth());
+
+ if (width > hardLimit) {
+ label->d_func()->ensureTextControl();
+ if (QWidgetTextControl *control = label->d_func()->control) {
+ QTextOption opt = control->document()->defaultTextOption();
+ opt.setWrapMode(QTextOption::WrapAnywhere);
+ control->document()->setDefaultTextOption(opt);
+ }
+ width = hardLimit;
+ }
+ }
+#ifdef Q_WS_S60
+ // in S60 portait messageBoxes should always occupy maximum width
+ if (QApplication::desktop()->size().height() > QApplication::desktop()->size().width()){
+ width = hardLimit;
+ } else {
+ // in landscape the messageBoxes should be of same width as in portrait
+ width = qMin(QApplication::desktop()->size().height(), hardLimit);
+ }
+#endif
+
+ if (informativeLabel) {
+ label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
+ QSizePolicy policy(QSizePolicy::Minimum, QSizePolicy::Preferred);
+ policy.setHeightForWidth(true);
+ informativeLabel->setSizePolicy(policy);
+ width = qMax(width, layoutMinimumWidth());
+ if (width > hardLimit) { // longest word is really big, so wrap anywhere
+ informativeLabel->d_func()->ensureTextControl();
+ if (QWidgetTextControl *control = informativeLabel->d_func()->control) {
+ QTextOption opt = control->document()->defaultTextOption();
+ opt.setWrapMode(QTextOption::WrapAnywhere);
+ control->document()->setDefaultTextOption(opt);
+ }
+ width = hardLimit;
+ }
+ policy.setHeightForWidth(label->wordWrap());
+ label->setSizePolicy(policy);
+ }
+
+ QFontMetrics fm(QApplication::font("QWorkspaceTitleBar"));
+ int windowTitleWidth = qMin(fm.width(q->windowTitle()) + 50, hardLimit);
+ if (windowTitleWidth > width)
+ width = windowTitleWidth;
+
+ layout->activate();
+ int height = (layout->hasHeightForWidth())
+ ? layout->totalHeightForWidth(width)
+ : layout->totalMinimumSize().height();
+
+#ifndef QT_NO_STYLE_S60
+ QS60Style *s60Style = 0;
+ s60Style = qobject_cast<QS60Style *>(QApplication::style());
+
+ //use custom pixel metric to deduce the minimum height of the messagebox
+ if (s60Style)
+ height = qMax(height, s60Style->pixelMetric((QStyle::PixelMetric)PM_MessageBoxHeight));
+#endif
+
+ q->setFixedSize(width, height);
+ QCoreApplication::removePostedEvents(q, QEvent::LayoutRequest);
+}
+
+
+#ifdef Q_WS_WINCE
+/*!
+ \internal
+ Hides special buttons which are rather shown in the title bar
+ on WinCE, to conserve screen space.
+*/
+
+void QMessageBoxPrivate::hideSpecial()
+{
+ Q_Q(QMessageBox);
+ QList<QPushButton*> list = q->findChildren<QPushButton*>();
+ for (int i=0; i<list.size(); ++i) {
+ QPushButton *pb = list.at(i);
+ QString text = pb->text();
+ text.remove(QChar::fromLatin1('&'));
+ if (text == QApplication::translate("QMessageBox", "OK" ))
+ pb->setFixedSize(0,0);
+ }
+}
+#endif
+
+static int oldButton(int button)
+{
+ switch (button & QMessageBox::ButtonMask) {
+ case QMessageBox::Ok:
+ return Old_Ok;
+ case QMessageBox::Cancel:
+ return Old_Cancel;
+ case QMessageBox::Yes:
+ return Old_Yes;
+ case QMessageBox::No:
+ return Old_No;
+ case QMessageBox::Abort:
+ return Old_Abort;
+ case QMessageBox::Retry:
+ return Old_Retry;
+ case QMessageBox::Ignore:
+ return Old_Ignore;
+ case QMessageBox::YesToAll:
+ return Old_YesAll;
+ case QMessageBox::NoToAll:
+ return Old_NoAll;
+ default:
+ return 0;
+ }
+}
+
+int QMessageBoxPrivate::execReturnCode(QAbstractButton *button)
+{
+ int ret = buttonBox->standardButton(button);
+ if (ret == QMessageBox::NoButton) {
+ ret = customButtonList.indexOf(button); // if button == 0, correctly sets ret = -1
+ } else if (compatMode) {
+ ret = oldButton(ret);
+ }
+ return ret;
+}
+
+void QMessageBoxPrivate::_q_buttonClicked(QAbstractButton *button)
+{
+ Q_Q(QMessageBox);
+#ifndef QT_NO_TEXTEDIT
+ if (detailsButton && detailsText && button == detailsButton) {
+ detailsButton->setLabel(detailsText->isHidden() ? HideLabel : ShowLabel);
+ detailsText->setHidden(!detailsText->isHidden());
+ updateSize();
+ } else
+#endif
+ {
+ clickedButton = button;
+ q->done(execReturnCode(button)); // does not trigger closeEvent
+ emit q->buttonClicked(button);
+
+ if (receiverToDisconnectOnClose) {
+ QObject::disconnect(q, signalToDisconnectOnClose, receiverToDisconnectOnClose,
+ memberToDisconnectOnClose);
+ receiverToDisconnectOnClose = 0;
+ }
+ signalToDisconnectOnClose.clear();
+ memberToDisconnectOnClose.clear();
+ }
+}
+
+/*!
+ \class QMessageBox
+
+ \brief The QMessageBox class provides a modal dialog for informing
+ the user or for asking the user a question and receiving an answer.
+
+ \ingroup standard-dialogs
+
+
+ A message box displays a primary \l{QMessageBox::text}{text} to
+ alert the user to a situation, an \l{QMessageBox::informativeText}
+ {informative text} to further explain the alert or to ask the user
+ a question, and an optional \l{QMessageBox::detailedText}
+ {detailed text} to provide even more data if the user requests
+ it. A message box can also display an \l{QMessageBox::icon} {icon}
+ and \l{QMessageBox::standardButtons} {standard buttons} for
+ accepting a user response.
+
+ Two APIs for using QMessageBox are provided, the property-based
+ API, and the static functions. Calling one of the static functions
+ is the simpler approach, but it is less flexible than using the
+ property-based API, and the result is less informative. Using the
+ property-based API is recommended.
+
+ \section1 The Property-based API
+
+ To use the property-based API, construct an instance of
+ QMessageBox, set the desired properties, and call exec() to show
+ the message. The simplest configuration is to set only the
+ \l{QMessageBox::text} {message text} property.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 5
+
+ The user must click the \gui{OK} button to dismiss the message
+ box. The rest of the GUI is blocked until the message box is
+ dismissed.
+
+ \image msgbox1.png
+
+ A better approach than just alerting the user to an event is to
+ also ask the user what to do about it. Store the question in the
+ \l{QMessageBox::informativeText} {informative text} property, and
+ set the \l{QMessageBox::standardButtons} {standard buttons}
+ property to the set of buttons you want as the set of user
+ responses. The buttons are specified by combining values from
+ StandardButtons using the bitwise OR operator. The display order
+ for the buttons is platform-dependent. For example, on Windows,
+ \gui{Save} is displayed to the left of \gui{Cancel}, whereas on
+ Mac OS, the order is reversed.
+
+ Mark one of your standard buttons to be your
+ \l{QMessageBox::defaultButton()} {default button}.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 6
+
+ This is the approach recommended in the
+ \l{http://developer.apple.com/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGWindows/chapter_18_section_7.html}
+ {Mac OS X Guidlines}. Similar guidlines apply for the other
+ platforms, but note the different ways the
+ \l{QMessageBox::informativeText} {informative text} is handled for
+ different platforms.
+
+ \image msgbox2.png
+
+ The exec() slot returns the StandardButtons value of the button
+ that was clicked.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 7
+
+ To give the user more information to help him answer the question,
+ set the \l{QMessageBox::detailedText} {detailed text} property. If
+ the \l{QMessageBox::detailedText} {detailed text} property is set,
+ the \gui{Show Details...} button will be shown.
+
+ \image msgbox3.png
+
+ Clicking the \gui{Show Details...} button displays the detailed text.
+
+ \image msgbox4.png
+
+ \section2 Rich Text and the Text Format Property
+
+ The \l{QMessageBox::detailedText} {detailed text} property is
+ always interpreted as plain text. The \l{QMessageBox::text} {main
+ text} and \l{QMessageBox::informativeText} {informative text}
+ properties can be either plain text or rich text. These strings
+ are interpreted according to the setting of the
+ \l{QMessageBox::textFormat} {text format} property. The default
+ setting is \l{Qt::AutoText} {auto-text}.
+
+ Note that for some plain text strings containing XML
+ meta-characters, the auto-text \l{Qt::mightBeRichText()} {rich
+ text detection test} may fail causing your plain text string to be
+ interpreted incorrectly as rich text. In these rare cases, use
+ Qt::convertFromPlainText() to convert your plain text string to a
+ visually equivalent rich text string, or set the
+ \l{QMessageBox::textFormat} {text format} property explicitly with
+ setTextFormat().
+
+ \section2 Severity Levels and the Icon and Pixmap Properties
+
+ QMessageBox supports four predefined message severity levels, or message
+ types, which really only differ in the predefined icon they each show.
+ Specify one of the four predefined message types by setting the
+ \l{QMessageBox::icon}{icon} property to one of the
+ \l{QMessageBox::Icon}{predefined icons}. The following rules are
+ guidelines:
+
+ \table
+ \row
+ \o \img qmessagebox-quest.png
+ \o \l Question
+ \o For asking a question during normal operations.
+ \row
+ \o \img qmessagebox-info.png
+ \o \l Information
+ \o For reporting information about normal operations.
+ \row
+ \o \img qmessagebox-warn.png
+ \o \l Warning
+ \o For reporting non-critical errors.
+ \row
+ \o \img qmessagebox-crit.png
+ \o \l Critical
+ \o For reporting critical errors.
+ \endtable
+
+ \l{QMessageBox::Icon}{Predefined icons} are not defined by QMessageBox, but
+ provided by the style. The default value is \l{QMessageBox::NoIcon}
+ {No Icon}. The message boxes are otherwise the same for all cases. When
+ using a standard icon, use the one recommended in the table, or use the
+ one recommended by the style guidelines for your platform. If none of the
+ standard icons is right for your message box, you can use a custom icon by
+ setting the \l{QMessageBox::iconPixmap}{icon pixmap} property instead of
+ setting the \l{QMessageBox::icon}{icon} property.
+
+ In summary, to set an icon, use \e{either} setIcon() for one of the
+ standard icons, \e{or} setIconPixmap() for a custom icon.
+
+ \section1 The Static Functions API
+
+ Building message boxes with the static functions API, although
+ convenient, is less flexible than using the property-based API,
+ because the static function signatures lack parameters for setting
+ the \l{QMessageBox::informativeText} {informative text} and
+ \l{QMessageBox::detailedText} {detailed text} properties. One
+ work-around for this has been to use the \c{title} parameter as
+ the message box main text and the \c{text} parameter as the
+ message box informative text. Because this has the obvious
+ drawback of making a less readable message box, platform
+ guidelines do not recommend it. The \e{Microsoft Windows User
+ Interface Guidelines} recommend using the
+ \l{QCoreApplication::applicationName} {application name} as the
+ \l{QMessageBox::setWindowTitle()} {window's title}, which means
+ that if you have an informative text in addition to your main
+ text, you must concatenate it to the \c{text} parameter.
+
+ Note that the static function signatures have changed with respect
+ to their button parameters, which are now used to set the
+ \l{QMessageBox::standardButtons} {standard buttons} and the
+ \l{QMessageBox::defaultButton()} {default button}.
+
+ Static functions are available for creating information(),
+ question(), warning(), and critical() message boxes.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 0
+
+ The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
+ how to use QMessageBox and the other built-in Qt dialogs.
+
+ \section1 Advanced Usage
+
+ If the \l{QMessageBox::StandardButtons} {standard buttons} are not
+ flexible enough for your message box, you can use the addButton()
+ overload that takes a text and a ButtonRoleto to add custom
+ buttons. The ButtonRole is used by QMessageBox to determine the
+ ordering of the buttons on screen (which varies according to the
+ platform). You can test the value of clickedButton() after calling
+ exec(). For example,
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 2
+
+ \section1 Default and Escape Keys
+
+ The default button (i.e., the button activated when \key Enter is
+ pressed) can be specified using setDefaultButton(). If a default
+ button is not specified, QMessageBox tries to find one based on
+ the \l{ButtonRole} {button roles} of the buttons used in the
+ message box.
+
+ The escape button (the button activated when \key Esc is pressed)
+ can be specified using setEscapeButton(). If an escape button is
+ not specified, QMessageBox tries to find one using these rules:
+
+ \list 1
+
+ \o If there is only one button, it is the button activated when
+ \key Esc is pressed.
+
+ \o If there is a \l Cancel button, it is the button activated when
+ \key Esc is pressed.
+
+ \o If there is exactly one button having either
+ \l{QMessageBox::RejectRole} {the Reject role} or the
+ \l{QMessageBox::NoRole} {the No role}, it is the button
+ activated when \key Esc is pressed.
+
+ \endlist
+
+ When an escape button can't be determined using these rules,
+ pressing \key Esc has no effect.
+
+ \sa QDialogButtonBox, {fowler}{GUI Design Handbook: Message Box}, {Standard Dialogs Example}, {Application Example}
+*/
+
+/*!
+ \enum QMessageBox::StandardButton
+ \since 4.2
+
+ These enums describe flags for standard buttons. Each button has a
+ defined \l ButtonRole.
+
+ \value Ok An "OK" button defined with the \l AcceptRole.
+ \value Open A "Open" button defined with the \l AcceptRole.
+ \value Save A "Save" button defined with the \l AcceptRole.
+ \value Cancel A "Cancel" button defined with the \l RejectRole.
+ \value Close A "Close" button defined with the \l RejectRole.
+ \value Discard A "Discard" or "Don't Save" button, depending on the platform,
+ defined with the \l DestructiveRole.
+ \value Apply An "Apply" button defined with the \l ApplyRole.
+ \value Reset A "Reset" button defined with the \l ResetRole.
+ \value RestoreDefaults A "Restore Defaults" button defined with the \l ResetRole.
+ \value Help A "Help" button defined with the \l HelpRole.
+ \value SaveAll A "Save All" button defined with the \l AcceptRole.
+ \value Yes A "Yes" button defined with the \l YesRole.
+ \value YesToAll A "Yes to All" button defined with the \l YesRole.
+ \value No A "No" button defined with the \l NoRole.
+ \value NoToAll A "No to All" button defined with the \l NoRole.
+ \value Abort An "Abort" button defined with the \l RejectRole.
+ \value Retry A "Retry" button defined with the \l AcceptRole.
+ \value Ignore An "Ignore" button defined with the \l AcceptRole.
+
+ \value NoButton An invalid button.
+
+ \omitvalue FirstButton
+ \omitvalue LastButton
+
+ The following values are obsolete:
+
+ \value YesAll Use YesToAll instead.
+ \value NoAll Use NoToAll instead.
+ \value Default Use the \c defaultButton argument of
+ information(), warning(), etc. instead, or call
+ setDefaultButton().
+ \value Escape Call setEscapeButton() instead.
+ \value FlagMask
+ \value ButtonMask
+
+ \sa ButtonRole, standardButtons
+*/
+
+/*!
+ \fn void QMessageBox::buttonClicked(QAbstractButton *button)
+
+ This signal is emitted whenever a button is clicked inside the QMessageBox.
+ The button that was clicked in returned in \a button.
+*/
+
+/*!
+ Constructs a message box with no text and no buttons. \a parent is
+ passed to the QDialog constructor.
+
+ On Mac OS X, if you want your message box to appear
+ as a Qt::Sheet of its \a parent, set the message box's
+ \l{setWindowModality()} {window modality} to Qt::WindowModal or use open().
+ Otherwise, the message box will be a standard dialog.
+
+*/
+QMessageBox::QMessageBox(QWidget *parent)
+ : QDialog(*new QMessageBoxPrivate, parent, Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
+{
+ Q_D(QMessageBox);
+ d->init();
+}
+
+/*!
+ Constructs a message box with the given \a icon, \a title, \a
+ text, and standard \a buttons. Standard or custom buttons can be
+ added at any time using addButton(). The \a parent and \a f
+ arguments are passed to the QDialog constructor.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ On Mac OS X, if \a parent is not 0 and you want your message box
+ to appear as a Qt::Sheet of that parent, set the message box's
+ \l{setWindowModality()} {window modality} to Qt::WindowModal
+ (default). Otherwise, the message box will be a standard dialog.
+
+ \sa setWindowTitle(), setText(), setIcon(), setStandardButtons()
+*/
+QMessageBox::QMessageBox(Icon icon, const QString &title, const QString &text,
+ StandardButtons buttons, QWidget *parent,
+ Qt::WindowFlags f)
+: QDialog(*new QMessageBoxPrivate, parent, f | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
+{
+ Q_D(QMessageBox);
+ d->init(title, text);
+ setIcon(icon);
+ if (buttons != NoButton)
+ setStandardButtons(buttons);
+}
+
+/*!
+ Destroys the message box.
+*/
+QMessageBox::~QMessageBox()
+{
+}
+
+/*!
+ \since 4.2
+
+ Adds the given \a button to the message box with the specified \a
+ role.
+
+ \sa removeButton(), button(), setStandardButtons()
+*/
+void QMessageBox::addButton(QAbstractButton *button, ButtonRole role)
+{
+ Q_D(QMessageBox);
+ if (!button)
+ return;
+ removeButton(button);
+ d->buttonBox->addButton(button, (QDialogButtonBox::ButtonRole)role);
+ d->customButtonList.append(button);
+ d->autoAddOkButton = false;
+}
+
+/*!
+ \since 4.2
+ \overload
+
+ Creates a button with the given \a text, adds it to the message box for the
+ specified \a role, and returns it.
+*/
+QPushButton *QMessageBox::addButton(const QString& text, ButtonRole role)
+{
+ Q_D(QMessageBox);
+ QPushButton *pushButton = new QPushButton(text);
+ addButton(pushButton, role);
+ d->updateSize();
+ return pushButton;
+}
+
+/*!
+ \since 4.2
+ \overload
+
+ Adds a standard \a button to the message box if it is valid to do so, and
+ returns the push button.
+
+ \sa setStandardButtons()
+*/
+QPushButton *QMessageBox::addButton(StandardButton button)
+{
+ Q_D(QMessageBox);
+ QPushButton *pushButton = d->buttonBox->addButton((QDialogButtonBox::StandardButton)button);
+ if (pushButton)
+ d->autoAddOkButton = false;
+ return pushButton;
+}
+
+/*!
+ \since 4.2
+
+ Removes \a button from the button box without deleting it.
+
+ \sa addButton(), setStandardButtons()
+*/
+void QMessageBox::removeButton(QAbstractButton *button)
+{
+ Q_D(QMessageBox);
+ d->customButtonList.removeAll(button);
+ if (d->escapeButton == button)
+ d->escapeButton = 0;
+ if (d->defaultButton == button)
+ d->defaultButton = 0;
+ d->buttonBox->removeButton(button);
+ d->updateSize();
+}
+
+/*!
+ \property QMessageBox::standardButtons
+ \brief collection of standard buttons in the message box
+ \since 4.2
+
+ This property controls which standard buttons are used by the message box.
+
+ By default, this property contains no standard buttons.
+
+ \sa addButton()
+*/
+void QMessageBox::setStandardButtons(StandardButtons buttons)
+{
+ Q_D(QMessageBox);
+ d->buttonBox->setStandardButtons(QDialogButtonBox::StandardButtons(int(buttons)));
+
+ QList<QAbstractButton *> buttonList = d->buttonBox->buttons();
+ if (!buttonList.contains(d->escapeButton))
+ d->escapeButton = 0;
+ if (!buttonList.contains(d->defaultButton))
+ d->defaultButton = 0;
+ d->autoAddOkButton = false;
+ d->updateSize();
+}
+
+QMessageBox::StandardButtons QMessageBox::standardButtons() const
+{
+ Q_D(const QMessageBox);
+ return QMessageBox::StandardButtons(int(d->buttonBox->standardButtons()));
+}
+
+/*!
+ \since 4.2
+
+ Returns the standard button enum value corresponding to the given \a button,
+ or NoButton if the given \a button isn't a standard button.
+
+ \sa button(), standardButtons()
+*/
+QMessageBox::StandardButton QMessageBox::standardButton(QAbstractButton *button) const
+{
+ Q_D(const QMessageBox);
+ return (QMessageBox::StandardButton)d->buttonBox->standardButton(button);
+}
+
+/*!
+ \since 4.2
+
+ Returns a pointer corresponding to the standard button \a which,
+ or 0 if the standard button doesn't exist in this message box.
+
+ \sa standardButtons, standardButton()
+*/
+QAbstractButton *QMessageBox::button(StandardButton which) const
+{
+ Q_D(const QMessageBox);
+ return d->buttonBox->button(QDialogButtonBox::StandardButton(which));
+}
+
+/*!
+ \since 4.2
+
+ Returns the button that is activated when escape is pressed.
+
+ By default, QMessageBox attempts to automatically detect an
+ escape button as follows:
+
+ \list 1
+ \o If there is only one button, it is made the escape button.
+ \o If there is a \l Cancel button, it is made the escape button.
+ \o On Mac OS X only, if there is exactly one button with the role
+ QMessageBox::RejectRole, it is made the escape button.
+ \endlist
+
+ When an escape button could not be automatically detected, pressing
+ \key Esc has no effect.
+
+ \sa addButton()
+*/
+QAbstractButton *QMessageBox::escapeButton() const
+{
+ Q_D(const QMessageBox);
+ return d->escapeButton;
+}
+
+/*!
+ \since 4.2
+
+ Sets the button that gets activated when the \key Escape key is
+ pressed to \a button.
+
+ \sa addButton(), clickedButton()
+*/
+void QMessageBox::setEscapeButton(QAbstractButton *button)
+{
+ Q_D(QMessageBox);
+ if (d->buttonBox->buttons().contains(button))
+ d->escapeButton = button;
+}
+
+/*!
+ \since 4.3
+
+ Sets the buttons that gets activated when the \key Escape key is
+ pressed to \a button.
+
+ \sa addButton(), clickedButton()
+*/
+void QMessageBox::setEscapeButton(QMessageBox::StandardButton button)
+{
+ Q_D(QMessageBox);
+ setEscapeButton(d->buttonBox->button(QDialogButtonBox::StandardButton(button)));
+}
+
+void QMessageBoxPrivate::detectEscapeButton()
+{
+ if (escapeButton) { // escape button explicitly set
+ detectedEscapeButton = escapeButton;
+ return;
+ }
+
+ // Cancel button automatically becomes escape button
+ detectedEscapeButton = buttonBox->button(QDialogButtonBox::Cancel);
+ if (detectedEscapeButton)
+ return;
+
+ // If there is only one button, make it the escape button
+ const QList<QAbstractButton *> buttons = buttonBox->buttons();
+ if (buttons.count() == 1) {
+ detectedEscapeButton = buttons.first();
+ return;
+ }
+
+ // if the message box has one RejectRole button, make it the escape button
+ for (int i = 0; i < buttons.count(); i++) {
+ if (buttonBox->buttonRole(buttons.at(i)) == QDialogButtonBox::RejectRole) {
+ if (detectedEscapeButton) { // already detected!
+ detectedEscapeButton = 0;
+ break;
+ }
+ detectedEscapeButton = buttons.at(i);
+ }
+ }
+ if (detectedEscapeButton)
+ return;
+
+ // if the message box has one NoRole button, make it the escape button
+ for (int i = 0; i < buttons.count(); i++) {
+ if (buttonBox->buttonRole(buttons.at(i)) == QDialogButtonBox::NoRole) {
+ if (detectedEscapeButton) { // already detected!
+ detectedEscapeButton = 0;
+ break;
+ }
+ detectedEscapeButton = buttons.at(i);
+ }
+ }
+}
+
+/*!
+ \since 4.2
+
+ Returns the button that was clicked by the user,
+ or 0 if the user hit the \key Esc key and
+ no \l{setEscapeButton()}{escape button} was set.
+
+ If exec() hasn't been called yet, returns 0.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qmessagebox.cpp 3
+
+ \sa standardButton(), button()
+*/
+QAbstractButton *QMessageBox::clickedButton() const
+{
+ Q_D(const QMessageBox);
+ return d->clickedButton;
+}
+
+/*!
+ \since 4.2
+
+ Returns the button that should be the message box's
+ \l{QPushButton::setDefault()}{default button}. Returns 0
+ if no default button was set.
+
+ \sa addButton(), QPushButton::setDefault()
+*/
+QPushButton *QMessageBox::defaultButton() const
+{
+ Q_D(const QMessageBox);
+ return d->defaultButton;
+}
+
+/*!
+ \since 4.2
+
+ Sets the message box's \l{QPushButton::setDefault()}{default button}
+ to \a button.
+
+ \sa addButton(), QPushButton::setDefault()
+*/
+void QMessageBox::setDefaultButton(QPushButton *button)
+{
+ Q_D(QMessageBox);
+ if (!d->buttonBox->buttons().contains(button))
+ return;
+ d->defaultButton = button;
+ button->setDefault(true);
+ button->setFocus();
+}
+
+/*!
+ \since 4.3
+
+ Sets the message box's \l{QPushButton::setDefault()}{default button}
+ to \a button.
+
+ \sa addButton(), QPushButton::setDefault()
+*/
+void QMessageBox::setDefaultButton(QMessageBox::StandardButton button)
+{
+ Q_D(QMessageBox);
+ setDefaultButton(d->buttonBox->button(QDialogButtonBox::StandardButton(button)));
+}
+
+/*!
+ \property QMessageBox::text
+ \brief the message box text to be displayed.
+
+ The text will be interpreted either as a plain text or as rich text,
+ depending on the text format setting (\l QMessageBox::textFormat).
+ The default setting is Qt::AutoText, i.e., the message box will try
+ to auto-detect the format of the text.
+
+ The default value of this property is an empty string.
+
+ \sa textFormat, QMessageBox::informativeText, QMessageBox::detailedText
+*/
+QString QMessageBox::text() const
+{
+ Q_D(const QMessageBox);
+ return d->label->text();
+}
+
+void QMessageBox::setText(const QString &text)
+{
+ Q_D(QMessageBox);
+ d->label->setText(text);
+ d->label->setWordWrap(d->label->textFormat() == Qt::RichText
+ || (d->label->textFormat() == Qt::AutoText && Qt::mightBeRichText(text)));
+ d->updateSize();
+}
+
+/*!
+ \enum QMessageBox::Icon
+
+ This enum has the following values:
+
+ \value NoIcon the message box does not have any icon.
+
+ \value Question an icon indicating that
+ the message is asking a question.
+
+ \value Information an icon indicating that
+ the message is nothing out of the ordinary.
+
+ \value Warning an icon indicating that the
+ message is a warning, but can be dealt with.
+
+ \value Critical an icon indicating that
+ the message represents a critical problem.
+
+*/
+
+/*!
+ \property QMessageBox::icon
+ \brief the message box's icon
+
+ The icon of the message box can be specified with one of the
+ values:
+
+ \list
+ \o QMessageBox::NoIcon
+ \o QMessageBox::Question
+ \o QMessageBox::Information
+ \o QMessageBox::Warning
+ \o QMessageBox::Critical
+ \endlist
+
+ The default is QMessageBox::NoIcon.
+
+ The pixmap used to display the actual icon depends on the current
+ \l{QWidget::style()} {GUI style}. You can also set a custom pixmap
+ for the icon by setting the \l{QMessageBox::iconPixmap} {icon
+ pixmap} property.
+
+ \sa iconPixmap
+*/
+QMessageBox::Icon QMessageBox::icon() const
+{
+ Q_D(const QMessageBox);
+ return d->icon;
+}
+
+void QMessageBox::setIcon(Icon icon)
+{
+ Q_D(QMessageBox);
+ setIconPixmap(QMessageBoxPrivate::standardIcon((QMessageBox::Icon)icon,
+ this));
+ d->icon = icon;
+}
+
+/*!
+ \property QMessageBox::iconPixmap
+ \brief the current icon
+
+ The icon currently used by the message box. Note that it's often
+ hard to draw one pixmap that looks appropriate in all GUI styles;
+ you may want to supply a different pixmap for each platform.
+
+ By default, this property is undefined.
+
+ \sa icon
+*/
+QPixmap QMessageBox::iconPixmap() const
+{
+ Q_D(const QMessageBox);
+ if (d->iconLabel && d->iconLabel->pixmap())
+ return *d->iconLabel->pixmap();
+ return QPixmap();
+}
+
+void QMessageBox::setIconPixmap(const QPixmap &pixmap)
+{
+ Q_D(QMessageBox);
+ d->iconLabel->setPixmap(pixmap);
+ d->updateSize();
+ d->icon = NoIcon;
+}
+
+/*!
+ \property QMessageBox::textFormat
+ \brief the format of the text displayed by the message box
+
+ The current text format used by the message box. See the \l
+ Qt::TextFormat enum for an explanation of the possible options.
+
+ The default format is Qt::AutoText.
+
+ \sa setText()
+*/
+Qt::TextFormat QMessageBox::textFormat() const
+{
+ Q_D(const QMessageBox);
+ return d->label->textFormat();
+}
+
+void QMessageBox::setTextFormat(Qt::TextFormat format)
+{
+ Q_D(QMessageBox);
+ d->label->setTextFormat(format);
+ d->label->setWordWrap(format == Qt::RichText
+ || (format == Qt::AutoText && Qt::mightBeRichText(d->label->text())));
+ d->updateSize();
+}
+
+/*!
+ \reimp
+*/
+bool QMessageBox::event(QEvent *e)
+{
+ bool result =QDialog::event(e);
+ switch (e->type()) {
+ case QEvent::LayoutRequest:
+ d_func()->updateSize();
+ break;
+ case QEvent::LanguageChange:
+ d_func()->retranslateStrings();
+ break;
+#ifdef Q_WS_WINCE
+ case QEvent::OkRequest:
+ case QEvent::HelpRequest: {
+ QString bName =
+ (e->type() == QEvent::OkRequest)
+ ? QApplication::translate("QMessageBox", "OK")
+ : QApplication::translate("QMessageBox", "Help");
+ QList<QPushButton*> list = findChildren<QPushButton*>();
+ for (int i=0; i<list.size(); ++i) {
+ QPushButton *pb = list.at(i);
+ if (pb->text() == bName) {
+ if (pb->isEnabled())
+ pb->click();
+ return pb->isEnabled();
+ }
+ }
+ }
+#endif
+ default:
+ break;
+ }
+ return result;
+}
+
+/*!
+ \reimp
+*/
+void QMessageBox::resizeEvent(QResizeEvent *event)
+{
+ QDialog::resizeEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QMessageBox::closeEvent(QCloseEvent *e)
+{
+ Q_D(QMessageBox);
+ if (!d->detectedEscapeButton) {
+ e->ignore();
+ return;
+ }
+ QDialog::closeEvent(e);
+ d->clickedButton = d->detectedEscapeButton;
+ setResult(d->execReturnCode(d->detectedEscapeButton));
+}
+
+/*!
+ \reimp
+*/
+void QMessageBox::changeEvent(QEvent *ev)
+{
+ Q_D(QMessageBox);
+ switch (ev->type()) {
+ case QEvent::StyleChange:
+ {
+ if (d->icon != NoIcon)
+ setIcon(d->icon);
+ Qt::TextInteractionFlags flags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, this));
+ d->label->setTextInteractionFlags(flags);
+ d->buttonBox->setCenterButtons(style()->styleHint(QStyle::SH_MessageBox_CenterButtons, 0, this));
+ if (d->informativeLabel)
+ d->informativeLabel->setTextInteractionFlags(flags);
+ // intentional fall through
+ }
+ case QEvent::FontChange:
+ case QEvent::ApplicationFontChange:
+#ifdef Q_WS_MAC
+ {
+ QFont f = font();
+ f.setBold(true);
+ d->label->setFont(f);
+ }
+#endif
+ default:
+ break;
+ }
+ QDialog::changeEvent(ev);
+}
+
+/*!
+ \reimp
+*/
+void QMessageBox::keyPressEvent(QKeyEvent *e)
+{
+ Q_D(QMessageBox);
+ if (e->key() == Qt::Key_Escape
+#ifdef Q_WS_MAC
+ || (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Period)
+#endif
+ ) {
+ if (d->detectedEscapeButton) {
+#ifdef Q_WS_MAC
+ d->detectedEscapeButton->animateClick();
+#else
+ d->detectedEscapeButton->click();
+#endif
+ }
+ return;
+ }
+
+#if defined (Q_OS_WIN) && !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_SHORTCUT)
+ if (e == QKeySequence::Copy) {
+ QString separator = QString::fromLatin1("---------------------------\n");
+ QString textToCopy = separator;
+ separator.prepend(QLatin1Char('\n'));
+ textToCopy += windowTitle() + separator; // title
+ textToCopy += d->label->text() + separator; // text
+
+ if (d->informativeLabel)
+ textToCopy += d->informativeLabel->text() + separator;
+
+ QString buttonTexts;
+ QList<QAbstractButton *> buttons = d->buttonBox->buttons();
+ for (int i = 0; i < buttons.count(); i++) {
+ buttonTexts += buttons[i]->text() + QLatin1String(" ");
+ }
+ textToCopy += buttonTexts + separator;
+
+ QApplication::clipboard()->setText(textToCopy);
+ return;
+ }
+#endif //QT_NO_SHORTCUT QT_NO_CLIPBOARD Q_OS_WIN
+
+#ifndef QT_NO_SHORTCUT
+ if (!(e->modifiers() & Qt::AltModifier)) {
+ int key = e->key() & ~((int)Qt::MODIFIER_MASK|(int)Qt::UNICODE_ACCEL);
+ if (key) {
+ const QList<QAbstractButton *> buttons = d->buttonBox->buttons();
+ for (int i = 0; i < buttons.count(); ++i) {
+ QAbstractButton *pb = buttons.at(i);
+ int acc = pb->shortcut() & ~((int)Qt::MODIFIER_MASK|(int)Qt::UNICODE_ACCEL);
+ if (acc == key) {
+ pb->animateClick();
+ return;
+ }
+ }
+ }
+ }
+#endif
+ QDialog::keyPressEvent(e);
+}
+
+#ifdef Q_WS_WINCE
+/*!
+ \reimp
+*/
+void QMessageBox::setVisible(bool visible)
+{
+ Q_D(QMessageBox);
+ if (visible)
+ d->hideSpecial();
+ QDialog::setVisible(visible);
+}
+#endif
+
+
+/*!
+ \overload
+
+ Opens the dialog and connects its finished() or buttonClicked() signal to
+ the slot specified by \a receiver and \a member. If the slot in \a member
+ has a pointer for its first parameter the connection is to buttonClicked(),
+ otherwise the connection is to finished().
+
+ The signal will be disconnected from the slot when the dialog is closed.
+*/
+void QMessageBox::open(QObject *receiver, const char *member)
+{
+ Q_D(QMessageBox);
+ const char *signal = member && strchr(member, '*') ? SIGNAL(buttonClicked(QAbstractButton*))
+ : SIGNAL(finished(int));
+ connect(this, signal, receiver, member);
+ d->signalToDisconnectOnClose = signal;
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+/*!
+ \since 4.5
+
+ Returns a list of all the buttons that have been added to the message box.
+
+ \sa buttonRole(), addButton(), removeButton()
+*/
+QList<QAbstractButton *> QMessageBox::buttons() const
+{
+ Q_D(const QMessageBox);
+ return d->buttonBox->buttons();
+}
+
+/*!
+ \since 4.5
+
+ Returns the button role for the specified \a button. This function returns
+ \l InvalidRole if \a button is 0 or has not been added to the message box.
+
+ \sa buttons(), addButton()
+*/
+QMessageBox::ButtonRole QMessageBox::buttonRole(QAbstractButton *button) const
+{
+ Q_D(const QMessageBox);
+ return QMessageBox::ButtonRole(d->buttonBox->buttonRole(button));
+}
+
+/*!
+ \reimp
+*/
+void QMessageBox::showEvent(QShowEvent *e)
+{
+ Q_D(QMessageBox);
+ if (d->autoAddOkButton) {
+ addButton(Ok);
+#if defined(Q_WS_WINCE)
+ d->hideSpecial();
+#endif
+ }
+ if (d->detailsButton)
+ addButton(d->detailsButton, QMessageBox::ActionRole);
+ d->detectEscapeButton();
+ d->updateSize();
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::updateAccessibility(this, 0, QAccessible::Alert);
+#endif
+#ifdef Q_WS_WIN
+ HMENU systemMenu = GetSystemMenu((HWND)winId(), FALSE);
+ if (!d->detectedEscapeButton) {
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
+ }
+ else {
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
+ }
+#endif
+ QDialog::showEvent(e);
+}
+
+
+static QMessageBox::StandardButton showNewMessageBox(QWidget *parent,
+ QMessageBox::Icon icon,
+ const QString& title, const QString& text,
+ QMessageBox::StandardButtons buttons,
+ QMessageBox::StandardButton defaultButton)
+{
+ // necessary for source compatibility with Qt 4.0 and 4.1
+ // handles (Yes, No) and (Yes|Default, No)
+ if (defaultButton && !(buttons & defaultButton))
+ return (QMessageBox::StandardButton)
+ QMessageBoxPrivate::showOldMessageBox(parent, icon, title,
+ text, int(buttons),
+ int(defaultButton), 0);
+
+ QMessageBox msgBox(icon, title, text, QMessageBox::NoButton, parent);
+ QDialogButtonBox *buttonBox = msgBox.findChild<QDialogButtonBox*>();
+ Q_ASSERT(buttonBox != 0);
+
+ uint mask = QMessageBox::FirstButton;
+ while (mask <= QMessageBox::LastButton) {
+ uint sb = buttons & mask;
+ mask <<= 1;
+ if (!sb)
+ continue;
+ QPushButton *button = msgBox.addButton((QMessageBox::StandardButton)sb);
+ // Choose the first accept role as the default
+ if (msgBox.defaultButton())
+ continue;
+ if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole)
+ || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton)))
+ msgBox.setDefaultButton(button);
+ }
+ if (msgBox.exec() == -1)
+ return QMessageBox::Cancel;
+ return msgBox.standardButton(msgBox.clickedButton());
+}
+
+/*!
+ \since 4.2
+
+ Opens an information message box with the given \a title and
+ \a text in front of the specified \a parent widget.
+
+ The standard \a buttons are added to the message box.
+ \a defaultButton specifies the button used when \key Enter is pressed.
+ \a defaultButton must refer to a button that was given in \a buttons.
+ If \a defaultButton is QMessageBox::NoButton, QMessageBox
+ chooses a suitable default automatically.
+
+ Returns the identity of the standard button that was clicked. If
+ \key Esc was pressed instead, the \l{Default and Escape Keys}
+ {escape button} is returned.
+
+ The message box is an \l{Qt::ApplicationModal}{application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa question(), warning(), critical()
+*/
+QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QString &title,
+ const QString& text, StandardButtons buttons,
+ StandardButton defaultButton)
+{
+ return showNewMessageBox(parent, Information, title, text, buttons,
+ defaultButton);
+}
+
+
+/*!
+ \since 4.2
+
+ Opens a question message box with the given \a title and \a
+ text in front of the specified \a parent widget.
+
+ The standard \a buttons are added to the message box. \a
+ defaultButton specifies the button used when \key Enter is
+ pressed. \a defaultButton must refer to a button that was given in \a buttons.
+ If \a defaultButton is QMessageBox::NoButton, QMessageBox
+ chooses a suitable default automatically.
+
+ Returns the identity of the standard button that was clicked. If
+ \key Esc was pressed instead, the \l{Default and Escape Keys}
+ {escape button} is returned.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa information(), warning(), critical()
+*/
+QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString &title,
+ const QString& text, StandardButtons buttons,
+ StandardButton defaultButton)
+{
+ return showNewMessageBox(parent, Question, title, text, buttons, defaultButton);
+}
+
+/*!
+ \since 4.2
+
+ Opens a warning message box with the given \a title and \a
+ text in front of the specified \a parent widget.
+
+ The standard \a buttons are added to the message box. \a
+ defaultButton specifies the button used when \key Enter is
+ pressed. \a defaultButton must refer to a button that was given in \a buttons.
+ If \a defaultButton is QMessageBox::NoButton, QMessageBox
+ chooses a suitable default automatically.
+
+ Returns the identity of the standard button that was clicked. If
+ \key Esc was pressed instead, the \l{Default and Escape Keys}
+ {escape button} is returned.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa question(), information(), critical()
+*/
+QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString &title,
+ const QString& text, StandardButtons buttons,
+ StandardButton defaultButton)
+{
+ return showNewMessageBox(parent, Warning, title, text, buttons, defaultButton);
+}
+
+/*!
+ \since 4.2
+
+ Opens a critical message box with the given \a title and \a
+ text in front of the specified \a parent widget.
+
+ The standard \a buttons are added to the message box. \a
+ defaultButton specifies the button used when \key Enter is
+ pressed. \a defaultButton must refer to a button that was given in \a buttons.
+ If \a defaultButton is QMessageBox::NoButton, QMessageBox
+ chooses a suitable default automatically.
+
+ Returns the identity of the standard button that was clicked. If
+ \key Esc was pressed instead, the \l{Default and Escape Keys}
+ {escape button} is returned.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa question(), warning(), information()
+*/
+QMessageBox::StandardButton QMessageBox::critical(QWidget *parent, const QString &title,
+ const QString& text, StandardButtons buttons,
+ StandardButton defaultButton)
+{
+ return showNewMessageBox(parent, Critical, title, text, buttons, defaultButton);
+}
+
+/*!
+ Displays a simple about box with title \a title and text \a
+ text. The about box's parent is \a parent.
+
+ about() looks for a suitable icon in four locations:
+
+ \list 1
+ \o It prefers \link QWidget::windowIcon() parent->icon() \endlink
+ if that exists.
+ \o If not, it tries the top-level widget containing \a parent.
+ \o If that fails, it tries the \link
+ QApplication::activeWindow() active window. \endlink
+ \o As a last resort it uses the Information icon.
+ \endlist
+
+ The about box has a single button labelled "OK". On Mac OS X, the
+ about box is popped up as a modeless window; on other platforms,
+ it is currently application modal.
+
+ \sa QWidget::windowIcon(), QApplication::activeWindow()
+*/
+void QMessageBox::about(QWidget *parent, const QString &title, const QString &text)
+{
+#ifdef Q_WS_MAC
+ static QPointer<QMessageBox> oldMsgBox;
+
+ if (oldMsgBox && oldMsgBox->text() == text) {
+ oldMsgBox->show();
+ oldMsgBox->raise();
+ oldMsgBox->activateWindow();
+ return;
+ }
+#endif
+
+ QMessageBox *msgBox = new QMessageBox(title, text, Information, 0, 0, 0, parent
+#ifdef Q_WS_MAC
+ , Qt::WindowTitleHint | Qt::WindowSystemMenuHint
+#endif
+ );
+ msgBox->setAttribute(Qt::WA_DeleteOnClose);
+ QIcon icon = msgBox->windowIcon();
+ QSize size = icon.actualSize(QSize(64, 64));
+ msgBox->setIconPixmap(icon.pixmap(size));
+
+ // should perhaps be a style hint
+#ifdef Q_WS_MAC
+ oldMsgBox = msgBox;
+#if 0
+ // ### doesn't work until close button is enabled in title bar
+ msgBox->d_func()->autoAddOkButton = false;
+#else
+ msgBox->d_func()->buttonBox->setCenterButtons(true);
+#endif
+ msgBox->show();
+#else
+ msgBox->exec();
+#endif
+}
+
+/*!
+ Displays a simple message box about Qt, with the given \a title
+ and centered over \a parent (if \a parent is not 0). The message
+ includes the version number of Qt being used by the application.
+
+ This is useful for inclusion in the \gui Help menu of an application,
+ as shown in the \l{mainwindows/menus}{Menus} example.
+
+ QApplication provides this functionality as a slot.
+
+ On Mac OS X, the about box is popped up as a modeless window; on
+ other platforms, it is currently application modal.
+
+ \sa QApplication::aboutQt()
+*/
+void QMessageBox::aboutQt(QWidget *parent, const QString &title)
+{
+#ifdef Q_WS_MAC
+ static QPointer<QMessageBox> oldMsgBox;
+
+ if (oldMsgBox) {
+ oldMsgBox->show();
+ oldMsgBox->raise();
+ oldMsgBox->activateWindow();
+ return;
+ }
+#endif
+
+ QString translatedTextAboutQtCaption;
+ translatedTextAboutQtCaption = QMessageBox::tr(
+ "<h3>About Qt</h3>"
+ "<p>This program uses Qt version %1.</p>"
+ ).arg(QLatin1String(QT_VERSION_STR));
+ QString translatedTextAboutQtText;
+ translatedTextAboutQtText = QMessageBox::tr(
+ "<p>Qt is a C++ toolkit for cross-platform application "
+ "development.</p>"
+ "<p>Qt provides single-source portability across MS&nbsp;Windows, "
+ "Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. "
+ "Qt is also available for embedded devices as Qt for Embedded Linux "
+ "and Qt for Windows CE.</p>"
+ "<p>Qt is available under three different licensing options designed "
+ "to accommodate the needs of our various users.</p>"
+ "<p>Qt licensed under our commercial license agreement is appropriate "
+ "for development of proprietary/commercial software where you do not "
+ "want to share any source code with third parties or otherwise cannot "
+ "comply with the terms of the GNU LGPL version 2.1 or GNU GPL version "
+ "3.0.</p>"
+ "<p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the "
+ "development of Qt applications (proprietary or open source) provided "
+ "you can comply with the terms and conditions of the GNU LGPL version "
+ "2.1.</p>"
+ "<p>Qt licensed under the GNU General Public License version 3.0 is "
+ "appropriate for the development of Qt applications where you wish to "
+ "use such applications in combination with software subject to the "
+ "terms of the GNU GPL version 3.0 or where you are otherwise willing "
+ "to comply with the terms of the GNU GPL version 3.0.</p>"
+ "<p>Please see <a href=\"http://qt.nokia.com/products/licensing\">qt.nokia.com/products/licensing</a> "
+ "for an overview of Qt licensing.</p>"
+ "<p>Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).</p>"
+ "<p>Qt is a Nokia product. See <a href=\"http://qt.nokia.com/\">qt.nokia.com</a> "
+ "for more information.</p>"
+ );
+ QMessageBox *msgBox = new QMessageBox(parent);
+ msgBox->setAttribute(Qt::WA_DeleteOnClose);
+ msgBox->setWindowTitle(title.isEmpty() ? tr("About Qt") : title);
+ msgBox->setText(translatedTextAboutQtCaption);
+ msgBox->setInformativeText(translatedTextAboutQtText);
+
+ QPixmap pm(QLatin1String(":/trolltech/qmessagebox/images/qtlogo-64.png"));
+ if (!pm.isNull())
+ msgBox->setIconPixmap(pm);
+#if defined(Q_WS_WINCE)
+ msgBox->setDefaultButton(msgBox->addButton(QMessageBox::Ok));
+#endif
+
+ // should perhaps be a style hint
+#ifdef Q_WS_MAC
+ oldMsgBox = msgBox;
+#if 0
+ // ### doesn't work until close button is enabled in title bar
+ msgBox->d_func()->autoAddOkButton = false;
+#else
+ msgBox->d_func()->buttonBox->setCenterButtons(true);
+#endif
+ msgBox->show();
+#else
+ msgBox->exec();
+#endif
+}
+
+/*!
+ \internal
+*/
+QSize QMessageBox::sizeHint() const
+{
+ // ### Qt 5: remove
+ return QDialog::sizeHint();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Source and binary compatibility routines for 4.0 and 4.1
+
+static QMessageBox::StandardButton newButton(int button)
+{
+ // this is needed for source compatibility with Qt 4.0 and 4.1
+ if (button == QMessageBox::NoButton || (button & NewButtonMask))
+ return QMessageBox::StandardButton(button & QMessageBox::ButtonMask);
+
+#if QT_VERSION < 0x050000
+ // this is needed for binary compatibility with Qt 4.0 and 4.1
+ switch (button & Old_ButtonMask) {
+ case Old_Ok:
+ return QMessageBox::Ok;
+ case Old_Cancel:
+ return QMessageBox::Cancel;
+ case Old_Yes:
+ return QMessageBox::Yes;
+ case Old_No:
+ return QMessageBox::No;
+ case Old_Abort:
+ return QMessageBox::Abort;
+ case Old_Retry:
+ return QMessageBox::Retry;
+ case Old_Ignore:
+ return QMessageBox::Ignore;
+ case Old_YesAll:
+ return QMessageBox::YesToAll;
+ case Old_NoAll:
+ return QMessageBox::NoToAll;
+ default:
+ return QMessageBox::NoButton;
+ }
+#else
+ return QMessageBox::NoButton;
+#endif
+}
+
+static bool detectedCompat(int button0, int button1, int button2)
+{
+ if (button0 != 0 && !(button0 & NewButtonMask))
+ return true;
+ if (button1 != 0 && !(button1 & NewButtonMask))
+ return true;
+ if (button2 != 0 && !(button2 & NewButtonMask))
+ return true;
+ return false;
+}
+
+QAbstractButton *QMessageBoxPrivate::findButton(int button0, int button1, int button2, int flags)
+{
+ Q_Q(QMessageBox);
+ int button = 0;
+
+ if (button0 & flags) {
+ button = button0;
+ } else if (button1 & flags) {
+ button = button1;
+ } else if (button2 & flags) {
+ button = button2;
+ }
+ return q->button(newButton(button));
+}
+
+void QMessageBoxPrivate::addOldButtons(int button0, int button1, int button2)
+{
+ Q_Q(QMessageBox);
+ q->addButton(newButton(button0));
+ q->addButton(newButton(button1));
+ q->addButton(newButton(button2));
+ q->setDefaultButton(
+ static_cast<QPushButton *>(findButton(button0, button1, button2, QMessageBox::Default)));
+ q->setEscapeButton(findButton(button0, button1, button2, QMessageBox::Escape));
+ compatMode = detectedCompat(button0, button1, button2);
+}
+
+QAbstractButton *QMessageBoxPrivate::abstractButtonForId(int id) const
+{
+ Q_Q(const QMessageBox);
+ QAbstractButton *result = customButtonList.value(id);
+ if (result)
+ return result;
+ if (id & QMessageBox::FlagMask) // for compatibility with Qt 4.0/4.1 (even if it is silly)
+ return 0;
+ return q->button(newButton(id));
+}
+
+int QMessageBoxPrivate::showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
+ const QString &title, const QString &text,
+ int button0, int button1, int button2)
+{
+ QMessageBox messageBox(icon, title, text, QMessageBox::NoButton, parent);
+ messageBox.d_func()->addOldButtons(button0, button1, button2);
+ return messageBox.exec();
+}
+
+int QMessageBoxPrivate::showOldMessageBox(QWidget *parent, QMessageBox::Icon icon,
+ const QString &title, const QString &text,
+ const QString &button0Text,
+ const QString &button1Text,
+ const QString &button2Text,
+ int defaultButtonNumber,
+ int escapeButtonNumber)
+{
+ QMessageBox messageBox(icon, title, text, QMessageBox::NoButton, parent);
+ QString myButton0Text = button0Text;
+ if (myButton0Text.isEmpty())
+ myButton0Text = QDialogButtonBox::tr("OK");
+ messageBox.addButton(myButton0Text, QMessageBox::ActionRole);
+ if (!button1Text.isEmpty())
+ messageBox.addButton(button1Text, QMessageBox::ActionRole);
+ if (!button2Text.isEmpty())
+ messageBox.addButton(button2Text, QMessageBox::ActionRole);
+
+ const QList<QAbstractButton *> &buttonList = messageBox.d_func()->customButtonList;
+ messageBox.setDefaultButton(static_cast<QPushButton *>(buttonList.value(defaultButtonNumber)));
+ messageBox.setEscapeButton(buttonList.value(escapeButtonNumber));
+
+ return messageBox.exec();
+}
+
+void QMessageBoxPrivate::retranslateStrings()
+{
+#ifndef QT_NO_TEXTEDIT
+ if (detailsButton)
+ detailsButton->setLabel(detailsText->isHidden() ? ShowLabel : HideLabel);
+#endif
+}
+
+/*!
+ \obsolete
+
+ Constructs a message box with a \a title, a \a text, an \a icon,
+ and up to three buttons.
+
+ The \a icon must be one of the following:
+ \list
+ \o QMessageBox::NoIcon
+ \o QMessageBox::Question
+ \o QMessageBox::Information
+ \o QMessageBox::Warning
+ \o QMessageBox::Critical
+ \endlist
+
+ Each button, \a button0, \a button1 and \a button2, can have one
+ of the following values:
+ \list
+ \o QMessageBox::NoButton
+ \o QMessageBox::Ok
+ \o QMessageBox::Cancel
+ \o QMessageBox::Yes
+ \o QMessageBox::No
+ \o QMessageBox::Abort
+ \o QMessageBox::Retry
+ \o QMessageBox::Ignore
+ \o QMessageBox::YesAll
+ \o QMessageBox::NoAll
+ \endlist
+
+ Use QMessageBox::NoButton for the later parameters to have fewer
+ than three buttons in your message box. If you don't specify any
+ buttons at all, QMessageBox will provide an Ok button.
+
+ One of the buttons can be OR-ed with the QMessageBox::Default
+ flag to make it the default button (clicked when Enter is
+ pressed).
+
+ One of the buttons can be OR-ed with the QMessageBox::Escape flag
+ to make it the cancel or close button (clicked when \key Esc is
+ pressed).
+
+ \snippet doc/src/snippets/dialogs/dialogs.cpp 2
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ The \a parent and \a f arguments are passed to
+ the QDialog constructor.
+
+ \sa setWindowTitle(), setText(), setIcon()
+*/
+QMessageBox::QMessageBox(const QString &title, const QString &text, Icon icon,
+ int button0, int button1, int button2, QWidget *parent,
+ Qt::WindowFlags f)
+ : QDialog(*new QMessageBoxPrivate, parent,
+ f /*| Qt::MSWindowsFixedSizeDialogHint #### */| Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint)
+{
+ Q_D(QMessageBox);
+ d->init(title, text);
+ setIcon(icon);
+ d->addOldButtons(button0, button1, button2);
+}
+
+/*!
+ \obsolete
+
+ Opens an information message box with the given \a title and the
+ \a text. The dialog may have up to three buttons. Each of the
+ buttons, \a button0, \a button1 and \a button2 may be set to one
+ of the following values:
+
+ \list
+ \o QMessageBox::NoButton
+ \o QMessageBox::Ok
+ \o QMessageBox::Cancel
+ \o QMessageBox::Yes
+ \o QMessageBox::No
+ \o QMessageBox::Abort
+ \o QMessageBox::Retry
+ \o QMessageBox::Ignore
+ \o QMessageBox::YesAll
+ \o QMessageBox::NoAll
+ \endlist
+
+ If you don't want all three buttons, set the last button, or last
+ two buttons to QMessageBox::NoButton.
+
+ One button can be OR-ed with QMessageBox::Default, and one
+ button can be OR-ed with QMessageBox::Escape.
+
+ Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.)
+ of the button that was clicked.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa question(), warning(), critical()
+*/
+int QMessageBox::information(QWidget *parent, const QString &title, const QString& text,
+ int button0, int button1, int button2)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Information, title, text,
+ button0, button1, button2);
+}
+
+/*!
+ \obsolete
+ \overload
+
+ Displays an information message box with the given \a title and
+ \a text, as well as one, two or three buttons. Returns the index
+ of the button that was clicked (0, 1 or 2).
+
+ \a button0Text is the text of the first button, and is optional.
+ If \a button0Text is not supplied, "OK" (translated) will be
+ used. \a button1Text is the text of the second button, and is
+ optional. \a button2Text is the text of the third button, and is
+ optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
+ default button; pressing Return or Enter is the same as clicking
+ the default button. It defaults to 0 (the first button). \a
+ escapeButtonNumber is the index of the escape button; pressing
+ \key Esc is the same as clicking this button. It defaults to -1;
+ supply 0, 1 or 2 to make pressing \key Esc equivalent to clicking
+ the relevant button.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa question(), warning(), critical()
+*/
+
+int QMessageBox::information(QWidget *parent, const QString &title, const QString& text,
+ const QString& button0Text, const QString& button1Text,
+ const QString& button2Text, int defaultButtonNumber,
+ int escapeButtonNumber)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Information, title, text,
+ button0Text, button1Text, button2Text,
+ defaultButtonNumber, escapeButtonNumber);
+}
+
+/*!
+ \obsolete
+
+ Opens a question message box with the given \a title and \a text.
+ The dialog may have up to three buttons. Each of the buttons, \a
+ button0, \a button1 and \a button2 may be set to one of the
+ following values:
+
+ \list
+ \o QMessageBox::NoButton
+ \o QMessageBox::Ok
+ \o QMessageBox::Cancel
+ \o QMessageBox::Yes
+ \o QMessageBox::No
+ \o QMessageBox::Abort
+ \o QMessageBox::Retry
+ \o QMessageBox::Ignore
+ \o QMessageBox::YesAll
+ \o QMessageBox::NoAll
+ \endlist
+
+ If you don't want all three buttons, set the last button, or last
+ two buttons to QMessageBox::NoButton.
+
+ One button can be OR-ed with QMessageBox::Default, and one
+ button can be OR-ed with QMessageBox::Escape.
+
+ Returns the identity (QMessageBox::Yes, or QMessageBox::No, etc.)
+ of the button that was clicked.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa information(), warning(), critical()
+*/
+int QMessageBox::question(QWidget *parent, const QString &title, const QString& text,
+ int button0, int button1, int button2)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Question, title, text,
+ button0, button1, button2);
+}
+
+/*!
+ \obsolete
+ \overload
+
+ Displays a question message box with the given \a title and \a
+ text, as well as one, two or three buttons. Returns the index of
+ the button that was clicked (0, 1 or 2).
+
+ \a button0Text is the text of the first button, and is optional.
+ If \a button0Text is not supplied, "OK" (translated) will be used.
+ \a button1Text is the text of the second button, and is optional.
+ \a button2Text is the text of the third button, and is optional.
+ \a defaultButtonNumber (0, 1 or 2) is the index of the default
+ button; pressing Return or Enter is the same as clicking the
+ default button. It defaults to 0 (the first button). \a
+ escapeButtonNumber is the index of the Escape button; pressing
+ Escape is the same as clicking this button. It defaults to -1;
+ supply 0, 1 or 2 to make pressing Escape equivalent to clicking
+ the relevant button.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa information(), warning(), critical()
+*/
+int QMessageBox::question(QWidget *parent, const QString &title, const QString& text,
+ const QString& button0Text, const QString& button1Text,
+ const QString& button2Text, int defaultButtonNumber,
+ int escapeButtonNumber)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Question, title, text,
+ button0Text, button1Text, button2Text,
+ defaultButtonNumber, escapeButtonNumber);
+}
+
+
+/*!
+ \obsolete
+
+ Opens a warning message box with the given \a title and \a text.
+ The dialog may have up to three buttons. Each of the button
+ parameters, \a button0, \a button1 and \a button2 may be set to
+ one of the following values:
+
+ \list
+ \o QMessageBox::NoButton
+ \o QMessageBox::Ok
+ \o QMessageBox::Cancel
+ \o QMessageBox::Yes
+ \o QMessageBox::No
+ \o QMessageBox::Abort
+ \o QMessageBox::Retry
+ \o QMessageBox::Ignore
+ \o QMessageBox::YesAll
+ \o QMessageBox::NoAll
+ \endlist
+
+ If you don't want all three buttons, set the last button, or last
+ two buttons to QMessageBox::NoButton.
+
+ One button can be OR-ed with QMessageBox::Default, and one
+ button can be OR-ed with QMessageBox::Escape.
+
+ Returns the identity (QMessageBox::Ok or QMessageBox::No or ...)
+ of the button that was clicked.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa information(), question(), critical()
+*/
+int QMessageBox::warning(QWidget *parent, const QString &title, const QString& text,
+ int button0, int button1, int button2)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Warning, title, text,
+ button0, button1, button2);
+}
+
+/*!
+ \obsolete
+ \overload
+
+ Displays a warning message box with the given \a title and \a
+ text, as well as one, two, or three buttons. Returns the number
+ of the button that was clicked (0, 1, or 2).
+
+ \a button0Text is the text of the first button, and is optional.
+ If \a button0Text is not supplied, "OK" (translated) will be used.
+ \a button1Text is the text of the second button, and is optional,
+ and \a button2Text is the text of the third button, and is
+ optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
+ default button; pressing Return or Enter is the same as clicking
+ the default button. It defaults to 0 (the first button). \a
+ escapeButtonNumber is the index of the Escape button; pressing
+ Escape is the same as clicking this button. It defaults to -1;
+ supply 0, 1, or 2 to make pressing Escape equivalent to clicking
+ the relevant button.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa information(), question(), critical()
+*/
+int QMessageBox::warning(QWidget *parent, const QString &title, const QString& text,
+ const QString& button0Text, const QString& button1Text,
+ const QString& button2Text, int defaultButtonNumber,
+ int escapeButtonNumber)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Warning, title, text,
+ button0Text, button1Text, button2Text,
+ defaultButtonNumber, escapeButtonNumber);
+}
+
+/*!
+ \obsolete
+
+ Opens a critical message box with the given \a title and \a text.
+ The dialog may have up to three buttons. Each of the button
+ parameters, \a button0, \a button1 and \a button2 may be set to
+ one of the following values:
+
+ \list
+ \o QMessageBox::NoButton
+ \o QMessageBox::Ok
+ \o QMessageBox::Cancel
+ \o QMessageBox::Yes
+ \o QMessageBox::No
+ \o QMessageBox::Abort
+ \o QMessageBox::Retry
+ \o QMessageBox::Ignore
+ \o QMessageBox::YesAll
+ \o QMessageBox::NoAll
+ \endlist
+
+ If you don't want all three buttons, set the last button, or last
+ two buttons to QMessageBox::NoButton.
+
+ One button can be OR-ed with QMessageBox::Default, and one
+ button can be OR-ed with QMessageBox::Escape.
+
+ Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.)
+ of the button that was clicked.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa information(), question(), warning()
+*/
+
+int QMessageBox::critical(QWidget *parent, const QString &title, const QString& text,
+ int button0, int button1, int button2)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Critical, title, text,
+ button0, button1, button2);
+}
+
+/*!
+ \obsolete
+ \overload
+
+ Displays a critical error message box with the given \a title and
+ \a text, as well as one, two, or three buttons. Returns the
+ number of the button that was clicked (0, 1 or 2).
+
+ \a button0Text is the text of the first button, and is optional.
+ If \a button0Text is not supplied, "OK" (translated) will be used.
+ \a button1Text is the text of the second button, and is optional,
+ and \a button2Text is the text of the third button, and is
+ optional. \a defaultButtonNumber (0, 1 or 2) is the index of the
+ default button; pressing Return or Enter is the same as clicking
+ the default button. It defaults to 0 (the first button). \a
+ escapeButtonNumber is the index of the Escape button; pressing
+ Escape is the same as clicking this button. It defaults to -1;
+ supply 0, 1, or 2 to make pressing Escape equivalent to clicking
+ the relevant button.
+
+ The message box is an \l{Qt::ApplicationModal} {application modal}
+ dialog box.
+
+ \warning Do not delete \a parent during the execution of the dialog.
+ If you want to do this, you should create the dialog
+ yourself using one of the QMessageBox constructors.
+
+ \sa information(), question(), warning()
+*/
+int QMessageBox::critical(QWidget *parent, const QString &title, const QString& text,
+ const QString& button0Text, const QString& button1Text,
+ const QString& button2Text, int defaultButtonNumber,
+ int escapeButtonNumber)
+{
+ return QMessageBoxPrivate::showOldMessageBox(parent, Critical, title, text,
+ button0Text, button1Text, button2Text,
+ defaultButtonNumber, escapeButtonNumber);
+}
+
+
+/*!
+ \obsolete
+
+ Returns the text of the message box button \a button, or
+ an empty string if the message box does not contain the button.
+
+ Use button() and QPushButton::text() instead.
+*/
+QString QMessageBox::buttonText(int button) const
+{
+ Q_D(const QMessageBox);
+
+ if (QAbstractButton *abstractButton = d->abstractButtonForId(button)) {
+ return abstractButton->text();
+ } else if (d->buttonBox->buttons().isEmpty() && (button == Ok || button == Old_Ok)) {
+ // for compatibility with Qt 4.0/4.1
+ return QDialogButtonBox::tr("OK");
+ }
+ return QString();
+}
+
+/*!
+ \obsolete
+
+ Sets the text of the message box button \a button to \a text.
+ Setting the text of a button that is not in the message box is
+ silently ignored.
+
+ Use addButton() instead.
+*/
+void QMessageBox::setButtonText(int button, const QString &text)
+{
+ Q_D(QMessageBox);
+ if (QAbstractButton *abstractButton = d->abstractButtonForId(button)) {
+ abstractButton->setText(text);
+ } else if (d->buttonBox->buttons().isEmpty() && (button == Ok || button == Old_Ok)) {
+ // for compatibility with Qt 4.0/4.1
+ addButton(QMessageBox::Ok)->setText(text);
+ }
+}
+
+#ifndef QT_NO_TEXTEDIT
+/*!
+ \property QMessageBox::detailedText
+ \brief the text to be displayed in the details area.
+ \since 4.2
+
+ The text will be interpreted as a plain text.
+
+ By default, this property contains an empty string.
+
+ \sa QMessageBox::text, QMessageBox::informativeText
+*/
+QString QMessageBox::detailedText() const
+{
+ Q_D(const QMessageBox);
+ return d->detailsText ? d->detailsText->text() : QString();
+}
+
+void QMessageBox::setDetailedText(const QString &text)
+{
+ Q_D(QMessageBox);
+ if (text.isEmpty()) {
+ delete d->detailsText;
+ d->detailsText = 0;
+ removeButton(d->detailsButton);
+ delete d->detailsButton;
+ d->detailsButton = 0;
+ return;
+ }
+
+ if (!d->detailsText) {
+ d->detailsText = new QMessageBoxDetailsText(this);
+ QGridLayout* grid = qobject_cast<QGridLayout*>(layout());
+ if (grid)
+ grid->addWidget(d->detailsText, grid->rowCount(), 0, 1, grid->columnCount());
+ d->detailsText->hide();
+ }
+ if (!d->detailsButton)
+ d->detailsButton = new DetailButton(this);
+ d->detailsText->setText(text);
+}
+#endif // QT_NO_TEXTEDIT
+
+/*!
+ \property QMessageBox::informativeText
+
+ \brief the informative text that provides a fuller description for
+ the message
+
+ \since 4.2
+
+ Infromative text can be used to expand upon the text() to give more
+ information to the user. On the Mac, this text appears in small
+ system font below the text(). On other platforms, it is simply
+ appended to the existing text.
+
+ By default, this property contains an empty string.
+
+ \sa QMessageBox::text, QMessageBox::detailedText
+*/
+QString QMessageBox::informativeText() const
+{
+ Q_D(const QMessageBox);
+ return d->informativeLabel ? d->informativeLabel->text() : QString();
+}
+
+void QMessageBox::setInformativeText(const QString &text)
+{
+ Q_D(QMessageBox);
+ if (text.isEmpty()) {
+ layout()->removeWidget(d->informativeLabel);
+ delete d->informativeLabel;
+ d->informativeLabel = 0;
+#ifndef Q_WS_MAC
+ d->label->setContentsMargins(2, 0, 0, 0);
+#endif
+ d->updateSize();
+ return;
+ }
+
+ if (!d->informativeLabel) {
+ QLabel *label = new QLabel;
+ label->setObjectName(QLatin1String("qt_msgbox_informativelabel"));
+ label->setTextInteractionFlags(Qt::TextInteractionFlags(style()->styleHint(QStyle::SH_MessageBox_TextInteractionFlags, 0, this)));
+ label->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ label->setOpenExternalLinks(true);
+ label->setWordWrap(true);
+#ifndef Q_WS_MAC
+ d->label->setContentsMargins(2, 0, 0, 0);
+ label->setContentsMargins(2, 0, 0, 6);
+ label->setIndent(9);
+#else
+ label->setContentsMargins(16, 0, 0, 0);
+ // apply a smaller font the information label on the mac
+ label->setFont(qt_app_fonts_hash()->value("QTipLabel"));
+#endif
+ label->setWordWrap(true);
+ QGridLayout *grid = static_cast<QGridLayout *>(layout());
+#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
+ label->hide();
+ QTextBrowser *textBrowser = new QTextBrowser(this);
+ textBrowser->setOpenExternalLinks(true);
+ grid->addWidget(textBrowser, 1, 1, 1, 1);
+ d->textBrowser = textBrowser;
+#else
+ grid->addWidget(label, 1, 1, 1, 1);
+#endif
+ d->informativeLabel = label;
+ }
+ d->informativeLabel->setText(text);
+
+#if defined(Q_OS_SYMBIAN) || defined(Q_WS_MAEMO_5)
+ //We need to put the informative label inside textBrowser to enable scrolling of long texts.
+ d->textBrowser->setText(d->informativeLabel->text());
+#endif
+
+ d->updateSize();
+}
+
+/*!
+ \since 4.2
+
+ This function shadows QWidget::setWindowTitle().
+
+ Sets the title of the message box to \a title. On Mac OS X,
+ the window title is ignored (as required by the Mac OS X
+ Guidelines).
+*/
+void QMessageBox::setWindowTitle(const QString &title)
+{
+ // Message boxes on the mac do not have a title
+#ifndef Q_WS_MAC
+ QDialog::setWindowTitle(title);
+#else
+ Q_UNUSED(title);
+#endif
+}
+
+
+/*!
+ \since 4.2
+
+ This function shadows QWidget::setWindowModality().
+
+ Sets the modality of the message box to \a windowModality.
+
+ On Mac OS X, if the modality is set to Qt::WindowModal and the message box
+ has a parent, then the message box will be a Qt::Sheet, otherwise the
+ message box will be a standard dialog.
+*/
+void QMessageBox::setWindowModality(Qt::WindowModality windowModality)
+{
+ QDialog::setWindowModality(windowModality);
+
+ if (parentWidget() && windowModality == Qt::WindowModal)
+ setParent(parentWidget(), Qt::Sheet);
+ else
+ setParent(parentWidget(), Qt::Dialog);
+ setDefaultButton(d_func()->defaultButton);
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \compat
+
+ Constructs a message box with the given \a parent, \a name, and
+ window flags, \a f.
+ The window title is specified by \a title, and the message box
+ displays message text and an icon specified by \a text and \a icon.
+
+ The buttons that the user can access to respond to the message are
+ defined by \a button0, \a button1, and \a button2.
+*/
+QMessageBox::QMessageBox(const QString& title,
+ const QString &text, Icon icon,
+ int button0, int button1, int button2,
+ QWidget *parent, const char *name,
+ bool modal, Qt::WindowFlags f)
+ : QDialog(*new QMessageBoxPrivate, parent,
+ f | Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu | Qt::WindowCloseButtonHint)
+{
+ Q_D(QMessageBox);
+ setObjectName(QString::fromAscii(name));
+ d->init(title, text);
+ d->addOldButtons(button0, button1, button2);
+ setModal(modal);
+ setIcon(icon);
+}
+
+/*!
+ \compat
+ Constructs a message box with the given \a parent and \a name.
+*/
+QMessageBox::QMessageBox(QWidget *parent, const char *name)
+ : QDialog(*new QMessageBoxPrivate, parent,
+ Qt::WStyle_Customize | Qt::WStyle_DialogBorder | Qt::WStyle_Title | Qt::WStyle_SysMenu | Qt::WindowCloseButtonHint)
+{
+ Q_D(QMessageBox);
+ setObjectName(QString::fromAscii(name));
+ d->init();
+}
+
+/*!
+ Returns the pixmap used for a standard icon. This
+ allows the pixmaps to be used in more complex message boxes.
+ \a icon specifies the required icon, e.g. QMessageBox::Information,
+ QMessageBox::Warning or QMessageBox::Critical.
+
+ \a style is unused.
+*/
+
+QPixmap QMessageBox::standardIcon(Icon icon, Qt::GUIStyle style)
+{
+ Q_UNUSED(style);
+ return QMessageBox::standardIcon(icon);
+}
+
+/*!
+ \fn int QMessageBox::message(const QString &title, const QString &text,
+ const QString &buttonText, QWidget *parent = 0,
+ const char *name = 0)
+
+ Opens a modal message box with the given \a title and showing the
+ given \a text. The message box has a single button which has the
+ given \a buttonText (or tr("OK")). The message box is centred over
+ its \a parent and is called \a name.
+
+ Use information(), warning(), question(), or critical() instead.
+
+ \oldcode
+ QMessageBox::message(tr("My App"), tr("All occurrences replaced."),
+ tr("Close"), this);
+ \newcode
+ QMessageBox::information(this, tr("My App"),
+ tr("All occurrences replaced."),
+ QMessageBox::Close);
+ \endcode
+*/
+
+/*!
+ \fn bool QMessageBox::query(const QString &caption,
+ const QString& text,
+ const QString& yesButtonText,
+ const QString& noButtonText,
+ QWidget *parent, const char *name)
+
+ \obsolete
+
+ Queries the user using a modal message box with up to two buttons.
+ The message box has the given \a caption (although some window
+ managers don't show it), and shows the given \a text. The left
+ button has the \a yesButtonText (or tr("OK")), and the right button
+ has the \a noButtonText (or isn't shown). The message box is centred
+ over its \a parent and is called \a name.
+
+ Use information(), question(), warning(), or critical() instead.
+*/
+
+#endif
+
+QPixmap QMessageBoxPrivate::standardIcon(QMessageBox::Icon icon, QMessageBox *mb)
+{
+ QStyle *style = mb ? mb->style() : QApplication::style();
+ int iconSize = style->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, mb);
+ QIcon tmpIcon;
+ switch (icon) {
+ case QMessageBox::Information:
+ tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation, 0, mb);
+ break;
+ case QMessageBox::Warning:
+ tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning, 0, mb);
+ break;
+ case QMessageBox::Critical:
+ tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical, 0, mb);
+ break;
+ case QMessageBox::Question:
+ tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mb);
+ default:
+ break;
+ }
+ if (!tmpIcon.isNull())
+ return tmpIcon.pixmap(iconSize, iconSize);
+ return QPixmap();
+}
+
+/*!
+ \obsolete
+
+ Returns the pixmap used for a standard icon. This allows the
+ pixmaps to be used in more complex message boxes. \a icon
+ specifies the required icon, e.g. QMessageBox::Question,
+ QMessageBox::Information, QMessageBox::Warning or
+ QMessageBox::Critical.
+
+ Call QStyle::standardIcon() with QStyle::SP_MessageBoxInformation etc.
+ instead.
+*/
+
+QPixmap QMessageBox::standardIcon(Icon icon)
+{
+ return QMessageBoxPrivate::standardIcon(icon, 0);
+}
+
+/*!
+ \typedef QMessageBox::Button
+ \obsolete
+
+ Use QMessageBox::StandardButton instead.
+*/
+
+/*!
+ \fn int QMessageBox::information(QWidget *parent, const QString &title,
+ const QString& text, StandardButton button0,
+ StandardButton button1)
+ \fn int QMessageBox::warning(QWidget *parent, const QString &title,
+ const QString& text, StandardButton button0,
+ StandardButton button1)
+ \fn int QMessageBox::critical(QWidget *parent, const QString &title,
+ const QString& text, StandardButton button0,
+ StandardButton button1)
+ \fn int QMessageBox::question(QWidget *parent, const QString &title,
+ const QString& text, StandardButton button0,
+ StandardButton button1)
+ \internal
+
+ ### Needed for Qt 4 source compatibility
+*/
+
+/*!
+ \fn int QMessageBox::exec()
+
+ Shows the message box as a \l{QDialog#Modal Dialogs}{modal dialog},
+ blocking until the user closes it.
+
+ When using a QMessageBox with standard buttons, this functions returns a
+ \l StandardButton value indicating the standard button that was clicked.
+ When using QMessageBox with custom buttons, this function returns an
+ opaque value; use clickedButton() to determine which button was clicked.
+
+ Users cannot interact with any other window in the same
+ application until they close the dialog, either by clicking a
+ button or by using a mechanism provided by the window system.
+
+ \sa show(), result()
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qmessagebox.cpp"
+
+#endif // QT_NO_MESSAGEBOX
diff --git a/src/widgets/dialogs/qmessagebox.h b/src/widgets/dialogs/qmessagebox.h
new file mode 100644
index 0000000000..b2c99d3881
--- /dev/null
+++ b/src/widgets/dialogs/qmessagebox.h
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMESSAGEBOX_H
+#define QMESSAGEBOX_H
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MESSAGEBOX
+
+class QLabel;
+class QMessageBoxPrivate;
+class QAbstractButton;
+
+class Q_WIDGETS_EXPORT QMessageBox : public QDialog
+{
+ Q_OBJECT
+ Q_ENUMS(Icon)
+ Q_FLAGS(StandardButtons)
+ Q_PROPERTY(QString text READ text WRITE setText)
+ // ### Qt 5: Rename 'icon' 'standardIcon' and 'iconPixmap' 'icon' (and use QIcon?)
+ Q_PROPERTY(Icon icon READ icon WRITE setIcon)
+ Q_PROPERTY(QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap)
+ Q_PROPERTY(Qt::TextFormat textFormat READ textFormat WRITE setTextFormat)
+ Q_PROPERTY(StandardButtons standardButtons READ standardButtons WRITE setStandardButtons)
+#ifndef QT_NO_TEXTEDIT
+ Q_PROPERTY(QString detailedText READ detailedText WRITE setDetailedText)
+#endif
+ Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText)
+
+public:
+ enum Icon {
+ NoIcon = 0,
+ Information = 1,
+ Warning = 2,
+ Critical = 3,
+ Question = 4
+ };
+
+ enum ButtonRole {
+ // keep this in sync with QDialogButtonBox::ButtonRole
+ InvalidRole = -1,
+ AcceptRole,
+ RejectRole,
+ DestructiveRole,
+ ActionRole,
+ HelpRole,
+ YesRole,
+ NoRole,
+ ResetRole,
+ ApplyRole,
+
+ NRoles
+ };
+
+ enum StandardButton {
+ // keep this in sync with QDialogButtonBox::StandardButton
+ NoButton = 0x00000000,
+ Ok = 0x00000400,
+ Save = 0x00000800,
+ SaveAll = 0x00001000,
+ Open = 0x00002000,
+ Yes = 0x00004000,
+ YesToAll = 0x00008000,
+ No = 0x00010000,
+ NoToAll = 0x00020000,
+ Abort = 0x00040000,
+ Retry = 0x00080000,
+ Ignore = 0x00100000,
+ Close = 0x00200000,
+ Cancel = 0x00400000,
+ Discard = 0x00800000,
+ Help = 0x01000000,
+ Apply = 0x02000000,
+ Reset = 0x04000000,
+ RestoreDefaults = 0x08000000,
+
+ FirstButton = Ok, // internal
+ LastButton = RestoreDefaults, // internal
+
+ YesAll = YesToAll, // obsolete
+ NoAll = NoToAll, // obsolete
+
+ Default = 0x00000100, // obsolete
+ Escape = 0x00000200, // obsolete
+ FlagMask = 0x00000300, // obsolete
+ ButtonMask = ~FlagMask // obsolete
+ };
+ typedef StandardButton Button; // obsolete
+
+ Q_DECLARE_FLAGS(StandardButtons, StandardButton)
+
+ explicit QMessageBox(QWidget *parent = 0);
+ QMessageBox(Icon icon, const QString &title, const QString &text,
+ StandardButtons buttons = NoButton, QWidget *parent = 0,
+ Qt::WindowFlags flags = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
+ ~QMessageBox();
+
+ void addButton(QAbstractButton *button, ButtonRole role);
+ QPushButton *addButton(const QString &text, ButtonRole role);
+ QPushButton *addButton(StandardButton button);
+ void removeButton(QAbstractButton *button);
+
+#ifdef Q_WS_WINCE
+ void setVisible(bool visible);
+#endif
+
+#ifdef Q_NO_USING_KEYWORD
+#ifndef Q_QDOC
+ void open() { QDialog::open(); }
+#endif
+#else
+ using QDialog::open;
+#endif
+ void open(QObject *receiver, const char *member);
+
+ QList<QAbstractButton *> buttons() const;
+ ButtonRole buttonRole(QAbstractButton *button) const;
+
+ void setStandardButtons(StandardButtons buttons);
+ StandardButtons standardButtons() const;
+ StandardButton standardButton(QAbstractButton *button) const;
+ QAbstractButton *button(StandardButton which) const;
+
+ QPushButton *defaultButton() const;
+ void setDefaultButton(QPushButton *button);
+ void setDefaultButton(StandardButton button);
+
+ QAbstractButton *escapeButton() const;
+ void setEscapeButton(QAbstractButton *button);
+ void setEscapeButton(StandardButton button);
+
+ QAbstractButton *clickedButton() const;
+
+ QString text() const;
+ void setText(const QString &text);
+
+ Icon icon() const;
+ void setIcon(Icon);
+
+ QPixmap iconPixmap() const;
+ void setIconPixmap(const QPixmap &pixmap);
+
+ Qt::TextFormat textFormat() const;
+ void setTextFormat(Qt::TextFormat format);
+
+ static StandardButton information(QWidget *parent, const QString &title,
+ const QString &text, StandardButtons buttons = Ok,
+ StandardButton defaultButton = NoButton);
+ // ### Qt 5: Replace Ok with Yes|No in question() function.
+ // Also consider if Ok == Yes and Cancel == No.
+ static StandardButton question(QWidget *parent, const QString &title,
+ const QString &text, StandardButtons buttons = Ok,
+ StandardButton defaultButton = NoButton);
+ static StandardButton warning(QWidget *parent, const QString &title,
+ const QString &text, StandardButtons buttons = Ok,
+ StandardButton defaultButton = NoButton);
+ static StandardButton critical(QWidget *parent, const QString &title,
+ const QString &text, StandardButtons buttons = Ok,
+ StandardButton defaultButton = NoButton);
+ static void about(QWidget *parent, const QString &title, const QString &text);
+ static void aboutQt(QWidget *parent, const QString &title = QString());
+
+ QSize sizeHint() const;
+
+ // the following functions are obsolete:
+
+ QMessageBox(const QString &title, const QString &text, Icon icon,
+ int button0, int button1, int button2,
+ QWidget *parent = 0,
+ Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
+
+ static int information(QWidget *parent, const QString &title,
+ const QString& text,
+ int button0, int button1 = 0, int button2 = 0);
+ static int information(QWidget *parent, const QString &title,
+ const QString& text,
+ const QString& button0Text,
+ const QString& button1Text = QString(),
+ const QString& button2Text = QString(),
+ int defaultButtonNumber = 0,
+ int escapeButtonNumber = -1);
+ inline static StandardButton information(QWidget *parent, const QString &title,
+ const QString& text,
+ StandardButton button0, StandardButton button1 = NoButton)
+ { return information(parent, title, text, StandardButtons(button0), button1); }
+
+ static int question(QWidget *parent, const QString &title,
+ const QString& text,
+ int button0, int button1 = 0, int button2 = 0);
+ static int question(QWidget *parent, const QString &title,
+ const QString& text,
+ const QString& button0Text,
+ const QString& button1Text = QString(),
+ const QString& button2Text = QString(),
+ int defaultButtonNumber = 0,
+ int escapeButtonNumber = -1);
+ inline static int question(QWidget *parent, const QString &title,
+ const QString& text,
+ StandardButton button0, StandardButton button1)
+ { return question(parent, title, text, StandardButtons(button0), button1); }
+
+ static int warning(QWidget *parent, const QString &title,
+ const QString& text,
+ int button0, int button1, int button2 = 0);
+ static int warning(QWidget *parent, const QString &title,
+ const QString& text,
+ const QString& button0Text,
+ const QString& button1Text = QString(),
+ const QString& button2Text = QString(),
+ int defaultButtonNumber = 0,
+ int escapeButtonNumber = -1);
+ inline static int warning(QWidget *parent, const QString &title,
+ const QString& text,
+ StandardButton button0, StandardButton button1)
+ { return warning(parent, title, text, StandardButtons(button0), button1); }
+
+ static int critical(QWidget *parent, const QString &title,
+ const QString& text,
+ int button0, int button1, int button2 = 0);
+ static int critical(QWidget *parent, const QString &title,
+ const QString& text,
+ const QString& button0Text,
+ const QString& button1Text = QString(),
+ const QString& button2Text = QString(),
+ int defaultButtonNumber = 0,
+ int escapeButtonNumber = -1);
+ inline static int critical(QWidget *parent, const QString &title,
+ const QString& text,
+ StandardButton button0, StandardButton button1)
+ { return critical(parent, title, text, StandardButtons(button0), button1); }
+
+ QString buttonText(int button) const;
+ void setButtonText(int button, const QString &text);
+
+ QString informativeText() const;
+ void setInformativeText(const QString &text);
+
+#ifndef QT_NO_TEXTEDIT
+ QString detailedText() const;
+ void setDetailedText(const QString &text);
+#endif
+
+ void setWindowTitle(const QString &title);
+ void setWindowModality(Qt::WindowModality windowModality);
+
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT_CONSTRUCTOR QMessageBox(const QString &title, const QString &text, Icon icon,
+ int button0, int button1, int button2,
+ QWidget *parent, const char *name, bool modal,
+ Qt::WindowFlags f = Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
+ QT3_SUPPORT_CONSTRUCTOR QMessageBox(QWidget *parent, const char *name);
+
+ static QT3_SUPPORT QPixmap standardIcon(Icon icon, Qt::GUIStyle);
+ static QT3_SUPPORT int message(const QString &title,
+ const QString& text,
+ const QString& buttonText=QString(),
+ QWidget *parent = 0, const char * = 0) {
+ return QMessageBox::information(parent, title, text,
+ buttonText.isEmpty() ? tr("OK") : buttonText) == 0;
+ }
+ static QT3_SUPPORT bool query(const QString &title,
+ const QString& text,
+ const QString& yesButtonText = QString(),
+ const QString& noButtonText = QString(),
+ QWidget *parent = 0, const char * = 0) {
+ return QMessageBox::information(parent, title, text,
+ yesButtonText.isEmpty() ? tr("OK") : yesButtonText,
+ noButtonText) == 0;
+ }
+#endif
+
+ static QPixmap standardIcon(Icon icon);
+
+Q_SIGNALS:
+ void buttonClicked(QAbstractButton *button);
+
+#ifdef qdoc
+public Q_SLOTS:
+ int exec();
+#endif
+
+protected:
+ bool event(QEvent *e);
+ void resizeEvent(QResizeEvent *event);
+ void showEvent(QShowEvent *event);
+ void closeEvent(QCloseEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void changeEvent(QEvent *event);
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_buttonClicked(QAbstractButton *))
+
+ Q_DISABLE_COPY(QMessageBox)
+ Q_DECLARE_PRIVATE(QMessageBox)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMessageBox::StandardButtons)
+
+#define QT_REQUIRE_VERSION(argc, argv, str) { QString s = QString::fromLatin1(str);\
+QString sq = QString::fromLatin1(qVersion()); \
+if ((sq.section(QChar::fromLatin1('.'),0,0).toInt()<<16)+\
+(sq.section(QChar::fromLatin1('.'),1,1).toInt()<<8)+\
+sq.section(QChar::fromLatin1('.'),2,2).toInt()<(s.section(QChar::fromLatin1('.'),0,0).toInt()<<16)+\
+(s.section(QChar::fromLatin1('.'),1,1).toInt()<<8)+\
+s.section(QChar::fromLatin1('.'),2,2).toInt()) { \
+if (!qApp){ \
+ new QApplication(argc,argv); \
+} \
+QString s = QApplication::tr("Executable '%1' requires Qt "\
+ "%2, found Qt %3.").arg(qAppName()).arg(QString::fromLatin1(\
+str)).arg(QString::fromLatin1(qVersion())); QMessageBox::critical(0, QApplication::tr(\
+"Incompatible Qt Library Error"), s, QMessageBox::Abort, 0); qFatal("%s", s.toLatin1().data()); }}
+
+#endif // QT_NO_MESSAGEBOX
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QMESSAGEBOX_H
diff --git a/src/widgets/dialogs/qmessagebox.qrc b/src/widgets/dialogs/qmessagebox.qrc
new file mode 100644
index 0000000000..8e6d7af671
--- /dev/null
+++ b/src/widgets/dialogs/qmessagebox.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/trolltech/qmessagebox">
+ <file>images/qtlogo-64.png</file>
+</qresource>
+</RCC>
diff --git a/src/widgets/dialogs/qnspanelproxy_mac.mm b/src/widgets/dialogs/qnspanelproxy_mac.mm
new file mode 100644
index 0000000000..1de548413a
--- /dev/null
+++ b/src/widgets/dialogs/qnspanelproxy_mac.mm
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qdialogbuttonbox.h>
+#if defined(Q_WS_MAC)
+#include <private/qt_mac_p.h>
+#include <private/qcocoaintrospection_p.h>
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#import <objc/objc-class.h>
+
+QT_BEGIN_NAMESPACE
+static QWidget *currentWindow = 0;
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+@class QT_MANGLE_NAMESPACE(QNSPanelProxy);
+
+@interface QT_MANGLE_NAMESPACE(QNSPanelProxy) : NSWindow {
+}
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation;
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen;
+- (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation;
+- (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen;
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSPanelProxy)
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
+{
+ // remove evil flag
+ windowStyle &= ~NSUtilityWindowMask;
+ self = [self qt_fakeInitWithContentRect:contentRect styleMask:windowStyle
+ backing:bufferingType defer:deferCreation];
+ return self;
+}
+
+- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen
+{
+ // remove evil flag
+ windowStyle &= ~NSUtilityWindowMask;
+ return [self qt_fakeInitWithContentRect:contentRect styleMask:windowStyle
+ backing:bufferingType defer:deferCreation screen:screen];
+}
+
+- (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
+{
+ Q_UNUSED(contentRect);
+ Q_UNUSED(windowStyle);
+ Q_UNUSED(bufferingType);
+ Q_UNUSED(deferCreation);
+ return nil;
+}
+
+- (id)qt_fakeInitWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle
+ backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation screen:(NSScreen *)screen
+{
+ Q_UNUSED(contentRect);
+ Q_UNUSED(windowStyle);
+ Q_UNUSED(bufferingType);
+ Q_UNUSED(deferCreation);
+ Q_UNUSED(screen);
+ return nil;
+}
+@end
+
+@class QT_MANGLE_NAMESPACE(QNSWindowProxy);
+
+@interface QT_MANGLE_NAMESPACE(QNSWindowProxy) : NSWindow {
+}
+- (void)setTitle:(NSString *)title;
+- (void)qt_fakeSetTitle:(NSString *)title;
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QNSWindowProxy)
+- (void)setTitle:(NSString *)title
+{
+ QCFString cftitle(currentWindow->windowTitle());
+
+ // evil reverse engineering
+ if ([title isEqualToString:@"Print"]
+ || [title isEqualToString:@"Page Setup"]
+ || [[self className] isEqualToString:@"PMPrintingWindow"])
+ title = (NSString *)(static_cast<CFStringRef>(cftitle));
+ return [self qt_fakeSetTitle:title];
+}
+
+- (void)qt_fakeSetTitle:(NSString *)title
+{
+ Q_UNUSED(title);
+}
+@end
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Intercept the NSColorPanel constructor if the shared
+ color panel doesn't exist yet. What's going on here is
+ quite wacky, because we want to override the NSPanel
+ constructor and at the same time call the old NSPanel
+ constructor. So what we do is we effectively rename the
+ old NSPanel constructor qt_fakeInitWithContentRect:...
+ and have the new one call the old one.
+*/
+void macStartInterceptNSPanelCtor()
+{
+ qt_cocoa_change_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:),
+ [QT_MANGLE_NAMESPACE(QNSPanelProxy) class],
+ @selector(initWithContentRect:styleMask:backing:defer:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:));
+ qt_cocoa_change_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:screen:),
+ [QT_MANGLE_NAMESPACE(QNSPanelProxy) class],
+ @selector(initWithContentRect:styleMask:backing:defer:screen:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:));
+}
+
+/*
+ Restore things as they were.
+*/
+void macStopInterceptNSPanelCtor()
+{
+ qt_cocoa_change_back_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:screen:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:screen:));
+ qt_cocoa_change_back_implementation(
+ [NSPanel class],
+ @selector(initWithContentRect:styleMask:backing:defer:),
+ @selector(qt_fakeInitWithContentRect:styleMask:backing:defer:));
+}
+
+/*
+ Intercept the NSPrintPanel and NSPageLayout setTitle: calls. The
+ hack is similar as for NSColorPanel above.
+*/
+void macStartInterceptWindowTitle(QWidget *window)
+{
+ currentWindow = window;
+ qt_cocoa_change_implementation(
+ [NSWindow class],
+ @selector(setTitle:),
+ [QT_MANGLE_NAMESPACE(QNSWindowProxy) class],
+ @selector(setTitle:),
+ @selector(qt_fakeSetTitle:));
+}
+
+/*
+ Restore things as they were.
+*/
+void macStopInterceptWindowTitle()
+{
+ currentWindow = 0;
+ qt_cocoa_change_back_implementation(
+ [NSWindow class],
+ @selector(setTitle:),
+ @selector(qt_fakeSetTitle:));
+}
+
+/*
+ Doesn't really belong in here.
+*/
+NSButton *macCreateButton(const char *text, NSView *superview)
+{
+ static const NSRect buttonFrameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } };
+
+ NSButton *button = [[NSButton alloc] initWithFrame:buttonFrameRect];
+ [button setButtonType:NSMomentaryLightButton];
+ [button setBezelStyle:NSRoundedBezelStyle];
+ [button setTitle:(NSString*)(CFStringRef)QCFString(QDialogButtonBox::tr(text)
+ .remove(QLatin1Char('&')))];
+ [[button cell] setFont:[NSFont systemFontOfSize:
+ [NSFont systemFontSizeForControlSize:NSRegularControlSize]]];
+ [superview addSubview:button];
+ return button;
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qprogressdialog.cpp b/src/widgets/dialogs/qprogressdialog.cpp
new file mode 100644
index 0000000000..8701dc10fb
--- /dev/null
+++ b/src/widgets/dialogs/qprogressdialog.cpp
@@ -0,0 +1,907 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qprogressdialog.h"
+
+#ifndef QT_NO_PROGRESSDIALOG
+
+#include "qshortcut.h"
+#include "qpainter.h"
+#include "qdrawutil.h"
+#include "qlabel.h"
+#include "qprogressbar.h"
+#include "qapplication.h"
+#include "qstyle.h"
+#include "qpushbutton.h"
+#include "qcursor.h"
+#include "qtimer.h"
+#include "qelapsedtimer.h"
+#include <private/qdialog_p.h>
+#include <limits.h>
+
+#if defined(QT_SOFTKEYS_ENABLED)
+#include <qaction.h>
+#endif
+#ifdef Q_WS_S60
+#include <QtWidgets/qdesktopwidget.h>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+// If the operation is expected to take this long (as predicted by
+// progress time), show the progress dialog.
+static const int defaultShowTime = 4000;
+// Wait at least this long before attempting to make a prediction.
+static const int minWaitTime = 50;
+
+class QProgressDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QProgressDialog)
+
+public:
+ QProgressDialogPrivate() : label(0), cancel(0), bar(0),
+ shown_once(false),
+ cancellation_flag(false),
+ showTime(defaultShowTime),
+#ifndef QT_NO_SHORTCUT
+ escapeShortcut(0),
+#endif
+#ifdef QT_SOFTKEYS_ENABLED
+ cancelAction(0),
+#endif
+ useDefaultCancelText(false)
+ {
+ }
+
+ void init(const QString &labelText, const QString &cancelText, int min, int max);
+ void layout();
+ void retranslateStrings();
+ void _q_disconnectOnClose();
+
+ QLabel *label;
+ QPushButton *cancel;
+ QProgressBar *bar;
+ QTimer *forceTimer;
+ bool shown_once;
+ bool cancellation_flag;
+ QElapsedTimer starttime;
+#ifndef QT_NO_CURSOR
+ QCursor parentCursor;
+#endif
+ int showTime;
+ bool autoClose;
+ bool autoReset;
+ bool forceHide;
+#ifndef QT_NO_SHORTCUT
+ QShortcut *escapeShortcut;
+#endif
+#ifdef QT_SOFTKEYS_ENABLED
+ QAction *cancelAction;
+#endif
+ bool useDefaultCancelText;
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+};
+
+void QProgressDialogPrivate::init(const QString &labelText, const QString &cancelText,
+ int min, int max)
+{
+ Q_Q(QProgressDialog);
+ label = new QLabel(labelText, q);
+ int align = q->style()->styleHint(QStyle::SH_ProgressDialog_TextLabelAlignment, 0, q);
+ label->setAlignment(Qt::Alignment(align));
+ bar = new QProgressBar(q);
+ bar->setRange(min, max);
+ autoClose = true;
+ autoReset = true;
+ forceHide = false;
+ QObject::connect(q, SIGNAL(canceled()), q, SLOT(cancel()));
+ forceTimer = new QTimer(q);
+ QObject::connect(forceTimer, SIGNAL(timeout()), q, SLOT(forceShow()));
+ if (useDefaultCancelText) {
+ retranslateStrings();
+ } else {
+ q->setCancelButtonText(cancelText);
+ }
+}
+
+void QProgressDialogPrivate::layout()
+{
+ Q_Q(QProgressDialog);
+ int sp = q->style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
+ int mtb = q->style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin);
+ int mlr = qMin(q->width() / 10, mtb);
+ const bool centered =
+ bool(q->style()->styleHint(QStyle::SH_ProgressDialog_CenterCancelButton, 0, q));
+
+ int additionalSpacing = 0;
+#ifdef Q_OS_SYMBIAN
+ //In Symbian, we need to have wider margins for dialog borders, as the actual border is some pixels
+ //inside the dialog area (to enable transparent borders)
+ additionalSpacing = mlr;
+#endif
+
+ QSize cs = cancel ? cancel->sizeHint() : QSize(0,0);
+ QSize bh = bar->sizeHint();
+ int cspc;
+ int lh = 0;
+
+ // Find spacing and sizes that fit. It is important that a progress
+ // dialog can be made very small if the user demands it so.
+ for (int attempt=5; attempt--;) {
+ cspc = cancel ? cs.height() + sp : 0;
+ lh = qMax(0, q->height() - mtb - bh.height() - sp - cspc);
+
+ if (lh < q->height()/4) {
+ // Getting cramped
+ sp /= 2;
+ mtb /= 2;
+ if (cancel) {
+ cs.setHeight(qMax(4,cs.height()-sp-2));
+ }
+ bh.setHeight(qMax(4,bh.height()-sp-1));
+ } else {
+ break;
+ }
+ }
+
+ if (cancel) {
+ cancel->setGeometry(
+ centered ? q->width()/2 - cs.width()/2 : q->width() - mlr - cs.width(),
+ q->height() - mtb - cs.height(),
+ cs.width(), cs.height());
+ }
+
+ if (label)
+ label->setGeometry(mlr, additionalSpacing, q->width() - mlr * 2, lh);
+ bar->setGeometry(mlr, lh + sp + additionalSpacing, q->width() - mlr * 2, bh.height());
+}
+
+void QProgressDialogPrivate::retranslateStrings()
+{
+ Q_Q(QProgressDialog);
+ if (useDefaultCancelText)
+ q->setCancelButtonText(QProgressDialog::tr("Cancel"));
+}
+
+void QProgressDialogPrivate::_q_disconnectOnClose()
+{
+ Q_Q(QProgressDialog);
+ if (receiverToDisconnectOnClose) {
+ QObject::disconnect(q, SIGNAL(canceled()), receiverToDisconnectOnClose,
+ memberToDisconnectOnClose);
+ receiverToDisconnectOnClose = 0;
+ }
+ memberToDisconnectOnClose.clear();
+}
+
+/*!
+ \class QProgressDialog
+ \brief The QProgressDialog class provides feedback on the progress of a slow operation.
+ \ingroup standard-dialogs
+
+
+ A progress dialog is used to give the user an indication of how long
+ an operation is going to take, and to demonstrate that the
+ application has not frozen. It can also give the user an opportunity
+ to abort the operation.
+
+ A common problem with progress dialogs is that it is difficult to know
+ when to use them; operations take different amounts of time on different
+ hardware. QProgressDialog offers a solution to this problem:
+ it estimates the time the operation will take (based on time for
+ steps), and only shows itself if that estimate is beyond minimumDuration()
+ (4 seconds by default).
+
+ Use setMinimum() and setMaximum() or the constructor to set the number of
+ "steps" in the operation and call setValue() as the operation
+ progresses. The number of steps can be chosen arbitrarily. It can be the
+ number of files copied, the number of bytes received, the number of
+ iterations through the main loop of your algorithm, or some other
+ suitable unit. Progress starts at the value set by setMinimum(),
+ and the progress dialog shows that the operation has finished when
+ you call setValue() with the value set by setMaximum() as its argument.
+
+ The dialog automatically resets and hides itself at the end of the
+ operation. Use setAutoReset() and setAutoClose() to change this
+ behavior. Note that if you set a new maximum (using setMaximum() or
+ setRange()) that equals your current value(), the dialog will not
+ close regardless.
+
+ There are two ways of using QProgressDialog: modal and modeless.
+
+ Compared to a modeless QProgressDialog, a modal QProgressDialog is simpler
+ to use for the programmer. Do the operation in a loop, call \l setValue() at
+ intervals, and check for cancellation with wasCanceled(). For example:
+
+ \snippet doc/src/snippets/dialogs/dialogs.cpp 3
+
+ A modeless progress dialog is suitable for operations that take
+ place in the background, where the user is able to interact with the
+ application. Such operations are typically based on QTimer (or
+ QObject::timerEvent()), QSocketNotifier, or QUrlOperator; or performed
+ in a separate thread. A QProgressBar in the status bar of your main window
+ is often an alternative to a modeless progress dialog.
+
+ You need to have an event loop to be running, connect the
+ canceled() signal to a slot that stops the operation, and call \l
+ setValue() at intervals. For example:
+
+ \snippet doc/src/snippets/dialogs/dialogs.cpp 4
+ \codeline
+ \snippet doc/src/snippets/dialogs/dialogs.cpp 5
+ \codeline
+ \snippet doc/src/snippets/dialogs/dialogs.cpp 6
+
+ In both modes the progress dialog may be customized by
+ replacing the child widgets with custom widgets by using setLabel(),
+ setBar(), and setCancelButton().
+ The functions setLabelText() and setCancelButtonText()
+ set the texts shown.
+
+ \image plastique-progressdialog.png A progress dialog shown in the Plastique widget style.
+
+ \sa QDialog, QProgressBar, {fowler}{GUI Design Handbook: Progress Indicator},
+ {Find Files Example}, {Pixelator Example}
+*/
+
+
+/*!
+ Constructs a progress dialog.
+
+ Default settings:
+ \list
+ \i The label text is empty.
+ \i The cancel button text is (translated) "Cancel".
+ \i minimum is 0;
+ \i maximum is 100
+ \endlist
+
+ The \a parent argument is dialog's parent widget. The widget flags, \a f, are
+ passed to the QDialog::QDialog() constructor.
+
+ \sa setLabelText(), setCancelButtonText(), setCancelButton(),
+ setMinimum(), setMaximum()
+*/
+
+QProgressDialog::QProgressDialog(QWidget *parent, Qt::WindowFlags f)
+ : QDialog(*(new QProgressDialogPrivate), parent, f)
+{
+ Q_D(QProgressDialog);
+ d->useDefaultCancelText = true;
+ d->init(QString::fromLatin1(""), QString(), 0, 100);
+}
+
+/*!
+ Constructs a progress dialog.
+
+ The \a labelText is the text used to remind the user what is progressing.
+
+ The \a cancelButtonText is the text to display on the cancel button. If
+ QString() is passed then no cancel button is shown.
+
+ The \a minimum and \a maximum is the number of steps in the operation for
+ which this progress dialog shows progress. For example, if the
+ operation is to examine 50 files, this value minimum value would be 0,
+ and the maximum would be 50. Before examining the first file, call
+ setValue(0). As each file is processed call setValue(1), setValue(2),
+ etc., finally calling setValue(50) after examining the last file.
+
+ The \a parent argument is the dialog's parent widget. The parent, \a parent, and
+ widget flags, \a f, are passed to the QDialog::QDialog() constructor.
+
+ \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(),
+ setMinimum(), setMaximum()
+*/
+
+QProgressDialog::QProgressDialog(const QString &labelText,
+ const QString &cancelButtonText,
+ int minimum, int maximum,
+ QWidget *parent, Qt::WindowFlags f)
+ : QDialog(*(new QProgressDialogPrivate), parent, f)
+{
+ Q_D(QProgressDialog);
+ d->init(labelText, cancelButtonText, minimum, maximum);
+}
+
+
+/*!
+ Destroys the progress dialog.
+*/
+
+QProgressDialog::~QProgressDialog()
+{
+}
+
+/*!
+ \fn void QProgressDialog::canceled()
+
+ This signal is emitted when the cancel button is clicked.
+ It is connected to the cancel() slot by default.
+
+ \sa wasCanceled()
+*/
+
+
+/*!
+ Sets the label to \a label. The progress dialog resizes to fit. The
+ label becomes owned by the progress dialog and will be deleted when
+ necessary, so do not pass the address of an object on the stack.
+
+ \sa setLabelText()
+*/
+
+void QProgressDialog::setLabel(QLabel *label)
+{
+ Q_D(QProgressDialog);
+ delete d->label;
+ d->label = label;
+ if (label) {
+ if (label->parentWidget() == this) {
+ label->hide(); // until we resize
+ } else {
+ label->setParent(this, 0);
+ }
+ }
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ if (label)
+ label->show();
+}
+
+
+/*!
+ \property QProgressDialog::labelText
+ \brief the label's text
+
+ The default text is an empty string.
+*/
+
+QString QProgressDialog::labelText() const
+{
+ Q_D(const QProgressDialog);
+ if (d->label)
+ return d->label->text();
+ return QString();
+}
+
+void QProgressDialog::setLabelText(const QString &text)
+{
+ Q_D(QProgressDialog);
+ if (d->label) {
+ d->label->setText(text);
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ }
+}
+
+
+/*!
+ Sets the cancel button to the push button, \a cancelButton. The
+ progress dialog takes ownership of this button which will be deleted
+ when necessary, so do not pass the address of an object that is on
+ the stack, i.e. use new() to create the button. If 0 is passed then
+ no cancel button will be shown.
+
+ \sa setCancelButtonText()
+*/
+
+void QProgressDialog::setCancelButton(QPushButton *cancelButton)
+{
+ Q_D(QProgressDialog);
+ delete d->cancel;
+ d->cancel = cancelButton;
+ if (cancelButton) {
+ if (cancelButton->parentWidget() == this) {
+ cancelButton->hide(); // until we resize
+ } else {
+ cancelButton->setParent(this, 0);
+ }
+ connect(d->cancel, SIGNAL(clicked()), this, SIGNAL(canceled()));
+#ifndef QT_NO_SHORTCUT
+ d->escapeShortcut = new QShortcut(Qt::Key_Escape, this, SIGNAL(canceled()));
+#endif
+ } else {
+#ifndef QT_NO_SHORTCUT
+ delete d->escapeShortcut;
+ d->escapeShortcut = 0;
+#endif
+ }
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ if (cancelButton)
+#if !defined(QT_SOFTKEYS_ENABLED)
+ cancelButton->show();
+#else
+ {
+ d->cancelAction = new QAction(cancelButton->text(), cancelButton);
+ d->cancelAction->setSoftKeyRole(QAction::NegativeSoftKey);
+ connect(d->cancelAction, SIGNAL(triggered()), this, SIGNAL(canceled()));
+ addAction(d->cancelAction);
+ }
+#endif
+}
+
+/*!
+ Sets the cancel button's text to \a cancelButtonText. If the text
+ is set to QString() then it will cause the cancel button to be
+ hidden and deleted.
+
+ \sa setCancelButton()
+*/
+
+void QProgressDialog::setCancelButtonText(const QString &cancelButtonText)
+{
+ Q_D(QProgressDialog);
+ d->useDefaultCancelText = false;
+
+ if (!cancelButtonText.isNull()) {
+ if (d->cancel) {
+ d->cancel->setText(cancelButtonText);
+#ifdef QT_SOFTKEYS_ENABLED
+ d->cancelAction->setText(cancelButtonText);
+#endif
+ } else {
+ setCancelButton(new QPushButton(cancelButtonText, this));
+ }
+ } else {
+ setCancelButton(0);
+ }
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+}
+
+
+/*!
+ Sets the progress bar widget to \a bar. The progress dialog resizes to
+ fit. The progress dialog takes ownership of the progress \a bar which
+ will be deleted when necessary, so do not use a progress bar
+ allocated on the stack.
+*/
+
+void QProgressDialog::setBar(QProgressBar *bar)
+{
+ Q_D(QProgressDialog);
+ if (!bar) {
+ qWarning("QProgressDialog::setBar: Cannot set a null progress bar");
+ return;
+ }
+#ifndef QT_NO_DEBUG
+ if (value() > 0)
+ qWarning("QProgressDialog::setBar: Cannot set a new progress bar "
+ "while the old one is active");
+#endif
+ delete d->bar;
+ d->bar = bar;
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+}
+
+
+/*!
+ \property QProgressDialog::wasCanceled
+ \brief whether the dialog was canceled
+*/
+
+bool QProgressDialog::wasCanceled() const
+{
+ Q_D(const QProgressDialog);
+ return d->cancellation_flag;
+}
+
+
+/*!
+ \property QProgressDialog::maximum
+ \brief the highest value represented by the progress bar
+
+ The default is 0.
+
+ \sa minimum, setRange()
+*/
+
+int QProgressDialog::maximum() const
+{
+ Q_D(const QProgressDialog);
+ return d->bar->maximum();
+}
+
+void QProgressDialog::setMaximum(int maximum)
+{
+ Q_D(QProgressDialog);
+ d->bar->setMaximum(maximum);
+}
+
+/*!
+ \property QProgressDialog::minimum
+ \brief the lowest value represented by the progress bar
+
+ The default is 0.
+
+ \sa maximum, setRange()
+*/
+
+int QProgressDialog::minimum() const
+{
+ Q_D(const QProgressDialog);
+ return d->bar->minimum();
+}
+
+void QProgressDialog::setMinimum(int minimum)
+{
+ Q_D(QProgressDialog);
+ d->bar->setMinimum(minimum);
+}
+
+/*!
+ Sets the progress dialog's minimum and maximum values
+ to \a minimum and \a maximum, respectively.
+
+ If \a maximum is smaller than \a minimum, \a minimum becomes the only
+ legal value.
+
+ If the current value falls outside the new range, the progress
+ dialog is reset with reset().
+
+ \sa minimum, maximum
+*/
+void QProgressDialog::setRange(int minimum, int maximum)
+{
+ Q_D(QProgressDialog);
+ d->bar->setRange(minimum, maximum);
+}
+
+
+/*!
+ Resets the progress dialog.
+ The progress dialog becomes hidden if autoClose() is true.
+
+ \sa setAutoClose(), setAutoReset()
+*/
+
+void QProgressDialog::reset()
+{
+ Q_D(QProgressDialog);
+#ifndef QT_NO_CURSOR
+ if (value() >= 0) {
+ if (parentWidget())
+ parentWidget()->setCursor(d->parentCursor);
+ }
+#endif
+ if (d->autoClose || d->forceHide)
+ hide();
+ d->bar->reset();
+ d->cancellation_flag = false;
+ d->shown_once = false;
+ d->forceTimer->stop();
+
+ /*
+ I wish we could disconnect the user slot provided to open() here but
+ unfortunately reset() is usually called before the slot has been invoked.
+ (reset() is itself invoked when canceled() is emitted.)
+ */
+ if (d->receiverToDisconnectOnClose)
+ QMetaObject::invokeMethod(this, "_q_disconnectOnClose", Qt::QueuedConnection);
+}
+
+/*!
+ Resets the progress dialog. wasCanceled() becomes true until
+ the progress dialog is reset.
+ The progress dialog becomes hidden.
+*/
+
+void QProgressDialog::cancel()
+{
+ Q_D(QProgressDialog);
+ d->forceHide = true;
+ reset();
+ d->forceHide = false;
+ d->cancellation_flag = true;
+}
+
+
+int QProgressDialog::value() const
+{
+ Q_D(const QProgressDialog);
+ return d->bar->value();
+}
+
+/*!
+ \property QProgressDialog::value
+ \brief the current amount of progress made.
+
+ For the progress dialog to work as expected, you should initially set
+ this property to 0 and finally set it to
+ QProgressDialog::maximum(); you can call setValue() any number of times
+ in-between.
+
+ \warning If the progress dialog is modal
+ (see QProgressDialog::QProgressDialog()),
+ setValue() calls QApplication::processEvents(), so take care that
+ this does not cause undesirable re-entrancy in your code. For example,
+ don't use a QProgressDialog inside a paintEvent()!
+
+ \sa minimum, maximum
+*/
+void QProgressDialog::setValue(int progress)
+{
+ Q_D(QProgressDialog);
+ if (progress == d->bar->value()
+ || (d->bar->value() == -1 && progress == d->bar->maximum()))
+ return;
+
+ d->bar->setValue(progress);
+
+ if (d->shown_once) {
+ if (isModal())
+ QApplication::processEvents();
+ } else {
+ if (progress == 0) {
+ d->starttime.start();
+ d->forceTimer->start(d->showTime);
+ return;
+ } else {
+ bool need_show;
+ int elapsed = d->starttime.elapsed();
+ if (elapsed >= d->showTime) {
+ need_show = true;
+ } else {
+ if (elapsed > minWaitTime) {
+ int estimate;
+ int totalSteps = maximum() - minimum();
+ int myprogress = progress - minimum();
+ if ((totalSteps - myprogress) >= INT_MAX / elapsed)
+ estimate = (totalSteps - myprogress) / myprogress * elapsed;
+ else
+ estimate = elapsed * (totalSteps - myprogress) / myprogress;
+ need_show = estimate >= d->showTime;
+ } else {
+ need_show = false;
+ }
+ }
+ if (need_show) {
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ show();
+ d->shown_once = true;
+ }
+ }
+#ifdef Q_WS_MAC
+ QApplication::flush();
+#endif
+ }
+
+ if (progress == d->bar->maximum() && d->autoReset)
+ reset();
+}
+
+/*!
+ Returns a size that fits the contents of the progress dialog.
+ The progress dialog resizes itself as required, so you should not
+ need to call this yourself.
+*/
+
+QSize QProgressDialog::sizeHint() const
+{
+ Q_D(const QProgressDialog);
+ QSize sh = d->label ? d->label->sizeHint() : QSize(0, 0);
+ QSize bh = d->bar->sizeHint();
+ int margin = style()->pixelMetric(QStyle::PM_DefaultTopLevelMargin);
+ int spacing = style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing);
+ int h = margin * 2 + bh.height() + sh.height() + spacing;
+ if (d->cancel)
+ h += d->cancel->sizeHint().height() + spacing;
+#ifdef Q_WS_S60
+ if (QApplication::desktop()->size().height() > QApplication::desktop()->size().width())
+ return QSize(qMax(QApplication::desktop()->size().width(), sh.width() + 2 * margin), h);
+ else
+ return QSize(qMax(QApplication::desktop()->size().height(), sh.width() + 2 * margin), h);
+#else
+ return QSize(qMax(200, sh.width() + 2 * margin), h);
+#endif
+}
+
+/*!\reimp
+*/
+void QProgressDialog::resizeEvent(QResizeEvent *)
+{
+ Q_D(QProgressDialog);
+ d->layout();
+}
+
+/*!
+ \reimp
+*/
+void QProgressDialog::changeEvent(QEvent *ev)
+{
+ Q_D(QProgressDialog);
+ if (ev->type() == QEvent::StyleChange) {
+ d->layout();
+ } else if (ev->type() == QEvent::LanguageChange) {
+ d->retranslateStrings();
+ }
+ QDialog::changeEvent(ev);
+}
+
+/*!
+ \property QProgressDialog::minimumDuration
+ \brief the time that must pass before the dialog appears
+
+ If the expected duration of the task is less than the
+ minimumDuration, the dialog will not appear at all. This prevents
+ the dialog popping up for tasks that are quickly over. For tasks
+ that are expected to exceed the minimumDuration, the dialog will
+ pop up after the minimumDuration time or as soon as any progress
+ is set.
+
+ If set to 0, the dialog is always shown as soon as any progress is
+ set. The default is 4000 milliseconds.
+*/
+void QProgressDialog::setMinimumDuration(int ms)
+{
+ Q_D(QProgressDialog);
+ d->showTime = ms;
+ if (d->bar->value() == 0) {
+ d->forceTimer->stop();
+ d->forceTimer->start(ms);
+ }
+}
+
+int QProgressDialog::minimumDuration() const
+{
+ Q_D(const QProgressDialog);
+ return d->showTime;
+}
+
+
+/*!
+ \reimp
+*/
+
+void QProgressDialog::closeEvent(QCloseEvent *e)
+{
+ emit canceled();
+ QDialog::closeEvent(e);
+}
+
+/*!
+ \property QProgressDialog::autoReset
+ \brief whether the progress dialog calls reset() as soon as value() equals maximum()
+
+ The default is true.
+
+ \sa setAutoClose()
+*/
+
+void QProgressDialog::setAutoReset(bool b)
+{
+ Q_D(QProgressDialog);
+ d->autoReset = b;
+}
+
+bool QProgressDialog::autoReset() const
+{
+ Q_D(const QProgressDialog);
+ return d->autoReset;
+}
+
+/*!
+ \property QProgressDialog::autoClose
+ \brief whether the dialog gets hidden by reset()
+
+ The default is true.
+
+ \sa setAutoReset()
+*/
+
+void QProgressDialog::setAutoClose(bool close)
+{
+ Q_D(QProgressDialog);
+ d->autoClose = close;
+}
+
+bool QProgressDialog::autoClose() const
+{
+ Q_D(const QProgressDialog);
+ return d->autoClose;
+}
+
+/*!
+ \reimp
+*/
+
+void QProgressDialog::showEvent(QShowEvent *e)
+{
+ Q_D(QProgressDialog);
+ QDialog::showEvent(e);
+ int w = qMax(isVisible() ? width() : 0, sizeHint().width());
+ int h = qMax(isVisible() ? height() : 0, sizeHint().height());
+ resize(w, h);
+ d->forceTimer->stop();
+}
+
+/*!
+ Shows the dialog if it is still hidden after the algorithm has been started
+ and minimumDuration milliseconds have passed.
+
+ \sa setMinimumDuration()
+*/
+
+void QProgressDialog::forceShow()
+{
+ Q_D(QProgressDialog);
+ d->forceTimer->stop();
+ if (d->shown_once || d->cancellation_flag)
+ return;
+
+ show();
+ d->shown_once = true;
+}
+
+/*!
+ \since 4.5
+ \overload
+
+ Opens the dialog and connects its accepted() signal to the slot specified
+ by \a receiver and \a member.
+
+ The signal will be disconnected from the slot when the dialog is closed.
+*/
+void QProgressDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QProgressDialog);
+ connect(this, SIGNAL(canceled()), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qprogressdialog.cpp"
+
+#endif // QT_NO_PROGRESSDIALOG
diff --git a/src/widgets/dialogs/qprogressdialog.h b/src/widgets/dialogs/qprogressdialog.h
new file mode 100644
index 0000000000..b981e5ef63
--- /dev/null
+++ b/src/widgets/dialogs/qprogressdialog.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPROGRESSDIALOG_H
+#define QPROGRESSDIALOG_H
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_PROGRESSDIALOG
+
+class QPushButton;
+class QLabel;
+class QProgressBar;
+class QTimer;
+class QProgressDialogPrivate;
+
+class Q_WIDGETS_EXPORT QProgressDialog : public QDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QProgressDialog)
+ Q_PROPERTY(bool wasCanceled READ wasCanceled)
+ Q_PROPERTY(int minimum READ minimum WRITE setMinimum)
+ Q_PROPERTY(int maximum READ maximum WRITE setMaximum)
+ Q_PROPERTY(int value READ value WRITE setValue)
+ Q_PROPERTY(bool autoReset READ autoReset WRITE setAutoReset)
+ Q_PROPERTY(bool autoClose READ autoClose WRITE setAutoClose)
+ Q_PROPERTY(int minimumDuration READ minimumDuration WRITE setMinimumDuration)
+ Q_PROPERTY(QString labelText READ labelText WRITE setLabelText)
+
+public:
+ explicit QProgressDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ QProgressDialog(const QString &labelText, const QString &cancelButtonText,
+ int minimum, int maximum, QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~QProgressDialog();
+
+ void setLabel(QLabel *label);
+ void setCancelButton(QPushButton *button);
+ void setBar(QProgressBar *bar);
+
+ bool wasCanceled() const;
+
+ int minimum() const;
+ int maximum() const;
+
+ int value() const;
+
+ QSize sizeHint() const;
+
+ QString labelText() const;
+ int minimumDuration() const;
+
+ void setAutoReset(bool reset);
+ bool autoReset() const;
+ void setAutoClose(bool close);
+ bool autoClose() const;
+
+#ifdef Q_NO_USING_KEYWORD
+#ifndef Q_QDOC
+ void open() { QDialog::open(); }
+#endif
+#else
+ using QDialog::open;
+#endif
+ void open(QObject *receiver, const char *member);
+
+public Q_SLOTS:
+ void cancel();
+ void reset();
+ void setMaximum(int maximum);
+ void setMinimum(int minimum);
+ void setRange(int minimum, int maximum);
+ void setValue(int progress);
+ void setLabelText(const QString &text);
+ void setCancelButtonText(const QString &text);
+ void setMinimumDuration(int ms);
+
+Q_SIGNALS:
+ void canceled();
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void closeEvent(QCloseEvent *event);
+ void changeEvent(QEvent *event);
+ void showEvent(QShowEvent *event);
+
+protected Q_SLOTS:
+ void forceShow();
+
+private:
+ Q_DISABLE_COPY(QProgressDialog)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_disconnectOnClose())
+};
+
+#endif // QT_NO_PROGRESSDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPROGRESSDIALOG_H
diff --git a/src/widgets/dialogs/qsidebar.cpp b/src/widgets/dialogs/qsidebar.cpp
new file mode 100644
index 0000000000..8efbb8dfcd
--- /dev/null
+++ b/src/widgets/dialogs/qsidebar.cpp
@@ -0,0 +1,509 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsidebar_p.h"
+#include "qfilesystemmodel.h"
+
+#ifndef QT_NO_FILEDIALOG
+
+#include <qaction.h>
+#include <qurl.h>
+#include <qmenu.h>
+#include <qmimedata.h>
+#include <qevent.h>
+#include <qdebug.h>
+#include <qfileiconprovider.h>
+#include <qfiledialog.h>
+
+QT_BEGIN_NAMESPACE
+
+void QSideBarDelegate::initStyleOption(QStyleOptionViewItem *option,
+ const QModelIndex &index) const
+{
+ QStyledItemDelegate::initStyleOption(option,index);
+ QVariant value = index.data(QUrlModel::EnabledRole);
+ if (value.isValid()) {
+ //If the bookmark/entry is not enabled then we paint it in gray
+ if (!qvariant_cast<bool>(value))
+ option->state &= ~QStyle::State_Enabled;
+ }
+}
+
+/*!
+ QUrlModel lets you have indexes from a QFileSystemModel to a list. When QFileSystemModel
+ changes them QUrlModel will automatically update.
+
+ Example usage: File dialog sidebar and combo box
+ */
+QUrlModel::QUrlModel(QObject *parent) : QStandardItemModel(parent), showFullPath(false), fileSystemModel(0)
+{
+}
+
+/*!
+ \reimp
+*/
+QStringList QUrlModel::mimeTypes() const
+{
+ return QStringList(QLatin1String("text/uri-list"));
+}
+
+/*!
+ \reimp
+*/
+Qt::ItemFlags QUrlModel::flags(const QModelIndex &index) const
+{
+ Qt::ItemFlags flags = QStandardItemModel::flags(index);
+ if (index.isValid()) {
+ flags &= ~Qt::ItemIsEditable;
+ // ### some future version could support "moving" urls onto a folder
+ flags &= ~Qt::ItemIsDropEnabled;
+ }
+
+ if (index.data(Qt::DecorationRole).isNull())
+ flags &= ~Qt::ItemIsEnabled;
+
+ return flags;
+}
+
+/*!
+ \reimp
+*/
+QMimeData *QUrlModel::mimeData(const QModelIndexList &indexes) const
+{
+ QList<QUrl> list;
+ for (int i = 0; i < indexes.count(); ++i) {
+ if (indexes.at(i).column() == 0)
+ list.append(indexes.at(i).data(UrlRole).toUrl());
+ }
+ QMimeData *data = new QMimeData();
+ data->setUrls(list);
+ return data;
+}
+
+#ifndef QT_NO_DRAGANDDROP
+
+/*!
+ Decide based upon the data if it should be accepted or not
+
+ We only accept dirs and not files
+*/
+bool QUrlModel::canDrop(QDragEnterEvent *event)
+{
+ if (!event->mimeData()->formats().contains(mimeTypes().first()))
+ return false;
+
+ const QList<QUrl> list = event->mimeData()->urls();
+ for (int i = 0; i < list.count(); ++i) {
+ QModelIndex idx = fileSystemModel->index(list.at(0).toLocalFile());
+ if (!fileSystemModel->isDir(idx))
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \reimp
+*/
+bool QUrlModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent)
+{
+ if (!data->formats().contains(mimeTypes().first()))
+ return false;
+ Q_UNUSED(action);
+ Q_UNUSED(column);
+ Q_UNUSED(parent);
+ addUrls(data->urls(), row);
+ return true;
+}
+
+#endif // QT_NO_DRAGANDDROP
+
+/*!
+ \reimp
+
+ If the role is the UrlRole then handle otherwise just pass to QStandardItemModel
+*/
+bool QUrlModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (value.type() == QVariant::Url) {
+ QUrl url = value.toUrl();
+ QModelIndex dirIndex = fileSystemModel->index(url.toLocalFile());
+ //On windows the popup display the "C:\", convert to nativeSeparators
+ if (showFullPath)
+ QStandardItemModel::setData(index, QDir::toNativeSeparators(fileSystemModel->data(dirIndex, QFileSystemModel::FilePathRole).toString()));
+ else {
+ QStandardItemModel::setData(index, QDir::toNativeSeparators(fileSystemModel->data(dirIndex, QFileSystemModel::FilePathRole).toString()), Qt::ToolTipRole);
+ QStandardItemModel::setData(index, fileSystemModel->data(dirIndex).toString());
+ }
+ QStandardItemModel::setData(index, fileSystemModel->data(dirIndex, Qt::DecorationRole),
+ Qt::DecorationRole);
+ QStandardItemModel::setData(index, url, UrlRole);
+ return true;
+ }
+ return QStandardItemModel::setData(index, value, role);
+}
+
+void QUrlModel::setUrl(const QModelIndex &index, const QUrl &url, const QModelIndex &dirIndex)
+{
+ setData(index, url, UrlRole);
+ if (url.path().isEmpty()) {
+ setData(index, fileSystemModel->myComputer());
+ setData(index, fileSystemModel->myComputer(Qt::DecorationRole), Qt::DecorationRole);
+ } else {
+ QString newName;
+ if (showFullPath) {
+ //On windows the popup display the "C:\", convert to nativeSeparators
+ newName = QDir::toNativeSeparators(dirIndex.data(QFileSystemModel::FilePathRole).toString());
+ } else {
+ newName = dirIndex.data().toString();
+ }
+
+ QIcon newIcon = qvariant_cast<QIcon>(dirIndex.data(Qt::DecorationRole));
+ if (!dirIndex.isValid()) {
+ newIcon = fileSystemModel->iconProvider()->icon(QFileIconProvider::Folder);
+ newName = QFileInfo(url.toLocalFile()).fileName();
+ if (!invalidUrls.contains(url))
+ invalidUrls.append(url);
+ //The bookmark is invalid then we set to false the EnabledRole
+ setData(index, false, EnabledRole);
+ } else {
+ //The bookmark is valid then we set to true the EnabledRole
+ setData(index, true, EnabledRole);
+ }
+
+ // Make sure that we have at least 32x32 images
+ const QSize size = newIcon.actualSize(QSize(32,32));
+ if (size.width() < 32) {
+ QPixmap smallPixmap = newIcon.pixmap(QSize(32, 32));
+ newIcon.addPixmap(smallPixmap.scaledToWidth(32, Qt::SmoothTransformation));
+ }
+
+ if (index.data().toString() != newName)
+ setData(index, newName);
+ QIcon oldIcon = qvariant_cast<QIcon>(index.data(Qt::DecorationRole));
+ if (oldIcon.cacheKey() != newIcon.cacheKey())
+ setData(index, newIcon, Qt::DecorationRole);
+ }
+}
+
+void QUrlModel::setUrls(const QList<QUrl> &list)
+{
+ removeRows(0, rowCount());
+ invalidUrls.clear();
+ watching.clear();
+ addUrls(list, 0);
+}
+
+/*!
+ Add urls \a list into the list at \a row. If move then movie
+ existing ones to row.
+
+ \sa dropMimeData()
+*/
+void QUrlModel::addUrls(const QList<QUrl> &list, int row, bool move)
+{
+ if (row == -1)
+ row = rowCount();
+ row = qMin(row, rowCount());
+ for (int i = list.count() - 1; i >= 0; --i) {
+ QUrl url = list.at(i);
+ if (!url.isValid() || url.scheme() != QLatin1String("file"))
+ continue;
+ //this makes sure the url is clean
+ const QString cleanUrl = QDir::cleanPath(url.toLocalFile());
+ url = QUrl::fromLocalFile(cleanUrl);
+
+ for (int j = 0; move && j < rowCount(); ++j) {
+ QString local = index(j, 0).data(UrlRole).toUrl().toLocalFile();
+#if defined(Q_OS_WIN)
+ if (index(j, 0).data(UrlRole).toUrl().toLocalFile().toLower() == cleanUrl.toLower()) {
+#else
+ if (index(j, 0).data(UrlRole).toUrl().toLocalFile() == cleanUrl) {
+#endif
+ removeRow(j);
+ if (j <= row)
+ row--;
+ break;
+ }
+ }
+ row = qMax(row, 0);
+ QModelIndex idx = fileSystemModel->index(cleanUrl);
+ if (!fileSystemModel->isDir(idx))
+ continue;
+ insertRows(row, 1);
+ setUrl(index(row, 0), url, idx);
+ watching.append(qMakePair(idx, cleanUrl));
+ }
+}
+
+/*!
+ Return the complete list of urls in a QList.
+*/
+QList<QUrl> QUrlModel::urls() const
+{
+ QList<QUrl> list;
+ for (int i = 0; i < rowCount(); ++i)
+ list.append(data(index(i, 0), UrlRole).toUrl());
+ return list;
+}
+
+/*!
+ QFileSystemModel to get index's from, clears existing rows
+*/
+void QUrlModel::setFileSystemModel(QFileSystemModel *model)
+{
+ if (model == fileSystemModel)
+ return;
+ if (fileSystemModel != 0) {
+ disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(dataChanged(QModelIndex,QModelIndex)));
+ disconnect(model, SIGNAL(layoutChanged()),
+ this, SLOT(layoutChanged()));
+ disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(layoutChanged()));
+ }
+ fileSystemModel = model;
+ if (fileSystemModel != 0) {
+ connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
+ this, SLOT(dataChanged(QModelIndex,QModelIndex)));
+ connect(model, SIGNAL(layoutChanged()),
+ this, SLOT(layoutChanged()));
+ connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
+ this, SLOT(layoutChanged()));
+ }
+ clear();
+ insertColumns(0, 1);
+}
+
+/*
+ If one of the index's we are watching has changed update our internal data
+*/
+void QUrlModel::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
+{
+ QModelIndex parent = topLeft.parent();
+ for (int i = 0; i < watching.count(); ++i) {
+ QModelIndex index = watching.at(i).first;
+ if (index.model() && topLeft.model()) {
+ Q_ASSERT(index.model() == topLeft.model());
+ }
+ if ( index.row() >= topLeft.row()
+ && index.row() <= bottomRight.row()
+ && index.column() >= topLeft.column()
+ && index.column() <= bottomRight.column()
+ && index.parent() == parent) {
+ changed(watching.at(i).second);
+ }
+ }
+}
+
+/*!
+ Re-get all of our data, anything could have changed!
+ */
+void QUrlModel::layoutChanged()
+{
+ QStringList paths;
+ for (int i = 0; i < watching.count(); ++i)
+ paths.append(watching.at(i).second);
+ watching.clear();
+ for (int i = 0; i < paths.count(); ++i) {
+ QString path = paths.at(i);
+ QModelIndex newIndex = fileSystemModel->index(path);
+ watching.append(QPair<QModelIndex, QString>(newIndex, path));
+ if (newIndex.isValid())
+ changed(path);
+ }
+}
+
+/*!
+ The following path changed data update our copy of that data
+
+ \sa layoutChanged() dataChanged()
+*/
+void QUrlModel::changed(const QString &path)
+{
+ for (int i = 0; i < rowCount(); ++i) {
+ QModelIndex idx = index(i, 0);
+ if (idx.data(UrlRole).toUrl().toLocalFile() == path) {
+ setData(idx, idx.data(UrlRole).toUrl());
+ }
+ }
+}
+
+QSidebar::QSidebar(QWidget *parent) : QListView(parent)
+{
+}
+
+void QSidebar::init(QFileSystemModel *model, const QList<QUrl> &newUrls)
+{
+ // ### TODO make icon size dynamic
+ setIconSize(QSize(24,24));
+ setUniformItemSizes(true);
+ urlModel = new QUrlModel(this);
+ urlModel->setFileSystemModel(model);
+ setModel(urlModel);
+ setItemDelegate(new QSideBarDelegate(this));
+
+ connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this, SLOT(clicked(QModelIndex)));
+#ifndef QT_NO_DRAGANDDROP
+ setDragDropMode(QAbstractItemView::DragDrop);
+#endif
+ setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(this, SIGNAL(customContextMenuRequested(QPoint)),
+ this, SLOT(showContextMenu(QPoint)));
+ urlModel->setUrls(newUrls);
+ setCurrentIndex(this->model()->index(0,0));
+}
+
+QSidebar::~QSidebar()
+{
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QSidebar::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (urlModel->canDrop(event))
+ QListView::dragEnterEvent(event);
+}
+#endif // QT_NO_DRAGANDDROP
+
+QSize QSidebar::sizeHint() const
+{
+ if (model())
+ return QListView::sizeHintForIndex(model()->index(0, 0)) + QSize(2 * frameWidth(), 2 * frameWidth());
+ return QListView::sizeHint();
+}
+
+void QSidebar::selectUrl(const QUrl &url)
+{
+ disconnect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this, SLOT(clicked(QModelIndex)));
+
+ selectionModel()->clear();
+ for (int i = 0; i < model()->rowCount(); ++i) {
+ if (model()->index(i, 0).data(QUrlModel::UrlRole).toUrl() == url) {
+ selectionModel()->select(model()->index(i, 0), QItemSelectionModel::Select);
+ break;
+ }
+ }
+
+ connect(selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
+ this, SLOT(clicked(QModelIndex)));
+}
+
+#ifndef QT_NO_MENU
+/*!
+ \internal
+
+ \sa removeEntry()
+*/
+void QSidebar::showContextMenu(const QPoint &position)
+{
+ QList<QAction *> actions;
+ if (indexAt(position).isValid()) {
+ QAction *action = new QAction(QFileDialog::tr("Remove"), this);
+ if (indexAt(position).data(QUrlModel::UrlRole).toUrl().path().isEmpty())
+ action->setEnabled(false);
+ connect(action, SIGNAL(triggered()), this, SLOT(removeEntry()));
+ actions.append(action);
+ }
+ if (actions.count() > 0)
+ QMenu::exec(actions, mapToGlobal(position));
+}
+#endif // QT_NO_MENU
+
+/*!
+ \internal
+
+ \sa showContextMenu()
+*/
+void QSidebar::removeEntry()
+{
+ QList<QModelIndex> idxs = selectionModel()->selectedIndexes();
+ QList<QPersistentModelIndex> indexes;
+ for (int i = 0; i < idxs.count(); i++)
+ indexes.append(idxs.at(i));
+
+ for (int i = 0; i < indexes.count(); ++i)
+ if (!indexes.at(i).data(QUrlModel::UrlRole).toUrl().path().isEmpty())
+ model()->removeRow(indexes.at(i).row());
+}
+
+/*!
+ \internal
+
+ \sa goToUrl()
+*/
+void QSidebar::clicked(const QModelIndex &index)
+{
+ QUrl url = model()->index(index.row(), 0).data(QUrlModel::UrlRole).toUrl();
+ emit goToUrl(url);
+ selectUrl(url);
+}
+
+/*!
+ \reimp
+ Don't automatically select something
+ */
+void QSidebar::focusInEvent(QFocusEvent *event)
+{
+ QAbstractScrollArea::focusInEvent(event);
+ viewport()->update();
+}
+
+/*!
+ \reimp
+ */
+bool QSidebar::event(QEvent * event)
+{
+ if (event->type() == QEvent::KeyRelease) {
+ QKeyEvent* ke = (QKeyEvent*) event;
+ if (ke->key() == Qt::Key_Delete) {
+ removeEntry();
+ return true;
+ }
+ }
+ return QListView::event(event);
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qsidebar_p.h b/src/widgets/dialogs/qsidebar_p.h
new file mode 100644
index 0000000000..6ad2716780
--- /dev/null
+++ b/src/widgets/dialogs/qsidebar_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSIDEBAR_H
+#define QSIDEBAR_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qlistwidget.h>
+#include <qstandarditemmodel.h>
+#include <qstyleditemdelegate.h>
+#include <qurl.h>
+
+#ifndef QT_NO_FILEDIALOG
+
+QT_BEGIN_NAMESPACE
+
+class QFileSystemModel;
+
+class QSideBarDelegate : public QStyledItemDelegate
+{
+ public:
+ QSideBarDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}
+ void initStyleOption(QStyleOptionViewItem *option,
+ const QModelIndex &index) const;
+};
+
+class Q_AUTOTEST_EXPORT QUrlModel : public QStandardItemModel
+{
+ Q_OBJECT
+
+public:
+ enum Roles {
+ UrlRole = Qt::UserRole + 1,
+ EnabledRole = Qt::UserRole + 2
+ };
+
+ QUrlModel(QObject *parent = 0);
+
+ QStringList mimeTypes() const;
+ QMimeData *mimeData(const QModelIndexList &indexes) const;
+#ifndef QT_NO_DRAGANDDROP
+ bool canDrop(QDragEnterEvent *event);
+ bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+#endif
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);
+
+ void setUrls(const QList<QUrl> &list);
+ void addUrls(const QList<QUrl> &urls, int row = -1, bool move = true);
+ QList<QUrl> urls() const;
+ void setFileSystemModel(QFileSystemModel *model);
+ bool showFullPath;
+
+private Q_SLOTS:
+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+ void layoutChanged();
+
+private:
+ void setUrl(const QModelIndex &index, const QUrl &url, const QModelIndex &dirIndex);
+ void changed(const QString &path);
+ void addIndexToWatch(const QString &path, const QModelIndex &index);
+ QFileSystemModel *fileSystemModel;
+ QList<QPair<QModelIndex, QString> > watching;
+ QList<QUrl> invalidUrls;
+};
+
+class Q_AUTOTEST_EXPORT QSidebar : public QListView
+{
+ Q_OBJECT
+
+Q_SIGNALS:
+ void goToUrl(const QUrl &url);
+
+public:
+ QSidebar(QWidget *parent = 0);
+ void init(QFileSystemModel *model, const QList<QUrl> &newUrls);
+ ~QSidebar();
+
+ QSize sizeHint() const;
+
+ void setUrls(const QList<QUrl> &list) { urlModel->setUrls(list); }
+ void addUrls(const QList<QUrl> &list, int row) { urlModel->addUrls(list, row); }
+ QList<QUrl> urls() const { return urlModel->urls(); }
+
+ void selectUrl(const QUrl &url);
+
+protected:
+ bool event(QEvent * e);
+ void focusInEvent(QFocusEvent *event);
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *event);
+#endif
+
+private Q_SLOTS:
+ void clicked(const QModelIndex &index);
+#ifndef QT_NO_MENU
+ void showContextMenu(const QPoint &position);
+#endif
+ void removeEntry();
+
+private:
+ QUrlModel *urlModel;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FILEDIALOG
+
+#endif // QSIDEBAR_H
+
diff --git a/src/widgets/dialogs/qwizard.cpp b/src/widgets/dialogs/qwizard.cpp
new file mode 100644
index 0000000000..83bdaa0e55
--- /dev/null
+++ b/src/widgets/dialogs/qwizard.cpp
@@ -0,0 +1,3928 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwizard.h"
+
+#ifndef QT_NO_WIZARD
+
+#include "qabstractspinbox.h"
+#include "qalgorithms.h"
+#include "qapplication.h"
+#include "qboxlayout.h"
+#include "qlayoutitem.h"
+#include "qdesktopwidget.h"
+#include "qevent.h"
+#include "qframe.h"
+#include "qlabel.h"
+#include "qlineedit.h"
+#include "qpainter.h"
+#include "qpushbutton.h"
+#include "qset.h"
+#include "qstyle.h"
+#include "qvarlengtharray.h"
+#if defined(Q_WS_MAC)
+#include "private/qt_mac_p.h"
+#include "qlibrary.h"
+#elif !defined(QT_NO_STYLE_WINDOWSVISTA)
+#include "qwizard_win_p.h"
+#include "qtimer.h"
+#endif
+
+#include "private/qdialog_p.h"
+#include <qdebug.h>
+
+#ifdef Q_WS_WINCE
+extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp
+#endif
+
+#include <string.h> // for memset()
+
+#ifdef QT_SOFTKEYS_ENABLED
+#include "qaction.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+// These fudge terms were needed a few places to obtain pixel-perfect results
+const int GapBetweenLogoAndRightEdge = 5;
+const int ModernHeaderTopMargin = 2;
+const int ClassicHMargin = 4;
+const int MacButtonTopMargin = 13;
+const int MacLayoutLeftMargin = 20;
+//const int MacLayoutTopMargin = 14; // Unused. Save some space and avoid warning.
+const int MacLayoutRightMargin = 20;
+const int MacLayoutBottomMargin = 17;
+
+static void changeSpacerSize(QLayout *layout, int index, int width, int height)
+{
+ QSpacerItem *spacer = layout->itemAt(index)->spacerItem();
+ if (!spacer)
+ return;
+ spacer->changeSize(width, height);
+}
+
+static QWidget *iWantTheFocus(QWidget *ancestor)
+{
+ const int MaxIterations = 100;
+
+ QWidget *candidate = ancestor;
+ for (int i = 0; i < MaxIterations; ++i) {
+ candidate = candidate->nextInFocusChain();
+ if (!candidate)
+ break;
+
+ if (candidate->focusPolicy() & Qt::TabFocus) {
+ if (candidate != ancestor && ancestor->isAncestorOf(candidate))
+ return candidate;
+ }
+ }
+ return 0;
+}
+
+static bool objectInheritsXAndXIsCloserThanY(const QObject *object, const QByteArray &classX,
+ const QByteArray &classY)
+{
+ const QMetaObject *metaObject = object->metaObject();
+ while (metaObject) {
+ if (metaObject->className() == classX)
+ return true;
+ if (metaObject->className() == classY)
+ return false;
+ metaObject = metaObject->superClass();
+ }
+ return false;
+}
+
+const int NFallbackDefaultProperties = 7;
+
+const struct {
+ const char *className;
+ const char *property;
+ const char *changedSignal;
+} fallbackProperties[NFallbackDefaultProperties] = {
+ // If you modify this list, make sure to update the documentation (and the auto test)
+ { "QAbstractButton", "checked", SIGNAL(toggled(bool)) },
+ { "QAbstractSlider", "value", SIGNAL(valueChanged(int)) },
+ { "QComboBox", "currentIndex", SIGNAL(currentIndexChanged(int)) },
+ { "QDateTimeEdit", "dateTime", SIGNAL(dateTimeChanged(QDateTime)) },
+ { "QLineEdit", "text", SIGNAL(textChanged(QString)) },
+ { "QListWidget", "currentRow", SIGNAL(currentRowChanged(int)) },
+ { "QSpinBox", "value", SIGNAL(valueChanged(int)) }
+};
+
+class QWizardDefaultProperty
+{
+public:
+ QByteArray className;
+ QByteArray property;
+ QByteArray changedSignal;
+
+ inline QWizardDefaultProperty() {}
+ inline QWizardDefaultProperty(const char *className, const char *property,
+ const char *changedSignal)
+ : className(className), property(property), changedSignal(changedSignal) {}
+};
+
+class QWizardField
+{
+public:
+ inline QWizardField() {}
+ QWizardField(QWizardPage *page, const QString &spec, QObject *object, const char *property,
+ const char *changedSignal);
+
+ void resolve(const QVector<QWizardDefaultProperty> &defaultPropertyTable);
+ void findProperty(const QWizardDefaultProperty *properties, int propertyCount);
+
+ QWizardPage *page;
+ QString name;
+ bool mandatory;
+ QObject *object;
+ QByteArray property;
+ QByteArray changedSignal;
+ QVariant initialValue;
+};
+
+QWizardField::QWizardField(QWizardPage *page, const QString &spec, QObject *object,
+ const char *property, const char *changedSignal)
+ : page(page), name(spec), mandatory(false), object(object), property(property),
+ changedSignal(changedSignal)
+{
+ if (name.endsWith(QLatin1Char('*'))) {
+ name.chop(1);
+ mandatory = true;
+ }
+}
+
+void QWizardField::resolve(const QVector<QWizardDefaultProperty> &defaultPropertyTable)
+{
+ if (property.isEmpty())
+ findProperty(defaultPropertyTable.constData(), defaultPropertyTable.count());
+ initialValue = object->property(property);
+}
+
+void QWizardField::findProperty(const QWizardDefaultProperty *properties, int propertyCount)
+{
+ QByteArray className;
+
+ for (int i = 0; i < propertyCount; ++i) {
+ if (objectInheritsXAndXIsCloserThanY(object, properties[i].className, className)) {
+ className = properties[i].className;
+ property = properties[i].property;
+ changedSignal = properties[i].changedSignal;
+ }
+ }
+}
+
+class QWizardLayoutInfo
+{
+public:
+ inline QWizardLayoutInfo()
+ : topLevelMarginLeft(-1), topLevelMarginRight(-1), topLevelMarginTop(-1),
+ topLevelMarginBottom(-1), childMarginLeft(-1), childMarginRight(-1),
+ childMarginTop(-1), childMarginBottom(-1), hspacing(-1), vspacing(-1),
+ wizStyle(QWizard::ClassicStyle), header(false), watermark(false), title(false),
+ subTitle(false), extension(false), sideWidget(false) {}
+
+ int topLevelMarginLeft;
+ int topLevelMarginRight;
+ int topLevelMarginTop;
+ int topLevelMarginBottom;
+ int childMarginLeft;
+ int childMarginRight;
+ int childMarginTop;
+ int childMarginBottom;
+ int hspacing;
+ int vspacing;
+ int buttonSpacing;
+ QWizard::WizardStyle wizStyle;
+ bool header;
+ bool watermark;
+ bool title;
+ bool subTitle;
+ bool extension;
+ bool sideWidget;
+
+ bool operator==(const QWizardLayoutInfo &other);
+ inline bool operator!=(const QWizardLayoutInfo &other) { return !operator==(other); }
+};
+
+bool QWizardLayoutInfo::operator==(const QWizardLayoutInfo &other)
+{
+ return topLevelMarginLeft == other.topLevelMarginLeft
+ && topLevelMarginRight == other.topLevelMarginRight
+ && topLevelMarginTop == other.topLevelMarginTop
+ && topLevelMarginBottom == other.topLevelMarginBottom
+ && childMarginLeft == other.childMarginLeft
+ && childMarginRight == other.childMarginRight
+ && childMarginTop == other.childMarginTop
+ && childMarginBottom == other.childMarginBottom
+ && hspacing == other.hspacing
+ && vspacing == other.vspacing
+ && buttonSpacing == other.buttonSpacing
+ && wizStyle == other.wizStyle
+ && header == other.header
+ && watermark == other.watermark
+ && title == other.title
+ && subTitle == other.subTitle
+ && extension == other.extension
+ && sideWidget == other.sideWidget;
+}
+
+class QWizardHeader : public QWidget
+{
+public:
+ enum RulerType { Ruler };
+
+ inline QWizardHeader(RulerType /* ruler */, QWidget *parent = 0)
+ : QWidget(parent) { setFixedHeight(2); }
+ QWizardHeader(QWidget *parent = 0);
+
+ void setup(const QWizardLayoutInfo &info, const QString &title,
+ const QString &subTitle, const QPixmap &logo, const QPixmap &banner,
+ Qt::TextFormat titleFormat, Qt::TextFormat subTitleFormat);
+
+protected:
+ void paintEvent(QPaintEvent *event);
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+private:
+ bool vistaDisabled() const;
+#endif
+private:
+ QLabel *titleLabel;
+ QLabel *subTitleLabel;
+ QLabel *logoLabel;
+ QGridLayout *layout;
+ QPixmap bannerPixmap;
+};
+
+QWizardHeader::QWizardHeader(QWidget *parent)
+ : QWidget(parent)
+{
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ setBackgroundRole(QPalette::Base);
+
+ titleLabel = new QLabel(this);
+ titleLabel->setBackgroundRole(QPalette::Base);
+
+ subTitleLabel = new QLabel(this);
+ subTitleLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+ subTitleLabel->setWordWrap(true);
+
+ logoLabel = new QLabel(this);
+
+ QFont font = titleLabel->font();
+ font.setBold(true);
+ titleLabel->setFont(font);
+
+ layout = new QGridLayout(this);
+ layout->setMargin(0);
+ layout->setSpacing(0);
+
+ layout->setRowMinimumHeight(3, 1);
+ layout->setRowStretch(4, 1);
+
+ layout->setColumnStretch(2, 1);
+ layout->setColumnMinimumWidth(4, 2 * GapBetweenLogoAndRightEdge);
+ layout->setColumnMinimumWidth(6, GapBetweenLogoAndRightEdge);
+
+ layout->addWidget(titleLabel, 2, 1, 1, 2);
+ layout->addWidget(subTitleLabel, 4, 2);
+ layout->addWidget(logoLabel, 1, 5, 5, 1);
+}
+
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+bool QWizardHeader::vistaDisabled() const
+{
+ bool styleDisabled = false;
+ QWizard *wiz = parentWidget() ? qobject_cast <QWizard *>(parentWidget()->parentWidget()) : 0;
+ if (wiz) {
+ // Designer dosen't support the Vista style for Wizards. This property is used to turn
+ // off the Vista style.
+ const QVariant v = wiz->property("_q_wizard_vista_off");
+ styleDisabled = v.isValid() && v.toBool();
+ }
+ return styleDisabled;
+}
+#endif
+
+void QWizardHeader::setup(const QWizardLayoutInfo &info, const QString &title,
+ const QString &subTitle, const QPixmap &logo, const QPixmap &banner,
+ Qt::TextFormat titleFormat, Qt::TextFormat subTitleFormat)
+{
+ bool modern = ((info.wizStyle == QWizard::ModernStyle)
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ || ((info.wizStyle == QWizard::AeroStyle
+ && QVistaHelper::vistaState() == QVistaHelper::Classic) || vistaDisabled())
+#endif
+ );
+
+ layout->setRowMinimumHeight(0, modern ? ModernHeaderTopMargin : 0);
+ layout->setRowMinimumHeight(1, modern ? info.topLevelMarginTop - ModernHeaderTopMargin - 1 : 0);
+ layout->setRowMinimumHeight(6, (modern ? 3 : GapBetweenLogoAndRightEdge) + 2);
+
+ int minColumnWidth0 = modern ? info.topLevelMarginLeft + info.topLevelMarginRight : 0;
+ int minColumnWidth1 = modern ? info.topLevelMarginLeft + info.topLevelMarginRight + 1
+ : info.topLevelMarginLeft + ClassicHMargin;
+ layout->setColumnMinimumWidth(0, minColumnWidth0);
+ layout->setColumnMinimumWidth(1, minColumnWidth1);
+
+ titleLabel->setTextFormat(titleFormat);
+ titleLabel->setText(title);
+ logoLabel->setPixmap(logo);
+
+ subTitleLabel->setTextFormat(subTitleFormat);
+ subTitleLabel->setText(QLatin1String("Pq\nPq"));
+ int desiredSubTitleHeight = subTitleLabel->sizeHint().height();
+ subTitleLabel->setText(subTitle);
+
+ if (modern) {
+ bannerPixmap = banner;
+ } else {
+ bannerPixmap = QPixmap();
+ }
+
+ if (bannerPixmap.isNull()) {
+ /*
+ There is no widthForHeight() function, so we simulate it with a loop.
+ */
+ int candidateSubTitleWidth = qMin(512, 2 * QApplication::desktop()->width() / 3);
+ int delta = candidateSubTitleWidth >> 1;
+ while (delta > 0) {
+ if (subTitleLabel->heightForWidth(candidateSubTitleWidth - delta)
+ <= desiredSubTitleHeight)
+ candidateSubTitleWidth -= delta;
+ delta >>= 1;
+ }
+
+ subTitleLabel->setMinimumSize(candidateSubTitleWidth, desiredSubTitleHeight);
+
+ QSize size = layout->totalMinimumSize();
+ setMinimumSize(size);
+ setMaximumSize(QWIDGETSIZE_MAX, size.height());
+ } else {
+ subTitleLabel->setMinimumSize(0, 0);
+ setFixedSize(banner.size() + QSize(0, 2));
+ }
+ updateGeometry();
+}
+
+void QWizardHeader::paintEvent(QPaintEvent * /* event */)
+{
+ QPainter painter(this);
+ painter.drawPixmap(0, 0, bannerPixmap);
+
+ int x = width() - 2;
+ int y = height() - 2;
+ const QPalette &pal = palette();
+ painter.setPen(pal.mid().color());
+ painter.drawLine(0, y, x, y);
+ painter.setPen(pal.base().color());
+ painter.drawPoint(x + 1, y);
+ painter.drawLine(0, y + 1, x + 1, y + 1);
+}
+
+// We save one vtable by basing QWizardRuler on QWizardHeader
+class QWizardRuler : public QWizardHeader
+{
+public:
+ inline QWizardRuler(QWidget *parent = 0)
+ : QWizardHeader(Ruler, parent) {}
+};
+
+class QWatermarkLabel : public QLabel
+{
+public:
+ QWatermarkLabel(QWidget *parent, QWidget *sideWidget) : QLabel(parent), m_sideWidget(sideWidget) {
+ m_layout = new QVBoxLayout(this);
+ if (m_sideWidget)
+ m_layout->addWidget(m_sideWidget);
+ }
+
+ QSize minimumSizeHint() const {
+ if (!pixmap() && !pixmap()->isNull())
+ return pixmap()->size();
+ return QFrame::minimumSizeHint();
+ }
+
+ void setSideWidget(QWidget *widget) {
+ if (m_sideWidget == widget)
+ return;
+ if (m_sideWidget) {
+ m_layout->removeWidget(m_sideWidget);
+ m_sideWidget->hide();
+ }
+ m_sideWidget = widget;
+ if (m_sideWidget)
+ m_layout->addWidget(m_sideWidget);
+ }
+ QWidget *sideWidget() const {
+ return m_sideWidget;
+ }
+private:
+ QVBoxLayout *m_layout;
+ QWidget *m_sideWidget;
+};
+
+class QWizardPagePrivate : public QWidgetPrivate
+{
+ Q_DECLARE_PUBLIC(QWizardPage)
+
+public:
+ enum TriState { Tri_Unknown = -1, Tri_False, Tri_True };
+
+ inline QWizardPagePrivate()
+ : wizard(0), completeState(Tri_Unknown), explicitlyFinal(false), commit(false) {}
+
+ bool cachedIsComplete() const;
+ void _q_maybeEmitCompleteChanged();
+ void _q_updateCachedCompleteState();
+
+ QWizard *wizard;
+ QString title;
+ QString subTitle;
+ QPixmap pixmaps[QWizard::NPixmaps];
+ QVector<QWizardField> pendingFields;
+ mutable TriState completeState;
+ bool explicitlyFinal;
+ bool commit;
+ QMap<int, QString> buttonCustomTexts;
+};
+
+bool QWizardPagePrivate::cachedIsComplete() const
+{
+ Q_Q(const QWizardPage);
+ if (completeState == Tri_Unknown)
+ completeState = q->isComplete() ? Tri_True : Tri_False;
+ return completeState == Tri_True;
+}
+
+void QWizardPagePrivate::_q_maybeEmitCompleteChanged()
+{
+ Q_Q(QWizardPage);
+ TriState newState = q->isComplete() ? Tri_True : Tri_False;
+ if (newState != completeState)
+ emit q->completeChanged();
+}
+
+void QWizardPagePrivate::_q_updateCachedCompleteState()
+{
+ Q_Q(QWizardPage);
+ completeState = q->isComplete() ? Tri_True : Tri_False;
+}
+
+class QWizardAntiFlickerWidget : public QWidget
+{
+ QWizard *wizard;
+ QWizardPrivate *wizardPrivate;
+public:
+ QWizardAntiFlickerWidget(QWizard *wizard, QWizardPrivate *wizardPrivate)
+ : QWidget(wizard)
+ , wizard(wizard)
+ , wizardPrivate(wizardPrivate) {}
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+protected:
+ void paintEvent(QPaintEvent *);
+#endif
+};
+
+class QWizardPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QWizard)
+
+public:
+ typedef QMap<int, QWizardPage *> PageMap;
+
+ enum Direction {
+ Backward,
+ Forward
+ };
+
+ inline QWizardPrivate()
+ : start(-1)
+ , startSetByUser(false)
+ , current(-1)
+ , canContinue(false)
+ , canFinish(false)
+ , disableUpdatesCount(0)
+ , opts(0)
+ , buttonsHaveCustomLayout(false)
+ , titleFmt(Qt::AutoText)
+ , subTitleFmt(Qt::AutoText)
+ , placeholderWidget1(0)
+ , placeholderWidget2(0)
+ , headerWidget(0)
+ , watermarkLabel(0)
+ , sideWidget(0)
+ , titleLabel(0)
+ , subTitleLabel(0)
+ , bottomRuler(0)
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ , vistaInitPending(false)
+ , vistaState(QVistaHelper::Dirty)
+ , vistaStateChanged(false)
+ , inHandleAeroStyleChange(false)
+#endif
+ , minimumWidth(0)
+ , minimumHeight(0)
+ , maximumWidth(QWIDGETSIZE_MAX)
+ , maximumHeight(QWIDGETSIZE_MAX)
+ {
+ for (int i = 0; i < QWizard::NButtons; ++i) {
+ btns[i] = 0;
+#ifdef QT_SOFTKEYS_ENABLED
+ softKeys[i] = 0;
+#endif
+ }
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA
+ && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)
+ vistaInitPending = true;
+#endif
+ }
+
+ void init();
+ void reset();
+ void cleanupPagesNotInHistory();
+ void addField(const QWizardField &field);
+ void removeFieldAt(int index);
+ void switchToPage(int newId, Direction direction);
+ QWizardLayoutInfo layoutInfoForCurrentPage();
+ void recreateLayout(const QWizardLayoutInfo &info);
+ void updateLayout();
+ void updateMinMaxSizes(const QWizardLayoutInfo &info);
+ void updateCurrentPage();
+ bool ensureButton(QWizard::WizardButton which) const;
+ void connectButton(QWizard::WizardButton which) const;
+ void updateButtonTexts();
+ void updateButtonLayout();
+ void setButtonLayout(const QWizard::WizardButton *array, int size);
+ bool buttonLayoutContains(QWizard::WizardButton which);
+ void updatePixmap(QWizard::WizardPixmap which);
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ bool vistaDisabled() const;
+ bool isVistaThemeEnabled(QVistaHelper::VistaState state) const;
+ void handleAeroStyleChange();
+#endif
+ bool isVistaThemeEnabled() const;
+ void disableUpdates();
+ void enableUpdates();
+ void _q_emitCustomButtonClicked();
+ void _q_updateButtonStates();
+ void _q_handleFieldObjectDestroyed(QObject *);
+ void setStyle(QStyle *style);
+#ifdef Q_WS_MAC
+ static QPixmap findDefaultBackgroundPixmap();
+#endif
+
+ PageMap pageMap;
+ QVector<QWizardField> fields;
+ QMap<QString, int> fieldIndexMap;
+ QVector<QWizardDefaultProperty> defaultPropertyTable;
+ QList<int> history;
+ QSet<int> initialized; // ### remove and move bit to QWizardPage?
+ int start;
+ bool startSetByUser;
+ int current;
+ bool canContinue;
+ bool canFinish;
+ QWizardLayoutInfo layoutInfo;
+ int disableUpdatesCount;
+
+ QWizard::WizardStyle wizStyle;
+ QWizard::WizardOptions opts;
+ QMap<int, QString> buttonCustomTexts;
+ bool buttonsHaveCustomLayout;
+ QList<QWizard::WizardButton> buttonsCustomLayout;
+ Qt::TextFormat titleFmt;
+ Qt::TextFormat subTitleFmt;
+ mutable QPixmap defaultPixmaps[QWizard::NPixmaps];
+
+ union {
+ // keep in sync with QWizard::WizardButton
+ mutable struct {
+ QAbstractButton *back;
+ QAbstractButton *next;
+ QAbstractButton *commit;
+ QAbstractButton *finish;
+ QAbstractButton *cancel;
+ QAbstractButton *help;
+ } btn;
+ mutable QAbstractButton *btns[QWizard::NButtons];
+ };
+ QWizardAntiFlickerWidget *antiFlickerWidget;
+ QWidget *placeholderWidget1;
+ QWidget *placeholderWidget2;
+ QWizardHeader *headerWidget;
+ QWatermarkLabel *watermarkLabel;
+ QWidget *sideWidget;
+ QFrame *pageFrame;
+ QLabel *titleLabel;
+ QLabel *subTitleLabel;
+ QWizardRuler *bottomRuler;
+#ifdef QT_SOFTKEYS_ENABLED
+ mutable QAction *softKeys[QWizard::NButtons];
+#endif
+
+ QVBoxLayout *pageVBoxLayout;
+ QHBoxLayout *buttonLayout;
+ QGridLayout *mainLayout;
+
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ QVistaHelper *vistaHelper;
+ bool vistaInitPending;
+ QVistaHelper::VistaState vistaState;
+ bool vistaStateChanged;
+ bool inHandleAeroStyleChange;
+#endif
+ int minimumWidth;
+ int minimumHeight;
+ int maximumWidth;
+ int maximumHeight;
+};
+
+static QString buttonDefaultText(int wstyle, int which, const QWizardPrivate *wizardPrivate)
+{
+#if defined(QT_NO_STYLE_WINDOWSVISTA)
+ Q_UNUSED(wizardPrivate);
+#endif
+ const bool macStyle = (wstyle == QWizard::MacStyle);
+ switch (which) {
+ case QWizard::BackButton:
+ return macStyle ? QWizard::tr("Go Back") : QWizard::tr("< &Back");
+ case QWizard::NextButton:
+ if (macStyle)
+ return QWizard::tr("Continue");
+ else
+ return wizardPrivate->isVistaThemeEnabled()
+ ? QWizard::tr("&Next") : QWizard::tr("&Next >");
+ case QWizard::CommitButton:
+ return QWizard::tr("Commit");
+ case QWizard::FinishButton:
+ return macStyle ? QWizard::tr("Done") : QWizard::tr("&Finish");
+ case QWizard::CancelButton:
+ return QWizard::tr("Cancel");
+ case QWizard::HelpButton:
+ return macStyle ? QWizard::tr("Help") : QWizard::tr("&Help");
+ default:
+ return QString();
+ }
+}
+
+void QWizardPrivate::init()
+{
+ Q_Q(QWizard);
+
+ antiFlickerWidget = new QWizardAntiFlickerWidget(q, this);
+ wizStyle = QWizard::WizardStyle(q->style()->styleHint(QStyle::SH_WizardStyle, 0, q));
+ if (wizStyle == QWizard::MacStyle) {
+ opts = (QWizard::NoDefaultButton | QWizard::NoCancelButton);
+ } else if (wizStyle == QWizard::ModernStyle) {
+ opts = QWizard::HelpButtonOnRight;
+ }
+
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ vistaHelper = new QVistaHelper(q);
+#endif
+
+ // create these buttons right away; create the other buttons as necessary
+ ensureButton(QWizard::BackButton);
+ ensureButton(QWizard::NextButton);
+ ensureButton(QWizard::CommitButton);
+ ensureButton(QWizard::FinishButton);
+
+ pageFrame = new QFrame(antiFlickerWidget);
+ pageFrame->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ pageVBoxLayout = new QVBoxLayout(pageFrame);
+ pageVBoxLayout->setSpacing(0);
+ pageVBoxLayout->addSpacing(0);
+ QSpacerItem *spacerItem = new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding);
+ pageVBoxLayout->addItem(spacerItem);
+
+ buttonLayout = new QHBoxLayout;
+ mainLayout = new QGridLayout(antiFlickerWidget);
+ mainLayout->setSizeConstraint(QLayout::SetNoConstraint);
+
+ updateButtonLayout();
+
+ for (int i = 0; i < NFallbackDefaultProperties; ++i)
+ defaultPropertyTable.append(QWizardDefaultProperty(fallbackProperties[i].className,
+ fallbackProperties[i].property,
+ fallbackProperties[i].changedSignal));
+}
+
+void QWizardPrivate::reset()
+{
+ Q_Q(QWizard);
+ if (current != -1) {
+ q->currentPage()->hide();
+ cleanupPagesNotInHistory();
+ for (int i = history.count() - 1; i >= 0; --i)
+ q->cleanupPage(history.at(i));
+ history.clear();
+ initialized.clear();
+
+ current = -1;
+ emit q->currentIdChanged(-1);
+ }
+}
+
+void QWizardPrivate::cleanupPagesNotInHistory()
+{
+ Q_Q(QWizard);
+
+ const QSet<int> original = initialized;
+ QSet<int>::const_iterator i = original.constBegin();
+ QSet<int>::const_iterator end = original.constEnd();
+
+ for (; i != end; ++i) {
+ if (!history.contains(*i)) {
+ q->cleanupPage(*i);
+ initialized.remove(*i);
+ }
+ }
+}
+
+void QWizardPrivate::addField(const QWizardField &field)
+{
+ Q_Q(QWizard);
+
+ QWizardField myField = field;
+ myField.resolve(defaultPropertyTable);
+
+ if (fieldIndexMap.contains(myField.name)) {
+ qWarning("QWizardPage::addField: Duplicate field '%s'", qPrintable(myField.name));
+ return;
+ }
+
+ fieldIndexMap.insert(myField.name, fields.count());
+ fields += myField;
+ if (myField.mandatory && !myField.changedSignal.isEmpty())
+ QObject::connect(myField.object, myField.changedSignal,
+ myField.page, SLOT(_q_maybeEmitCompleteChanged()));
+ QObject::connect(
+ myField.object, SIGNAL(destroyed(QObject*)), q,
+ SLOT(_q_handleFieldObjectDestroyed(QObject*)));
+}
+
+void QWizardPrivate::removeFieldAt(int index)
+{
+ Q_Q(QWizard);
+
+ const QWizardField &field = fields.at(index);
+ fieldIndexMap.remove(field.name);
+ if (field.mandatory && !field.changedSignal.isEmpty())
+ QObject::disconnect(field.object, field.changedSignal,
+ field.page, SLOT(_q_maybeEmitCompleteChanged()));
+ QObject::disconnect(
+ field.object, SIGNAL(destroyed(QObject*)), q,
+ SLOT(_q_handleFieldObjectDestroyed(QObject*)));
+ fields.remove(index);
+}
+
+void QWizardPrivate::switchToPage(int newId, Direction direction)
+{
+ Q_Q(QWizard);
+
+ disableUpdates();
+
+ int oldId = current;
+ if (QWizardPage *oldPage = q->currentPage()) {
+ oldPage->hide();
+
+ if (direction == Backward) {
+ if (!(opts & QWizard::IndependentPages)) {
+ q->cleanupPage(oldId);
+ initialized.remove(oldId);
+ }
+ Q_ASSERT(history.last() == oldId);
+ history.removeLast();
+ Q_ASSERT(history.last() == newId);
+ }
+ }
+
+ current = newId;
+
+ QWizardPage *newPage = q->currentPage();
+ if (newPage) {
+ if (direction == Forward) {
+ if (!initialized.contains(current)) {
+ initialized.insert(current);
+ q->initializePage(current);
+ }
+ history.append(current);
+ }
+ newPage->show();
+ }
+
+ canContinue = (q->nextId() != -1);
+ canFinish = (newPage && newPage->isFinalPage());
+
+ _q_updateButtonStates();
+ updateButtonTexts();
+
+ const QWizard::WizardButton nextOrCommit =
+ newPage && newPage->isCommitPage() ? QWizard::CommitButton : QWizard::NextButton;
+ QAbstractButton *nextOrFinishButton =
+ btns[canContinue ? nextOrCommit : QWizard::FinishButton];
+ QWidget *candidate = 0;
+
+ /*
+ If there is no default button and the Next or Finish button
+ is enabled, give focus directly to it as a convenience to the
+ user. This is the normal case on Mac OS X.
+
+ Otherwise, give the focus to the new page's first child that
+ can handle it. If there is no such child, give the focus to
+ Next or Finish.
+ */
+ if ((opts & QWizard::NoDefaultButton) && nextOrFinishButton->isEnabled()) {
+ candidate = nextOrFinishButton;
+ } else if (newPage) {
+ candidate = iWantTheFocus(newPage);
+ }
+ if (!candidate)
+ candidate = nextOrFinishButton;
+ candidate->setFocus();
+
+ if (wizStyle == QWizard::MacStyle)
+ q->updateGeometry();
+
+ enableUpdates();
+ updateLayout();
+
+ emit q->currentIdChanged(current);
+}
+
+// keep in sync with QWizard::WizardButton
+static const char * const buttonSlots[QWizard::NStandardButtons] = {
+ SLOT(back()), SLOT(next()), SLOT(next()), SLOT(accept()), SLOT(reject()),
+ SIGNAL(helpRequested())
+};
+
+QWizardLayoutInfo QWizardPrivate::layoutInfoForCurrentPage()
+{
+ Q_Q(QWizard);
+ QStyle *style = q->style();
+
+ QWizardLayoutInfo info;
+
+ const int layoutHorizontalSpacing = style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
+ info.topLevelMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, 0, q);
+ info.topLevelMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, 0, q);
+ info.topLevelMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, 0, q);
+ info.topLevelMarginBottom = style->pixelMetric(QStyle::PM_LayoutBottomMargin, 0, q);
+ info.childMarginLeft = style->pixelMetric(QStyle::PM_LayoutLeftMargin, 0, titleLabel);
+ info.childMarginRight = style->pixelMetric(QStyle::PM_LayoutRightMargin, 0, titleLabel);
+ info.childMarginTop = style->pixelMetric(QStyle::PM_LayoutTopMargin, 0, titleLabel);
+ info.childMarginBottom = style->pixelMetric(QStyle::PM_LayoutBottomMargin, 0, titleLabel);
+ info.hspacing = (layoutHorizontalSpacing == -1)
+ ? style->layoutSpacing(QSizePolicy::DefaultType, QSizePolicy::DefaultType, Qt::Horizontal)
+ : layoutHorizontalSpacing;
+ info.vspacing = style->pixelMetric(QStyle::PM_LayoutVerticalSpacing);
+ info.buttonSpacing = (layoutHorizontalSpacing == -1)
+ ? style->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal)
+ : layoutHorizontalSpacing;
+
+ if (wizStyle == QWizard::MacStyle)
+ info.buttonSpacing = 12;
+
+ info.wizStyle = wizStyle;
+ if ((info.wizStyle == QWizard::AeroStyle)
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ && (QVistaHelper::vistaState() == QVistaHelper::Classic || vistaDisabled())
+#endif
+ )
+ info.wizStyle = QWizard::ModernStyle;
+
+ QString titleText;
+ QString subTitleText;
+ QPixmap backgroundPixmap;
+ QPixmap watermarkPixmap;
+
+ if (QWizardPage *page = q->currentPage()) {
+ titleText = page->title();
+ subTitleText = page->subTitle();
+ backgroundPixmap = page->pixmap(QWizard::BackgroundPixmap);
+ watermarkPixmap = page->pixmap(QWizard::WatermarkPixmap);
+ }
+
+ info.header = (info.wizStyle == QWizard::ClassicStyle || info.wizStyle == QWizard::ModernStyle)
+ && !(opts & QWizard::IgnoreSubTitles) && !subTitleText.isEmpty();
+ info.sideWidget = sideWidget;
+ info.watermark = (info.wizStyle != QWizard::MacStyle) && (info.wizStyle != QWizard::AeroStyle)
+ && !watermarkPixmap.isNull();
+ info.title = !info.header && !titleText.isEmpty();
+ info.subTitle = !(opts & QWizard::IgnoreSubTitles) && !info.header && !subTitleText.isEmpty();
+ info.extension = (info.watermark || info.sideWidget) && (opts & QWizard::ExtendedWatermarkPixmap);
+
+ return info;
+}
+
+void QWizardPrivate::recreateLayout(const QWizardLayoutInfo &info)
+{
+ Q_Q(QWizard);
+
+ /*
+ Start by undoing the main layout.
+ */
+ for (int i = mainLayout->count() - 1; i >= 0; --i) {
+ QLayoutItem *item = mainLayout->takeAt(i);
+ if (item->layout()) {
+ item->layout()->setParent(0);
+ } else {
+ delete item;
+ }
+ }
+ for (int i = mainLayout->columnCount() - 1; i >= 0; --i)
+ mainLayout->setColumnMinimumWidth(i, 0);
+ for (int i = mainLayout->rowCount() - 1; i >= 0; --i)
+ mainLayout->setRowMinimumHeight(i, 0);
+
+ /*
+ Now, recreate it.
+ */
+
+ bool mac = (info.wizStyle == QWizard::MacStyle);
+ bool classic = (info.wizStyle == QWizard::ClassicStyle);
+ bool modern = (info.wizStyle == QWizard::ModernStyle);
+ bool aero = (info.wizStyle == QWizard::AeroStyle);
+ int deltaMarginLeft = info.topLevelMarginLeft - info.childMarginLeft;
+ int deltaMarginRight = info.topLevelMarginRight - info.childMarginRight;
+ int deltaMarginTop = info.topLevelMarginTop - info.childMarginTop;
+ int deltaMarginBottom = info.topLevelMarginBottom - info.childMarginBottom;
+ int deltaVSpacing = info.topLevelMarginBottom - info.vspacing;
+
+ int row = 0;
+ int numColumns;
+ if (mac) {
+ numColumns = 3;
+ } else if (info.watermark || info.sideWidget) {
+ numColumns = 2;
+ } else {
+ numColumns = 1;
+ }
+ int pageColumn = qMin(1, numColumns - 1);
+
+ if (mac) {
+ mainLayout->setMargin(0);
+ mainLayout->setSpacing(0);
+ buttonLayout->setContentsMargins(MacLayoutLeftMargin, MacButtonTopMargin, MacLayoutRightMargin, MacLayoutBottomMargin);
+ pageVBoxLayout->setMargin(7);
+ } else {
+ if (modern) {
+ mainLayout->setMargin(0);
+ mainLayout->setSpacing(0);
+ pageVBoxLayout->setContentsMargins(deltaMarginLeft, deltaMarginTop,
+ deltaMarginRight, deltaMarginBottom);
+ buttonLayout->setContentsMargins(info.topLevelMarginLeft, info.topLevelMarginTop,
+ info.topLevelMarginRight, info.topLevelMarginBottom);
+ } else {
+ mainLayout->setContentsMargins(info.topLevelMarginLeft, info.topLevelMarginTop,
+ info.topLevelMarginRight, info.topLevelMarginBottom);
+ mainLayout->setHorizontalSpacing(info.hspacing);
+ mainLayout->setVerticalSpacing(info.vspacing);
+ pageVBoxLayout->setContentsMargins(0, 0, 0, 0);
+ buttonLayout->setContentsMargins(0, 0, 0, 0);
+ }
+ }
+ buttonLayout->setSpacing(info.buttonSpacing);
+
+ if (info.header) {
+ if (!headerWidget)
+ headerWidget = new QWizardHeader(antiFlickerWidget);
+ headerWidget->setAutoFillBackground(modern);
+ mainLayout->addWidget(headerWidget, row++, 0, 1, numColumns);
+ }
+ if (headerWidget)
+ headerWidget->setVisible(info.header);
+
+ int watermarkStartRow = row;
+
+ if (mac)
+ mainLayout->setRowMinimumHeight(row++, 10);
+
+ if (info.title) {
+ if (!titleLabel) {
+ titleLabel = new QLabel(antiFlickerWidget);
+ titleLabel->setBackgroundRole(QPalette::Base);
+ titleLabel->setWordWrap(true);
+ }
+
+ QFont titleFont = q->font();
+ titleFont.setPointSize(titleFont.pointSize() + (mac ? 3 : 4));
+ titleFont.setBold(true);
+ titleLabel->setPalette(QPalette());
+
+ if (aero) {
+ // ### hardcoded for now:
+ titleFont = QFont(QLatin1String("Segoe UI"), 12);
+ QPalette pal(titleLabel->palette());
+ pal.setColor(QPalette::Text, "#003399");
+ titleLabel->setPalette(pal);
+ }
+
+ titleLabel->setFont(titleFont);
+ const int aeroTitleIndent = 25; // ### hardcoded for now - should be calculated somehow
+ if (aero)
+ titleLabel->setIndent(aeroTitleIndent);
+ else if (mac)
+ titleLabel->setIndent(2);
+ else if (classic)
+ titleLabel->setIndent(info.childMarginLeft);
+ else
+ titleLabel->setIndent(info.topLevelMarginLeft);
+ if (modern) {
+ if (!placeholderWidget1) {
+ placeholderWidget1 = new QWidget(antiFlickerWidget);
+ placeholderWidget1->setBackgroundRole(QPalette::Base);
+ }
+ placeholderWidget1->setFixedHeight(info.topLevelMarginLeft + 2);
+ mainLayout->addWidget(placeholderWidget1, row++, pageColumn);
+ }
+ mainLayout->addWidget(titleLabel, row++, pageColumn);
+ if (modern) {
+ if (!placeholderWidget2) {
+ placeholderWidget2 = new QWidget(antiFlickerWidget);
+ placeholderWidget2->setBackgroundRole(QPalette::Base);
+ }
+ placeholderWidget2->setFixedHeight(5);
+ mainLayout->addWidget(placeholderWidget2, row++, pageColumn);
+ }
+ if (mac)
+ mainLayout->setRowMinimumHeight(row++, 7);
+ }
+ if (placeholderWidget1)
+ placeholderWidget1->setVisible(info.title && modern);
+ if (placeholderWidget2)
+ placeholderWidget2->setVisible(info.title && modern);
+
+ if (info.subTitle) {
+ if (!subTitleLabel) {
+ subTitleLabel = new QLabel(pageFrame);
+ subTitleLabel->setWordWrap(true);
+
+ subTitleLabel->setContentsMargins(info.childMarginLeft , 0,
+ info.childMarginRight , 0);
+
+ pageVBoxLayout->insertWidget(1, subTitleLabel);
+ }
+ }
+
+ // ### try to replace with margin.
+ changeSpacerSize(pageVBoxLayout, 0, 0, info.subTitle ? info.childMarginLeft : 0);
+
+ int hMargin = mac ? 1 : 0;
+ int vMargin = hMargin;
+
+ pageFrame->setFrameStyle(mac ? (QFrame::Box | QFrame::Raised) : QFrame::NoFrame);
+ pageFrame->setLineWidth(0);
+ pageFrame->setMidLineWidth(hMargin);
+
+ if (info.header) {
+ if (modern) {
+ hMargin = info.topLevelMarginLeft;
+ vMargin = deltaMarginBottom;
+ } else if (classic) {
+ hMargin = deltaMarginLeft + ClassicHMargin;
+ vMargin = 0;
+ }
+ }
+
+ if (aero) {
+ int leftMargin = 18; // ### hardcoded for now - should be calculated somehow
+ int topMargin = vMargin;
+ int rightMargin = hMargin; // ### for now
+ int bottomMargin = vMargin;
+ pageFrame->setContentsMargins(leftMargin, topMargin, rightMargin, bottomMargin);
+ } else {
+ pageFrame->setContentsMargins(hMargin, vMargin, hMargin, vMargin);
+ }
+
+ if ((info.watermark || info.sideWidget) && !watermarkLabel) {
+ watermarkLabel = new QWatermarkLabel(antiFlickerWidget, sideWidget);
+ watermarkLabel->setBackgroundRole(QPalette::Base);
+ watermarkLabel->setMinimumHeight(1);
+ watermarkLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ watermarkLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ }
+
+ //bool wasSemiTransparent = pageFrame->testAttribute(Qt::WA_SetPalette);
+ const bool wasSemiTransparent =
+ pageFrame->palette().brush(QPalette::Window).color().alpha() < 255
+ || pageFrame->palette().brush(QPalette::Base).color().alpha() < 255;
+ if (mac) {
+ if (!wasSemiTransparent) {
+ QPalette pal = pageFrame->palette();
+ pal.setBrush(QPalette::Window, QColor(255, 255, 255, 153));
+ // ### The next line is required to ensure visual semitransparency when
+ // ### switching from ModernStyle to MacStyle. See TAG1 below.
+ pal.setBrush(QPalette::Base, QColor(255, 255, 255, 153));
+ pageFrame->setPalette(pal);
+ pageFrame->setAutoFillBackground(true);
+ antiFlickerWidget->setAutoFillBackground(false);
+ }
+ } else {
+ if (wasSemiTransparent)
+ pageFrame->setPalette(QPalette());
+
+ bool baseBackground = (modern && !info.header); // ### TAG1
+ pageFrame->setBackgroundRole(baseBackground ? QPalette::Base : QPalette::Window);
+
+ if (titleLabel)
+ titleLabel->setAutoFillBackground(baseBackground);
+ pageFrame->setAutoFillBackground(baseBackground);
+ if (watermarkLabel)
+ watermarkLabel->setAutoFillBackground(baseBackground);
+ if (placeholderWidget1)
+ placeholderWidget1->setAutoFillBackground(baseBackground);
+ if (placeholderWidget2)
+ placeholderWidget2->setAutoFillBackground(baseBackground);
+
+ if (aero) {
+ QPalette pal = pageFrame->palette();
+ pal.setBrush(QPalette::Window, QColor(255, 255, 255));
+ pageFrame->setPalette(pal);
+ pageFrame->setAutoFillBackground(true);
+ pal = antiFlickerWidget->palette();
+ pal.setBrush(QPalette::Window, QColor(255, 255, 255));
+ antiFlickerWidget->setPalette(pal);
+ antiFlickerWidget->setAutoFillBackground(true);
+ }
+ }
+
+ mainLayout->addWidget(pageFrame, row++, pageColumn);
+
+ int watermarkEndRow = row;
+ if (classic)
+ mainLayout->setRowMinimumHeight(row++, deltaVSpacing);
+
+ if (aero) {
+ buttonLayout->setContentsMargins(9, 9, 9, 9);
+ mainLayout->setContentsMargins(0, 11, 0, 0);
+ }
+
+ int buttonStartColumn = info.extension ? 1 : 0;
+ int buttonNumColumns = info.extension ? 1 : numColumns;
+
+ if (classic || modern) {
+ if (!bottomRuler)
+ bottomRuler = new QWizardRuler(antiFlickerWidget);
+ mainLayout->addWidget(bottomRuler, row++, buttonStartColumn, 1, buttonNumColumns);
+ }
+
+ if (classic)
+ mainLayout->setRowMinimumHeight(row++, deltaVSpacing);
+
+ mainLayout->addLayout(buttonLayout, row++, buttonStartColumn, 1, buttonNumColumns);
+
+ if (info.watermark || info.sideWidget) {
+ if (info.extension)
+ watermarkEndRow = row;
+ mainLayout->addWidget(watermarkLabel, watermarkStartRow, 0,
+ watermarkEndRow - watermarkStartRow, 1);
+ }
+
+ mainLayout->setColumnMinimumWidth(0, mac && !info.watermark ? 181 : 0);
+ if (mac)
+ mainLayout->setColumnMinimumWidth(2, 21);
+
+ if (headerWidget)
+ headerWidget->setVisible(info.header);
+ if (titleLabel)
+ titleLabel->setVisible(info.title);
+ if (subTitleLabel)
+ subTitleLabel->setVisible(info.subTitle);
+ if (bottomRuler)
+ bottomRuler->setVisible(classic || modern);
+ if (watermarkLabel)
+ watermarkLabel->setVisible(info.watermark || info.sideWidget);
+
+ layoutInfo = info;
+}
+
+void QWizardPrivate::updateLayout()
+{
+ Q_Q(QWizard);
+
+ disableUpdates();
+
+ QWizardLayoutInfo info = layoutInfoForCurrentPage();
+ if (layoutInfo != info)
+ recreateLayout(info);
+ QWizardPage *page = q->currentPage();
+
+ // If the page can expand vertically, let it stretch "infinitely" more
+ // than the QSpacerItem at the bottom. Otherwise, let the QSpacerItem
+ // stretch "infinitely" more than the page. Change the bottom item's
+ // policy accordingly. The case that the page has no layout is basically
+ // for Designer, only.
+ if (page) {
+ bool expandPage = !page->layout();
+ if (!expandPage) {
+ const QLayoutItem *pageItem = pageVBoxLayout->itemAt(pageVBoxLayout->indexOf(page));
+ expandPage = pageItem->expandingDirections() & Qt::Vertical;
+ }
+ QSpacerItem *bottomSpacer = pageVBoxLayout->itemAt(pageVBoxLayout->count() - 1)->spacerItem();
+ Q_ASSERT(bottomSpacer);
+ bottomSpacer->changeSize(0, 0, QSizePolicy::Ignored, expandPage ? QSizePolicy::Ignored : QSizePolicy::MinimumExpanding);
+ pageVBoxLayout->invalidate();
+ }
+
+ if (info.header) {
+ Q_ASSERT(page);
+ headerWidget->setup(info, page->title(), page->subTitle(),
+ page->pixmap(QWizard::LogoPixmap), page->pixmap(QWizard::BannerPixmap),
+ titleFmt, subTitleFmt);
+ }
+
+ if (info.watermark || info.sideWidget) {
+ QPixmap pix;
+ if (info.watermark) {
+ if (page)
+ pix = page->pixmap(QWizard::WatermarkPixmap);
+ else
+ pix = q->pixmap(QWizard::WatermarkPixmap);
+ }
+ watermarkLabel->setPixmap(pix); // in case there is no watermark and we show the side widget we need to clear the watermark
+ }
+
+ if (info.title) {
+ Q_ASSERT(page);
+ titleLabel->setTextFormat(titleFmt);
+ titleLabel->setText(page->title());
+ }
+ if (info.subTitle) {
+ Q_ASSERT(page);
+ subTitleLabel->setTextFormat(subTitleFmt);
+ subTitleLabel->setText(page->subTitle());
+ }
+
+ enableUpdates();
+ updateMinMaxSizes(info);
+}
+
+void QWizardPrivate::updateMinMaxSizes(const QWizardLayoutInfo &info)
+{
+ Q_Q(QWizard);
+
+ int extraHeight = 0;
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ if (isVistaThemeEnabled())
+ extraHeight = vistaHelper->titleBarSize() + vistaHelper->topOffset();
+#endif
+ QSize minimumSize = mainLayout->totalMinimumSize() + QSize(0, extraHeight);
+ QSize maximumSize = mainLayout->totalMaximumSize();
+ if (info.header && headerWidget->maximumWidth() != QWIDGETSIZE_MAX) {
+ minimumSize.setWidth(headerWidget->maximumWidth());
+ maximumSize.setWidth(headerWidget->maximumWidth());
+ }
+ if (info.watermark && !info.sideWidget) {
+ minimumSize.setHeight(mainLayout->totalSizeHint().height());
+ maximumSize.setHeight(mainLayout->totalSizeHint().height());
+ }
+ if (q->minimumWidth() == minimumWidth) {
+ minimumWidth = minimumSize.width();
+ q->setMinimumWidth(minimumWidth);
+ }
+ if (q->minimumHeight() == minimumHeight) {
+ minimumHeight = minimumSize.height();
+ q->setMinimumHeight(minimumHeight);
+ }
+ if (q->maximumWidth() == maximumWidth) {
+ maximumWidth = maximumSize.width();
+ q->setMaximumWidth(maximumWidth);
+ }
+ if (q->maximumHeight() == maximumHeight) {
+ maximumHeight = maximumSize.height();
+ q->setMaximumHeight(maximumHeight);
+ }
+}
+
+void QWizardPrivate::updateCurrentPage()
+{
+ Q_Q(QWizard);
+ if (q->currentPage()) {
+ canContinue = (q->nextId() != -1);
+ canFinish = q->currentPage()->isFinalPage();
+ } else {
+ canContinue = false;
+ canFinish = false;
+ }
+ _q_updateButtonStates();
+ updateButtonTexts();
+}
+
+bool QWizardPrivate::ensureButton(QWizard::WizardButton which) const
+{
+ Q_Q(const QWizard);
+ if (uint(which) >= QWizard::NButtons)
+ return false;
+
+ if (!btns[which]) {
+ QPushButton *pushButton = new QPushButton(antiFlickerWidget);
+ QStyle *style = q->style();
+ if (style != QApplication::style()) // Propagate style
+ pushButton->setStyle(style);
+ // Make navigation buttons detectable as passive interactor in designer
+ switch (which) {
+ case QWizard::CommitButton:
+ case QWizard::FinishButton:
+ case QWizard::CancelButton:
+ break;
+ default: {
+ QString objectName = QLatin1String("__qt__passive_wizardbutton");
+ objectName += QString::number(which);
+ pushButton->setObjectName(objectName);
+ }
+ break;
+ }
+#ifdef Q_WS_MAC
+ pushButton->setAutoDefault(false);
+#endif
+ pushButton->hide();
+#ifdef Q_CC_HPACC
+ const_cast<QWizardPrivate *>(this)->btns[which] = pushButton;
+#else
+ btns[which] = pushButton;
+#endif
+ if (which < QWizard::NStandardButtons)
+ pushButton->setText(buttonDefaultText(wizStyle, which, this));
+
+#ifdef QT_SOFTKEYS_ENABLED
+ QAction *softKey = new QAction(pushButton->text(), pushButton);
+ QAction::SoftKeyRole softKeyRole;
+ switch(which) {
+ case QWizard::NextButton:
+ case QWizard::FinishButton:
+ case QWizard::CancelButton:
+ softKeyRole = QAction::NegativeSoftKey;
+ break;
+ case QWizard::BackButton:
+ case QWizard::CommitButton:
+ case QWizard::HelpButton:
+ case QWizard::CustomButton1:
+ case QWizard::CustomButton2:
+ case QWizard::CustomButton3:
+ default:
+ softKeyRole = QAction::PositiveSoftKey;
+ break;
+ }
+ softKey->setSoftKeyRole(softKeyRole);
+ softKeys[which] = softKey;
+#endif
+ connectButton(which);
+ }
+ return true;
+}
+
+void QWizardPrivate::connectButton(QWizard::WizardButton which) const
+{
+ Q_Q(const QWizard);
+ if (which < QWizard::NStandardButtons) {
+ QObject::connect(btns[which], SIGNAL(clicked()), q, buttonSlots[which]);
+ } else {
+ QObject::connect(btns[which], SIGNAL(clicked()), q, SLOT(_q_emitCustomButtonClicked()));
+ }
+
+#ifdef QT_SOFTKEYS_ENABLED
+ QObject::connect(softKeys[which], SIGNAL(triggered()), btns[which], SIGNAL(clicked()));
+#endif
+}
+
+void QWizardPrivate::updateButtonTexts()
+{
+ Q_Q(QWizard);
+ for (int i = 0; i < QWizard::NButtons; ++i) {
+ if (btns[i]) {
+ if (q->currentPage() && (q->currentPage()->d_func()->buttonCustomTexts.contains(i)))
+ btns[i]->setText(q->currentPage()->d_func()->buttonCustomTexts.value(i));
+ else if (buttonCustomTexts.contains(i))
+ btns[i]->setText(buttonCustomTexts.value(i));
+ else if (i < QWizard::NStandardButtons)
+ btns[i]->setText(buttonDefaultText(wizStyle, i, this));
+#ifdef QT_SOFTKEYS_ENABLED
+ softKeys[i]->setText(btns[i]->text());
+#endif
+ }
+ }
+}
+
+void QWizardPrivate::updateButtonLayout()
+{
+ if (buttonsHaveCustomLayout) {
+ QVarLengthArray<QWizard::WizardButton> array(buttonsCustomLayout.count());
+ for (int i = 0; i < buttonsCustomLayout.count(); ++i)
+ array[i] = buttonsCustomLayout.at(i);
+ setButtonLayout(array.constData(), array.count());
+ } else {
+ // Positions:
+ // Help Stretch Custom1 Custom2 Custom3 Cancel Back Next Commit Finish Cancel Help
+
+ const int ArraySize = 12;
+ QWizard::WizardButton array[ArraySize];
+ memset(array, -1, sizeof(array));
+ Q_ASSERT(array[0] == QWizard::NoButton);
+
+ if (opts & QWizard::HaveHelpButton) {
+ int i = (opts & QWizard::HelpButtonOnRight) ? 11 : 0;
+ array[i] = QWizard::HelpButton;
+ }
+ array[1] = QWizard::Stretch;
+ if (opts & QWizard::HaveCustomButton1)
+ array[2] = QWizard::CustomButton1;
+ if (opts & QWizard::HaveCustomButton2)
+ array[3] = QWizard::CustomButton2;
+ if (opts & QWizard::HaveCustomButton3)
+ array[4] = QWizard::CustomButton3;
+
+ if (!(opts & QWizard::NoCancelButton)) {
+ int i = (opts & QWizard::CancelButtonOnLeft) ? 5 : 10;
+ array[i] = QWizard::CancelButton;
+ }
+ array[6] = QWizard::BackButton;
+ array[7] = QWizard::NextButton;
+ array[8] = QWizard::CommitButton;
+ array[9] = QWizard::FinishButton;
+
+ setButtonLayout(array, ArraySize);
+ }
+}
+
+void QWizardPrivate::setButtonLayout(const QWizard::WizardButton *array, int size)
+{
+ QWidget *prev = pageFrame;
+
+ for (int i = buttonLayout->count() - 1; i >= 0; --i) {
+ QLayoutItem *item = buttonLayout->takeAt(i);
+ if (QWidget *widget = item->widget())
+ widget->hide();
+ delete item;
+ }
+
+ for (int i = 0; i < size; ++i) {
+ QWizard::WizardButton which = array[i];
+ if (which == QWizard::Stretch) {
+ buttonLayout->addStretch(1);
+ } else if (which != QWizard::NoButton) {
+ ensureButton(which);
+ buttonLayout->addWidget(btns[which]);
+
+ // Back, Next, Commit, and Finish are handled in _q_updateButtonStates()
+ if (which != QWizard::BackButton && which != QWizard::NextButton
+ && which != QWizard::CommitButton && which != QWizard::FinishButton)
+ btns[which]->show();
+
+ if (prev)
+ QWidget::setTabOrder(prev, btns[which]);
+ prev = btns[which];
+ }
+ }
+
+ _q_updateButtonStates();
+}
+
+bool QWizardPrivate::buttonLayoutContains(QWizard::WizardButton which)
+{
+ return !buttonsHaveCustomLayout || buttonsCustomLayout.contains(which);
+}
+
+void QWizardPrivate::updatePixmap(QWizard::WizardPixmap which)
+{
+ Q_Q(QWizard);
+ if (which == QWizard::BackgroundPixmap) {
+ if (wizStyle == QWizard::MacStyle) {
+ q->update();
+ q->updateGeometry();
+ }
+ } else {
+ updateLayout();
+ }
+}
+
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+bool QWizardPrivate::vistaDisabled() const
+{
+ Q_Q(const QWizard);
+ const QVariant v = q->property("_q_wizard_vista_off");
+ return v.isValid() && v.toBool();
+}
+
+bool QWizardPrivate::isVistaThemeEnabled(QVistaHelper::VistaState state) const
+{
+ return wizStyle == QWizard::AeroStyle
+ && QVistaHelper::vistaState() == state
+ && !vistaDisabled();
+}
+
+void QWizardPrivate::handleAeroStyleChange()
+{
+ Q_Q(QWizard);
+
+ if (inHandleAeroStyleChange)
+ return; // prevent recursion
+ inHandleAeroStyleChange = true;
+
+ vistaHelper->disconnectBackButton();
+ q->removeEventFilter(vistaHelper);
+
+ if (isVistaThemeEnabled()) {
+ if (isVistaThemeEnabled(QVistaHelper::VistaAero)) {
+ vistaHelper->setDWMTitleBar(QVistaHelper::ExtendedTitleBar);
+ q->installEventFilter(vistaHelper);
+ q->setMouseTracking(true);
+ antiFlickerWidget->move(0, vistaHelper->titleBarSize() + vistaHelper->topOffset());
+ vistaHelper->backButton()->move(
+ 0, vistaHelper->topOffset() // ### should ideally work without the '+ 1'
+ - qMin(vistaHelper->topOffset(), vistaHelper->topPadding() + 1));
+ } else {
+ vistaHelper->setDWMTitleBar(QVistaHelper::NormalTitleBar);
+ q->setMouseTracking(true);
+ antiFlickerWidget->move(0, vistaHelper->topOffset());
+ vistaHelper->backButton()->move(0, -1); // ### should ideally work with (0, 0)
+ }
+ vistaHelper->setTitleBarIconAndCaptionVisible(false);
+ QObject::connect(
+ vistaHelper->backButton(), SIGNAL(clicked()), q, buttonSlots[QWizard::BackButton]);
+ vistaHelper->backButton()->show();
+ } else {
+ q->setMouseTracking(true); // ### original value possibly different
+#ifndef QT_NO_CURSOR
+ q->unsetCursor(); // ### ditto
+#endif
+ antiFlickerWidget->move(0, 0);
+ vistaHelper->hideBackButton();
+ vistaHelper->setTitleBarIconAndCaptionVisible(true);
+ }
+
+ _q_updateButtonStates();
+
+ if (q->isVisible())
+ vistaHelper->setWindowPosHack();
+
+ inHandleAeroStyleChange = false;
+}
+#endif
+
+bool QWizardPrivate::isVistaThemeEnabled() const
+{
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ return isVistaThemeEnabled(QVistaHelper::VistaAero)
+ || isVistaThemeEnabled(QVistaHelper::VistaBasic);
+#else
+ return false;
+#endif
+}
+
+void QWizardPrivate::disableUpdates()
+{
+ Q_Q(QWizard);
+ if (disableUpdatesCount++ == 0) {
+ q->setUpdatesEnabled(false);
+ antiFlickerWidget->hide();
+ }
+}
+
+void QWizardPrivate::enableUpdates()
+{
+ Q_Q(QWizard);
+ if (--disableUpdatesCount == 0) {
+ antiFlickerWidget->show();
+ q->setUpdatesEnabled(true);
+ }
+}
+
+void QWizardPrivate::_q_emitCustomButtonClicked()
+{
+ Q_Q(QWizard);
+ QObject *button = q->sender();
+ for (int i = QWizard::NStandardButtons; i < QWizard::NButtons; ++i) {
+ if (btns[i] == button) {
+ emit q->customButtonClicked(QWizard::WizardButton(i));
+ break;
+ }
+ }
+}
+
+void QWizardPrivate::_q_updateButtonStates()
+{
+ Q_Q(QWizard);
+
+ disableUpdates();
+
+ const QWizardPage *page = q->currentPage();
+ bool complete = page && page->isComplete();
+
+ btn.back->setEnabled(history.count() > 1
+ && !q->page(history.at(history.count() - 2))->isCommitPage()
+ && (!canFinish || !(opts & QWizard::DisabledBackButtonOnLastPage)));
+ btn.next->setEnabled(canContinue && complete);
+ btn.commit->setEnabled(canContinue && complete);
+ btn.finish->setEnabled(canFinish && complete);
+
+ const bool backButtonVisible = buttonLayoutContains(QWizard::BackButton)
+ && (history.count() > 1 || !(opts & QWizard::NoBackButtonOnStartPage))
+ && (canContinue || !(opts & QWizard::NoBackButtonOnLastPage));
+ bool commitPage = page && page->isCommitPage();
+ btn.back->setVisible(backButtonVisible);
+ btn.next->setVisible(buttonLayoutContains(QWizard::NextButton) && !commitPage
+ && (canContinue || (opts & QWizard::HaveNextButtonOnLastPage)));
+ btn.commit->setVisible(buttonLayoutContains(QWizard::CommitButton) && commitPage
+ && canContinue);
+ btn.finish->setVisible(buttonLayoutContains(QWizard::FinishButton)
+ && (canFinish || (opts & QWizard::HaveFinishButtonOnEarlyPages)));
+
+ bool useDefault = !(opts & QWizard::NoDefaultButton);
+ if (QPushButton *nextPush = qobject_cast<QPushButton *>(btn.next))
+ nextPush->setDefault(canContinue && useDefault && !commitPage);
+ if (QPushButton *commitPush = qobject_cast<QPushButton *>(btn.commit))
+ commitPush->setDefault(canContinue && useDefault && commitPage);
+ if (QPushButton *finishPush = qobject_cast<QPushButton *>(btn.finish))
+ finishPush->setDefault(!canContinue && useDefault);
+
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ if (isVistaThemeEnabled()) {
+ vistaHelper->backButton()->setEnabled(btn.back->isEnabled());
+ vistaHelper->backButton()->setVisible(backButtonVisible);
+ btn.back->setVisible(false);
+ }
+#endif
+
+#ifdef QT_SOFTKEYS_ENABLED
+ QAbstractButton *wizardButton;
+ for (int i = 0; i < QWizard::NButtons; ++i) {
+ wizardButton = btns[i];
+ if (wizardButton && !wizardButton->testAttribute(Qt::WA_WState_Hidden)) {
+ wizardButton->hide();
+ q->addAction(softKeys[i]);
+ } else {
+ q->removeAction(softKeys[i]);
+ }
+ }
+#endif
+
+ enableUpdates();
+}
+
+void QWizardPrivate::_q_handleFieldObjectDestroyed(QObject *object)
+{
+ QVector<QWizardField>::iterator it = fields.begin();
+ while (it != fields.end()) {
+ const QWizardField &field = *it;
+ if (field.object == object) {
+ fieldIndexMap.remove(field.name);
+ it = fields.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void QWizardPrivate::setStyle(QStyle *style)
+{
+ for (int i = 0; i < QWizard::NButtons; i++)
+ if (btns[i])
+ btns[i]->setStyle(style);
+ const PageMap::const_iterator pcend = pageMap.constEnd();
+ for (PageMap::const_iterator it = pageMap.constBegin(); it != pcend; ++it)
+ it.value()->setStyle(style);
+}
+
+#ifdef Q_WS_MAC
+
+QPixmap QWizardPrivate::findDefaultBackgroundPixmap()
+{
+ QCFType<CFURLRef> url;
+ const int ExpectedImageWidth = 242;
+ const int ExpectedImageHeight = 414;
+ if (LSFindApplicationForInfo(kLSUnknownCreator, CFSTR("com.apple.KeyboardSetupAssistant"),
+ 0, 0, &url) == noErr) {
+ QCFType<CFBundleRef> bundle = CFBundleCreate(kCFAllocatorDefault, url);
+ if (bundle) {
+ url = CFBundleCopyResourceURL(bundle, CFSTR("Background"), CFSTR("tif"), 0);
+ if (url) {
+ QCFType<CGImageSourceRef> imageSource = CGImageSourceCreateWithURL(url, 0);
+ QCFType<CGImageRef> image = CGImageSourceCreateImageAtIndex(imageSource, 0, 0);
+ if (image) {
+ int width = CGImageGetWidth(image);
+ int height = CGImageGetHeight(image);
+ if (width == ExpectedImageWidth && height == ExpectedImageHeight)
+ return QPixmap::fromMacCGImageRef(image);
+ }
+ }
+ }
+ }
+ return QPixmap();
+
+}
+
+#endif
+
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+void QWizardAntiFlickerWidget::paintEvent(QPaintEvent *)
+{
+ if (wizardPrivate->isVistaThemeEnabled()) {
+ int leftMargin, topMargin, rightMargin, bottomMargin;
+ wizardPrivate->buttonLayout->getContentsMargins(
+ &leftMargin, &topMargin, &rightMargin, &bottomMargin);
+ const int buttonLayoutTop = wizardPrivate->buttonLayout->contentsRect().top() - topMargin;
+ QPainter painter(this);
+ const QBrush brush(QColor(240, 240, 240)); // ### hardcoded for now
+ painter.fillRect(0, buttonLayoutTop, width(), height() - buttonLayoutTop, brush);
+ painter.setPen(QPen(QBrush(QColor(223, 223, 223)), 0)); // ### hardcoded for now
+ painter.drawLine(0, buttonLayoutTop, width(), buttonLayoutTop);
+ if (wizardPrivate->isVistaThemeEnabled(QVistaHelper::VistaBasic)) {
+ if (window()->isActiveWindow())
+ painter.setPen(QPen(QBrush(QColor(169, 191, 214)), 0)); // ### hardcoded for now
+ else
+ painter.setPen(QPen(QBrush(QColor(182, 193, 204)), 0)); // ### hardcoded for now
+ painter.drawLine(0, 0, width(), 0);
+ }
+ }
+}
+#endif
+
+/*!
+ \class QWizard
+ \since 4.3
+ \brief The QWizard class provides a framework for wizards.
+
+ A wizard (also called an assistant on Mac OS X) is a special type
+ of input dialog that consists of a sequence of pages. A wizard's
+ purpose is to guide the user through a process step by step.
+ Wizards are useful for complex or infrequent tasks that users may
+ find difficult to learn.
+
+ QWizard inherits QDialog and represents a wizard. Each page is a
+ QWizardPage (a QWidget subclass). To create your own wizards, you
+ can use these classes directly, or you can subclass them for more
+ control.
+
+ Topics:
+
+ \tableofcontents
+
+ \section1 A Trivial Example
+
+ The following example illustrates how to create wizard pages and
+ add them to a wizard. For more advanced examples, see
+ \l{dialogs/classwizard}{Class Wizard} and \l{dialogs/licensewizard}{License
+ Wizard}.
+
+ \snippet examples/dialogs/trivialwizard/trivialwizard.cpp 1
+ \snippet examples/dialogs/trivialwizard/trivialwizard.cpp 3
+ \dots
+ \snippet examples/dialogs/trivialwizard/trivialwizard.cpp 4
+ \codeline
+ \snippet examples/dialogs/trivialwizard/trivialwizard.cpp 5
+ \snippet examples/dialogs/trivialwizard/trivialwizard.cpp 7
+ \dots
+ \snippet examples/dialogs/trivialwizard/trivialwizard.cpp 8
+ \codeline
+ \snippet examples/dialogs/trivialwizard/trivialwizard.cpp 10
+
+ \section1 Wizard Look and Feel
+
+ QWizard supports four wizard looks:
+
+ \list
+ \o ClassicStyle
+ \o ModernStyle
+ \o MacStyle
+ \o AeroStyle
+ \endlist
+
+ You can explicitly set the look to use using setWizardStyle()
+ (e.g., if you want the same look on all platforms).
+
+ \table
+ \header \o ClassicStyle
+ \o ModernStyle
+ \o MacStyle
+ \o AeroStyle
+ \row \o \inlineimage qtwizard-classic1.png
+ \o \inlineimage qtwizard-modern1.png
+ \o \inlineimage qtwizard-mac1.png
+ \o \inlineimage qtwizard-aero1.png
+ \row \o \inlineimage qtwizard-classic2.png
+ \o \inlineimage qtwizard-modern2.png
+ \o \inlineimage qtwizard-mac2.png
+ \o \inlineimage qtwizard-aero2.png
+ \endtable
+
+ Note: AeroStyle has effect only on a Windows Vista system with alpha compositing enabled.
+ ModernStyle is used as a fallback when this condition is not met.
+
+ In addition to the wizard style, there are several options that
+ control the look and feel of the wizard. These can be set using
+ setOption() or setOptions(). For example, HaveHelpButton makes
+ QWizard show a \gui Help button along with the other wizard
+ buttons.
+
+ You can even change the order of the wizard buttons to any
+ arbitrary order using setButtonLayout(), and you can add up to
+ three custom buttons (e.g., a \gui Print button) to the button
+ row. This is achieved by calling setButton() or setButtonText()
+ with CustomButton1, CustomButton2, or CustomButton3 to set up the
+ button, and by enabling the HaveCustomButton1, HaveCustomButton2,
+ or HaveCustomButton3 options. Whenever the user clicks a custom
+ button, customButtonClicked() is emitted. For example:
+
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 29
+
+ \section1 Elements of a Wizard Page
+
+ Wizards consist of a sequence of \l{QWizardPage}s. At any time,
+ only one page is shown. A page has the following attributes:
+
+ \list
+ \o A \l{QWizardPage::}{title}.
+ \o A \l{QWizardPage::}{subTitle}.
+ \o A set of pixmaps, which may or may not be honored, depending
+ on the wizard's style:
+ \list
+ \o WatermarkPixmap (used by ClassicStyle and ModernStyle)
+ \o BannerPixmap (used by ModernStyle)
+ \o LogoPixmap (used by ClassicStyle and ModernStyle)
+ \o BackgroundPixmap (used by MacStyle)
+ \endlist
+ \endlist
+
+ The diagram belows shows how QWizard renders these attributes,
+ assuming they are all present and ModernStyle is used:
+
+ \image qtwizard-nonmacpage.png
+
+ When a \l{QWizardPage::}{subTitle} is set, QWizard displays it
+ in a header, in which case it also uses the BannerPixmap and the
+ LogoPixmap to decorate the header. The WatermarkPixmap is
+ displayed on the left side, below the header. At the bottom,
+ there is a row of buttons allowing the user to navigate through
+ the pages.
+
+ The page itself (the \l{QWizardPage} widget) occupies the area
+ between the header, the watermark, and the button row. Typically,
+ the page is a QWizardPage on which a QGridLayout is installed,
+ with standard child widgets (\l{QLabel}s, \l{QLineEdit}s, etc.).
+
+ If the wizard's style is MacStyle, the page looks radically
+ different:
+
+ \image qtwizard-macpage.png
+
+ The watermark, banner, and logo pixmaps are ignored by the
+ MacStyle. If the BackgroundPixmap is set, it is used as the
+ background for the wizard; otherwise, a default "assistant" image
+ is used.
+
+ The title and subtitle are set by calling
+ QWizardPage::setTitle() and QWizardPage::setSubTitle() on the
+ individual pages. They may be plain text or HTML (see titleFormat
+ and subTitleFormat). The pixmaps can be set globally for the
+ entire wizard using setPixmap(), or on a per-page basis using
+ QWizardPage::setPixmap().
+
+ \target field mechanism
+ \section1 Registering and Using Fields
+
+ In many wizards, the contents of a page may affect the default
+ values of the fields of a later page. To make it easy to
+ communicate between pages, QWizard supports a "field" mechanism
+ that allows you to register a field (e.g., a QLineEdit) on a page
+ and to access its value from any page. It is also possible to
+ specify mandatory fields (i.e., fields that must be filled before
+ the user can advance to the next page).
+
+ To register a field, call QWizardPage::registerField() field.
+ For example:
+
+ \snippet examples/dialogs/classwizard/classwizard.cpp 8
+ \dots
+ \snippet examples/dialogs/classwizard/classwizard.cpp 10
+ \snippet examples/dialogs/classwizard/classwizard.cpp 11
+ \dots
+ \snippet examples/dialogs/classwizard/classwizard.cpp 13
+
+ The above code registers three fields, \c className, \c
+ baseClass, and \c qobjectMacro, which are associated with three
+ child widgets. The asterisk (\c *) next to \c className denotes a
+ mandatory field.
+
+ \target initialize page
+ The fields of any page are accessible from any other page. For
+ example:
+
+ \snippet examples/dialogs/classwizard/classwizard.cpp 17
+
+ Here, we call QWizardPage::field() to access the contents of the
+ \c className field (which was defined in the \c ClassInfoPage)
+ and use it to initialize the \c OuputFilePage. The field's
+ contents is returned as a QVariant.
+
+ When we create a field using QWizardPage::registerField(), we
+ pass a unique field name and a widget. We can also provide a Qt
+ property name and a "changed" signal (a signal that is emitted
+ when the property changes) as third and fourth arguments;
+ however, this is not necessary for the most common Qt widgets,
+ such as QLineEdit, QCheckBox, and QComboBox, because QWizard
+ knows which properties to look for.
+
+ \target mandatory fields
+
+ If an asterisk (\c *) is appended to the name when the property
+ is registered, the field is a \e{mandatory field}. When a page has
+ mandatory fields, the \gui Next and/or \gui Finish buttons are
+ enabled only when all mandatory fields are filled.
+
+ To consider a field "filled", QWizard simply checks that the
+ field's current value doesn't equal the original value (the value
+ it had when initializePage() was called). For QLineEdit and
+ QAbstractSpinBox subclasses, QWizard also checks that
+ \l{QLineEdit::hasAcceptableInput()}{hasAcceptableInput()} returns
+ true, to honor any validator or mask.
+
+ QWizard's mandatory field mechanism is provided for convenience.
+ A more powerful (but also more cumbersome) alternative is to
+ reimplement QWizardPage::isComplete() and to emit the
+ QWizardPage::completeChanged() signal whenever the page becomes
+ complete or incomplete.
+
+ The enabled/disabled state of the \gui Next and/or \gui Finish
+ buttons is one way to perform validation on the user input.
+ Another way is to reimplement validateCurrentPage() (or
+ QWizardPage::validatePage()) to perform some last-minute
+ validation (and show an error message if the user has entered
+ incomplete or invalid information). If the function returns true,
+ the next page is shown (or the wizard finishes); otherwise, the
+ current page stays up.
+
+ \section1 Creating Linear Wizards
+
+ Most wizards have a linear structure, with page 1 followed by
+ page 2 and so on until the last page. The \l{dialogs/classwizard}{Class
+ Wizard} example is such a wizard. With QWizard, linear wizards
+ are created by instantiating the \l{QWizardPage}s and inserting
+ them using addPage(). By default, the pages are shown in the
+ order in which they were added. For example:
+
+ \snippet examples/dialogs/classwizard/classwizard.cpp 0
+ \dots
+ \snippet examples/dialogs/classwizard/classwizard.cpp 2
+
+ When a page is about to be shown, QWizard calls initializePage()
+ (which in turn calls QWizardPage::initializePage()) to fill the
+ page with default values. By default, this function does nothing,
+ but it can be reimplemented to initialize the page's contents
+ based on other pages' fields (see the \l{initialize page}{example
+ above}).
+
+ If the user presses \gui Back, cleanupPage() is called (which in
+ turn calls QWizardPage::cleanupPage()). The default
+ implementation resets the page's fields to their original values
+ (the values they had before initializePage() was called). If you
+ want the \gui Back button to be non-destructive and keep the
+ values entered by the user, simply enable the IndependentPages
+ option.
+
+ \section1 Creating Non-Linear Wizards
+
+ Some wizards are more complex in that they allow different
+ traversal paths based on the information provided by the user.
+ The \l{dialogs/licensewizard}{License Wizard} example illustrates this.
+ It provides five wizard pages; depending on which options are
+ selected, the user can reach different pages.
+
+ \image licensewizard-flow.png
+
+ In complex wizards, pages are identified by IDs. These IDs are
+ typically defined using an enum. For example:
+
+ \snippet examples/dialogs/licensewizard/licensewizard.h 0
+ \dots
+ \snippet examples/dialogs/licensewizard/licensewizard.h 2
+ \dots
+ \snippet examples/dialogs/licensewizard/licensewizard.h 3
+
+ The pages are inserted using setPage(), which takes an ID and an
+ instance of QWizardPage (or of a subclass):
+
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 1
+ \dots
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 8
+
+ By default, the pages are shown in increasing ID order. To
+ provide a dynamic order that depends on the options chosen by the
+ user, we must reimplement QWizardPage::nextId(). For example:
+
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 18
+ \codeline
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 23
+ \codeline
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 24
+ \codeline
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 25
+ \codeline
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 26
+
+ It would also be possible to put all the logic in one place, in a
+ QWizard::nextId() reimplementation. For example:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qwizard.cpp 0
+
+ To start at another page than the page with the lowest ID, call
+ setStartId().
+
+ To test whether a page has been visited or not, call
+ hasVisitedPage(). For example:
+
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 27
+
+ \sa QWizardPage, {Class Wizard Example}, {License Wizard Example}
+*/
+
+/*!
+ \enum QWizard::WizardButton
+
+ This enum specifies the buttons in a wizard.
+
+ \value BackButton The \gui Back button (\gui {Go Back} on Mac OS X)
+ \value NextButton The \gui Next button (\gui Continue on Mac OS X)
+ \value CommitButton The \gui Commit button
+ \value FinishButton The \gui Finish button (\gui Done on Mac OS X)
+ \value CancelButton The \gui Cancel button (see also NoCancelButton)
+ \value HelpButton The \gui Help button (see also HaveHelpButton)
+ \value CustomButton1 The first user-defined button (see also HaveCustomButton1)
+ \value CustomButton2 The second user-defined button (see also HaveCustomButton2)
+ \value CustomButton3 The third user-defined button (see also HaveCustomButton3)
+
+ The following value is only useful when calling setButtonLayout():
+
+ \value Stretch A horizontal stretch in the button layout
+
+ \omitvalue NoButton
+ \omitvalue NStandardButtons
+ \omitvalue NButtons
+
+ \sa setButton(), setButtonText(), setButtonLayout(), customButtonClicked()
+*/
+
+/*!
+ \enum QWizard::WizardPixmap
+
+ This enum specifies the pixmaps that can be associated with a page.
+
+ \value WatermarkPixmap The tall pixmap on the left side of a ClassicStyle or ModernStyle page
+ \value LogoPixmap The small pixmap on the right side of a ClassicStyle or ModernStyle page header
+ \value BannerPixmap The pixmap that occupies the background of a ModernStyle page header
+ \value BackgroundPixmap The pixmap that occupies the background of a MacStyle wizard
+
+ \omitvalue NPixmaps
+
+ \sa setPixmap(), QWizardPage::setPixmap(), {Elements of a Wizard Page}
+*/
+
+/*!
+ \enum QWizard::WizardStyle
+
+ This enum specifies the different looks supported by QWizard.
+
+ \value ClassicStyle Classic Windows look
+ \value ModernStyle Modern Windows look
+ \value MacStyle Mac OS X look
+ \value AeroStyle Windows Aero look
+
+ \omitvalue NStyles
+
+ \sa setWizardStyle(), WizardOption, {Wizard Look and Feel}
+*/
+
+/*!
+ \enum QWizard::WizardOption
+
+ This enum specifies various options that affect the look and feel
+ of a wizard.
+
+ \value IndependentPages The pages are independent of each other
+ (i.e., they don't derive values from each
+ other).
+ \value IgnoreSubTitles Don't show any subtitles, even if they are set.
+ \value ExtendedWatermarkPixmap Extend any WatermarkPixmap all the
+ way down to the window's edge.
+ \value NoDefaultButton Don't make the \gui Next or \gui Finish button the
+ dialog's \l{QPushButton::setDefault()}{default button}.
+ \value NoBackButtonOnStartPage Don't show the \gui Back button on the start page.
+ \value NoBackButtonOnLastPage Don't show the \gui Back button on the last page.
+ \value DisabledBackButtonOnLastPage Disable the \gui Back button on the last page.
+ \value HaveNextButtonOnLastPage Show the (disabled) \gui Next button on the last page.
+ \value HaveFinishButtonOnEarlyPages Show the (disabled) \gui Finish button on non-final pages.
+ \value NoCancelButton Don't show the \gui Cancel button.
+ \value CancelButtonOnLeft Put the \gui Cancel button on the left of \gui Back (rather than on
+ the right of \gui Finish or \gui Next).
+ \value HaveHelpButton Show the \gui Help button.
+ \value HelpButtonOnRight Put the \gui Help button on the far right of the button layout
+ (rather than on the far left).
+ \value HaveCustomButton1 Show the first user-defined button (CustomButton1).
+ \value HaveCustomButton2 Show the second user-defined button (CustomButton2).
+ \value HaveCustomButton3 Show the third user-defined button (CustomButton3).
+
+ \sa setOptions(), setOption(), testOption()
+*/
+
+/*!
+ Constructs a wizard with the given \a parent and window \a flags.
+
+ \sa parent(), windowFlags()
+*/
+QWizard::QWizard(QWidget *parent, Qt::WindowFlags flags)
+ : QDialog(*new QWizardPrivate, parent, flags)
+{
+ Q_D(QWizard);
+ d->init();
+#ifdef Q_WS_WINCE
+ if (!qt_wince_is_mobile())
+ setWindowFlags(windowFlags() & ~Qt::WindowOkButtonHint);
+#endif
+}
+
+/*!
+ Destroys the wizard and its pages, releasing any allocated resources.
+*/
+QWizard::~QWizard()
+{
+ Q_D(QWizard);
+ delete d->buttonLayout;
+}
+
+/*!
+ Adds the given \a page to the wizard, and returns the page's ID.
+
+ The ID is guaranteed to be larger than any other ID in the
+ QWizard so far.
+
+ \sa setPage(), page(), pageAdded()
+*/
+int QWizard::addPage(QWizardPage *page)
+{
+ Q_D(QWizard);
+ int theid = 0;
+ if (!d->pageMap.isEmpty())
+ theid = (d->pageMap.constEnd() - 1).key() + 1;
+ setPage(theid, page);
+ return theid;
+}
+
+/*!
+ \fn void QWizard::setPage(int id, QWizardPage *page)
+
+ Adds the given \a page to the wizard with the given \a id.
+
+ \note Adding a page may influence the value of the startId property
+ in case it was not set explicitly.
+
+ \sa addPage(), page(), pageAdded()
+*/
+void QWizard::setPage(int theid, QWizardPage *page)
+{
+ Q_D(QWizard);
+
+ if (!page) {
+ qWarning("QWizard::setPage: Cannot insert null page");
+ return;
+ }
+
+ if (theid == -1) {
+ qWarning("QWizard::setPage: Cannot insert page with ID -1");
+ return;
+ }
+
+ if (d->pageMap.contains(theid)) {
+ qWarning("QWizard::setPage: Page with duplicate ID %d ignored", theid);
+ return;
+ }
+
+ page->setParent(d->pageFrame);
+
+ QVector<QWizardField> &pendingFields = page->d_func()->pendingFields;
+ for (int i = 0; i < pendingFields.count(); ++i)
+ d->addField(pendingFields.at(i));
+ pendingFields.clear();
+
+ connect(page, SIGNAL(completeChanged()), this, SLOT(_q_updateButtonStates()));
+
+ d->pageMap.insert(theid, page);
+ page->d_func()->wizard = this;
+
+ int n = d->pageVBoxLayout->count();
+
+ // disable layout to prevent layout updates while adding
+ bool pageVBoxLayoutEnabled = d->pageVBoxLayout->isEnabled();
+ d->pageVBoxLayout->setEnabled(false);
+
+ d->pageVBoxLayout->insertWidget(n - 1, page);
+
+ // hide new page and reset layout to old status
+ page->hide();
+ d->pageVBoxLayout->setEnabled(pageVBoxLayoutEnabled);
+
+ if (!d->startSetByUser && d->pageMap.constBegin().key() == theid)
+ d->start = theid;
+ emit pageAdded(theid);
+}
+
+/*!
+ Removes the page with the given \a id. cleanupPage() will be called if necessary.
+
+ \note Removing a page may influence the value of the startId property.
+
+ \since 4.5
+ \sa addPage(), setPage(), pageRemoved(), startId()
+*/
+void QWizard::removePage(int id)
+{
+ Q_D(QWizard);
+
+ QWizardPage *removedPage = 0;
+
+ // update startItem accordingly
+ if (d->pageMap.count() > 0) { // only if we have any pages
+ if (d->start == id) {
+ const int firstId = d->pageMap.constBegin().key();
+ if (firstId == id) {
+ if (d->pageMap.count() > 1)
+ d->start = (++d->pageMap.constBegin()).key(); // secondId
+ else
+ d->start = -1; // removing the last page
+ } else { // startSetByUser has to be "true" here
+ d->start = firstId;
+ }
+ d->startSetByUser = false;
+ }
+ }
+
+ if (d->pageMap.contains(id))
+ emit pageRemoved(id);
+
+ if (!d->history.contains(id)) {
+ // Case 1: removing a page not in the history
+ removedPage = d->pageMap.take(id);
+ d->updateCurrentPage();
+ } else if (id != d->current) {
+ // Case 2: removing a page in the history before the current page
+ removedPage = d->pageMap.take(id);
+ d->history.removeOne(id);
+ d->_q_updateButtonStates();
+ } else if (d->history.count() == 1) {
+ // Case 3: removing the current page which is the first (and only) one in the history
+ d->reset();
+ removedPage = d->pageMap.take(id);
+ if (d->pageMap.isEmpty())
+ d->updateCurrentPage();
+ else
+ restart();
+ } else {
+ // Case 4: removing the current page which is not the first one in the history
+ back();
+ removedPage = d->pageMap.take(id);
+ d->updateCurrentPage();
+ }
+
+ if (removedPage) {
+ if (d->initialized.contains(id)) {
+ cleanupPage(id);
+ d->initialized.remove(id);
+ }
+
+ d->pageVBoxLayout->removeWidget(removedPage);
+
+ for (int i = d->fields.count() - 1; i >= 0; --i) {
+ if (d->fields.at(i).page == removedPage) {
+ removedPage->d_func()->pendingFields += d->fields.at(i);
+ d->removeFieldAt(i);
+ }
+ }
+ }
+}
+
+/*!
+ \fn QWizardPage *QWizard::page(int id) const
+
+ Returns the page with the given \a id, or 0 if there is no such
+ page.
+
+ \sa addPage(), setPage()
+*/
+QWizardPage *QWizard::page(int theid) const
+{
+ Q_D(const QWizard);
+ return d->pageMap.value(theid);
+}
+
+/*!
+ \fn bool QWizard::hasVisitedPage(int id) const
+
+ Returns true if the page history contains page \a id; otherwise,
+ returns false.
+
+ Pressing \gui Back marks the current page as "unvisited" again.
+
+ \sa visitedPages()
+*/
+bool QWizard::hasVisitedPage(int theid) const
+{
+ Q_D(const QWizard);
+ return d->history.contains(theid);
+}
+
+/*!
+ Returns the list of IDs of visited pages, in the order in which the pages
+ were visited.
+
+ Pressing \gui Back marks the current page as "unvisited" again.
+
+ \sa hasVisitedPage()
+*/
+QList<int> QWizard::visitedPages() const
+{
+ Q_D(const QWizard);
+ return d->history;
+}
+
+/*!
+ Returns the list of page IDs.
+ \since 4.5
+*/
+QList<int> QWizard::pageIds() const
+{
+ Q_D(const QWizard);
+ return d->pageMap.keys();
+}
+
+/*!
+ \property QWizard::startId
+ \brief the ID of the first page
+
+ If this property isn't explicitly set, this property defaults to
+ the lowest page ID in this wizard, or -1 if no page has been
+ inserted yet.
+
+ \sa restart(), nextId()
+*/
+void QWizard::setStartId(int theid)
+{
+ Q_D(QWizard);
+ int newStart = theid;
+ if (theid == -1)
+ newStart = d->pageMap.count() ? d->pageMap.constBegin().key() : -1;
+
+ if (d->start == newStart) {
+ d->startSetByUser = theid != -1;
+ return;
+ }
+
+ if (!d->pageMap.contains(newStart)) {
+ qWarning("QWizard::setStartId: Invalid page ID %d", newStart);
+ return;
+ }
+ d->start = newStart;
+ d->startSetByUser = theid != -1;
+}
+
+int QWizard::startId() const
+{
+ Q_D(const QWizard);
+ return d->start;
+}
+
+/*!
+ Returns a pointer to the current page, or 0 if there is no current
+ page (e.g., before the wizard is shown).
+
+ This is equivalent to calling page(currentId()).
+
+ \sa page(), currentId(), restart()
+*/
+QWizardPage *QWizard::currentPage() const
+{
+ Q_D(const QWizard);
+ return page(d->current);
+}
+
+/*!
+ \property QWizard::currentId
+ \brief the ID of the current page
+
+ This property cannot be set directly. To change the current page,
+ call next(), back(), or restart().
+
+ By default, this property has a value of -1, indicating that no page is
+ currently shown.
+
+ \sa currentIdChanged(), currentPage()
+*/
+int QWizard::currentId() const
+{
+ Q_D(const QWizard);
+ return d->current;
+}
+
+/*!
+ Sets the value of the field called \a name to \a value.
+
+ This function can be used to set fields on any page of the wizard.
+
+ \sa QWizardPage::registerField(), QWizardPage::setField(), field()
+*/
+void QWizard::setField(const QString &name, const QVariant &value)
+{
+ Q_D(QWizard);
+
+ int index = d->fieldIndexMap.value(name, -1);
+ if (index != -1) {
+ const QWizardField &field = d->fields.at(index);
+ if (!field.object->setProperty(field.property, value))
+ qWarning("QWizard::setField: Couldn't write to property '%s'",
+ field.property.constData());
+ return;
+ }
+
+ qWarning("QWizard::setField: No such field '%s'", qPrintable(name));
+}
+
+/*!
+ Returns the value of the field called \a name.
+
+ This function can be used to access fields on any page of the wizard.
+
+ \sa QWizardPage::registerField(), QWizardPage::field(), setField()
+*/
+QVariant QWizard::field(const QString &name) const
+{
+ Q_D(const QWizard);
+
+ int index = d->fieldIndexMap.value(name, -1);
+ if (index != -1) {
+ const QWizardField &field = d->fields.at(index);
+ return field.object->property(field.property);
+ }
+
+ qWarning("QWizard::field: No such field '%s'", qPrintable(name));
+ return QVariant();
+}
+
+/*!
+ \property QWizard::wizardStyle
+ \brief the look and feel of the wizard
+
+ By default, QWizard uses the AeroStyle on a Windows Vista system with alpha compositing
+ enabled, regardless of the current widget style. If this is not the case, the default
+ wizard style depends on the current widget style as follows: MacStyle is the default if
+ the current widget style is QMacStyle, ModernStyle is the default if the current widget
+ style is QWindowsStyle, and ClassicStyle is the default in all other cases.
+
+ \sa {Wizard Look and Feel}, options
+*/
+void QWizard::setWizardStyle(WizardStyle style)
+{
+ Q_D(QWizard);
+
+ const bool styleChange = style != d->wizStyle;
+
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ const bool aeroStyleChange =
+ d->vistaInitPending || d->vistaStateChanged || (styleChange && (style == AeroStyle || d->wizStyle == AeroStyle));
+ d->vistaStateChanged = false;
+ d->vistaInitPending = false;
+#endif
+
+ if (styleChange
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ || aeroStyleChange
+#endif
+ ) {
+ d->disableUpdates();
+ d->wizStyle = style;
+ d->updateButtonTexts();
+ d->updateLayout();
+ updateGeometry();
+ d->enableUpdates();
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ if (aeroStyleChange)
+ d->handleAeroStyleChange();
+#endif
+ }
+}
+
+QWizard::WizardStyle QWizard::wizardStyle() const
+{
+ Q_D(const QWizard);
+ return d->wizStyle;
+}
+
+/*!
+ Sets the given \a option to be enabled if \a on is true;
+ otherwise, clears the given \a option.
+
+ \sa options, testOption(), setWizardStyle()
+*/
+void QWizard::setOption(WizardOption option, bool on)
+{
+ Q_D(QWizard);
+ if (!(d->opts & option) != !on)
+ setOptions(d->opts ^ option);
+}
+
+/*!
+ Returns true if the given \a option is enabled; otherwise, returns
+ false.
+
+ \sa options, setOption(), setWizardStyle()
+*/
+bool QWizard::testOption(WizardOption option) const
+{
+ Q_D(const QWizard);
+ return (d->opts & option) != 0;
+}
+
+/*!
+ \property QWizard::options
+ \brief the various options that affect the look and feel of the wizard
+
+ By default, the following options are set (depending on the platform):
+
+ \list
+ \o Windows: HelpButtonOnRight.
+ \o Mac OS X: NoDefaultButton and NoCancelButton.
+ \o X11 and QWS (Qt for Embedded Linux): none.
+ \endlist
+
+ \sa wizardStyle
+*/
+void QWizard::setOptions(WizardOptions options)
+{
+ Q_D(QWizard);
+
+ WizardOptions changed = (options ^ d->opts);
+ if (!changed)
+ return;
+
+ d->disableUpdates();
+
+ d->opts = options;
+ if ((changed & IndependentPages) && !(d->opts & IndependentPages))
+ d->cleanupPagesNotInHistory();
+
+ if (changed & (NoDefaultButton | HaveHelpButton | HelpButtonOnRight | NoCancelButton
+ | CancelButtonOnLeft | HaveCustomButton1 | HaveCustomButton2
+ | HaveCustomButton3)) {
+ d->updateButtonLayout();
+ } else if (changed & (NoBackButtonOnStartPage | NoBackButtonOnLastPage
+ | HaveNextButtonOnLastPage | HaveFinishButtonOnEarlyPages
+ | DisabledBackButtonOnLastPage)) {
+ d->_q_updateButtonStates();
+ }
+
+ d->enableUpdates();
+ d->updateLayout();
+}
+
+QWizard::WizardOptions QWizard::options() const
+{
+ Q_D(const QWizard);
+ return d->opts;
+}
+
+/*!
+ Sets the text on button \a which to be \a text.
+
+ By default, the text on buttons depends on the wizardStyle. For
+ example, on Mac OS X, the \gui Next button is called \gui
+ Continue.
+
+ To add extra buttons to the wizard (e.g., a \gui Print button),
+ one way is to call setButtonText() with CustomButton1,
+ CustomButton2, or CustomButton3 to set their text, and make the
+ buttons visible using the HaveCustomButton1, HaveCustomButton2,
+ and/or HaveCustomButton3 options.
+
+ Button texts may also be set on a per-page basis using QWizardPage::setButtonText().
+
+ \sa setButton(), button(), setButtonLayout(), setOptions(), QWizardPage::setButtonText()
+*/
+void QWizard::setButtonText(WizardButton which, const QString &text)
+{
+ Q_D(QWizard);
+
+ if (!d->ensureButton(which))
+ return;
+
+ d->buttonCustomTexts.insert(which, text);
+
+ if (!currentPage() || !currentPage()->d_func()->buttonCustomTexts.contains(which))
+ d->btns[which]->setText(text);
+}
+
+/*!
+ Returns the text on button \a which.
+
+ If a text has ben set using setButtonText(), this text is returned.
+
+ By default, the text on buttons depends on the wizardStyle. For
+ example, on Mac OS X, the \gui Next button is called \gui
+ Continue.
+
+ \sa button(), setButton(), setButtonText(), QWizardPage::buttonText(),
+ QWizardPage::setButtonText()
+*/
+QString QWizard::buttonText(WizardButton which) const
+{
+ Q_D(const QWizard);
+
+ if (!d->ensureButton(which))
+ return QString();
+
+ if (d->buttonCustomTexts.contains(which))
+ return d->buttonCustomTexts.value(which);
+
+ const QString defText = buttonDefaultText(d->wizStyle, which, d);
+ if(!defText.isNull())
+ return defText;
+
+ return d->btns[which]->text();
+}
+
+/*!
+ Sets the order in which buttons are displayed to \a layout, where
+ \a layout is a list of \l{WizardButton}s.
+
+ The default layout depends on the options (e.g., whether
+ HelpButtonOnRight) that are set. You can call this function if
+ you need more control over the buttons' layout than what \l
+ options already provides.
+
+ You can specify horizontal stretches in the layout using \l
+ Stretch.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qwizard.cpp 1
+
+ \sa setButton(), setButtonText(), setOptions()
+*/
+void QWizard::setButtonLayout(const QList<WizardButton> &layout)
+{
+ Q_D(QWizard);
+
+ for (int i = 0; i < layout.count(); ++i) {
+ WizardButton button1 = layout.at(i);
+
+ if (button1 == NoButton || button1 == Stretch)
+ continue;
+ if (!d->ensureButton(button1))
+ return;
+
+ // O(n^2), but n is very small
+ for (int j = 0; j < i; ++j) {
+ WizardButton button2 = layout.at(j);
+ if (button2 == button1) {
+ qWarning("QWizard::setButtonLayout: Duplicate button in layout");
+ return;
+ }
+ }
+ }
+
+ d->buttonsHaveCustomLayout = true;
+ d->buttonsCustomLayout = layout;
+ d->updateButtonLayout();
+}
+
+/*!
+ Sets the button corresponding to role \a which to \a button.
+
+ To add extra buttons to the wizard (e.g., a \gui Print button),
+ one way is to call setButton() with CustomButton1 to
+ CustomButton3, and make the buttons visible using the
+ HaveCustomButton1 to HaveCustomButton3 options.
+
+ \sa setButtonText(), setButtonLayout(), options
+*/
+void QWizard::setButton(WizardButton which, QAbstractButton *button)
+{
+ Q_D(QWizard);
+
+ if (uint(which) >= NButtons || d->btns[which] == button)
+ return;
+
+ if (QAbstractButton *oldButton = d->btns[which]) {
+ d->buttonLayout->removeWidget(oldButton);
+ delete oldButton;
+ }
+
+ d->btns[which] = button;
+ if (button) {
+ button->setParent(d->antiFlickerWidget);
+ d->buttonCustomTexts.insert(which, button->text());
+ d->connectButton(which);
+ } else {
+ d->buttonCustomTexts.remove(which); // ### what about page-specific texts set for 'which'
+ d->ensureButton(which); // (QWizardPage::setButtonText())? Clear them as well?
+ }
+
+ d->updateButtonLayout();
+}
+
+/*!
+ Returns the button corresponding to role \a which.
+
+ \sa setButton(), setButtonText()
+*/
+QAbstractButton *QWizard::button(WizardButton which) const
+{
+ Q_D(const QWizard);
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ if (d->wizStyle == AeroStyle && which == BackButton)
+ return d->vistaHelper->backButton();
+#endif
+ if (!d->ensureButton(which))
+ return 0;
+ return d->btns[which];
+}
+
+/*!
+ \property QWizard::titleFormat
+ \brief the text format used by page titles
+
+ The default format is Qt::AutoText.
+
+ \sa QWizardPage::title, subTitleFormat
+*/
+void QWizard::setTitleFormat(Qt::TextFormat format)
+{
+ Q_D(QWizard);
+ d->titleFmt = format;
+ d->updateLayout();
+}
+
+Qt::TextFormat QWizard::titleFormat() const
+{
+ Q_D(const QWizard);
+ return d->titleFmt;
+}
+
+/*!
+ \property QWizard::subTitleFormat
+ \brief the text format used by page subtitles
+
+ The default format is Qt::AutoText.
+
+ \sa QWizardPage::title, titleFormat
+*/
+void QWizard::setSubTitleFormat(Qt::TextFormat format)
+{
+ Q_D(QWizard);
+ d->subTitleFmt = format;
+ d->updateLayout();
+}
+
+Qt::TextFormat QWizard::subTitleFormat() const
+{
+ Q_D(const QWizard);
+ return d->subTitleFmt;
+}
+
+/*!
+ Sets the pixmap for role \a which to \a pixmap.
+
+ The pixmaps are used by QWizard when displaying a page. Which
+ pixmaps are actually used depend on the \l{Wizard Look and
+ Feel}{wizard style}.
+
+ Pixmaps can also be set for a specific page using
+ QWizardPage::setPixmap().
+
+ \sa QWizardPage::setPixmap(), {Elements of a Wizard Page}
+*/
+void QWizard::setPixmap(WizardPixmap which, const QPixmap &pixmap)
+{
+ Q_D(QWizard);
+ Q_ASSERT(uint(which) < NPixmaps);
+ d->defaultPixmaps[which] = pixmap;
+ d->updatePixmap(which);
+}
+
+/*!
+ Returns the pixmap set for role \a which.
+
+ By default, the only pixmap that is set is the BackgroundPixmap on
+ Mac OS X.
+
+ \sa QWizardPage::pixmap(), {Elements of a Wizard Page}
+*/
+QPixmap QWizard::pixmap(WizardPixmap which) const
+{
+ Q_D(const QWizard);
+ Q_ASSERT(uint(which) < NPixmaps);
+#ifdef Q_WS_MAC
+ if (which == BackgroundPixmap && d->defaultPixmaps[BackgroundPixmap].isNull())
+ d->defaultPixmaps[BackgroundPixmap] = d->findDefaultBackgroundPixmap();
+#endif
+ return d->defaultPixmaps[which];
+}
+
+/*!
+ Sets the default property for \a className to be \a property,
+ and the associated change signal to be \a changedSignal.
+
+ The default property is used when an instance of \a className (or
+ of one of its subclasses) is passed to
+ QWizardPage::registerField() and no property is specified.
+
+ QWizard knows the most common Qt widgets. For these (or their
+ subclasses), you don't need to specify a \a property or a \a
+ changedSignal. The table below lists these widgets:
+
+ \table
+ \header \o Widget \o Property \o Change Notification Signal
+ \row \o QAbstractButton \o bool \l{QAbstractButton::}{checked} \o \l{QAbstractButton::}{toggled()}
+ \row \o QAbstractSlider \o int \l{QAbstractSlider::}{value} \o \l{QAbstractSlider::}{valueChanged()}
+ \row \o QComboBox \o int \l{QComboBox::}{currentIndex} \o \l{QComboBox::}{currentIndexChanged()}
+ \row \o QDateTimeEdit \o QDateTime \l{QDateTimeEdit::}{dateTime} \o \l{QDateTimeEdit::}{dateTimeChanged()}
+ \row \o QLineEdit \o QString \l{QLineEdit::}{text} \o \l{QLineEdit::}{textChanged()}
+ \row \o QListWidget \o int \l{QListWidget::}{currentRow} \o \l{QListWidget::}{currentRowChanged()}
+ \row \o QSpinBox \o int \l{QSpinBox::}{value} \o \l{QSpinBox::}{valueChanged()}
+ \endtable
+
+ \sa QWizardPage::registerField()
+*/
+void QWizard::setDefaultProperty(const char *className, const char *property,
+ const char *changedSignal)
+{
+ Q_D(QWizard);
+ for (int i = d->defaultPropertyTable.count() - 1; i >= 0; --i) {
+ if (qstrcmp(d->defaultPropertyTable.at(i).className, className) == 0) {
+ d->defaultPropertyTable.remove(i);
+ break;
+ }
+ }
+ d->defaultPropertyTable.append(QWizardDefaultProperty(className, property, changedSignal));
+}
+
+/*!
+ \since 4.7
+
+ Sets the given \a widget to be shown on the left side of the wizard.
+ For styles which use the WatermarkPixmap (ClassicStyle and ModernStyle)
+ the side widget is displayed on top of the watermark, for other styles
+ or when the watermark is not provided the side widget is displayed
+ on the left side of the wizard.
+
+ Passing 0 shows no side widget.
+
+ When the \a widget is not 0 the wizard reparents it.
+
+ Any previous side widget is hidden.
+
+ You may call setSideWidget() with the same widget at different
+ times.
+
+ All widgets set here will be deleted by the wizard when it is
+ destroyed unless you separately reparent the widget after setting
+ some other side widget (or 0).
+
+ By default, no side widget is present.
+*/
+void QWizard::setSideWidget(QWidget *widget)
+{
+ Q_D(QWizard);
+
+ d->sideWidget = widget;
+ if (d->watermarkLabel) {
+ d->watermarkLabel->setSideWidget(widget);
+ d->updateLayout();
+ }
+}
+
+/*!
+ \since 4.7
+
+ Returns the widget on the left side of the wizard or 0.
+
+ By default, no side widget is present.
+*/
+QWidget *QWizard::sideWidget() const
+{
+ Q_D(const QWizard);
+
+ return d->sideWidget;
+}
+
+/*!
+ \reimp
+*/
+void QWizard::setVisible(bool visible)
+{
+ Q_D(QWizard);
+ if (visible) {
+ if (d->current == -1)
+ restart();
+ }
+ QDialog::setVisible(visible);
+}
+
+/*!
+ \reimp
+*/
+QSize QWizard::sizeHint() const
+{
+ Q_D(const QWizard);
+ QSize result = d->mainLayout->totalSizeHint();
+#ifdef Q_WS_S60
+ QSize extra(QApplication::desktop()->availableGeometry(QCursor::pos()).size());
+#else
+ QSize extra(500, 360);
+#endif
+ if (d->wizStyle == MacStyle && d->current != -1) {
+ QSize pixmap(currentPage()->pixmap(BackgroundPixmap).size());
+ extra.setWidth(616);
+ if (!pixmap.isNull()) {
+ extra.setHeight(pixmap.height());
+
+ /*
+ The width isn't always reliable as a size hint, as
+ some wizard backgrounds just cover the leftmost area.
+ Use a rule of thumb to determine if the width is
+ reliable or not.
+ */
+ if (pixmap.width() >= pixmap.height())
+ extra.setWidth(pixmap.width());
+ }
+ }
+ return result.expandedTo(extra);
+}
+
+/*!
+ \fn void QWizard::currentIdChanged(int id)
+
+ This signal is emitted when the current page changes, with the new
+ current \a id.
+
+ \sa currentId(), currentPage()
+*/
+
+/*!
+ \fn void QWizard::pageAdded(int id)
+
+ \since 4.7
+
+ This signal is emitted whenever a page is added to the
+ wizard. The page's \a id is passed as parameter.
+
+ \sa addPage(), setPage(), startId()
+*/
+
+/*!
+ \fn void QWizard::pageRemoved(int id)
+
+ \since 4.7
+
+ This signal is emitted whenever a page is removed from the
+ wizard. The page's \a id is passed as parameter.
+
+ \sa removePage(), startId()
+*/
+
+/*!
+ \fn void QWizard::helpRequested()
+
+ This signal is emitted when the user clicks the \gui Help button.
+
+ By default, no \gui Help button is shown. Call
+ setOption(HaveHelpButton, true) to have one.
+
+ Example:
+
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 0
+ \dots
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 5
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 7
+ \dots
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 8
+ \codeline
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 10
+ \dots
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 12
+ \codeline
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 14
+ \codeline
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 15
+
+ \sa customButtonClicked()
+*/
+
+/*!
+ \fn void QWizard::customButtonClicked(int which)
+
+ This signal is emitted when the user clicks a custom button. \a
+ which can be CustomButton1, CustomButton2, or CustomButton3.
+
+ By default, no custom button is shown. Call setOption() with
+ HaveCustomButton1, HaveCustomButton2, or HaveCustomButton3 to have
+ one, and use setButtonText() or setButton() to configure it.
+
+ \sa helpRequested()
+*/
+
+/*!
+ Goes back to the previous page.
+
+ This is equivalent to pressing the \gui Back button.
+
+ \sa next(), accept(), reject(), restart()
+*/
+void QWizard::back()
+{
+ Q_D(QWizard);
+ int n = d->history.count() - 2;
+ if (n < 0)
+ return;
+ d->switchToPage(d->history.at(n), QWizardPrivate::Backward);
+}
+
+/*!
+ Advances to the next page.
+
+ This is equivalent to pressing the \gui Next or \gui Commit button.
+
+ \sa nextId(), back(), accept(), reject(), restart()
+*/
+void QWizard::next()
+{
+ Q_D(QWizard);
+
+ if (d->current == -1)
+ return;
+
+ if (validateCurrentPage()) {
+ int next = nextId();
+ if (next != -1) {
+ if (d->history.contains(next)) {
+ qWarning("QWizard::next: Page %d already met", next);
+ return;
+ }
+ if (!d->pageMap.contains(next)) {
+ qWarning("QWizard::next: No such page %d", next);
+ return;
+ }
+ d->switchToPage(next, QWizardPrivate::Forward);
+ }
+ }
+}
+
+/*!
+ Restarts the wizard at the start page. This function is called automatically when the
+ wizard is shown.
+
+ \sa startId()
+*/
+void QWizard::restart()
+{
+ Q_D(QWizard);
+ d->disableUpdates();
+ d->reset();
+ d->switchToPage(startId(), QWizardPrivate::Forward);
+ d->enableUpdates();
+}
+
+/*!
+ \reimp
+*/
+bool QWizard::event(QEvent *event)
+{
+ Q_D(QWizard);
+ if (event->type() == QEvent::StyleChange) { // Propagate style
+ d->setStyle(style());
+ d->updateLayout();
+ }
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ else if (event->type() == QEvent::Show && d->vistaInitPending) {
+ d->vistaInitPending = false;
+ d->wizStyle = AeroStyle;
+ d->handleAeroStyleChange();
+ }
+ else if (d->isVistaThemeEnabled()) {
+ d->vistaHelper->mouseEvent(event);
+ }
+#endif
+ return QDialog::event(event);
+}
+
+/*!
+ \reimp
+*/
+void QWizard::resizeEvent(QResizeEvent *event)
+{
+ Q_D(QWizard);
+ int heightOffset = 0;
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ if (d->isVistaThemeEnabled()) {
+ heightOffset = d->vistaHelper->topOffset();
+ if (d->isVistaThemeEnabled(QVistaHelper::VistaAero))
+ heightOffset += d->vistaHelper->titleBarSize();
+ }
+#endif
+ d->antiFlickerWidget->resize(event->size().width(), event->size().height() - heightOffset);
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ if (d->isVistaThemeEnabled())
+ d->vistaHelper->resizeEvent(event);
+#endif
+ QDialog::resizeEvent(event);
+}
+
+/*!
+ \reimp
+*/
+void QWizard::paintEvent(QPaintEvent * event)
+{
+ Q_D(QWizard);
+ if (d->wizStyle == MacStyle && currentPage()) {
+ QPixmap backgroundPixmap = currentPage()->pixmap(BackgroundPixmap);
+ if (backgroundPixmap.isNull())
+ return;
+
+ QPainter painter(this);
+ painter.drawPixmap(0, (height() - backgroundPixmap.height()) / 2, backgroundPixmap);
+ }
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ else if (d->isVistaThemeEnabled()) {
+ if (d->isVistaThemeEnabled(QVistaHelper::VistaBasic)) {
+ QPainter painter(this);
+ QColor color = d->vistaHelper->basicWindowFrameColor();
+ painter.fillRect(0, 0, width(), QVistaHelper::topOffset(), color);
+ }
+ d->vistaHelper->paintEvent(event);
+ }
+#else
+ Q_UNUSED(event);
+#endif
+}
+
+#if defined(Q_WS_WIN)
+/*!
+ \reimp
+*/
+bool QWizard::winEvent(MSG *message, long *result)
+{
+#if !defined(QT_NO_STYLE_WINDOWSVISTA)
+ Q_D(QWizard);
+ if (d->isVistaThemeEnabled()) {
+ const bool winEventResult = d->vistaHelper->handleWinEvent(message, result);
+ if (QVistaHelper::vistaState() != d->vistaState) {
+ d->vistaState = QVistaHelper::vistaState();
+ d->vistaStateChanged = true;
+ setWizardStyle(AeroStyle);
+ }
+ return winEventResult;
+ } else {
+ return QDialog::winEvent(message, result);
+ }
+#else
+ return QDialog::winEvent(message, result);
+#endif
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QWizard::done(int result)
+{
+ Q_D(QWizard);
+ // canceling leaves the wizard in a known state
+ if (result == Rejected) {
+ d->reset();
+ } else {
+ if (!validateCurrentPage())
+ return;
+ }
+ QDialog::done(result);
+}
+
+/*!
+ \fn void QWizard::initializePage(int id)
+
+ This virtual function is called by QWizard to prepare page \a id
+ just before it is shown either as a result of QWizard::restart()
+ being called, or as a result of the user clicking \gui Next. (However, if the \l
+ QWizard::IndependentPages option is set, this function is only
+ called the first time the page is shown.)
+
+ By reimplementing this function, you can ensure that the page's
+ fields are properly initialized based on fields from previous
+ pages.
+
+ The default implementation calls QWizardPage::initializePage() on
+ page(\a id).
+
+ \sa QWizardPage::initializePage(), cleanupPage()
+*/
+void QWizard::initializePage(int theid)
+{
+ QWizardPage *page = this->page(theid);
+ if (page)
+ page->initializePage();
+}
+
+/*!
+ \fn void QWizard::cleanupPage(int id)
+
+ This virtual function is called by QWizard to clean up page \a id just before the
+ user leaves it by clicking \gui Back (unless the \l QWizard::IndependentPages option is set).
+
+ The default implementation calls QWizardPage::cleanupPage() on
+ page(\a id).
+
+ \sa QWizardPage::cleanupPage(), initializePage()
+*/
+void QWizard::cleanupPage(int theid)
+{
+ QWizardPage *page = this->page(theid);
+ if (page)
+ page->cleanupPage();
+}
+
+/*!
+ This virtual function is called by QWizard when the user clicks
+ \gui Next or \gui Finish to perform some last-minute validation.
+ If it returns true, the next page is shown (or the wizard
+ finishes); otherwise, the current page stays up.
+
+ The default implementation calls QWizardPage::validatePage() on
+ the currentPage().
+
+ When possible, it is usually better style to disable the \gui
+ Next or \gui Finish button (by specifying \l{mandatory fields} or
+ by reimplementing QWizardPage::isComplete()) than to reimplement
+ validateCurrentPage().
+
+ \sa QWizardPage::validatePage(), currentPage()
+*/
+bool QWizard::validateCurrentPage()
+{
+ QWizardPage *page = currentPage();
+ if (!page)
+ return true;
+
+ return page->validatePage();
+}
+
+/*!
+ This virtual function is called by QWizard to find out which page
+ to show when the user clicks the \gui Next button.
+
+ The return value is the ID of the next page, or -1 if no page follows.
+
+ The default implementation calls QWizardPage::nextId() on the
+ currentPage().
+
+ By reimplementing this function, you can specify a dynamic page
+ order.
+
+ \sa QWizardPage::nextId(), currentPage()
+*/
+int QWizard::nextId() const
+{
+ const QWizardPage *page = currentPage();
+ if (!page)
+ return -1;
+
+ return page->nextId();
+}
+
+/*!
+ \class QWizardPage
+ \since 4.3
+ \brief The QWizardPage class is the base class for wizard pages.
+
+ QWizard represents a wizard. Each page is a QWizardPage. When
+ you create your own wizards, you can use QWizardPage directly,
+ or you can subclass it for more control.
+
+ A page has the following attributes, which are rendered by
+ QWizard: a \l title, a \l subTitle, and a \l{setPixmap()}{set of
+ pixmaps}. See \l{Elements of a Wizard Page} for details. Once a
+ page is added to the wizard (using QWizard::addPage() or
+ QWizard::setPage()), wizard() returns a pointer to the
+ associated QWizard object.
+
+ Page provides five virtual functions that can be reimplemented to
+ provide custom behavior:
+
+ \list
+ \o initializePage() is called to initialize the page's contents
+ when the user clicks the wizard's \gui Next button. If you
+ want to derive the page's default from what the user entered
+ on previous pages, this is the function to reimplement.
+ \o cleanupPage() is called to reset the page's contents when the
+ user clicks the wizard's \gui Back button.
+ \o validatePage() validates the page when the user clicks \gui
+ Next or \gui Finish. It is often used to show an error message
+ if the user has entered incomplete or invalid information.
+ \o nextId() returns the ID of the next page. It is useful when
+ \l{creating non-linear wizards}, which allow different
+ traversal paths based on the information provided by the user.
+ \o isComplete() is called to determine whether the \gui Next
+ and/or \gui Finish button should be enabled or disabled. If
+ you reimplement isComplete(), also make sure that
+ completeChanged() is emitted whenever the complete state
+ changes.
+ \endlist
+
+ Normally, the \gui Next button and the \gui Finish button of a
+ wizard are mutually exclusive. If isFinalPage() returns true, \gui
+ Finish is available; otherwise, \gui Next is available. By
+ default, isFinalPage() is true only when nextId() returns -1. If
+ you want to show \gui Next and \gui Final simultaneously for a
+ page (letting the user perform an "early finish"), call
+ setFinalPage(true) on that page. For wizards that support early
+ finishes, you might also want to set the
+ \l{QWizard::}{HaveNextButtonOnLastPage} and
+ \l{QWizard::}{HaveFinishButtonOnEarlyPages} options on the
+ wizard.
+
+ In many wizards, the contents of a page may affect the default
+ values of the fields of a later page. To make it easy to
+ communicate between pages, QWizard supports a \l{Registering and
+ Using Fields}{"field" mechanism} that allows you to register a
+ field (e.g., a QLineEdit) on a page and to access its value from
+ any page. Fields are global to the entire wizard and make it easy
+ for any single page to access information stored by another page,
+ without having to put all the logic in QWizard or having the
+ pages know explicitly about each other. Fields are registered
+ using registerField() and can be accessed at any time using
+ field() and setField().
+
+ \sa QWizard, {Class Wizard Example}, {License Wizard Example}
+*/
+
+/*!
+ Constructs a wizard page with the given \a parent.
+
+ When the page is inserted into a wizard using QWizard::addPage()
+ or QWizard::setPage(), the parent is automatically set to be the
+ wizard.
+
+ \sa wizard()
+*/
+QWizardPage::QWizardPage(QWidget *parent)
+ : QWidget(*new QWizardPagePrivate, parent, 0)
+{
+ connect(this, SIGNAL(completeChanged()), this, SLOT(_q_updateCachedCompleteState()));
+}
+
+/*!
+ \property QWizardPage::title
+ \brief the title of the page
+
+ The title is shown by the QWizard, above the actual page. All
+ pages should have a title.
+
+ The title may be plain text or HTML, depending on the value of the
+ \l{QWizard::titleFormat} property.
+
+ By default, this property contains an empty string.
+
+ \sa subTitle, {Elements of a Wizard Page}
+*/
+void QWizardPage::setTitle(const QString &title)
+{
+ Q_D(QWizardPage);
+ d->title = title;
+ if (d->wizard && d->wizard->currentPage() == this)
+ d->wizard->d_func()->updateLayout();
+}
+
+QString QWizardPage::title() const
+{
+ Q_D(const QWizardPage);
+ return d->title;
+}
+
+/*!
+ \property QWizardPage::subTitle
+ \brief the subtitle of the page
+
+ The subtitle is shown by the QWizard, between the title and the
+ actual page. Subtitles are optional. In
+ \l{QWizard::ClassicStyle}{ClassicStyle} and
+ \l{QWizard::ModernStyle}{ModernStyle}, using subtitles is
+ necessary to make the header appear. In
+ \l{QWizard::MacStyle}{MacStyle}, the subtitle is shown as a text
+ label just above the actual page.
+
+ The subtitle may be plain text or HTML, depending on the value of
+ the \l{QWizard::subTitleFormat} property.
+
+ By default, this property contains an empty string.
+
+ \sa title, QWizard::IgnoreSubTitles, {Elements of a Wizard Page}
+*/
+void QWizardPage::setSubTitle(const QString &subTitle)
+{
+ Q_D(QWizardPage);
+ d->subTitle = subTitle;
+ if (d->wizard && d->wizard->currentPage() == this)
+ d->wizard->d_func()->updateLayout();
+}
+
+QString QWizardPage::subTitle() const
+{
+ Q_D(const QWizardPage);
+ return d->subTitle;
+}
+
+/*!
+ Sets the pixmap for role \a which to \a pixmap.
+
+ The pixmaps are used by QWizard when displaying a page. Which
+ pixmaps are actually used depend on the \l{Wizard Look and
+ Feel}{wizard style}.
+
+ Pixmaps can also be set for the entire wizard using
+ QWizard::setPixmap(), in which case they apply for all pages that
+ don't specify a pixmap.
+
+ \sa QWizard::setPixmap(), {Elements of a Wizard Page}
+*/
+void QWizardPage::setPixmap(QWizard::WizardPixmap which, const QPixmap &pixmap)
+{
+ Q_D(QWizardPage);
+ Q_ASSERT(uint(which) < QWizard::NPixmaps);
+ d->pixmaps[which] = pixmap;
+ if (d->wizard && d->wizard->currentPage() == this)
+ d->wizard->d_func()->updatePixmap(which);
+}
+
+/*!
+ Returns the pixmap set for role \a which.
+
+ Pixmaps can also be set for the entire wizard using
+ QWizard::setPixmap(), in which case they apply for all pages that
+ don't specify a pixmap.
+
+ \sa QWizard::pixmap(), {Elements of a Wizard Page}
+*/
+QPixmap QWizardPage::pixmap(QWizard::WizardPixmap which) const
+{
+ Q_D(const QWizardPage);
+ Q_ASSERT(uint(which) < QWizard::NPixmaps);
+
+ const QPixmap &pixmap = d->pixmaps[which];
+ if (!pixmap.isNull())
+ return pixmap;
+
+ if (wizard())
+ return wizard()->pixmap(which);
+
+ return pixmap;
+}
+
+/*!
+ This virtual function is called by QWizard::initializePage() to
+ prepare the page just before it is shown either as a result of QWizard::restart()
+ being called, or as a result of the user clicking \gui Next.
+ (However, if the \l QWizard::IndependentPages option is set, this function is only
+ called the first time the page is shown.)
+
+ By reimplementing this function, you can ensure that the page's
+ fields are properly initialized based on fields from previous
+ pages. For example:
+
+ \snippet examples/dialogs/classwizard/classwizard.cpp 17
+
+ The default implementation does nothing.
+
+ \sa QWizard::initializePage(), cleanupPage(), QWizard::IndependentPages
+*/
+void QWizardPage::initializePage()
+{
+}
+
+/*!
+ This virtual function is called by QWizard::cleanupPage() when
+ the user leaves the page by clicking \gui Back (unless the \l QWizard::IndependentPages
+ option is set).
+
+ The default implementation resets the page's fields to their
+ original values (the values they had before initializePage() was
+ called).
+
+ \sa QWizard::cleanupPage(), initializePage(), QWizard::IndependentPages
+*/
+void QWizardPage::cleanupPage()
+{
+ Q_D(QWizardPage);
+ if (d->wizard) {
+ QVector<QWizardField> &fields = d->wizard->d_func()->fields;
+ for (int i = 0; i < fields.count(); ++i) {
+ const QWizardField &field = fields.at(i);
+ if (field.page == this)
+ field.object->setProperty(field.property, field.initialValue);
+ }
+ }
+}
+
+/*!
+ This virtual function is called by QWizard::validateCurrentPage()
+ when the user clicks \gui Next or \gui Finish to perform some
+ last-minute validation. If it returns true, the next page is shown
+ (or the wizard finishes); otherwise, the current page stays up.
+
+ The default implementation returns true.
+
+ When possible, it is usually better style to disable the \gui
+ Next or \gui Finish button (by specifying \l{mandatory fields} or
+ reimplementing isComplete()) than to reimplement validatePage().
+
+ \sa QWizard::validateCurrentPage(), isComplete()
+*/
+bool QWizardPage::validatePage()
+{
+ return true;
+}
+
+/*!
+ This virtual function is called by QWizard to determine whether
+ the \gui Next or \gui Finish button should be enabled or
+ disabled.
+
+ The default implementation returns true if all \l{mandatory
+ fields} are filled; otherwise, it returns false.
+
+ If you reimplement this function, make sure to emit completeChanged(),
+ from the rest of your implementation, whenever the value of isComplete()
+ changes. This ensures that QWizard updates the enabled or disabled state of
+ its buttons. An example of the reimplementation is
+ available \l{http://qt.nokia.com/doc/qq/qq22-qwizard.html#validatebeforeitstoolate}
+ {here}.
+
+ \sa completeChanged(), isFinalPage()
+*/
+bool QWizardPage::isComplete() const
+{
+ Q_D(const QWizardPage);
+
+ if (!d->wizard)
+ return true;
+
+ const QVector<QWizardField> &wizardFields = d->wizard->d_func()->fields;
+ for (int i = wizardFields.count() - 1; i >= 0; --i) {
+ const QWizardField &field = wizardFields.at(i);
+ if (field.page == this && field.mandatory) {
+ QVariant value = field.object->property(field.property);
+ if (value == field.initialValue)
+ return false;
+
+#ifndef QT_NO_LINEEDIT
+ if (QLineEdit *lineEdit = qobject_cast<QLineEdit *>(field.object)) {
+ if (!lineEdit->hasAcceptableInput())
+ return false;
+ }
+#endif
+#ifndef QT_NO_SPINBOX
+ if (QAbstractSpinBox *spinBox = qobject_cast<QAbstractSpinBox *>(field.object)) {
+ if (!spinBox->hasAcceptableInput())
+ return false;
+ }
+#endif
+ }
+ }
+ return true;
+}
+
+/*!
+ Explicitly sets this page to be final if \a finalPage is true.
+
+ After calling setFinalPage(true), isFinalPage() returns true and the \gui
+ Finish button is visible (and enabled if isComplete() returns
+ true).
+
+ After calling setFinalPage(false), isFinalPage() returns true if
+ nextId() returns -1; otherwise, it returns false.
+
+ \sa isComplete(), QWizard::HaveFinishButtonOnEarlyPages
+*/
+void QWizardPage::setFinalPage(bool finalPage)
+{
+ Q_D(QWizardPage);
+ d->explicitlyFinal = finalPage;
+ QWizard *wizard = this->wizard();
+ if (wizard && wizard->currentPage() == this)
+ wizard->d_func()->updateCurrentPage();
+}
+
+/*!
+ This function is called by QWizard to determine whether the \gui
+ Finish button should be shown for this page or not.
+
+ By default, it returns true if there is no next page
+ (i.e., nextId() returns -1); otherwise, it returns false.
+
+ By explicitly calling setFinalPage(true), you can let the user perform an
+ "early finish".
+
+ \sa isComplete(), QWizard::HaveFinishButtonOnEarlyPages
+*/
+bool QWizardPage::isFinalPage() const
+{
+ Q_D(const QWizardPage);
+ if (d->explicitlyFinal)
+ return true;
+
+ QWizard *wizard = this->wizard();
+ if (wizard && wizard->currentPage() == this) {
+ // try to use the QWizard implementation if possible
+ return wizard->nextId() == -1;
+ } else {
+ return nextId() == -1;
+ }
+}
+
+/*!
+ Sets this page to be a commit page if \a commitPage is true; otherwise,
+ sets it to be a normal page.
+
+ A commit page is a page that represents an action which cannot be undone
+ by clicking \gui Back or \gui Cancel.
+
+ A \gui Commit button replaces the \gui Next button on a commit page. Clicking this
+ button simply calls QWizard::next() just like clicking \gui Next does.
+
+ A page entered directly from a commit page has its \gui Back button disabled.
+
+ \sa isCommitPage()
+*/
+void QWizardPage::setCommitPage(bool commitPage)
+{
+ Q_D(QWizardPage);
+ d->commit = commitPage;
+ QWizard *wizard = this->wizard();
+ if (wizard && wizard->currentPage() == this)
+ wizard->d_func()->updateCurrentPage();
+}
+
+/*!
+ Returns true if this page is a commit page; otherwise returns false.
+
+ \sa setCommitPage()
+*/
+bool QWizardPage::isCommitPage() const
+{
+ Q_D(const QWizardPage);
+ return d->commit;
+}
+
+/*!
+ Sets the text on button \a which to be \a text on this page.
+
+ By default, the text on buttons depends on the QWizard::wizardStyle,
+ but may be redefined for the wizard as a whole using QWizard::setButtonText().
+
+ \sa buttonText(), QWizard::setButtonText(), QWizard::buttonText()
+*/
+void QWizardPage::setButtonText(QWizard::WizardButton which, const QString &text)
+{
+ Q_D(QWizardPage);
+ d->buttonCustomTexts.insert(which, text);
+ if (wizard() && wizard()->currentPage() == this && wizard()->d_func()->btns[which])
+ wizard()->d_func()->btns[which]->setText(text);
+}
+
+/*!
+ Returns the text on button \a which on this page.
+
+ If a text has ben set using setButtonText(), this text is returned.
+ Otherwise, if a text has been set using QWizard::setButtonText(),
+ this text is returned.
+
+ By default, the text on buttons depends on the QWizard::wizardStyle.
+ For example, on Mac OS X, the \gui Next button is called \gui
+ Continue.
+
+ \sa setButtonText(), QWizard::buttonText(), QWizard::setButtonText()
+*/
+QString QWizardPage::buttonText(QWizard::WizardButton which) const
+{
+ Q_D(const QWizardPage);
+
+ if (d->buttonCustomTexts.contains(which))
+ return d->buttonCustomTexts.value(which);
+
+ if (wizard())
+ return wizard()->buttonText(which);
+
+ return QString();
+}
+
+/*!
+ This virtual function is called by QWizard::nextId() to find
+ out which page to show when the user clicks the \gui Next button.
+
+ The return value is the ID of the next page, or -1 if no page follows.
+
+ By default, this function returns the lowest ID greater than the ID
+ of the current page, or -1 if there is no such ID.
+
+ By reimplementing this function, you can specify a dynamic page
+ order. For example:
+
+ \snippet examples/dialogs/licensewizard/licensewizard.cpp 18
+
+ \sa QWizard::nextId()
+*/
+int QWizardPage::nextId() const
+{
+ Q_D(const QWizardPage);
+
+ if (!d->wizard)
+ return -1;
+
+ bool foundCurrentPage = false;
+
+ const QWizardPrivate::PageMap &pageMap = d->wizard->d_func()->pageMap;
+ QWizardPrivate::PageMap::const_iterator i = pageMap.constBegin();
+ QWizardPrivate::PageMap::const_iterator end = pageMap.constEnd();
+
+ for (; i != end; ++i) {
+ if (i.value() == this) {
+ foundCurrentPage = true;
+ } else if (foundCurrentPage) {
+ return i.key();
+ }
+ }
+ return -1;
+}
+
+/*!
+ \fn void QWizardPage::completeChanged()
+
+ This signal is emitted whenever the complete state of the page
+ (i.e., the value of isComplete()) changes.
+
+ If you reimplement isComplete(), make sure to emit
+ completeChanged() whenever the value of isComplete() changes, to
+ ensure that QWizard updates the enabled or disabled state of its
+ buttons.
+
+ \sa isComplete()
+*/
+
+/*!
+ Sets the value of the field called \a name to \a value.
+
+ This function can be used to set fields on any page of the wizard.
+ It is equivalent to calling
+ wizard()->\l{QWizard::setField()}{setField(\a name, \a value)}.
+
+ \sa QWizard::setField(), field(), registerField()
+*/
+void QWizardPage::setField(const QString &name, const QVariant &value)
+{
+ Q_D(QWizardPage);
+ if (!d->wizard)
+ return;
+ d->wizard->setField(name, value);
+}
+
+/*!
+ Returns the value of the field called \a name.
+
+ This function can be used to access fields on any page of the
+ wizard. It is equivalent to calling
+ wizard()->\l{QWizard::field()}{field(\a name)}.
+
+ Example:
+
+ \snippet examples/dialogs/classwizard/classwizard.cpp 17
+
+ \sa QWizard::field(), setField(), registerField()
+*/
+QVariant QWizardPage::field(const QString &name) const
+{
+ Q_D(const QWizardPage);
+ if (!d->wizard)
+ return QVariant();
+ return d->wizard->field(name);
+}
+
+/*!
+ Creates a field called \a name associated with the given \a
+ property of the given \a widget. From then on, that property
+ becomes accessible using field() and setField().
+
+ Fields are global to the entire wizard and make it easy for any
+ single page to access information stored by another page, without
+ having to put all the logic in QWizard or having the pages know
+ explicitly about each other.
+
+ If \a name ends with an asterisk (\c *), the field is a mandatory
+ field. When a page has mandatory fields, the \gui Next and/or
+ \gui Finish buttons are enabled only when all mandatory fields
+ are filled. This requires a \a changedSignal to be specified, to
+ tell QWizard to recheck the value stored by the mandatory field.
+
+ QWizard knows the most common Qt widgets. For these (or their
+ subclasses), you don't need to specify a \a property or a \a
+ changedSignal. The table below lists these widgets:
+
+ \table
+ \header \o Widget \o Property \o Change Notification Signal
+ \row \o QAbstractButton \o bool \l{QAbstractButton::}{checked} \o \l{QAbstractButton::}{toggled()}
+ \row \o QAbstractSlider \o int \l{QAbstractSlider::}{value} \o \l{QAbstractSlider::}{valueChanged()}
+ \row \o QComboBox \o int \l{QComboBox::}{currentIndex} \o \l{QComboBox::}{currentIndexChanged()}
+ \row \o QDateTimeEdit \o QDateTime \l{QDateTimeEdit::}{dateTime} \o \l{QDateTimeEdit::}{dateTimeChanged()}
+ \row \o QLineEdit \o QString \l{QLineEdit::}{text} \o \l{QLineEdit::}{textChanged()}
+ \row \o QListWidget \o int \l{QListWidget::}{currentRow} \o \l{QListWidget::}{currentRowChanged()}
+ \row \o QSpinBox \o int \l{QSpinBox::}{value} \o \l{QSpinBox::}{valueChanged()}
+ \endtable
+
+ You can use QWizard::setDefaultProperty() to add entries to this
+ table or to override existing entries.
+
+ To consider a field "filled", QWizard simply checks that their
+ current value doesn't equal their original value (the value they
+ had before initializePage() was called). For QLineEdit, it also
+ checks that
+ \l{QLineEdit::hasAcceptableInput()}{hasAcceptableInput()} returns
+ true, to honor any validator or mask.
+
+ QWizard's mandatory field mechanism is provided for convenience.
+ It can be bypassed by reimplementing QWizardPage::isComplete().
+
+ \sa field(), setField(), QWizard::setDefaultProperty()
+*/
+void QWizardPage::registerField(const QString &name, QWidget *widget, const char *property,
+ const char *changedSignal)
+{
+ Q_D(QWizardPage);
+ QWizardField field(this, name, widget, property, changedSignal);
+ if (d->wizard) {
+ d->wizard->d_func()->addField(field);
+ } else {
+ d->pendingFields += field;
+ }
+}
+
+/*!
+ Returns the wizard associated with this page, or 0 if this page
+ hasn't been inserted into a QWizard yet.
+
+ \sa QWizard::addPage(), QWizard::setPage()
+*/
+QWizard *QWizardPage::wizard() const
+{
+ Q_D(const QWizardPage);
+ return d->wizard;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwizard.cpp"
+
+#endif // QT_NO_WIZARD
diff --git a/src/widgets/dialogs/qwizard.h b/src/widgets/dialogs/qwizard.h
new file mode 100644
index 0000000000..77eef53037
--- /dev/null
+++ b/src/widgets/dialogs/qwizard.h
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIZARD_H
+#define QWIZARD_H
+
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_WIZARD
+
+class QAbstractButton;
+class QWizardPage;
+class QWizardPrivate;
+
+class Q_WIDGETS_EXPORT QWizard : public QDialog
+{
+ Q_OBJECT
+ Q_ENUMS(WizardStyle WizardOption)
+ Q_FLAGS(WizardOptions)
+ Q_PROPERTY(WizardStyle wizardStyle READ wizardStyle WRITE setWizardStyle)
+ Q_PROPERTY(WizardOptions options READ options WRITE setOptions)
+ Q_PROPERTY(Qt::TextFormat titleFormat READ titleFormat WRITE setTitleFormat)
+ Q_PROPERTY(Qt::TextFormat subTitleFormat READ subTitleFormat WRITE setSubTitleFormat)
+ Q_PROPERTY(int startId READ startId WRITE setStartId)
+ Q_PROPERTY(int currentId READ currentId NOTIFY currentIdChanged)
+
+public:
+ enum WizardButton {
+ BackButton,
+ NextButton,
+ CommitButton,
+ FinishButton,
+ CancelButton,
+ HelpButton,
+ CustomButton1,
+ CustomButton2,
+ CustomButton3,
+ Stretch,
+
+ NoButton = -1,
+ NStandardButtons = 6,
+ NButtons = 9
+ };
+
+ enum WizardPixmap {
+ WatermarkPixmap,
+ LogoPixmap,
+ BannerPixmap,
+ BackgroundPixmap,
+ NPixmaps
+ };
+
+ enum WizardStyle {
+ ClassicStyle,
+ ModernStyle,
+ MacStyle,
+ AeroStyle,
+ NStyles
+ };
+
+ enum WizardOption {
+ IndependentPages = 0x00000001,
+ IgnoreSubTitles = 0x00000002,
+ ExtendedWatermarkPixmap = 0x00000004,
+ NoDefaultButton = 0x00000008,
+ NoBackButtonOnStartPage = 0x00000010,
+ NoBackButtonOnLastPage = 0x00000020,
+ DisabledBackButtonOnLastPage = 0x00000040,
+ HaveNextButtonOnLastPage = 0x00000080,
+ HaveFinishButtonOnEarlyPages = 0x00000100,
+ NoCancelButton = 0x00000200,
+ CancelButtonOnLeft = 0x00000400,
+ HaveHelpButton = 0x00000800,
+ HelpButtonOnRight = 0x00001000,
+ HaveCustomButton1 = 0x00002000,
+ HaveCustomButton2 = 0x00004000,
+ HaveCustomButton3 = 0x00008000
+ };
+
+ Q_DECLARE_FLAGS(WizardOptions, WizardOption)
+
+ explicit QWizard(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~QWizard();
+
+ int addPage(QWizardPage *page);
+ void setPage(int id, QWizardPage *page);
+ void removePage(int id);
+ QWizardPage *page(int id) const;
+ bool hasVisitedPage(int id) const;
+ QList<int> visitedPages() const; // ### visitedIds()?
+ QList<int> pageIds() const;
+ void setStartId(int id);
+ int startId() const;
+ QWizardPage *currentPage() const;
+ int currentId() const;
+
+ virtual bool validateCurrentPage();
+ virtual int nextId() const;
+
+ void setField(const QString &name, const QVariant &value);
+ QVariant field(const QString &name) const;
+
+ void setWizardStyle(WizardStyle style);
+ WizardStyle wizardStyle() const;
+
+ void setOption(WizardOption option, bool on = true);
+ bool testOption(WizardOption option) const;
+ void setOptions(WizardOptions options);
+ WizardOptions options() const;
+
+ void setButtonText(WizardButton which, const QString &text);
+ QString buttonText(WizardButton which) const;
+ void setButtonLayout(const QList<WizardButton> &layout);
+ void setButton(WizardButton which, QAbstractButton *button);
+ QAbstractButton *button(WizardButton which) const;
+
+ void setTitleFormat(Qt::TextFormat format);
+ Qt::TextFormat titleFormat() const;
+ void setSubTitleFormat(Qt::TextFormat format);
+ Qt::TextFormat subTitleFormat() const;
+ void setPixmap(WizardPixmap which, const QPixmap &pixmap);
+ QPixmap pixmap(WizardPixmap which) const;
+
+ void setSideWidget(QWidget *widget);
+ QWidget *sideWidget() const;
+
+ void setDefaultProperty(const char *className, const char *property,
+ const char *changedSignal);
+
+ void setVisible(bool visible);
+ QSize sizeHint() const;
+
+Q_SIGNALS:
+ void currentIdChanged(int id);
+ void helpRequested();
+ void customButtonClicked(int which);
+ void pageAdded(int id);
+ void pageRemoved(int id);
+
+public Q_SLOTS:
+ void back();
+ void next();
+ void restart();
+
+protected:
+ bool event(QEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+#if defined(Q_WS_WIN)
+ bool winEvent(MSG * message, long * result);
+#endif
+ void done(int result);
+ virtual void initializePage(int id);
+ virtual void cleanupPage(int id);
+
+private:
+ Q_DISABLE_COPY(QWizard)
+ Q_DECLARE_PRIVATE(QWizard)
+ Q_PRIVATE_SLOT(d_func(), void _q_emitCustomButtonClicked())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateButtonStates())
+ Q_PRIVATE_SLOT(d_func(), void _q_handleFieldObjectDestroyed(QObject *))
+
+ friend class QWizardPage;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QWizard::WizardOptions)
+
+class QWizardPagePrivate;
+
+class Q_WIDGETS_EXPORT QWizardPage : public QWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(QString title READ title WRITE setTitle)
+ Q_PROPERTY(QString subTitle READ subTitle WRITE setSubTitle)
+
+public:
+ QWizardPage(QWidget *parent = 0);
+
+ void setTitle(const QString &title);
+ QString title() const;
+ void setSubTitle(const QString &subTitle);
+ QString subTitle() const;
+ void setPixmap(QWizard::WizardPixmap which, const QPixmap &pixmap);
+ QPixmap pixmap(QWizard::WizardPixmap which) const;
+ void setFinalPage(bool finalPage);
+ bool isFinalPage() const;
+ void setCommitPage(bool commitPage);
+ bool isCommitPage() const;
+ void setButtonText(QWizard::WizardButton which, const QString &text);
+ QString buttonText(QWizard::WizardButton which) const;
+
+ virtual void initializePage();
+ virtual void cleanupPage();
+ virtual bool validatePage();
+ virtual bool isComplete() const;
+ virtual int nextId() const;
+
+Q_SIGNALS:
+ void completeChanged();
+
+protected:
+ void setField(const QString &name, const QVariant &value);
+ QVariant field(const QString &name) const;
+ void registerField(const QString &name, QWidget *widget, const char *property = 0,
+ const char *changedSignal = 0);
+ QWizard *wizard() const;
+
+private:
+ Q_DISABLE_COPY(QWizardPage)
+ Q_DECLARE_PRIVATE(QWizardPage)
+ Q_PRIVATE_SLOT(d_func(), void _q_maybeEmitCompleteChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateCachedCompleteState())
+
+ friend class QWizard;
+ friend class QWizardPrivate;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_WIZARD
+
+#endif // QWIZARD_H
diff --git a/src/widgets/dialogs/qwizard_win.cpp b/src/widgets/dialogs/qwizard_win.cpp
new file mode 100644
index 0000000000..6177700d8c
--- /dev/null
+++ b/src/widgets/dialogs/qwizard_win.cpp
@@ -0,0 +1,773 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_WIZARD
+#ifndef QT_NO_STYLE_WINDOWSVISTA
+
+#include "qwizard_win_p.h"
+#include <private/qsystemlibrary_p.h>
+#include <private/qapplication_p.h>
+#include "qplatformnativeinterface_qpa.h"
+#include "qwizard.h"
+#include "qpaintengine.h"
+#include "qapplication.h"
+#include <QtGui/QMouseEvent>
+#include <QtWidgets/QDesktopWidget>
+
+// Note, these tests are duplicates in qwindowsxpstyle_p.h.
+#ifdef Q_CC_GNU
+# include <w32api.h>
+# if (__W32API_MAJOR_VERSION >= 3 || (__W32API_MAJOR_VERSION == 2 && __W32API_MINOR_VERSION >= 5))
+# ifdef _WIN32_WINNT
+# undef _WIN32_WINNT
+# endif
+# define _WIN32_WINNT 0x0501
+# include <commctrl.h>
+# endif
+#endif
+
+#include <uxtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+//DWM related
+typedef struct { //MARGINS
+ int cxLeftWidth; // width of left border that retains its size
+ int cxRightWidth; // width of right border that retains its size
+ int cyTopHeight; // height of top border that retains its size
+ int cyBottomHeight; // height of bottom border that retains its size
+} WIZ_MARGINS;
+typedef struct { //DTTOPTS
+ DWORD dwSize;
+ DWORD dwFlags;
+ COLORREF crText;
+ COLORREF crBorder;
+ COLORREF crShadow;
+ int eTextShadowType;
+ POINT ptShadowOffset;
+ int iBorderSize;
+ int iFontPropId;
+ int iColorPropId;
+ int iStateId;
+ BOOL fApplyOverlay;
+ int iGlowSize;
+} WIZ_DTTOPTS;
+
+typedef struct {
+ DWORD dwFlags;
+ DWORD dwMask;
+} WIZ_WTA_OPTIONS;
+
+#define WIZ_WM_THEMECHANGED 0x031A
+#define WIZ_WM_DWMCOMPOSITIONCHANGED 0x031E
+
+enum WIZ_WINDOWTHEMEATTRIBUTETYPE {
+ WIZ_WTA_NONCLIENT = 1
+};
+
+#define WIZ_WTNCA_NODRAWCAPTION 0x00000001
+#define WIZ_WTNCA_NODRAWICON 0x00000002
+
+#define WIZ_DT_CENTER 0x00000001 //DT_CENTER
+#define WIZ_DT_VCENTER 0x00000004
+#define WIZ_DT_SINGLELINE 0x00000020
+#define WIZ_DT_NOPREFIX 0x00000800
+
+enum WIZ_NAVIGATIONPARTS { //NAVIGATIONPARTS
+ WIZ_NAV_BACKBUTTON = 1,
+ WIZ_NAV_FORWARDBUTTON = 2,
+ WIZ_NAV_MENUBUTTON = 3,
+};
+
+enum WIZ_NAV_BACKBUTTONSTATES { //NAV_BACKBUTTONSTATES
+ WIZ_NAV_BB_NORMAL = 1,
+ WIZ_NAV_BB_HOT = 2,
+ WIZ_NAV_BB_PRESSED = 3,
+ WIZ_NAV_BB_DISABLED = 4,
+};
+
+#define WIZ_TMT_CAPTIONFONT (801) //TMT_CAPTIONFONT
+#define WIZ_DTT_COMPOSITED (1UL << 13) //DTT_COMPOSITED
+#define WIZ_DTT_GLOWSIZE (1UL << 11) //DTT_GLOWSIZE
+
+#define WIZ_WM_NCMOUSELEAVE 674 //WM_NCMOUSELEAVE
+
+#define WIZ_WP_CAPTION 1 //WP_CAPTION
+#define WIZ_CS_ACTIVE 1 //CS_ACTIVE
+#define WIZ_TMT_FILLCOLORHINT 3821 //TMT_FILLCOLORHINT
+#define WIZ_TMT_BORDERCOLORHINT 3822 //TMT_BORDERCOLORHINT
+
+typedef BOOL (WINAPI *PtrDwmDefWindowProc)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *plResult);
+typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL* pfEnabled);
+typedef HRESULT (WINAPI *PtrDwmExtendFrameIntoClientArea)(HWND hWnd, const WIZ_MARGINS* pMarInset);
+typedef HRESULT (WINAPI *PtrSetWindowThemeAttribute)(HWND hwnd, enum WIZ_WINDOWTHEMEATTRIBUTETYPE eAttribute, PVOID pvAttribute, DWORD cbAttribute);
+
+static PtrDwmDefWindowProc pDwmDefWindowProc = 0;
+static PtrDwmIsCompositionEnabled pDwmIsCompositionEnabled = 0;
+static PtrDwmExtendFrameIntoClientArea pDwmExtendFrameIntoClientArea = 0;
+static PtrSetWindowThemeAttribute pSetWindowThemeAttribute = 0;
+
+//Theme related
+typedef bool (WINAPI *PtrIsAppThemed)();
+typedef bool (WINAPI *PtrIsThemeActive)();
+typedef HANDLE (WINAPI *PtrOpenThemeData)(HWND hwnd, LPCWSTR pszClassList);
+typedef HRESULT (WINAPI *PtrCloseThemeData)(HANDLE hTheme);
+typedef HRESULT (WINAPI *PtrGetThemeSysFont)(HANDLE hTheme, int iFontId, LOGFONTW *plf);
+typedef HRESULT (WINAPI *PtrDrawThemeTextEx)(HANDLE hTheme, HDC hdc, int iPartId, int iStateId, LPCWSTR pszText, int cchText, DWORD dwTextFlags, LPRECT pRect, const WIZ_DTTOPTS *pOptions);
+typedef HRESULT (WINAPI *PtrDrawThemeBackground)(HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT *pRect, OPTIONAL const RECT *pClipRect);
+typedef HRESULT (WINAPI *PtrGetThemePartSize)(HANDLE hTheme, HDC hdc, int iPartId, int iStateId, OPTIONAL RECT *prc, enum THEMESIZE eSize, OUT SIZE *psz);
+typedef HRESULT (WINAPI *PtrGetThemeColor)(HANDLE hTheme, int iPartId, int iStateId, int iPropId, OUT COLORREF *pColor);
+
+static PtrIsAppThemed pIsAppThemed = 0;
+static PtrIsThemeActive pIsThemeActive = 0;
+static PtrOpenThemeData pOpenThemeData = 0;
+static PtrCloseThemeData pCloseThemeData = 0;
+static PtrGetThemeSysFont pGetThemeSysFont = 0;
+static PtrDrawThemeTextEx pDrawThemeTextEx = 0;
+static PtrDrawThemeBackground pDrawThemeBackground = 0;
+static PtrGetThemePartSize pGetThemePartSize = 0;
+static PtrGetThemeColor pGetThemeColor = 0;
+
+bool QVistaHelper::is_vista = false;
+QVistaHelper::VistaState QVistaHelper::cachedVistaState = QVistaHelper::Dirty;
+
+/******************************************************************************
+** QVistaBackButton
+*/
+
+QVistaBackButton::QVistaBackButton(QWidget *widget)
+ : QAbstractButton(widget)
+{
+ setFocusPolicy(Qt::NoFocus);
+}
+
+QSize QVistaBackButton::sizeHint() const
+{
+ ensurePolished();
+ int size = int(QStyleHelper::dpiScaled(32));
+ int width = size, height = size;
+/*
+ HANDLE theme = pOpenThemeData(0, L"Navigation");
+ SIZE size;
+ if (pGetThemePartSize(theme, 0, WIZ_NAV_BACKBUTTON, WIZ_NAV_BB_NORMAL, 0, TS_TRUE, &size) == S_OK) {
+ width = size.cx;
+ height = size.cy;
+ }
+*/
+ return QSize(width, height);
+}
+
+void QVistaBackButton::enterEvent(QEvent *event)
+{
+ if (isEnabled())
+ update();
+ QAbstractButton::enterEvent(event);
+}
+
+void QVistaBackButton::leaveEvent(QEvent *event)
+{
+ if (isEnabled())
+ update();
+ QAbstractButton::leaveEvent(event);
+}
+
+void QVistaBackButton::paintEvent(QPaintEvent *)
+{
+ QPainter p(this);
+ QRect r = rect();
+ HANDLE theme = pOpenThemeData(0, L"Navigation");
+ //RECT rect;
+ RECT clipRect;
+ int xoffset = QWidget::mapToParent(r.topLeft()).x() - 1;
+ int yoffset = QWidget::mapToParent(r.topLeft()).y() - 1;
+
+ clipRect.top = r.top() + yoffset;
+ clipRect.bottom = r.bottom() + yoffset;
+ clipRect.left = r.left() + xoffset;
+ clipRect.right = r.right() + xoffset;
+
+ int state = WIZ_NAV_BB_NORMAL;
+ if (!isEnabled())
+ state = WIZ_NAV_BB_DISABLED;
+ else if (isDown())
+ state = WIZ_NAV_BB_PRESSED;
+ else if (underMouse())
+ state = WIZ_NAV_BB_HOT;
+
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ HDC hdc = static_cast<HDC>(nativeInterface->nativeResourceForBackingStore("getDC", backingStore()));
+ pDrawThemeBackground(theme, hdc, WIZ_NAV_BACKBUTTON, state, &clipRect, &clipRect);
+}
+
+/******************************************************************************
+** QVistaHelper
+*/
+
+QVistaHelper::QVistaHelper(QWizard *wizard)
+ : QObject(wizard)
+ , pressed(false)
+ , wizard(wizard)
+ , backButton_(0)
+{
+ is_vista = resolveSymbols();
+ if (is_vista)
+ backButton_ = new QVistaBackButton(wizard);
+
+ // Handle diff between Windows 7 and Vista
+ iconSpacing = QStyleHelper::dpiScaled(7);
+ textSpacing = QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7 ?
+ iconSpacing : QStyleHelper::dpiScaled(20);
+}
+
+QVistaHelper::~QVistaHelper()
+{
+}
+
+bool QVistaHelper::isCompositionEnabled()
+{
+ bool value = is_vista;
+ if (is_vista) {
+ HRESULT hr;
+ BOOL bEnabled;
+
+ hr = pDwmIsCompositionEnabled(&bEnabled);
+ value = (SUCCEEDED(hr) && bEnabled);
+ }
+ return value;
+}
+
+bool QVistaHelper::isThemeActive()
+{
+ return is_vista && pIsThemeActive();
+}
+
+QVistaHelper::VistaState QVistaHelper::vistaState()
+{
+ if (cachedVistaState == Dirty)
+ cachedVistaState =
+ isCompositionEnabled() ? VistaAero : isThemeActive() ? VistaBasic : Classic;
+ return cachedVistaState;
+}
+
+QColor QVistaHelper::basicWindowFrameColor()
+{
+ DWORD rgb;
+ HWND handle = QApplicationPrivate::getHWNDForWidget(QApplication::desktop());
+ HANDLE hTheme = pOpenThemeData(handle, L"WINDOW");
+ pGetThemeColor(
+ hTheme, WIZ_WP_CAPTION, WIZ_CS_ACTIVE,
+ wizard->isActiveWindow() ? WIZ_TMT_FILLCOLORHINT : WIZ_TMT_BORDERCOLORHINT,
+ &rgb);
+ BYTE r = GetRValue(rgb);
+ BYTE g = GetGValue(rgb);
+ BYTE b = GetBValue(rgb);
+ return QColor(r, g, b);
+}
+
+bool QVistaHelper::setDWMTitleBar(TitleBarChangeType type)
+{
+ bool value = false;
+ if (vistaState() == VistaAero) {
+ WIZ_MARGINS mar = {0};
+ if (type == NormalTitleBar)
+ mar.cyTopHeight = 0;
+ else
+ mar.cyTopHeight = titleBarSize() + topOffset();
+ HWND wizardHandle = QApplicationPrivate::getHWNDForWidget(wizard);
+ HRESULT hr = pDwmExtendFrameIntoClientArea(wizardHandle, &mar);
+ value = SUCCEEDED(hr);
+ }
+ return value;
+}
+
+void QVistaHelper::drawTitleBar(QPainter *painter)
+{
+ Q_ASSERT(backButton_);
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ QBackingStore *backingStore = backButton_->backingStore();
+ HDC hdc = static_cast<HDC>(nativeInterface->nativeResourceForBackingStore("getDC", backingStore));
+
+ if (vistaState() == VistaAero)
+ drawBlackRect(QRect(0, 0, wizard->width(),
+ titleBarSize() + topOffset()), hdc);
+ const int btnTop = backButton_->mapToParent(QPoint()).y();
+ const int btnHeight = backButton_->size().height();
+ const int verticalCenter = (btnTop + btnHeight / 2) - 1;
+
+ const QString text = wizard->window()->windowTitle();
+ const QFont font = QApplication::font("QWorkspaceTitleBar");
+ const QFontMetrics fontMetrics(font);
+ const QRect brect = fontMetrics.boundingRect(text);
+ int textHeight = brect.height();
+ int textWidth = brect.width();
+ int glowOffset = 0;
+
+ if (vistaState() == VistaAero) {
+ textHeight += 2 * glowSize();
+ textWidth += 2 * glowSize();
+ glowOffset = glowSize();
+ }
+
+ drawTitleText(
+ painter, text,
+ QRect(titleOffset() - glowOffset, verticalCenter - textHeight / 2, textWidth, textHeight),
+ hdc);
+
+ if (!wizard->windowIcon().isNull()) {
+ QRect rect(leftMargin(), verticalCenter - iconSize() / 2, iconSize(), iconSize());
+ HICON hIcon = 0; //###FIXME wizard->windowIcon().pixmap(iconSize()).toWinHICON();
+ DrawIconEx(hdc, rect.left(), rect.top(), hIcon, 0, 0, 0, NULL, DI_NORMAL | DI_COMPAT);
+ DestroyIcon(hIcon);
+ }
+}
+
+void QVistaHelper::setTitleBarIconAndCaptionVisible(bool visible)
+{
+ if (is_vista) {
+ WIZ_WTA_OPTIONS opt;
+ opt.dwFlags = WIZ_WTNCA_NODRAWICON | WIZ_WTNCA_NODRAWCAPTION;
+ if (visible)
+ opt.dwMask = 0;
+ else
+ opt.dwMask = WIZ_WTNCA_NODRAWICON | WIZ_WTNCA_NODRAWCAPTION;
+ HWND handle = QApplicationPrivate::getHWNDForWidget(wizard);
+ pSetWindowThemeAttribute(handle, WIZ_WTA_NONCLIENT, &opt, sizeof(WIZ_WTA_OPTIONS));
+ }
+}
+
+bool QVistaHelper::winEvent(MSG* msg, long* result)
+{
+ bool retval = true;
+
+ switch (msg->message) {
+ case WM_NCHITTEST: {
+ LRESULT lResult;
+ pDwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lResult);
+ if (lResult == HTCLOSE || lResult == HTMAXBUTTON || lResult == HTMINBUTTON || lResult == HTHELP)
+ *result = lResult;
+ else
+ *result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
+ break;
+ }
+ case WM_NCMOUSEMOVE:
+ case WM_NCLBUTTONDOWN:
+ case WM_NCLBUTTONUP:
+ case WIZ_WM_NCMOUSELEAVE: {
+ LRESULT lResult;
+ pDwmDefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam, &lResult);
+ *result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
+ break;
+ }
+ case WM_NCCALCSIZE: {
+ NCCALCSIZE_PARAMS* lpncsp = (NCCALCSIZE_PARAMS*)msg->lParam;
+ *result = DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
+ lpncsp->rgrc[0].top -= (vistaState() == VistaAero ? titleBarSize() : 0);
+ break;
+ }
+ default:
+ retval = false;
+ }
+
+ return retval;
+}
+
+void QVistaHelper::setMouseCursor(QPoint pos)
+{
+#ifndef QT_NO_CURSOR
+ if (rtTop.contains(pos))
+ wizard->setCursor(Qt::SizeVerCursor);
+ else
+ wizard->setCursor(Qt::ArrowCursor);
+#endif
+}
+
+void QVistaHelper::mouseEvent(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::MouseMove:
+ mouseMoveEvent(static_cast<QMouseEvent *>(event));
+ break;
+ case QEvent::MouseButtonPress:
+ mousePressEvent(static_cast<QMouseEvent *>(event));
+ break;
+ case QEvent::MouseButtonRelease:
+ mouseReleaseEvent(static_cast<QMouseEvent *>(event));
+ break;
+ default:
+ break;
+ }
+}
+
+// The following hack ensures that the titlebar is updated correctly
+// when the wizard style changes to and from AeroStyle. Specifically,
+// this function causes a Windows message of type WM_NCCALCSIZE to
+// be triggered.
+void QVistaHelper::setWindowPosHack()
+{
+ const int x = wizard->geometry().x(); // ignored by SWP_NOMOVE
+ const int y = wizard->geometry().y(); // ignored by SWP_NOMOVE
+ const int w = wizard->width();
+ const int h = wizard->height();
+ HWND handle = QApplicationPrivate::getHWNDForWidget(wizard);
+ SetWindowPos(handle, 0, x, y, w, h, SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
+}
+
+// The following hack allows any QWidget subclass to access
+// QWidgetPrivate::topData() without being declared as a
+// friend by QWidget.
+class QHackWidget : public QWidget
+{
+public:
+ Q_DECLARE_PRIVATE(QWidget)
+ QTLWExtra* topData() { return d_func()->topData(); }
+};
+
+void QVistaHelper::collapseTopFrameStrut()
+{
+ QTLWExtra *top = ((QHackWidget *)wizard)->d_func()->topData();
+ int x1, y1, x2, y2;
+ top->frameStrut.getCoords(&x1, &y1, &x2, &y2);
+ top->frameStrut.setCoords(x1, 0, x2, y2);
+}
+
+bool QVistaHelper::handleWinEvent(MSG *message, long *result)
+{
+ if (message->message == WIZ_WM_THEMECHANGED || message->message == WIZ_WM_DWMCOMPOSITIONCHANGED)
+ cachedVistaState = Dirty;
+
+ bool status = false;
+ if (wizard->wizardStyle() == QWizard::AeroStyle && vistaState() == VistaAero) {
+ status = winEvent(message, result);
+ if (message->message == WM_NCCALCSIZE) {
+ if (status)
+ collapseTopFrameStrut();
+ } else if (message->message == WM_NCPAINT) {
+ wizard->update();
+ }
+ }
+ return status;
+}
+
+void QVistaHelper::resizeEvent(QResizeEvent * event)
+{
+ Q_UNUSED(event);
+ rtTop = QRect (0, 0, wizard->width(), frameSize());
+ int height = captionSize() + topOffset();
+ if (vistaState() == VistaBasic)
+ height -= titleBarSize();
+ rtTitle = QRect (0, frameSize(), wizard->width(), height);
+}
+
+void QVistaHelper::paintEvent(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter painter(wizard);
+ drawTitleBar(&painter);
+}
+
+void QVistaHelper::mouseMoveEvent(QMouseEvent *event)
+{
+ if (wizard->windowState() & Qt::WindowMaximized) {
+ event->ignore();
+ return;
+ }
+
+ QRect rect = wizard->geometry();
+ if (pressed) {
+ switch (change) {
+ case resizeTop:
+ {
+ const int dy = event->pos().y() - pressedPos.y();
+ if ((dy > 0 && rect.height() > wizard->minimumHeight())
+ || (dy < 0 && rect.height() < wizard->maximumHeight()))
+ rect.setTop(rect.top() + dy);
+ }
+ break;
+ case movePosition: {
+ QPoint newPos = event->pos() - pressedPos;
+ rect.moveLeft(rect.left() + newPos.x());
+ rect.moveTop(rect.top() + newPos.y());
+ break; }
+ default:
+ break;
+ }
+ wizard->setGeometry(rect);
+
+ } else if (vistaState() == VistaAero) {
+ setMouseCursor(event->pos());
+ }
+ event->ignore();
+}
+
+void QVistaHelper::mousePressEvent(QMouseEvent *event)
+{
+ change = noChange;
+
+ if (wizard->windowState() & Qt::WindowMaximized) {
+ event->ignore();
+ return;
+ }
+
+ if (rtTitle.contains(event->pos())) {
+ change = movePosition;
+ } else if (rtTop.contains(event->pos()))
+ change = (vistaState() == VistaAero) ? resizeTop : movePosition;
+
+ if (change != noChange) {
+ if (vistaState() == VistaAero)
+ setMouseCursor(event->pos());
+ pressed = true;
+ pressedPos = event->pos();
+ } else {
+ event->ignore();
+ }
+}
+
+void QVistaHelper::mouseReleaseEvent(QMouseEvent *event)
+{
+ change = noChange;
+ if (pressed) {
+ pressed = false;
+ wizard->releaseMouse();
+ if (vistaState() == VistaAero)
+ setMouseCursor(event->pos());
+ }
+ event->ignore();
+}
+
+bool QVistaHelper::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj != wizard)
+ return QObject::eventFilter(obj, event);
+
+ if (event->type() == QEvent::MouseMove) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ long result;
+ MSG msg;
+ msg.message = WM_NCHITTEST;
+ msg.wParam = 0;
+ msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
+ HWND handle = QApplicationPrivate::getHWNDForWidget(wizard);
+ msg.hwnd = handle;
+ winEvent(&msg, &result);
+ msg.wParam = result;
+ msg.message = WM_NCMOUSEMOVE;
+ winEvent(&msg, &result);
+ } else if (event->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ long result;
+ MSG msg;
+ msg.message = WM_NCHITTEST;
+ msg.wParam = 0;
+ msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
+ HWND handle = QApplicationPrivate::getHWNDForWidget(wizard);
+ msg.hwnd = handle;
+ winEvent(&msg, &result);
+ msg.wParam = result;
+ msg.message = WM_NCLBUTTONDOWN;
+ winEvent(&msg, &result);
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
+ long result;
+ MSG msg;
+ msg.message = WM_NCHITTEST;
+ msg.wParam = 0;
+ msg.lParam = MAKELPARAM(mouseEvent->globalX(), mouseEvent->globalY());
+ HWND handle = QApplicationPrivate::getHWNDForWidget(wizard);
+ msg.hwnd = handle;
+ winEvent(&msg, &result);
+ msg.wParam = result;
+ msg.message = WM_NCLBUTTONUP;
+ winEvent(&msg, &result);
+ }
+
+ return false;
+}
+
+HFONT QVistaHelper::getCaptionFont(HANDLE hTheme)
+{
+ LOGFONT lf = {0};
+
+ if (!hTheme)
+ pGetThemeSysFont(hTheme, WIZ_TMT_CAPTIONFONT, &lf);
+ else
+ {
+ NONCLIENTMETRICS ncm = {sizeof(NONCLIENTMETRICS)};
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, false);
+ lf = ncm.lfMessageFont;
+ }
+ return CreateFontIndirect(&lf);
+}
+
+bool QVistaHelper::drawTitleText(QPainter *painter, const QString &text, const QRect &rect, HDC hdc)
+{
+ bool value = false;
+ if (vistaState() == VistaAero) {
+ HWND handle = QApplicationPrivate::getHWNDForWidget(QApplication::desktop());
+ HANDLE hTheme = pOpenThemeData(handle, L"WINDOW");
+ if (!hTheme) return false;
+ // Set up a memory DC and bitmap that we'll draw into
+ HDC dcMem;
+ HBITMAP bmp;
+ BITMAPINFO dib = {{0}};
+ dcMem = CreateCompatibleDC(hdc);
+
+ dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dib.bmiHeader.biWidth = rect.width();
+ dib.bmiHeader.biHeight = -rect.height();
+ dib.bmiHeader.biPlanes = 1;
+ dib.bmiHeader.biBitCount = 32;
+ dib.bmiHeader.biCompression = BI_RGB;
+
+ bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
+
+ // Set up the DC
+ HFONT hCaptionFont = getCaptionFont(hTheme);
+ HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp);
+ HFONT hOldFont = (HFONT)SelectObject(dcMem, (HGDIOBJ) hCaptionFont);
+
+ // Draw the text!
+ WIZ_DTTOPTS dto = { sizeof(WIZ_DTTOPTS) };
+ const UINT uFormat = WIZ_DT_SINGLELINE|WIZ_DT_CENTER|WIZ_DT_VCENTER|WIZ_DT_NOPREFIX;
+ RECT rctext ={0,0, rect.width(), rect.height()};
+
+ dto.dwFlags = WIZ_DTT_COMPOSITED|WIZ_DTT_GLOWSIZE;
+ dto.iGlowSize = glowSize();
+
+ pDrawThemeTextEx(hTheme, dcMem, 0, 0, (LPCWSTR)text.utf16(), -1, uFormat, &rctext, &dto );
+ BitBlt(hdc, rect.left(), rect.top(), rect.width(), rect.height(), dcMem, 0, 0, SRCCOPY);
+ SelectObject(dcMem, (HGDIOBJ) hOldBmp);
+ SelectObject(dcMem, (HGDIOBJ) hOldFont);
+ DeleteObject(bmp);
+ DeleteObject(hCaptionFont);
+ DeleteDC(dcMem);
+ //ReleaseDC(hwnd, hdc);
+ } else if (vistaState() == VistaBasic) {
+ painter->drawText(rect, text);
+ }
+ return value;
+}
+
+bool QVistaHelper::drawBlackRect(const QRect &rect, HDC hdc)
+{
+ bool value = false;
+ if (vistaState() == VistaAero) {
+ // Set up a memory DC and bitmap that we'll draw into
+ HDC dcMem;
+ HBITMAP bmp;
+ BITMAPINFO dib = {{0}};
+ dcMem = CreateCompatibleDC(hdc);
+
+ dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dib.bmiHeader.biWidth = rect.width();
+ dib.bmiHeader.biHeight = -rect.height();
+ dib.bmiHeader.biPlanes = 1;
+ dib.bmiHeader.biBitCount = 32;
+ dib.bmiHeader.biCompression = BI_RGB;
+
+ bmp = CreateDIBSection(hdc, &dib, DIB_RGB_COLORS, NULL, NULL, 0);
+ HBITMAP hOldBmp = (HBITMAP)SelectObject(dcMem, (HGDIOBJ) bmp);
+
+ BitBlt(hdc, rect.left(), rect.top(), rect.width(), rect.height(), dcMem, 0, 0, SRCCOPY);
+ SelectObject(dcMem, (HGDIOBJ) hOldBmp);
+
+ DeleteObject(bmp);
+ DeleteDC(dcMem);
+ }
+ return value;
+}
+
+bool QVistaHelper::resolveSymbols()
+{
+ static bool tried = false;
+ if (!tried) {
+ tried = true;
+ QSystemLibrary dwmLib(L"dwmapi");
+ pDwmIsCompositionEnabled =
+ (PtrDwmIsCompositionEnabled)dwmLib.resolve("DwmIsCompositionEnabled");
+ if (pDwmIsCompositionEnabled) {
+ pDwmDefWindowProc = (PtrDwmDefWindowProc)dwmLib.resolve("DwmDefWindowProc");
+ pDwmExtendFrameIntoClientArea =
+ (PtrDwmExtendFrameIntoClientArea)dwmLib.resolve("DwmExtendFrameIntoClientArea");
+ }
+ QSystemLibrary themeLib(L"uxtheme");
+ pIsAppThemed = (PtrIsAppThemed)themeLib.resolve("IsAppThemed");
+ if (pIsAppThemed) {
+ pDrawThemeBackground = (PtrDrawThemeBackground)themeLib.resolve("DrawThemeBackground");
+ pGetThemePartSize = (PtrGetThemePartSize)themeLib.resolve("GetThemePartSize");
+ pGetThemeColor = (PtrGetThemeColor)themeLib.resolve("GetThemeColor");
+ pIsThemeActive = (PtrIsThemeActive)themeLib.resolve("IsThemeActive");
+ pOpenThemeData = (PtrOpenThemeData)themeLib.resolve("OpenThemeData");
+ pCloseThemeData = (PtrCloseThemeData)themeLib.resolve("CloseThemeData");
+ pGetThemeSysFont = (PtrGetThemeSysFont)themeLib.resolve("GetThemeSysFont");
+ pDrawThemeTextEx = (PtrDrawThemeTextEx)themeLib.resolve("DrawThemeTextEx");
+ pSetWindowThemeAttribute = (PtrSetWindowThemeAttribute)themeLib.resolve("SetWindowThemeAttribute");
+ }
+ }
+
+ return (
+ pDwmIsCompositionEnabled != 0
+ && pDwmDefWindowProc != 0
+ && pDwmExtendFrameIntoClientArea != 0
+ && pIsAppThemed != 0
+ && pDrawThemeBackground != 0
+ && pGetThemePartSize != 0
+ && pGetThemeColor != 0
+ && pIsThemeActive != 0
+ && pOpenThemeData != 0
+ && pCloseThemeData != 0
+ && pGetThemeSysFont != 0
+ && pDrawThemeTextEx != 0
+ && pSetWindowThemeAttribute != 0
+ );
+}
+
+int QVistaHelper::titleOffset()
+{
+ int iconOffset = wizard ->windowIcon().isNull() ? 0 : iconSize() + textSpacing;
+ return leftMargin() + iconOffset;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_STYLE_WINDOWSVISTA
+
+#endif // QT_NO_WIZARD
diff --git a/src/widgets/dialogs/qwizard_win_p.h b/src/widgets/dialogs/qwizard_win_p.h
new file mode 100644
index 0000000000..f53a9ba75c
--- /dev/null
+++ b/src/widgets/dialogs/qwizard_win_p.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIZARD_WIN_P_H
+#define QWIZARD_WIN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_WIZARD
+#ifndef QT_NO_STYLE_WINDOWSVISTA
+
+#include <qt_windows.h>
+#include <qobject.h>
+#include <qwidget.h>
+#include <qabstractbutton.h>
+#include <QtWidgets/private/qwidget_p.h>
+#include <QtWidgets/private/qstylehelper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QVistaBackButton : public QAbstractButton
+{
+public:
+ QVistaBackButton(QWidget *widget);
+
+ QSize sizeHint() const;
+ inline QSize minimumSizeHint() const
+ { return sizeHint(); }
+
+ void enterEvent(QEvent *event);
+ void leaveEvent(QEvent *event);
+ void paintEvent(QPaintEvent *event);
+};
+
+class QWizard;
+
+class QVistaHelper : public QObject
+{
+public:
+ QVistaHelper(QWizard *wizard);
+ ~QVistaHelper();
+ enum TitleBarChangeType { NormalTitleBar, ExtendedTitleBar };
+ bool setDWMTitleBar(TitleBarChangeType type);
+ void setTitleBarIconAndCaptionVisible(bool visible);
+ void mouseEvent(QEvent *event);
+ bool handleWinEvent(MSG *message, long *result);
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+ QVistaBackButton *backButton() const { return backButton_; }
+ void disconnectBackButton() { if (backButton_) backButton_->disconnect(); }
+ void hideBackButton() { if (backButton_) backButton_->hide(); }
+ void setWindowPosHack();
+ QColor basicWindowFrameColor();
+ enum VistaState { VistaAero, VistaBasic, Classic, Dirty };
+ static VistaState vistaState();
+ static int titleBarSize() { return frameSize() + captionSize(); }
+ static int topPadding() { // padding under text
+ return int(QStyleHelper::dpiScaled(
+ QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7 ? 4 : 6));
+ }
+ static int topOffset() {
+ static int aeroOffset = QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7 ?
+ QStyleHelper::dpiScaled(4) : QStyleHelper::dpiScaled(13);
+ return (titleBarSize() + (vistaState() == VistaAero ? aeroOffset : 3)); }
+private:
+ static HFONT getCaptionFont(HANDLE hTheme);
+ bool drawTitleText(QPainter *painter, const QString &text, const QRect &rect, HDC hdc);
+ static bool drawBlackRect(const QRect &rect, HDC hdc);
+
+ static int frameSize() { return GetSystemMetrics(SM_CYSIZEFRAME); }
+ static int captionSize() { return GetSystemMetrics(SM_CYCAPTION); }
+
+ static int backButtonSize() { return int(QStyleHelper::dpiScaled(30)); }
+ static int iconSize() { return 16; } // Standard Aero
+ static int glowSize() { return 10; }
+ int leftMargin() { return backButton_->isVisible() ? backButtonSize() + iconSpacing : 0; }
+
+ int titleOffset();
+ bool resolveSymbols();
+ void drawTitleBar(QPainter *painter);
+ void setMouseCursor(QPoint pos);
+ void collapseTopFrameStrut();
+ bool winEvent(MSG *message, long *result);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ bool eventFilter(QObject *obj, QEvent *event);
+
+ static bool is_vista;
+ static VistaState cachedVistaState;
+ static bool isCompositionEnabled();
+ static bool isThemeActive();
+ enum Changes { resizeTop, movePosition, noChange } change;
+ QPoint pressedPos;
+ bool pressed;
+ QRect rtTop;
+ QRect rtTitle;
+ QWizard *wizard;
+ QVistaBackButton *backButton_;
+
+ int titleBarOffset; // Extra spacing above the text
+ int iconSpacing; // Space between button and icon
+ int textSpacing; // Space between icon and text
+};
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_STYLE_WINDOWSVISTA
+#endif // QT_NO_WIZARD
+#endif // QWIZARD_WIN_P_H