summaryrefslogtreecommitdiffstats
path: root/src/widgets/dialogs
diff options
context:
space:
mode:
Diffstat (limited to 'src/widgets/dialogs')
-rw-r--r--src/widgets/dialogs/dialogs.pri106
-rw-r--r--src/widgets/dialogs/images/fit-page-24.pngbin0 -> 985 bytes
-rw-r--r--src/widgets/dialogs/images/fit-page-32.pngbin0 -> 1330 bytes
-rw-r--r--src/widgets/dialogs/images/fit-width-24.pngbin0 -> 706 bytes
-rw-r--r--src/widgets/dialogs/images/fit-width-32.pngbin0 -> 1004 bytes
-rw-r--r--src/widgets/dialogs/images/go-first-24.pngbin0 -> 796 bytes
-rw-r--r--src/widgets/dialogs/images/go-first-32.pngbin0 -> 985 bytes
-rw-r--r--src/widgets/dialogs/images/go-last-24.pngbin0 -> 792 bytes
-rw-r--r--src/widgets/dialogs/images/go-last-32.pngbin0 -> 984 bytes
-rw-r--r--src/widgets/dialogs/images/go-next-24.pngbin0 -> 782 bytes
-rw-r--r--src/widgets/dialogs/images/go-next-32.pngbin0 -> 948 bytes
-rw-r--r--src/widgets/dialogs/images/go-previous-24.pngbin0 -> 797 bytes
-rw-r--r--src/widgets/dialogs/images/go-previous-32.pngbin0 -> 945 bytes
-rw-r--r--src/widgets/dialogs/images/layout-landscape-24.pngbin0 -> 820 bytes
-rw-r--r--src/widgets/dialogs/images/layout-landscape-32.pngbin0 -> 1353 bytes
-rw-r--r--src/widgets/dialogs/images/layout-portrait-24.pngbin0 -> 817 bytes
-rw-r--r--src/widgets/dialogs/images/layout-portrait-32.pngbin0 -> 1330 bytes
-rw-r--r--src/widgets/dialogs/images/page-setup-24.pngbin0 -> 620 bytes
-rw-r--r--src/widgets/dialogs/images/page-setup-32.pngbin0 -> 1154 bytes
-rw-r--r--src/widgets/dialogs/images/print-24.pngbin0 -> 914 bytes
-rw-r--r--src/widgets/dialogs/images/print-32.pngbin0 -> 1202 bytes
-rw-r--r--src/widgets/dialogs/images/qtlogo-64.pngbin0 -> 2991 bytes
-rw-r--r--src/widgets/dialogs/images/status-color.pngbin0 -> 1475 bytes
-rw-r--r--src/widgets/dialogs/images/status-gray-scale.pngbin0 -> 1254 bytes
-rw-r--r--src/widgets/dialogs/images/view-page-multi-24.pngbin0 -> 390 bytes
-rw-r--r--src/widgets/dialogs/images/view-page-multi-32.pngbin0 -> 556 bytes
-rw-r--r--src/widgets/dialogs/images/view-page-one-24.pngbin0 -> 662 bytes
-rw-r--r--src/widgets/dialogs/images/view-page-one-32.pngbin0 -> 810 bytes
-rw-r--r--src/widgets/dialogs/images/view-page-sided-24.pngbin0 -> 700 bytes
-rw-r--r--src/widgets/dialogs/images/view-page-sided-32.pngbin0 -> 908 bytes
-rw-r--r--src/widgets/dialogs/images/zoom-in-24.pngbin0 -> 1302 bytes
-rw-r--r--src/widgets/dialogs/images/zoom-in-32.pngbin0 -> 1873 bytes
-rw-r--r--src/widgets/dialogs/images/zoom-out-24.pngbin0 -> 1247 bytes
-rw-r--r--src/widgets/dialogs/images/zoom-out-32.pngbin0 -> 1749 bytes
-rw-r--r--src/widgets/dialogs/qabstractpagesetupdialog.cpp139
-rw-r--r--src/widgets/dialogs/qabstractpagesetupdialog.h82
-rw-r--r--src/widgets/dialogs/qabstractpagesetupdialog_p.h88
-rw-r--r--src/widgets/dialogs/qabstractprintdialog.cpp499
-rw-r--r--src/widgets/dialogs/qabstractprintdialog.h130
-rw-r--r--src/widgets/dialogs/qabstractprintdialog_p.h99
-rw-r--r--src/widgets/dialogs/qcolordialog.cpp2115
-rw-r--r--src/widgets/dialogs/qcolordialog.h150
-rw-r--r--src/widgets/dialogs/qcolordialog_mac.mm500
-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.cpp3486
-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.cpp825
-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.cpp2027
-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.cpp2751
-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/qpagesetupdialog.cpp240
-rw-r--r--src/widgets/dialogs/qpagesetupdialog.h112
-rw-r--r--src/widgets/dialogs/qpagesetupdialog_mac.mm315
-rw-r--r--src/widgets/dialogs/qpagesetupdialog_unix.cpp620
-rw-r--r--src/widgets/dialogs/qpagesetupdialog_unix_p.h105
-rw-r--r--src/widgets/dialogs/qpagesetupdialog_win.cpp168
-rw-r--r--src/widgets/dialogs/qpagesetupwidget.ui353
-rw-r--r--src/widgets/dialogs/qprintdialog.h174
-rw-r--r--src/widgets/dialogs/qprintdialog.qdoc58
-rw-r--r--src/widgets/dialogs/qprintdialog.qrc38
-rw-r--r--src/widgets/dialogs/qprintdialog_mac.mm429
-rw-r--r--src/widgets/dialogs/qprintdialog_unix.cpp1286
-rw-r--r--src/widgets/dialogs/qprintdialog_win.cpp316
-rw-r--r--src/widgets/dialogs/qprintpreviewdialog.cpp803
-rw-r--r--src/widgets/dialogs/qprintpreviewdialog.h107
-rw-r--r--src/widgets/dialogs/qprintpropertieswidget.ui70
-rw-r--r--src/widgets/dialogs/qprintsettingsoutput.ui363
-rw-r--r--src/widgets/dialogs/qprintwidget.ui116
-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.cpp759
-rw-r--r--src/widgets/dialogs/qwizard_win_p.h158
102 files changed, 36576 insertions, 0 deletions
diff --git a/src/widgets/dialogs/dialogs.pri b/src/widgets/dialogs/dialogs.pri
new file mode 100644
index 0000000000..472787a20c
--- /dev/null
+++ b/src/widgets/dialogs/dialogs.pri
@@ -0,0 +1,106 @@
+# Qt dialogs module
+
+HEADERS += \
+ dialogs/qabstractprintdialog.h \
+ dialogs/qabstractprintdialog_p.h \
+ dialogs/qabstractpagesetupdialog.h \
+ dialogs/qabstractpagesetupdialog_p.h \
+ 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/qpagesetupdialog.h \
+ dialogs/qprintdialog.h \
+ dialogs/qprogressdialog.h \
+ dialogs/qsidebar_p.h \
+ dialogs/qfilesystemmodel.h \
+ dialogs/qfilesystemmodel_p.h \
+ dialogs/qfileinfogatherer_p.h \
+ dialogs/qwizard.h \
+ dialogs/qprintpreviewdialog.h
+
+!qpa:mac {
+ OBJECTIVE_SOURCES += dialogs/qfiledialog_mac.mm \
+ dialogs/qfontdialog_mac.mm \
+ dialogs/qnspanelproxy_mac.mm \
+ dialogs/qpagesetupdialog_mac.mm \
+ dialogs/qprintdialog_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 {
+ HEADERS += dialogs/qwizard_win_p.h \
+ dialogs/qfiledialog_win_p.h
+ SOURCES += dialogs/qdialogsbinarycompat_win.cpp \
+ dialogs/qfiledialog_win.cpp \
+ dialogs/qpagesetupdialog_win.cpp \
+ dialogs/qprintdialog_win.cpp \
+ dialogs/qwizard_win.cpp
+
+ !win32-borland:!wince*: LIBS += -lshell32 # the filedialog needs this library
+}
+
+!mac:!symbian:unix|qpa {
+ HEADERS += dialogs/qpagesetupdialog_unix_p.h
+ SOURCES += dialogs/qprintdialog_unix.cpp \
+ dialogs/qpagesetupdialog_unix.cpp
+ FORMS += dialogs/qprintsettingsoutput.ui \
+ dialogs/qprintwidget.ui \
+ dialogs/qprintpropertieswidget.ui
+}
+
+wince*|symbian: FORMS += dialogs/qfiledialog_embedded.ui
+else: FORMS += dialogs/qfiledialog.ui
+
+INCLUDEPATH += $$PWD
+SOURCES += \
+ dialogs/qabstractprintdialog.cpp \
+ dialogs/qabstractpagesetupdialog.cpp \
+ 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/qpagesetupdialog.cpp \
+ dialogs/qwizard.cpp \
+ dialogs/qprintpreviewdialog.cpp
+
+symbian:contains(QT_CONFIG, s60) {
+ LIBS += -lCommonDialogs
+ SOURCES += dialogs/qfiledialog_symbian.cpp \
+ dialogs/qcolordialog_symbian.cpp
+}
+
+FORMS += dialogs/qpagesetupwidget.ui
+RESOURCES += dialogs/qprintdialog.qrc
+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/fit-page-24.png b/src/widgets/dialogs/images/fit-page-24.png
new file mode 100644
index 0000000000..c7b39d8853
--- /dev/null
+++ b/src/widgets/dialogs/images/fit-page-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/fit-page-32.png b/src/widgets/dialogs/images/fit-page-32.png
new file mode 100644
index 0000000000..98bc12d3ed
--- /dev/null
+++ b/src/widgets/dialogs/images/fit-page-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/fit-width-24.png b/src/widgets/dialogs/images/fit-width-24.png
new file mode 100644
index 0000000000..a729ffda54
--- /dev/null
+++ b/src/widgets/dialogs/images/fit-width-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/fit-width-32.png b/src/widgets/dialogs/images/fit-width-32.png
new file mode 100644
index 0000000000..470a8b45d0
--- /dev/null
+++ b/src/widgets/dialogs/images/fit-width-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-first-24.png b/src/widgets/dialogs/images/go-first-24.png
new file mode 100644
index 0000000000..55315ffa38
--- /dev/null
+++ b/src/widgets/dialogs/images/go-first-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-first-32.png b/src/widgets/dialogs/images/go-first-32.png
new file mode 100644
index 0000000000..0fe6f94b77
--- /dev/null
+++ b/src/widgets/dialogs/images/go-first-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-last-24.png b/src/widgets/dialogs/images/go-last-24.png
new file mode 100644
index 0000000000..81061b80f2
--- /dev/null
+++ b/src/widgets/dialogs/images/go-last-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-last-32.png b/src/widgets/dialogs/images/go-last-32.png
new file mode 100644
index 0000000000..887506107e
--- /dev/null
+++ b/src/widgets/dialogs/images/go-last-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-next-24.png b/src/widgets/dialogs/images/go-next-24.png
new file mode 100644
index 0000000000..9a55ef3d86
--- /dev/null
+++ b/src/widgets/dialogs/images/go-next-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-next-32.png b/src/widgets/dialogs/images/go-next-32.png
new file mode 100644
index 0000000000..6d98f50f4f
--- /dev/null
+++ b/src/widgets/dialogs/images/go-next-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-previous-24.png b/src/widgets/dialogs/images/go-previous-24.png
new file mode 100644
index 0000000000..2ea769eb8d
--- /dev/null
+++ b/src/widgets/dialogs/images/go-previous-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/go-previous-32.png b/src/widgets/dialogs/images/go-previous-32.png
new file mode 100644
index 0000000000..37ba0c4e8d
--- /dev/null
+++ b/src/widgets/dialogs/images/go-previous-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/layout-landscape-24.png b/src/widgets/dialogs/images/layout-landscape-24.png
new file mode 100644
index 0000000000..6f89a31cb6
--- /dev/null
+++ b/src/widgets/dialogs/images/layout-landscape-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/layout-landscape-32.png b/src/widgets/dialogs/images/layout-landscape-32.png
new file mode 100644
index 0000000000..6a94946c36
--- /dev/null
+++ b/src/widgets/dialogs/images/layout-landscape-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/layout-portrait-24.png b/src/widgets/dialogs/images/layout-portrait-24.png
new file mode 100644
index 0000000000..e0dbabc83b
--- /dev/null
+++ b/src/widgets/dialogs/images/layout-portrait-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/layout-portrait-32.png b/src/widgets/dialogs/images/layout-portrait-32.png
new file mode 100644
index 0000000000..d17468c0a4
--- /dev/null
+++ b/src/widgets/dialogs/images/layout-portrait-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/page-setup-24.png b/src/widgets/dialogs/images/page-setup-24.png
new file mode 100644
index 0000000000..4bfafdace0
--- /dev/null
+++ b/src/widgets/dialogs/images/page-setup-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/page-setup-32.png b/src/widgets/dialogs/images/page-setup-32.png
new file mode 100644
index 0000000000..2313b8fe3b
--- /dev/null
+++ b/src/widgets/dialogs/images/page-setup-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/print-24.png b/src/widgets/dialogs/images/print-24.png
new file mode 100644
index 0000000000..c6bf3e8672
--- /dev/null
+++ b/src/widgets/dialogs/images/print-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/print-32.png b/src/widgets/dialogs/images/print-32.png
new file mode 100644
index 0000000000..5830888653
--- /dev/null
+++ b/src/widgets/dialogs/images/print-32.png
Binary files differ
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/images/status-color.png b/src/widgets/dialogs/images/status-color.png
new file mode 100644
index 0000000000..af3cbfa31c
--- /dev/null
+++ b/src/widgets/dialogs/images/status-color.png
Binary files differ
diff --git a/src/widgets/dialogs/images/status-gray-scale.png b/src/widgets/dialogs/images/status-gray-scale.png
new file mode 100644
index 0000000000..4462588809
--- /dev/null
+++ b/src/widgets/dialogs/images/status-gray-scale.png
Binary files differ
diff --git a/src/widgets/dialogs/images/view-page-multi-24.png b/src/widgets/dialogs/images/view-page-multi-24.png
new file mode 100644
index 0000000000..87241472ae
--- /dev/null
+++ b/src/widgets/dialogs/images/view-page-multi-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/view-page-multi-32.png b/src/widgets/dialogs/images/view-page-multi-32.png
new file mode 100644
index 0000000000..130885a041
--- /dev/null
+++ b/src/widgets/dialogs/images/view-page-multi-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/view-page-one-24.png b/src/widgets/dialogs/images/view-page-one-24.png
new file mode 100644
index 0000000000..4c6457b892
--- /dev/null
+++ b/src/widgets/dialogs/images/view-page-one-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/view-page-one-32.png b/src/widgets/dialogs/images/view-page-one-32.png
new file mode 100644
index 0000000000..537193984e
--- /dev/null
+++ b/src/widgets/dialogs/images/view-page-one-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/view-page-sided-24.png b/src/widgets/dialogs/images/view-page-sided-24.png
new file mode 100644
index 0000000000..2131305c41
--- /dev/null
+++ b/src/widgets/dialogs/images/view-page-sided-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/view-page-sided-32.png b/src/widgets/dialogs/images/view-page-sided-32.png
new file mode 100644
index 0000000000..e4d63f9992
--- /dev/null
+++ b/src/widgets/dialogs/images/view-page-sided-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/zoom-in-24.png b/src/widgets/dialogs/images/zoom-in-24.png
new file mode 100644
index 0000000000..d29b142b6c
--- /dev/null
+++ b/src/widgets/dialogs/images/zoom-in-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/zoom-in-32.png b/src/widgets/dialogs/images/zoom-in-32.png
new file mode 100644
index 0000000000..34d70af37b
--- /dev/null
+++ b/src/widgets/dialogs/images/zoom-in-32.png
Binary files differ
diff --git a/src/widgets/dialogs/images/zoom-out-24.png b/src/widgets/dialogs/images/zoom-out-24.png
new file mode 100644
index 0000000000..19703474f8
--- /dev/null
+++ b/src/widgets/dialogs/images/zoom-out-24.png
Binary files differ
diff --git a/src/widgets/dialogs/images/zoom-out-32.png b/src/widgets/dialogs/images/zoom-out-32.png
new file mode 100644
index 0000000000..b832206612
--- /dev/null
+++ b/src/widgets/dialogs/images/zoom-out-32.png
Binary files differ
diff --git a/src/widgets/dialogs/qabstractpagesetupdialog.cpp b/src/widgets/dialogs/qabstractpagesetupdialog.cpp
new file mode 100644
index 0000000000..080ddeaa85
--- /dev/null
+++ b/src/widgets/dialogs/qabstractpagesetupdialog.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractpagesetupdialog.h"
+#include "qabstractpagesetupdialog_p.h"
+
+#ifndef QT_NO_PRINTDIALOG
+
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qprinter.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+ \class QAbstractPageSetupDialog
+
+ \brief The QAbstractPageSetupDialog class provides a base for
+ implementations of page setup dialogs.
+*/
+
+/*!
+ Constructs the page setup dialog for the printer \a printer with
+ \a parent as parent widget.
+*/
+QAbstractPageSetupDialog::QAbstractPageSetupDialog(QPrinter *printer, QWidget *parent)
+ : QDialog(*(new QAbstractPageSetupDialogPrivate), parent)
+{
+ Q_D(QAbstractPageSetupDialog);
+ setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
+ d->setPrinter(printer);
+}
+
+/*!
+ \internal
+*/
+QAbstractPageSetupDialog::QAbstractPageSetupDialog(QAbstractPageSetupDialogPrivate &ptr,
+ QPrinter *printer, QWidget *parent)
+ : QDialog(ptr, parent)
+{
+ Q_D(QAbstractPageSetupDialog);
+ setWindowTitle(QCoreApplication::translate("QPrintPreviewDialog", "Page Setup"));
+ d->setPrinter(printer);
+}
+
+QAbstractPageSetupDialog::~QAbstractPageSetupDialog()
+{
+ Q_D(QAbstractPageSetupDialog);
+ if (d->opts & QPageSetupDialog::OwnsPrinter)
+ delete d->printer;
+}
+
+/*!
+ Returns the printer that this page setup dialog is operating on.
+*/
+QPrinter *QAbstractPageSetupDialog::printer()
+{
+ Q_D(QAbstractPageSetupDialog);
+ return d->printer;
+}
+
+void QAbstractPageSetupDialogPrivate::setPrinter(QPrinter *newPrinter)
+{
+ if (newPrinter) {
+ printer = newPrinter;
+ } else {
+ printer = new QPrinter;
+ opts |= QPageSetupDialog::OwnsPrinter;
+ }
+#ifndef Q_WS_X11
+ if (printer->outputFormat() != QPrinter::NativeFormat)
+ qWarning("QPageSetupDialog: Cannot be used on non-native printers");
+#endif
+}
+
+/*!
+ \fn int QAbstractPageSetupDialog::exec()
+
+ This virtual function is called to pop up the dialog. It must be
+ reimplemented in subclasses.
+*/
+
+/*!
+ \reimp
+*/
+void QAbstractPageSetupDialog::done(int result)
+{
+ Q_D(QAbstractPageSetupDialog);
+ QDialog::done(result);
+ if (d->receiverToDisconnectOnClose) {
+ disconnect(this, SIGNAL(accepted()),
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTDIALOG
diff --git a/src/widgets/dialogs/qabstractpagesetupdialog.h b/src/widgets/dialogs/qabstractpagesetupdialog.h
new file mode 100644
index 0000000000..ac3ffa5451
--- /dev/null
+++ b/src/widgets/dialogs/qabstractpagesetupdialog.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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTPAGESETUPDIALOG_H
+#define QABSTRACTPAGESETUPDIALOG_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_PRINTDIALOG
+
+class QAbstractPageSetupDialogPrivate;
+class QPrinter;
+
+// ### Qt 5: Remove this class
+class Q_GUI_EXPORT QAbstractPageSetupDialog : public QDialog
+{
+ Q_DECLARE_PRIVATE(QAbstractPageSetupDialog)
+ Q_OBJECT
+
+public:
+ explicit QAbstractPageSetupDialog(QPrinter *printer, QWidget *parent = 0);
+ QAbstractPageSetupDialog(QAbstractPageSetupDialogPrivate &ptr,
+ QPrinter *printer, QWidget *parent = 0);
+ ~QAbstractPageSetupDialog();
+
+ virtual int exec() = 0;
+ void done(int result);
+
+ QPrinter *printer();
+};
+
+#endif // QT_NO_PRINTDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTPAGESETUPDIALOG_H
diff --git a/src/widgets/dialogs/qabstractpagesetupdialog_p.h b/src/widgets/dialogs/qabstractpagesetupdialog_p.h
new file mode 100644
index 0000000000..3dbfdd5e26
--- /dev/null
+++ b/src/widgets/dialogs/qabstractpagesetupdialog_p.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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTPAGESETUPDIALOG_P_H
+#define QABSTRACTPAGESETUPDIALOG_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"
+
+#ifndef QT_NO_PRINTDIALOG
+
+#include "qbytearray.h"
+#include "qpagesetupdialog.h"
+#include "qpointer.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPrinter;
+
+class QAbstractPageSetupDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractPageSetupDialog)
+
+public:
+ QAbstractPageSetupDialogPrivate() : printer(0) {}
+
+ void setPrinter(QPrinter *newPrinter);
+
+ QPrinter *printer;
+ QPageSetupDialog::PageSetupDialogOptions opts;
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTDIALOG
+
+#endif // QABSTRACTPAGESETUPDIALOG_P_H
diff --git a/src/widgets/dialogs/qabstractprintdialog.cpp b/src/widgets/dialogs/qabstractprintdialog.cpp
new file mode 100644
index 0000000000..004f6877e4
--- /dev/null
+++ b/src/widgets/dialogs/qabstractprintdialog.cpp
@@ -0,0 +1,499 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractprintdialog_p.h"
+#include "qcoreapplication.h"
+#include "qprintdialog.h"
+#include "qprinter.h"
+#include "private/qprinter_p.h"
+
+#ifndef QT_NO_PRINTDIALOG
+
+QT_BEGIN_NAMESPACE
+
+// hack
+class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
+{
+};
+
+/*!
+ \class QAbstractPrintDialog
+ \brief The QAbstractPrintDialog class provides a base implementation for
+ print dialogs used to configure printers.
+
+ \ingroup printing
+
+ This class implements getter and setter functions that are used to
+ customize settings shown in print dialogs, but it is not used directly.
+ Use QPrintDialog to display a print dialog in your application.
+
+ In Symbian, there is no support for printing. Hence, this dialog should not
+ be used in Symbian.
+
+ \sa QPrintDialog, QPrinter, {Printing with Qt}
+*/
+
+/*!
+ \enum QAbstractPrintDialog::PrintRange
+
+ Used to specify the print range selection option.
+
+ \value AllPages All pages should be printed.
+ \value Selection Only the selection should be printed.
+ \value PageRange The specified page range should be printed.
+ \value CurrentPage Only the currently visible page should be printed.
+
+ \sa QPrinter::PrintRange
+*/
+
+/*!
+ \enum QAbstractPrintDialog::PrintDialogOption
+
+ Used to specify which parts of the print dialog should be visible.
+
+ \value None None of the options are enabled.
+ \value PrintToFile The print to file option is enabled.
+ \value PrintSelection The print selection option is enabled.
+ \value PrintPageRange The page range selection option is enabled.
+ \value PrintShowPageSize Show the page size + margins page only if this is enabled.
+ \value PrintCollateCopies The collate copies option is enabled
+ \value PrintCurrentPage The print current page option is enabled
+
+ This value is obsolete and does nothing since Qt 4.5:
+
+ \value DontUseSheet In previous versions of Qt, exec() the print dialog
+ would create a sheet by default the dialog was given a parent.
+ This is no longer supported in Qt 4.5. If you want to use sheets, use
+ QPrintDialog::open() instead.
+*/
+
+/*!
+ Constructs an abstract print dialog for \a printer with \a parent
+ as parent widget.
+*/
+QAbstractPrintDialog::QAbstractPrintDialog(QPrinter *printer, QWidget *parent)
+ : QDialog(*(new QAbstractPrintDialogPrivate), parent)
+{
+ Q_D(QAbstractPrintDialog);
+ setWindowTitle(QCoreApplication::translate("QPrintDialog", "Print"));
+ d->setPrinter(printer);
+}
+
+/*!
+ \internal
+*/
+QAbstractPrintDialog::QAbstractPrintDialog(QAbstractPrintDialogPrivate &ptr,
+ QPrinter *printer,
+ QWidget *parent)
+ : QDialog(ptr, parent)
+{
+ Q_D(QAbstractPrintDialog);
+ setWindowTitle(QCoreApplication::translate("QPrintDialog", "Print"));
+ d->setPrinter(printer);
+}
+
+/*!
+ \internal
+*/
+QAbstractPrintDialog::~QAbstractPrintDialog()
+{
+ Q_D(QAbstractPrintDialog);
+ if (d->ownsPrinter)
+ delete d->printer;
+}
+
+/*!
+ Sets the given \a option to be enabled if \a on is true;
+ otherwise, clears the given \a option.
+
+ \sa options, testOption()
+*/
+void QPrintDialog::setOption(PrintDialogOption option, bool on)
+{
+ Q_D(QPrintDialog);
+ if (!(d->options & option) != !on)
+ setOptions(d->options ^ option);
+}
+
+/*!
+ Returns true if the given \a option is enabled; otherwise, returns
+ false.
+
+ \sa options, setOption()
+*/
+bool QPrintDialog::testOption(PrintDialogOption option) const
+{
+ Q_D(const QPrintDialog);
+ return (d->options & option) != 0;
+}
+
+/*!
+ \property QPrintDialog::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 QPrintDialog::setOptions(PrintDialogOptions options)
+{
+ Q_D(QPrintDialog);
+
+ PrintDialogOptions changed = (options ^ d->options);
+ if (!changed)
+ return;
+
+ d->options = options;
+}
+
+QPrintDialog::PrintDialogOptions QPrintDialog::options() const
+{
+ Q_D(const QPrintDialog);
+ return d->options;
+}
+
+/*!
+ \obsolete
+
+ Use QPrintDialog::setOptions() instead.
+*/
+void QAbstractPrintDialog::setEnabledOptions(PrintDialogOptions options)
+{
+ Q_D(QAbstractPrintDialog);
+ d->options = options;
+}
+
+/*!
+ \obsolete
+
+ Use QPrintDialog::setOption(\a option, true) instead.
+*/
+void QAbstractPrintDialog::addEnabledOption(PrintDialogOption option)
+{
+ Q_D(QAbstractPrintDialog);
+ d->options |= option;
+}
+
+/*!
+ \obsolete
+
+ Use QPrintDialog::options() instead.
+*/
+QAbstractPrintDialog::PrintDialogOptions QAbstractPrintDialog::enabledOptions() const
+{
+ Q_D(const QAbstractPrintDialog);
+ return d->options;
+}
+
+/*!
+ \obsolete
+
+ Use QPrintDialog::testOption(\a option) instead.
+*/
+bool QAbstractPrintDialog::isOptionEnabled(PrintDialogOption option) const
+{
+ Q_D(const QAbstractPrintDialog);
+ return d->options & option;
+}
+
+/*!
+ Sets the print range option in to be \a range.
+ */
+void QAbstractPrintDialog::setPrintRange(PrintRange range)
+{
+ Q_D(QAbstractPrintDialog);
+ d->pd->printRange = QPrinter::PrintRange(range);
+}
+
+/*!
+ Returns the print range.
+*/
+QAbstractPrintDialog::PrintRange QAbstractPrintDialog::printRange() const
+{
+ Q_D(const QAbstractPrintDialog);
+ return QAbstractPrintDialog::PrintRange(d->pd->printRange);
+}
+
+/*!
+ Sets the page range in this dialog to be from \a min to \a max. This also
+ enables the PrintPageRange option.
+*/
+void QAbstractPrintDialog::setMinMax(int min, int max)
+{
+ Q_D(QAbstractPrintDialog);
+ Q_ASSERT_X(min <= max, "QAbstractPrintDialog::setMinMax",
+ "'min' must be less than or equal to 'max'");
+ d->pd->minPage = min;
+ d->pd->maxPage = max;
+ d->options |= PrintPageRange;
+}
+
+/*!
+ Returns the minimum page in the page range.
+ By default, this value is set to 1.
+*/
+int QAbstractPrintDialog::minPage() const
+{
+ Q_D(const QAbstractPrintDialog);
+ return d->pd->minPage;
+}
+
+/*!
+ Returns the maximum page in the page range. As of Qt 4.4, this
+ function returns INT_MAX by default. Previous versions returned 1
+ by default.
+*/
+int QAbstractPrintDialog::maxPage() const
+{
+ Q_D(const QAbstractPrintDialog);
+ return d->pd->maxPage;
+}
+
+/*!
+ Sets the range in the print dialog to be from \a from to \a to.
+*/
+void QAbstractPrintDialog::setFromTo(int from, int to)
+{
+ Q_D(QAbstractPrintDialog);
+ Q_ASSERT_X(from <= to, "QAbstractPrintDialog::setFromTo",
+ "'from' must be less than or equal to 'to'");
+ d->pd->fromPage = from;
+ d->pd->toPage = to;
+
+ if (d->pd->minPage == 0 && d->pd->maxPage == 0)
+ setMinMax(1, to);
+}
+
+/*!
+ Returns the first page to be printed
+ By default, this value is set to 0.
+*/
+int QAbstractPrintDialog::fromPage() const
+{
+ Q_D(const QAbstractPrintDialog);
+ return d->pd->fromPage;
+}
+
+/*!
+ Returns the last page to be printed.
+ By default, this value is set to 0.
+*/
+int QAbstractPrintDialog::toPage() const
+{
+ Q_D(const QAbstractPrintDialog);
+ return d->pd->toPage;
+}
+
+
+/*!
+ Returns the printer that this printer dialog operates
+ on.
+*/
+QPrinter *QAbstractPrintDialog::printer() const
+{
+ Q_D(const QAbstractPrintDialog);
+ return d->printer;
+}
+
+void QAbstractPrintDialogPrivate::setPrinter(QPrinter *newPrinter)
+{
+ if (newPrinter) {
+ printer = newPrinter;
+ ownsPrinter = false;
+ if (printer->fromPage() || printer->toPage())
+ options |= QAbstractPrintDialog::PrintPageRange;
+ } else {
+ printer = new QPrinter;
+ ownsPrinter = true;
+ }
+ pd = printer->d_func();
+}
+
+/*!
+ \fn int QAbstractPrintDialog::exec()
+
+ This virtual function is called to pop up the dialog. It must be
+ reimplemented in subclasses.
+*/
+
+/*!
+ \class QPrintDialog
+
+ \brief The QPrintDialog class provides a dialog for specifying
+ the printer's configuration.
+
+ \ingroup standard-dialogs
+ \ingroup printing
+
+ The dialog allows users to change document-related settings, such
+ as the paper size and orientation, type of print (color or
+ grayscale), range of pages, and number of copies to print.
+
+ Controls are also provided to enable users to choose from the
+ printers available, including any configured network printers.
+
+ Typically, QPrintDialog objects are constructed with a QPrinter
+ object, and executed using the exec() function.
+
+ \snippet doc/src/snippets/code/src_gui_dialogs_qabstractprintdialog.cpp 0
+
+ If the dialog is accepted by the user, the QPrinter object is
+ correctly configured for printing.
+
+ \table
+ \row
+ \o \inlineimage plastique-printdialog.png
+ \o \inlineimage plastique-printdialog-properties.png
+ \endtable
+
+ The printer dialog (shown above in Plastique style) enables access to common
+ printing properties. On X11 platforms that use the CUPS printing system, the
+ settings for each available printer can be modified via the dialog's
+ \gui{Properties} push button.
+
+ On Windows and Mac OS X, the native print dialog is used, which means that
+ some QWidget and QDialog properties set on the dialog won't be respected.
+ The native print dialog on Mac OS X does not support setting printer options,
+ i.e. setOptions() and setOption() have no effect.
+
+ In Qt 4.4, it was possible to use the static functions to show a sheet on
+ Mac OS X. This is no longer supported in Qt 4.5. If you want this
+ functionality, use QPrintDialog::open().
+
+ \sa QPageSetupDialog, QPrinter, {Pixelator Example}, {Order Form Example},
+ {Image Viewer Example}, {Scribble Example}
+*/
+
+/*!
+ \fn QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
+
+ Constructs a new modal printer dialog for the given \a printer
+ with the given \a parent.
+*/
+
+/*!
+ \fn QPrintDialog::~QPrintDialog()
+
+ Destroys the print dialog.
+*/
+
+/*!
+ \fn int QPrintDialog::exec()
+ \reimp
+*/
+
+/*!
+ \since 4.4
+
+ Set a list of widgets as \a tabs to be shown on the print dialog, if supported.
+
+ Currently this option is only supported on X11.
+
+ Setting the option tabs will transfer their ownership to the print dialog.
+*/
+void QAbstractPrintDialog::setOptionTabs(const QList<QWidget*> &tabs)
+{
+ Q_D(QAbstractPrintDialog);
+ d->setTabs(tabs);
+}
+
+/*!
+
+ \fn void QPrintDialog::accepted(QPrinter *printer)
+
+ This signal is emitted when the user accepts the values set in the print dialog.
+ The \a printer parameter includes the printer that the settings were applied to.
+*/
+
+/*!
+ \fn QPrinter *QPrintDialog::printer()
+
+ Returns the printer that this printer dialog operates
+ on. This can be useful when using the QPrintDialog::open() method.
+*/
+
+/*!
+ 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 QPrintDialog::done(int result)
+{
+ Q_D(QPrintDialog);
+ QDialog::done(result);
+ if (result == Accepted)
+ emit accepted(printer());
+ if (d->receiverToDisconnectOnClose) {
+ disconnect(this, SIGNAL(accepted(QPrinter*)),
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+}
+
+/*!
+ \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 QPrintDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QPrintDialog);
+ connect(this, SIGNAL(accepted(QPrinter*)), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTDIALOG
diff --git a/src/widgets/dialogs/qabstractprintdialog.h b/src/widgets/dialogs/qabstractprintdialog.h
new file mode 100644
index 0000000000..b9ac05ccff
--- /dev/null
+++ b/src/widgets/dialogs/qabstractprintdialog.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTPRINTDIALOG_H
+#define QABSTRACTPRINTDIALOG_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_PRINTER
+
+class QAbstractPrintDialogPrivate;
+class QPrinter;
+
+// ### Qt 5: remove this class
+class Q_GUI_EXPORT QAbstractPrintDialog : public QDialog
+{
+ Q_DECLARE_PRIVATE(QAbstractPrintDialog)
+ Q_OBJECT
+
+public:
+ // Keep in sync with QPrinter::PrintRange
+ enum PrintRange {
+ AllPages,
+ Selection,
+ PageRange,
+ CurrentPage
+ };
+
+ enum PrintDialogOption {
+ None = 0x0000, // obsolete
+ PrintToFile = 0x0001,
+ PrintSelection = 0x0002,
+ PrintPageRange = 0x0004,
+ PrintShowPageSize = 0x0008,
+ PrintCollateCopies = 0x0010,
+ DontUseSheet = 0x0020,
+ PrintCurrentPage = 0x0040
+ };
+
+ Q_DECLARE_FLAGS(PrintDialogOptions, PrintDialogOption)
+
+#ifndef QT_NO_PRINTDIALOG
+ explicit QAbstractPrintDialog(QPrinter *printer, QWidget *parent = 0);
+ ~QAbstractPrintDialog();
+
+ virtual int exec() = 0;
+
+ // obsolete
+ void addEnabledOption(PrintDialogOption option);
+ void setEnabledOptions(PrintDialogOptions options);
+ PrintDialogOptions enabledOptions() const;
+ bool isOptionEnabled(PrintDialogOption option) const;
+
+ void setOptionTabs(const QList<QWidget*> &tabs);
+
+ void setPrintRange(PrintRange range);
+ PrintRange printRange() const;
+
+ void setMinMax(int min, int max);
+ int minPage() const;
+ int maxPage() const;
+
+ void setFromTo(int fromPage, int toPage);
+ int fromPage() const;
+ int toPage() const;
+
+ QPrinter *printer() const;
+
+protected:
+ QAbstractPrintDialog(QAbstractPrintDialogPrivate &ptr, QPrinter *printer, QWidget *parent = 0);
+
+private:
+ Q_DISABLE_COPY(QAbstractPrintDialog)
+
+#endif // QT_NO_PRINTDIALOG
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QAbstractPrintDialog::PrintDialogOptions)
+
+#endif // QT_NO_PRINTER
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QABSTRACTPRINTDIALOG_H
diff --git a/src/widgets/dialogs/qabstractprintdialog_p.h b/src/widgets/dialogs/qabstractprintdialog_p.h
new file mode 100644
index 0000000000..1b5fa599f0
--- /dev/null
+++ b/src/widgets/dialogs/qabstractprintdialog_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTPRINTDIALOG_P_H
+#define QABSTRACTPRINTDIALOG_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"
+
+#ifndef QT_NO_PRINTDIALOG
+
+#include "QtGui/qabstractprintdialog.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PRINTER
+
+class QPrinter;
+class QPrinterPrivate;
+
+class QAbstractPrintDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QAbstractPrintDialog)
+
+public:
+ QAbstractPrintDialogPrivate()
+ : printer(0), pd(0), ownsPrinter(false)
+ , options(QAbstractPrintDialog::PrintToFile | QAbstractPrintDialog::PrintPageRange |
+ QAbstractPrintDialog::PrintCollateCopies | QAbstractPrintDialog::PrintShowPageSize)
+ {
+ }
+
+ QPrinter *printer;
+ QPrinterPrivate *pd;
+ bool ownsPrinter;
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+
+ QAbstractPrintDialog::PrintDialogOptions options;
+
+ virtual void setTabs(const QList<QWidget *> &) {}
+ void setPrinter(QPrinter *newPrinter);
+};
+
+#endif //QT_NO_PRINTER
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTDIALOG
+
+#endif // QABSTRACTPRINTDIALOG_P_H
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
new file mode 100644
index 0000000000..f99e6c2621
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..80a893d568
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOLORDIALOG_H
+#define QCOLORDIALOG_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_COLORDIALOG
+
+class QColorDialogPrivate;
+
+class Q_GUI_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..ee9b19ad99
--- /dev/null
+++ b/src/widgets/dialogs/qcolordialog_mac.mm
@@ -0,0 +1,500 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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) {
+ @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).
+ }
+ }
+
+ 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..243e7277c5
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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..3dbb5c11a9
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..6838d927a8
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..ee23b7bf87
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDIALOG_H
+#define QDIALOG_H
+
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QPushButton;
+class QDialogPrivate;
+
+class Q_GUI_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..a2a948e951
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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 "QtGui/qdialog.h"
+#include "QtGui/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..beec2cd29c
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <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_GUI_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_GUI_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_GUI_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..6d474cc4f9
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qerrormessage.h"
+
+#ifndef QT_NO_ERRORMESSAGE
+
+#include "qapplication.h"
+#include "qcheckbox.h"
+#include "qlabel.h"
+#include "qlayout.h"
+#include "qmessagebox.h"
+#include "qpushbutton.h"
+#include "qstringlist.h"
+#include "qtextedit.h"
+#include "qdialog_p.h"
+#include "qpixmap.h"
+#include "qmetaobject.h"
+#include "qthread.h"
+#include "qqueue.h"
+#include "qset.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef Q_WS_WINCE
+extern bool qt_wince_is_mobile(); //defined in qguifunctions_wince.cpp
+extern bool qt_wince_is_high_dpi(); //defined in qguifunctions_wince.cpp
+
+#include "qguifunctions_wince.h"
+#endif
+
+#if defined(QT_SOFTKEYS_ENABLED)
+#include <qaction.h>
+#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..500482c722
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QERRORMESSAGE_H
+#define QERRORMESSAGE_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_ERRORMESSAGE
+
+class QErrorMessagePrivate;
+
+class Q_GUI_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..897a9164a2
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -0,0 +1,3486 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <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
+#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_GUI_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_GUI_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_GUI_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_GUI_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_GUI_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);
+}
+
+/**
+ Returns the text in the line edit which can be one or more file names
+ */
+QStringList QFileDialogPrivate::typedFiles() const
+{
+ QStringList files;
+ QString editText = lineEdit()->text();
+ if (!editText.contains(QLatin1Char('"')))
+ files << editText;
+ 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
+ files << toInternal(tokens.at(i));
+ }
+ }
+ 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();
+#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 (path[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 = path[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..fabb575a5a
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILEDIALOG_H
+#define QFILEDIALOG_H
+
+#include <QtCore/qdir.h>
+#include <QtCore/qstring.h>
+#include <QtGui/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_GUI_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..dcb08114e2
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+*********************************************************************</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..e8de400cab
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+*********************************************************************</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..832f9bfaf8
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..882acdd758
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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..ed9895019f
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..114f4bedbc
--- /dev/null
+++ b/src/widgets/dialogs/qfiledialog_win.cpp
@@ -0,0 +1,825 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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"
+
+#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 = parent ? parent->winId() : 0;
+ 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;
+}
+
+extern void qt_win_eatMouseMove();
+
+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(parentWindow ? parentWindow->winId() : 0);
+ 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(parentWindow ? parentWindow->winId() : 0);
+ 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 = (parent ? parent->winId() : 0);
+ 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..7580f0ad6b
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <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..b36b21e63d
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..db308ef57e
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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..cb8eb6ad66
--- /dev/null
+++ b/src/widgets/dialogs/qfilesystemmodel.cpp
@@ -0,0 +1,2027 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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 hideDotAndDotDot = (filters & QDir::NoDotAndDotDot);
+
+ // 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 isDotOrDot = ( (node->fileName == QLatin1String(".")
+ || node->fileName == QLatin1String("..")));
+ if ( (hideHidden && (!isDotOrDot && node->isHidden()))
+ || (hideSystem && node->isSystem())
+ || (hideDirs && node->isDir())
+ || (hideFiles && node->isFile())
+ || (hideSymlinks && node->isSymLink())
+ || (hideReadable && node->isReadable())
+ || (hideWritable && node->isWritable())
+ || (hideExecutable && node->isExecutable())
+ || (hideDotAndDotDot && isDotOrDot))
+ 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..8aa9875d13
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMMODEL_H
+#define QFILESYSTEMMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qdir.h>
+#include <QtGui/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_GUI_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..e83bbd11d3
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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..b58021d877
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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 <QtGui/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..a09f16d0a0
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFONTDIALOG_H
+#define QFONTDIALOG_H
+
+#include <QtGui/qwindowdefs.h>
+#include <QtGui/qdialog.h>
+#include <QtGui/qfont.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_FONTDIALOG
+
+class QFontDialogPrivate;
+
+class Q_GUI_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..1552ad675f
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..3179b89af7
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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..26a6698a6c
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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 <QtGui/qfilesystemmodel.h>
+QT_BEGIN_NAMESPACE
+#ifndef QT_NO_FSCOMPLETER
+
+/*!
+ QCompleter that can deal with QFileSystemModel
+ */
+class 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..f13b8f55c3
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..b0e6fbb216
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QINPUTDIALOG_H
+#define QINPUTDIALOG_H
+
+#include <QtGui/qdialog.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qlineedit.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_INPUTDIALOG
+
+class QInputDialogPrivate;
+
+class Q_GUI_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..d6dbcf6e78
--- /dev/null
+++ b/src/widgets/dialogs/qmessagebox.cpp
@@ -0,0 +1,2751 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/qmessagebox.h>
+
+#ifndef QT_NO_MESSAGEBOX
+
+#include <QtGui/qdialogbuttonbox.h>
+#include "private/qlabel_p.h"
+#include "private/qapplication_p.h"
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+#include <QtGui/qstyle.h>
+#include <QtGui/qstyleoption.h>
+#include <QtGui/qgridlayout.h>
+#include <QtGui/qdesktopwidget.h>
+#include <QtGui/qpushbutton.h>
+#include <QtGui/qaccessible.h>
+#include <QtGui/qicon.h>
+#include <QtGui/qtextdocument.h>
+#include <QtGui/qapplication.h>
+#include <QtGui/qtextedit.h>
+#include <QtGui/qtextbrowser.h>
+#include <QtGui/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 (QTextControl *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 (QTextControl *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;
+ }
+#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..37ddb38e2d
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMESSAGEBOX_H
+#define QMESSAGEBOX_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_MESSAGEBOX
+
+class QLabel;
+class QMessageBoxPrivate;
+class QAbstractButton;
+
+class Q_GUI_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..5c8ef24688
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <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/qpagesetupdialog.cpp b/src/widgets/dialogs/qpagesetupdialog.cpp
new file mode 100644
index 0000000000..4037e1cff8
--- /dev/null
+++ b/src/widgets/dialogs/qpagesetupdialog.cpp
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qabstractpagesetupdialog_p.h>
+
+#ifndef QT_NO_PRINTDIALOG
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPageSetupDialog
+
+ \brief The QPageSetupDialog class provides a configuration dialog
+ for the page-related options on a printer.
+
+ \ingroup standard-dialogs
+ \ingroup printing
+
+ On Windows and Mac OS X the page setup dialog is implemented using
+ the native page setup dialogs.
+
+ Note that on Windows and Mac OS X custom paper sizes won't be
+ reflected in the native page setup dialogs. Additionally, custom
+ page margins set on a QPrinter won't show in the native Mac OS X
+ page setup dialog.
+
+ In Symbian, there is no support for printing. Hence, this dialog should not
+ be used in Symbian.
+
+ \sa QPrinter, QPrintDialog
+*/
+
+
+/*!
+ \fn QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
+
+ Constructs a page setup dialog that configures \a printer with \a
+ parent as the parent widget.
+*/
+
+/*!
+ \since 4.5
+
+ \fn QPageSetupDialog::QPageSetupDialog(QWidget *parent)
+
+ Constructs a page setup dialog that configures a default-constructed
+ QPrinter with \a parent as the parent widget.
+
+ \sa printer()
+*/
+
+/*!
+ \fn QPrinter *QPageSetupDialog::printer()
+
+ Returns the printer that was passed to the QPageSetupDialog
+ constructor.
+*/
+
+// hack
+class QPageSetupDialogPrivate : public QAbstractPageSetupDialogPrivate
+{
+};
+
+/*!
+ \enum QPageSetupDialog::PageSetupDialogOption
+ \since 4.4
+
+ Used to specify options to the page setup dialog
+
+ This value is obsolete and does nothing since Qt 4.5:
+
+ \value DontUseSheet In previous versions of QDialog::exec() the
+ page setup dialog would create a sheet by default if the dialog
+ was given a parent. This is no longer supported from Qt 4.5. If
+ you want to use sheets, use QPageSetupDialog::open() instead.
+
+ \omitvalue None
+ \omitvalue OwnsPrinter
+*/
+
+/*!
+ Sets the given \a option to be enabled if \a on is true;
+ otherwise, clears the given \a option.
+
+ \sa options, testOption()
+*/
+void QPageSetupDialog::setOption(PageSetupDialogOption option, bool on)
+{
+ Q_D(QPageSetupDialog);
+ 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 QPageSetupDialog::testOption(PageSetupDialogOption option) const
+{
+ Q_D(const QPageSetupDialog);
+ return (d->opts & option) != 0;
+}
+
+/*!
+ \property QPageSetupDialog::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 QPageSetupDialog::setOptions(PageSetupDialogOptions options)
+{
+ Q_D(QPageSetupDialog);
+
+ PageSetupDialogOptions changed = (options ^ d->opts);
+ if (!changed)
+ return;
+
+ d->opts = options;
+}
+
+QPageSetupDialog::PageSetupDialogOptions QPageSetupDialog::options() const
+{
+ Q_D(const QPageSetupDialog);
+ return d->opts;
+}
+
+/*!
+ \obsolete
+
+ Use setOption(\a option, true) instead.
+*/
+void QPageSetupDialog::addEnabledOption(PageSetupDialogOption option)
+{
+ setOption(option, true);
+}
+
+/*!
+ \obsolete
+
+ Use setOptions(\a options) instead.
+*/
+void QPageSetupDialog::setEnabledOptions(PageSetupDialogOptions options)
+{
+ setOptions(options);
+}
+
+/*!
+ \obsolete
+
+ Use options() instead.
+*/
+QPageSetupDialog::PageSetupDialogOptions QPageSetupDialog::enabledOptions() const
+{
+ return options();
+}
+
+/*!
+ \obsolete
+
+ Use testOption(\a option) instead.
+*/
+bool QPageSetupDialog::isOptionEnabled(PageSetupDialogOption option) const
+{
+ return testOption(option);
+}
+
+/*!
+ \overload
+ \since 4.5
+
+ 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 QPageSetupDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QPageSetupDialog);
+ connect(this, SIGNAL(accepted()), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+#if defined(Q_WS_MAC) || defined(Q_OS_WIN)
+/*! \fn void QPageSetupDialog::setVisible(bool visible)
+ \reimp
+*/
+#endif
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/widgets/dialogs/qpagesetupdialog.h b/src/widgets/dialogs/qpagesetupdialog.h
new file mode 100644
index 0000000000..184af251da
--- /dev/null
+++ b/src/widgets/dialogs/qpagesetupdialog.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPAGESETUPDIALOG_H
+#define QPAGESETUPDIALOG_H
+
+#include <QtGui/qabstractpagesetupdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_PRINTDIALOG
+
+class QPageSetupDialogPrivate;
+
+class Q_GUI_EXPORT QPageSetupDialog : public QAbstractPageSetupDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPageSetupDialog)
+ Q_ENUMS(PageSetupDialogOption)
+ Q_PROPERTY(PageSetupDialogOptions options READ options WRITE setOptions)
+
+public:
+ enum PageSetupDialogOption {
+ None = 0x00000000, // internal
+ DontUseSheet = 0x00000001,
+ OwnsPrinter = 0x80000000 // internal
+ };
+
+ Q_DECLARE_FLAGS(PageSetupDialogOptions, PageSetupDialogOption)
+
+ explicit QPageSetupDialog(QPrinter *printer, QWidget *parent = 0);
+ explicit QPageSetupDialog(QWidget *parent = 0);
+
+ // obsolete
+ void addEnabledOption(PageSetupDialogOption option);
+ void setEnabledOptions(PageSetupDialogOptions options);
+ PageSetupDialogOptions enabledOptions() const;
+ bool isOptionEnabled(PageSetupDialogOption option) const;
+
+ void setOption(PageSetupDialogOption option, bool on = true);
+ bool testOption(PageSetupDialogOption option) const;
+ void setOptions(PageSetupDialogOptions options);
+ PageSetupDialogOptions options() const;
+
+#if defined(Q_WS_MAC) || defined(Q_OS_WIN)
+ virtual void setVisible(bool visible);
+#endif
+ virtual int exec();
+
+#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);
+
+#ifdef qdoc
+ QPrinter *printer();
+#endif
+};
+
+#endif // QT_NO_PRINTDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPAGESETUPDIALOG_H
diff --git a/src/widgets/dialogs/qpagesetupdialog_mac.mm b/src/widgets/dialogs/qpagesetupdialog_mac.mm
new file mode 100644
index 0000000000..fa3f47378f
--- /dev/null
+++ b/src/widgets/dialogs/qpagesetupdialog_mac.mm
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpagesetupdialog.h"
+
+#include <qhash.h>
+#include <private/qapplication_p.h>
+#include <private/qprintengine_mac_p.h>
+#include <private/qabstractpagesetupdialog_p.h>
+
+#ifndef QT_NO_PRINTDIALOG
+
+QT_USE_NAMESPACE
+
+@class QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate);
+
+@interface QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) : NSObject {
+ QMacPrintEnginePrivate *pe;
+}
+- (id)initWithMacPrintEngine:(QMacPrintEnginePrivate *)printEngine;
+- (void)pageLayoutDidEnd:(NSPageLayout *)pageLayout
+ returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate)
+- (id)initWithMacPrintEngine:(QMacPrintEnginePrivate *)printEngine
+{
+ self = [super init];
+ if (self) {
+ pe = printEngine;
+ }
+ return self;
+
+}
+- (void)pageLayoutDidEnd:(NSPageLayout *)pageLayout
+ returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ Q_UNUSED(pageLayout);
+ QPageSetupDialog *dialog = static_cast<QPageSetupDialog *>(contextInfo);
+ if (returnCode == NSOKButton) {
+ PMRect paperRect;
+ PMGetUnadjustedPaperRect(pe->format, &paperRect);
+ pe->customSize = QSizeF(paperRect.right - paperRect.left,
+ paperRect.bottom - paperRect.top);
+ }
+ dialog->done((returnCode == NSOKButton) ? QDialog::Accepted : QDialog::Rejected);
+}
+@end
+
+QT_BEGIN_NAMESPACE
+
+extern void macStartInterceptWindowTitle(QWidget *window);
+extern void macStopInterceptWindowTitle();
+
+class QPageSetupDialogPrivate : public QAbstractPageSetupDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QPageSetupDialog)
+
+public:
+ QPageSetupDialogPrivate() : ep(0)
+#ifndef QT_MAC_USE_COCOA
+ ,upp(0)
+#else
+ ,pageLayout(0)
+#endif
+ {}
+
+ ~QPageSetupDialogPrivate() {
+#ifndef QT_MAC_USE_COCOA
+ if (upp) {
+ DisposePMSheetDoneUPP(upp);
+ upp = 0;
+ }
+ QHash<PMPrintSession, QPageSetupDialogPrivate *>::iterator it = sheetCallbackMap.begin();
+ while (it != sheetCallbackMap.end()) {
+ if (it.value() == this) {
+ it = sheetCallbackMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+#endif
+ }
+
+#ifndef QT_MAC_USE_COCOA
+ void openCarbonPageLayout(Qt::WindowModality modality);
+ void closeCarbonPageLayout();
+ static void pageSetupDialogSheetDoneCallback(PMPrintSession printSession, WindowRef /*documentWindow*/, Boolean accepted) {
+ QPageSetupDialogPrivate *priv = sheetCallbackMap.value(printSession);
+ if (!priv) {
+ qWarning("%s:%d: QPageSetupDialog::exec: Could not retrieve data structure, "
+ "you most likely now have an infinite modal loop", __FILE__, __LINE__);
+ return;
+ }
+ priv->q_func()->done(accepted ? QDialog::Accepted : QDialog::Rejected);
+ }
+#else
+ void openCocoaPageLayout(Qt::WindowModality modality);
+ void closeCocoaPageLayout();
+#endif
+
+ QMacPrintEnginePrivate *ep;
+#ifndef QT_MAC_USE_COCOA
+ PMSheetDoneUPP upp;
+ static QHash<PMPrintSession, QPageSetupDialogPrivate*> sheetCallbackMap;
+#else
+ NSPageLayout *pageLayout;
+#endif
+};
+
+#ifndef QT_MAC_USE_COCOA
+QHash<PMPrintSession, QPageSetupDialogPrivate*> QPageSetupDialogPrivate::sheetCallbackMap;
+void QPageSetupDialogPrivate::openCarbonPageLayout(Qt::WindowModality modality)
+{
+ Q_Q(QPageSetupDialog);
+ // If someone is reusing a QPrinter object, the end released all our old
+ // information. In this case, we must reinitialize.
+ if (ep->session == 0)
+ ep->initialize();
+
+ sheetCallbackMap.insert(ep->session, this);
+ if (modality == Qt::ApplicationModal) {
+ QWidget modal_widg(0, Qt::Window);
+ modal_widg.setObjectName(QLatin1String(__FILE__ "__modal_dlg"));
+ modal_widg.createWinId();
+ QApplicationPrivate::enterModal(&modal_widg);
+ QApplicationPrivate::native_modal_dialog_active = true;
+ Boolean accepted;
+ PMSessionPageSetupDialog(ep->session, ep->format, &accepted);
+ QApplicationPrivate::leaveModal(&modal_widg);
+ QApplicationPrivate::native_modal_dialog_active = false;
+ pageSetupDialogSheetDoneCallback(ep->session, 0, accepted);
+ } else {
+ // Window Modal means that we use a sheet at the moment, there's no other way to do it correctly.
+ if (!upp)
+ upp = NewPMSheetDoneUPP(QPageSetupDialogPrivate::pageSetupDialogSheetDoneCallback);
+ PMSessionUseSheets(ep->session, qt_mac_window_for(q->parentWidget()), upp);
+ Boolean unused;
+ PMSessionPageSetupDialog(ep->session, ep->format, &unused);
+ }
+}
+
+void QPageSetupDialogPrivate::closeCarbonPageLayout()
+{
+ // if the margins have changed, we have to use the margins from the new
+ // PMFormat object
+ if (q_func()->result() == QDialog::Accepted) {
+ PMPaper paper;
+ PMPaperMargins margins;
+ PMGetPageFormatPaper(ep->format, &paper);
+ PMPaperGetMargins(paper, &margins);
+ ep->leftMargin = margins.left;
+ ep->topMargin = margins.top;
+ ep->rightMargin = margins.right;
+ ep->bottomMargin = margins.bottom;
+
+ PMRect paperRect;
+ PMGetUnadjustedPaperRect(ep->format, &paperRect);
+ ep->customSize = QSizeF(paperRect.right - paperRect.left,
+ paperRect.bottom - paperRect.top);
+ }
+ sheetCallbackMap.remove(ep->session);
+}
+#else
+void QPageSetupDialogPrivate::openCocoaPageLayout(Qt::WindowModality modality)
+{
+ Q_Q(QPageSetupDialog);
+
+ // If someone is reusing a QPrinter object, the end released all our old
+ // information. In this case, we must reinitialize.
+ if (ep->session == 0)
+ ep->initialize();
+
+ macStartInterceptWindowTitle(q);
+ pageLayout = [NSPageLayout pageLayout];
+ // Keep a copy to this since we plan on using it for a bit.
+ [pageLayout retain];
+ QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPageLayoutDelegate) alloc] initWithMacPrintEngine:ep];
+
+ if (modality == Qt::ApplicationModal) {
+ int rval = [pageLayout runModalWithPrintInfo:ep->printInfo];
+ [delegate pageLayoutDidEnd:pageLayout returnCode:rval contextInfo:q];
+ } else {
+ Q_ASSERT(q->parentWidget());
+ [pageLayout beginSheetWithPrintInfo:ep->printInfo
+ modalForWindow:qt_mac_window_for(q->parentWidget())
+ delegate:delegate
+ didEndSelector:@selector(pageLayoutDidEnd:returnCode:contextInfo:)
+ contextInfo:q];
+ }
+
+ macStopInterceptWindowTitle();
+}
+
+void QPageSetupDialogPrivate::closeCocoaPageLayout()
+{
+ // NSPageLayout can change the session behind our back and then our
+ // d->ep->session object will become a dangling pointer. Update it
+ // based on the "current" session
+ ep->session = static_cast<PMPrintSession>([ep->printInfo PMPrintSession]);
+
+ [pageLayout release];
+ pageLayout = 0;
+}
+#endif
+
+QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
+ : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), printer, parent)
+{
+ Q_D(QPageSetupDialog);
+ d->ep = static_cast<QMacPrintEngine *>(d->printer->paintEngine())->d_func();
+}
+
+QPageSetupDialog::QPageSetupDialog(QWidget *parent)
+ : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), 0, parent)
+{
+ Q_D(QPageSetupDialog);
+ d->ep = static_cast<QMacPrintEngine *>(d->printer->paintEngine())->d_func();
+}
+
+void QPageSetupDialog::setVisible(bool visible)
+{
+ Q_D(QPageSetupDialog);
+
+ if (d->printer->outputFormat() != QPrinter::NativeFormat)
+ return;
+
+#ifndef QT_MAC_USE_COCOA
+ bool isCurrentlyVisible = d->sheetCallbackMap.contains(d->ep->session);
+#else
+ bool isCurrentlyVisible = (d->pageLayout != 0);
+#endif
+ if (!visible == !isCurrentlyVisible)
+ return;
+
+ if (visible) {
+#ifndef QT_MAC_USE_COCOA
+ d->openCarbonPageLayout(parentWidget() ? Qt::WindowModal
+ : Qt::ApplicationModal);
+#else
+ d->openCocoaPageLayout(parentWidget() ? Qt::WindowModal
+ : Qt::ApplicationModal);
+#endif
+ return;
+ } else {
+#ifndef QT_MAC_USE_COCOA
+ d->closeCarbonPageLayout();
+#else
+ if (d->pageLayout) {
+ d->closeCocoaPageLayout();
+ return;
+ }
+#endif
+ }
+}
+
+int QPageSetupDialog::exec()
+{
+ Q_D(QPageSetupDialog);
+
+ if (d->printer->outputFormat() != QPrinter::NativeFormat)
+ return Rejected;
+
+#ifndef QT_MAC_USE_COCOA
+ d->openCarbonPageLayout(Qt::ApplicationModal);
+ d->closeCarbonPageLayout();
+#else
+ QMacCocoaAutoReleasePool pool;
+ d->openCocoaPageLayout(Qt::ApplicationModal);
+ d->closeCocoaPageLayout();
+#endif
+ return result();
+}
+
+QT_END_NAMESPACE
+
+#endif /* QT_NO_PRINTDIALOG */
diff --git a/src/widgets/dialogs/qpagesetupdialog_unix.cpp b/src/widgets/dialogs/qpagesetupdialog_unix.cpp
new file mode 100644
index 0000000000..a4e0927e8c
--- /dev/null
+++ b/src/widgets/dialogs/qpagesetupdialog_unix.cpp
@@ -0,0 +1,620 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpagesetupdialog.h"
+
+#ifndef QT_NO_PRINTDIALOG
+#include "qpagesetupdialog_unix_p.h"
+
+#include "qpainter.h"
+#include "qprintdialog.h"
+#include "qdialogbuttonbox.h"
+#include <ui_qpagesetupwidget.h>
+
+#include <QtGui/qprinter.h>
+#include <private/qabstractpagesetupdialog_p.h>
+#include <private/qprinter_p.h>
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+# include <private/qcups_p.h>
+# include <cups/cups.h>
+# include <private/qpdf_p.h>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+QSizeF qt_printerPaperSize(QPrinter::Orientation, QPrinter::PaperSize, QPrinter::Unit, int);
+
+// Disabled until we have support for papersources on unix
+// #define PSD_ENABLE_PAPERSOURCE
+
+static void populatePaperSizes(QComboBox* cb)
+{
+ cb->addItem(QPrintDialog::tr("A0"), QPrinter::A0);
+ cb->addItem(QPrintDialog::tr("A1"), QPrinter::A1);
+ cb->addItem(QPrintDialog::tr("A2"), QPrinter::A2);
+ cb->addItem(QPrintDialog::tr("A3"), QPrinter::A3);
+ cb->addItem(QPrintDialog::tr("A4"), QPrinter::A4);
+ cb->addItem(QPrintDialog::tr("A5"), QPrinter::A5);
+ cb->addItem(QPrintDialog::tr("A6"), QPrinter::A6);
+ cb->addItem(QPrintDialog::tr("A7"), QPrinter::A7);
+ cb->addItem(QPrintDialog::tr("A8"), QPrinter::A8);
+ cb->addItem(QPrintDialog::tr("A9"), QPrinter::A9);
+ cb->addItem(QPrintDialog::tr("B0"), QPrinter::B0);
+ cb->addItem(QPrintDialog::tr("B1"), QPrinter::B1);
+ cb->addItem(QPrintDialog::tr("B2"), QPrinter::B2);
+ cb->addItem(QPrintDialog::tr("B3"), QPrinter::B3);
+ cb->addItem(QPrintDialog::tr("B4"), QPrinter::B4);
+ cb->addItem(QPrintDialog::tr("B5"), QPrinter::B5);
+ cb->addItem(QPrintDialog::tr("B6"), QPrinter::B6);
+ cb->addItem(QPrintDialog::tr("B7"), QPrinter::B7);
+ cb->addItem(QPrintDialog::tr("B8"), QPrinter::B8);
+ cb->addItem(QPrintDialog::tr("B9"), QPrinter::B9);
+ cb->addItem(QPrintDialog::tr("B10"), QPrinter::B10);
+ cb->addItem(QPrintDialog::tr("C5E"), QPrinter::C5E);
+ cb->addItem(QPrintDialog::tr("DLE"), QPrinter::DLE);
+ cb->addItem(QPrintDialog::tr("Executive"), QPrinter::Executive);
+ cb->addItem(QPrintDialog::tr("Folio"), QPrinter::Folio);
+ cb->addItem(QPrintDialog::tr("Ledger"), QPrinter::Ledger);
+ cb->addItem(QPrintDialog::tr("Legal"), QPrinter::Legal);
+ cb->addItem(QPrintDialog::tr("Letter"), QPrinter::Letter);
+ cb->addItem(QPrintDialog::tr("Tabloid"), QPrinter::Tabloid);
+ cb->addItem(QPrintDialog::tr("US Common #10 Envelope"), QPrinter::Comm10E);
+ cb->addItem(QPrintDialog::tr("Custom"), QPrinter::Custom);
+}
+
+
+static QSizeF sizeForOrientation(QPrinter::Orientation orientation, const QSizeF &size)
+{
+ return (orientation == QPrinter::Portrait) ? size : QSizeF(size.height(), size.width());
+}
+
+#ifdef PSD_ENABLE_PAPERSOURCE
+static const char *paperSourceNames[] = {
+ "Only One",
+ "Lower",
+ "Middle",
+ "Manual",
+ "Envelope",
+ "Envelope manual",
+ "Auto",
+ "Tractor",
+ "Small format",
+ "Large format",
+ "Large capacity",
+ "Cassette",
+ "Form source",
+ 0
+};
+
+struct PaperSourceNames
+{
+ PaperSourceNames(const char *nam, QPrinter::PaperSource ps)
+ : paperSource(ps), name(nam) {}
+ QPrinter::PaperSource paperSource;
+ const char *name;
+};
+#endif
+
+
+class QPagePreview : public QWidget
+{
+public:
+ QPagePreview(QWidget *parent) : QWidget(parent)
+ {
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ setMinimumSize(50, 50);
+ }
+
+ void setPaperSize(const QSizeF& size)
+ {
+ m_size = size;
+ update();
+ }
+
+ void setMargins(qreal left, qreal top, qreal right, qreal bottom)
+ {
+ m_left = left;
+ m_top = top;
+ m_right = right;
+ m_bottom = bottom;
+ update();
+ }
+
+protected:
+ void paintEvent(QPaintEvent *)
+ {
+ QRect pageRect;
+ QSizeF adjustedSize(m_size);
+ adjustedSize.scale(width()-10, height()-10, Qt::KeepAspectRatio);
+ pageRect = QRect(QPoint(0,0), adjustedSize.toSize());
+ pageRect.moveCenter(rect().center());
+
+ qreal width_factor = pageRect.width() / m_size.width();
+ qreal height_factor = pageRect.height() / m_size.height();
+ int leftSize = qRound(m_left*width_factor);
+ int topSize = qRound(m_top*height_factor);
+ int rightSize = qRound(m_right*width_factor);
+ int bottomSize = qRound(m_bottom * height_factor);
+ QRect marginRect(pageRect.x()+leftSize,
+ pageRect.y()+topSize,
+ pageRect.width() - (leftSize+rightSize+1),
+ pageRect.height() - (topSize+bottomSize+1));
+
+ QPainter p(this);
+ QColor shadow(palette().mid().color());
+ for (int i=1; i<6; ++i) {
+ shadow.setAlpha(180-i*30);
+ QRect offset(pageRect.adjusted(i, i, i, i));
+ p.setPen(shadow);
+ p.drawLine(offset.left(), offset.bottom(), offset.right(), offset.bottom());
+ p.drawLine(offset.right(), offset.top(), offset.right(), offset.bottom()-1);
+ }
+ p.fillRect(pageRect, palette().light());
+
+ if (marginRect.isValid()) {
+ p.setPen(QPen(palette().color(QPalette::Dark), 0, Qt::DotLine));
+ p.drawRect(marginRect);
+
+ marginRect.adjust(2, 2, -1, -1);
+ p.setClipRect(marginRect);
+ QFont font;
+ font.setPointSizeF(font.pointSizeF()*0.25);
+ p.setFont(font);
+ p.setPen(palette().color(QPalette::Dark));
+ QString text(QLatin1String("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi."));
+ for (int i=0; i<3; ++i)
+ text += text;
+ p.drawText(marginRect, Qt::TextWordWrap|Qt::AlignVCenter, text);
+ }
+ }
+
+private:
+ // all these are in points
+ qreal m_left, m_top, m_right, m_bottom;
+ QSizeF m_size;
+};
+
+
+class QPageSetupDialogPrivate : public QAbstractPageSetupDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QPageSetupDialog)
+
+public:
+ ~QPageSetupDialogPrivate();
+ void init();
+
+ QPageSetupWidget *widget;
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ QCUPSSupport *cups;
+#endif
+};
+
+QPageSetupDialogPrivate::~QPageSetupDialogPrivate()
+{
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ delete cups;
+#endif
+}
+
+void QPageSetupDialogPrivate::init()
+{
+ Q_Q(QPageSetupDialog);
+
+ widget = new QPageSetupWidget(q);
+ widget->setPrinter(printer);
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (printer->outputFormat() == QPrinter::NativeFormat && QCUPSSupport::isAvailable()) {
+ cups = new QCUPSSupport;
+ widget->selectPrinter(cups);
+ } else {
+ cups = 0;
+ }
+#endif
+
+ QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Ok
+ | QDialogButtonBox::Cancel,
+ Qt::Horizontal, q);
+ QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
+ QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
+
+ QVBoxLayout *lay = new QVBoxLayout(q);
+ lay->addWidget(widget);
+ lay->addWidget(buttons);
+}
+
+QPageSetupWidget::QPageSetupWidget(QWidget *parent)
+ : QWidget(parent),
+ m_printer(0),
+ m_blockSignals(false),
+ m_cups(0)
+{
+ widget.setupUi(this);
+
+ QString suffix = (QLocale::system().measurementSystem() == QLocale::ImperialSystem)
+ ? QString::fromLatin1(" in")
+ : QString::fromLatin1(" mm");
+ widget.topMargin->setSuffix(suffix);
+ widget.bottomMargin->setSuffix(suffix);
+ widget.leftMargin->setSuffix(suffix);
+ widget.rightMargin->setSuffix(suffix);
+ widget.paperWidth->setSuffix(suffix);
+ widget.paperHeight->setSuffix(suffix);
+
+ QVBoxLayout *lay = new QVBoxLayout(widget.preview);
+ widget.preview->setLayout(lay);
+ m_pagePreview = new QPagePreview(widget.preview);
+ lay->addWidget(m_pagePreview);
+
+ setAttribute(Qt::WA_WState_Polished, false);
+
+#ifdef PSD_ENABLE_PAPERSOURCE
+ for (int i=0; paperSourceNames[i]; ++i)
+ widget.paperSource->insertItem(paperSourceNames[i]);
+#else
+ widget.paperSourceLabel->setVisible(false);
+ widget.paperSource->setVisible(false);
+#endif
+
+ widget.reverseLandscape->setVisible(false);
+ widget.reversePortrait->setVisible(false);
+
+ populatePaperSizes(widget.paperSize);
+
+ QStringList units;
+ units << tr("Centimeters (cm)") << tr("Millimeters (mm)") << tr("Inches (in)") << tr("Points (pt)");
+ widget.unit->addItems(units);
+ connect(widget.unit, SIGNAL(activated(int)), this, SLOT(unitChanged(int)));
+ widget.unit->setCurrentIndex((QLocale::system().measurementSystem() == QLocale::ImperialSystem) ? 2 : 1);
+
+ connect(widget.paperSize, SIGNAL(currentIndexChanged(int)), this, SLOT(_q_paperSizeChanged()));
+ connect(widget.paperWidth, SIGNAL(valueChanged(double)), this, SLOT(_q_paperSizeChanged()));
+ connect(widget.paperHeight, SIGNAL(valueChanged(double)), this, SLOT(_q_paperSizeChanged()));
+
+ connect(widget.leftMargin, SIGNAL(valueChanged(double)), this, SLOT(setLeftMargin(double)));
+ connect(widget.topMargin, SIGNAL(valueChanged(double)), this, SLOT(setTopMargin(double)));
+ connect(widget.rightMargin, SIGNAL(valueChanged(double)), this, SLOT(setRightMargin(double)));
+ connect(widget.bottomMargin, SIGNAL(valueChanged(double)), this, SLOT(setBottomMargin(double)));
+
+ connect(widget.portrait, SIGNAL(clicked()), this, SLOT(_q_pageOrientationChanged()));
+ connect(widget.landscape, SIGNAL(clicked()), this, SLOT(_q_pageOrientationChanged()));
+}
+
+void QPageSetupWidget::setPrinter(QPrinter *printer)
+{
+ m_printer = printer;
+ m_blockSignals = true;
+ selectPdfPsPrinter(printer);
+ printer->getPageMargins(&m_leftMargin, &m_topMargin, &m_rightMargin, &m_bottomMargin, QPrinter::Point);
+ unitChanged(widget.unit->currentIndex());
+ m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+ m_paperSize = printer->paperSize(QPrinter::Point);
+ widget.paperWidth->setValue(m_paperSize.width() / m_currentMultiplier);
+ widget.paperHeight->setValue(m_paperSize.height() / m_currentMultiplier);
+
+ widget.landscape->setChecked(printer->orientation() == QPrinter::Landscape);
+
+#ifdef PSD_ENABLE_PAPERSOURCE
+ widget.paperSource->setCurrentItem(printer->paperSource());
+#endif
+ Q_ASSERT(m_blockSignals);
+ m_blockSignals = false;
+ _q_paperSizeChanged();
+}
+
+// set gui data on printer
+void QPageSetupWidget::setupPrinter() const
+{
+ QPrinter::Orientation orientation = widget.portrait->isChecked()
+ ? QPrinter::Portrait
+ : QPrinter::Landscape;
+ m_printer->setOrientation(orientation);
+ // paper format
+ QVariant val = widget.paperSize->itemData(widget.paperSize->currentIndex());
+ int ps = m_printer->pageSize();
+ if (val.type() == QVariant::Int) {
+ ps = val.toInt();
+ }
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ else if (m_cups && QCUPSSupport::isAvailable() && m_cups->currentPPD()) {
+ QByteArray cupsPageSize = val.toByteArray();
+ QPrintEngine *engine = m_printer->printEngine();
+ engine->setProperty(PPK_CupsStringPageSize, QString::fromLatin1(cupsPageSize));
+ engine->setProperty(PPK_CupsOptions, m_cups->options());
+
+ QRect pageRect = m_cups->pageRect(cupsPageSize);
+ engine->setProperty(PPK_CupsPageRect, pageRect);
+
+ QRect paperRect = m_cups->paperRect(cupsPageSize);
+ engine->setProperty(PPK_CupsPaperRect, paperRect);
+
+ for(ps = 0; ps < QPrinter::NPaperSize; ++ps) {
+ QPdf::PaperSize size = QPdf::paperSize(QPrinter::PaperSize(ps));
+ if (size.width == paperRect.width() && size.height == paperRect.height())
+ break;
+ }
+ }
+#endif
+ if (ps == QPrinter::Custom)
+ m_printer->setPaperSize(sizeForOrientation(orientation, m_paperSize), QPrinter::Point);
+ else
+ m_printer->setPaperSize(static_cast<QPrinter::PaperSize>(ps));
+
+#ifdef PSD_ENABLE_PAPERSOURCE
+ m_printer->setPaperSource((QPrinter::PaperSource)widget.paperSource->currentIndex());
+#endif
+ m_printer->setPageMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin, QPrinter::Point);
+
+}
+
+void QPageSetupWidget::selectPrinter(QCUPSSupport *cups)
+{
+ m_cups = cups;
+ widget.paperSize->clear();
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (m_cups && QCUPSSupport::isAvailable()) {
+ const ppd_option_t* pageSizes = m_cups->pageSizes();
+ const int numChoices = pageSizes ? pageSizes->num_choices : 0;
+
+ int cupsDefaultSize = 0;
+ QSize qtPreferredSize = m_printer->paperSize(QPrinter::Point).toSize();
+ bool preferredSizeMatched = false;
+ for (int i = 0; i < numChoices; ++i) {
+ widget.paperSize->addItem(QString::fromLocal8Bit(pageSizes->choices[i].text), QByteArray(pageSizes->choices[i].choice));
+ if (static_cast<int>(pageSizes->choices[i].marked) == 1)
+ cupsDefaultSize = i;
+ if (m_printer->d_func()->hasUserSetPageSize) {
+ QRect cupsPaperSize = m_cups->paperRect(pageSizes->choices[i].choice);
+ QSize diff = cupsPaperSize.size() - qtPreferredSize;
+ if (qAbs(diff.width()) < 5 && qAbs(diff.height()) < 5) {
+ widget.paperSize->setCurrentIndex(i);
+ preferredSizeMatched = true;
+ }
+ }
+ }
+ if (!preferredSizeMatched)
+ widget.paperSize->setCurrentIndex(cupsDefaultSize);
+ if (m_printer->d_func()->hasCustomPageMargins) {
+ m_printer->getPageMargins(&m_leftMargin, &m_topMargin, &m_rightMargin, &m_bottomMargin, QPrinter::Point);
+ } else {
+ QByteArray cupsPaperSizeChoice = widget.paperSize->itemData(widget.paperSize->currentIndex()).toByteArray();
+ QRect paper = m_cups->paperRect(cupsPaperSizeChoice);
+ QRect content = m_cups->pageRect(cupsPaperSizeChoice);
+
+ m_leftMargin = content.x() - paper.x();
+ m_topMargin = content.y() - paper.y();
+ m_rightMargin = paper.right() - content.right();
+ m_bottomMargin = paper.bottom() - content.bottom();
+ }
+ }
+#endif
+ if (widget.paperSize->count() == 0) {
+ populatePaperSizes(widget.paperSize);
+ widget.paperSize->setCurrentIndex(widget.paperSize->findData(
+ QLocale::system().measurementSystem() == QLocale::ImperialSystem ? QPrinter::Letter : QPrinter::A4));
+ }
+
+ unitChanged(widget.unit->currentIndex());
+ m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+}
+
+void QPageSetupWidget::selectPdfPsPrinter(const QPrinter *p)
+{
+ m_cups = 0;
+ widget.paperSize->clear();
+ populatePaperSizes(widget.paperSize);
+ widget.paperSize->setCurrentIndex(widget.paperSize->findData(p->paperSize()));
+
+ m_leftMargin = 90;
+ m_topMargin = 72;
+ m_bottomMargin = 72;
+ m_rightMargin = 90;
+ unitChanged(widget.unit->currentIndex());
+ m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+}
+
+// Updates size/preview after the combobox has been changed.
+void QPageSetupWidget::_q_paperSizeChanged()
+{
+ QVariant val = widget.paperSize->itemData(widget.paperSize->currentIndex());
+ int index = m_printer->pageSize();
+ if (val.type() == QVariant::Int) {
+ index = val.toInt();
+ }
+
+ if (m_blockSignals) return;
+ m_blockSignals = true;
+
+ QPrinter::PaperSize size = QPrinter::PaperSize(index);
+ QPrinter::Orientation orientation = widget.portrait->isChecked()
+ ? QPrinter::Portrait
+ : QPrinter::Landscape;
+
+ bool custom = size == QPrinter::Custom;
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ custom = custom ? !m_cups : custom;
+#endif
+
+ widget.paperWidth->setEnabled(custom);
+ widget.paperHeight->setEnabled(custom);
+ widget.widthLabel->setEnabled(custom);
+ widget.heightLabel->setEnabled(custom);
+ if (custom) {
+ m_paperSize.setWidth( widget.paperWidth->value() * m_currentMultiplier);
+ m_paperSize.setHeight( widget.paperHeight->value() * m_currentMultiplier);
+ m_pagePreview->setPaperSize(m_paperSize);
+ } else {
+ Q_ASSERT(m_printer);
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (m_cups) { // combobox is filled with cups based data
+ QByteArray cupsPageSize = widget.paperSize->itemData(widget.paperSize->currentIndex()).toByteArray();
+ m_paperSize = m_cups->paperRect(cupsPageSize).size();
+ if (orientation == QPrinter::Landscape)
+ m_paperSize = QSizeF(m_paperSize.height(), m_paperSize.width()); // swap
+ }
+ else
+#endif
+ m_paperSize = qt_printerPaperSize(orientation, size, QPrinter::Point, 1);
+
+ m_pagePreview->setPaperSize(m_paperSize);
+ widget.paperWidth->setValue(m_paperSize.width() / m_currentMultiplier);
+ widget.paperHeight->setValue(m_paperSize.height() / m_currentMultiplier);
+ }
+ m_blockSignals = false;
+}
+
+void QPageSetupWidget::_q_pageOrientationChanged()
+{
+ if (QPrinter::PaperSize(widget.paperSize->currentIndex()) == QPrinter::Custom) {
+ double tmp = widget.paperWidth->value();
+ widget.paperWidth->setValue(widget.paperHeight->value());
+ widget.paperHeight->setValue(tmp);
+ }
+ _q_paperSizeChanged();
+}
+
+extern double qt_multiplierForUnit(QPrinter::Unit unit, int resolution);
+
+void QPageSetupWidget::unitChanged(int item)
+{
+ QString suffix;
+ switch(item) {
+ case 0:
+ m_currentMultiplier = 10 * qt_multiplierForUnit(QPrinter::Millimeter, 1);
+ suffix = QString::fromLatin1(" cm");
+ break;
+ case 2:
+ m_currentMultiplier = qt_multiplierForUnit(QPrinter::Inch, 1);
+ suffix = QString::fromLatin1(" in");
+ break;
+ case 3:
+ m_currentMultiplier = qt_multiplierForUnit(QPrinter::Point, 1);
+ suffix = QString::fromLatin1(" pt");
+ break;
+ case 1:
+ default:
+ m_currentMultiplier = qt_multiplierForUnit(QPrinter::Millimeter, 1);
+ suffix = QString::fromLatin1(" mm");
+ break;
+ }
+ const bool old = m_blockSignals;
+ m_blockSignals = true;
+ widget.topMargin->setSuffix(suffix);
+ widget.leftMargin->setSuffix(suffix);
+ widget.rightMargin->setSuffix(suffix);
+ widget.bottomMargin->setSuffix(suffix);
+ widget.paperWidth->setSuffix(suffix);
+ widget.paperHeight->setSuffix(suffix);
+ widget.topMargin->setValue(m_topMargin / m_currentMultiplier);
+ widget.leftMargin->setValue(m_leftMargin / m_currentMultiplier);
+ widget.rightMargin->setValue(m_rightMargin / m_currentMultiplier);
+ widget.bottomMargin->setValue(m_bottomMargin / m_currentMultiplier);
+ widget.paperWidth->setValue(m_paperSize.width() / m_currentMultiplier);
+ widget.paperHeight->setValue(m_paperSize.height() / m_currentMultiplier);
+ m_blockSignals = old;
+}
+
+void QPageSetupWidget::setTopMargin(double newValue)
+{
+ if (m_blockSignals) return;
+ m_topMargin = newValue * m_currentMultiplier;
+ m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+}
+
+void QPageSetupWidget::setBottomMargin(double newValue)
+{
+ if (m_blockSignals) return;
+ m_bottomMargin = newValue * m_currentMultiplier;
+ m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+}
+
+void QPageSetupWidget::setLeftMargin(double newValue)
+{
+ if (m_blockSignals) return;
+ m_leftMargin = newValue * m_currentMultiplier;
+ m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+}
+
+void QPageSetupWidget::setRightMargin(double newValue)
+{
+ if (m_blockSignals) return;
+ m_rightMargin = newValue * m_currentMultiplier;
+ m_pagePreview->setMargins(m_leftMargin, m_topMargin, m_rightMargin, m_bottomMargin);
+}
+
+
+
+QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
+ : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), printer, parent)
+{
+ Q_D(QPageSetupDialog);
+ d->init();
+}
+
+
+QPageSetupDialog::QPageSetupDialog(QWidget *parent)
+ : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), 0, parent)
+{
+ Q_D(QPageSetupDialog);
+ d->init();
+}
+
+/*!
+ \internal
+*/
+int QPageSetupDialog::exec()
+{
+ Q_D(QPageSetupDialog);
+
+ int ret = QDialog::exec();
+ if (ret == Accepted)
+ d->widget->setupPrinter();
+ return ret;
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_qpagesetupdialog.cpp"
+
+#endif // QT_NO_PRINTDIALOG
diff --git a/src/widgets/dialogs/qpagesetupdialog_unix_p.h b/src/widgets/dialogs/qpagesetupdialog_unix_p.h
new file mode 100644
index 0000000000..fea70b6bfe
--- /dev/null
+++ b/src/widgets/dialogs/qpagesetupdialog_unix_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QPAGESETUPWIDGET_H
+#define QPAGESETUPWIDGET_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 "qglobal.h"
+
+#ifndef QT_NO_PRINTDIALOG
+
+#include <ui_qpagesetupwidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPrinter;
+class QPagePreview;
+class QCUPSSupport;
+
+class QPageSetupWidget : public QWidget {
+ Q_OBJECT
+public:
+ QPageSetupWidget(QWidget *parent = 0);
+ QPageSetupWidget(QPrinter *printer, QWidget *parent = 0);
+ void setPrinter(QPrinter *printer);
+ /// copy information from the widget and apply that to the printer.
+ void setupPrinter() const;
+ void selectPrinter(QCUPSSupport *m_cups);
+ void selectPdfPsPrinter(const QPrinter *p);
+
+private slots:
+ void _q_pageOrientationChanged();
+ void _q_paperSizeChanged();
+ void unitChanged(int item);
+ void setTopMargin(double newValue);
+ void setBottomMargin(double newValue);
+ void setLeftMargin(double newValue);
+ void setRightMargin(double newValue);
+
+private:
+ Ui::QPageSetupWidget widget;
+ QPagePreview *m_pagePreview;
+ QPrinter *m_printer;
+ qreal m_leftMargin;
+ qreal m_topMargin;
+ qreal m_rightMargin;
+ qreal m_bottomMargin;
+ QSizeF m_paperSize;
+ qreal m_currentMultiplier;
+ bool m_blockSignals;
+ QCUPSSupport *m_cups;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_PRINTDIALOG
+#endif
diff --git a/src/widgets/dialogs/qpagesetupdialog_win.cpp b/src/widgets/dialogs/qpagesetupdialog_win.cpp
new file mode 100644
index 0000000000..d74da7c2fc
--- /dev/null
+++ b/src/widgets/dialogs/qpagesetupdialog_win.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpagesetupdialog.h"
+
+#ifndef QT_NO_PRINTDIALOG
+#include <qapplication.h>
+
+#include <private/qprintengine_win_p.h>
+#include <private/qabstractpagesetupdialog_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPageSetupDialogPrivate : public QAbstractPageSetupDialogPrivate
+{
+};
+
+QPageSetupDialog::QPageSetupDialog(QPrinter *printer, QWidget *parent)
+ : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), printer, parent)
+{
+}
+
+QPageSetupDialog::QPageSetupDialog(QWidget *parent)
+ : QAbstractPageSetupDialog(*(new QPageSetupDialogPrivate), 0, parent)
+{
+}
+
+int QPageSetupDialog::exec()
+{
+ Q_D(QPageSetupDialog);
+
+ if (d->printer->outputFormat() != QPrinter::NativeFormat)
+ return Rejected;
+
+ QWin32PrintEngine *engine = static_cast<QWin32PrintEngine*>(d->printer->paintEngine());
+ QWin32PrintEnginePrivate *ep = static_cast<QWin32PrintEnginePrivate *>(engine->d_ptr.data());
+
+ PAGESETUPDLG psd;
+ memset(&psd, 0, sizeof(PAGESETUPDLG));
+ psd.lStructSize = sizeof(PAGESETUPDLG);
+
+ // we need a temp DEVMODE struct if we don't have a global DEVMODE
+ HGLOBAL hDevMode = 0;
+ int devModeSize = 0;
+ if (!ep->globalDevMode) {
+ devModeSize = sizeof(DEVMODE) + ep->devMode->dmDriverExtra;
+ hDevMode = GlobalAlloc(GHND, devModeSize);
+ if (hDevMode) {
+ void *dest = GlobalLock(hDevMode);
+ memcpy(dest, ep->devMode, devModeSize);
+ GlobalUnlock(hDevMode);
+ }
+ psd.hDevMode = hDevMode;
+ } else {
+ psd.hDevMode = ep->devMode;
+ }
+
+ HGLOBAL *tempDevNames = ep->createDevNames();
+ psd.hDevNames = tempDevNames;
+
+ QWidget *parent = parentWidget();
+ parent = parent ? parent->window() : QApplication::activeWindow();
+ Q_ASSERT(!parent ||parent->testAttribute(Qt::WA_WState_Created));
+ psd.hwndOwner = parent ? parent->winId() : 0;
+
+ QRect paperRect = d->printer->paperRect();
+ QRect pageRect = d->printer->pageRect();
+
+ psd.Flags = PSD_MARGINS;
+ double multiplier = 1;
+ switch (QLocale::system().measurementSystem()) {
+ case QLocale::MetricSystem:
+ psd.Flags |= PSD_INHUNDREDTHSOFMILLIMETERS;
+ multiplier = 1;
+ break;
+ case QLocale::ImperialSystem:
+ psd.Flags |= PSD_INTHOUSANDTHSOFINCHES;
+ multiplier = 25.4/10;
+ break;
+ }
+
+ QRect marginRect = ep->getPageMargins();
+ psd.rtMargin.left = marginRect.left() / multiplier;
+ psd.rtMargin.top = marginRect.top() / multiplier;
+ psd.rtMargin.right = marginRect.width() / multiplier;;
+ psd.rtMargin.bottom = marginRect.height() / multiplier;;
+
+ bool result = PageSetupDlg(&psd);
+ if (result) {
+ ep->readDevnames(psd.hDevNames);
+ ep->readDevmode(psd.hDevMode);
+
+ QRect theseMargins = QRect(psd.rtMargin.left * multiplier,
+ psd.rtMargin.top * multiplier,
+ psd.rtMargin.right * multiplier,
+ psd.rtMargin.bottom * multiplier);
+
+ if (theseMargins != marginRect) {
+ ep->setPageMargins(psd.rtMargin.left * multiplier,
+ psd.rtMargin.top * multiplier,
+ psd.rtMargin.right * multiplier,
+ psd.rtMargin.bottom * multiplier);
+ }
+
+ ep->updateCustomPaperSize();
+
+ // copy from our temp DEVMODE struct
+ if (!ep->globalDevMode && hDevMode) {
+ void *src = GlobalLock(hDevMode);
+ memcpy(ep->devMode, src, devModeSize);
+ GlobalUnlock(hDevMode);
+ }
+ }
+
+ if (!ep->globalDevMode && hDevMode)
+ GlobalFree(hDevMode);
+ GlobalFree(tempDevNames);
+ done(result);
+ return result;
+}
+
+void QPageSetupDialog::setVisible(bool visible)
+{
+ if (!visible)
+ return;
+ exec();
+}
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/widgets/dialogs/qpagesetupwidget.ui b/src/widgets/dialogs/qpagesetupwidget.ui
new file mode 100644
index 0000000000..ace2ab8f44
--- /dev/null
+++ b/src/widgets/dialogs/qpagesetupwidget.ui
@@ -0,0 +1,353 @@
+<ui version="4.0" >
+ <class>QPageSetupWidget</class>
+ <widget class="QWidget" name="QPageSetupWidget" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>416</width>
+ <height>488</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item row="0" column="0" colspan="2" >
+ <layout class="QHBoxLayout" name="horizontalLayout_4" >
+ <item>
+ <widget class="QComboBox" name="unit" />
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QGroupBox" name="groupBox_2" >
+ <property name="title" >
+ <string>Paper</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="pageSizeLabel" >
+ <property name="text" >
+ <string>Page size:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>paperSize</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="paperSize" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="widthLabel" >
+ <property name="text" >
+ <string>Width:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>paperWidth</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <layout class="QHBoxLayout" name="horizontalLayout_3" >
+ <item>
+ <widget class="QDoubleSpinBox" name="paperWidth" >
+ <property name="maximum" >
+ <double>9999.989999999999782</double>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="heightLabel" >
+ <property name="text" >
+ <string>Height:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>paperHeight</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="paperHeight" >
+ <property name="maximum" >
+ <double>9999.989999999999782</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="paperSourceLabel" >
+ <property name="text" >
+ <string>Paper source:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>paperSource</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="paperSource" />
+ </item>
+ <item row="1" column="2" >
+ <spacer name="horizontalSpacer_4" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QGroupBox" name="groupBox_3" >
+ <property name="title" >
+ <string>Orientation</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" >
+ <item>
+ <widget class="QRadioButton" name="portrait" >
+ <property name="text" >
+ <string>Portrait</string>
+ </property>
+ <property name="checked" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="landscape" >
+ <property name="text" >
+ <string>Landscape</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="reverseLandscape" >
+ <property name="text" >
+ <string>Reverse landscape</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="reversePortrait" >
+ <property name="text" >
+ <string>Reverse portrait</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_5" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item rowspan="2" row="2" column="1" >
+ <widget class="QWidget" native="1" name="preview" />
+ </item>
+ <item row="3" column="0" >
+ <widget class="QGroupBox" name="groupBox" >
+ <property name="title" >
+ <string>Margins</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" >
+ <item>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="1" >
+ <widget class="QDoubleSpinBox" name="topMargin" >
+ <property name="toolTip" >
+ <string>top margin</string>
+ </property>
+ <property name="accessibleName" >
+ <string>top margin</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="maximum" >
+ <double>999.990000000000009</double>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="3" >
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <spacer name="horizontalSpacer_7" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="leftMargin" >
+ <property name="toolTip" >
+ <string>left margin</string>
+ </property>
+ <property name="accessibleName" >
+ <string>left margin</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="maximum" >
+ <double>999.990000000000009</double>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="rightMargin" >
+ <property name="toolTip" >
+ <string>right margin</string>
+ </property>
+ <property name="accessibleName" >
+ <string>right margin</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="maximum" >
+ <double>999.990000000000009</double>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_8" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QDoubleSpinBox" name="bottomMargin" >
+ <property name="toolTip" >
+ <string>bottom margin</string>
+ </property>
+ <property name="accessibleName" >
+ <string>bottom margin</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="maximum" >
+ <double>999.990000000000009</double>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <spacer name="horizontalSpacer_2" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0" >
+ <spacer name="horizontalSpacer_5" >
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType" >
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <spacer name="verticalSpacer" >
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0" >
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/widgets/dialogs/qprintdialog.h b/src/widgets/dialogs/qprintdialog.h
new file mode 100644
index 0000000000..05431608c4
--- /dev/null
+++ b/src/widgets/dialogs/qprintdialog.h
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPRINTDIALOG_H
+#define QPRINTDIALOG_H
+
+#include <QtGui/qabstractprintdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_PRINTDIALOG
+
+class QPrintDialogPrivate;
+class QPushButton;
+class QPrinter;
+
+#if defined (Q_OS_UNIX) && !defined(QTOPIA_PRINTDIALOG) && !defined(Q_WS_MAC) && !defined(Q_OS_SYMBIAN)
+class QUnixPrintWidgetPrivate;
+
+class Q_GUI_EXPORT QUnixPrintWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ QUnixPrintWidget(QPrinter *printer, QWidget *parent = 0);
+ ~QUnixPrintWidget();
+ void updatePrinter();
+
+private:
+ friend class QPrintDialogPrivate;
+ friend class QUnixPrintWidgetPrivate;
+ QUnixPrintWidgetPrivate *d;
+ Q_PRIVATE_SLOT(d, void _q_printerChanged(int))
+ Q_PRIVATE_SLOT(d, void _q_btnBrowseClicked())
+ Q_PRIVATE_SLOT(d, void _q_btnPropertiesClicked())
+};
+#endif
+
+class Q_GUI_EXPORT QPrintDialog : public QAbstractPrintDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPrintDialog)
+ Q_ENUMS(PrintDialogOption)
+ Q_PROPERTY(PrintDialogOptions options READ options WRITE setOptions)
+
+public:
+ explicit QPrintDialog(QPrinter *printer, QWidget *parent = 0);
+ explicit QPrintDialog(QWidget *parent = 0);
+ ~QPrintDialog();
+
+ int exec();
+#if defined (Q_OS_UNIX) && !defined(QTOPIA_PRINTDIALOG) && !defined(Q_WS_MAC)
+ virtual void accept();
+#endif
+ void done(int result);
+
+#if defined (Q_OS_UNIX) && defined (QT3_SUPPORT)
+ QT3_SUPPORT void setPrinter(QPrinter *, bool = false);
+ QT3_SUPPORT QPrinter *printer() const;
+ QT3_SUPPORT void addButton(QPushButton *button);
+#endif
+
+ void setOption(PrintDialogOption option, bool on = true);
+ bool testOption(PrintDialogOption option) const;
+ void setOptions(PrintDialogOptions options);
+ PrintDialogOptions options() const;
+
+#if defined(Q_OS_UNIX) || defined(Q_WS_MAC) || defined(Q_OS_WIN)
+ 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);
+
+#ifdef qdoc
+ QPrinter *printer();
+#endif
+
+#ifdef QTOPIA_PRINTDIALOG
+public:
+ bool eventFilter(QObject *, QEvent *);
+#endif
+
+#ifdef Q_NO_USING_KEYWORD
+#ifndef Q_QDOC
+ void accepted() { QDialog::accepted(); }
+#endif
+#else
+ using QDialog::accepted;
+#endif
+
+Q_SIGNALS:
+ void accepted(QPrinter *printer);
+
+private:
+#ifndef QTOPIA_PRINTDIALOG
+ Q_PRIVATE_SLOT(d_func(), void _q_chbPrintLastFirstToggled(bool))
+#if defined (Q_OS_UNIX) && !defined (Q_OS_MAC)
+ Q_PRIVATE_SLOT(d_func(), void _q_collapseOrExpandDialog())
+#endif
+# if defined(Q_OS_UNIX) && !defined (Q_OS_MAC) && !defined(QT_NO_MESSAGEBOX)
+ Q_PRIVATE_SLOT(d_func(), void _q_checkFields())
+# endif
+#else // QTOPIA_PRINTDIALOG
+ Q_PRIVATE_SLOT(d_func(), void _q_okClicked())
+ Q_PRIVATE_SLOT(d_func(),void _q_printerOrFileSelected(QAbstractButton *b))
+ Q_PRIVATE_SLOT(d_func(),void _q_paperSizeSelected(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_orientSelected(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_pageOrderSelected(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_colorModeSelected(QAbstractButton *))
+ Q_PRIVATE_SLOT(d_func(), void _q_setNumCopies(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_printRangeSelected(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_setFirstPage(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_setLastPage(int))
+ Q_PRIVATE_SLOT(d_func(), void _q_fileNameEditChanged(const QString &text))
+#endif // QTOPIA_PRINTDIALOG
+ friend class QUnixPrintWidget;
+};
+
+#endif // QT_NO_PRINTDIALOG
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPRINTDIALOG_H
diff --git a/src/widgets/dialogs/qprintdialog.qdoc b/src/widgets/dialogs/qprintdialog.qdoc
new file mode 100644
index 0000000000..0fff9dd450
--- /dev/null
+++ b/src/widgets/dialogs/qprintdialog.qdoc
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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 documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef QT3_SUPPORT
+/*!
+ \fn QPrinter *QPrintDialog::printer() const
+
+ Returns a pointer to the printer this dialog configures, or 0 if
+ this dialog does not operate on any printer.
+
+ This function is available for Unix platforms only.
+*/
+
+/*!
+ \fn void QPrintDialog::setPrinter(QPrinter *printer, bool pickupSettings)
+
+ Sets this dialog to configure printer \a printer, or no printer if \a printer
+ is null. If \a pickupSettings is true, the dialog reads most of
+ its settings from \a printer. If \a pickupSettings is false (the
+ default) the dialog keeps its old settings.
+
+ This function is available for Unix platforms only.
+*/
+
+/*!
+ \fn void QPrintDialog::addButton(QPushButton *button)
+
+ Adds the \a button to the layout of the print dialog. The added
+ buttons are arranged from the left to the right below the
+ last groupbox of the printdialog.
+
+ This function is available for Unix platforms only.
+*/
+#endif
diff --git a/src/widgets/dialogs/qprintdialog.qrc b/src/widgets/dialogs/qprintdialog.qrc
new file mode 100644
index 0000000000..f54eb6b5ee
--- /dev/null
+++ b/src/widgets/dialogs/qprintdialog.qrc
@@ -0,0 +1,38 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/trolltech/dialogs/qprintpreviewdialog">
+<file>images/fit-page-24.png</file>
+<file>images/fit-page-32.png</file>
+<file>images/fit-width-24.png</file>
+<file>images/fit-width-32.png</file>
+<file>images/go-first-24.png</file>
+<file>images/go-first-32.png</file>
+<file>images/go-last-24.png</file>
+<file>images/go-last-32.png</file>
+<file>images/go-next-24.png</file>
+<file>images/go-next-32.png</file>
+<file>images/go-previous-24.png</file>
+<file>images/go-previous-32.png</file>
+<file>images/layout-landscape-24.png</file>
+<file>images/layout-landscape-32.png</file>
+<file>images/layout-portrait-24.png</file>
+<file>images/layout-portrait-32.png</file>
+<file>images/page-setup-24.png</file>
+<file>images/page-setup-32.png</file>
+<file>images/print-24.png</file>
+<file>images/print-32.png</file>
+<file>images/view-page-multi-24.png</file>
+<file>images/view-page-multi-32.png</file>
+<file>images/view-page-one-24.png</file>
+<file>images/view-page-one-32.png</file>
+<file>images/view-page-sided-24.png</file>
+<file>images/view-page-sided-32.png</file>
+<file>images/zoom-in-24.png</file>
+<file>images/zoom-in-32.png</file>
+<file>images/zoom-out-24.png</file>
+<file>images/zoom-out-32.png</file>
+</qresource>
+<qresource prefix="/trolltech/dialogs/qprintdialog">
+<file>images/status-color.png</file>
+<file>images/status-gray-scale.png</file>
+</qresource>
+</RCC>
diff --git a/src/widgets/dialogs/qprintdialog_mac.mm b/src/widgets/dialogs/qprintdialog_mac.mm
new file mode 100644
index 0000000000..ed60b1016f
--- /dev/null
+++ b/src/widgets/dialogs/qprintdialog_mac.mm
@@ -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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_PRINTDIALOG
+
+#include <private/qt_mac_p.h>
+
+#include <qhash.h>
+#include <qprintdialog.h>
+#include <private/qapplication_p.h>
+#include <private/qabstractprintdialog_p.h>
+#include <private/qprintengine_mac_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QPrintDialog)
+
+public:
+ QPrintDialogPrivate() : ep(0), printPanel(0)
+#ifndef QT_MAC_USE_COCOA
+ ,upp(0)
+#endif
+ {}
+#ifndef QT_MAC_USE_COCOA
+ ~QPrintDialogPrivate() {
+ if (upp) {
+ DisposePMSheetDoneUPP(upp);
+ upp = 0;
+ }
+ QHash<PMPrintSession, QPrintDialogPrivate *>::iterator it = sheetCallbackMap.begin();
+ while (it != sheetCallbackMap.end()) {
+ if (it.value() == this) {
+ it = sheetCallbackMap.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+#endif
+
+#ifndef QT_MAC_USE_COCOA
+ void openCarbonPrintPanel(Qt::WindowModality modality);
+ void closeCarbonPrintPanel();
+ static void printDialogSheetDoneCallback(PMPrintSession printSession, WindowRef /*documentWindow*/, Boolean accepted) {
+ QPrintDialogPrivate *priv = sheetCallbackMap.value(printSession);
+ if (!priv) {
+ qWarning("%s:%d: QPrintDialog::exec: Could not retrieve data structure, "
+ "you most likely now have an infinite loop", __FILE__, __LINE__);
+ return;
+ }
+ priv->q_func()->done(accepted ? QDialog::Accepted : QDialog::Rejected);
+ priv->closeCarbonPrintPanel();
+ }
+#else
+ void openCocoaPrintPanel(Qt::WindowModality modality);
+ void closeCocoaPrintPanel();
+#endif
+ void initBeforeRun();
+
+ inline QPrintDialog *printDialog() { return q_func(); }
+
+ inline void _q_printToFileChanged(int) {}
+ inline void _q_rbPrintRangeToggled(bool) {}
+ inline void _q_printerChanged(int) {}
+#ifndef QT_NO_MESSAGEBOX
+ inline void _q_checkFields() {}
+#endif
+ inline void _q_chbPrintLastFirstToggled(bool) {}
+ inline void _q_paperSizeChanged(int) {}
+ inline void _q_btnBrowseClicked() {}
+ inline void _q_btnPropertiesClicked() {}
+
+ QMacPrintEnginePrivate *ep;
+ NSPrintPanel *printPanel;
+#ifndef QT_MAC_USE_COCOA
+ PMSheetDoneUPP upp;
+ static QHash<PMPrintSession, QPrintDialogPrivate *> sheetCallbackMap;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+#ifdef QT_MAC_USE_COCOA
+
+@class QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate);
+
+@interface QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) : NSObject {
+}
+- (void)printPanelDidEnd:(NSPrintPanel *)printPanel
+ returnCode:(int)returnCode contextInfo:(void *)contextInfo;
+@end
+
+@implementation QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate)
+- (void)printPanelDidEnd:(NSPrintPanel *)printPanel
+ returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ Q_UNUSED(printPanel);
+
+ QPrintDialogPrivate *d = static_cast<QPrintDialogPrivate *>(contextInfo);
+ QPrintDialog *dialog = d->printDialog();
+
+ if (returnCode == NSOKButton) {
+ UInt32 frompage, topage;
+ PMGetFirstPage(d->ep->settings, &frompage);
+ PMGetLastPage(d->ep->settings, &topage);
+ topage = qMin(UInt32(INT_MAX), topage);
+ dialog->setFromTo(frompage, topage);
+
+ // OK, I need to map these values back let's see
+ // If from is 1 and to is INT_MAX, then print it all
+ // (Apologies to the folks with more than INT_MAX pages)
+ if (dialog->fromPage() == 1 && dialog->toPage() == INT_MAX) {
+ dialog->setPrintRange(QPrintDialog::AllPages);
+ dialog->setFromTo(0, 0);
+ } else {
+ dialog->setPrintRange(QPrintDialog::PageRange); // In a way a lie, but it shouldn't hurt.
+ // Carbon hands us back a very large number here even for ALL, set it to max
+ // in that case to follow the behavior of the other print dialogs.
+ if (dialog->maxPage() < dialog->toPage())
+ dialog->setFromTo(dialog->fromPage(), dialog->maxPage());
+ }
+ // Keep us in sync with file output
+ PMDestinationType dest;
+
+ // If the user selected print to file, the session has been
+ // changed behind our back and our d->ep->session object is a
+ // dangling pointer. Update it based on the "current" session
+ d->ep->session = static_cast<PMPrintSession>([d->ep->printInfo PMPrintSession]);
+
+ PMSessionGetDestinationType(d->ep->session, d->ep->settings, &dest);
+ if (dest == kPMDestinationFile) {
+ QCFType<CFURLRef> file;
+ PMSessionCopyDestinationLocation(d->ep->session, d->ep->settings, &file);
+ UInt8 localFile[2048]; // Assuming there's a POSIX file system here.
+ CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile));
+ d->ep->outputFilename
+ = QString::fromUtf8(reinterpret_cast<const char *>(localFile));
+ } else {
+ // Keep output format.
+ QPrinter::OutputFormat format;
+ format = d->printer->outputFormat();
+ d->printer->setOutputFileName(QString());
+ d->printer->setOutputFormat(format);
+ }
+ }
+
+ dialog->done((returnCode == NSOKButton) ? QDialog::Accepted : QDialog::Rejected);
+}
+@end
+
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern void macStartInterceptWindowTitle(QWidget *window);
+extern void macStopInterceptWindowTitle();
+
+
+void QPrintDialogPrivate::initBeforeRun()
+{
+ Q_Q(QPrintDialog);
+ // If someone is reusing a QPrinter object, the end released all our old
+ // information. In this case, we must reinitialize.
+ if (ep->session == 0)
+ ep->initialize();
+
+
+ // It seems the only way that PM lets you use all is if the minimum
+ // for the page range is 1. This _kind of_ makes sense if you think about
+ // it. However, calling PMSetFirstPage() or PMSetLastPage() always enforces
+ // the range.
+ PMSetPageRange(ep->settings, q->minPage(), q->maxPage());
+ if (q->printRange() == QAbstractPrintDialog::PageRange) {
+ PMSetFirstPage(ep->settings, q->fromPage(), false);
+ PMSetLastPage(ep->settings, q->toPage(), false);
+ }
+}
+
+#ifndef QT_MAC_USE_COCOA
+QHash<PMPrintSession, QPrintDialogPrivate *> QPrintDialogPrivate::sheetCallbackMap;
+void QPrintDialogPrivate::openCarbonPrintPanel(Qt::WindowModality modality)
+{
+ Q_Q(QPrintDialog);
+ initBeforeRun();
+ sheetCallbackMap.insert(ep->session, this);
+ if (modality == Qt::ApplicationModal) {
+ QWidget modal_widg(0, Qt::Window);
+ modal_widg.setObjectName(QLatin1String(__FILE__ "__modal_dlg"));
+ modal_widg.createWinId();
+ QApplicationPrivate::enterModal(&modal_widg);
+ QApplicationPrivate::native_modal_dialog_active = true;
+ Boolean acceptStatus;
+ PMSessionPrintDialog(ep->session, ep->settings, ep->format, &acceptStatus);
+ QApplicationPrivate::leaveModal(&modal_widg);
+ QApplicationPrivate::native_modal_dialog_active = false;
+ printDialogSheetDoneCallback(ep->session, 0, acceptStatus);
+ } else {
+ // Window Modal means that we use a sheet at the moment, there's no other way to do it correctly.
+ if (!upp)
+ upp = NewPMSheetDoneUPP(QPrintDialogPrivate::printDialogSheetDoneCallback);
+ PMSessionUseSheets(ep->session, qt_mac_window_for(q->parentWidget()), upp);
+ QApplicationPrivate::native_modal_dialog_active = true;
+ Boolean unused;
+ PMSessionPrintDialog(ep->session, ep->settings, ep->format, &unused);
+ }
+}
+
+void QPrintDialogPrivate::closeCarbonPrintPanel()
+{
+ Q_Q(QPrintDialog);
+ QApplicationPrivate::native_modal_dialog_active = false;
+ if (q->result() == QDialog::Accepted) {
+ UInt32 frompage, topage;
+ PMGetFirstPage(ep->settings, &frompage);
+ PMGetLastPage(ep->settings, &topage);
+ topage = qMin(UInt32(INT_MAX), topage);
+ q->setFromTo(frompage, topage);
+
+ // OK, I need to map these values back let's see
+ // If from is 1 and to is INT_MAX, then print it all
+ // (Apologies to the folks with more than INT_MAX pages)
+ // ...that's a joke.
+ if (q->fromPage() == 1 && q->toPage() == INT_MAX) {
+ q->setPrintRange(QAbstractPrintDialog::AllPages);
+ q->setFromTo(0,0);
+ } else {
+ q->setPrintRange(QAbstractPrintDialog::PageRange); // In a way a lie, but it shouldn't hurt.
+ // Carbon hands us back a very large number here even for ALL, set it to max
+ // in that case to follow the behavior of the other print dialogs.
+ if (q->maxPage() < q->toPage())
+ q->setFromTo(q->fromPage(), q->maxPage());
+ }
+ // Keep us in sync with file output
+ PMDestinationType dest;
+ PMSessionGetDestinationType(ep->session, ep->settings, &dest);
+ if (dest == kPMDestinationFile) {
+ QCFType<CFURLRef> file;
+ PMSessionCopyDestinationLocation(ep->session, ep->settings, &file);
+ UInt8 localFile[2048]; // Assuming there's a POSIX file system here.
+ CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile));
+ ep->outputFilename = QString::fromUtf8(reinterpret_cast<const char *>(localFile));
+ } else {
+ ep->outputFilename = QString();
+ }
+ }
+ sheetCallbackMap.remove(ep->session);
+}
+#else
+void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality)
+{
+ Q_Q(QPrintDialog);
+
+ initBeforeRun();
+
+ QPrintDialog::PrintDialogOptions qtOptions = q->options();
+ NSPrintPanelOptions macOptions = NSPrintPanelShowsCopies;
+ if (qtOptions & QPrintDialog::PrintPageRange)
+ macOptions |= NSPrintPanelShowsPageRange;
+ if (qtOptions & QPrintDialog::PrintShowPageSize)
+ macOptions |= NSPrintPanelShowsPaperSize | NSPrintPanelShowsPageSetupAccessory
+ | NSPrintPanelShowsOrientation;
+
+ macStartInterceptWindowTitle(q);
+ printPanel = [NSPrintPanel printPanel];
+ QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) *delegate = [[QT_MANGLE_NAMESPACE(QCocoaPrintPanelDelegate) alloc] init];
+ [printPanel setOptions:macOptions];
+
+ if (modality == Qt::ApplicationModal) {
+ int rval = [printPanel runModalWithPrintInfo:ep->printInfo];
+ [delegate printPanelDidEnd:printPanel returnCode:rval contextInfo:this];
+ } else {
+ Q_ASSERT(q->parentWidget());
+ NSWindow *windowRef = qt_mac_window_for(q->parentWidget());
+ [printPanel beginSheetWithPrintInfo:ep->printInfo
+ modalForWindow:windowRef
+ delegate:delegate
+ didEndSelector:@selector(printPanelDidEnd:returnCode:contextInfo:)
+ contextInfo:this];
+ }
+
+ macStopInterceptWindowTitle();
+}
+
+void QPrintDialogPrivate::closeCocoaPrintPanel()
+{
+ // ###
+}
+#endif
+
+static bool warnIfNotNative(QPrinter *printer)
+{
+ if (printer->outputFormat() != QPrinter::NativeFormat) {
+ qWarning("QPrintDialog: Cannot be used on non-native printers");
+ return false;
+ }
+ return true;
+}
+
+
+QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
+ : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
+{
+ Q_D(QPrintDialog);
+ if (!warnIfNotNative(d->printer))
+ return;
+ d->ep = static_cast<QMacPrintEngine *>(d->printer->paintEngine())->d_func();
+}
+
+QPrintDialog::QPrintDialog(QWidget *parent)
+ : QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent)
+{
+ Q_D(QPrintDialog);
+ if (!warnIfNotNative(d->printer))
+ return;
+ d->ep = static_cast<QMacPrintEngine *>(d->printer->paintEngine())->d_func();
+}
+
+QPrintDialog::~QPrintDialog()
+{
+}
+
+int QPrintDialog::exec()
+{
+ Q_D(QPrintDialog);
+ if (!warnIfNotNative(d->printer))
+ return QDialog::Rejected;
+
+#ifndef QT_MAC_USE_COCOA
+ d->openCarbonPrintPanel(Qt::ApplicationModal);
+#else
+ QMacCocoaAutoReleasePool pool;
+
+ d->openCocoaPrintPanel(Qt::ApplicationModal);
+ d->closeCocoaPrintPanel();
+#endif
+ return result();
+}
+
+#ifdef QT3_SUPPORT
+QPrinter *QPrintDialog::printer() const
+{
+ Q_D(const QPrintDialog);
+ return d->printer;
+}
+#endif
+
+/*!
+ \reimp
+*/
+void QPrintDialog::setVisible(bool visible)
+{
+ Q_D(QPrintDialog);
+
+ bool isCurrentlyVisible = (d->printPanel != 0);
+
+ if (!visible == !isCurrentlyVisible)
+ return;
+
+ if (d->printer->outputFormat() != QPrinter::NativeFormat)
+ return;
+
+ if (visible) {
+#ifndef QT_MAC_USE_COCOA
+ d->openCarbonPrintPanel(parentWidget() ? Qt::WindowModal
+ : Qt::ApplicationModal);
+#else
+ d->openCocoaPrintPanel(parentWidget() ? Qt::WindowModal
+ : Qt::ApplicationModal);
+#endif
+ return;
+ } else {
+ if (d->printPanel) {
+#ifndef QT_MAC_USE_COCOA
+ d->closeCarbonPrintPanel();
+#else
+ d->closeCocoaPrintPanel();
+#endif
+ return;
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qprintdialog.cpp"
+
+#endif // QT_NO_PRINTDIALOG
diff --git a/src/widgets/dialogs/qprintdialog_unix.cpp b/src/widgets/dialogs/qprintdialog_unix.cpp
new file mode 100644
index 0000000000..c6a1474b21
--- /dev/null
+++ b/src/widgets/dialogs/qprintdialog_unix.cpp
@@ -0,0 +1,1286 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+
+#ifndef QT_NO_PRINTDIALOG
+
+#include "private/qabstractprintdialog_p.h"
+#include <QtGui/qmessagebox.h>
+#include "qprintdialog.h"
+#include "qfiledialog.h"
+#include <QtCore/qdir.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qfilesystemmodel.h>
+#include <QtGui/qstyleditemdelegate.h>
+#include <QtGui/qprinter.h>
+
+#include <QtGui/qdialogbuttonbox.h>
+
+#include "qfscompleter_p.h"
+#include "ui_qprintpropertieswidget.h"
+#include "ui_qprintsettingsoutput.h"
+#include "ui_qprintwidget.h"
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+# include <private/qcups_p.h>
+# include <cups/cups.h>
+# include <private/qpdf_p.h>
+#else
+# include <QtCore/qlibrary.h>
+#endif
+
+#include <private/qprinterinfo_unix_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOptionTreeItem;
+class QPPDOptionsModel;
+
+class QPrintPropertiesDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ QPrintPropertiesDialog(QAbstractPrintDialog *parent = 0);
+ ~QPrintPropertiesDialog();
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ void setCups(QCUPSSupport *cups) { m_cups = cups; }
+ void addItemToOptions(QOptionTreeItem *parent, QList<const ppd_option_t*>& options, QList<const char*>& markedOptions) const;
+#endif
+
+ void selectPrinter();
+ void selectPdfPsPrinter(const QPrinter *p);
+
+ /// copy printer properties to the widget
+ void applyPrinterProperties(QPrinter *p);
+ void setupPrinter() const;
+
+protected:
+ void showEvent(QShowEvent* event);
+
+private:
+ Ui::QPrintPropertiesWidget widget;
+ QDialogButtonBox *m_buttons;
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ QCUPSSupport *m_cups;
+ QPPDOptionsModel *m_cupsOptionsModel;
+#endif
+};
+
+class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QPrintDialog)
+ Q_DECLARE_TR_FUNCTIONS(QPrintDialog)
+public:
+ QPrintDialogPrivate();
+ ~QPrintDialogPrivate();
+
+ void init();
+ /// copy printer properties to the widget
+ void applyPrinterProperties(QPrinter *p);
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ void selectPrinter(QCUPSSupport *cups);
+#endif
+
+ void _q_chbPrintLastFirstToggled(bool);
+#ifndef QT_NO_MESSAGEBOX
+ void _q_checkFields();
+#endif
+ void _q_collapseOrExpandDialog();
+
+ void setupPrinter();
+ void updateWidgets();
+
+ virtual void setTabs(const QList<QWidget*> &tabs);
+
+ Ui::QPrintSettingsOutput options;
+ QUnixPrintWidget *top;
+ QWidget *bottom;
+ QDialogButtonBox *buttons;
+ QPushButton *collapseButton;
+};
+
+#if defined (Q_OS_UNIX)
+class QUnixPrintWidgetPrivate
+{
+public:
+ QUnixPrintWidgetPrivate(QUnixPrintWidget *q);
+ ~QUnixPrintWidgetPrivate();
+
+ /// copy printer properties to the widget
+ void applyPrinterProperties(QPrinter *p);
+ bool checkFields();
+ void setupPrinter();
+ void setOptionsPane(QPrintDialogPrivate *pane);
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ void setCupsProperties();
+#endif
+
+// slots
+ void _q_printerChanged(int index);
+ void _q_btnPropertiesClicked();
+ void _q_btnBrowseClicked();
+
+ QUnixPrintWidget * const parent;
+ QPrintPropertiesDialog *propertiesDialog;
+ Ui::QPrintWidget widget;
+ QAbstractPrintDialog * q;
+ QPrinter *printer;
+ QList<QPrinterDescription> lprPrinters;
+ void updateWidget();
+
+private:
+ QPrintDialogPrivate *optionsPane;
+ bool filePrintersAdded;
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ QCUPSSupport* cups;
+ int cupsPrinterCount;
+ const cups_dest_t* cupsPrinters;
+ const ppd_file_t* cupsPPD;
+#endif
+};
+#endif
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+class QOptionTreeItem
+{
+public:
+ enum ItemType { Root, Group, Option, Choice };
+
+ QOptionTreeItem(ItemType t, int i, const void* p, const char* desc, QOptionTreeItem* pi)
+ : type(t),
+ index(i),
+ ptr(p),
+ description(desc),
+ selected(-1),
+ selDescription(0),
+ parentItem(pi) {}
+
+ ~QOptionTreeItem() {
+ while (!childItems.isEmpty())
+ delete childItems.takeFirst();
+ }
+
+ ItemType type;
+ int index;
+ const void* ptr;
+ const char* description;
+ int selected;
+ const char* selDescription;
+ QOptionTreeItem* parentItem;
+ QList<QOptionTreeItem*> childItems;
+};
+
+class QPPDOptionsModel : public QAbstractItemModel
+{
+ friend class QPPDOptionsEditor;
+public:
+ QPPDOptionsModel(QCUPSSupport *cups, QObject *parent = 0);
+ ~QPPDOptionsModel();
+
+ int columnCount(const QModelIndex& parent = QModelIndex()) const;
+ int rowCount(const QModelIndex& parent = QModelIndex()) const;
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+ QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
+ QModelIndex parent(const QModelIndex& index) const;
+ Qt::ItemFlags flags(const QModelIndex& index) const;
+ QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
+
+ QOptionTreeItem* rootItem;
+ QCUPSSupport *cups;
+ const ppd_file_t* ppd;
+ void parseItems();
+ void parseGroups(QOptionTreeItem* parent);
+ void parseOptions(QOptionTreeItem* parent);
+ void parseChoices(QOptionTreeItem* parent);
+};
+
+class QPPDOptionsEditor : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ QPPDOptionsEditor(QObject* parent = 0) : QStyledItemDelegate(parent) {}
+ ~QPPDOptionsEditor() {}
+
+ QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
+ void setEditorData(QWidget* editor, const QModelIndex& index) const;
+ void setModelData( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
+
+private slots:
+ void cbChanged(int index);
+
+};
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+QPrintPropertiesDialog::QPrintPropertiesDialog(QAbstractPrintDialog *parent)
+ : QDialog(parent)
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ , m_cups(0), m_cupsOptionsModel(0)
+#endif
+{
+ QVBoxLayout *lay = new QVBoxLayout(this);
+ this->setLayout(lay);
+ QWidget *content = new QWidget(this);
+ widget.setupUi(content);
+ m_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
+ lay->addWidget(content);
+ lay->addWidget(m_buttons);
+
+ connect(m_buttons->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept()));
+ connect(m_buttons->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+QPrintPropertiesDialog::~QPrintPropertiesDialog()
+{
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ delete m_cupsOptionsModel;
+#else
+ delete widget.cupsPropertiesPage;
+#endif
+}
+
+void QPrintPropertiesDialog::applyPrinterProperties(QPrinter *p)
+{
+ widget.pageSetup->setPrinter(p);
+}
+
+void QPrintPropertiesDialog::setupPrinter() const
+{
+ widget.pageSetup->setupPrinter();
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ QPPDOptionsModel* model = static_cast<QPPDOptionsModel*>(widget.treeView->model());
+ if (model) {
+ QOptionTreeItem* rootItem = model->rootItem;
+ QList<const ppd_option_t*> options;
+ QList<const char*> markedOptions;
+
+ addItemToOptions(rootItem, options, markedOptions);
+ model->cups->saveOptions(options, markedOptions);
+ }
+#endif
+}
+
+void QPrintPropertiesDialog::selectPrinter()
+{
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ widget.pageSetup->selectPrinter(m_cups);
+ widget.treeView->setModel(0);
+ if (m_cups && QCUPSSupport::isAvailable()) {
+
+ if (m_cupsOptionsModel == 0) {
+ m_cupsOptionsModel = new QPPDOptionsModel(m_cups);
+
+ widget.treeView->setItemDelegate(new QPPDOptionsEditor(this));
+ } else {
+ // update the model
+ m_cupsOptionsModel->parseItems();
+ }
+
+ if (m_cupsOptionsModel->rowCount() > 0) {
+ widget.treeView->setModel(m_cupsOptionsModel);
+
+ for (int i = 0; i < m_cupsOptionsModel->rowCount(); ++i)
+ widget.treeView->expand(m_cupsOptionsModel->index(i,0));
+
+ widget.tabs->setTabEnabled(1, true); // enable the advanced tab
+ } else {
+ widget.tabs->setTabEnabled(1, false);
+ }
+
+ } else
+#endif
+ {
+ widget.cupsPropertiesPage->setEnabled(false);
+ widget.pageSetup->selectPrinter(0);
+ }
+}
+
+void QPrintPropertiesDialog::selectPdfPsPrinter(const QPrinter *p)
+{
+ widget.treeView->setModel(0);
+ widget.pageSetup->selectPdfPsPrinter(p);
+ widget.tabs->setTabEnabled(1, false); // disable the advanced tab
+}
+
+void QPrintPropertiesDialog::showEvent(QShowEvent* event)
+{
+ widget.treeView->resizeColumnToContents(0);
+ event->accept();
+}
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+void QPrintPropertiesDialog::addItemToOptions(QOptionTreeItem *parent, QList<const ppd_option_t*>& options, QList<const char*>& markedOptions) const
+{
+ for (int i = 0; i < parent->childItems.count(); ++i) {
+ QOptionTreeItem *itm = parent->childItems.at(i);
+ if (itm->type == QOptionTreeItem::Option) {
+ const ppd_option_t* opt = reinterpret_cast<const ppd_option_t*>(itm->ptr);
+ options << opt;
+ if (qstrcmp(opt->defchoice, opt->choices[itm->selected].choice) != 0) {
+ markedOptions << opt->keyword << opt->choices[itm->selected].choice;
+ }
+ } else {
+ addItemToOptions(itm, options, markedOptions);
+ }
+ }
+}
+#endif
+
+QPrintDialogPrivate::QPrintDialogPrivate()
+ : top(0), bottom(0), buttons(0), collapseButton(0)
+{
+}
+
+QPrintDialogPrivate::~QPrintDialogPrivate()
+{
+}
+
+void QPrintDialogPrivate::init()
+{
+ Q_Q(QPrintDialog);
+
+ top = new QUnixPrintWidget(0, q);
+ bottom = new QWidget(q);
+ options.setupUi(bottom);
+ options.color->setIconSize(QSize(32, 32));
+ options.color->setIcon(QIcon(QLatin1String(":/trolltech/dialogs/qprintdialog/images/status-color.png")));
+ options.grayscale->setIconSize(QSize(32, 32));
+ options.grayscale->setIcon(QIcon(QLatin1String(":/trolltech/dialogs/qprintdialog/images/status-gray-scale.png")));
+ top->d->setOptionsPane(this);
+
+ buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, q);
+ collapseButton = new QPushButton(QPrintDialog::tr("&Options >>"), buttons);
+ buttons->addButton(collapseButton, QDialogButtonBox::ResetRole);
+ bottom->setVisible(false);
+
+ QPushButton *printButton = buttons->button(QDialogButtonBox::Ok);
+ printButton->setText(QPrintDialog::tr("&Print"));
+ printButton->setDefault(true);
+
+ QVBoxLayout *lay = new QVBoxLayout(q);
+ q->setLayout(lay);
+ lay->addWidget(top);
+ lay->addWidget(bottom);
+ lay->addWidget(buttons);
+
+ QPrinter* p = q->printer();
+
+ applyPrinterProperties(p);
+
+#ifdef QT_NO_MESSAGEBOX
+ QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(accept()));
+#else
+ QObject::connect(buttons, SIGNAL(accepted()), q, SLOT(_q_checkFields()));
+#endif
+ QObject::connect(buttons, SIGNAL(rejected()), q, SLOT(reject()));
+
+ QObject::connect(options.reverse, SIGNAL(toggled(bool)),
+ q, SLOT(_q_chbPrintLastFirstToggled(bool)));
+
+ QObject::connect(collapseButton, SIGNAL(released()), q, SLOT(_q_collapseOrExpandDialog()));
+}
+
+void QPrintDialogPrivate::applyPrinterProperties(QPrinter *p)
+{
+ if (p->colorMode() == QPrinter::Color)
+ options.color->setChecked(true);
+ else
+ options.grayscale->setChecked(true);
+
+ switch(p->duplex()) {
+ case QPrinter::DuplexNone:
+ options.noDuplex->setChecked(true); break;
+ case QPrinter::DuplexLongSide:
+ case QPrinter::DuplexAuto:
+ options.duplexLong->setChecked(true); break;
+ case QPrinter::DuplexShortSide:
+ options.duplexShort->setChecked(true); break;
+ }
+ options.copies->setValue(p->copyCount());
+ options.collate->setChecked(p->collateCopies());
+ options.reverse->setChecked(p->pageOrder() == QPrinter::LastPageFirst);
+ top->d->applyPrinterProperties(p);
+}
+
+void QPrintDialogPrivate::_q_chbPrintLastFirstToggled(bool checked)
+{
+ Q_Q(QPrintDialog);
+ if (checked)
+ q->printer()->setPageOrder(QPrinter::LastPageFirst);
+ else
+ q->printer()->setPageOrder(QPrinter::FirstPageFirst);
+}
+
+void QPrintDialogPrivate::_q_collapseOrExpandDialog()
+{
+ int collapseHeight = 0;
+ Q_Q(QPrintDialog);
+ QWidget *widgetToHide = bottom;
+ if (widgetToHide->isVisible()) {
+ collapseButton->setText(QPrintDialog::tr("&Options >>"));
+ collapseHeight = widgetToHide->y() + widgetToHide->height() - (top->y() + top->height());
+ }
+ else
+ collapseButton->setText(QPrintDialog::tr("&Options <<"));
+ widgetToHide->setVisible(! widgetToHide->isVisible());
+ if (! widgetToHide->isVisible()) { // make it shrink
+ q->layout()->activate();
+ q->resize( QSize(q->width(), q->height() - collapseHeight) );
+ }
+}
+
+#ifndef QT_NO_MESSAGEBOX
+void QPrintDialogPrivate::_q_checkFields()
+{
+ Q_Q(QPrintDialog);
+ if (top->d->checkFields())
+ q->accept();
+}
+#endif // QT_NO_MESSAGEBOX
+
+void QPrintDialogPrivate::setupPrinter()
+{
+ Q_Q(QPrintDialog);
+ QPrinter* p = q->printer();
+
+ if (options.duplex->isEnabled()) {
+ if (options.noDuplex->isChecked())
+ p->setDuplex(QPrinter::DuplexNone);
+ else if (options.duplexLong->isChecked())
+ p->setDuplex(QPrinter::DuplexLongSide);
+ else
+ p->setDuplex(QPrinter::DuplexShortSide);
+ }
+
+ p->setColorMode( options.color->isChecked() ? QPrinter::Color : QPrinter::GrayScale );
+
+ // print range
+ if (options.printAll->isChecked()) {
+ p->setPrintRange(QPrinter::AllPages);
+ p->setFromTo(0,0);
+ } else if (options.printSelection->isChecked()) {
+ p->setPrintRange(QPrinter::Selection);
+ p->setFromTo(0,0);
+ } else if (options.printCurrentPage->isChecked()) {
+ p->setPrintRange(QPrinter::CurrentPage);
+ p->setFromTo(0,0);
+ } else if (options.printRange->isChecked()) {
+ p->setPrintRange(QPrinter::PageRange);
+ p->setFromTo(options.from->value(), qMax(options.from->value(), options.to->value()));
+ }
+
+ // copies
+ p->setCopyCount(options.copies->value());
+ p->setCollateCopies(options.collate->isChecked());
+
+ top->d->setupPrinter();
+}
+
+void QPrintDialogPrivate::updateWidgets()
+{
+ Q_Q(QPrintDialog);
+ options.gbPrintRange->setVisible(q->isOptionEnabled(QPrintDialog::PrintPageRange) ||
+ q->isOptionEnabled(QPrintDialog::PrintSelection) ||
+ q->isOptionEnabled(QPrintDialog::PrintCurrentPage));
+
+ options.printRange->setEnabled(q->isOptionEnabled(QPrintDialog::PrintPageRange));
+ options.printSelection->setVisible(q->isOptionEnabled(QPrintDialog::PrintSelection));
+ options.printCurrentPage->setVisible(q->isOptionEnabled(QPrintDialog::PrintCurrentPage));
+ options.collate->setVisible(q->isOptionEnabled(QPrintDialog::PrintCollateCopies));
+
+ switch (q->printRange()) {
+ case QPrintDialog::AllPages:
+ options.printAll->setChecked(true);
+ break;
+ case QPrintDialog::Selection:
+ options.printSelection->setChecked(true);
+ break;
+ case QPrintDialog::PageRange:
+ options.printRange->setChecked(true);
+ break;
+ case QPrintDialog::CurrentPage:
+ if (q->isOptionEnabled(QPrintDialog::PrintCurrentPage))
+ options.printCurrentPage->setChecked(true);
+ break;
+ default:
+ break;
+ }
+ const int minPage = qMax(1, qMin(q->minPage() , q->maxPage()));
+ const int maxPage = qMax(1, q->maxPage() == INT_MAX ? 9999 : q->maxPage());
+
+ options.from->setMinimum(minPage);
+ options.to->setMinimum(minPage);
+ options.from->setMaximum(maxPage);
+ options.to->setMaximum(maxPage);
+
+ options.from->setValue(q->fromPage());
+ options.to->setValue(q->toPage());
+ top->d->updateWidget();
+}
+
+void QPrintDialogPrivate::setTabs(const QList<QWidget*> &tabWidgets)
+{
+ while(options.tabs->count() > 2)
+ delete options.tabs->widget(2);
+
+ QList<QWidget*>::ConstIterator iter = tabWidgets.begin();
+ while(iter != tabWidgets.constEnd()) {
+ QWidget *tab = *iter;
+ options.tabs->addTab(tab, tab->windowTitle());
+ ++iter;
+ }
+}
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+void QPrintDialogPrivate::selectPrinter(QCUPSSupport *cups)
+{
+ options.duplex->setEnabled(cups && cups->ppdOption("Duplex"));
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
+ : QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
+{
+ Q_D(QPrintDialog);
+ d->init();
+}
+
+/*!
+ Constructs a print dialog with the given \a parent.
+*/
+QPrintDialog::QPrintDialog(QWidget *parent)
+ : QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent)
+{
+ Q_D(QPrintDialog);
+ d->init();
+}
+
+QPrintDialog::~QPrintDialog()
+{
+}
+
+void QPrintDialog::setVisible(bool visible)
+{
+ Q_D(QPrintDialog);
+
+ if (visible)
+ d->updateWidgets();
+
+ QAbstractPrintDialog::setVisible(visible);
+}
+
+int QPrintDialog::exec()
+{
+ return QDialog::exec();
+}
+
+void QPrintDialog::accept()
+{
+ Q_D(QPrintDialog);
+ d->setupPrinter();
+ QDialog::accept();
+}
+
+#ifdef QT3_SUPPORT
+QPrinter *QPrintDialog::printer() const
+{
+ Q_D(const QPrintDialog);
+ return d->printer;
+}
+
+void QPrintDialog::setPrinter(QPrinter *printer, bool pickupSettings)
+{
+ if (!printer)
+ return;
+
+ Q_D(QPrintDialog);
+ d->printer = printer;
+
+ if (pickupSettings)
+ d->applyPrinterProperties(printer);
+}
+
+void QPrintDialog::addButton(QPushButton *button)
+{
+ Q_D(QPrintDialog);
+ d->buttons->addButton(button, QDialogButtonBox::HelpRole);
+}
+#endif // QT3_SUPPORT
+
+#if defined (Q_OS_UNIX)
+
+/*! \internal
+*/
+QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p)
+ : parent(p), propertiesDialog(0), printer(0), optionsPane(0), filePrintersAdded(false)
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ , cups(0), cupsPrinterCount(0), cupsPrinters(0), cupsPPD(0)
+#endif
+{
+ q = 0;
+ if (parent)
+ q = qobject_cast<QAbstractPrintDialog*> (parent->parent());
+
+ widget.setupUi(parent);
+
+ int currentPrinterIndex = 0;
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ cups = new QCUPSSupport;
+ if (QCUPSSupport::isAvailable()) {
+ cupsPPD = cups->currentPPD();
+ cupsPrinterCount = cups->availablePrintersCount();
+ cupsPrinters = cups->availablePrinters();
+
+ for (int i = 0; i < cupsPrinterCount; ++i) {
+ QString printerName(QString::fromLocal8Bit(cupsPrinters[i].name));
+ if (cupsPrinters[i].instance)
+ printerName += QLatin1Char('/') + QString::fromLocal8Bit(cupsPrinters[i].instance);
+
+ widget.printers->addItem(printerName);
+ if (cupsPrinters[i].is_default)
+ widget.printers->setCurrentIndex(i);
+ }
+ // the model depends on valid ppd. so before enabling the
+ // properties button we make sure the ppd is in fact valid.
+ if (cupsPrinterCount && cups->currentPPD()) {
+ widget.properties->setEnabled(true);
+ }
+ currentPrinterIndex = cups->currentPrinterIndex();
+ } else {
+#endif
+ currentPrinterIndex = qt_getLprPrinters(lprPrinters);
+ // populating printer combo
+ QList<QPrinterDescription>::const_iterator i = lprPrinters.constBegin();
+ for(; i != lprPrinters.constEnd(); ++i)
+ widget.printers->addItem((*i).name);
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ }
+#endif
+
+#if !defined(QT_NO_FILESYSTEMMODEL) && !defined(QT_NO_COMPLETER)
+ QFileSystemModel *fsm = new QFileSystemModel(widget.filename);
+ fsm->setRootPath(QDir::homePath());
+ widget.filename->setCompleter(new QCompleter(fsm, widget.filename));
+#endif
+ _q_printerChanged(currentPrinterIndex);
+
+ QObject::connect(widget.printers, SIGNAL(currentIndexChanged(int)),
+ parent, SLOT(_q_printerChanged(int)));
+ QObject::connect(widget.fileBrowser, SIGNAL(clicked()), parent, SLOT(_q_btnBrowseClicked()));
+ QObject::connect(widget.properties, SIGNAL(clicked()), parent, SLOT(_q_btnPropertiesClicked()));
+
+ // disable features that QPrinter does not yet support.
+ widget.preview->setVisible(false);
+}
+
+void QUnixPrintWidgetPrivate::updateWidget()
+{
+ const bool printToFile = q == 0 || q->isOptionEnabled(QPrintDialog::PrintToFile);
+ if (printToFile && !filePrintersAdded) {
+ if (widget.printers->count())
+ widget.printers->insertSeparator(widget.printers->count());
+ widget.printers->addItem(QPrintDialog::tr("Print to File (PDF)"));
+ filePrintersAdded = true;
+ }
+ if (!printToFile && filePrintersAdded) {
+ widget.printers->removeItem(widget.printers->count()-1);
+ widget.printers->removeItem(widget.printers->count()-1);
+ if (widget.printers->count())
+ widget.printers->removeItem(widget.printers->count()-1); // remove separator
+ filePrintersAdded = false;
+ }
+ if (printer && filePrintersAdded && (printer->outputFormat() != QPrinter::NativeFormat
+ || printer->printerName().isEmpty()))
+ {
+ if (printer->outputFormat() == QPrinter::PdfFormat)
+ widget.printers->setCurrentIndex(widget.printers->count() - 1);
+ widget.filename->setEnabled(true);
+ widget.lOutput->setEnabled(true);
+ }
+
+ widget.filename->setVisible(printToFile);
+ widget.lOutput->setVisible(printToFile);
+ widget.fileBrowser->setVisible(printToFile);
+
+ widget.properties->setVisible(q->isOptionEnabled(QAbstractPrintDialog::PrintShowPageSize));
+}
+
+QUnixPrintWidgetPrivate::~QUnixPrintWidgetPrivate()
+{
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ delete cups;
+#endif
+}
+
+void QUnixPrintWidgetPrivate::_q_printerChanged(int index)
+{
+ if (index < 0)
+ return;
+ const int printerCount = widget.printers->count();
+ widget.filename->setEnabled(false);
+ widget.lOutput->setEnabled(false);
+
+ if (filePrintersAdded) {
+ Q_ASSERT(index != printerCount - 3); // separator
+ if (index == printerCount - 1) { // PDF
+ widget.location->setText(QPrintDialog::tr("Local file"));
+ widget.type->setText(QPrintDialog::tr("Write PDF file"));
+ widget.properties->setEnabled(true);
+ widget.filename->setEnabled(true);
+ QString filename = widget.filename->text();
+ QString suffix = QFileInfo(filename).suffix();
+ widget.filename->setText(filename);
+ widget.lOutput->setEnabled(true);
+ if (propertiesDialog)
+ propertiesDialog->selectPdfPsPrinter(printer);
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (optionsPane)
+ optionsPane->selectPrinter(0);
+#endif
+ return;
+ }
+ }
+
+ widget.location->setText(QString());
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (QCUPSSupport::isAvailable()) {
+ cups->setCurrentPrinter(index);
+
+ const cups_option_t *opt = cups->printerOption(QString::fromLatin1("printer-location"));
+ QString location;
+ if (opt)
+ location = QString::fromLocal8Bit(opt->value);
+ widget.location->setText(location);
+
+ cupsPPD = cups->currentPPD();
+ // set printer type line
+ QString type;
+ if (cupsPPD)
+ type = QString::fromLocal8Bit(cupsPPD->manufacturer) + QLatin1String(" - ") + QString::fromLocal8Bit(cupsPPD->modelname);
+ widget.type->setText(type);
+ if (propertiesDialog)
+ propertiesDialog->selectPrinter();
+ if (optionsPane)
+ optionsPane->selectPrinter(cups);
+ } else {
+ if (optionsPane)
+ optionsPane->selectPrinter(0);
+#endif
+ if (lprPrinters.count() > 0) {
+ QString type = lprPrinters.at(index).name + QLatin1Char('@') + lprPrinters.at(index).host;
+ if (!lprPrinters.at(index).comment.isEmpty())
+ type += QLatin1String(", ") + lprPrinters.at(index).comment;
+ widget.type->setText(type);
+ if (propertiesDialog)
+ propertiesDialog->selectPrinter();
+ }
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ }
+#endif
+}
+
+void QUnixPrintWidgetPrivate::setOptionsPane(QPrintDialogPrivate *pane)
+{
+ optionsPane = pane;
+ if (optionsPane)
+ _q_printerChanged(widget.printers->currentIndex());
+}
+
+void QUnixPrintWidgetPrivate::_q_btnBrowseClicked()
+{
+ QString filename = widget.filename->text();
+#ifndef QT_NO_FILEDIALOG
+ filename = QFileDialog::getSaveFileName(parent, QPrintDialog::tr("Print To File ..."), filename,
+ QString(), 0, QFileDialog::DontConfirmOverwrite);
+#else
+ filename.clear();
+#endif
+ if (!filename.isEmpty()) {
+ widget.filename->setText(filename);
+ widget.printers->setCurrentIndex(widget.printers->count() - 1); // the pdf one
+ }
+}
+
+void QUnixPrintWidgetPrivate::applyPrinterProperties(QPrinter *p)
+{
+ if (p == 0)
+ return;
+ printer = p;
+ if (p->outputFileName().isEmpty()) {
+ QString home = QString::fromLocal8Bit(qgetenv("HOME").constData());
+ QString cur = QDir::currentPath();
+ if (home.at(home.length()-1) != QLatin1Char('/'))
+ home += QLatin1Char('/');
+ if (cur.at(cur.length()-1) != QLatin1Char('/'))
+ cur += QLatin1Char('/');
+ if (cur.left(home.length()) != home)
+ cur = home;
+#ifdef Q_WS_X11
+ if (p->docName().isEmpty()) {
+ cur += QLatin1String("print.pdf");
+ } else {
+ QRegExp re(QString::fromLatin1("(.*)\\.\\S+"));
+ if (re.exactMatch(p->docName()))
+ cur += re.cap(1);
+ else
+ cur += p->docName();
+ cur += QLatin1String(".pdf");
+ }
+#endif
+ widget.filename->setText(cur);
+ }
+ else
+ widget.filename->setText( p->outputFileName() );
+ QString printer = p->printerName();
+ if (!printer.isEmpty()) {
+ for (int i = 0; i < widget.printers->count(); ++i) {
+ if (widget.printers->itemText(i) == printer) {
+ widget.printers->setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+ // PDF and PS printers are not added to the dialog yet, we'll handle those cases in QUnixPrintWidgetPrivate::updateWidget
+
+ if (propertiesDialog)
+ propertiesDialog->applyPrinterProperties(p);
+}
+
+#ifndef QT_NO_MESSAGEBOX
+bool QUnixPrintWidgetPrivate::checkFields()
+{
+ if (widget.filename->isEnabled()) {
+ QString file = widget.filename->text();
+ QFile f(file);
+ QFileInfo fi(f);
+ bool exists = fi.exists();
+ bool opened = false;
+ if (exists && fi.isDir()) {
+ QMessageBox::warning(q, q->windowTitle(),
+ QPrintDialog::tr("%1 is a directory.\nPlease choose a different file name.").arg(file));
+ return false;
+ } else if ((exists && !fi.isWritable()) || !(opened = f.open(QFile::Append))) {
+ QMessageBox::warning(q, q->windowTitle(),
+ QPrintDialog::tr("File %1 is not writable.\nPlease choose a different file name.").arg(file));
+ return false;
+ } else if (exists) {
+ int ret = QMessageBox::question(q, q->windowTitle(),
+ QPrintDialog::tr("%1 already exists.\nDo you want to overwrite it?").arg(file),
+ QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
+ if (ret == QMessageBox::No)
+ return false;
+ }
+ if (opened) {
+ f.close();
+ if (!exists)
+ f.remove();
+ }
+ }
+
+ // Every test passed. Accept the dialog.
+ return true;
+}
+#endif // QT_NO_MESSAGEBOX
+
+void QUnixPrintWidgetPrivate::_q_btnPropertiesClicked()
+{
+ if (!propertiesDialog) {
+ propertiesDialog = new QPrintPropertiesDialog(q);
+ propertiesDialog->setResult(QDialog::Rejected);
+ }
+
+ if (propertiesDialog->result() == QDialog::Rejected) {
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ propertiesDialog->setCups(cups);
+#endif
+ propertiesDialog->applyPrinterProperties(q->printer());
+
+ if (q->isOptionEnabled(QPrintDialog::PrintToFile)
+ && (widget.printers->currentIndex() == widget.printers->count() - 1)) // PDF
+ propertiesDialog->selectPdfPsPrinter(q->printer());
+ else
+ propertiesDialog->selectPrinter();
+ }
+ propertiesDialog->exec();
+}
+
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+void QUnixPrintWidgetPrivate::setCupsProperties()
+{
+ if (cups && QCUPSSupport::isAvailable() && cups->pageSizes()) {
+ QPrintEngine *engine = printer->printEngine();
+ const ppd_option_t* pageSizes = cups->pageSizes();
+ QByteArray cupsPageSize;
+ for (int i = 0; i < pageSizes->num_choices; ++i) {
+ if (static_cast<int>(pageSizes->choices[i].marked) == 1)
+ cupsPageSize = pageSizes->choices[i].choice;
+ }
+ engine->setProperty(PPK_CupsStringPageSize, QString::fromLatin1(cupsPageSize));
+ engine->setProperty(PPK_CupsOptions, cups->options());
+
+ QRect pageRect = cups->pageRect(cupsPageSize);
+ engine->setProperty(PPK_CupsPageRect, pageRect);
+
+ QRect paperRect = cups->paperRect(cupsPageSize);
+ engine->setProperty(PPK_CupsPaperRect, paperRect);
+
+ for (int ps = 0; ps < QPrinter::NPaperSize; ++ps) {
+ QPdf::PaperSize size = QPdf::paperSize(QPrinter::PaperSize(ps));
+ if (size.width == paperRect.width() && size.height == paperRect.height())
+ printer->setPaperSize(static_cast<QPrinter::PaperSize>(ps));
+ }
+ }
+}
+#endif
+
+void QUnixPrintWidgetPrivate::setupPrinter()
+{
+ const int printerCount = widget.printers->count();
+ const int index = widget.printers->currentIndex();
+
+ if (filePrintersAdded && index == printerCount - 1) { // PDF
+ printer->setPrinterName(QString());
+ Q_ASSERT(index != printerCount - 3); // separator
+ printer->setOutputFormat(QPrinter::PdfFormat);
+ QString path = widget.filename->text();
+ if (QDir::isRelativePath(path))
+ path = QDir::homePath() + QDir::separator() + path;
+ printer->setOutputFileName(path);
+ }
+ else {
+ printer->setPrinterName(widget.printers->currentText());
+ printer->setOutputFileName(QString());
+ }
+
+ if (propertiesDialog && propertiesDialog->result() == QDialog::Accepted)
+ propertiesDialog->setupPrinter();
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+ if (!propertiesDialog)
+ setCupsProperties();
+#endif
+}
+
+
+/*! \internal
+*/
+QUnixPrintWidget::QUnixPrintWidget(QPrinter *printer, QWidget *parent)
+ : QWidget(parent), d(new QUnixPrintWidgetPrivate(this))
+{
+ d->applyPrinterProperties(printer);
+}
+
+/*! \internal
+*/
+QUnixPrintWidget::~QUnixPrintWidget()
+{
+ delete d;
+}
+
+/*! \internal
+
+ Updates the printer with the states held in the QUnixPrintWidget.
+*/
+void QUnixPrintWidget::updatePrinter()
+{
+ d->setupPrinter();
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+#if !defined(QT_NO_CUPS) && !defined(QT_NO_LIBRARY)
+
+QPPDOptionsModel::QPPDOptionsModel(QCUPSSupport *c, QObject *parent)
+ : QAbstractItemModel(parent), rootItem(0), cups(c), ppd(c->currentPPD())
+{
+ parseItems();
+}
+
+QPPDOptionsModel::~QPPDOptionsModel()
+{
+}
+
+int QPPDOptionsModel::columnCount(const QModelIndex&) const
+{
+ return 2;
+}
+
+int QPPDOptionsModel::rowCount(const QModelIndex& parent) const
+{
+ QOptionTreeItem* itm;
+ if (!parent.isValid())
+ itm = rootItem;
+ else
+ itm = reinterpret_cast<QOptionTreeItem*>(parent.internalPointer());
+
+ if (itm->type == QOptionTreeItem::Option)
+ return 0;
+
+ return itm->childItems.count();
+}
+
+QVariant QPPDOptionsModel::data(const QModelIndex& index, int role) const
+{
+ switch(role) {
+ case Qt::FontRole: {
+ QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
+ if (itm && itm->type == QOptionTreeItem::Group){
+ QFont font = QApplication::font();
+ font.setBold(true);
+ return QVariant(font);
+ }
+ return QVariant();
+ }
+ break;
+
+ case Qt::DisplayRole: {
+ QOptionTreeItem* itm;
+ if (!index.isValid())
+ itm = rootItem;
+ else
+ itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
+
+ if (index.column() == 0)
+ return cups->unicodeString(itm->description);
+ else if (itm->type == QOptionTreeItem::Option && itm->selected > -1)
+ return cups->unicodeString(itm->selDescription);
+ else
+ return QVariant();
+ }
+ break;
+
+ default:
+ return QVariant();
+ }
+ if (role != Qt::DisplayRole)
+ return QVariant();
+}
+
+QModelIndex QPPDOptionsModel::index(int row, int column, const QModelIndex& parent) const
+{
+ QOptionTreeItem* itm;
+ if (!parent.isValid())
+ itm = rootItem;
+ else
+ itm = reinterpret_cast<QOptionTreeItem*>(parent.internalPointer());
+
+ return createIndex(row, column, itm->childItems.at(row));
+}
+
+
+QModelIndex QPPDOptionsModel::parent(const QModelIndex& index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
+
+ if (itm->parentItem && itm->parentItem != rootItem)
+ return createIndex(itm->parentItem->index, 0, itm->parentItem);
+ else
+ return QModelIndex();
+}
+
+Qt::ItemFlags QPPDOptionsModel::flags(const QModelIndex& index) const
+{
+ if (!index.isValid() || reinterpret_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Group)
+ return Qt::ItemIsEnabled;
+
+ if (index.column() == 1)
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
+
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+}
+
+void QPPDOptionsModel::parseItems()
+{
+ emit layoutAboutToBeChanged();
+ ppd = cups->currentPPD();
+ delete rootItem;
+ rootItem = new QOptionTreeItem(QOptionTreeItem::Root, 0, ppd, "Root Item", 0);
+ parseGroups(rootItem);
+ emit layoutChanged();
+}
+
+void QPPDOptionsModel::parseGroups(QOptionTreeItem* parent)
+{
+ if (parent->type == QOptionTreeItem::Root) {
+
+ const ppd_file_t* ppdFile = reinterpret_cast<const ppd_file_t*>(parent->ptr);
+
+ if (ppdFile) {
+ for (int i = 0; i < ppdFile->num_groups; ++i) {
+ QOptionTreeItem* group = new QOptionTreeItem(QOptionTreeItem::Group, i, &ppdFile->groups[i], ppdFile->groups[i].text, parent);
+ parent->childItems.append(group);
+ parseGroups(group); // parse possible subgroups
+ parseOptions(group); // parse options
+ }
+ }
+ } else if (parent->type == QOptionTreeItem::Group) {
+
+ const ppd_group_t* group = reinterpret_cast<const ppd_group_t*>(parent->ptr);
+
+ if (group) {
+ for (int i = 0; i < group->num_subgroups; ++i) {
+ QOptionTreeItem* subgroup = new QOptionTreeItem(QOptionTreeItem::Group, i, &group->subgroups[i], group->subgroups[i].text, parent);
+ parent->childItems.append(subgroup);
+ parseGroups(subgroup); // parse possible subgroups
+ parseOptions(subgroup); // parse options
+ }
+ }
+ }
+}
+
+void QPPDOptionsModel::parseOptions(QOptionTreeItem* parent)
+{
+ const ppd_group_t* group = reinterpret_cast<const ppd_group_t*>(parent->ptr);
+ for (int i = 0; i < group->num_options; ++i) {
+ QOptionTreeItem* opt = new QOptionTreeItem(QOptionTreeItem::Option, i, &group->options[i], group->options[i].text, parent);
+ parent->childItems.append(opt);
+ parseChoices(opt);
+ }
+}
+
+void QPPDOptionsModel::parseChoices(QOptionTreeItem* parent)
+{
+ const ppd_option_t* option = reinterpret_cast<const ppd_option_t*>(parent->ptr);
+ bool marked = false;
+ for (int i = 0; i < option->num_choices; ++i) {
+ QOptionTreeItem* choice = new QOptionTreeItem(QOptionTreeItem::Choice, i, &option->choices[i], option->choices[i].text, parent);
+ if (static_cast<int>(option->choices[i].marked) == 1) {
+ parent->selected = i;
+ parent->selDescription = option->choices[i].text;
+ marked = true;
+ } else if (!marked && qstrcmp(option->choices[i].choice, option->defchoice) == 0) {
+ parent->selected = i;
+ parent->selDescription = option->choices[i].text;
+ }
+ parent->childItems.append(choice);
+ }
+}
+
+QVariant QPPDOptionsModel::headerData(int section, Qt::Orientation, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ switch(section){
+ case 0:
+ return QVariant(QApplication::translate("QPPDOptionsModel", "Name"));
+ case 1:
+ return QVariant(QApplication::translate("QPPDOptionsModel", "Value"));
+ default:
+ return QVariant();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+QWidget* QPPDOptionsEditor::createEditor(QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const
+{
+ if (index.column() == 1 && reinterpret_cast<QOptionTreeItem*>(index.internalPointer())->type == QOptionTreeItem::Option)
+ return new QComboBox(parent);
+ else
+ return 0;
+}
+
+void QPPDOptionsEditor::setEditorData(QWidget* editor, const QModelIndex& index) const
+{
+ if (index.column() != 1)
+ return;
+
+ QComboBox* cb = static_cast<QComboBox*>(editor);
+ QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
+
+ if (itm->selected == -1)
+ cb->addItem(QString());
+
+ for (int i = 0; i < itm->childItems.count(); ++i)
+ cb->addItem(QString::fromLocal8Bit(itm->childItems.at(i)->description));
+
+ if (itm->selected > -1)
+ cb->setCurrentIndex(itm->selected);
+
+ connect(cb, SIGNAL(currentIndexChanged(int)), this, SLOT(cbChanged(int)));
+}
+
+void QPPDOptionsEditor::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
+{
+ QComboBox* cb = static_cast<QComboBox*>(editor);
+ QOptionTreeItem* itm = reinterpret_cast<QOptionTreeItem*>(index.internalPointer());
+
+ if (itm->selected == cb->currentIndex())
+ return;
+
+ const ppd_option_t* opt = reinterpret_cast<const ppd_option_t*>(itm->ptr);
+ QPPDOptionsModel* m = static_cast<QPPDOptionsModel*>(model);
+
+ if (m->cups->markOption(opt->keyword, opt->choices[cb->currentIndex()].choice) == 0) {
+ itm->selected = cb->currentIndex();
+ itm->selDescription = reinterpret_cast<const ppd_option_t*>(itm->ptr)->choices[itm->selected].text;
+ }
+}
+
+void QPPDOptionsEditor::cbChanged(int)
+{
+/*
+ emit commitData(static_cast<QWidget*>(sender()));
+*/
+}
+
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qprintdialog.cpp"
+#include "qprintdialog_unix.moc"
+#include "qrc_qprintdialog.cpp"
+
+#endif // QT_NO_PRINTDIALOG
+
diff --git a/src/widgets/dialogs/qprintdialog_win.cpp b/src/widgets/dialogs/qprintdialog_win.cpp
new file mode 100644
index 0000000000..4f6866b2df
--- /dev/null
+++ b/src/widgets/dialogs/qprintdialog_win.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_PRINTDIALOG
+
+#include "qprintdialog.h"
+
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qmessagebox.h>
+#include <private/qapplication_p.h>
+
+#include <private/qabstractprintdialog_p.h>
+#include <private/qprintengine_win_p.h>
+#include <private/qprinter_p.h>
+
+#if !defined(PD_NOCURRENTPAGE)
+#define PD_NOCURRENTPAGE 0x00800000
+#define PD_RESULT_PRINT 1
+#define PD_RESULT_APPLY 2
+#define START_PAGE_GENERAL 0XFFFFFFFF
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern void qt_win_eatMouseMove();
+
+class QPrintDialogPrivate : public QAbstractPrintDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QPrintDialog)
+public:
+ QPrintDialogPrivate()
+ : ep(0)
+ {
+ }
+
+ inline void _q_printToFileChanged(int) {}
+ inline void _q_rbPrintRangeToggled(bool) {}
+ inline void _q_printerChanged(int) {}
+ inline void _q_chbPrintLastFirstToggled(bool) {}
+ inline void _q_paperSizeChanged(int) {}
+ inline void _q_btnBrowseClicked() {}
+ inline void _q_btnPropertiesClicked() {}
+ int openWindowsPrintDialogModally();
+
+ QWin32PrintEnginePrivate *ep;
+};
+
+static void qt_win_setup_PRINTDLGEX(PRINTDLGEX *pd, QWidget *parent,
+ QPrintDialog *pdlg,
+ QPrintDialogPrivate *d, HGLOBAL *tempDevNames)
+{
+ DEVMODE *devMode = d->ep->devMode;
+
+ if (devMode) {
+ int size = sizeof(DEVMODE) + devMode->dmDriverExtra;
+ pd->hDevMode = GlobalAlloc(GHND, size);
+ {
+ void *dest = GlobalLock(pd->hDevMode);
+ memcpy(dest, devMode, size);
+ GlobalUnlock(pd->hDevMode);
+ }
+ } else {
+ pd->hDevMode = NULL;
+ }
+ pd->hDevNames = tempDevNames;
+
+ pd->Flags = PD_RETURNDC;
+ pd->Flags |= PD_USEDEVMODECOPIESANDCOLLATE;
+
+ if (!pdlg->isOptionEnabled(QPrintDialog::PrintSelection))
+ pd->Flags |= PD_NOSELECTION;
+ if (pdlg->isOptionEnabled(QPrintDialog::PrintPageRange)) {
+ pd->nMinPage = pdlg->minPage();
+ pd->nMaxPage = pdlg->maxPage();
+ }
+
+ if(!pdlg->isOptionEnabled(QPrintDialog::PrintToFile))
+ pd->Flags |= PD_DISABLEPRINTTOFILE;
+
+ if (pdlg->printRange() == QPrintDialog::Selection)
+ pd->Flags |= PD_SELECTION;
+ else if (pdlg->printRange() == QPrintDialog::PageRange)
+ pd->Flags |= PD_PAGENUMS;
+ else
+ pd->Flags |= PD_ALLPAGES;
+
+ // As stated by MSDN, to enable collate option when minpage==maxpage==0
+ // set the PD_NOPAGENUMS flag
+ if (pd->nMinPage==0 && pd->nMaxPage==0)
+ pd->Flags |= PD_NOPAGENUMS;
+
+ // Disable Current Page option if not required as default is Enabled
+ if (!pdlg->isOptionEnabled(QPrintDialog::PrintCurrentPage))
+ pd->Flags |= PD_NOCURRENTPAGE;
+
+ // Default to showing the General tab first
+ pd->nStartPage = START_PAGE_GENERAL;
+
+ // We don't support more than one page range in the QPrinter API yet.
+ pd->nPageRanges = 1;
+ pd->nMaxPageRanges = 1;
+
+ if (d->ep->printToFile)
+ pd->Flags |= PD_PRINTTOFILE;
+ Q_ASSERT(parent);
+ pd->hwndOwner = parent->window()->winId();
+ pd->lpPageRanges[0].nFromPage = qMax(pdlg->fromPage(), pdlg->minPage());
+ pd->lpPageRanges[0].nToPage = (pdlg->toPage() > 0) ? qMin(pdlg->toPage(), pdlg->maxPage()) : 1;
+ pd->nCopies = d->ep->num_copies;
+}
+
+static void qt_win_read_back_PRINTDLGEX(PRINTDLGEX *pd, QPrintDialog *pdlg, QPrintDialogPrivate *d)
+{
+ if (pd->Flags & PD_SELECTION) {
+ pdlg->setPrintRange(QPrintDialog::Selection);
+ pdlg->setFromTo(0, 0);
+ } else if (pd->Flags & PD_PAGENUMS) {
+ pdlg->setPrintRange(QPrintDialog::PageRange);
+ pdlg->setFromTo(pd->lpPageRanges[0].nFromPage, pd->lpPageRanges[0].nToPage);
+ } else if (pd->Flags & PD_CURRENTPAGE) {
+ pdlg->setPrintRange(QPrintDialog::CurrentPage);
+ pdlg->setFromTo(0, 0);
+ } else { // PD_ALLPAGES
+ pdlg->setPrintRange(QPrintDialog::AllPages);
+ pdlg->setFromTo(0, 0);
+ }
+
+ d->ep->printToFile = (pd->Flags & PD_PRINTTOFILE) != 0;
+
+ d->ep->readDevnames(pd->hDevNames);
+ d->ep->readDevmode(pd->hDevMode);
+ d->ep->updateCustomPaperSize();
+
+ if (d->ep->printToFile && d->ep->fileName.isEmpty())
+ d->ep->fileName = d->ep->port;
+ else if (!d->ep->printToFile && d->ep->fileName == QLatin1String("FILE:"))
+ d->ep->fileName.clear();
+}
+
+static bool warnIfNotNative(QPrinter *printer)
+{
+ if (printer->outputFormat() != QPrinter::NativeFormat) {
+ qWarning("QPrintDialog: Cannot be used on non-native printers");
+ return false;
+ }
+ return true;
+}
+
+QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
+ : QAbstractPrintDialog( *(new QPrintDialogPrivate), printer, parent)
+{
+ Q_D(QPrintDialog);
+ if (!warnIfNotNative(d->printer))
+ return;
+ d->ep = static_cast<QWin32PrintEngine *>(d->printer->paintEngine())->d_func();
+}
+
+QPrintDialog::QPrintDialog(QWidget *parent)
+ : QAbstractPrintDialog( *(new QPrintDialogPrivate), 0, parent)
+{
+ Q_D(QPrintDialog);
+ if (!warnIfNotNative(d->printer))
+ return;
+ d->ep = static_cast<QWin32PrintEngine *>(d->printer->paintEngine())->d_func();
+}
+
+QPrintDialog::~QPrintDialog()
+{
+}
+
+int QPrintDialog::exec()
+{
+ if (!warnIfNotNative(printer()))
+ return 0;
+
+ Q_D(QPrintDialog);
+ return d->openWindowsPrintDialogModally();
+}
+
+int QPrintDialogPrivate::openWindowsPrintDialogModally()
+{
+ Q_Q(QPrintDialog);
+ QWidget *parent = q->parentWidget();
+ if (parent)
+ parent = parent->window();
+ else
+ parent = QApplication::activeWindow();
+
+ // If there is no window, fall back to the print dialog itself
+ if (parent == 0)
+ parent = q;
+
+ QWidget modal_widget;
+ modal_widget.setAttribute(Qt::WA_NoChildEventsForParent, true);
+ modal_widget.setParent(parent, Qt::Window);
+ QApplicationPrivate::enterModal(&modal_widget);
+
+ HGLOBAL *tempDevNames = ep->createDevNames();
+
+ bool done;
+ bool result;
+ bool doPrinting;
+
+ PRINTPAGERANGE pageRange;
+ PRINTDLGEX pd;
+ memset(&pd, 0, sizeof(PRINTDLGEX));
+ pd.lStructSize = sizeof(PRINTDLGEX);
+ pd.lpPageRanges = &pageRange;
+ qt_win_setup_PRINTDLGEX(&pd, parent, q, this, tempDevNames);
+
+ do {
+ done = true;
+ doPrinting = false;
+ result = (PrintDlgEx(&pd) == S_OK);
+ if (result && (pd.dwResultAction == PD_RESULT_PRINT
+ || pd.dwResultAction == PD_RESULT_APPLY))
+ {
+ doPrinting = (pd.dwResultAction == PD_RESULT_PRINT);
+ if ((pd.Flags & PD_PAGENUMS)
+ && (pd.lpPageRanges[0].nFromPage > pd.lpPageRanges[0].nToPage))
+ {
+ pd.lpPageRanges[0].nFromPage = 1;
+ pd.lpPageRanges[0].nToPage = 1;
+ done = false;
+ }
+ if (pd.hDC == 0)
+ result = false;
+ }
+
+ if (!done) {
+ QMessageBox::warning(0, QPrintDialog::tr("Print"),
+ QPrintDialog::tr("The 'From' value cannot be greater than the 'To' value."),
+ QPrintDialog::tr("OK"));
+ }
+ } while (!done);
+
+ QApplicationPrivate::leaveModal(&modal_widget);
+
+ qt_win_eatMouseMove();
+
+ // write values back...
+ if (result && (pd.dwResultAction == PD_RESULT_PRINT
+ || pd.dwResultAction == PD_RESULT_APPLY))
+ {
+ qt_win_read_back_PRINTDLGEX(&pd, q, this);
+ // update printer validity
+ printer->d_func()->validPrinter = !ep->name.isEmpty();
+ }
+
+ // Cleanup...
+ GlobalFree(tempDevNames);
+
+ q->done(result && doPrinting);
+
+ return result && doPrinting;
+}
+
+void QPrintDialog::setVisible(bool visible)
+{
+ Q_D(QPrintDialog);
+
+ // its always modal, so we cannot hide a native print dialog
+ if (!visible)
+ return;
+
+ if (!warnIfNotNative(d->printer))
+ return;
+
+ (void)d->openWindowsPrintDialogModally();
+ return;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qprintdialog.cpp"
+
+#endif // QT_NO_PRINTDIALOG
diff --git a/src/widgets/dialogs/qprintpreviewdialog.cpp b/src/widgets/dialogs/qprintpreviewdialog.cpp
new file mode 100644
index 0000000000..950500d739
--- /dev/null
+++ b/src/widgets/dialogs/qprintpreviewdialog.cpp
@@ -0,0 +1,803 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qprintpreviewdialog.h"
+#include "qprintpreviewwidget.h"
+#include <private/qprinter_p.h>
+#include "private/qdialog_p.h"
+#include "qprintdialog.h"
+
+#include <QtGui/qaction.h>
+#include <QtGui/qboxlayout.h>
+#include <QtGui/qcombobox.h>
+#include <QtGui/qlabel.h>
+#include <QtGui/qlineedit.h>
+#include <QtGui/qpagesetupdialog.h>
+#include <QtGui/qprinter.h>
+#include <QtGui/qstyle.h>
+#include <QtGui/qtoolbutton.h>
+#include <QtGui/qvalidator.h>
+#include <QtGui/qfiledialog.h>
+#include <QtGui/qmainwindow.h>
+#include <QtGui/qtoolbar.h>
+#include <QtGui/qformlayout.h>
+#include <QtCore/QCoreApplication>
+
+#include <math.h>
+
+#ifndef QT_NO_PRINTPREVIEWDIALOG
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+class QPrintPreviewMainWindow : public QMainWindow
+{
+public:
+ QPrintPreviewMainWindow(QWidget *parent) : QMainWindow(parent) {}
+ QMenu *createPopupMenu() { return 0; }
+};
+
+class ZoomFactorValidator : public QDoubleValidator
+{
+public:
+ ZoomFactorValidator(QObject* parent)
+ : QDoubleValidator(parent) {}
+ ZoomFactorValidator(qreal bottom, qreal top, int decimals, QObject *parent)
+ : QDoubleValidator(bottom, top, decimals, parent) {}
+
+ State validate(QString &input, int &pos) const
+ {
+ bool replacePercent = false;
+ if (input.endsWith(QLatin1Char('%'))) {
+ input = input.left(input.length() - 1);
+ replacePercent = true;
+ }
+ State state = QDoubleValidator::validate(input, pos);
+ if (replacePercent)
+ input += QLatin1Char('%');
+ const int num_size = 4;
+ if (state == Intermediate) {
+ int i = input.indexOf(QLocale::system().decimalPoint());
+ if ((i == -1 && input.size() > num_size)
+ || (i != -1 && i > num_size))
+ return Invalid;
+ }
+ return state;
+ }
+};
+
+class LineEdit : public QLineEdit
+{
+ Q_OBJECT
+public:
+ LineEdit(QWidget* parent = 0)
+ : QLineEdit(parent)
+ {
+ setContextMenuPolicy(Qt::NoContextMenu);
+ connect(this, SIGNAL(returnPressed()), SLOT(handleReturnPressed()));
+ }
+
+protected:
+ void focusInEvent(QFocusEvent *e)
+ {
+ origText = text();
+ QLineEdit::focusInEvent(e);
+ }
+
+ void focusOutEvent(QFocusEvent *e)
+ {
+ if (isModified() && !hasAcceptableInput())
+ setText(origText);
+ QLineEdit::focusOutEvent(e);
+ }
+
+private slots:
+ void handleReturnPressed()
+ {
+ origText = text();
+ }
+
+private:
+ QString origText;
+};
+} // anonymous namespace
+
+class QPrintPreviewDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QPrintPreviewDialog)
+public:
+ QPrintPreviewDialogPrivate()
+ : printDialog(0), ownPrinter(false),
+ initialized(false) {}
+
+ // private slots
+ void _q_fit(QAction *action);
+ void _q_zoomIn();
+ void _q_zoomOut();
+ void _q_navigate(QAction *action);
+ void _q_setMode(QAction *action);
+ void _q_pageNumEdited();
+ void _q_print();
+ void _q_pageSetup();
+ void _q_previewChanged();
+ void _q_zoomFactorChanged();
+
+ void init(QPrinter *printer = 0);
+ void populateScene();
+ void layoutPages();
+ void setupActions();
+ void updateNavActions();
+ void setFitting(bool on);
+ bool isFitting();
+ void updatePageNumLabel();
+ void updateZoomFactor();
+
+ QPrintDialog *printDialog;
+ QPrintPreviewWidget *preview;
+ QPrinter *printer;
+ bool ownPrinter;
+ bool initialized;
+
+ // widgets:
+ QLineEdit *pageNumEdit;
+ QLabel *pageNumLabel;
+ QComboBox *zoomFactor;
+
+ // actions:
+ QActionGroup* navGroup;
+ QAction *nextPageAction;
+ QAction *prevPageAction;
+ QAction *firstPageAction;
+ QAction *lastPageAction;
+
+ QActionGroup* fitGroup;
+ QAction *fitWidthAction;
+ QAction *fitPageAction;
+
+ QActionGroup* zoomGroup;
+ QAction *zoomInAction;
+ QAction *zoomOutAction;
+
+ QActionGroup* orientationGroup;
+ QAction *portraitAction;
+ QAction *landscapeAction;
+
+ QActionGroup* modeGroup;
+ QAction *singleModeAction;
+ QAction *facingModeAction;
+ QAction *overviewModeAction;
+
+ QActionGroup *printerGroup;
+ QAction *printAction;
+ QAction *pageSetupAction;
+#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
+ QAction *closeAction;
+#endif
+
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+};
+
+void QPrintPreviewDialogPrivate::init(QPrinter *_printer)
+{
+ Q_Q(QPrintPreviewDialog);
+
+ if (_printer) {
+ preview = new QPrintPreviewWidget(_printer, q);
+ printer = _printer;
+ } else {
+ ownPrinter = true;
+ printer = new QPrinter;
+ preview = new QPrintPreviewWidget(printer, q);
+ }
+ QObject::connect(preview, SIGNAL(paintRequested(QPrinter*)), q, SIGNAL(paintRequested(QPrinter*)));
+ QObject::connect(preview, SIGNAL(previewChanged()), q, SLOT(_q_previewChanged()));
+ setupActions();
+
+ pageNumEdit = new LineEdit;
+ pageNumEdit->setAlignment(Qt::AlignRight);
+ pageNumEdit->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ pageNumLabel = new QLabel;
+ QObject::connect(pageNumEdit, SIGNAL(editingFinished()), q, SLOT(_q_pageNumEdited()));
+
+ zoomFactor = new QComboBox;
+ zoomFactor->setEditable(true);
+ zoomFactor->setMinimumContentsLength(7);
+ zoomFactor->setInsertPolicy(QComboBox::NoInsert);
+ LineEdit *zoomEditor = new LineEdit;
+ zoomEditor->setValidator(new ZoomFactorValidator(1, 1000, 1, zoomEditor));
+ zoomFactor->setLineEdit(zoomEditor);
+ static const short factorsX2[] = { 25, 50, 100, 200, 250, 300, 400, 800, 1600 };
+ for (int i = 0; i < int(sizeof(factorsX2) / sizeof(factorsX2[0])); ++i)
+ zoomFactor->addItem(QPrintPreviewDialog::tr("%1%").arg(factorsX2[i] / 2.0));
+ QObject::connect(zoomFactor->lineEdit(), SIGNAL(editingFinished()),
+ q, SLOT(_q_zoomFactorChanged()));
+ QObject::connect(zoomFactor, SIGNAL(currentIndexChanged(int)),
+ q, SLOT(_q_zoomFactorChanged()));
+
+ QPrintPreviewMainWindow *mw = new QPrintPreviewMainWindow(q);
+ QToolBar *toolbar = new QToolBar(mw);
+ toolbar->addAction(fitWidthAction);
+ toolbar->addAction(fitPageAction);
+ toolbar->addSeparator();
+ toolbar->addWidget(zoomFactor);
+ toolbar->addAction(zoomOutAction);
+ toolbar->addAction(zoomInAction);
+ toolbar->addSeparator();
+ toolbar->addAction(portraitAction);
+ toolbar->addAction(landscapeAction);
+ toolbar->addSeparator();
+ toolbar->addAction(firstPageAction);
+ toolbar->addAction(prevPageAction);
+
+ // this is to ensure the label text and the editor text are
+ // aligned in all styles - the extra QVBoxLayout is a workaround
+ // for bug in QFormLayout
+ QWidget *pageEdit = new QWidget(toolbar);
+ QVBoxLayout *vboxLayout = new QVBoxLayout;
+ vboxLayout->setContentsMargins(0, 0, 0, 0);
+#ifdef Q_WS_MAC
+ // We query the widgets about their size and then we fix the size.
+ // This should do the trick for the laying out part...
+ QSize pageNumEditSize, pageNumLabelSize;
+ pageNumEditSize = pageNumEdit->minimumSizeHint();
+ pageNumLabelSize = pageNumLabel->minimumSizeHint();
+ pageNumEdit->resize(pageNumEditSize);
+ pageNumLabel->resize(pageNumLabelSize);
+#endif
+ QFormLayout *formLayout = new QFormLayout;
+#ifdef Q_WS_MAC
+ // We have to change the growth policy in Mac.
+ formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+#endif
+ formLayout->setWidget(0, QFormLayout::LabelRole, pageNumEdit);
+ formLayout->setWidget(0, QFormLayout::FieldRole, pageNumLabel);
+ vboxLayout->addLayout(formLayout);
+ vboxLayout->setAlignment(Qt::AlignVCenter);
+ pageEdit->setLayout(vboxLayout);
+ toolbar->addWidget(pageEdit);
+
+ toolbar->addAction(nextPageAction);
+ toolbar->addAction(lastPageAction);
+ toolbar->addSeparator();
+ toolbar->addAction(singleModeAction);
+ toolbar->addAction(facingModeAction);
+ toolbar->addAction(overviewModeAction);
+ toolbar->addSeparator();
+ toolbar->addAction(pageSetupAction);
+ toolbar->addAction(printAction);
+#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
+ toolbar->addAction(closeAction);
+#endif
+
+ // Cannot use the actions' triggered signal here, since it doesn't autorepeat
+ QToolButton *zoomInButton = static_cast<QToolButton *>(toolbar->widgetForAction(zoomInAction));
+ QToolButton *zoomOutButton = static_cast<QToolButton *>(toolbar->widgetForAction(zoomOutAction));
+ zoomInButton->setAutoRepeat(true);
+ zoomInButton->setAutoRepeatInterval(200);
+ zoomInButton->setAutoRepeatDelay(200);
+ zoomOutButton->setAutoRepeat(true);
+ zoomOutButton->setAutoRepeatInterval(200);
+ zoomOutButton->setAutoRepeatDelay(200);
+ QObject::connect(zoomInButton, SIGNAL(clicked()), q, SLOT(_q_zoomIn()));
+ QObject::connect(zoomOutButton, SIGNAL(clicked()), q, SLOT(_q_zoomOut()));
+
+ mw->addToolBar(toolbar);
+ mw->setCentralWidget(preview);
+ // QMainWindows are always created as top levels, force it to be a
+ // plain widget
+ mw->setParent(q, Qt::Widget);
+
+ QVBoxLayout *topLayout = new QVBoxLayout;
+ topLayout->addWidget(mw);
+ topLayout->setMargin(0);
+ q->setLayout(topLayout);
+
+ QString caption = QCoreApplication::translate("QPrintPreviewDialog", "Print Preview");
+ if (!printer->docName().isEmpty())
+ caption += QString::fromLatin1(": ") + printer->docName();
+ q->setWindowTitle(caption);
+
+ if (!printer->isValid()
+#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
+ || printer->outputFormat() != QPrinter::NativeFormat
+#endif
+ )
+ pageSetupAction->setEnabled(false);
+ preview->setFocus();
+}
+
+static inline void qt_setupActionIcon(QAction *action, const QLatin1String &name)
+{
+ QLatin1String imagePrefix(":/trolltech/dialogs/qprintpreviewdialog/images/");
+ QIcon icon;
+ icon.addFile(imagePrefix + name + QLatin1String("-24.png"), QSize(24, 24));
+ icon.addFile(imagePrefix + name + QLatin1String("-32.png"), QSize(32, 32));
+ action->setIcon(icon);
+}
+
+void QPrintPreviewDialogPrivate::setupActions()
+{
+ Q_Q(QPrintPreviewDialog);
+
+ // Navigation
+ navGroup = new QActionGroup(q);
+ navGroup->setExclusive(false);
+ nextPageAction = navGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Next page"));
+ prevPageAction = navGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Previous page"));
+ firstPageAction = navGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "First page"));
+ lastPageAction = navGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Last page"));
+ qt_setupActionIcon(nextPageAction, QLatin1String("go-next"));
+ qt_setupActionIcon(prevPageAction, QLatin1String("go-previous"));
+ qt_setupActionIcon(firstPageAction, QLatin1String("go-first"));
+ qt_setupActionIcon(lastPageAction, QLatin1String("go-last"));
+ QObject::connect(navGroup, SIGNAL(triggered(QAction*)), q, SLOT(_q_navigate(QAction*)));
+
+
+ fitGroup = new QActionGroup(q);
+ fitWidthAction = fitGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Fit width"));
+ fitPageAction = fitGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Fit page"));
+ fitWidthAction->setObjectName(QLatin1String("fitWidthAction"));
+ fitPageAction->setObjectName(QLatin1String("fitPageAction"));
+ fitWidthAction->setCheckable(true);
+ fitPageAction->setCheckable(true);
+ qt_setupActionIcon(fitWidthAction, QLatin1String("fit-width"));
+ qt_setupActionIcon(fitPageAction, QLatin1String("fit-page"));
+ QObject::connect(fitGroup, SIGNAL(triggered(QAction*)), q, SLOT(_q_fit(QAction*)));
+
+ // Zoom
+ zoomGroup = new QActionGroup(q);
+ zoomInAction = zoomGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Zoom in"));
+ zoomOutAction = zoomGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Zoom out"));
+ qt_setupActionIcon(zoomInAction, QLatin1String("zoom-in"));
+ qt_setupActionIcon(zoomOutAction, QLatin1String("zoom-out"));
+
+ // Portrait/Landscape
+ orientationGroup = new QActionGroup(q);
+ portraitAction = orientationGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Portrait"));
+ landscapeAction = orientationGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Landscape"));
+ portraitAction->setCheckable(true);
+ landscapeAction->setCheckable(true);
+ qt_setupActionIcon(portraitAction, QLatin1String("layout-portrait"));
+ qt_setupActionIcon(landscapeAction, QLatin1String("layout-landscape"));
+ QObject::connect(portraitAction, SIGNAL(triggered(bool)), preview, SLOT(setPortraitOrientation()));
+ QObject::connect(landscapeAction, SIGNAL(triggered(bool)), preview, SLOT(setLandscapeOrientation()));
+
+ // Display mode
+ modeGroup = new QActionGroup(q);
+ singleModeAction = modeGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Show single page"));
+ facingModeAction = modeGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Show facing pages"));
+ overviewModeAction = modeGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Show overview of all pages"));
+ qt_setupActionIcon(singleModeAction, QLatin1String("view-page-one"));
+ qt_setupActionIcon(facingModeAction, QLatin1String("view-page-sided"));
+ qt_setupActionIcon(overviewModeAction, QLatin1String("view-page-multi"));
+ singleModeAction->setObjectName(QLatin1String("singleModeAction"));
+ facingModeAction->setObjectName(QLatin1String("facingModeAction"));
+ overviewModeAction->setObjectName(QLatin1String("overviewModeAction"));
+
+ singleModeAction->setCheckable(true);
+ facingModeAction->setCheckable(true);
+ overviewModeAction->setCheckable(true);
+ QObject::connect(modeGroup, SIGNAL(triggered(QAction*)), q, SLOT(_q_setMode(QAction*)));
+
+ // Print
+ printerGroup = new QActionGroup(q);
+ printAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Print"));
+ pageSetupAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Page setup"));
+ qt_setupActionIcon(printAction, QLatin1String("print"));
+ qt_setupActionIcon(pageSetupAction, QLatin1String("page-setup"));
+ QObject::connect(printAction, SIGNAL(triggered(bool)), q, SLOT(_q_print()));
+ QObject::connect(pageSetupAction, SIGNAL(triggered(bool)), q, SLOT(_q_pageSetup()));
+#if defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
+ closeAction = printerGroup->addAction(QCoreApplication::translate("QPrintPreviewDialog", "Close"));
+ QObject::connect(closeAction, SIGNAL(triggered(bool)), q, SLOT(reject()));
+#endif
+
+ // Initial state:
+ fitPageAction->setChecked(true);
+ singleModeAction->setChecked(true);
+ if (preview->orientation() == QPrinter::Portrait)
+ portraitAction->setChecked(true);
+ else
+ landscapeAction->setChecked(true);
+}
+
+
+bool QPrintPreviewDialogPrivate::isFitting()
+{
+ return (fitGroup->isExclusive()
+ && (fitWidthAction->isChecked() || fitPageAction->isChecked()));
+}
+
+
+void QPrintPreviewDialogPrivate::setFitting(bool on)
+{
+ if (isFitting() == on)
+ return;
+ fitGroup->setExclusive(on);
+ if (on) {
+ QAction* action = fitWidthAction->isChecked() ? fitWidthAction : fitPageAction;
+ action->setChecked(true);
+ if (fitGroup->checkedAction() != action) {
+ // work around exclusitivity problem
+ fitGroup->removeAction(action);
+ fitGroup->addAction(action);
+ }
+ } else {
+ fitWidthAction->setChecked(false);
+ fitPageAction->setChecked(false);
+ }
+}
+
+void QPrintPreviewDialogPrivate::updateNavActions()
+{
+ int curPage = preview->currentPage();
+ int numPages = preview->pageCount();
+ nextPageAction->setEnabled(curPage < numPages);
+ prevPageAction->setEnabled(curPage > 1);
+ firstPageAction->setEnabled(curPage > 1);
+ lastPageAction->setEnabled(curPage < numPages);
+ pageNumEdit->setText(QString::number(curPage));
+}
+
+void QPrintPreviewDialogPrivate::updatePageNumLabel()
+{
+ Q_Q(QPrintPreviewDialog);
+
+ int numPages = preview->pageCount();
+ int maxChars = QString::number(numPages).length();
+ pageNumLabel->setText(QString::fromLatin1("/ %1").arg(numPages));
+ int cyphersWidth = q->fontMetrics().width(QString().fill(QLatin1Char('8'), maxChars));
+ int maxWidth = pageNumEdit->minimumSizeHint().width() + cyphersWidth;
+ pageNumEdit->setMinimumWidth(maxWidth);
+ pageNumEdit->setMaximumWidth(maxWidth);
+ pageNumEdit->setValidator(new QIntValidator(1, numPages, pageNumEdit));
+ // any old one will be deleted later along with its parent pageNumEdit
+}
+
+void QPrintPreviewDialogPrivate::updateZoomFactor()
+{
+ zoomFactor->lineEdit()->setText(QString().sprintf("%.1f%%", preview->zoomFactor()*100));
+}
+
+void QPrintPreviewDialogPrivate::_q_fit(QAction* action)
+{
+ setFitting(true);
+ if (action == fitPageAction)
+ preview->fitInView();
+ else
+ preview->fitToWidth();
+}
+
+void QPrintPreviewDialogPrivate::_q_zoomIn()
+{
+ setFitting(false);
+ preview->zoomIn();
+ updateZoomFactor();
+}
+
+void QPrintPreviewDialogPrivate::_q_zoomOut()
+{
+ setFitting(false);
+ preview->zoomOut();
+ updateZoomFactor();
+}
+
+void QPrintPreviewDialogPrivate::_q_pageNumEdited()
+{
+ bool ok = false;
+ int res = pageNumEdit->text().toInt(&ok);
+ if (ok)
+ preview->setCurrentPage(res);
+}
+
+void QPrintPreviewDialogPrivate::_q_navigate(QAction* action)
+{
+ int curPage = preview->currentPage();
+ if (action == prevPageAction)
+ preview->setCurrentPage(curPage - 1);
+ else if (action == nextPageAction)
+ preview->setCurrentPage(curPage + 1);
+ else if (action == firstPageAction)
+ preview->setCurrentPage(1);
+ else if (action == lastPageAction)
+ preview->setCurrentPage(preview->pageCount());
+ updateNavActions();
+}
+
+void QPrintPreviewDialogPrivate::_q_setMode(QAction* action)
+{
+ if (action == overviewModeAction) {
+ preview->setViewMode(QPrintPreviewWidget::AllPagesView);
+ setFitting(false);
+ fitGroup->setEnabled(false);
+ navGroup->setEnabled(false);
+ pageNumEdit->setEnabled(false);
+ pageNumLabel->setEnabled(false);
+ } else if (action == facingModeAction) {
+ preview->setViewMode(QPrintPreviewWidget::FacingPagesView);
+ } else {
+ preview->setViewMode(QPrintPreviewWidget::SinglePageView);
+ }
+ if (action == facingModeAction || action == singleModeAction) {
+ fitGroup->setEnabled(true);
+ navGroup->setEnabled(true);
+ pageNumEdit->setEnabled(true);
+ pageNumLabel->setEnabled(true);
+ setFitting(true);
+ }
+}
+
+void QPrintPreviewDialogPrivate::_q_print()
+{
+ Q_Q(QPrintPreviewDialog);
+
+#if defined(Q_WS_WIN) || defined(Q_WS_MAC)
+ if (printer->outputFormat() != QPrinter::NativeFormat) {
+ QString title;
+ QString suffix;
+ if (printer->outputFormat() == QPrinter::PdfFormat) {
+ title = QCoreApplication::translate("QPrintPreviewDialog", "Export to PDF");
+ suffix = QLatin1String(".pdf");
+ } else {
+ title = QCoreApplication::translate("QPrintPreviewDialog", "Export to PostScript");
+ suffix = QLatin1String(".ps");
+ }
+ QString fileName = QFileDialog::getSaveFileName(q, title, printer->outputFileName(),
+ QLatin1Char('*') + suffix);
+ if (!fileName.isEmpty()) {
+ if (QFileInfo(fileName).suffix().isEmpty())
+ fileName.append(suffix);
+ printer->setOutputFileName(fileName);
+ }
+ if (!printer->outputFileName().isEmpty())
+ preview->print();
+ q->accept();
+ return;
+ }
+#endif
+
+ if (!printDialog)
+ printDialog = new QPrintDialog(printer, q);
+ if (printDialog->exec() == QDialog::Accepted) {
+ preview->print();
+ q->accept();
+ }
+}
+
+void QPrintPreviewDialogPrivate::_q_pageSetup()
+{
+ Q_Q(QPrintPreviewDialog);
+
+ QPageSetupDialog pageSetup(printer, q);
+ if (pageSetup.exec() == QDialog::Accepted) {
+ // update possible orientation changes
+ if (preview->orientation() == QPrinter::Portrait) {
+ portraitAction->setChecked(true);
+ preview->setPortraitOrientation();
+ }else {
+ landscapeAction->setChecked(true);
+ preview->setLandscapeOrientation();
+ }
+ }
+}
+
+void QPrintPreviewDialogPrivate::_q_previewChanged()
+{
+ updateNavActions();
+ updatePageNumLabel();
+ updateZoomFactor();
+}
+
+void QPrintPreviewDialogPrivate::_q_zoomFactorChanged()
+{
+ QString text = zoomFactor->lineEdit()->text();
+ bool ok;
+ qreal factor = text.remove(QLatin1Char('%')).toFloat(&ok);
+ factor = qMax(qreal(1.0), qMin(qreal(1000.0), factor));
+ if (ok) {
+ preview->setZoomFactor(factor/100.0);
+ zoomFactor->setEditText(QString::fromLatin1("%1%").arg(factor));
+ setFitting(false);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+
+/*!
+ \class QPrintPreviewDialog
+ \since 4.4
+
+ \brief The QPrintPreviewDialog class provides a dialog for
+ previewing and configuring page layouts for printer output.
+
+ \ingroup standard-dialogs
+ \ingroup printing
+
+ Using QPrintPreviewDialog in your existing application is
+ straightforward:
+
+ \list 1
+ \o Create the QPrintPreviewDialog.
+
+ You can construct a QPrintPreviewDialog with an existing QPrinter
+ object, or you can have QPrintPreviewDialog create one for you,
+ which will be the system default printer.
+
+ \o Connect the paintRequested() signal to a slot.
+
+ When the dialog needs to generate a set of preview pages, the
+ paintRequested() signal will be emitted. You can use the exact
+ same code for the actual printing as for having the preview
+ generated, including calling QPrinter::newPage() to start a new
+ page in the preview. Connect a slot to the paintRequested()
+ signal, where you draw onto the QPrinter object that is passed
+ into the slot.
+
+ \o Call exec().
+
+ Call QPrintPreviewDialog::exec() to show the preview dialog.
+ \endlist
+
+ In Symbian, there is no support for printing. Hence, this dialog should not
+ be used in Symbian.
+
+ \sa QPrinter, QPrintDialog, QPageSetupDialog, QPrintPreviewWidget
+*/
+
+/*!
+ Constructs a QPrintPreviewDialog based on \a printer and with \a
+ parent as the parent widget. The widget flags \a flags are passed on
+ to the QWidget constructor.
+
+ \sa QWidget::setWindowFlags()
+*/
+QPrintPreviewDialog::QPrintPreviewDialog(QPrinter* printer, QWidget *parent, Qt::WindowFlags flags)
+ : QDialog(*new QPrintPreviewDialogPrivate, parent, flags)
+{
+ Q_D(QPrintPreviewDialog);
+ d->init(printer);
+}
+
+/*!
+ \overload
+ \fn QPrintPreviewDialog::QPrintPreviewDialog(QWidget *parent, Qt::WindowFlags flags)
+
+ This will create an internal QPrinter object, which will use the
+ system default printer.
+*/
+QPrintPreviewDialog::QPrintPreviewDialog(QWidget *parent, Qt::WindowFlags f)
+ : QDialog(*new QPrintPreviewDialogPrivate, parent, f)
+{
+ Q_D(QPrintPreviewDialog);
+ d->init();
+}
+
+/*!
+ Destroys the QPrintPreviewDialog.
+*/
+QPrintPreviewDialog::~QPrintPreviewDialog()
+{
+ Q_D(QPrintPreviewDialog);
+ if (d->ownPrinter)
+ delete d->printer;
+ delete d->printDialog;
+}
+
+/*!
+ \reimp
+*/
+void QPrintPreviewDialog::setVisible(bool visible)
+{
+ Q_D(QPrintPreviewDialog);
+ // this will make the dialog get a decent default size
+ if (visible && !d->initialized) {
+ d->preview->updatePreview();
+ d->initialized = true;
+ }
+ QDialog::setVisible(visible);
+}
+
+/*!
+ \reimp
+*/
+void QPrintPreviewDialog::done(int result)
+{
+ Q_D(QPrintPreviewDialog);
+ QDialog::done(result);
+ if (d->receiverToDisconnectOnClose) {
+ disconnect(this, SIGNAL(finished(int)),
+ d->receiverToDisconnectOnClose, d->memberToDisconnectOnClose);
+ d->receiverToDisconnectOnClose = 0;
+ }
+ d->memberToDisconnectOnClose.clear();
+}
+
+/*!
+ \overload
+ \since 4.5
+
+ Opens the dialog and connects its finished(int) 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 QPrintPreviewDialog::open(QObject *receiver, const char *member)
+{
+ Q_D(QPrintPreviewDialog);
+ // the int parameter isn't very useful here; we could just as well connect
+ // to reject(), but this feels less robust somehow
+ connect(this, SIGNAL(finished(int)), receiver, member);
+ d->receiverToDisconnectOnClose = receiver;
+ d->memberToDisconnectOnClose = member;
+ QDialog::open();
+}
+
+/*!
+ Returns a pointer to the QPrinter object this dialog is currently
+ operating on.
+*/
+QPrinter *QPrintPreviewDialog::printer()
+{
+ Q_D(QPrintPreviewDialog);
+ return d->printer;
+}
+
+/*!
+ \fn void QPrintPreviewDialog::paintRequested(QPrinter *printer)
+
+ This signal is emitted when the QPrintPreviewDialog needs to generate
+ a set of preview pages.
+
+ The \a printer instance supplied is the paint device onto which you should
+ paint the contents of each page, using the QPrinter instance in the same way
+ as you would when printing directly.
+*/
+
+
+QT_END_NAMESPACE
+
+#include "moc_qprintpreviewdialog.cpp"
+#include "qprintpreviewdialog.moc"
+
+#endif // QT_NO_PRINTPREVIEWDIALOG
+
+
diff --git a/src/widgets/dialogs/qprintpreviewdialog.h b/src/widgets/dialogs/qprintpreviewdialog.h
new file mode 100644
index 0000000000..a49455b520
--- /dev/null
+++ b/src/widgets/dialogs/qprintpreviewdialog.h
@@ -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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPRINTPREVIEWDIALOG_H
+#define QPRINTPREVIEWDIALOG_H
+
+#include <QtGui/qdialog.h>
+
+#ifndef QT_NO_PRINTPREVIEWDIALOG
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGraphicsView;
+class QPrintPreviewDialogPrivate;
+
+class Q_GUI_EXPORT QPrintPreviewDialog : public QDialog
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPrintPreviewDialog)
+
+public:
+ explicit QPrintPreviewDialog(QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ explicit QPrintPreviewDialog(QPrinter *printer, QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ ~QPrintPreviewDialog();
+
+#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);
+
+ QPrinter *printer();
+
+ void setVisible(bool visible);
+ void done(int result);
+
+Q_SIGNALS:
+ void paintRequested(QPrinter *printer);
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_fit(QAction *action))
+ Q_PRIVATE_SLOT(d_func(), void _q_zoomIn())
+ Q_PRIVATE_SLOT(d_func(), void _q_zoomOut())
+ Q_PRIVATE_SLOT(d_func(), void _q_navigate(QAction *action))
+ Q_PRIVATE_SLOT(d_func(), void _q_setMode(QAction *action))
+ Q_PRIVATE_SLOT(d_func(), void _q_pageNumEdited())
+ Q_PRIVATE_SLOT(d_func(), void _q_print())
+ Q_PRIVATE_SLOT(d_func(), void _q_pageSetup())
+ Q_PRIVATE_SLOT(d_func(), void _q_previewChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_zoomFactorChanged())
+
+ void *dummy; // ### Qt 5 - remove me
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_PRINTPREVIEWDIALOG
+
+#endif // QPRINTPREVIEWDIALOG_H
diff --git a/src/widgets/dialogs/qprintpropertieswidget.ui b/src/widgets/dialogs/qprintpropertieswidget.ui
new file mode 100644
index 0000000000..26fa09599e
--- /dev/null
+++ b/src/widgets/dialogs/qprintpropertieswidget.ui
@@ -0,0 +1,70 @@
+<ui version="4.0" >
+ <class>QPrintPropertiesWidget</class>
+ <widget class="QWidget" name="QPrintPropertiesWidget" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>396</width>
+ <height>288</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTabWidget" name="tabs" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tabPage" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>392</width>
+ <height>261</height>
+ </rect>
+ </property>
+ <attribute name="title" >
+ <string>Page</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QPageSetupWidget" native="1" name="pageSetup" />
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="cupsPropertiesPage" >
+ <attribute name="title" >
+ <string>Advanced</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" >
+ <item>
+ <widget class="QTreeView" name="treeView" >
+ <property name="alternatingRowColors" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>QPageSetupWidget</class>
+ <extends>QWidget</extends>
+ <header>qpagesetupdialog_unix_p.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/widgets/dialogs/qprintsettingsoutput.ui b/src/widgets/dialogs/qprintsettingsoutput.ui
new file mode 100644
index 0000000000..be916790fb
--- /dev/null
+++ b/src/widgets/dialogs/qprintsettingsoutput.ui
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QPrintSettingsOutput</class>
+ <widget class="QWidget" name="QPrintSettingsOutput">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>426</width>
+ <height>171</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QTabWidget" name="tabs">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="copiesTab">
+ <attribute name="title">
+ <string>Copies</string>
+ </attribute>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QGroupBox" name="gbPrintRange">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Print range</string>
+ </property>
+ <layout class="QVBoxLayout" name="_3">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="margin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="printAll">
+ <property name="text">
+ <string>Print all</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="_4">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="printRange">
+ <property name="text">
+ <string>Pages from</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="from">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>to</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="to">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>999</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="printCurrentPage">
+ <property name="text">
+ <string>Current Page</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="printSelection">
+ <property name="text">
+ <string>Selection</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>1</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Output Settings</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Copies:</string>
+ </property>
+ <property name="buddy">
+ <cstring>copies</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="2">
+ <widget class="QSpinBox" name="copies">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>999</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>91</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QCheckBox" name="collate">
+ <property name="text">
+ <string>Collate</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" rowspan="2" colspan="2">
+ <widget class="QLabel" name="outputIcon">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Ignored" vsizetype="Ignored">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QCheckBox" name="reverse">
+ <property name="text">
+ <string>Reverse</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="4">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="optionsTab">
+ <attribute name="title">
+ <string>Options</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="1">
+ <widget class="QGroupBox" name="colorMode">
+ <property name="title">
+ <string>Color Mode</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="2" column="0">
+ <spacer name="verticalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>1</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="color">
+ <property name="text">
+ <string>Color</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" rowspan="3">
+ <widget class="QLabel" name="colorIcon"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QRadioButton" name="grayscale">
+ <property name="text">
+ <string>Grayscale</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QGroupBox" name="duplex">
+ <property name="title">
+ <string>Duplex Printing</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QRadioButton" name="noDuplex">
+ <property name="text">
+ <string>None</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="duplexLong">
+ <property name="text">
+ <string>Long side</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="duplexShort">
+ <property name="text">
+ <string>Short side</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_42">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>1</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>printRange</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>from</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>76</x>
+ <y>59</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>122</x>
+ <y>57</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>printRange</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>to</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>69</x>
+ <y>67</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>215</x>
+ <y>67</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/widgets/dialogs/qprintwidget.ui b/src/widgets/dialogs/qprintwidget.ui
new file mode 100644
index 0000000000..8a4f3bde0a
--- /dev/null
+++ b/src/widgets/dialogs/qprintwidget.ui
@@ -0,0 +1,116 @@
+<ui version="4.0" >
+ <class>QPrintWidget</class>
+ <widget class="QWidget" name="QPrintWidget" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>443</width>
+ <height>175</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="printerGroup" >
+ <property name="title" >
+ <string>Printer</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>&amp;Name:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>printers</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="printers" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
+ <horstretch>3</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QPushButton" name="properties" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Fixed" hsizetype="Minimum" >
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>P&amp;roperties</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Location:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLabel" name="location" />
+ </item>
+ <item row="1" column="2" >
+ <widget class="QCheckBox" name="preview" >
+ <property name="text" >
+ <string>Preview</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Type:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="type" />
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="lOutput" >
+ <property name="text" >
+ <string>Output &amp;file:</string>
+ </property>
+ <property name="buddy" >
+ <cstring>filename</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2" >
+ <layout class="QHBoxLayout" name="horizontalLayout" >
+ <item>
+ <widget class="QLineEdit" name="filename" />
+ </item>
+ <item>
+ <widget class="QToolButton" name="fileBrowser" >
+ <property name="text" >
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/widgets/dialogs/qprogressdialog.cpp b/src/widgets/dialogs/qprogressdialog.cpp
new file mode 100644
index 0000000000..a3fff9b617
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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 <QtGui/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..21a40c152f
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPROGRESSDIALOG_H
+#define QPROGRESSDIALOG_H
+
+#include <QtGui/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_GUI_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..2869e1262b
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..188f4d7f0f
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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..ce5118f91d
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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..148a5924b9
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIZARD_H
+#define QWIZARD_H
+
+#include <QtGui/qdialog.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_WIZARD
+
+class QAbstractButton;
+class QWizardPage;
+class QWizardPrivate;
+
+class Q_GUI_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_GUI_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..3480c6853c
--- /dev/null
+++ b/src/widgets/dialogs/qwizard_win.cpp
@@ -0,0 +1,759 @@
+/****************************************************************************
+**
+** 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_WIZARD
+#ifndef QT_NO_STYLE_WINDOWSVISTA
+
+#include "qwizard_win_p.h"
+#include <private/qsystemlibrary_p.h>
+#include "qwizard.h"
+#include "qpaintengine.h"
+#include "qapplication.h"
+#include <QtGui/QMouseEvent>
+#include <QtGui/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;
+
+ pDrawThemeBackground(theme, p.paintEngine()->getDC(), 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;
+ HANDLE hTheme = pOpenThemeData(QApplication::desktop()->winId(), 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();
+ HRESULT hr = pDwmExtendFrameIntoClientArea(wizard->winId(), &mar);
+ value = SUCCEEDED(hr);
+ }
+ return value;
+}
+
+void QVistaHelper::drawTitleBar(QPainter *painter)
+{
+ HDC hdc = painter->paintEngine()->getDC();
+
+ if (vistaState() == VistaAero)
+ drawBlackRect(QRect(0, 0, wizard->width(),
+ titleBarSize() + topOffset()), hdc);
+ Q_ASSERT(backButton_);
+ 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 = 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;
+ pSetWindowThemeAttribute(wizard->winId(), 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();
+ SetWindowPos(wizard->winId(), 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());
+ msg.hwnd = wizard->winId();
+ 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());
+ msg.hwnd = wizard->winId();
+ 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());
+ msg.hwnd = wizard->winId();
+ 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) {
+ HANDLE hTheme = pOpenThemeData(QApplication::desktop()->winId(), 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..b76f08264d
--- /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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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 <QtGui/private/qwidget_p.h>
+#include <QtGui/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