diff options
Diffstat (limited to 'src/gui')
199 files changed, 16984 insertions, 976 deletions
diff --git a/src/gui/dialogs/dialogs.pri b/src/gui/dialogs/dialogs.pri index f1ec858..b9fad41 100644 --- a/src/gui/dialogs/dialogs.pri +++ b/src/gui/dialogs/dialogs.pri @@ -7,6 +7,7 @@ HEADERS += \ 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 \ @@ -45,7 +46,7 @@ win32 { !win32-borland:!wince*: LIBS += -lshell32 # the filedialog needs this library } -!mac:!embedded:unix { +!mac:!embedded:!symbian:unix { HEADERS += dialogs/qpagesetupdialog_unix_p.h SOURCES += dialogs/qprintdialog_unix.cpp \ dialogs/qpagesetupdialog_unix.cpp @@ -70,7 +71,7 @@ embedded { } } -wince*: FORMS += dialogs/qfiledialog_wince.ui +wince*|symbian: FORMS += dialogs/qfiledialog_embedded.ui else: FORMS += dialogs/qfiledialog.ui INCLUDEPATH += $$PWD @@ -94,4 +95,4 @@ SOURCES += \ FORMS += dialogs/qpagesetupwidget.ui RESOURCES += dialogs/qprintdialog.qrc -RESOURCES += dialogs/qmessagebox.qrc
\ No newline at end of file +RESOURCES += dialogs/qmessagebox.qrc diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp index b3f3c5b..2d31c0b 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -64,8 +64,12 @@ 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_WS_S60) +# include "qfiledialog.h" +#endif +#if defined(Q_OS_SYMBIAN) +#include "qmenubar.h" #endif - #ifndef SPI_GETSNAPTODEFBUTTON # define SPI_GETSNAPTODEFBUTTON 95 #endif @@ -292,9 +296,13 @@ QDialog::QDialog(QDialogPrivate &dd, QWidget *parent, Qt::WindowFlags f) QDialog::~QDialog() { - // Need to hide() here, as our (to-be) overridden hide() - // will not be called in ~QWidget. - hide(); + 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 + } } /*! @@ -486,7 +494,22 @@ int QDialog::exec() #endif //QT_NO_MENUBAR #endif //Q_WS_WINCE_WM +#ifdef Q_OS_SYMBIAN +#ifndef QT_NO_MENUBAR + QMenuBar *menuBar = 0; + if (!findChild<QMenuBar *>()) + menuBar = new QMenuBar(this); +#endif +#endif + +#if !defined(Q_WS_S60) show(); +#else + if (qobject_cast<QFileDialog *>(this)) + showFullScreen(); + else + show(); +#endif #ifdef Q_WS_MAC d->mac_nativeDialogModalHelp(); @@ -511,6 +534,13 @@ int QDialog::exec() delete menuBar; #endif //QT_NO_MENUBAR #endif //Q_WS_WINCE_WM +#ifdef Q_OS_SYMBIAN +#ifndef QT_NO_MENUBAR + else if (menuBar) + delete menuBar; +#endif //QT_NO_MENUBAR +#endif //Q_OS_SYMBIAN + return res; } diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 493cec5..e3a4ca4 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -58,12 +58,15 @@ #include <qdebug.h> #include <qapplication.h> #include <qstylepainter.h> -#ifndef Q_WS_WINCE +#if !defined(Q_WS_WINCE) && !defined(Q_WS_S60) #include "ui_qfiledialog.h" #else -#include "ui_qfiledialog_wince.h" +#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 @@ -353,7 +356,6 @@ QFileDialog::~QFileDialog() settings.beginGroup(QLatin1String("Qt")); settings.setValue(QLatin1String("filedialog"), saveState()); #endif - delete d->qFileDialogUi; d->deleteNativeDialog_sys(); } @@ -485,6 +487,38 @@ void QFileDialog::changeEvent(QEvent *e) 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); @@ -2078,7 +2112,7 @@ void QFileDialogPrivate::init(const QString &directory, const QString &nameFilte q->restoreState(settings.value(QLatin1String("filedialog")).toByteArray()); #endif -#ifdef Q_WS_WINCE +#if defined(Q_EMBEDDED_SMALLSCREEN) qFileDialogUi->lookInLabel->setVisible(false); qFileDialogUi->fileNameLabel->setVisible(false); qFileDialogUi->fileTypeLabel->setVisible(false); @@ -2118,7 +2152,7 @@ void QFileDialogPrivate::createWidgets() q, SLOT(_q_rowsInserted(const QModelIndex &))); model->setReadOnly(false); - qFileDialogUi = new Ui_QFileDialog(); + qFileDialogUi.reset(new Ui_QFileDialog()); qFileDialogUi->setupUi(q); QList<QUrl> initialBookmarks; @@ -2144,7 +2178,7 @@ void QFileDialogPrivate::createWidgets() qFileDialogUi->fileNameLabel->setBuddy(qFileDialogUi->fileNameEdit); #endif #ifndef QT_NO_COMPLETER - completer = new QFSCompletor(model, q); + completer = new QFSCompleter(model, q); qFileDialogUi->fileNameEdit->setCompleter(completer); QObject::connect(qFileDialogUi->fileNameEdit, SIGNAL(textChanged(QString)), q, SLOT(_q_autoCompleteFileName(QString))); @@ -2202,9 +2236,9 @@ void QFileDialogPrivate::createWidgets() treeHeader->addAction(showHeader); } - QItemSelectionModel *selModel = qFileDialogUi->treeView->selectionModel(); + QScopedPointer<QItemSelectionModel> selModel(qFileDialogUi->treeView->selectionModel()); qFileDialogUi->treeView->setSelectionModel(qFileDialogUi->listView->selectionModel()); - delete selModel; + QObject::connect(qFileDialogUi->treeView, SIGNAL(activated(QModelIndex)), q, SLOT(_q_enterDirectory(QModelIndex))); QObject::connect(qFileDialogUi->treeView, SIGNAL(customContextMenuRequested(QPoint)), @@ -2286,9 +2320,9 @@ void QFileDialog::setProxyModel(QAbstractProxyModel *proxyModel) connect(d->model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SLOT(_q_rowsInserted(const QModelIndex &))); } - QItemSelectionModel *selModel = d->qFileDialogUi->treeView->selectionModel(); + QScopedPointer<QItemSelectionModel> selModel(d->qFileDialogUi->treeView->selectionModel()); d->qFileDialogUi->treeView->setSelectionModel(d->qFileDialogUi->listView->selectionModel()); - delete selModel; + d->setRootIndex(idx); // reconnect selection @@ -3169,7 +3203,7 @@ void QFileDialogLineEdit::keyPressEvent(QKeyEvent *e) #ifndef QT_NO_COMPLETER -QString QFSCompletor::pathFromIndex(const QModelIndex &index) const +QString QFSCompleter::pathFromIndex(const QModelIndex &index) const { const QFileSystemModel *dirModel; if (proxyModel) @@ -3184,14 +3218,17 @@ QString QFSCompletor::pathFromIndex(const QModelIndex &index) const return index.data(QFileSystemModel::FilePathRole).toString(); } -QStringList QFSCompletor::splitPath(const QString &path) const +QStringList QFSCompleter::splitPath(const QString &path) const { if (path.isEmpty()) return QStringList(completionPrefix()); QString pathCopy = QDir::toNativeSeparators(path); QString sep = QDir::separator(); -#ifdef Q_OS_WIN +#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("\\\\")); @@ -3203,7 +3240,11 @@ QStringList QFSCompletor::splitPath(const QString &path) const QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']')); -#ifdef Q_OS_WIN +#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); @@ -3215,7 +3256,7 @@ QStringList QFSCompletor::splitPath(const QString &path) const parts[0] = sep[0]; #endif -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(QLatin1Char(':')); #else bool startsFromRoot = path[0] == sep[0]; diff --git a/src/gui/dialogs/qfiledialog_wince.ui b/src/gui/dialogs/qfiledialog_embedded.ui index 8aa9e1b..8aa9e1b 100644 --- a/src/gui/dialogs/qfiledialog_wince.ui +++ b/src/gui/dialogs/qfiledialog_embedded.ui diff --git a/src/gui/dialogs/qfiledialog_p.h b/src/gui/dialogs/qfiledialog_p.h index a393ec7..2925c8c 100644 --- a/src/gui/dialogs/qfiledialog_p.h +++ b/src/gui/dialogs/qfiledialog_p.h @@ -76,6 +76,7 @@ #include <qtimeline.h> #include <qdebug.h> #include "qsidebar_p.h" +#include "qfscompleter_p.h" #if defined (Q_OS_UNIX) #include <unistd.h> @@ -91,25 +92,6 @@ class QCompleter; class QHBoxLayout; class Ui_QFileDialog; -#ifndef QT_NO_COMPLETER -/*! - QCompleter that can deal with QFileSystemModel - */ -class QFSCompletor : public QCompleter { -public: - QFSCompletor(QFileSystemModel *model, QObject *parent = 0) : QCompleter(model, parent), proxyModel(0), sourceModel(model) - { -#ifdef Q_OS_WIN - setCaseSensitivity(Qt::CaseInsensitive); -#endif - } - QString pathFromIndex(const QModelIndex &index) const; - QStringList splitPath(const QString& path) const; - - QAbstractProxyModel *proxyModel; - QFileSystemModel *sourceModel; -}; -#endif // QT_NO_COMPLETER struct QFileDialogArgs { @@ -131,31 +113,7 @@ class Q_AUTOTEST_EXPORT QFileDialogPrivate : public QDialogPrivate Q_DECLARE_PUBLIC(QFileDialog) public: - 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(); void createToolButtons(); void createMenuActions(); @@ -224,7 +182,7 @@ public: static inline QString toInternal(const QString &path) { -#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) +#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('/'); @@ -298,7 +256,7 @@ public: bool defaultFileTypes; bool fileNameLabelExplicitlySat; QStringList nameFilters; - + // Members for using native dialogs: bool nativeDialogInUse; // setVisible_sys returns true if it ends up showing a native @@ -360,7 +318,7 @@ public: void mac_nativeDialogModalHelp(); #endif - Ui_QFileDialog *qFileDialogUi; + QScopedPointer<Ui_QFileDialog> qFileDialogUi; QString acceptLabel; @@ -369,6 +327,11 @@ public: QByteArray signalToDisconnectOnClose; QFileDialog::Options opts; + + ~QFileDialogPrivate(); + +private: + Q_DISABLE_COPY(QFileDialogPrivate) }; class QFileDialogLineEdit : public QLineEdit diff --git a/src/gui/dialogs/qfileinfogatherer.cpp b/src/gui/dialogs/qfileinfogatherer.cpp index 23a2cbc..119164d 100644 --- a/src/gui/dialogs/qfileinfogatherer.cpp +++ b/src/gui/dialogs/qfileinfogatherer.cpp @@ -83,10 +83,10 @@ QFileInfoGatherer::QFileInfoGatherer(QObject *parent) */ QFileInfoGatherer::~QFileInfoGatherer() { - mutex.lock(); + QMutexLocker locker(&mutex); abort = true; condition.wakeOne(); - mutex.unlock(); + locker.unlock(); wait(); } @@ -94,9 +94,8 @@ void QFileInfoGatherer::setResolveSymlinks(bool enable) { Q_UNUSED(enable); #ifdef Q_OS_WIN - mutex.lock(); + QMutexLocker locker(&mutex); m_resolveSymlinks = enable; - mutex.unlock(); #endif } @@ -107,9 +106,8 @@ bool QFileInfoGatherer::resolveSymlinks() const void QFileInfoGatherer::setIconProvider(QFileIconProvider *provider) { - mutex.lock(); + QMutexLocker locker(&mutex); m_iconProvider = provider; - mutex.unlock(); } QFileIconProvider *QFileInfoGatherer::iconProvider() const @@ -124,12 +122,11 @@ QFileIconProvider *QFileInfoGatherer::iconProvider() const */ void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStringList &files) { - mutex.lock(); + 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) { - mutex.unlock(); return; } loc = this->path.lastIndexOf(path, loc - 1); @@ -137,7 +134,6 @@ void QFileInfoGatherer::fetchExtendedInformation(const QString &path, const QStr this->path.push(path); this->files.push(files); condition.wakeAll(); - mutex.unlock(); } /*! @@ -160,10 +156,9 @@ void QFileInfoGatherer::updateFile(const QString &filePath) void QFileInfoGatherer::clear() { #ifndef QT_NO_FILESYSTEMWATCHER - mutex.lock(); + QMutexLocker locker(&mutex); watcher->removePaths(watcher->files()); watcher->removePaths(watcher->directories()); - mutex.unlock(); #endif } @@ -175,9 +170,8 @@ void QFileInfoGatherer::clear() void QFileInfoGatherer::removePath(const QString &path) { #ifndef QT_NO_FILESYSTEMWATCHER - mutex.lock(); + QMutexLocker locker(&mutex); watcher->removePath(path); - mutex.unlock(); #endif } @@ -198,9 +192,8 @@ void QFileInfoGatherer::run() { forever { bool updateFiles = false; - mutex.lock(); + QMutexLocker locker(&mutex); if (abort) { - mutex.unlock(); return; } if (this->path.isEmpty()) @@ -214,8 +207,9 @@ void QFileInfoGatherer::run() this->files.pop_front(); updateFiles = true; } - mutex.unlock(); - if (updateFiles) getFileInfos(path, list); + locker.unlock(); + if (updateFiles) + getFileInfos(path, list); } } @@ -287,6 +281,8 @@ QString QFileInfoGatherer::translateDriveName(const QFileInfo &drive) const #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 diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index 603789e..d9ae5bf 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -355,7 +355,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS // ### 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) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) && QDir::fromNativeSeparators(longPath) != QLatin1String("/") #endif ) @@ -384,9 +384,21 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS r = translateVisibleLocation(rootNode, r); index = q->index(r, 0, QModelIndex()); pathElements.pop_front(); - } else { + } else +#endif + +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + { if (!pathElements.at(0).contains(QLatin1String(":"))) +#if defined(Q_CC_NOKIAX86) + { + // Workaround for bizarre compiler crash. + QString rootPath = QDir(longPath).rootPath(); + pathElements.prepend(rootPath); + } +#else pathElements.prepend(QDir(longPath).rootPath()); +#endif if (pathElements.at(0).endsWith(QLatin1Char('/'))) pathElements[0].chop(1); } @@ -1596,12 +1608,25 @@ void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, cons 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(), i.value()->fileName); + 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); } @@ -1924,8 +1949,8 @@ bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const return true; } -#include "moc_qfilesystemmodel.cpp" +QT_END_NAMESPACE -#endif // QT_NO_FILESYSTEMMODEL +#include "moc_qfilesystemmodel.cpp" -QT_END_NAMESPACE +#endif // QT_NO_FILESYSTEMMODEL
\ No newline at end of file diff --git a/src/gui/dialogs/qfscompleter_p.h b/src/gui/dialogs/qfscompleter_p.h new file mode 100644 index 0000000..c65eeea --- /dev/null +++ b/src/gui/dialogs/qfscompleter_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOMPLETOR_P_H +#define QCOMPLETOR_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_COMPLETER + +/*! + 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_COMPLETER +QT_END_NAMESPACE +#endif // QCOMPLETOR_P_H + diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index 1fefb67..68044c8 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -270,7 +270,7 @@ void QMessageBoxPrivate::updateSize() return; QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()).size(); -#if defined(Q_WS_QWS) || defined(Q_WS_WINCE) +#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 diff --git a/src/gui/dialogs/qpagesetupdialog_win.cpp b/src/gui/dialogs/qpagesetupdialog_win.cpp index 2c74ed2..ffad77c 100644 --- a/src/gui/dialogs/qpagesetupdialog_win.cpp +++ b/src/gui/dialogs/qpagesetupdialog_win.cpp @@ -71,7 +71,7 @@ int QPageSetupDialog::exec() return Rejected; QWin32PrintEngine *engine = static_cast<QWin32PrintEngine*>(d->printer->paintEngine()); - QWin32PrintEnginePrivate *ep = static_cast<QWin32PrintEnginePrivate *>(engine->d_ptr); + QWin32PrintEnginePrivate *ep = static_cast<QWin32PrintEnginePrivate *>(engine->d_ptr.data()); PAGESETUPDLG psd; memset(&psd, 0, sizeof(PAGESETUPDLG)); diff --git a/src/gui/dialogs/qprintdialog_unix.cpp b/src/gui/dialogs/qprintdialog_unix.cpp index 8456d13..2f7f7c1 100644 --- a/src/gui/dialogs/qprintdialog_unix.cpp +++ b/src/gui/dialogs/qprintdialog_unix.cpp @@ -44,7 +44,6 @@ #ifndef QT_NO_PRINTDIALOG #include "private/qabstractprintdialog_p.h" -#include "qfiledialog_p.h" #include <QtGui/qmessagebox.h> #include "qprintdialog.h" #include "qfiledialog.h" @@ -55,6 +54,7 @@ #include <QtGui/qdialogbuttonbox.h> +#include "qfscompleter_p.h" #include "ui_qprintpropertieswidget.h" #include "ui_qprintsettingsoutput.h" #include "ui_qprintwidget.h" @@ -696,7 +696,7 @@ QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p) QFileSystemModel *fsm = new QFileSystemModel(widget.filename); fsm->setRootPath(QDir::homePath()); #if !defined(QT_NO_COMPLETER) && !defined(QT_NO_FILEDIALOG) - widget.filename->setCompleter(new QFSCompletor(fsm, widget.filename)); + widget.filename->setCompleter(new QFSCompleter(fsm, widget.filename)); #endif #endif _q_printerChanged(currentPrinterIndex); diff --git a/src/gui/dialogs/qprintpreviewdialog.cpp b/src/gui/dialogs/qprintpreviewdialog.cpp index a696160..835f372 100644 --- a/src/gui/dialogs/qprintpreviewdialog.cpp +++ b/src/gui/dialogs/qprintpreviewdialog.cpp @@ -42,6 +42,7 @@ #include "qprintpreviewdialog.h" #include "qprintpreviewwidget.h" #include <private/qprinter_p.h> +#include "private/qdialog_p.h" #include <QtGui/qaction.h> #include <QtGui/qboxlayout.h> @@ -138,12 +139,12 @@ private: }; } // anonymous namespace -class QPrintPreviewDialogPrivate +class QPrintPreviewDialogPrivate : public QDialogPrivate { Q_DECLARE_PUBLIC(QPrintPreviewDialog) public: - QPrintPreviewDialogPrivate(QPrintPreviewDialog *q) - : q_ptr(q), printDialog(0), ownPrinter(false), + QPrintPreviewDialogPrivate() + : printDialog(0), ownPrinter(false), initialized(false) {} // private slots @@ -168,7 +169,6 @@ public: void updatePageNumLabel(); void updateZoomFactor(); - QPrintPreviewDialog *q_ptr; QPrintDialog *printDialog; QPrintPreviewWidget *preview; QPrinter *printer; @@ -662,7 +662,7 @@ void QPrintPreviewDialogPrivate::_q_zoomFactorChanged() \sa QWidget::setWindowFlags() */ QPrintPreviewDialog::QPrintPreviewDialog(QPrinter* printer, QWidget *parent, Qt::WindowFlags flags) - : QDialog(parent, flags), d_ptr(new QPrintPreviewDialogPrivate(this)) + : QDialog(*new QPrintPreviewDialogPrivate, parent, flags) { Q_D(QPrintPreviewDialog); d->init(printer); @@ -676,7 +676,7 @@ QPrintPreviewDialog::QPrintPreviewDialog(QPrinter* printer, QWidget *parent, Qt: system default printer. */ QPrintPreviewDialog::QPrintPreviewDialog(QWidget *parent, Qt::WindowFlags f) - : QDialog(parent, f), d_ptr(new QPrintPreviewDialogPrivate(this)) + : QDialog(*new QPrintPreviewDialogPrivate, parent, f) { Q_D(QPrintPreviewDialog); d->init(); @@ -691,7 +691,6 @@ QPrintPreviewDialog::~QPrintPreviewDialog() if (d->ownPrinter) delete d->printer; delete d->printDialog; - delete d_ptr; } /*! diff --git a/src/gui/dialogs/qprintpreviewdialog.h b/src/gui/dialogs/qprintpreviewdialog.h index c3a4d57..49262db 100644 --- a/src/gui/dialogs/qprintpreviewdialog.h +++ b/src/gui/dialogs/qprintpreviewdialog.h @@ -94,7 +94,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_previewChanged()) Q_PRIVATE_SLOT(d_func(), void _q_zoomFactorChanged()) - QPrintPreviewDialogPrivate *d_ptr; + void *dummy; // ### Qt 5 - remove me }; diff --git a/src/gui/embedded/qsoundqss_qws.cpp b/src/gui/embedded/qsoundqss_qws.cpp index 283bbd3..ed988ca 100644 --- a/src/gui/embedded/qsoundqss_qws.cpp +++ b/src/gui/embedded/qsoundqss_qws.cpp @@ -1036,24 +1036,28 @@ void QWSSoundServerPrivate::stopFile(int wid, int sid) void QWSSoundServerPrivate::stopAll(int wid) { QWSSoundServerProvider *bucket; - QList<QWSSoundServerProvider*>::Iterator it = active.begin(); - while (it != active.end()) { - bucket = *it; - if (bucket->groupId() == wid) { - it = active.erase(it); - delete bucket; - } else { - ++it; + if (!active.isEmpty()) { + QList<QWSSoundServerProvider*>::Iterator it = active.begin(); + while (it != active.end()) { + bucket = *it; + if (bucket->groupId() == wid) { + it = active.erase(it); + delete bucket; + } else { + ++it; + } } } - it = inactive.begin(); - while (it != inactive.end()) { - bucket = *it; - if (bucket->groupId() == wid) { - it = inactive.erase(it); - delete bucket; - } else { - ++it; + if (!inactive.isEmpty()) { + QList<QWSSoundServerProvider*>::Iterator it = inactive.begin(); + while (it != inactive.end()) { + bucket = *it; + if (bucket->groupId() == wid) { + it = inactive.erase(it); + delete bucket; + } else { + ++it; + } } } } diff --git a/src/gui/embedded/qwindowsystem_qws.cpp b/src/gui/embedded/qwindowsystem_qws.cpp index a15decd..45d5bce 100644 --- a/src/gui/embedded/qwindowsystem_qws.cpp +++ b/src/gui/embedded/qwindowsystem_qws.cpp @@ -1304,7 +1304,13 @@ QWSServer::QWSServer(int flags, QObject *parent) : QObject(*new QWSServerPrivate, parent) { Q_D(QWSServer); - d->initServer(flags); + QT_TRY { + d->initServer(flags); + } QT_CATCH(...) { + qwsServer = 0; + qwsServerPrivate = 0; + QT_RETHROW; + } } #ifdef QT3_SUPPORT @@ -1750,21 +1756,23 @@ void QWSServerPrivate::cleanupFonts(bool force) #if defined(QWS_DEBUG_FONTCLEANUP) qDebug() << "cleanupFonts()"; #endif - QMap<QByteArray, int>::Iterator it = fontReferenceCount.begin(); - while (it != fontReferenceCount.end()) { - if (it.value() && !force) { - ++it; - continue; - } + if (!fontReferenceCount.isEmpty()) { + QMap<QByteArray, int>::Iterator it = fontReferenceCount.begin(); + while (it != fontReferenceCount.end()) { + if (it.value() && !force) { + ++it; + continue; + } - const QByteArray &fontName = it.key(); + const QByteArray &fontName = it.key(); #if defined(QWS_DEBUG_FONTCLEANUP) - qDebug() << "removing unused font file" << fontName; + qDebug() << "removing unused font file" << fontName; #endif - QFile::remove(QFile::decodeName(fontName)); - sendFontRemovedEvent(fontName); + QFile::remove(QFile::decodeName(fontName)); + sendFontRemovedEvent(fontName); - it = fontReferenceCount.erase(it); + it = fontReferenceCount.erase(it); + } } if (crashedClientIds.isEmpty()) @@ -3966,7 +3974,8 @@ void QWSServerPrivate::openDisplay() void QWSServerPrivate::closeDisplay() { - qt_screen->shutdownDevice(); + if (qt_screen) + qt_screen->shutdownDevice(); } /*! @@ -4065,9 +4074,14 @@ void QWSServer::startup(int flags) void QWSServer::closedown() { - unlink(qws_qtePipeFilename().toLatin1().constData()); - delete qwsServer; + QScopedPointer<QWSServer> server(qwsServer); qwsServer = 0; + QT_TRY { + unlink(qws_qtePipeFilename().toLatin1().constData()); + } QT_CATCH(const std::bad_alloc &) { + // ### TODO - what to do when we run out of memory + // when calling toLatin1? + } } void QWSServerPrivate::emergency_cleanup() diff --git a/src/gui/embedded/qwscursor_qws.cpp b/src/gui/embedded/qwscursor_qws.cpp index 3a5bd2c..b25e9b1 100644 --- a/src/gui/embedded/qwscursor_qws.cpp +++ b/src/gui/embedded/qwscursor_qws.cpp @@ -531,7 +531,7 @@ void QWSCursor::set(const uchar *data, const uchar *mask, cursor = QImage(width,height, QImage::Format_Indexed8); - if (!width || !height || !data || !mask) + if (!width || !height || !data || !mask || cursor.isNull()) return; cursor.setNumColors(3); diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index a436805..d9cba2a 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -568,6 +568,7 @@ #include <QtGui/qpixmapcache.h> #include <QtGui/qstyleoption.h> #include <QtGui/qevent.h> +#include <QInputContext> #include <private/qgraphicsitem_p.h> #include <private/qgraphicswidget_p.h> @@ -3324,7 +3325,7 @@ QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) co QTransform x; const QGraphicsItem *p = child; do { - p->d_ptr->combineTransformToParent(&x); + p->d_ptr->.data()->combineTransformToParent(&x); } while ((p = p->d_ptr->parent) && p != root); if (parentOfOther) return x.inverted(ok); @@ -3682,7 +3683,7 @@ QRectF QGraphicsItem::sceneBoundingRect() const const QGraphicsItem *parentItem = this; const QGraphicsItemPrivate *itemd; do { - itemd = parentItem->d_ptr; + itemd = parentItem->d_ptr.data(); if (itemd->transformData) break; offset += itemd->pos; @@ -8391,7 +8392,7 @@ class QGraphicsTextItemPrivate { public: QGraphicsTextItemPrivate() - : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false) + : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false), clickCausedFocus(0) { } mutable QTextControl *control; @@ -8412,6 +8413,8 @@ public: bool useDefaultImpl; bool tabChangesFocus; + uint clickCausedFocus : 1; + QGraphicsTextItem *qq; }; @@ -8741,7 +8744,13 @@ void QGraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event) dd->useDefaultImpl = false; return; } + dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8753,7 +8762,13 @@ void QGraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QGraphicsItem::mouseMoveEvent(event); return; } + dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8773,7 +8788,23 @@ void QGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } return; } + + if (event->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!dd->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent _event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(event->widget(), &_event); + } else { + QGraphicsItem::mouseReleaseEvent(event); + } + dd->clickCausedFocus = 0; + dd->sendControlEvent(event); + + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8792,6 +8823,11 @@ void QGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) } dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8800,6 +8836,11 @@ void QGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) void QGraphicsTextItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8808,6 +8849,18 @@ void QGraphicsTextItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) void QGraphicsTextItem::keyPressEvent(QKeyEvent *event) { dd->sendControlEvent(event); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->update(); + } + break; + } + } } /*! @@ -8816,6 +8869,18 @@ void QGraphicsTextItem::keyPressEvent(QKeyEvent *event) void QGraphicsTextItem::keyReleaseEvent(QKeyEvent *event) { dd->sendControlEvent(event); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->update(); + } + break; + } + } } /*! @@ -8824,7 +8889,22 @@ void QGraphicsTextItem::keyReleaseEvent(QKeyEvent *event) void QGraphicsTextItem::focusInEvent(QFocusEvent *event) { dd->sendControlEvent(event); + if (event->reason() == Qt::MouseFocusReason) { + dd->clickCausedFocus = 1; + } update(); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->reset(); + } + break; + } + } } /*! @@ -8834,6 +8914,18 @@ void QGraphicsTextItem::focusOutEvent(QFocusEvent *event) { dd->sendControlEvent(event); update(); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->reset(); + } + break; + } + } } /*! @@ -8842,6 +8934,11 @@ void QGraphicsTextItem::focusOutEvent(QFocusEvent *event) void QGraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8850,6 +8947,11 @@ void QGraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event) void QGraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8858,6 +8960,11 @@ void QGraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) void QGraphicsTextItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8866,6 +8973,11 @@ void QGraphicsTextItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event) void QGraphicsTextItem::dropEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8882,6 +8994,11 @@ void QGraphicsTextItem::inputMethodEvent(QInputMethodEvent *event) void QGraphicsTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8890,6 +9007,11 @@ void QGraphicsTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) void QGraphicsTextItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8898,6 +9020,11 @@ void QGraphicsTextItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) void QGraphicsTextItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index 6ea17c2..989be43 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -46,6 +46,7 @@ #include <QtCore/qobject.h> #include <QtCore/qvariant.h> #include <QtCore/qrect.h> +#include <QtCore/qscopedpointer.h> #include <QtGui/qpainterpath.h> #include <QtGui/qpixmap.h> @@ -421,7 +422,7 @@ protected: protected: QGraphicsItem(QGraphicsItemPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene); - QGraphicsItemPrivate *d_ptr; + QScopedPointer<QGraphicsItemPrivate> d_ptr; void addToIndex(); void removeFromIndex(); diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp index b58eb53..2d4bddb 100644 --- a/src/gui/graphicsview/qgraphicslayoutitem.cpp +++ b/src/gui/graphicsview/qgraphicslayoutitem.cpp @@ -369,7 +369,6 @@ QGraphicsLayoutItem::~QGraphicsLayoutItem() } } } - delete d_ptr; } /*! diff --git a/src/gui/graphicsview/qgraphicslayoutitem.h b/src/gui/graphicsview/qgraphicslayoutitem.h index 31f5d90..d667c4f 100644 --- a/src/gui/graphicsview/qgraphicslayoutitem.h +++ b/src/gui/graphicsview/qgraphicslayoutitem.h @@ -42,6 +42,7 @@ #ifndef QGRAPHICSLAYOUTITEM_H #define QGRAPHICSLAYOUTITEM_H +#include <QtCore/qscopedpointer.h> #include <QtGui/qsizepolicy.h> #include <QtGui/qevent.h> @@ -112,7 +113,7 @@ protected: QGraphicsLayoutItem(QGraphicsLayoutItemPrivate &dd); virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const = 0; - QGraphicsLayoutItemPrivate *d_ptr; + QScopedPointer<QGraphicsLayoutItemPrivate> d_ptr; private: QSizeF *effectiveSizeHints(const QSizeF &constraint) const; diff --git a/src/gui/graphicsview/qgraphicsproxywidget.h b/src/gui/graphicsview/qgraphicsproxywidget.h index ab8c9da..0c874c8 100644 --- a/src/gui/graphicsview/qgraphicsproxywidget.h +++ b/src/gui/graphicsview/qgraphicsproxywidget.h @@ -129,7 +129,7 @@ protected Q_SLOTS: private: Q_DISABLE_COPY(QGraphicsProxyWidget) - Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QGraphicsProxyWidget) + Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QGraphicsProxyWidget) Q_PRIVATE_SLOT(d_func(), void _q_removeWidgetSlot()) friend class QWidget; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 673fd23..900fa1a 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -1984,8 +1984,8 @@ void QGraphicsScenePrivate::invalidateSortCache() inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) { // Return true if sibling item1 is on top of item2. - const QGraphicsItemPrivate *d1 = item1->d_ptr; - const QGraphicsItemPrivate *d2 = item2->d_ptr; + const QGraphicsItemPrivate *d1 = item1->d_ptr.data(); + const QGraphicsItemPrivate *d2 = item2->d_ptr.data(); bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent; bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent; if (f1 != f2) return f2; @@ -2017,8 +2017,8 @@ inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem bool QGraphicsScenePrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2) { // Siblings? Just check their z-values. - const QGraphicsItemPrivate *d1 = item1->d_ptr; - const QGraphicsItemPrivate *d2 = item2->d_ptr; + const QGraphicsItemPrivate *d1 = item1->d_ptr.data(); + const QGraphicsItemPrivate *d2 = item2->d_ptr.data(); if (d1->parent == d2->parent) return qt_closestLeaf(item1, item2); @@ -4746,7 +4746,7 @@ void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painte const QStyleOptionGraphicsItem *option, QWidget *widget, bool painterStateProtection) { - QGraphicsItemPrivate *itemd = item->d_ptr; + QGraphicsItemPrivate *itemd = item->d_ptr.data(); QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode); // Render directly, using no cache. diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp index 0ffd2b1..ad57aac 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.cpp +++ b/src/gui/graphicsview/qgraphicssceneevent.cpp @@ -313,7 +313,6 @@ QGraphicsSceneEvent::QGraphicsSceneEvent(QGraphicsSceneEventPrivate &dd, Type ty */ QGraphicsSceneEvent::~QGraphicsSceneEvent() { - delete d_ptr; } /*! diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h index be50e96..4ebe3df 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.h +++ b/src/gui/graphicsview/qgraphicssceneevent.h @@ -44,6 +44,7 @@ #include <QtCore/qcoreevent.h> #include <QtCore/qpoint.h> +#include <QtCore/qscopedpointer.h> QT_BEGIN_HEADER @@ -70,7 +71,7 @@ public: protected: QGraphicsSceneEvent(QGraphicsSceneEventPrivate &dd, Type type = None); - QGraphicsSceneEventPrivate *d_ptr; + QScopedPointer<QGraphicsSceneEventPrivate> d_ptr; Q_DECLARE_PRIVATE(QGraphicsSceneEvent) }; diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index c94c1d7..a3e2ebe 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -751,7 +751,7 @@ QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRect const QGraphicsItem *parentItem = item; const QGraphicsItemPrivate *itemd; do { - itemd = parentItem->d_ptr; + itemd = parentItem->d_ptr.data(); if (itemd->transformData) break; offset += itemd->pos; @@ -1001,6 +1001,11 @@ QGraphicsView::QGraphicsView(QWidget *parent) // using a simple reference count. The same goes for acceptDrops and mouse // tracking. setAttribute(Qt::WA_InputMethodEnabled); + + // viewport part of the graphics view has to be enabled + // as well, because when events come this widget is asked + // for input context and so on + viewport()->setAttribute(Qt::WA_InputMethodEnabled); } /*! @@ -1015,6 +1020,11 @@ QGraphicsView::QGraphicsView(QGraphicsScene *scene, QWidget *parent) setAcceptDrops(true); setBackgroundRole(QPalette::Base); setAttribute(Qt::WA_InputMethodEnabled); + + // viewport part of the graphics view has to be enabled + // as well, because when events come this widget is asked + // for input context and so on + viewport()->setAttribute(Qt::WA_InputMethodEnabled); } /*! @@ -1027,6 +1037,11 @@ QGraphicsView::QGraphicsView(QGraphicsViewPrivate &dd, QWidget *parent) setAcceptDrops(true); setBackgroundRole(QPalette::Base); setAttribute(Qt::WA_InputMethodEnabled); + + // viewport part of the graphics view has to be enabled + // as well, because when events come this widget is asked + // for input context and so on + viewport()->setAttribute(Qt::WA_InputMethodEnabled); } /*! diff --git a/src/gui/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 78bd062..4e4944c 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -333,7 +333,7 @@ void QGraphicsWidget::resize(const QSizeF &size) void QGraphicsWidget::setGeometry(const QRectF &rect) { QGraphicsWidgetPrivate *wd = QGraphicsWidget::d_func(); - QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr; + QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr.data(); QRectF newGeom; QPointF oldPos = d->geom.topLeft(); if (!wd->inSetPos) { diff --git a/src/gui/graphicsview/qgraphicswidget.h b/src/gui/graphicsview/qgraphicswidget.h index 337490c..0563dcb 100644 --- a/src/gui/graphicsview/qgraphicswidget.h +++ b/src/gui/graphicsview/qgraphicswidget.h @@ -228,7 +228,7 @@ protected: private: Q_DISABLE_COPY(QGraphicsWidget) - Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QGraphicsWidget) + Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QGraphicsWidget) friend class QGraphicsScene; friend class QGraphicsScenePrivate; friend class QGraphicsView; diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 329fb01..4ff3a27 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -4,7 +4,7 @@ QT = core DEFINES += QT_BUILD_GUI_LIB QT_NO_USING_NAMESPACE win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x65000000 -!win32:!embedded:!mac:CONFIG += x11 +!win32:!embedded:!mac:!symbian:CONFIG += x11 unix:QMAKE_PKGCONFIG_REQUIRES = QtCore @@ -45,3 +45,7 @@ QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist DEFINES += Q_INTERNAL_QAPP_SRC +symbian:TARGET.UID3=0x2001B2DD + +# ro-section in gui can exceed default allocated space, so more rw-section little further +symbian-sbsv2: MMP_RULES += "LINKEROPTION armcc --rw-base 0x800000"
\ No newline at end of file diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index bf348af..c15e8b6 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -62,6 +62,9 @@ mac { HEADERS += image/qpixmap_mac_p.h SOURCES += image/qpixmap_mac.cpp } +symbian { + SOURCES += image/qpixmap_s60.cpp +} # Built-in image format support HEADERS += \ diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 75538a8..281d8d4 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -185,6 +185,13 @@ static int depthForFormat(QImage::Format format) return depth; } +/*! \fn QImageData * QImageData::create(const QSize &size, QImage::Format format, int numColors) + + \internal + + Creates a new image data. + Returns 0 if invalid parameters are give or anything else failed. +*/ QImageData * QImageData::create(const QSize &size, QImage::Format format, int numColors) { if (!size.isValid() || numColors < 0 || format == QImage::Format_Invalid) @@ -223,7 +230,7 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu || INT_MAX/sizeof(uchar *) < uint(height)) return 0; - QImageData *d = new QImageData; + QScopedPointer<QImageData> d(new QImageData); d->colortable.resize(numColors); if (depth == 1) { d->colortable[0] = QColor(Qt::black).rgba(); @@ -246,12 +253,11 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu d->data = (uchar *)malloc(d->nbytes); if (!d->data) { - delete d; return 0; } d->ref.ref(); - return d; + return d.take(); } @@ -1621,6 +1627,7 @@ int QImage::numColors() const /*! Returns a pointer to the scanline pointer table. This is the beginning of the data block for the image. + Returns 0 in case of an error. Use the bits() or scanLine() function instead. */ @@ -1636,6 +1643,8 @@ uchar **QImage::jumpTable() if (!d->jumptable) { d->jumptable = (uchar **)malloc(d->height*sizeof(uchar *)); + if (!d->jumptable) + return 0; uchar *data = d->data; int height = d->height; uchar **p = d->jumptable; @@ -1656,6 +1665,8 @@ const uchar * const *QImage::jumpTable() const return 0; if (!d->jumptable) { d->jumptable = (uchar **)malloc(d->height*sizeof(uchar *)); + if (!d->jumptable) + return 0; uchar *data = d->data; int height = d->height; uchar **p = d->jumptable; diff --git a/src/gui/image/qimageiohandler.cpp b/src/gui/image/qimageiohandler.cpp index a47c69e..f432f87 100644 --- a/src/gui/image/qimageiohandler.cpp +++ b/src/gui/image/qimageiohandler.cpp @@ -272,7 +272,6 @@ QImageIOHandler::QImageIOHandler(QImageIOHandlerPrivate &dd) */ QImageIOHandler::~QImageIOHandler() { - delete d_ptr; } /*! diff --git a/src/gui/image/qimageiohandler.h b/src/gui/image/qimageiohandler.h index 3b654f3..34de715 100644 --- a/src/gui/image/qimageiohandler.h +++ b/src/gui/image/qimageiohandler.h @@ -44,6 +44,7 @@ #include <QtCore/qplugin.h> #include <QtCore/qfactoryinterface.h> +#include <QtCore/qscopedpointer.h> QT_BEGIN_HEADER @@ -109,7 +110,7 @@ public: protected: QImageIOHandler(QImageIOHandlerPrivate &dd); - QImageIOHandlerPrivate *d_ptr; + QScopedPointer<QImageIOHandlerPrivate> d_ptr; private: Q_DISABLE_COPY(QImageIOHandler) }; diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp index 23baa96..96f2a14 100644 --- a/src/gui/image/qpicture.cpp +++ b/src/gui/image/qpicture.cpp @@ -132,7 +132,6 @@ QPicture::QPicture(int formatVersion) { Q_D(QPicture); d_ptr->q_ptr = this; - d->paintEngine = 0; if (formatVersion == 0) qWarning("QPicture: invalid format version 0"); @@ -155,7 +154,7 @@ QPicture::QPicture(int formatVersion) */ QPicture::QPicture(const QPicture &pic) - : QPaintDevice(), d_ptr(pic.d_ptr) + : QPaintDevice(), d_ptr(pic.d_ptr.data()) { d_func()->ref.ref(); } @@ -173,10 +172,6 @@ QPicture::QPicture(QPicturePrivate &dptr) */ QPicture::~QPicture() { - if (!d_func()->ref.deref()) { - delete d_func()->paintEngine; - delete d_func(); - } } /*! @@ -1030,9 +1025,7 @@ void QPicture::detach_helper() x->formatMinor = d->formatMinor; x->brect = d->brect; x->override_rect = d->override_rect; - if (!d->ref.deref()) - delete d; - d_ptr = x; + d_ptr.reset(x); } /*! @@ -1041,13 +1034,25 @@ void QPicture::detach_helper() */ QPicture& QPicture::operator=(const QPicture &p) { - qAtomicAssign<QPicturePrivate>(d_ptr, p.d_ptr); + d_ptr.assign(p.d_ptr.data()); return *this; } /*! \internal + Constructs a QPicturePrivate +*/ +QPicturePrivate::QPicturePrivate() + : in_memory_only(false), + q_ptr(0) +{ + ref = 1; +} + +/*! + \internal + Sets formatOk to false and resets the format version numbers to default */ @@ -1135,8 +1140,8 @@ bool QPicturePrivate::checkFormat() QPaintEngine *QPicture::paintEngine() const { if (!d_func()->paintEngine) - const_cast<QPicture*>(this)->d_func()->paintEngine = new QPicturePaintEngine; - return d_func()->paintEngine; + const_cast<QPicture*>(this)->d_func()->paintEngine.reset(new QPicturePaintEngine); + return d_func()->paintEngine.data(); } /***************************************************************************** diff --git a/src/gui/image/qpicture.h b/src/gui/image/qpicture.h index edfac71..d28131f 100644 --- a/src/gui/image/qpicture.h +++ b/src/gui/image/qpicture.h @@ -106,7 +106,7 @@ private: bool exec(QPainter *p, QDataStream &ds, int i); void detach_helper(); - QPicturePrivate *d_ptr; + QScopedSharedPointer<QPicturePrivate> d_ptr; friend class QPicturePaintEngine; friend class Q3Picture; friend class QAlphaPaintEngine; @@ -114,7 +114,7 @@ private: public: typedef QPicturePrivate* DataPtr; - inline DataPtr &data_ptr() { return d_ptr; } + inline DataPtr &data_ptr() { return d_ptr.data_ptr(); } }; Q_DECLARE_SHARED(QPicture) diff --git a/src/gui/image/qpicture_p.h b/src/gui/image/qpicture_p.h index 3e8391f..a9c4dd5 100644 --- a/src/gui/image/qpicture_p.h +++ b/src/gui/image/qpicture_p.h @@ -143,7 +143,7 @@ public: PdcReservedStop = 199 // for Qt }; - inline QPicturePrivate() : in_memory_only(false), q_ptr(0) { ref = 1; } + QPicturePrivate(); QAtomicInt ref; bool checkFormat(); @@ -156,7 +156,7 @@ public: int formatMinor; QRect brect; QRect override_rect; - QPaintEngine *paintEngine; + QScopedPointer<QPaintEngine> paintEngine; bool in_memory_only; QList<QImage> image_list; QList<QPixmap> pixmap_list; diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index f6b5de2..0ab14aa 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -76,6 +76,10 @@ # include <private/qpixmap_x11_p.h> #endif +#if defined(Q_OS_SYMBIAN) +# include <private/qt_s60_p.h> +#endif + #include "qpixmap_raster_p.h" QT_BEGIN_NAMESPACE @@ -1901,7 +1905,10 @@ int QPixmap::defaultDepth() return 32; // XXX #elif defined(Q_WS_MAC) return 32; +#elif defined(Q_OS_SYMBIAN) + return S60->screenDepth; #endif + } typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index a5609e4..afe7b1c 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -51,6 +51,10 @@ QT_BEGIN_HEADER +#if defined(Q_OS_SYMBIAN) +class CFbsBitmap; +#endif + QT_BEGIN_NAMESPACE QT_MODULE(Gui) @@ -59,7 +63,6 @@ class QImageWriter; class QColor; class QVariant; class QX11Info; - class QPixmapData; class Q_GUI_EXPORT QPixmap : public QPaintDevice @@ -152,6 +155,11 @@ public: static QPixmap fromMacCGImageRef(CGImageRef image); #endif +#if defined(Q_OS_SYMBIAN) + CFbsBitmap *toSymbianCFbsBitmap() const; + static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap); +#endif + inline QPixmap copy(int x, int y, int width, int height) const; QPixmap copy(const QRect &rect = QRect()) const; diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp new file mode 100644 index 0000000..132e26e --- /dev/null +++ b/src/gui/image/qpixmap_s60.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <exception> +#include <w32std.h> +#include <fbs.h> + +#include <private/qt_s60_p.h> +#include "qpixmap.h" +#include "qpixmap_raster_p.h" +#include <qwidget.h> + +QT_BEGIN_NAMESPACE + +QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h ) +{ + CWsScreenDevice* screenDevice = S60->screenDevice(); + TSize screenSize = screenDevice->SizeInPixels(); + + TSize srcSize; + // Find out if this is one of our windows. + QSymbianControl *sControl; + sControl = winId->MopGetObject(sControl); + if (sControl && sControl->widget()->windowType() == Qt::Desktop) { + // Grabbing desktop widget + srcSize = screenSize; + } else { + TPoint relativePos = winId->PositionRelativeToScreen(); + x += relativePos.iX; + y += relativePos.iY; + srcSize = winId->Size(); + } + + TRect srcRect(TPoint(x, y), srcSize); + // Clip to the screen + srcRect.Intersection(TRect(screenSize)); + + if (w > 0 && h > 0) { + TRect subRect(TPoint(x, y), TSize(w, h)); + // Clip to the subRect + srcRect.Intersection(subRect); + } + + if (srcRect.IsEmpty()) + return QPixmap(); + + TDisplayMode displayMode = screenDevice->DisplayMode(); + CFbsBitmap* temporary = new (ELeave) CFbsBitmap(); + TInt error = temporary->Create(srcRect.Size(), displayMode); + if (error == KErrNone) + error = screenDevice->CopyScreenToBitmap(temporary, srcRect); + + if (error != KErrNone) { + CBase::Delete(temporary); + return QPixmap(); + } + + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(temporary); + CBase::Delete(temporary); + return pixmap; +} + +/*! +\since 4.6 + +Returns a \c CFbsBitmap that is equivalent to the QPixmap by copying the data. + +It is the caller's responsibility to delete the \c CFbsBitmap after use. + +\warning This function is only available on Symbian OS. + +\sa fromSymbianCFbsBitmap() +*/ + +CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const +{ + if (isNull()) + return 0; + + TDisplayMode mode; + const QImage img = toImage(); + QImage::Format destFormat = img.format(); + switch (img.format()) { + case QImage::Format_Mono: + destFormat = QImage::Format_MonoLSB; + // Fall through intended + case QImage::Format_MonoLSB: + mode = EGray2; + break; + case QImage::Format_Indexed8: + if (img.isGrayscale()) + mode = EGray256; + else + mode = EColor256; + break; + case QImage::Format_RGB32: + mode = EColor16MU; + break; + case QImage::Format_ARGB6666_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_ARGB8555_Premultiplied: + destFormat = QImage::Format_ARGB32_Premultiplied; + // Fall through intended + case QImage::Format_ARGB32_Premultiplied: +#if !defined(__SERIES60_31__) && !defined(__S60_32__) + // ### TODO: Add runtime detection as well? + mode = EColor16MAP; + break; +#endif + destFormat = QImage::Format_ARGB32; + // Fall through intended + case QImage::Format_ARGB32: + mode = EColor16MA; + break; + case QImage::Format_RGB555: + destFormat = QImage::Format_RGB16; + // Fall through intended + case QImage::Format_RGB16: + mode = EColor64K; + break; + case QImage::Format_RGB666: + destFormat = QImage::Format_RGB888; + // Fall through intended + case QImage::Format_RGB888: + mode = EColor16M; + break; + case QImage::Format_RGB444: + mode = EColor4K; + break; + case QImage::Format_Invalid: + return 0; + default: + qWarning("Image format not supported: %d", img.format()); + return 0; + } + + CFbsBitmap* bitmap = new (ELeave) CFbsBitmap(); + TSize size(width(), height()); + if (bitmap->Create(size, mode) != KErrNone) { + CBase::Delete(bitmap); + return 0; + } + + const QImage converted = img.convertToFormat(destFormat); + + bitmap->LockHeap(); + const uchar *sptr = converted.bits(); + uchar *dptr = (uchar*)bitmap->DataAddress(); + Mem::Copy(dptr, sptr, converted.numBytes()); + bitmap->UnlockHeap(); + return bitmap; +} + +/*! +\since 4.6 + +Returns a QPixmap that is equivalent to the \c CFbsBitmap by copying the data. +If the CFbsBitmap is not valid or is compressed in memory, this function will +return a null QPixmap. + +\warning This function is only available on Symbian OS. + +\sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} +*/ + +QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) +{ + int width = bitmap->SizeInPixels().iWidth; + int height = bitmap->SizeInPixels().iHeight; + + if (!bitmap || width <= 0 || height <= 0 || bitmap->IsCompressedInRAM()) + return QPixmap(); + + TDisplayMode displayMode = bitmap->DisplayMode(); + QImage::Format format = qt_TDisplayMode2Format(displayMode); + int bytesPerLine = CFbsBitmap::ScanLineLength(width, displayMode); + bitmap->LockHeap(); + QImage image = QImage((const uchar*)bitmap->DataAddress(), width, height, bytesPerLine, format); + if (displayMode == EGray2) { + image.setNumColors(2); + image.setColor(0, QColor(Qt::color0).rgba()); + image.setColor(1, QColor(Qt::color1).rgba()); + } else if (displayMode == EGray256) { + for (int i=0; i < 256; ++i) + image.setColor(i, qRgb(i, i, i)); + }else if (displayMode == EColor256) { + const TColor256Util *palette = TColor256Util::Default(); + for (int i=0; i < 256; ++i) + image.setColor(i, (QRgb)(palette->Color256(i).Value())); + } + QPixmap pixmap = QPixmap::fromImage(image.copy()); + bitmap->UnlockHeap(); + return pixmap; +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index bdcddfd..59c8ce7 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -87,7 +87,9 @@ QT_BEGIN_NAMESPACE \sa QCache, QPixmap */ -#if defined(Q_WS_QWS) || defined(Q_WS_WINCE) +#if defined(Q_OS_SYMBIAN) +static int cache_limit = 1024; // 1048 KB cache limit for symbian +#elif defined(Q_WS_QWS) || defined(Q_WS_WINCE) static int cache_limit = 2048; // 2048 KB cache limit for embedded #else static int cache_limit = 10240; // 10 MB cache limit for desktop @@ -597,7 +599,12 @@ void QPixmapCache::remove(const Key &key) void QPixmapCache::clear() { - pm_cache()->clear(); + QT_TRY { + pm_cache()->clear(); + } QT_CATCH(const std::bad_alloc &) { + // if we ran out of memory during pm_cache(), it's no leak, + // so just ignore it. + } } QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapdatafactory.cpp b/src/gui/image/qpixmapdatafactory.cpp index bba7378..1254c40 100644 --- a/src/gui/image/qpixmapdatafactory.cpp +++ b/src/gui/image/qpixmapdatafactory.cpp @@ -47,7 +47,7 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#ifdef Q_WS_WIN +#if defined(Q_WS_WIN) || defined(Q_WS_S60) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC @@ -75,7 +75,7 @@ QPixmapData* QSimplePixmapDataFactory::create(QPixmapData::PixelType type) #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) +#elif defined(Q_WS_WIN) || defined(Q_WS_S60) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); diff --git a/src/gui/inputmethod/inputmethod.pri b/src/gui/inputmethod/inputmethod.pri index d321cd4..f688364 100644 --- a/src/gui/inputmethod/inputmethod.pri +++ b/src/gui/inputmethod/inputmethod.pri @@ -23,4 +23,9 @@ mac:!embedded { HEADERS += inputmethod/qmacinputcontext_p.h SOURCES += inputmethod/qmacinputcontext_mac.cpp } +symbian { + HEADERS += inputmethod/qcoefepinputcontext_p.h + SOURCES += inputmethod/qcoefepinputcontext_s60.cpp + LIBS += -lfepbase +} diff --git a/src/gui/inputmethod/qcoefepinputcontext_p.h b/src/gui/inputmethod/qcoefepinputcontext_p.h new file mode 100644 index 0000000..b33489e --- /dev/null +++ b/src/gui/inputmethod/qcoefepinputcontext_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOEFEPINPUTCONTEXT_P_H +#define QCOEFEPINPUTCONTEXT_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_IM + +#include "qinputcontext.h" +#include <qhash.h> +#include <private/qcore_symbian_p.h> +#include <private/qt_s60_p.h> + +#include <fepbase.h> +#include <aknedsts.h> + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QCoeFepInputContext : public QInputContext, + public MCoeFepAwareTextEditor, + public MCoeFepAwareTextEditor_Extension1, + public MObjectProvider +{ + Q_OBJECT + +public: + QCoeFepInputContext(QObject *parent = 0); + ~QCoeFepInputContext(); + + QString identifierName() { return QLatin1String("coefep"); } + QString language(); + + void reset(); + void update(); + + bool filterEvent(const QEvent *event); + void mouseHandler( int x, QMouseEvent *event); + bool isComposing() const { return m_isEditing; } + + void setFocusWidget(QWidget * w); + void widgetDestroyed(QWidget *w); + + TCoeInputCapabilities inputCapabilities(); + +private: + void commitCurrentString(bool triggeredBySymbian); + void updateHints(); + void applyHints(Qt::InputMethodHints hints); + void applyFormat(QList<QInputMethodEvent::Attribute> *attributes); + + // From MCoeFepAwareTextEditor +public: + void StartFepInlineEditL(const TDesC& aInitialInlineText, TInt aPositionOfInsertionPointInInlineText, + TBool aCursorVisibility, const MFormCustomDraw* aCustomDraw, + MFepInlineTextFormatRetriever& aInlineTextFormatRetriever, + MFepPointerEventHandlerDuringInlineEdit& aPointerEventHandlerDuringInlineEdit); + void UpdateFepInlineTextL(const TDesC& aNewInlineText, TInt aPositionOfInsertionPointInInlineText); + void SetInlineEditingCursorVisibilityL(TBool aCursorVisibility); + void CancelFepInlineEdit(); + TInt DocumentLengthForFep() const; + TInt DocumentMaximumLengthForFep() const; + void SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection); + void GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const; + void GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, TInt aLengthToRetrieve) const; + void GetFormatForFep(TCharFormat& aFormat, TInt aDocumentPosition) const; + void GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLine, TInt& aHeight, TInt& aAscent, + TInt aDocumentPosition) const; +private: + void DoCommitFepInlineEditL(); + MCoeFepAwareTextEditor_Extension1* Extension1(TBool& aSetToTrue); + + // From MCoeFepAwareTextEditor_Extension1 +public: + void SetStateTransferingOwnershipL(MCoeFepAwareTextEditor_Extension1::CState* aState, TUid aTypeSafetyUid); + MCoeFepAwareTextEditor_Extension1::CState* State(TUid aTypeSafetyUid); + + // From MObjectProvider +public: + TTypeUid::Ptr MopSupplyObject(TTypeUid id); + +private: + QSymbianControl *m_parent; + CAknEdwinState *m_fepState; + QString m_preeditString; + Qt::InputMethodHints m_lastImHints; + TUint m_textCapabilities; + bool m_isEditing; + bool m_inDestruction; + int m_cursorVisibility; + int m_inlinePosition; + MFepInlineTextFormatRetriever *m_formatRetriever; + MFepPointerEventHandlerDuringInlineEdit *m_pointerHandler; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_IM + +#endif // QCOEFEPINPUTCONTEXT_P_H diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp new file mode 100644 index 0000000..9e70cff --- /dev/null +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -0,0 +1,725 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_IM + +#include "qcoefepinputcontext_p.h" +#include <qapplication.h> +#include <qtextformat.h> + +#include <fepitfr.h> + +#include <limits.h> +// You only find these enumerations on SDK 5 onwards, so we need to provide our own +// to remain compatible with older releases. They won't be called by pre-5.0 SDKs. + +// MAknEdStateObserver::EAknCursorPositionChanged +#define QT_EAknCursorPositionChanged MAknEdStateObserver::EAknEdwinStateEvent(6) +// MAknEdStateObserver::EAknActivatePenInputRequest +#define QT_EAknActivatePenInputRequest MAknEdStateObserver::EAknEdwinStateEvent(7) + +QT_BEGIN_NAMESPACE + +QCoeFepInputContext::QCoeFepInputContext(QObject *parent) + : QInputContext(parent), + m_fepState(new (ELeave) CAknEdwinState), + m_lastImHints(Qt::ImhNone), + m_textCapabilities(TCoeInputCapabilities::EAllText), + m_isEditing(false), + m_inDestruction(false), + m_cursorVisibility(1), + m_inlinePosition(0), + m_formatRetriever(0), + m_pointerHandler(0) +{ + m_fepState->SetObjectProvider(this); + m_fepState->SetFlags(EAknEditorFlagDefault); + m_fepState->SetDefaultInputMode( EAknEditorTextInputMode ); + m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); + m_fepState->SetDefaultCase( EAknEditorLowerCase ); + m_fepState->SetPermittedCases( EAknEditorLowerCase|EAknEditorUpperCase ); + m_fepState->SetSpecialCharacterTableResourceId( 0 ); + m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); +} + +QCoeFepInputContext::~QCoeFepInputContext() +{ + m_inDestruction = true; + + // This is to make sure that the FEP manager "forgets" about us, + // otherwise we may get callbacks even after we're destroyed. + // The call below is essentially equivalent to InputCapabilitiesChanged(), + // but is synchronous, rather than asynchronous. + CCoeEnv::Static()->SyncNotifyFocusObserversOfChangeInFocus(); + + if (m_fepState) + delete m_fepState; +} + +void QCoeFepInputContext::reset() +{ + CCoeEnv::Static()->Fep()->CancelTransaction(); +} + +void QCoeFepInputContext::update() +{ + updateHints(); + + // For pre-5.0 SDKs, we don't do text updates on S60 side. + if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { + return; + } + + // Don't be fooled (as I was) by the name of this enumeration. + // What it really does is tell the virtual keyboard UI that the text has been + // updated and it should be reflected in the internal display of the VK. + m_fepState->ReportAknEdStateEventL(QT_EAknCursorPositionChanged); +} + +void QCoeFepInputContext::setFocusWidget(QWidget *w) +{ + commitCurrentString(false); + + QInputContext::setFocusWidget(w); + + updateHints(); +} + +void QCoeFepInputContext::widgetDestroyed(QWidget *w) +{ + // Make sure that the input capabilities of whatever new widget got focused are queried. + CCoeControl *ctrl = w->effectiveWinId(); + if (ctrl->IsFocused()) { + ctrl->SetFocus(false); + ctrl->SetFocus(true); + } +} + +/*! + Definition of struct for mapping Symbian to ISO locale + ### REMOVE + See below. +*/ +struct symbianToISO { + int symbian_language; + char iso_name[8]; +}; + +/*! + Mapping from Symbian to ISO locale + ### REMOVE + This was taken from the preliminary QLocale port to S60, and should be + removed once that is finished. +*/ +static const symbianToISO symbian_to_iso_list[] = { + { ELangEnglish, "en_GB" }, + { ELangFrench, "fr_FR" }, + { ELangGerman, "de_DE" }, + { ELangSpanish, "es_ES" }, + { ELangItalian, "it_IT" }, + { ELangSwedish, "sv_SE" }, + { ELangDanish, "da_DK" }, + { ELangNorwegian, "no_NO" }, + { ELangFinnish, "fi_FI" }, + { ELangAmerican, "en_US" }, + { ELangPortuguese, "pt_PT" }, + { ELangTurkish, "tr_TR" }, + { ELangIcelandic, "is_IS" }, + { ELangRussian, "ru_RU" }, + { ELangHungarian, "hu_HU" }, + { ELangDutch, "nl_NL" }, + { ELangBelgianFlemish, "nl_BE" }, + { ELangCzech, "cs_CZ" }, + { ELangSlovak, "sk_SK" }, + { ELangPolish, "pl_PL" }, + { ELangSlovenian, "sl_SI" }, + { ELangTaiwanChinese, "zh_TW" }, + { ELangHongKongChinese, "zh_HK" }, + { ELangPrcChinese, "zh_CN" }, + { ELangJapanese, "ja_JP" }, + { ELangThai, "th_TH" }, + { ELangArabic, "ar_AE" }, + { ELangTagalog, "tl_PH" }, + { ELangBulgarian, "bg_BG" }, + { ELangCatalan, "ca_ES" }, + { ELangCroatian, "hr_HR" }, + { ELangEstonian, "et_EE" }, + { ELangFarsi, "fa_IR" }, + { ELangCanadianFrench, "fr_CA" }, + { ELangGreek, "el_GR" }, + { ELangHebrew, "he_IL" }, + { ELangHindi, "hi_IN" }, + { ELangIndonesian, "id_ID" }, + { ELangLatvian, "lv_LV" }, + { ELangLithuanian, "lt_LT" }, + { ELangMalay, "ms_MY" }, + { ELangBrazilianPortuguese, "pt_BR" }, + { ELangRomanian, "ro_RO" }, + { ELangSerbian, "sr_YU" }, + { ELangLatinAmericanSpanish, "es" }, + { ELangUkrainian, "uk_UA" }, + { ELangUrdu, "ur_PK" }, // India/Pakistan + { ELangVietnamese, "vi_VN" }, +#ifdef __E32LANG_H__ +// 5.0 + { ELangBasque, "eu_ES" }, + { ELangGalician, "gl_ES" }, +#endif + //{ ELangEnglish_Apac, "en" }, + //{ ELangEnglish_Taiwan, "en_TW" }, + //{ ELangEnglish_HongKong, "en_HK" }, + //{ ELangEnglish_Prc, "en_CN" }, + //{ ELangEnglish_Japan, "en_JP"}, + //{ ELangEnglish_Thailand, "en_TH" }, + //{ ELangMalay_Apac, "ms" } +}; + +/*! + Number of Symbian to ISO locale mappings + ### Remove. + See comment for array above. +*/ +static const int symbian_to_iso_count + = sizeof(symbian_to_iso_list)/sizeof(symbianToISO); + +QString QCoeFepInputContext::language() +{ + TLanguage lang = m_fepState->LocalLanguage(); + if (lang < symbian_to_iso_count) { + return QLatin1String(symbian_to_iso_list[lang].iso_name); + } else { + return QLatin1String("C"); + } +} + +bool QCoeFepInputContext::filterEvent(const QEvent *event) +{ + // The CloseSoftwareInputPanel event is not handled here, because the VK will automatically + // close when it discovers that the underlying widget does not have input capabilities. + + if (!focusWidget()) + return false; + + if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { + const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event); + Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); + if (keyEvent->key() == Qt::Key_F20 && m_lastImHints & Qt::ImhHiddenText) { + // Special case in Symbian. On editors with secret text, F20 is for some reason + // considered to be a backspace. + QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(), + keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count()); + QApplication::sendEvent(focusWidget(), &modifiedEvent); + return true; + } + } + + // For pre-5.0 SDKs, we don't launch the keyboard. + if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { + return false; + } + + if (event->type() == QEvent::RequestSoftwareInputPanel) { + // Notify S60 that we want the virtual keyboard to show up. + QSymbianControl *sControl; + sControl = focusWidget()->effectiveWinId()->MopGetObject(sControl); + Q_ASSERT(sControl); + + // The FEP UI temporarily steals focus when it shows up the first time, causing + // all sorts of weird effects on the focused widgets. Since it will immediately give + // back focus to us, we temporarily disable focus handling until the job's done. + if (sControl) { + sControl->setIgnoreFocusChanged(true); + } + + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::QT_EAknActivatePenInputRequest); + + if (sControl) { + sControl->setIgnoreFocusChanged(false); + } + return true; + } + + return false; +} + +void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event) +{ + Q_ASSERT(m_isEditing); + Q_ASSERT(focusWidget()); + + if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) { + commitCurrentString(false); + int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); + + QList<QInputMethodEvent::Attribute> attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos + x, 0, QVariant()); + QInputMethodEvent event("", attributes); + sendEvent(event); + } +} + +TCoeInputCapabilities QCoeFepInputContext::inputCapabilities() +{ + if (m_inDestruction) { + return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0); + } + + return TCoeInputCapabilities(m_textCapabilities, this, 0); +} + +static QTextCharFormat qt_TCharFormat2QTextCharFormat(const TCharFormat &cFormat) +{ + QTextCharFormat qFormat; + + QBrush foreground(QColor(cFormat.iFontPresentation.iTextColor.Internal())); + qFormat.setForeground(foreground); + + qFormat.setFontStrikeOut(cFormat.iFontPresentation.iStrikethrough == EStrikethroughOn); + qFormat.setFontUnderline(cFormat.iFontPresentation.iUnderline == EUnderlineOn); + + return qFormat; +} + +void QCoeFepInputContext::updateHints() +{ + QWidget *w = focusWidget(); + if (w) { + Qt::InputMethodHints hints = w->inputMethodHints(); + if (hints != m_lastImHints) { + m_lastImHints = hints; + applyHints(hints); + } + } else { + CCoeEnv::Static()->InputCapabilitiesChanged(); + } +} + +void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints) +{ + using namespace Qt; + + bool numbersOnly = hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly + || hints & ImhDialableCharactersOnly; + bool noOnlys = !(numbersOnly || hints & ImhUppercaseOnly + || hints & ImhLowercaseOnly); + TInt flags; + Qt::InputMethodHints oldHints = hints; + + // Some sanity checking. Make sure that only one preference is set. + InputMethodHints prefs = ImhPreferNumbers | ImhPreferUppercase | ImhPreferLowercase; + prefs &= hints; + if (prefs != ImhPreferNumbers && prefs != ImhPreferUppercase && prefs != ImhPreferLowercase) { + hints &= ~prefs; + } + if (!noOnlys) { + // Make sure that the preference is within the permitted set. + if (hints & ImhPreferNumbers && !(hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly + || hints & ImhDialableCharactersOnly)) { + hints &= ~ImhPreferNumbers; + } else if (hints & ImhPreferUppercase && !(hints & ImhUppercaseOnly)) { + hints &= ~ImhPreferUppercase; + } else if (hints & ImhPreferLowercase && !(hints & ImhLowercaseOnly)) { + hints &= ~ImhPreferLowercase; + } + // If there is no preference, set it to something within the permitted set. + if (!(hints & ImhPreferNumbers || hints & ImhPreferUppercase || hints & ImhPreferLowercase)) { + if (hints & ImhLowercaseOnly) { + hints |= ImhPreferLowercase; + } else if (hints & ImhUppercaseOnly) { + hints |= ImhPreferUppercase; + } else if (hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly + || hints & ImhDialableCharactersOnly) { + hints |= ImhPreferNumbers; + } + } + } + + if (hints & ImhPreferNumbers) { + m_fepState->SetDefaultInputMode(EAknEditorNumericInputMode); + m_fepState->SetCurrentInputMode(EAknEditorNumericInputMode); + } else { + m_fepState->SetDefaultInputMode(EAknEditorTextInputMode); + m_fepState->SetCurrentInputMode(EAknEditorTextInputMode); + } + flags = 0; + if (numbersOnly) { + flags |= EAknEditorNumericInputMode; + } + if (hints & ImhUppercaseOnly || hints & ImhLowercaseOnly) { + flags |= EAknEditorTextInputMode; + } + if (flags == 0) { + flags = EAknEditorAllInputModes; + } + m_fepState->SetPermittedInputModes(flags); + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateInputModeUpdate); + + if (hints & ImhPreferLowercase) { + m_fepState->SetDefaultCase(EAknEditorLowerCase); + m_fepState->SetCurrentCase(EAknEditorLowerCase); + } else if (hints & ImhPreferUppercase) { + m_fepState->SetDefaultCase(EAknEditorUpperCase); + m_fepState->SetCurrentCase(EAknEditorUpperCase); + } else if (hints & ImhNoAutoUppercase) { + m_fepState->SetDefaultCase(EAknEditorLowerCase); + m_fepState->SetCurrentCase(EAknEditorLowerCase); + } else { + m_fepState->SetDefaultCase(EAknEditorTextCase); + m_fepState->SetCurrentCase(EAknEditorTextCase); + } + flags = 0; + if (hints & ImhUppercaseOnly) { + flags |= EAknEditorUpperCase; + } + if (hints & ImhLowercaseOnly) { + flags |= EAknEditorLowerCase; + } + if (flags == 0) { + flags = EAknEditorAllCaseModes; + if (hints & ImhNoAutoUppercase) { + flags &= ~EAknEditorTextCase; + } + } + m_fepState->SetPermittedCases(flags); + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateCaseModeUpdate); + + flags = 0; + if (hints & ImhUppercaseOnly && !(hints & ImhLowercaseOnly) + || hints & ImhLowercaseOnly && !(hints & ImhUppercaseOnly)) { + flags |= EAknEditorFlagFixedCase; + } + // Using T9 and hidden text together may actually crash the FEP, so check for hidden text too. + if (hints & ImhNoPredictiveText || hints & ImhHiddenText) { + flags |= EAknEditorFlagNoT9; + } + m_fepState->SetFlags(flags); + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateFlagsUpdate); + + if (hints & ImhFormattedNumbersOnly) { + flags = EAknEditorCalculatorNumberModeKeymap; + } else if (hints & ImhDigitsOnly) { + flags = EAknEditorPlainNumberModeKeymap; + } else { + // ImhDialableCharactersOnly is the fallback as well, so we don't need to check for + // that flag. + flags = EAknEditorStandardNumberModeKeymap; + } + m_fepState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(flags)); + + if (hints & ImhHiddenText) { + m_textCapabilities = TCoeInputCapabilities::EAllText | TCoeInputCapabilities::ESecretText; + } else { + m_textCapabilities = TCoeInputCapabilities::EAllText; + } + + CCoeEnv::Static()->InputCapabilitiesChanged(); +} + +void QCoeFepInputContext::applyFormat(QList<QInputMethodEvent::Attribute> *attributes) +{ + TCharFormat cFormat; + TInt numChars = 0; + TInt charPos = 0; + int oldSize = attributes->size(); + while (m_formatRetriever) { + m_formatRetriever->GetFormatOfFepInlineText(cFormat, numChars, charPos); + if (numChars <= 0) { + // This shouldn't happen according to S60 docs, but apparently does sometimes. + break; + } + attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + charPos, + numChars, + QVariant(qt_TCharFormat2QTextCharFormat(cFormat)))); + charPos += numChars; + if (charPos >= m_preeditString.size()) { + break; + } + } + + if (attributes->size() == oldSize) { + // S60 didn't provide any format, so let's give our own instead. + attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + 0, + m_preeditString.size(), + standardFormat(PreeditFormat))); + } +} + +void QCoeFepInputContext::StartFepInlineEditL(const TDesC& aInitialInlineText, + TInt aPositionOfInsertionPointInInlineText, TBool aCursorVisibility, const MFormCustomDraw* /*aCustomDraw*/, + MFepInlineTextFormatRetriever& aInlineTextFormatRetriever, + MFepPointerEventHandlerDuringInlineEdit& aPointerEventHandlerDuringInlineEdit) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + m_isEditing = true; + + QList<QInputMethodEvent::Attribute> attributes; + + m_cursorVisibility = aCursorVisibility ? 1 : 0; + m_inlinePosition = aPositionOfInsertionPointInInlineText; + m_preeditString = qt_TDesC2QStringL(aInitialInlineText); + + m_formatRetriever = &aInlineTextFormatRetriever; + m_pointerHandler = &aPointerEventHandlerDuringInlineEdit; + + applyFormat(&attributes); + + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + m_inlinePosition, + m_cursorVisibility, + QVariant())); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::UpdateFepInlineTextL(const TDesC& aNewInlineText, + TInt aPositionOfInsertionPointInInlineText) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + m_inlinePosition = aPositionOfInsertionPointInInlineText; + + QList<QInputMethodEvent::Attribute> attributes; + applyFormat(&attributes); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + m_inlinePosition, + m_cursorVisibility, + QVariant())); + m_preeditString = qt_TDesC2QStringL(aNewInlineText); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::SetInlineEditingCursorVisibilityL(TBool aCursorVisibility) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + m_cursorVisibility = aCursorVisibility ? 1 : 0; + + QList<QInputMethodEvent::Attribute> attributes; + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + m_inlinePosition, + m_cursorVisibility, + QVariant())); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::CancelFepInlineEdit() +{ + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("", 0, 0); + m_preeditString.clear(); + sendEvent(event); + + m_isEditing = false; +} + +TInt QCoeFepInputContext::DocumentLengthForFep() const +{ + QWidget *w = focusWidget(); + if (!w) + return 0; + + QVariant variant = w->inputMethodQuery(Qt::ImSurroundingText); + return variant.value<QString>().size() + m_preeditString.size(); +} + +TInt QCoeFepInputContext::DocumentMaximumLengthForFep() const +{ + QWidget *w = focusWidget(); + if (!w) + return 0; + + QVariant variant = w->inputMethodQuery(Qt::ImMaximumTextLength); + int size; + if (variant.isValid()) { + size = variant.toInt(); + } else { + size = INT_MAX; // Sensible default for S60. + } + return size; +} + +void QCoeFepInputContext::SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + int pos = aCursorSelection.iAnchorPos; + int length = aCursorSelection.iCursorPos - pos; + + QList<QInputMethodEvent::Attribute> attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos, length, QVariant()); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + m_preeditString.size(); + int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt() + m_preeditString.size(); + aCursorSelection.iAnchorPos = anchor; + aCursorSelection.iCursorPos = cursor; +} + +void QCoeFepInputContext::GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, + TInt aLengthToRetrieve) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + QString text = w->inputMethodQuery(Qt::ImSurroundingText).value<QString>(); + // FEP expects the preedit string to be part of the editor content, so let's mix it in. + int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); + text.insert(cursor, m_preeditString); + aEditorContent.Copy(qt_QString2TPtrC(text.mid(aDocumentPosition, aLengthToRetrieve))); +} + +void QCoeFepInputContext::GetFormatForFep(TCharFormat& aFormat, TInt aDocumentPosition) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>(); + QFontMetrics metrics(font); + //QString name = font.rawName(); + QString name = font.defaultFamily(); // TODO! FIXME! Should be the above. + QHBufC hBufC(name); + aFormat = TCharFormat(hBufC->Des(), metrics.height()); + + aDocumentPosition = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); +} + +void QCoeFepInputContext::GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLine, TInt& aHeight, + TInt& aAscent, TInt aDocumentPosition) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + QRect rect = w->inputMethodQuery(Qt::ImMicroFocus).value<QRect>(); + aLeftSideOfBaseLine.iX = rect.left(); + aLeftSideOfBaseLine.iY = rect.bottom(); + + QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>(); + QFontMetrics metrics(font); + aHeight = metrics.height(); + aAscent = metrics.ascent(); + + aDocumentPosition = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); +} + +void QCoeFepInputContext::DoCommitFepInlineEditL() +{ + commitCurrentString(true); +} + +void QCoeFepInputContext::commitCurrentString(bool triggeredBySymbian) +{ + if (m_preeditString.size() == 0) { + return; + } + + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString(m_preeditString, 0, 0);//m_preeditString.size()); + m_preeditString.clear(); + sendEvent(event); + + m_isEditing = false; + + if (!triggeredBySymbian) { + CCoeEnv::Static()->Fep()->CancelTransaction(); + } +} + +MCoeFepAwareTextEditor_Extension1* QCoeFepInputContext::Extension1(TBool& aSetToTrue) +{ + aSetToTrue = ETrue; + return this; +} + +void QCoeFepInputContext::SetStateTransferingOwnershipL(MCoeFepAwareTextEditor_Extension1::CState* aState, + TUid /*aTypeSafetyUid*/) +{ + // Note: The S60 docs are wrong! See the State() function. + if (m_fepState) + delete m_fepState; + m_fepState = static_cast<CAknEdwinState *>(aState); +} + +MCoeFepAwareTextEditor_Extension1::CState* QCoeFepInputContext::State(TUid /*aTypeSafetyUid*/) +{ + // Note: The S60 docs are horribly wrong when describing the + // SetStateTransferingOwnershipL function and this function. They say that the former + // sets a CState object identified by the TUid, and the latter retrieves it. + // In reality, the CState is expected to always be a CAknEdwinState (even if it was not + // previously set), and the TUid is ignored. All in all, there is a single CAknEdwinState + // per QCoeFepInputContext, which should be deleted if the SetStateTransferingOwnershipL + // function is used to set a new one. + return m_fepState; +} + +TTypeUid::Ptr QCoeFepInputContext::MopSupplyObject(TTypeUid /*id*/) +{ + return TTypeUid::Null(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_IM diff --git a/src/gui/inputmethod/qinputcontext.cpp b/src/gui/inputmethod/qinputcontext.cpp index 8db326b..a0b2a54 100644 --- a/src/gui/inputmethod/qinputcontext.cpp +++ b/src/gui/inputmethod/qinputcontext.cpp @@ -209,9 +209,21 @@ void QInputContext::setFocusWidget(QWidget *widget) way. Although the input events have accept() and ignore() methods, leave it untouched. - \a event is currently restricted to QKeyEvent. But some input - method related events such as QWheelEvent or QTabletEvent may be - added in future. + \a event is currently restricted to events of these types: + + \list + \i CloseSoftwareInputPanel + \i KeyPress + \i KeyRelease + \i MouseButtonDblClick + \i MouseButtonPress + \i MouseButtonRelease + \i MouseMove + \i RequestSoftwareInputPanel + \endlist + + But some input method related events such as QWheelEvent or + QTabletEvent may be added in future. The filtering opportunity is always given to the input context as soon as possible. It has to be taken place before any other key @@ -415,13 +427,6 @@ QTextFormat QInputContext::standardFormat(StandardFormat s) const switch (s) { case QInputContext::PreeditFormat: { fmt.setUnderlineStyle(QTextCharFormat::DashUnderline); -#ifndef Q_WS_WIN - int h1, s1, v1, h2, s2, v2; - pal.color(QPalette::Base).getHsv(&h1, &s1, &v1); - pal.color(QPalette::Background).getHsv(&h2, &s2, &v2); - bg.setHsv(h1, s1, (v1 + v2) / 2); - fmt.setBackground(QBrush(bg)); -#endif break; } case QInputContext::SelectionFormat: { @@ -459,6 +464,31 @@ bool QInputContext::x11FilterEvent(QWidget * /*keywidget*/, XEvent * /*event*/) } #endif // Q_WS_X11 +#ifdef Q_WS_S60 +/*! + This function may be overridden only if input method is depending + on Symbian and you need raw TWsEvent. Otherwise, this function must not. + + This function is designed to filter raw key events on S60, but + other input methods may use this to implement some special + features. + + Return true if the \a event has been consumed. Otherwise, the + unfiltered \a event will be translated into QEvent and forwarded + to filterEvent(). Filtering at both s60FilterEvent() and + filterEvent() in single input method is allowed. + + \a keywidget is a client widget into which a text is inputted. \a + event is inputted TWsEvent. + + \sa filterEvent() +*/ +bool QInputContext::s60FilterEvent(QWidget * /*keywidget*/, TWsEvent * /*event*/) +{ + return false; +} +#endif // Q_WS_S60 + QT_END_NAMESPACE #endif //Q_NO_IM diff --git a/src/gui/inputmethod/qinputcontext.h b/src/gui/inputmethod/qinputcontext.h index bcaa7fe..bc4c63c 100644 --- a/src/gui/inputmethod/qinputcontext.h +++ b/src/gui/inputmethod/qinputcontext.h @@ -67,6 +67,10 @@ QT_BEGIN_HEADER +#ifdef Q_WS_S60 +class TWsEvent; +#endif + QT_BEGIN_NAMESPACE QT_MODULE(Gui) @@ -76,7 +80,6 @@ class QFont; class QPopupMenu; class QInputContextPrivate; - class Q_GUI_EXPORT QInputContext : public QObject { Q_OBJECT @@ -105,6 +108,9 @@ public: #if defined(Q_WS_X11) virtual bool x11FilterEvent( QWidget *keywidget, XEvent *event ); #endif // Q_WS_X11 +#if defined(Q_WS_S60) + virtual bool s60FilterEvent( QWidget *keywidget, TWsEvent *event ); +#endif // Q_WS_S60 virtual bool filterEvent( const QEvent *event ); void sendEvent(const QInputMethodEvent &event); diff --git a/src/gui/inputmethod/qinputcontextfactory.cpp b/src/gui/inputmethod/qinputcontextfactory.cpp index 06625f9..188b13a 100644 --- a/src/gui/inputmethod/qinputcontextfactory.cpp +++ b/src/gui/inputmethod/qinputcontextfactory.cpp @@ -71,6 +71,9 @@ #ifdef Q_WS_MAC #include "qmacinputcontext_p.h" #endif +#ifdef Q_WS_S60 +#include "qcoefepinputcontext_p.h" +#endif #include "private/qfactoryloader_p.h" #include "qmutex.h" @@ -145,6 +148,11 @@ QInputContext *QInputContextFactory::create( const QString& key, QObject *parent result = new QMacInputContext; } #endif +#if defined(Q_WS_S60) + if (key == QLatin1String("coefep")) { + result = new QCoeFepInputContext; + } +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else @@ -182,6 +190,9 @@ QStringList QInputContextFactory::keys() #if defined(Q_WS_MAC) result << QLatin1String("mac"); #endif +#if defined(Q_WS_S60) + result << QLatin1String("coefep"); +#endif #if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) result += loader()->keys(); #endif // QT_NO_LIBRARY @@ -217,6 +228,10 @@ QStringList QInputContextFactory::languages( const QString &key ) if (key == QLatin1String("mac")) return QStringList(QString()); #endif +#if defined(Q_WS_S60) + if (key == QLatin1String("coefep")) + return QStringList(QString()); +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else @@ -241,6 +256,10 @@ QString QInputContextFactory::displayName( const QString &key ) if (key == QLatin1String("xim")) return QInputContext::tr( "XIM" ); #endif +#ifdef Q_WS_S60 + if (key == QLatin1String("coefep")) + return QInputContext::tr( "FEP" ); +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else @@ -272,6 +291,10 @@ QString QInputContextFactory::description( const QString &key ) if (key == QLatin1String("mac")) return QInputContext::tr( "Mac OS X input method" ); #endif +#if defined(Q_WS_S60) + if (key == QLatin1String("coefep")) + return QInputContext::tr( "S60 FEP input method" ); +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else diff --git a/src/gui/inputmethod/qwininputcontext_win.cpp b/src/gui/inputmethod/qwininputcontext_win.cpp index b94c604..11ee2f2 100644 --- a/src/gui/inputmethod/qwininputcontext_win.cpp +++ b/src/gui/inputmethod/qwininputcontext_win.cpp @@ -759,7 +759,12 @@ void QWinInputContext::updateImeStatus(QWidget *w, bool hasFocus) { if (!w) return; - bool e = w->testAttribute(Qt::WA_InputMethodEnabled) && w->isEnabled(); + // It's always the proxy that carries the hints. + QWidget *focusProxyWidget = w->focusProxy(); + if (!focusProxyWidget) + focusProxyWidget = w; + bool e = w->testAttribute(Qt::WA_InputMethodEnabled) && w->isEnabled() + && !(focusProxyWidget->inputMethodHints() & Qt::ImhExclusiveInputMask); bool hasIme = e && hasFocus; #ifdef Q_IME_DEBUG qDebug("%s HasFocus = %d hasIme = %d e = %d ", w->className(), hasFocus, hasIme, e); diff --git a/src/gui/inputmethod/qximinputcontext_x11.cpp b/src/gui/inputmethod/qximinputcontext_x11.cpp index b43a134..c1eccd5 100644 --- a/src/gui/inputmethod/qximinputcontext_x11.cpp +++ b/src/gui/inputmethod/qximinputcontext_x11.cpp @@ -611,7 +611,7 @@ void QXIMInputContext::setFocusWidget(QWidget *w) QInputContext::setFocusWidget(w); - if (!w) + if (!w || w->inputMethodHints() & Qt::ImhExclusiveInputMask) return; ICData *data = ximData.value(w->effectiveWinId()); diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 9effc70..3e85b67 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -61,6 +61,7 @@ #ifndef QT_NO_ACCESSIBILITY #include <qaccessible.h> #endif +#include <private/qactiontokeyeventmapper_p.h> QT_BEGIN_NAMESPACE @@ -2003,15 +2004,18 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) if (QApplication::keypadNavigationEnabled()) { if (!hasEditFocus()) { setEditFocus(true); + QActionToKeyEventMapper::addSoftKey(QAction::BackSoftKey, Qt::Key_Back, this); return; } } break; case Qt::Key_Back: - if (QApplication::keypadNavigationEnabled() && hasEditFocus()) + if (QApplication::keypadNavigationEnabled() && hasEditFocus()) { + QActionToKeyEventMapper::removeSoftkey(this); setEditFocus(false); - else + } else { event->ignore(); + } return; default: if (QApplication::keypadNavigationEnabled() && !hasEditFocus()) { diff --git a/src/gui/itemviews/qabstractitemview_p.h b/src/gui/itemviews/qabstractitemview_p.h index 8594ad7..1d2a233 100644 --- a/src/gui/itemviews/qabstractitemview_p.h +++ b/src/gui/itemviews/qabstractitemview_p.h @@ -304,7 +304,7 @@ public: */ inline bool isPersistent(const QModelIndex &index) const { - return static_cast<QAbstractItemModelPrivate *>(model->d_ptr)->persistent.indexes.contains(index); + return static_cast<QAbstractItemModelPrivate *>(model->d_ptr.data())->persistent.indexes.contains(index); } QModelIndexList selectedDraggableIndexes() const; diff --git a/src/gui/itemviews/qcolumnview_p.h b/src/gui/itemviews/qcolumnview_p.h index 8f75bec..432e5e8 100644 --- a/src/gui/itemviews/qcolumnview_p.h +++ b/src/gui/itemviews/qcolumnview_p.h @@ -55,7 +55,7 @@ #include "qcolumnview.h" -#ifndef QT_NO_QCOlUMNVIEW +#ifndef QT_NO_QCOLUMNVIEW #include <private/qabstractitemview_p.h> diff --git a/src/gui/itemviews/qdirmodel.cpp b/src/gui/itemviews/qdirmodel.cpp index 65e3032..2596e8c 100644 --- a/src/gui/itemviews/qdirmodel.cpp +++ b/src/gui/itemviews/qdirmodel.cpp @@ -869,8 +869,10 @@ QModelIndex QDirModel::index(const QString &path, int column) const return QModelIndex(); QString absolutePath = QDir(path).absolutePath(); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) absolutePath = absolutePath.toLower(); +#endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) // On Windows, "filename......." and "filename" are equivalent if (absolutePath.endsWith(QLatin1Char('.'))) { int i; @@ -910,7 +912,10 @@ QModelIndex QDirModel::index(const QString &path, int column) const pathElements.pop_front(); if (childAppended) emit const_cast<QDirModel*>(this)->layoutChanged(); - } else if (pathElements.at(0).endsWith(QLatin1Char(':'))) { + } else +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + if (pathElements.at(0).endsWith(QLatin1Char(':'))) { pathElements[0] += QLatin1Char('/'); } #else @@ -932,11 +937,9 @@ QModelIndex QDirModel::index(const QString &path, int column) const for (int j = parent->children.count() - 1; j >= 0; --j) { const QFileInfo& fi = parent->children.at(j).info; QString childFileName; -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath(); +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) childFileName = childFileName.toLower(); -#else - childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath(); #endif if (childFileName == element) { if (i == pathElements.count() - 1) @@ -953,7 +956,7 @@ QModelIndex QDirModel::index(const QString &path, int column) const if (parent->info.isRoot()) newPath = parent->info.absoluteFilePath() + element; else - newPath= parent->info.absoluteFilePath() + QLatin1Char('/') + element; + newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #else QString newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #endif @@ -1305,6 +1308,8 @@ QString QDirModelPrivate::name(const QModelIndex &index) const #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (name.startsWith(QLatin1Char('/'))) // UNC host return info.fileName(); +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) if (name.endsWith(QLatin1Char('/'))) name.chop(1); #endif diff --git a/src/gui/itemviews/qfileiconprovider.cpp b/src/gui/itemviews/qfileiconprovider.cpp index 434bcde..9a97c2a 100644 --- a/src/gui/itemviews/qfileiconprovider.cpp +++ b/src/gui/itemviews/qfileiconprovider.cpp @@ -180,7 +180,6 @@ QFileIconProvider::QFileIconProvider() QFileIconProvider::~QFileIconProvider() { - delete d_ptr; } /*! diff --git a/src/gui/itemviews/qfileiconprovider.h b/src/gui/itemviews/qfileiconprovider.h index 7928552..a6152ea 100644 --- a/src/gui/itemviews/qfileiconprovider.h +++ b/src/gui/itemviews/qfileiconprovider.h @@ -42,8 +42,9 @@ #ifndef QFILEICONPROVIDER_H #define QFILEICONPROVIDER_H -#include <QtGui/qicon.h> #include <QtCore/qfileinfo.h> +#include <QtCore/qscopedpointer.h> +#include <QtGui/qicon.h> QT_BEGIN_HEADER @@ -67,7 +68,7 @@ public: private: Q_DECLARE_PRIVATE(QFileIconProvider) - QFileIconProviderPrivate *d_ptr; + QScopedPointer<QFileIconProviderPrivate> d_ptr; Q_DISABLE_COPY(QFileIconProvider) }; diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index d0321d8..b437119 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -3563,7 +3563,7 @@ bool QHeaderViewPrivate::read(QDataStream &in) in >> minimumSectionSize; in >> align; - defaultAlignment = (Qt::Alignment)align; + defaultAlignment = Qt::Alignment(align); in >> global; globalResizeMode = (QHeaderView::ResizeMode)global; diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp index a748199..fda6255 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -1321,7 +1321,7 @@ QStyleOptionViewItem QItemDelegate::setOptions(const QModelIndex &index, // set text alignment value = index.data(Qt::TextAlignmentRole); if (value.isValid()) - opt.displayAlignment = (Qt::Alignment)value.toInt(); + opt.displayAlignment = Qt::Alignment(value.toInt()); // set foreground brush value = index.data(Qt::ForegroundRole); diff --git a/src/gui/itemviews/qstandarditemmodel.cpp b/src/gui/itemviews/qstandarditemmodel.cpp index 30daed2..675a5b3 100644 --- a/src/gui/itemviews/qstandarditemmodel.cpp +++ b/src/gui/itemviews/qstandarditemmodel.cpp @@ -778,8 +778,6 @@ QStandardItem &QStandardItem::operator=(const QStandardItem &other) */ QStandardItem::~QStandardItem() { - Q_D(QStandardItem); - delete d; } /*! @@ -899,7 +897,7 @@ Qt::ItemFlags QStandardItem::flags() const if (!v.isValid()) return (Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable |Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled); - return ((Qt::ItemFlags)(v.toInt())); + return Qt::ItemFlags(v.toInt()); } /*! @@ -1896,7 +1894,7 @@ void QStandardItem::read(QDataStream &in) in >> d->values; qint32 flags; in >> flags; - setFlags((Qt::ItemFlags)flags); + setFlags(Qt::ItemFlags(flags)); } /*! diff --git a/src/gui/itemviews/qstandarditemmodel.h b/src/gui/itemviews/qstandarditemmodel.h index f24f0ab..66d7576 100644 --- a/src/gui/itemviews/qstandarditemmodel.h +++ b/src/gui/itemviews/qstandarditemmodel.h @@ -240,7 +240,7 @@ protected: QStandardItem(const QStandardItem &other); QStandardItem(QStandardItemPrivate &dd); QStandardItem &operator=(const QStandardItem &other); - QStandardItemPrivate *d_ptr; + QScopedPointer<QStandardItemPrivate> d_ptr; void emitDataChanged(); diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp index 7f2c8ed..b75f151 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -322,7 +322,7 @@ void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option, value = index.data(Qt::TextAlignmentRole); if (value.isValid() && !value.isNull()) - option->displayAlignment = (Qt::Alignment)value.toInt(); + option->displayAlignment = Qt::Alignment(value.toInt()); value = index.data(Qt::ForegroundRole); if (qVariantCanConvert<QBrush>(value)) diff --git a/src/gui/itemviews/qtreewidget.cpp b/src/gui/itemviews/qtreewidget.cpp index 2a6ac30..709c7b9 100644 --- a/src/gui/itemviews/qtreewidget.cpp +++ b/src/gui/itemviews/qtreewidget.cpp @@ -853,7 +853,7 @@ void QTreeModel::sortItems(QList<QTreeWidgetItem*> *items, int column, Qt::SortO items->replace(r, item); for (int c = 0; c < colCount; ++c) { QModelIndex from = createIndex(oldRow, c, item); - if (static_cast<QAbstractItemModelPrivate *>(d_ptr)->persistent.indexes.contains(from)) { + if (static_cast<QAbstractItemModelPrivate *>(d_ptr.data())->persistent.indexes.contains(from)) { QModelIndex to = createIndex(r, c, item); fromList << from; toList << to; diff --git a/src/gui/itemviews/qtreewidgetitemiterator.cpp b/src/gui/itemviews/qtreewidgetitemiterator.cpp index 3e30e03..7e167b9 100644 --- a/src/gui/itemviews/qtreewidgetitemiterator.cpp +++ b/src/gui/itemviews/qtreewidgetitemiterator.cpp @@ -97,7 +97,7 @@ QTreeWidgetItemIterator::QTreeWidgetItemIterator(QTreeWidget *widget, IteratorFl Q_ASSERT(widget); QTreeModel *model = qobject_cast<QTreeModel*>(widget->model()); Q_ASSERT(model); - d_ptr = new QTreeWidgetItemIteratorPrivate(this, model); + d_ptr.reset(new QTreeWidgetItemIteratorPrivate(this, model)); model->iterators.append(this); if (!model->rootItem->children.isEmpty()) current = model->rootItem->children.first(); if (current && !matchesFlags(current)) @@ -150,7 +150,6 @@ QTreeWidgetItemIterator::QTreeWidgetItemIterator(QTreeWidgetItem *item, Iterator QTreeWidgetItemIterator::~QTreeWidgetItemIterator() { d_func()->m_model->iterators.removeAll(this); - delete d_ptr; } /*! diff --git a/src/gui/itemviews/qtreewidgetitemiterator.h b/src/gui/itemviews/qtreewidgetitemiterator.h index 8a76c69..535339d 100644 --- a/src/gui/itemviews/qtreewidgetitemiterator.h +++ b/src/gui/itemviews/qtreewidgetitemiterator.h @@ -43,6 +43,7 @@ #define QTREEWIDGETITEMITERATOR_H #include <QtCore/qglobal.h> +#include <QtCore/qscopedpointer.h> QT_BEGIN_HEADER @@ -105,7 +106,7 @@ public: private: bool matchesFlags(const QTreeWidgetItem *item) const; - QTreeWidgetItemIteratorPrivate *d_ptr; + QScopedPointer<QTreeWidgetItemIteratorPrivate> d_ptr; QTreeWidgetItem *current; IteratorFlags flags; Q_DECLARE_PRIVATE(QTreeWidgetItemIterator) diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index a1b982a..8e3b6cb 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -90,6 +90,27 @@ win32 { !contains(DEFINES, QT_NO_DIRECTDRAW):LIBS += ddraw.lib } +symbian { + SOURCES += \ + kernel/qapplication_s60.cpp \ + kernel/qeventdispatcher_s60.cpp \ + kernel/qwidget_s60.cpp \ + kernel/qcursor_s60.cpp \ + kernel/qdesktopwidget_s60.cpp \ + kernel/qkeymapper_s60.cpp\ + kernel/qclipboard_s60.cpp\ + kernel/qdnd_s60.cpp \ + kernel/qsound_s60.cpp + + HEADERS += \ + kernel/qt_s60_p.h \ + kernel/qeventdispatcher_s60_p.h + LIBS += -lbafl -lestor + + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE +} + + unix:x11 { INCLUDEPATH += ../3rdparty/xorg HEADERS += \ diff --git a/src/gui/kernel/qaction.cpp b/src/gui/kernel/qaction.cpp index f44d207..9dedc9d 100644 --- a/src/gui/kernel/qaction.cpp +++ b/src/gui/kernel/qaction.cpp @@ -81,7 +81,8 @@ static QString qt_strippedText(QString s) QActionPrivate::QActionPrivate() : group(0), enabled(1), forceDisabled(0), visible(1), forceInvisible(0), checkable(0), checked(0), separator(0), fontSet(false), - menuRole(QAction::TextHeuristicRole), iconVisibleInMenu(-1) + menuRole(QAction::TextHeuristicRole), softKeyRole(QAction::OptionsSoftKey), + iconVisibleInMenu(-1) { #ifdef QT3_SUPPORT static int qt_static_action_id = -1; @@ -1359,6 +1360,32 @@ QAction::MenuRole QAction::menuRole() const } /*! + \property QAction::softKeyRole + \brief the action's softkey role + \since 4.6 + + This indicates what softkey action this action is. Usually used on mobile + platforms to map QActions to hardware keys. + + The softkey role can be changed any time. +*/ +void QAction::setSoftKeyRole(SoftKeyRole softKeyRole) +{ + Q_D(QAction); + if (d->softKeyRole == softKeyRole) + return; + + d->softKeyRole = softKeyRole; + d->sendDataChanged(); +} + +QAction::SoftKeyRole QAction::softKeyRole() const +{ + Q_D(const QAction); + return d->softKeyRole; +} + +/*! \property QAction::iconVisibleInMenu \brief Whether or not an action should show an icon in a menu \since 4.4 diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h index d7bf8c3..3449acf 100644 --- a/src/gui/kernel/qaction.h +++ b/src/gui/kernel/qaction.h @@ -67,6 +67,7 @@ class Q_GUI_EXPORT QAction : public QObject Q_DECLARE_PRIVATE(QAction) Q_ENUMS(MenuRole) + Q_ENUMS(SoftKeyRole) Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable) Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) @@ -84,11 +85,16 @@ class Q_GUI_EXPORT QAction : public QObject #endif Q_PROPERTY(bool visible READ isVisible WRITE setVisible) Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole) + Q_PROPERTY(SoftKeyRole softKeyRole READ softKeyRole WRITE setSoftKeyRole) Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu) public: enum MenuRole { NoRole, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole, AboutRole, PreferencesRole, QuitRole }; + enum SoftKeyRole { OptionsSoftKey, SelectSoftKey, BackSoftKey, NextSoftKey, PreviousSoftKey, + OkSoftKey, CancelSoftKey, EditSoftKey, ViewSoftKey, BackSpaceSoftKey, + EndEditSoftKey, RevertEditSoftKey, DeselectSoftKey, FinishSoftKey, + MenuSoftKey, ContextMenuSoftKey, ExitSoftKey }; explicit QAction(QObject* parent); QAction(const QString &text, QObject* parent); QAction(const QIcon &icon, const QString &text, QObject* parent); @@ -168,6 +174,9 @@ public: void setMenuRole(MenuRole menuRole); MenuRole menuRole() const; + void setSoftKeyRole(SoftKeyRole softKeyRole); + SoftKeyRole softKeyRole() const; + void setIconVisibleInMenu(bool visible); bool isIconVisibleInMenu() const; diff --git a/src/gui/kernel/qaction_p.h b/src/gui/kernel/qaction_p.h index 0617ef5..6051d9a 100644 --- a/src/gui/kernel/qaction_p.h +++ b/src/gui/kernel/qaction_p.h @@ -102,6 +102,7 @@ public: uint separator : 1; uint fontSet : 1; QAction::MenuRole menuRole; + QAction::SoftKeyRole softKeyRole; int iconVisibleInMenu : 3; // Only has values -1, 0, and 1 QList<QWidget *> widgets; #ifndef QT_NO_GRAPHICSVIEW diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index b066f4d..64009d4 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -74,6 +74,9 @@ #ifdef Q_WS_X11 #include <private/qt_x11_p.h> +#endif + +#if defined(Q_WS_X11) || defined(Q_WS_S60) #include "qinputcontextfactory.h" #endif @@ -130,6 +133,8 @@ bool QApplicationPrivate::quitOnLastWindowClosed = true; #ifdef Q_WS_WINCE int QApplicationPrivate::autoMaximizeThreshold = -1; bool QApplicationPrivate::autoSipEnabled = false; +#else +bool QApplicationPrivate::autoSipEnabled = true; #endif QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) @@ -428,7 +433,12 @@ bool Q_GUI_EXPORT qt_tab_all_widgets = true; bool qt_in_tab_key_event = false; int qt_antialiasing_threshold = -1; static int drag_time = 500; +#ifdef Q_WS_S60 +// The screens are a bit too small to for your thumb when using only 4 pixels drag distance. +static int drag_distance = 8; +#else static int drag_distance = 4; +#endif static Qt::LayoutDirection layout_direction = Qt::LeftToRight; QSize QApplicationPrivate::app_strut = QSize(0,0); // no default application strut bool QApplicationPrivate::animate_ui = true; @@ -439,11 +449,17 @@ bool QApplicationPrivate::animate_tooltip = false; bool QApplicationPrivate::fade_tooltip = false; bool QApplicationPrivate::animate_toolbox = false; bool QApplicationPrivate::widgetCount = false; +bool QApplicationPrivate::auto_sip_on_mouse_focus = false; +QString* QApplicationPrivate::styleOverride = 0; #if defined(Q_WS_WIN) && !defined(Q_WS_WINCE) bool QApplicationPrivate::inSizeMove = false; #endif #ifdef QT_KEYPAD_NAVIGATION +# if defined(Q_WS_S60) +bool QApplicationPrivate::keypadNavigation = true; +# else bool QApplicationPrivate::keypadNavigation = false; +# endif QWidget *QApplicationPrivate::oldEditFocus = 0; #endif @@ -982,7 +998,8 @@ QApplication::~QApplication() if (QWidgetPrivate::mapper) { QWidgetMapper * myMapper = QWidgetPrivate::mapper; QWidgetPrivate::mapper = 0; - for (QWidgetMapper::Iterator it = myMapper->begin(); it != myMapper->end(); ++it) { + for (QWidgetMapper::ConstIterator it = myMapper->constBegin(); + it != myMapper->constEnd(); ++it) { register QWidget *w = *it; if (!w->parent()) // window w->destroy(true, true); @@ -994,7 +1011,7 @@ QApplication::~QApplication() if (QWidgetPrivate::uncreatedWidgets) { QWidgetSet *mySet = QWidgetPrivate::uncreatedWidgets; QWidgetPrivate::uncreatedWidgets = 0; - for (QWidgetSet::Iterator it = mySet->begin(); it != mySet->end(); ++it) { + for (QWidgetSet::ConstIterator it = mySet->constBegin(); it != mySet->constEnd(); ++it) { register QWidget *w = *it; if (!w->parent()) // window w->destroy(true, true); @@ -1059,6 +1076,7 @@ QApplication::~QApplication() QApplicationPrivate::animate_tooltip = false; QApplicationPrivate::fade_tooltip = false; QApplicationPrivate::widgetCount = false; + QApplicationPrivate::auto_sip_on_mouse_focus = false; #ifndef QT_NO_STATEMACHINE // trigger unregistering of QStateMachine's GUI types @@ -1216,11 +1234,15 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis \since 4.5 \brief toggles automatic SIP (software input panel) visibility - The auto SIP property is only available as part of Qt for Windows CE. - Set this property to true to automatically display the SIP when entering widgets that accept keyboard input. This property only affects widgets with - the WA_InputMethodEnabled attribute set. + the WA_InputMethodEnabled attribute set, and is typically used to launch + a virtual keyboard on devices which have very few or no keys. + + The property only has an effect on platforms which use software input + panels, such as Windows CE and Symbian. + + The default is platform dependent. */ #ifdef Q_WS_WINCE @@ -1233,6 +1255,7 @@ int QApplication::autoMaximizeThreshold() const { return QApplicationPrivate::autoMaximizeThreshold; } +#endif void QApplication::setAutoSipEnabled(const bool enabled) { @@ -1243,7 +1266,6 @@ bool QApplication::autoSipEnabled() const { return QApplicationPrivate::autoSipEnabled; } -#endif #ifndef QT_NO_STYLE_STYLESHEET @@ -1925,6 +1947,8 @@ QString desktopstyle; desktopstyle = QLatin1String("Windows"); // default styles for Windows #elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) desktopstyle = QLatin1String("CDE"); // default style for X11 on Solaris +#elif defined(Q_WS_S60) + style = QLatin1String("S60"); #elif defined(Q_WS_X11) && defined(Q_OS_IRIX) desktopstyle = QLatin1String("SGI"); // default style for X11 on IRIX #elif defined(Q_WS_QWS) @@ -2079,6 +2103,16 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) prev->setEditFocus(false); } #endif +#ifndef QT_NO_IM + if (focus) { + QInputContext *prevIc; + prevIc = prev->inputContext(); + if (prevIc && prevIc != focus->inputContext()) { + QEvent closeSIPEvent(QEvent::CloseSoftwareInputPanel); + QApplication::sendEvent(prev, &closeSIPEvent); + } + } +#endif QFocusEvent out(QEvent::FocusOut, reason); QPointer<QWidget> that = prev; QApplication::sendEvent(prev, &out); @@ -3431,6 +3465,39 @@ Qt::LayoutDirection QApplication::layoutDirection() return layout_direction; } +/*! + \property autoSipOnMouseFocus + \since 4.6 + \brief toggles SIP (software input panel) launch policy + + This property holds whether widgets should request a software input + panel when it is focused with the mouse. This is typically used to + launch a virtual keyboard on devices which have very few or no keys. + + If the property is set to true, the widget asks for an input panel + on the mouse click which causes the widget to be focused. If the + property is set to false, the user must click a second time before + the widget asks for an input panel. + + \note If the widget is focused by other means than a mouse click, + the next click is will trigger an input panel request, + regardless of the value of this property. + + The default is platform dependent. + + \sa QEvent::RequestSoftwareInputPanel, QInputContext +*/ + +void QApplication::setAutoSipOnMouseFocus(bool enable) +{ + QApplicationPrivate::auto_sip_on_mouse_focus = enable; +} + +bool QApplication::autoSipOnMouseFocus() +{ + return QApplicationPrivate::auto_sip_on_mouse_focus; +} + /*! \obsolete @@ -3709,6 +3776,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPoint relpos = mouse->pos(); if (e->spontaneous()) { +#ifndef QT_NO_IM + QInputContext *ic = w->inputContext(); + if (ic + && w->testAttribute(Qt::WA_InputMethodEnabled) + && ic->filterEvent(mouse)) + return true; +#endif if (e->type() == QEvent::MouseButtonPress) { QWidget *fw = w; @@ -4019,6 +4093,20 @@ bool QApplication::notify(QObject *receiver, QEvent *e) break; #endif + case QEvent::RequestSoftwareInputPanel: + case QEvent::CloseSoftwareInputPanel: +#ifndef QT_NO_IM + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + QInputContext *ic = w->inputContext(); + if (ic && ic->filterEvent(e)) { + break; + } + } +#endif + res = d->notify_helper(receiver, e); + break; + default: res = d->notify_helper(receiver, e); break; @@ -4680,7 +4768,7 @@ void QApplicationPrivate::emitLastWindowClosed() If \a enable is true, Qt::Key_Up and Qt::Key_Down are used to change focus. - This feature is available in Qt for Embedded Linux only. + This feature is available in Qt for Embedded Linux and Symbian only. \sa keypadNavigationEnabled() */ @@ -4691,9 +4779,9 @@ void QApplication::setKeypadNavigationEnabled(bool enable) /*! Returns true if Qt is set to use keypad navigation; otherwise returns - false. The default is false. + false. The default value is true on Symbian, but false on other platforms. - This feature is available in Qt for Embedded Linux only. + This feature is available in Qt for Embedded Linux and Symbian only. \sa setKeypadNavigationEnabled() */ @@ -4750,8 +4838,8 @@ bool QApplication::keypadNavigationEnabled() The default value on X11 is 400 milliseconds. On Windows and Mac OS X, the operating system's value is used. - On Microsoft Windows, calling this function sets the double click interval - for all applications. + On Microsoft Windows and Symbian, calling this function sets the + double click interval for all applications. */ /*! @@ -4909,8 +4997,7 @@ void QApplication::setInputContext(QInputContext *inputContext) qWarning("QApplication::setInputContext: called with 0 input context"); return; } - if (d->inputContext) - delete d->inputContext; + delete d->inputContext; d->inputContext = inputContext; } @@ -4934,6 +5021,11 @@ QInputContext *QApplication::inputContext() const qic = QInputContextFactory::create(QLatin1String("xim"), that); that->d_func()->inputContext = qic; } +#elif defined(Q_WS_S60) + if (!d->inputContext) { + QApplication *that = const_cast<QApplication *>(this); + that->d_func()->inputContext = QInputContextFactory::create(QString::fromLatin1("coefep"), that); + } #endif return d->inputContext; } diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 2baf6dc..32bfcf5 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -61,6 +61,10 @@ QT_BEGIN_HEADER +#if defined(Q_WS_S60) +class TWsEvent; +#endif + QT_BEGIN_NAMESPACE QT_MODULE(Gui) @@ -84,6 +88,7 @@ class QApplicationPrivate; #endif #define qApp (static_cast<QApplication *>(QCoreApplication::instance())) + class Q_GUI_EXPORT QApplication : public QCoreApplication { Q_OBJECT @@ -92,6 +97,8 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication Q_PROPERTY(int cursorFlashTime READ cursorFlashTime WRITE setCursorFlashTime) Q_PROPERTY(int doubleClickInterval READ doubleClickInterval WRITE setDoubleClickInterval) Q_PROPERTY(int keyboardInputInterval READ keyboardInputInterval WRITE setKeyboardInputInterval) + Q_PROPERTY(bool autoSipOnMouseFocus READ autoSipOnMouseFocus + WRITE setAutoSipOnMouseFocus) #ifndef QT_NO_WHEELEVENT Q_PROPERTY(int wheelScrollLines READ wheelScrollLines WRITE setWheelScrollLines) #endif @@ -104,8 +111,8 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication #endif #ifdef Q_WS_WINCE Q_PROPERTY(int autoMaximizeThreshold READ autoMaximizeThreshold WRITE setAutoMaximizeThreshold) - Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled) #endif + Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled) public: enum Type { Tty, GuiClient, GuiServer }; @@ -223,6 +230,12 @@ public: virtual int x11ClientMessage(QWidget*, XEvent*, bool passive_only); int x11ProcessEvent(XEvent*); #endif +#if defined(Q_WS_S60) + int s60ProcessEvent(TWsEvent *event); + virtual bool s60EventFilter(TWsEvent *aEvent); + void symbianHandleCommand(int command); + void symbianResourceChange(int type); +#endif #if defined(Q_WS_QWS) virtual bool qwsEventFilter(QWSEvent *); int qwsProcessEvent(QWSEvent*); @@ -239,7 +252,6 @@ public: void winFocus(QWidget *, bool); static void winMouseButtonUp(); #endif - #ifndef QT_NO_SESSIONMANAGER // session management bool isSessionRestored() const; @@ -284,9 +296,11 @@ public Q_SLOTS: #ifdef Q_WS_WINCE void setAutoMaximizeThreshold(const int threshold); int autoMaximizeThreshold() const; +#endif void setAutoSipEnabled(const bool enabled); bool autoSipEnabled() const; -#endif + void setAutoSipOnMouseFocus(bool); + bool autoSipOnMouseFocus(); static void closeAllWindows(); static void aboutQt(); diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index dd2f479..3377a4d 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -100,6 +100,7 @@ extern QSysInfo::MacVersion qt_macver; #if defined(Q_WS_QWS) class QWSManager; class QDirectPainter; +struct QWSServerCleaner { ~QWSServerCleaner(); }; #endif #ifndef QT_NO_TABLET @@ -222,8 +223,8 @@ public: static void emitLastWindowClosed(); #ifdef Q_WS_WINCE static int autoMaximizeThreshold; - static bool autoSipEnabled; #endif + static bool autoSipEnabled; static QString desktopStyleKey(); static QGraphicsSystem *graphicsSystem() @@ -235,7 +236,6 @@ public: void createEventDispatcher(); QString appName() const; - static void dispatchEnterLeave(QWidget *enter, QWidget *leave); //modality @@ -357,6 +357,7 @@ public: static bool fade_tooltip; static bool animate_toolbox; static bool widgetCount; // Coupled with -widgetcount switch + static bool auto_sip_on_mouse_focus; #ifdef Q_WS_MAC static bool native_modal_dialog_active; #endif @@ -384,6 +385,7 @@ public: #ifdef Q_WS_QWS QPointer<QWSManager> last_manager; + QWSServerCleaner qwsServerCleaner; # ifndef QT_NO_DIRECTPAINTER QMap<WId, QDirectPainter *> *directPainters; # endif @@ -422,6 +424,9 @@ public: QWidget *buttonDown, QWidget *alienWidget); static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver); +#ifdef Q_WS_S60 + static TUint resolveS60ScanCode(TInt scanCode, TUint keysym); +#endif #if defined(Q_WS_WIN) || defined(Q_WS_X11) void sendSyntheticEnterLeave(QWidget *widget); #endif @@ -431,6 +436,10 @@ private: QMap<const QScreen*, QRect> maxWindowRects; #endif +#ifdef Q_WS_S60 + static QHash<TInt, TUint> scanCodeCache; +#endif + static QApplicationPrivate *self; static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); }; diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index edae670..936768d 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -159,6 +159,8 @@ bool qws_overrideCursor = false; #ifndef QT_NO_QWS_MANAGER #include "qdecorationfactory_qws.h" +extern Q_GUI_EXPORT QWSServer *qwsServer; + QT_BEGIN_NAMESPACE QT_USE_NAMESPACE @@ -485,8 +487,13 @@ QList<QWSCommand*> *qt_get_server_queue() void qt_server_enqueue(const QWSCommand *command) { QWSCommand *copy = QWSCommand::factory(command->type); - copy->copyFrom(command); - outgoing.append(copy); + QT_TRY { + copy->copyFrom(command); + outgoing.append(copy); + } QT_CATCH(...) { + delete copy; + QT_RETHROW; + } } QWSDisplay::Data::Data(QObject* parent, bool singleProcess) @@ -2296,7 +2303,7 @@ void qt_init(QApplicationPrivate *priv, int type) qws_decoration = QApplication::qwsSetDecoration(decoration); #endif // QT_NO_QWS_MANAGER #ifndef QT_NO_QWS_INPUTMETHODS - qApp->setInputContext(new QWSInputContext); + qApp->setInputContext(new QWSInputContext(qApp)); #endif } @@ -3543,10 +3550,10 @@ bool QETWidget::translateKeyEvent(const QWSKeyEvent *event, bool grab) /* grab i #if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT) if (type == QEvent::KeyPress && !grab - && static_cast<QApplicationPrivate*>(qApp->d_ptr)->use_compat()) { + && static_cast<QApplicationPrivate*>(qApp->d_ptr.data())->use_compat()) { // send accel events if the keyboard is not grabbed QKeyEvent a(type, code, state, text, autor, int(text.length())); - if (static_cast<QApplicationPrivate*>(qApp->d_ptr)->qt_tryAccelEvent(this, &a)) + if (static_cast<QApplicationPrivate*>(qApp->d_ptr.data())->qt_tryAccelEvent(this, &a)) return true; } #else @@ -3746,4 +3753,14 @@ void QApplication::setArgs(int c, char **v) d->argv = v; } +/* \internal + This is used to clean up the qws server + in case the QApplication constructor threw an exception + */ +QWSServerCleaner::~QWSServerCleaner() +{ + if (qwsServer && qws_single_process) + QWSServer::closedown(); +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp new file mode 100644 index 0000000..b7561e4 --- /dev/null +++ b/src/gui/kernel/qapplication_s60.cpp @@ -0,0 +1,1184 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication_p.h" +#include "qsessionmanager.h" +#include "qevent.h" +#include "qeventdispatcher_s60_p.h" +#include "qwidget.h" +#include "qdesktopwidget.h" +#include "private/qbackingstore_p.h" +#include "qt_s60_p.h" +#include "private/qevent_p.h" +#include "qstring.h" +#include "qdebug.h" +#include "qimage.h" +#include "private/qkeymapper_p.h" +#include "private/qfont_p.h" +#ifndef QT_NO_STYLE_S60 +#include "private/qs60style_p.h" +#endif +#include "private/qwindowsurface_s60_p.h" +#include "qpaintengine.h" +#include "private/qmenubar_p.h" + +#include "apgwgnam.h" // For CApaWindowGroupName +#include <MdaAudioTonePlayer.h> // For CMdaAudioToneUtility + +#ifndef QT_NO_IM +#include "qinputcontext.h" +#include <private/qcoefepinputcontext_p.h> +#endif // QT_NO_IM + +#include "private/qstylesheetstyle_p.h" + +QT_BEGIN_NAMESPACE + +static WId autoGrabWindow = 0; // Not the same as QWidget::grab*() +#if defined(QT_DEBUG) +static bool appNoGrab = false; // Grabbing enabled +#endif + +Q_GUI_EXPORT QS60Data *qt_s60Data = 0; +extern bool qt_sendSpontaneousEvent(QObject*,QEvent*); + +extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp + +QWidget *qt_button_down = 0; // widget got last button-down + +bool qt_nograb() // application no-grab option +{ +#if defined(QT_DEBUG) + return appNoGrab; +#else + return false; +#endif +} + +// Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument +class QS60Beep : public CBase, public MMdaAudioToneObserver +{ +public: + static QS60Beep* NewL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); + void Play(); + ~QS60Beep(); +private: + void ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); + void MatoPrepareComplete(TInt aError); + void MatoPlayComplete(TInt aError); +private: + typedef enum TBeepState + { + EBeepNotPrepared, + EBeepPrepared, + EBeepPlaying + }; +private: + CMdaAudioToneUtility* iToneUtil; + TBeepState iState; + TInt iFrequency; + TTimeIntervalMicroSeconds iDuration; +}; + +QS60Beep::~QS60Beep() +{ + delete iToneUtil; +} + +QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) +{ + QS60Beep* self=new (ELeave) QS60Beep(); + CleanupStack::PushL(self); + self->ConstructL(aFrequency, aDuration); + CleanupStack::Pop(); + return self; +}; + +void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) +{ + iToneUtil=CMdaAudioToneUtility::NewL(*this); + iState=EBeepNotPrepared; + iFrequency=aFrequency; + iDuration=aDuration; + iToneUtil->PrepareToPlayTone(iFrequency,iDuration); +} + +void QS60Beep::Play() +{ + if(iState!=EBeepNotPrepared){ + if(iState==EBeepPlaying) { + iToneUtil->CancelPlay(); + iState=EBeepPrepared; + } + } + + iToneUtil->Play(); + iState=EBeepPlaying; +} + +void QS60Beep::MatoPrepareComplete(TInt aError) +{ + if(aError==KErrNone) { + iState=EBeepPrepared; + } +} + +void QS60Beep::MatoPlayComplete(TInt aError) +{ + Q_UNUSED(aError); + iState=EBeepPrepared; +} + + +QHash<TInt, TUint> QApplicationPrivate::scanCodeCache; + +static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers) +{ + Qt::KeyboardModifiers result = Qt::NoModifier; + + if (s60Modifiers & EModifierKeypad) + result |= Qt::KeypadModifier; + if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift + || s60Modifiers & EModifierRightShift) + result |= Qt::ShiftModifier; + if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl + || s60Modifiers & EModifierRightCtrl) + result |= Qt::ControlModifier; + if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt + || s60Modifiers & EModifierRightAlt) + result |= Qt::AltModifier; + + return result; +} + +static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent) +{ + switch (pEvent->iType) { + case TPointerEvent::EButton1Down: + *type = QEvent::MouseButtonPress; + *button = Qt::LeftButton; + break; + case TPointerEvent::EButton1Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::LeftButton; + break; + case TPointerEvent::EButton2Down: + *type = QEvent::MouseButtonPress; + *button = Qt::MidButton; + break; + case TPointerEvent::EButton2Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::MidButton; + break; + case TPointerEvent::EButton3Down: + *type = QEvent::MouseButtonPress; + *button = Qt::RightButton; + break; + case TPointerEvent::EButton3Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::RightButton; + break; + case TPointerEvent::EDrag: + *type = QEvent::MouseMove; + *button = Qt::NoButton; + break; + case TPointerEvent::EMove: + // Qt makes no distinction between move and drag + *type = QEvent::MouseMove; + *button = Qt::NoButton; + break; + default: + *type = QEvent::None; + *button = Qt::NoButton; + break; + } + if (pEvent->iModifiers & EModifierDoubleClick){ + *type = QEvent::MouseButtonDblClick; + } + + if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick) + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button); + else if (*type == QEvent::MouseButtonRelease) + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button)); + + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask; +} + +//### Can be replaced with CAknLongTapDetector if animation is required. +//NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,. +//also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used. +class QLongTapTimer : public CTimer +{ +public: + static QLongTapTimer* NewL(QAbstractLongTapObserver *observer); + QLongTapTimer(QAbstractLongTapObserver *observer); + void ConstructL(); +public: + void PointerEventL(const TPointerEvent &event); + void RunL(); +protected: +private: + QAbstractLongTapObserver *m_observer; + TPointerEvent m_event; + QPoint m_pressedCoordinates; + int m_dragDistance; +}; + +QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer) +{ + QLongTapTimer* self = new QLongTapTimer(observer); + self->ConstructL(); + return self; +} +void QLongTapTimer::ConstructL() +{ + CTimer::ConstructL(); +} + +QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh) +{ + m_observer = observer; + m_dragDistance = qApp->startDragDistance(); + CActiveScheduler::Add(this); +} + +void QLongTapTimer::PointerEventL(const TPointerEvent& event) +{ + if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat) + { + QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates); + if (diff.manhattanLength() < m_dragDistance) + return; + } + Cancel(); + m_event = event; + if (event.iType == TPointerEvent::EButton1Down) + { + m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY); + // must be same as KLongTapDelay in aknlongtapdetector.h + After(800000); + } +} +void QLongTapTimer::RunL() +{ + if (m_observer) + m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition); +} + +QSymbianControl::QSymbianControl(QWidget *w) + : CCoeControl(), qwidget(w), m_ignoreFocusChanged(false) +{ +} + +void QSymbianControl::ConstructL(bool topLevel, bool desktop) +{ + if (!desktop) + { + if (topLevel) + CreateWindowL(S60->windowGroup()); + + SetFocusing(true); + m_longTapDetector = QLongTapTimer::NewL(this); + } +} + +QSymbianControl::~QSymbianControl() +{ + S60->appUi()->RemoveFromStack(this); + delete m_longTapDetector; +} + +void QSymbianControl::setWidget(QWidget *w) +{ + qwidget = w; +} +void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ) +{ + QWidget *alienWidget; + QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY); + QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY); + alienWidget = qwidget->childAt(widgetPos); + if (!alienWidget) + alienWidget = qwidget; + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~Qt::LeftButton); + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | Qt::RightButton; + QMouseEvent mEvent(QEvent::MouseButtonPress, alienWidget->mapFrom(qwidget, widgetPos), globalPos, + Qt::RightButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); + sendMouseEvent(alienWidget, &mEvent); + m_previousEventLongTap = true; +} + +void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) +{ + //### refactor me, getting too complex + m_longTapDetector->PointerEventL(pEvent); + QMouseEvent::Type type; + Qt::MouseButton button; + mapS60MouseEventTypeToQt(&type, &button, &pEvent); + + if (m_previousEventLongTap) + if (type == QEvent::MouseButtonRelease){ + button = Qt::RightButton; + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & ~Qt::RightButton; + m_previousEventLongTap = false; + } + if (type == QMouseEvent::None) + return; + + // store events for later sending/saving + QWidget *alienWidget; + typedef QPair<QWidget*,QMouseEvent> Event; + QList<Event > events; + + QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); + TPoint controlScreenPos = PositionRelativeToScreen(); + QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; + + if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick) + { + // get the button press target + alienWidget = qwidget->childAt(widgetPos); + if (!alienWidget) + alienWidget = qwidget; + S60->mousePressTarget = alienWidget; + //pointer grab + SetGloballyCapturing(ETrue); + SetPointerCapture(ETrue); + } + else if (type == QEvent::MouseButtonRelease) + { + //release pointer grab + SetGloballyCapturing(EFalse); + SetPointerCapture(EFalse); + } + alienWidget = S60->mousePressTarget; + + if (alienWidget != S60->lastPointerEventTarget) + if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove) + { + //moved to another widget, create enter and leave events + if (S60->lastPointerEventTarget) + { + QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal(S60->lastCursorPos), S60->lastCursorPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + events.append(Event(S60->lastPointerEventTarget,mEventLeave)); + } + QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + + events.append(Event(alienWidget,mEventEnter)); + } + S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; + S60->lastPointerEventTarget = alienWidget; + if (alienWidget) + { + QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + events.append(Event(alienWidget,mEvent)); + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if (dispatcher = qobject_cast<QEventDispatcherS60 *>(alienWidget->d_func()->threadData->eventDispatcher)) { + if (dispatcher->excludeUserInputEvents()) { + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); + } + return; + } + } + } + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + sendMouseEvent(next.first, &(next.second)); + } +} + +void QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent) +{ + qt_sendSpontaneousEvent(widget, mEvent); +} + +TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type) +{ + TKeyResponse r = EKeyWasNotConsumed; + QT_TRANSLATE_EXCEPTION_TO_SYMBIAN_LEAVE(r = OfferKeyEvent(keyEvent, type)); + return r; +} + +TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCode type) +{ + switch (type) { + //case EEventKeyDown: // <-- Intentionally left out. See below. + case EEventKeyUp: + case EEventKey: + { + // S60 has a confusing way of delivering key events. There are three types of + // events: EKeyEvent, EKeyEventDown and EKeyEventUp. When a key is pressed, the + // two first events are generated. When releasing the key, the last one is + // generated. + // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp events, + // we need to do some special tricks to map it to the Qt way. First, we completely + // discard EKeyEventDown events, since they are redundant. Second, since + // EKeyEventUp does not give us a keysym, we need to cache the keysyms from + // the EKeyEvent events. This is what resolveS60ScanCode does. + + + // ### hackish way to send Qt application to background when pressing right softkey + /* + if( keyEvent.iScanCode == EStdKeyDevice1 ) { + S60->window_group->SetOrdinalPosition(-1); + qApp->setActiveWindow(0); + return EKeyWasNotConsumed; + } + */ + + TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode, + keyEvent.iCode); + int keyCode; + if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) { + // Normal characters keys. + keyCode = s60Keysym; + } else { + // Special S60 keys. + keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym); + } + Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); + QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, + mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), + false, 1, keyEvent.iScanCode, s60Keysym, mods); +// WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child(); +// if (!wid) +// Could happen if window isn't shown yet. +// return EKeyWasNotConsumed; + QWidget *widget; + widget = QWidget::keyboardGrabber(); + if (!widget) { + if (QApplicationPrivate::popupWidgets != 0) { + widget = QApplication::activePopupWidget()->focusWidget(); + if (!widget) { + widget = QApplication::activePopupWidget(); + } + } else { + widget = QApplicationPrivate::focus_widget; + if (!widget) { + widget = qwidget; + } + } + } + + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if (dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) { + if (dispatcher->excludeUserInputEvents()) { + dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent)); + return EKeyWasConsumed; + } + } + return sendKeyEvent(widget, &qKeyEvent); + } + } + return EKeyWasNotConsumed; +} + +void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent) +{ + switch (inputEvent->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent)); + break; + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent)); + break; + default: + // Shouldn't get here. + Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown"); + break; + } +} + +TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent) +{ +#ifndef QT_NO_IM + if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) { + QInputContext *qic = widget->inputContext(); + if(qic && qic->filterEvent(keyEvent)) + return EKeyWasConsumed; + } +#endif // QT_NO_IM + + if (widget && qt_sendSpontaneousEvent(widget, keyEvent)) + if (keyEvent->isAccepted()) + return EKeyWasConsumed; + + return EKeyWasNotConsumed; +} + +#ifndef QT_NO_IM +TCoeInputCapabilities QSymbianControl::InputCapabilities() const +{ + QWidget *w = 0; + + if(qwidget->hasFocus()) { + w = qwidget; + } else { + w = qwidget->focusWidget(); + } + + QCoeFepInputContext *ic; + if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled) + && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) { + return ic->inputCapabilities(); + } else { + return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0); + } +} +#endif + +void QSymbianControl::Draw(const TRect& r) const +{ + QWindowSurface *surface = qwidget->windowSurface(); + if (!surface) + return; + + QPaintEngine *engine = surface->paintDevice()->paintEngine(); + if (!engine) + return; + if (engine->type() == QPaintEngine::Raster) { + QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface()); + CFbsBitmap *bitmap = s60Surface->symbianBitmap(); + CWindowGc &gc = SystemGc(); + if (qwidget->d_func()->isOpaque) + gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); + gc.BitBlt(r.iTl, bitmap, r); + } else { + surface->flush(qwidget, QRegion(qt_TRect2QRect(r)), QPoint()); + } +} + +void QSymbianControl::SizeChanged() +{ + CCoeControl::SizeChanged(); + + QSize oldSize = qwidget->size(); + QSize newSize(Size().iWidth, Size().iHeight); + + if (oldSize != newSize) { + QRect cr = qwidget->geometry(); + cr.setSize(newSize); + qwidget->data->crect = cr; + if (qwidget->isVisible()) { + QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = true; + QResizeEvent e(newSize, oldSize); + qt_sendSpontaneousEvent(qwidget, &e); + if (!qwidget->testAttribute(Qt::WA_StaticContents)) + qwidget->d_func()->syncBackingStore(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = false; + } + } +} + +void QSymbianControl::PositionChanged() +{ + CCoeControl::PositionChanged(); + + QPoint oldPos = qwidget->geometry().topLeft(); + QPoint newPos(Position().iX, Position().iY); + + if (oldPos != newPos) { + QRect cr = qwidget->geometry(); + cr.moveTopLeft(newPos); + qwidget->data->crect = cr; + QTLWExtra *top = qwidget->d_func()->maybeTopData(); + if (top) + top->normalGeometry = cr; + if (qwidget->isVisible()) { + QMoveEvent e(newPos, oldPos); + qt_sendSpontaneousEvent(qwidget, &e); + } else { + QMoveEvent * e = new QMoveEvent(newPos, oldPos); + QApplication::postEvent(qwidget, e); + } + } +} + +void QSymbianControl::FocusChanged(TDrawNow aDrawNow) +{ + if (m_ignoreFocusChanged) + return; + + // Popups never get focused, but still receive the FocusChanged when they are hidden. + if (QApplicationPrivate::popupWidgets != 0 + || (qwidget->windowType() & Qt::Popup) == Qt::Popup) + return; + + if (IsFocused()) { + QApplication::setActiveWindow(qwidget); + // If widget is fullscreen, hide status pane and button container + // otherwise show them. + CEikStatusPane* statusPane = S60->statusPane(); + CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer(); + bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen; + if (statusPane && (statusPane->IsVisible() == isFullscreen)) + statusPane->MakeVisible(!isFullscreen); + if (buttonGroup && (buttonGroup->IsVisible() == isFullscreen)) + buttonGroup->MakeVisible(!isFullscreen); + } else { + QApplication::setActiveWindow(0); + } +} + +void QSymbianControl::HandleResourceChange(int resourceType) +{ + switch (resourceType) { + case KInternalStatusPaneChange: + qwidget->d_func()->setWindowIcon_sys(true); + break; + case KUidValueCoeFontChangeEvent: + // font change event + break; + case KEikDynamicLayoutVariantSwitch: + { + if (qwidget->isFullScreen()) { + SetExtentToWholeScreen(); + } else if (qwidget->isMaximized()) { + TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + SetExtent(r.iTl, r.Size()); + } + break; + } + default: + break; + } + + CCoeControl::HandleResourceChange(resourceType); + +} +void QSymbianControl::CancelLongTapTimer() +{ + m_longTapDetector->Cancel(); +} + +TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id) +{ + if (id.iUid == ETypeId) + return id.MakePtr(this); + + return CCoeControl::MopSupplyObject(id); +} + +void qt_init(QApplicationPrivate *priv, int) +{ + S60 = new QS60Data; + +#ifdef QT_NO_DEBUG + if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty()) +#endif + S60->wsSession().SetAutoFlush(ETrue); + + S60->updateScreenSize(); + + + TDisplayMode mode = S60->screenDevice()->DisplayMode(); + S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode); + + RProcess me; + TSecureId securId = me.SecureId(); + S60->uid = securId.operator TUid(); + + // New code to configure the window group name such that window server knows the associated application's UID + CApaWindowGroupName *wgn = CApaWindowGroupName::NewL(S60->wsSession()); + wgn->SetAppUid(S60->uid); + User::LeaveIfError(wgn->SetWindowGroupName((S60->windowGroup()))); + delete wgn; + +/* + ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag + int argc = priv->argc; + char **argv = priv->argv; + + // Get command line params + int j = argc ? 1 : 0; + for (int i=1; i<argc; i++) { + if (argv[i] && *argv[i] != '-') { + argv[j++] = argv[i]; + continue; + } + +#if defined(QT_DEBUG) + if (qstrcmp(argv[i], "-nograb") == 0) + appNoGrab = !appNoGrab; + else +#endif // QT_DEBUG + ; + } +*/ +} + +/***************************************************************************** + qt_cleanup() - cleans up when the application is finished + *****************************************************************************/ +void qt_cleanup() +{ + QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles +// S60 structure and window server session are freed in eventdispatcher destructor as they are needed there + + // It's important that this happens here, before the event dispatcher gets + // deleted, because the input context needs the event loop one last time before + // it dies. + delete QApplicationPrivate::inputContext; + QApplicationPrivate::inputContext = 0; +} + +void QApplicationPrivate::initializeWidgetPaletteHash() +{ + // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash() + // Possibly a task fot the S60Style guys +} + +void QApplicationPrivate::createEventDispatcher() +{ + Q_Q(QApplication); + eventDispatcher = new QEventDispatcherS60(q); +} + +QString QApplicationPrivate::appName() const +{ + return QCoreApplicationPrivate::appName(); +} + +bool QApplicationPrivate::modalState() +{ + return false; +} + +void QApplicationPrivate::enterModal_sys(QWidget *widget) +{ + // TODO: Implement QApplicationPrivate::enterModal_sys(QWidget *widget) +} + +void QApplicationPrivate::leaveModal_sys(QWidget *widget) +{ + // TODO: Implement QApplicationPrivate::leaveModal_sys(QWidget *widget) +} + +void QApplicationPrivate::openPopup(QWidget *popup) +{ + if (!QApplicationPrivate::popupWidgets) + QApplicationPrivate::popupWidgets = new QWidgetList; + QApplicationPrivate::popupWidgets->append(popup); + + if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()) { + Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); + WId id = popup->effectiveWinId(); + id->SetPointerCapture(true); + id->SetGloballyCapturing(true); + autoGrabWindow = id; + } + + // popups are not focus-handled by the window system (the first + // popup grabbed the keyboard), so we have to do that manually: A + // new popup gets the focus + if (QApplication::focusWidget()) + static_cast<QSymbianControl*>(QApplication::focusWidget()->effectiveWinId())->CancelLongTapTimer(); + QWidget *fw = popup->focusWidget(); + if (fw) { + fw->setFocus(Qt::PopupFocusReason); + } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup + fw = QApplication::focusWidget(); + if (fw) { + QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } +} + +void QApplicationPrivate::closePopup(QWidget *popup) +{ + if (!QApplicationPrivate::popupWidgets) + return; + QApplicationPrivate::popupWidgets->removeAll(popup); + + if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup + delete QApplicationPrivate::popupWidgets; + QApplicationPrivate::popupWidgets = 0; + if (!qt_nograb()) { // grabbing not disabled + Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); + WId id = popup->effectiveWinId(); + id->SetPointerCapture(false); + id->SetGloballyCapturing(false); + if (QWidgetPrivate::mouseGrabber != 0) + QWidgetPrivate::mouseGrabber->grabMouse(); + + autoGrabWindow = 0; + if (QWidgetPrivate::keyboardGrabber != 0) + QWidgetPrivate::keyboardGrabber->grabKeyboard(); + + QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget() + : q_func()->focusWidget(); + if (fw) { + if (fw != q_func()->focusWidget()) { + fw->setFocus(Qt::PopupFocusReason); + } else { + QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } + } + } else { + // popups are not focus-handled by the window system (the + // first popup grabbed the keyboard), so we have to do that + // manually: A popup was closed, so the previous popup gets + // the focus. + QWidget* aw = QApplicationPrivate::popupWidgets->last(); + if (QWidget *fw = QApplication::focusWidget()) { + QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } +} + +QWidget * QApplication::topLevelAt(QPoint const& point) +{ + QWidget *found = 0; + int lowestZ = INT_MAX; + QWidgetList list = QApplication::topLevelWidgets(); + for (int i = 0; i < list.count(); ++i) { + QWidget *widget = list.at(i); + if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) { + Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created)); + if (widget->geometry().adjusted(0,0,1,1).contains(point)) { + // At this point we know there is a Qt widget under the point. + // Now we need to make sure it is the top most in the z-order. + RDrawableWindow* rw = widget->d_func()->topData()->rwindow; + int z = rw->OrdinalPosition(); + if (z < lowestZ) { + lowestZ = z; + found = widget; + } + } + } + } + return found; +} + +void QApplication::alert(QWidget *widget, int duration) +{ + // TODO: Implement QApplication::alert(QWidget *widget, int duration) +} + +int QApplication::doubleClickInterval() +{ + TTimeIntervalMicroSeconds32 us; + TInt distance; + S60->wsSession().GetDoubleClickSettings(us, distance); + return (us.Int() / 1000); +} + +void QApplication::setDoubleClickInterval(int ms) +{ + TTimeIntervalMicroSeconds32 newUs( ms * 1000); + TTimeIntervalMicroSeconds32 us; + TInt distance; + S60->wsSession().GetDoubleClickSettings(us, distance); + if (us != newUs) + S60->wsSession().SetDoubleClick(newUs, distance); +} + +int QApplication::keyboardInputInterval() +{ + return QApplicationPrivate::keyboard_input_time; +} + +void QApplication::setKeyboardInputInterval(int ms) +{ + QApplicationPrivate::keyboard_input_time = ms; +} + +int QApplication::cursorFlashTime() +{ + return QApplicationPrivate::cursor_flash_time; +} + +void QApplication::setCursorFlashTime(int msecs) +{ + QApplicationPrivate::cursor_flash_time = msecs; +} + +void QApplication::beep() +{ + TInt frequency=440; + TTimeIntervalMicroSeconds duration(500000); + QS60Beep* beep=NULL; + TRAPD(err, beep=QS60Beep::NewL(frequency, duration)); + if(!err) { + beep->Play(); + } + delete beep; + beep=NULL; +} + +int QApplication::s60ProcessEvent(TWsEvent *event) +{ + bool handled = s60EventFilter(event); + if (handled) + return 1; + + // Qt event handling. Handle some events regardless of if the handle is in our + // widget map or not. + CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle()); + const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control); + switch (event->Type()) { +#ifndef QT_NO_IM + case EEventKey: + case EEventKeyUp: + case EEventKeyDown: + { + // The control doesn't seem to be any of our widgets, so rely on the focused + // widget instead. If the user needs the control, it can be found inside the + // event structure. + QWidget *w = qApp ? qApp->focusWidget() : 0; + if (w) { + QInputContext *ic = w->inputContext(); + if (ic && ic->s60FilterEvent(w, event)) { + return 1; + } else { + return 0; + } + } + break; + } +#endif + case EEventPointerEnter: + if (controlInMap) + return 1; // Qt::Enter will be generated in HandlePointerL + break; + case EEventPointerExit: + if (controlInMap) { + if (S60) { + // mouseEvent outside our window, send leave event to last focused widget + QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos, + Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); + if (S60->lastPointerEventTarget) + qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent); + S60->lastPointerEventTarget = 0; + } + return 1; + } + break; + case EEventScreenDeviceChanged: + if (S60) + S60->updateScreenSize(); + if (qt_desktopWidget) { + QSize oldSize = qt_desktopWidget->size(); + qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels); + qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels); + QResizeEvent e(qt_desktopWidget->size(), oldSize); + QApplication::sendEvent(qt_desktopWidget, &e); + } + return 0; // Propagate to CONE + case EEventWindowVisibilityChanged: + if (controlInMap) { + const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged(); + QWidget *w = QWidgetPrivate::mapper->value(control); + if (!w->d_func()->maybeTopData()) + break; + if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) { + delete w->d_func()->topData()->backingStore; + w->d_func()->topData()->backingStore = 0; + } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible) + && !w->d_func()->maybeBackingStore()) { + w->d_func()->topData()->backingStore = new QWidgetBackingStore(w); + w->update(); + } + return 1; + } + break; + default: + break; + } + + if (!controlInMap) + return -1; + + return 0; +} + +bool QApplication::s60EventFilter(TWsEvent *aEvent) +{ + return false; +} + +/*! + Handles commands which are typically handled by CAknAppUi::HandleCommandL() + Qts Ui integration into Symbian is partially achieved by deriving from CAknAppUi. + Currently, exit, menu and softkey commands are handled + + \sa s60EventFilter(), s60ProcessEvent() +*/ +void QApplication::symbianHandleCommand(int command) +{ + switch (command) { + case EEikCmdExit: + case EAknSoftkeyExit: + exit(); + break; + default: + if (command >= SOFTKEYSTART && command <= SOFTKEYEND) { + int index= command-SOFTKEYSTART; + QWidget *focused = QApplication::focusWidget(); + QWidget *softKeySource = focused ? focused : QApplication::activeWindow(); + const QList<QAction*>& softKeys = softKeySource->softKeys(); + Q_ASSERT(index < softKeys.count()); + softKeys.at(index)->activate(QAction::Trigger); + } + else + QMenuBarPrivate::symbianCommands(command); + break; + } +} + +void QApplication::symbianResourceChange(int type) +{ + switch (type) { + case KEikDynamicLayoutVariantSwitch: + { + if (S60) + S60->updateScreenSize(); + +#ifndef QT_NO_STYLE_S60 + QS60Style *s60Style = 0; + +#ifndef QT_NO_STYLE_STYLESHEET + QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style()); + if (proxy) + s60Style = qobject_cast<QS60Style*>(proxy->baseStyle()); + else +#endif + s60Style = qobject_cast<QS60Style*>(QApplication::style()); + + if (s60Style) + s60Style->handleDynamicLayoutVariantSwitch(); +#endif + } + break; + +#ifndef QT_NO_STYLE_S60 + case KAknsMessageSkinChange: + if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) + s60Style->handleSkinChange(); + break; +#endif + + default: + break; + } +} + +#ifndef QT_NO_WHEELEVENT +int QApplication::wheelScrollLines() +{ + return QApplicationPrivate::wheel_scroll_lines; +} + +void QApplication::setWheelScrollLines(int n) +{ + QApplicationPrivate::wheel_scroll_lines = n; +} +#endif //QT_NO_WHEELEVENT + +bool QApplication::isEffectEnabled(Qt::UIEffect effect) +{ + // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect) + return false; +} + +void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) +{ + // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) +} + +TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym) +{ + if (keysym) { + // If keysym is specified, cache it. + scanCodeCache.insert(scanCode, keysym); + return keysym; + } else { + // If not, retrieve the cached version. + return scanCodeCache[scanCode]; + } +} + +#ifndef QT_NO_SESSIONMANAGER +QSessionManager::QSessionManager(QApplication * app, QString &id, QString& key) +{ + +} + +QSessionManager::~QSessionManager() +{ + +} + +bool QSessionManager::allowsInteraction() +{ + return false; +} + +void QSessionManager::cancel() +{ + +} +#endif //QT_NO_SESSIONMANAGER +QT_END_NAMESPACE + + diff --git a/src/gui/kernel/qclipboard_s60.cpp b/src/gui/kernel/qclipboard_s60.cpp new file mode 100644 index 0000000..f89f3e5 --- /dev/null +++ b/src/gui/kernel/qclipboard_s60.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclipboard.h" + +#ifndef QT_NO_CLIPBOARD + +#include "qapplication.h" +#include "qbitmap.h" +#include "qdatetime.h" +#include "qbuffer.h" +#include "qwidget.h" +#include "qevent.h" +#include <QtDebug> + +// Symbian's clipboard +#include <baclipb.h> +QT_BEGIN_NAMESPACE + +//### Mime Type mapping to UIDs + +const TUid KQtCbDataStream = {0x666777}; + + +class QClipboardData +{ +public: + QClipboardData(); + ~QClipboardData(); + + void setSource(QMimeData* s) + { + if (s == src) + return; + delete src; + src = s; + } + QMimeData* source() + { return src; } + bool connected() + { return connection; } + void clear(); + RFs fsSession(); + + +private: + QMimeData* src; + RFs iFs; + bool connection; +}; + +QClipboardData::QClipboardData():src(0),connection(true) +{ + clear(); + if (KErrNone != iFs.Connect()) + { + qWarning("QClipboardData::fileserver connnect failed"); + connection = false; + } +} + +QClipboardData::~QClipboardData() +{ + iFs.Close(); + connection = false; + delete src; +} + +void QClipboardData::clear() +{ + QMimeData* newSrc = new QMimeData; + delete src; + src = newSrc; +} +RFs QClipboardData::fsSession() +{ + return iFs; +} + +static QClipboardData *internalCbData = 0; + +static void cleanupClipboardData() +{ + delete internalCbData; + internalCbData = 0; +} + +static QClipboardData *clipboardData() +{ + if (internalCbData == 0) { + internalCbData = new QClipboardData; + if (internalCbData) + { + if (!internalCbData->connected()) + { + delete internalCbData; + internalCbData = 0; + } + else + { + qAddPostRoutine(cleanupClipboardData); + } + } + } + return internalCbData; +} + +void writeToStream(const QMimeData* aData, RWriteStream& aStream) +{ + QStringList headers = aData->formats(); + aStream << TCardinality(headers.count()); + for (QStringList::const_iterator iter= headers.constBegin();iter != headers.constEnd();iter++) + { + HBufC* stringData = TPtrC(reinterpret_cast<const TUint16*>((*iter).utf16())).AllocLC(); + QByteArray ba = aData->data((*iter)); + qDebug() << "copy to clipboard mime: " << *iter << " data: " << ba; + // mime type + aStream << TCardinality(stringData->Size()); + aStream << *(stringData); + // mime data + aStream << TCardinality(ba.size()); + aStream.WriteL(reinterpret_cast<const uchar*>(ba.constData()),ba.size()); + CleanupStack::PopAndDestroy(stringData); + } +} + +void readFromStream(QMimeData* aData,RReadStream& aStream) +{ + TCardinality mimeTypeCount; + aStream >> mimeTypeCount; + for (int i = 0; i< mimeTypeCount;i++) + { + // mime type + TCardinality mimeTypeSize; + aStream >> mimeTypeSize; + HBufC* mimeTypeBuf = HBufC::NewLC(aStream,mimeTypeSize); + QString mimeType = QString::fromUtf16(mimeTypeBuf->Des().Ptr(),mimeTypeBuf->Length()); + // mime data + TCardinality dataSize; + aStream >> dataSize; + QByteArray ba; + ba.reserve(dataSize); + aStream.ReadL(reinterpret_cast<uchar*>(ba.data_ptr()->data),dataSize); + ba.data_ptr()->size = dataSize; + qDebug() << "paste from clipboard mime: " << mimeType << " data: " << ba; + aData->setData(mimeType,ba); + CleanupStack::PopAndDestroy(mimeTypeBuf); + + } +} + + +/***************************************************************************** + QClipboard member functions + *****************************************************************************/ + +void QClipboard::clear(Mode mode) +{ + setText(QString(), mode); +} +const QMimeData* QClipboard::mimeData(Mode mode) const +{ + if (mode != Clipboard) return 0; + QClipboardData *d = clipboardData(); + if (d) + { + //###fixme when exceptions are added to Qt + TRAPD(err,{ + RFs fs = d->fsSession(); + CClipboard* cb = CClipboard::NewForReadingLC(fs); + Q_ASSERT(cb); + RStoreReadStream stream; + TStreamId stid = (cb->StreamDictionary()).At(KQtCbDataStream); + stream.OpenLC(cb->Store(),stid); + readFromStream(d->source(),stream); + CleanupStack::PopAndDestroy(2,cb); + return d->source(); + }); + if (err != KErrNone){ + qDebug()<< "clipboard is empty/err: " << err; + } + + } + return 0; +} + + +void QClipboard::setMimeData(QMimeData* src, Mode mode) +{ + if (mode != Clipboard) return; + QClipboardData *d = clipboardData(); + if (d) + { + //###fixme when exceptions are added to Qt + TRAPD(err,{ + RFs fs = d->fsSession(); + CClipboard* cb = CClipboard::NewForWritingLC(fs); + RStoreWriteStream stream; + TStreamId stid = stream.CreateLC(cb->Store()); + writeToStream(src,stream); + d->setSource(src); + stream.CommitL(); + (cb->StreamDictionary()).AssignL(KQtCbDataStream,stid); + cb->CommitL(); + CleanupStack::PopAndDestroy(2,cb); + }); + if (err != KErrNone){ + qDebug()<< "clipboard write err :" << err; + } + } + emitChanged(QClipboard::Clipboard); +} + +bool QClipboard::supportsMode(Mode mode) const +{ + return (mode == Clipboard); +} + +bool QClipboard::ownsMode(Mode mode) const +{ + if (mode == Clipboard) + qWarning("QClipboard::ownsClipboard: UNIMPLEMENTED!"); + return false; +} + +bool QClipboard::event(QEvent *e) +{ + return true; +} + +void QClipboard::connectNotify( const char * ) +{ +} + +void QClipboard::ownerDestroyed() +{ +} +QT_END_NAMESPACE +#endif // QT_NO_CLIPBOARD
\ No newline at end of file diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 4ffa8fd..e5056a4 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -561,7 +561,6 @@ QCursor::operator QVariant() const { return QVariant(QVariant::Cursor, this); } - +QT_END_NAMESPACE #endif // QT_NO_CURSOR -QT_END_NAMESPACE diff --git a/src/gui/kernel/qcursor_qws.cpp b/src/gui/kernel/qcursor_qws.cpp index 097b982..99800a8 100644 --- a/src/gui/kernel/qcursor_qws.cpp +++ b/src/gui/kernel/qcursor_qws.cpp @@ -66,7 +66,11 @@ QCursorData::~QCursorData() { delete bm; delete bmm; - QPaintDevice::qwsDisplay()->destroyCursor(id); + QT_TRY { + QPaintDevice::qwsDisplay()->destroyCursor(id); + } QT_CATCH(const std::bad_alloc &) { + // do nothing. + } } diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp new file mode 100644 index 0000000..a281130 --- /dev/null +++ b/src/gui/kernel/qcursor_s60.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qcursor_p.h> +#include <qcursor.h> +#include <qt_s60_p.h> + +#ifdef QT_NO_CURSOR +QT_BEGIN_NAMESPACE + +QPoint QCursor::pos() +{ + return S60->lastCursorPos; +} + +void QCursor::setPos(int x, int y) +{ + S60->lastCursorPos = QPoint(x, y); +} + +QT_END_NAMESPACE +#endif // QT_NO_CURSOR diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp new file mode 100644 index 0000000..eefd0ef --- /dev/null +++ b/src/gui/kernel/qdesktopwidget_s60.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesktopwidget.h" +#include "qapplication_p.h" +#include "qwidget_p.h" +#include "qt_s60_p.h" +#include <w32std.h> + +#include "hal.h" +#include "hal_data.h" + +QT_BEGIN_NAMESPACE + +class QDesktopWidgetPrivate : public QWidgetPrivate +{ + +public: + QDesktopWidgetPrivate(); + ~QDesktopWidgetPrivate(); + + static void init(QDesktopWidget *that); + static void cleanup(); + + static int screenCount; + static int primaryScreen; + + static QVector<QRect> *rects; + static QVector<QRect> *workrects; + + static int refcount; +}; + +int QDesktopWidgetPrivate::screenCount = 1; +int QDesktopWidgetPrivate::primaryScreen = 0; +QVector<QRect> *QDesktopWidgetPrivate::rects = 0; +QVector<QRect> *QDesktopWidgetPrivate::workrects = 0; +int QDesktopWidgetPrivate::refcount = 0; + +QDesktopWidgetPrivate::QDesktopWidgetPrivate() +{ + ++refcount; +} + +QDesktopWidgetPrivate::~QDesktopWidgetPrivate() +{ + if (!--refcount) + cleanup(); +} + +void QDesktopWidgetPrivate::init(QDesktopWidget *that) +{ + int screenCount=0; + + if (HAL::Get(0, HALData::EDisplayNumberOfScreens, screenCount) == KErrNone) + QDesktopWidgetPrivate::screenCount = screenCount; + else + QDesktopWidgetPrivate::screenCount = 0; + + rects = new QVector<QRect>(); + workrects = new QVector<QRect>(); + + rects->resize(QDesktopWidgetPrivate::screenCount); + workrects->resize(QDesktopWidgetPrivate::screenCount); + + // ### TODO: Implement proper multi-display support + rects->resize(1); + rects->replace(0, that->rect()); + workrects->resize(1); + workrects->replace(0, that->rect()); +} + +void QDesktopWidgetPrivate::cleanup() +{ + delete rects; + rects = 0; + delete workrects; + workrects = 0; +} + + +QDesktopWidget::QDesktopWidget() + : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop) +{ + setObjectName(QLatin1String("desktop")); + QDesktopWidgetPrivate::init(this); +} + +QDesktopWidget::~QDesktopWidget() +{ + QDesktopWidgetPrivate::cleanup(); +} + +bool QDesktopWidget::isVirtualDesktop() const +{ + return true; +} + +int QDesktopWidget::primaryScreen() const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +int QDesktopWidget::numScreens() const +{ + Q_D(const QDesktopWidget); + return QDesktopWidgetPrivate::screenCount; +} + +QWidget *QDesktopWidget::screen(int /* screen */) +{ + return this; +} + +const QRect QDesktopWidget::availableGeometry(int /* screen */) const +{ + TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + return qt_TRect2QRect(clientRect); +} + +const QRect QDesktopWidget::screenGeometry(int /* screen */) const +{ + Q_D(const QDesktopWidget); + return QRect(0, 0, S60->screenWidthInPixels, S60->screenHeightInPixels); + } + +int QDesktopWidget::screenNumber(const QWidget *widget) const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +int QDesktopWidget::screenNumber(const QPoint &point) const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +void QDesktopWidget::resizeEvent(QResizeEvent *) +{ + Q_D(QDesktopWidget); + QVector<QRect> oldrects; + oldrects = *d->rects; + QVector<QRect> oldworkrects; + oldworkrects = *d->workrects; + int oldscreencount = d->screenCount; + + QDesktopWidgetPrivate::cleanup(); + QDesktopWidgetPrivate::init(this); + + for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) { + QRect oldrect = oldrects[i]; + QRect newrect = d->rects->at(i); + if (oldrect != newrect) + emit resized(i); + } + + for (int j = 0; j < qMin(oldscreencount, d->screenCount); ++j) { + QRect oldrect = oldworkrects[j]; + QRect newrect = d->workrects->at(j); + if (oldrect != newrect) + emit workAreaResized(j); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp new file mode 100644 index 0000000..c459f8f --- /dev/null +++ b/src/gui/kernel/qdnd_s60.cpp @@ -0,0 +1,395 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" + +#ifndef QT_NO_DRAGANDDROP + +#include "qwidget.h" +#include "qdatetime.h" +#include "qbitmap.h" +#include "qcursor.h" +#include "qevent.h" +#include "qpainter.h" +#include "qdnd_p.h" + +#include <COECNTRL.H> +// pointer cursor +#include <w32std.h> +#include <gdi.h> +QT_BEGIN_NAMESPACE +//### artistic impression of Symbians default DnD cursor ? + +static QPixmap *defaultPm = 0; +static const int default_pm_hotx = -50; +static const int default_pm_hoty = -50; +static const char *const default_pm[] = { +"13 9 3 1", +". c None", +" c #000000", +"X c #FFFFFF", +"X X X X X X X", +" X X X X X X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X X X X X X ", +"X X X X X X X", +}; +//### actions need to be redefined for S60 +// Shift/Ctrl handling, and final drop status +static Qt::DropAction global_accepted_action = Qt::MoveAction; +static Qt::DropActions possible_actions = Qt::IgnoreAction; + + +// static variables in place of a proper cross-process solution +static QDrag *drag_object; +static bool qt_symbian_dnd_dragging = false; + + +static Qt::KeyboardModifiers oldstate; + +class QShapedPixmapWidget +{ +public: + QShapedPixmapWidget(RWsSession aWsSession,RWindowTreeNode* aNode) + { + sprite = RWsSprite(aWsSession); + cursorSprite.iBitmap = 0; + cursorSprite.iMaskBitmap = 0; + cursorSprite.iInvertMask = EFalse; + cursorSprite.iOffset = TPoint(0,0); + cursorSprite.iInterval = TTimeIntervalMicroSeconds32(0); + cursorSprite.iDrawMode = CGraphicsContext::EDrawModePEN; + sprite.Construct(*aNode,TPoint(0,0), ESpriteNoShadows | ESpriteNoChildClip); + sprite.AppendMember(cursorSprite); + sprite.Activate(); + } + ~QShapedPixmapWidget() + { + sprite.Close(); + cursorSprite.iBitmap = 0; + delete cursorBitmap; + cursorBitmap = 0; //redundant... + } + void disableCursor() + { + cursorSprite.iBitmap = 0; + sprite.UpdateMember(0,cursorSprite); + } + void enableCursor() + { + cursorSprite.iBitmap = cursorBitmap; + sprite.UpdateMember(0,cursorSprite); + } + void setPixmap(QPixmap pm) + { + //### heaplock centralized. + QImage temp = pm.toImage(); + QSize size = pm.size(); + temp.bits(); + CFbsBitmap *curbm = new (ELeave) CFbsBitmap(); + curbm->Create(TSize(size.width(),size.height()),EColor16MA); + curbm->LockHeap(ETrue); + memcpy((uchar*)curbm->DataAddress(),temp.bits(),temp.numBytes()); + curbm->UnlockHeap(ETrue); + delete cursorSprite.iBitmap; + cursorSprite.iBitmap = curbm; + cursorBitmap = curbm; + sprite.UpdateMember(0,cursorSprite); + } + CFbsBitmap *cursorBitmap; + RWsPointerCursor pointerCursor; + RWsSprite sprite; + TSpriteMember cursorSprite; + +}; + + +static QShapedPixmapWidget *qt_symbian_dnd_deco = 0; + +void QDragManager::updatePixmap() +{ + if (qt_symbian_dnd_deco) { + QPixmap pm; + QPoint pm_hot(default_pm_hotx,default_pm_hoty); + if (drag_object) { + pm = drag_object->pixmap(); + if (!pm.isNull()) + pm_hot = drag_object->hotSpot(); + } + if (pm.isNull()) { + if (!defaultPm) + defaultPm = new QPixmap(default_pm); + pm = *defaultPm; + } + qt_symbian_dnd_deco->setPixmap(pm); + } +} + +void QDragManager::timerEvent(QTimerEvent *) { } + +void QDragManager::move(const QPoint&) { +} + +void QDragManager::updateCursor() +{ +} + + +bool QDragManager::eventFilter(QObject *o, QEvent *e) +{ + if (beingCancelled) { + return false; + } + if (!o->isWidgetType()) + return false; + + switch(e->type()) { + case QEvent::MouseButtonPress: + { + } + case QEvent::MouseMove: + { + if (!object) { //#### this should not happen + qWarning("QDragManager::eventFilter: No object"); + return true; + } + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + if (manager->object) + possible_actions = manager->dragPrivate()->possible_actions; + else + possible_actions = Qt::IgnoreAction; + + QMouseEvent *me = (QMouseEvent *)e; + + if (me->buttons()) { + Qt::DropAction prevAction = global_accepted_action; + QWidget *cw = QApplication::widgetAt(me->globalPos()); + // map the Coords relative to the window. + if (!cw) + return true; + TPoint windowPos = cw->effectiveWinId()->PositionRelativeToScreen(); + qt_symbian_dnd_deco->sprite.SetPosition(TPoint(me->globalX()- windowPos.iX,me->globalY()- windowPos.iY)); + + while (cw && !cw->acceptDrops() && !cw->isWindow()) + cw = cw->parentWidget(); + + if (object->target() != cw) { + if (object->target()) { + QDragLeaveEvent dle; + QApplication::sendEvent(object->target(), &dle); + willDrop = false; + global_accepted_action = Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + object->d_func()->target = 0; + } + if (cw && cw->acceptDrops()) { + object->d_func()->target = cw; + QDragEnterEvent dee(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QApplication::sendEvent(object->target(), &dee); + willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction; + global_accepted_action = willDrop ? dee.dropAction() : Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + } + } else if (cw) { + QDragMoveEvent dme(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + if (global_accepted_action != Qt::IgnoreAction) { + dme.setDropAction(global_accepted_action); + dme.accept(); + } + QApplication::sendEvent(cw, &dme); + willDrop = dme.isAccepted(); + global_accepted_action = willDrop ? dme.dropAction() : Qt::IgnoreAction; + updatePixmap(); + updateCursor(); + } + if (global_accepted_action != prevAction) + emitActionChanged(global_accepted_action); + } + return true; // Eat all mouse events + } + + case QEvent::MouseButtonRelease: + { + qApp->removeEventFilter(this); + if (restoreCursor) { + qt_symbian_dnd_deco->disableCursor(); + willDrop = false; + restoreCursor = false; + } + if (object && object->target()) { + + QMouseEvent *me = (QMouseEvent *)e; + + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + + QDropEvent de(object->target()->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QApplication::sendEvent(object->target(), &de); + if (de.isAccepted()) + global_accepted_action = de.dropAction(); + else + global_accepted_action = Qt::IgnoreAction; + + if (object) + object->deleteLater(); + drag_object = object = 0; + } + eventLoop->exit(); + return true; // Eat all mouse events + } + + default: + break; + } + return false; +} + +Qt::DropAction QDragManager::drag(QDrag *o) +{ + Q_ASSERT(!qt_symbian_dnd_dragging); + if (object == o || !o || !o->source()) + return Qt::IgnoreAction; + + if (object) { + cancel(); + qApp->removeEventFilter(this); + beingCancelled = false; + } + + object = drag_object = o; + RWsSession winSession = o->source()->effectiveWinId()->ControlEnv()->WsSession(); + Q_ASSERT(!qt_symbian_dnd_deco); + qt_symbian_dnd_deco = new QShapedPixmapWidget(winSession, o->source()->effectiveWinId()->DrawableWindow()); + + oldstate = Qt::NoModifier; // #### Should use state that caused the drag + willDrop = false; + updatePixmap(); + updateCursor(); + restoreCursor = true; + + object->d_func()->target = 0; + TPoint windowPos = source()->effectiveWinId()->PositionRelativeToScreen(); + qt_symbian_dnd_deco->sprite.SetPosition(TPoint(QCursor::pos().x()- windowPos.iX ,QCursor::pos().y() - windowPos.iY)); + + QPoint hotspot = drag_object->hotSpot(); + qt_symbian_dnd_deco->cursorSprite.iOffset = TPoint(- hotspot.x(),- hotspot.y()); + qt_symbian_dnd_deco->sprite.UpdateMember(0,qt_symbian_dnd_deco->cursorSprite); + + qApp->installEventFilter(this); + + global_accepted_action = Qt::MoveAction; + qt_symbian_dnd_dragging = true; + + eventLoop = new QEventLoop; + // block + (void) eventLoop->exec(QEventLoop::AllEvents); + delete eventLoop; + eventLoop = 0; + + delete qt_symbian_dnd_deco; + qt_symbian_dnd_deco = 0; + qt_symbian_dnd_dragging = false; + + + return global_accepted_action; +} + + +void QDragManager::cancel(bool deleteSource) +{ + beingCancelled = true; + + if (object->target()) { + QDragLeaveEvent dle; + QApplication::sendEvent(object->target(), &dle); + } + + if (drag_object) { + if (deleteSource) + object->deleteLater(); + drag_object = object = 0; + } + + delete qt_symbian_dnd_deco; + qt_symbian_dnd_deco = 0; + + global_accepted_action = Qt::IgnoreAction; +} + + +void QDragManager::drop() +{ +} + +QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const +{ + if (!drag_object) + return QVariant(); + QByteArray data = drag_object->mimeData()->data(mimetype); + if (type == QVariant::String) + return QString::fromUtf8(data); + return data; +} + +bool QDropData::hasFormat_sys(const QString &format) const +{ + return formats().contains(format); +} + +QStringList QDropData::formats_sys() const +{ + if (drag_object) + return drag_object->mimeData()->formats(); + return QStringList(); +} + +QT_END_NAMESPACE +#endif // QT_NO_DRAGANDDROP diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index a59e870..99677e2 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1676,6 +1676,17 @@ Qt::ButtonState QContextMenuEvent::state() const several are specified for any character in the string the behaviour is undefined. + \value Selection + If set, the edit cursor should be moved to the specified position + in the editor text contents. In contrast with \c Cursor, this + attribute does not work on the preedit text, but on the surrounding + text. The cursor will be moved after the commit string has been + committed, and the preedit string will be located at the new edit + position. + The start position specifies the new position and the length + variable can be used to set a selection starting from that point. + The value is unused. + \sa Attribute */ diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 449730d..7696d05 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -241,7 +241,7 @@ public: inline QT3_SUPPORT_CONSTRUCTOR QKeyEvent(Type type, int key, int /*ascii*/, int modifiers, const QString& text = QString(), bool autorep = false, ushort count = 1) - : QInputEvent(type, (Qt::KeyboardModifiers)(modifiers & (int)Qt::KeyButtonMask)), txt(text), k(key), + : QInputEvent(type, Qt::KeyboardModifiers(modifiers & (int)Qt::KeyButtonMask)), txt(text), k(key), c(count), autor(autorep) { if (key >= Qt::Key_Back && key <= Qt::Key_MediaLast) @@ -424,7 +424,8 @@ public: TextFormat, Cursor, Language, - Ruby + Ruby, + Selection }; class Attribute { public: diff --git a/src/gui/kernel/qeventdispatcher_s60.cpp b/src/gui/kernel/qeventdispatcher_s60.cpp new file mode 100644 index 0000000..51878df --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qwidget.h> + +#include "qeventdispatcher_s60_p.h" + +QT_BEGIN_NAMESPACE + +QEventDispatcherS60::QEventDispatcherS60(QObject *parent) + : QEventDispatcherSymbian(parent), + m_noInputEvents(false) +{ +} + +QEventDispatcherS60::~QEventDispatcherS60() +{ + for (int c = 0; c < m_deferredInputEvents.size(); ++c) { + delete m_deferredInputEvents[c].event; + } +} + +bool QEventDispatcherS60::processEvents ( QEventLoop::ProcessEventsFlags flags ) +{ + bool ret = false; + + QT_TRY { + bool oldNoInputEventsValue = m_noInputEvents; + if (flags & QEventLoop::ExcludeUserInputEvents) { + m_noInputEvents = true; + } else { + m_noInputEvents = false; + ret = sendDeferredInputEvents() || ret; + } + + ret = QEventDispatcherSymbian::processEvents(flags) || ret; + + m_noInputEvents = oldNoInputEventsValue; + } QT_CATCH (const std::exception& ex) { +#ifndef QT_NO_EXCEPTIONS + CActiveScheduler::Current()->Error(qt_translateExceptionToSymbianError(ex)); +#endif + } + + return ret; +} + +bool QEventDispatcherS60::hasPendingEvents() +{ + return !m_deferredInputEvents.isEmpty() || QEventDispatcherSymbian::hasPendingEvents(); +} + +void QEventDispatcherS60::saveInputEvent(QSymbianControl *control, QWidget *widget, QInputEvent *event) +{ + DeferredInputEvent inputEvent = {control, widget, event}; + m_deferredInputEvents.append(inputEvent); + connect(widget, SIGNAL(destroyed(QObject *)), SLOT(removeInputEventsForWidget(QObject *))); +} + +bool QEventDispatcherS60::sendDeferredInputEvents() +{ + bool eventsSent = false; + while (!m_deferredInputEvents.isEmpty()) { + DeferredInputEvent inputEvent = m_deferredInputEvents.takeFirst(); +#ifndef QT_NO_EXCEPTIONS + try { +#endif + inputEvent.control->sendInputEvent(inputEvent.widget, inputEvent.event); +#ifndef QT_NO_EXCEPTIONS + } catch (...) { + delete inputEvent.event; + throw; + } +#endif + delete inputEvent.event; + eventsSent = true; + } + + return eventsSent; +} + +void QEventDispatcherS60::removeInputEventsForWidget(QObject *object) +{ + for (int c = 0; c < m_deferredInputEvents.size(); ++c) { + if (m_deferredInputEvents[c].widget == object) { + delete m_deferredInputEvents[c].event; + m_deferredInputEvents.removeAt(c--); + } + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qeventdispatcher_s60_p.h b/src/gui/kernel/qeventdispatcher_s60_p.h new file mode 100644 index 0000000..e42af95 --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_S60_P_H +#define QEVENTDISPATCHER_S60_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/qeventdispatcher_symbian_p.h> +#include "qt_s60_p.h" + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QEventDispatcherS60 : public QEventDispatcherSymbian +{ + Q_OBJECT + +public: + QEventDispatcherS60(QObject *parent = 0); + ~QEventDispatcherS60(); + + bool processEvents ( QEventLoop::ProcessEventsFlags flags ); + bool hasPendingEvents(); + + bool excludeUserInputEvents() { return m_noInputEvents; } + + void saveInputEvent(QSymbianControl *control, QWidget *widget, QInputEvent *event); + +private: + bool sendDeferredInputEvents(); + +private Q_SLOTS: + void removeInputEventsForWidget(QObject *object); + +private: + bool m_noInputEvents; + + struct DeferredInputEvent + { + QSymbianControl *control; + QWidget *widget; + QInputEvent *event; + }; + QList<DeferredInputEvent> m_deferredInputEvents; +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_S60_P_H diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index f1d938c..8937aaf 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -58,6 +58,7 @@ #include <qlist.h> #include <qlocale.h> #include <qevent.h> +#include <qhash.h> #if defined (Q_WS_MAC64) # include <private/qt_mac_p.h> @@ -203,6 +204,13 @@ public: UInt32 keyboard_dead; KeyboardLayoutItem *keyLayout[256]; #elif defined(Q_WS_QWS) +#elif defined(Q_WS_S60) +private: + QHash<TUint, int> s60ToQtKeyMap; + void fillKeyMap(); +public: + QString translateKeyEvent(int keySym, Qt::KeyboardModifiers modifiers); + int mapS60KeyToQt(TUint s60key); #endif }; diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp new file mode 100644 index 0000000..bb074c1 --- /dev/null +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qkeymapper_p.h" +#include <e32keys.h> + +QT_BEGIN_NAMESPACE + +QKeyMapperPrivate::QKeyMapperPrivate() +{ + fillKeyMap(); +} + +QKeyMapperPrivate::~QKeyMapperPrivate() +{ +} + +QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e) +{ + QList<int> result; + return result; +} + +void QKeyMapperPrivate::clearMappings() +{ + // stub +} + +QString QKeyMapperPrivate::translateKeyEvent(int keySym, Qt::KeyboardModifiers modifiers) +{ + if (keySym >= Qt::Key_Escape) + return QString(); + + // Symbian doesn't actually use modifiers, but gives us the character code directly. + + return QString(QChar(keySym)); +} + +void QKeyMapperPrivate::fillKeyMap() +{ + using namespace Qt; + static const struct { + TUint s60Key; + int qtKey; + } map[] = { + {EKeyBell, Key_unknown}, + {EKeyBackspace, Key_Backspace}, + {EKeyTab, Key_Tab}, + {EKeyLineFeed, Key_unknown}, + {EKeyVerticalTab, Key_unknown}, + {EKeyFormFeed, Key_unknown}, + {EKeyEnter, Key_Enter}, + {EKeyEscape, Key_Escape}, + {EKeySpace, Key_Space}, + {EKeyDelete, Key_Delete}, + {EKeyPrintScreen, Key_SysReq}, + {EKeyPause, Key_Pause}, + {EKeyHome, Key_Home}, + {EKeyEnd, Key_End}, + {EKeyPageUp, Key_PageUp}, + {EKeyPageDown, Key_PageDown}, + {EKeyInsert, Key_Insert}, + {EKeyLeftArrow, Key_Left}, + {EKeyRightArrow, Key_Right}, + {EKeyUpArrow, Key_Up}, + {EKeyDownArrow, Key_Down}, + {EKeyLeftShift, Key_Shift}, + {EKeyRightShift, Key_Shift}, + {EKeyLeftAlt, Key_Alt}, + {EKeyRightAlt, Key_AltGr}, + {EKeyLeftCtrl, Key_Control}, + {EKeyRightCtrl, Key_Control}, + {EKeyLeftFunc, Key_Super_L}, + {EKeyRightFunc, Key_Super_R}, + {EKeyCapsLock, Key_CapsLock}, + {EKeyNumLock, Key_NumLock}, + {EKeyScrollLock, Key_ScrollLock}, + {EKeyF1, Key_F1}, + {EKeyF2, Key_F2}, + {EKeyF3, Key_F3}, + {EKeyF4, Key_F4}, + {EKeyF5, Key_F5}, + {EKeyF6, Key_F6}, + {EKeyF7, Key_F7}, + {EKeyF8, Key_F8}, + {EKeyF9, Key_F9}, + {EKeyF10, Key_F10}, + {EKeyF11, Key_F11}, + {EKeyF12, Key_F12}, + {EKeyF13, Key_F13}, + {EKeyF14, Key_F14}, + {EKeyF15, Key_F15}, + {EKeyF16, Key_F16}, + {EKeyF17, Key_F17}, + {EKeyF18, Key_F18}, + {EKeyF19, Key_F19}, + {EKeyF20, Key_F20}, + {EKeyF21, Key_F21}, + {EKeyF22, Key_F22}, + {EKeyF23, Key_F23}, + {EKeyF24, Key_F24}, + {EKeyOff, Key_unknown}, + {EKeyIncContrast, Key_unknown}, + {EKeyDecContrast, Key_unknown}, + {EKeyBacklightOn, Key_unknown}, + {EKeyBacklightOff, Key_unknown}, + {EKeyBacklightToggle, Key_unknown}, + {EKeySliderDown, Key_unknown}, + {EKeySliderUp, Key_unknown}, + {EKeyMenu, Key_Menu}, + {EKeyDictaphonePlay, Key_unknown}, + {EKeyDictaphoneStop, Key_unknown}, + {EKeyDictaphoneRecord, Key_unknown}, + {EKeyHelp, Key_unknown}, + {EKeyDial, Key_Call}, + {EKeyScreenDimension0, Key_unknown}, + {EKeyScreenDimension1, Key_unknown}, + {EKeyScreenDimension2, Key_unknown}, + {EKeyScreenDimension3, Key_unknown}, + {EKeyIncVolume, Key_unknown}, + {EKeyDecVolume, Key_unknown}, + {EKeyDevice0, Key_Context1}, // Found by manual testing, left softkey. + {EKeyDevice1, Key_Context2}, // Found by manual testing. + {EKeyDevice2, Key_unknown}, + {EKeyDevice3, Key_Select}, // Found by manual testing. + {EKeyDevice4, Key_unknown}, + {EKeyDevice5, Key_unknown}, + {EKeyDevice6, Key_unknown}, + {EKeyDevice7, Key_unknown}, + {EKeyDevice8, Key_unknown}, + {EKeyDevice9, Key_unknown}, + {EKeyDeviceA, Key_unknown}, + {EKeyDeviceB, Key_unknown}, + {EKeyDeviceC, Key_unknown}, + {EKeyDeviceD, Key_unknown}, + {EKeyDeviceE, Key_unknown}, + {EKeyDeviceF, Key_unknown}, + {EKeyApplication0, Key_Launch0}, + {EKeyApplication1, Key_Launch1}, + {EKeyApplication2, Key_Launch2}, + {EKeyApplication3, Key_Launch3}, + {EKeyApplication4, Key_Launch4}, + {EKeyApplication5, Key_Launch5}, + {EKeyApplication6, Key_Launch6}, + {EKeyApplication7, Key_Launch7}, + {EKeyApplication8, Key_Launch8}, + {EKeyApplication9, Key_Launch9}, + {EKeyApplicationA, Key_LaunchA}, + {EKeyApplicationB, Key_LaunchB}, + {EKeyApplicationC, Key_LaunchC}, + {EKeyApplicationD, Key_LaunchD}, + {EKeyApplicationE, Key_LaunchE}, + {EKeyApplicationF, Key_LaunchF}, + {EKeyYes, Key_Yes}, + {EKeyNo, Key_No}, + {EKeyIncBrightness, Key_unknown}, + {EKeyDecBrightness, Key_unknown}, + {EKeyKeyboardExtend, Key_unknown}, + {EKeyDevice10, Key_unknown}, + {EKeyDevice11, Key_unknown}, + {EKeyDevice12, Key_unknown}, + {EKeyDevice13, Key_unknown}, + {EKeyDevice14, Key_unknown}, + {EKeyDevice15, Key_unknown}, + {EKeyDevice16, Key_unknown}, + {EKeyDevice17, Key_unknown}, + {EKeyDevice18, Key_unknown}, + {EKeyDevice19, Key_unknown}, + {EKeyDevice1A, Key_unknown}, + {EKeyDevice1B, Key_unknown}, + {EKeyDevice1C, Key_unknown}, + {EKeyDevice1D, Key_unknown}, + {EKeyDevice1E, Key_unknown}, + {EKeyDevice1F, Key_unknown}, + {EKeyApplication10, Key_unknown}, + {EKeyApplication11, Key_unknown}, + {EKeyApplication12, Key_unknown}, + {EKeyApplication13, Key_unknown}, + {EKeyApplication14, Key_unknown}, + {EKeyApplication15, Key_unknown}, + {EKeyApplication16, Key_unknown}, + {EKeyApplication17, Key_unknown}, + {EKeyApplication18, Key_unknown}, + {EKeyApplication19, Key_unknown}, + {EKeyApplication1A, Key_unknown}, + {EKeyApplication1B, Key_unknown}, + {EKeyApplication1C, Key_unknown}, + {EKeyApplication1D, Key_unknown}, + {EKeyApplication1E, Key_unknown}, + {EKeyApplication1F, Key_unknown} + }; + const int mapSize = int(sizeof(map)/sizeof(map[0])); + s60ToQtKeyMap.reserve(mapSize + 5); // +5? docs: Ideally, slightly more than number of items + for (int i = 0; i < mapSize; ++i) + s60ToQtKeyMap.insert(map[i].s60Key, map[i].qtKey); +} + +int QKeyMapperPrivate::mapS60KeyToQt(TUint s60key) +{ + QHash<TUint, int>::const_iterator mapping; + mapping = s60ToQtKeyMap.find(s60key); + if (mapping != s60ToQtKeyMap.end()) { + return *mapping; + } else { + return Qt::Key_unknown; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qlayout.cpp b/src/gui/kernel/qlayout.cpp index 0a233d5..2d4ff18 100644 --- a/src/gui/kernel/qlayout.cpp +++ b/src/gui/kernel/qlayout.cpp @@ -145,7 +145,12 @@ QLayout::QLayout(QLayoutPrivate &dd, QLayout *lay, QWidget *w) } else { d->topLevel = true; w->d_func()->layout = this; - invalidate(); + QT_TRY { + invalidate(); + } QT_CATCH(...) { + w->d_func()->layout = 0; + QT_RETHROW; + } } } } @@ -230,7 +235,12 @@ QLayout::QLayout(QWidget *parent, int margin, int spacing, const char *name) } else { d->topLevel = true; parent->d_func()->layout = this; - invalidate(); + QT_TRY { + invalidate(); + } QT_CATCH(...) { + parent->d_func()->layout = 0; + QT_RETHROW; + } } } } diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 735fe0f..72f7732 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -146,9 +146,8 @@ public: QShortcutMap constructor. */ QShortcutMap::QShortcutMap() + : d_ptr(new QShortcutMapPrivate(this)) { - d_ptr = new QShortcutMapPrivate(this); - Q_ASSERT(d_ptr != 0); resetState(); } @@ -157,8 +156,6 @@ QShortcutMap::QShortcutMap() */ QShortcutMap::~QShortcutMap() { - delete d_ptr; - d_ptr = 0; } /*! \internal diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h index 3fe9546..28ee1f0 100644 --- a/src/gui/kernel/qshortcutmap_p.h +++ b/src/gui/kernel/qshortcutmap_p.h @@ -55,6 +55,7 @@ #include "QtGui/qkeysequence.h" #include "QtCore/qvector.h" +#include "QtCore/qscopedpointer.h" QT_BEGIN_NAMESPACE @@ -104,7 +105,7 @@ private: #ifndef QT_NO_ACTION bool correctContext(Qt::ShortcutContext context,QAction *a, QWidget *active_window) const; #endif - QShortcutMapPrivate *d_ptr; + QScopedPointer<QShortcutMapPrivate> d_ptr; QKeySequence::SequenceMatch find(QKeyEvent *e); QKeySequence::SequenceMatch matches(const QKeySequence &seq1, const QKeySequence &seq2) const; diff --git a/src/gui/kernel/qsound.cpp b/src/gui/kernel/qsound.cpp index fb152cf..8246ee3 100644 --- a/src/gui/kernel/qsound.cpp +++ b/src/gui/kernel/qsound.cpp @@ -153,6 +153,9 @@ public: \o Qt for Embedded Linux \o A built-in mixing sound server is used, accessing \c /dev/dsp directly. Only the WAVE format is supported. + \o Symbian + \o CMdaAudioPlayerUtility is used. All formats that Symbian OS or devices support + are supported also by Qt. \endtable Note that QSound does not support \l{resources.html}{resources}. diff --git a/src/gui/kernel/qsound_s60.cpp b/src/gui/kernel/qsound_s60.cpp new file mode 100644 index 0000000..00fc2fe --- /dev/null +++ b/src/gui/kernel/qsound_s60.cpp @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + + +#ifndef QT_NO_SOUND + +#include "qdir.h" +#include "qapplication.h" +#include "qsound.h" +#include "qsound_p.h" +#include "qfileinfo.h" +#include <private/qcore_symbian_p.h> + +#include <e32std.h> +#include <MdaAudioSamplePlayer.h> + +QT_BEGIN_NAMESPACE + +class QAuServerS60; + +class QAuBucketS60 : public QAuBucket, public MMdaAudioPlayerCallback +{ +public: + QAuBucketS60( QAuServerS60 *server, QSound *sound); + ~QAuBucketS60(); + + void play(); + void stop(); + + inline QSound* sound() const { return m_sound; } + +public: // from MMdaAudioPlayerCallback + void MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration); + void MapcPlayComplete(TInt aError); + +private: + QSound *m_sound; + QAuServerS60 *m_server; + bool m_prepared; + bool m_playCalled; + CMdaAudioPlayerUtility* m_playUtility; +}; + + +class QAuServerS60 : public QAuServer +{ +public: + QAuServerS60( QObject* parent ); + + void init( QSound* s ) + { + QAuBucketS60 *bucket = new QAuBucketS60( this, s ); + setBucket( s, bucket ); + } + + void play( QSound* s ) + { + bucket( s )->play(); + } + + void stop( QSound* s ) + { + bucket( s )->stop(); + } + + bool okay() { return true; } + +protected: + void playCompleted(QAuBucketS60* bucket, int error) + { + QSound *sound = bucket->sound(); + if(!error) { + // We need to handle repeats by ourselves, since with Symbian API we don't + // know how many loops have been played when user asks it + if( decLoop( sound ) ) { + play( sound ); + } + } else { + // We don't have a way to inform about errors -> just decrement loops + // in order that QSound::isFinished will return true; + while(decLoop(sound)); + } + } + +protected: + QAuBucketS60* bucket( QSound *s ) + { + return (QAuBucketS60*)QAuServer::bucket( s ); + } + + friend class QAuBucketS60; + +}; + +QAuServerS60::QAuServerS60(QObject* parent) : + QAuServer(parent) +{ + setObjectName(QLatin1String("QAuServerS60")); +} + + +QAuServer* qt_new_audio_server() +{ + return new QAuServerS60(qApp); +} + +QAuBucketS60::QAuBucketS60( QAuServerS60 *server, QSound *sound ) + : m_sound( sound ), m_server( server ), m_prepared(false), m_playCalled(false) +{ + QString filepath = QFileInfo( m_sound->fileName() ).absoluteFilePath(); + filepath = QDir::toNativeSeparators(filepath); + TPtrC filepathPtr(qt_QString2TPtrC(filepath)); + TRAPD(err, m_playUtility = CMdaAudioPlayerUtility::NewL(*this); + m_playUtility->OpenFileL(filepathPtr)); + if(err){ + m_server->playCompleted(this, err); + } +} + +void QAuBucketS60::play() +{ + if(m_prepared) { + // OpenFileL call is completed we can start playing immediately + m_playUtility->Play(); + } else { + m_playCalled = true; + } + +} + +void QAuBucketS60::stop() +{ + m_playCalled = false; + m_playUtility->Stop(); +} + +void QAuBucketS60::MapcPlayComplete(TInt aError) +{ + m_server->playCompleted(this, aError); +} + +void QAuBucketS60::MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& /*aDuration*/) +{ + if(aError) { + m_server->playCompleted(this, aError); + } else { + m_prepared = true; + if(m_playCalled){ + play(); + } + } +} + +QAuBucketS60::~QAuBucketS60() +{ + if(m_playUtility){ + m_playUtility->Stop(); + m_playUtility->Close(); + } + + delete m_playUtility; +} + + +#endif // QT_NO_SOUND + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h new file mode 100644 index 0000000..2d47a14 --- /dev/null +++ b/src/gui/kernel/qt_s60_p.h @@ -0,0 +1,285 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_S60_P_H +#define QT_S60_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 "QtGui/qwindowdefs.h" +#include "private/qcore_symbian_p.h" +#include "qhash.h" +#include "qpoint.h" +#include "QtGui/qfont.h" +#include "QtGui/qimage.h" +#include "QtGui/qevent.h" +#include "qpointer.h" +#include <w32std.h> +#include <coecntrl.h> +#include <eikenv.h> +#include <eikappui.h> +#include <aknutils.h> // AknLayoutUtils +#include <avkon.hrh> // EEikStatusPaneUidTitle +#include <akntitle.h> // CAknTitlePane +#include <akncontext.h> // CAknContextPane +#include <eikspane.h> // CEikStatusPane + +QT_BEGIN_NAMESPACE + +// Application internal HandleResourceChangeL events, +// system evens seems to start with 0x10 +const TInt KInternalStatusPaneChange = 0x50000000; + +struct QS60Data; +extern QS60Data *qt_s60Data; + +#define S60 qt_s60Data + +class QS60Data +{ +public: + TUid uid; + int screenDepth; + QPoint lastCursorPos; + QPoint lastPointerEventPos; + QPointer<QWidget> lastPointerEventTarget; + QPointer<QWidget> mousePressTarget; + int screenWidthInPixels; + int screenHeightInPixels; + int screenWidthInTwips; + int screenHeightInTwips; + int defaultDpiX; + int defaultDpiY; + static inline void updateScreenSize(); + static inline RWsSession& wsSession(); + static inline RWindowGroup& windowGroup(); + static inline CWsScreenDevice* screenDevice(); + static inline CCoeAppUi* appUi(); + static inline CEikStatusPane* statusPane(); + static inline CCoeControl* statusPaneSubPane(TInt aPaneId); + static inline CAknTitlePane* titlePane(); + static inline CAknContextPane* contextPane(); + static inline CEikButtonGroupContainer* buttonGroupContainer(); +}; + +class QAbstractLongTapObserver +{ +public: + virtual void HandleLongTapEventL( const TPoint& aPenEventLocation, + const TPoint& aPenEventScreenLocation ) = 0; +}; +class QLongTapTimer; + +class QSymbianControl : public CCoeControl, public QAbstractLongTapObserver +{ +public: + DECLARE_TYPE_ID(0x51740000) // Fun fact: the two first values are "Qt" in ASCII. + +public: + QSymbianControl(QWidget *w); + void ConstructL(bool topLevel = false, bool desktop = false); + ~QSymbianControl(); + void HandleResourceChange(int resourceType); + void HandlePointerEventL(const TPointerEvent& aPointerEvent); + TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); +#ifndef QT_NO_IM + TCoeInputCapabilities InputCapabilities() const; +#endif + TTypeUid::Ptr MopSupplyObject(TTypeUid id); + + inline QWidget* widget() const { return qwidget; }; + void setWidget(QWidget *w); + void sendInputEvent(QWidget *widget, QInputEvent *inputEvent); + void setIgnoreFocusChanged(bool enabled) { m_ignoreFocusChanged = enabled; } + void CancelLongTapTimer(); + +protected: + void Draw(const TRect& aRect) const; + void SizeChanged(); + void PositionChanged(); + void FocusChanged(TDrawNow aDrawNow); + +private: + TKeyResponse OfferKeyEvent(const TKeyEvent& aKeyEvent,TEventCode aType); + TKeyResponse sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent); + void sendMouseEvent(QWidget *widget, QMouseEvent *mEvent); + void HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ); + +private: + QWidget *qwidget; + bool m_ignoreFocusChanged; + QLongTapTimer* m_longTapDetector; + bool m_previousEventLongTap; +}; + +inline void QS60Data::updateScreenSize() +{ + TPixelsTwipsAndRotation params; + int mode = S60->screenDevice()->CurrentScreenMode(); + S60->screenDevice()->GetScreenModeSizeAndRotation(mode, params); + S60->screenWidthInPixels = params.iPixelSize.iWidth; + S60->screenHeightInPixels = params.iPixelSize.iHeight; + S60->screenWidthInTwips = params.iTwipsSize.iWidth; + S60->screenHeightInTwips = params.iTwipsSize.iHeight; + + TReal inches = S60->screenHeightInTwips / (TReal)KTwipsPerInch; + S60->defaultDpiY = S60->screenHeightInPixels / inches; + inches = S60->screenWidthInTwips / (TReal)KTwipsPerInch; + S60->defaultDpiX = S60->screenWidthInPixels / inches; +} + +inline RWsSession& QS60Data::wsSession() +{ + return CCoeEnv::Static()->WsSession(); +} + +inline RWindowGroup& QS60Data::windowGroup() +{ + return CCoeEnv::Static()->RootWin(); +} + +inline CWsScreenDevice* QS60Data::screenDevice() +{ + return CCoeEnv::Static()->ScreenDevice(); +} + +inline CCoeAppUi* QS60Data::appUi() +{ + return CCoeEnv::Static()-> AppUi(); +} + +inline CEikStatusPane* QS60Data::statusPane() +{ + return CEikonEnv::Static()->AppUiFactory()->StatusPane(); +} + +// Returns the application's status pane control, if not present returns NULL. +inline CCoeControl* QS60Data::statusPaneSubPane( TInt aPaneId ) +{ + const TUid paneUid = { aPaneId }; + CEikStatusPane* statusPane = S60->statusPane(); + if (statusPane && statusPane->PaneCapabilities(paneUid).IsPresent()) { + CCoeControl* control = NULL; + // ControlL shouldn't leave because the pane is present + TRAPD(err, control = statusPane->ControlL(paneUid)); + return err != KErrNone ? NULL : control; + } + return NULL; +} + +// Returns the application's title pane, if not present returns NULL. +inline CAknTitlePane* QS60Data::titlePane() +{ + return static_cast<CAknTitlePane*>(S60->statusPaneSubPane(EEikStatusPaneUidTitle)); +} + +// Returns the application's title pane, if not present returns NULL. +inline CAknContextPane* QS60Data::contextPane() +{ + return static_cast<CAknContextPane*>(S60->statusPaneSubPane(EEikStatusPaneUidContext)); +} + +inline CEikButtonGroupContainer* QS60Data::buttonGroupContainer() +{ + return CEikonEnv::Static()->AppUiFactory()->Cba(); +} + +static inline QFont qt_TFontSpec2QFontL(const TFontSpec &fontSpec) +{ + return QFont( + qt_TDesC2QStringL(fontSpec.iTypeface.iName), + fontSpec.iHeight / KTwipsPerPoint, + fontSpec.iFontStyle.StrokeWeight() == EStrokeWeightNormal ? QFont::Normal : QFont::Bold, + fontSpec.iFontStyle.Posture() == EPostureItalic + ); +} + +static inline QImage::Format qt_TDisplayMode2Format(TDisplayMode mode) +{ + QImage::Format format; + switch(mode) { + case EGray2: + format = QImage::Format_MonoLSB; + break; + case EColor256: + case EGray256: + format = QImage::Format_Indexed8; + break; + case EColor4K: + format = QImage::Format_RGB444; + break; + case EColor64K: + format = QImage::Format_RGB16; + break; + case EColor16M: + format = QImage::Format_RGB666; + break; + case EColor16MU: + format = QImage::Format_RGB32; + break; + case EColor16MA: + format = QImage::Format_ARGB32; + break; +#if !defined(__SERIES60_31__) && !defined(__S60_32__) + case EColor16MAP: + format = QImage::Format_ARGB32_Premultiplied; + break; +#endif + default: + format = QImage::Format_Invalid; + break; + } + return format; +} + + +QT_END_NAMESPACE + +#endif // QT_S60_P_H diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index db73c07..efd90f6 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -99,6 +99,10 @@ #endif #include <private/qpaintengine_raster_p.h> +#if defined(Q_WS_S60) +#include "private/qt_s60_p.h" +#endif + #include "qwidget_p.h" #include "qaction_p.h" #include "qlayout_p.h" @@ -209,6 +213,7 @@ QWidgetPrivate::QWidgetPrivate(int version) , window_event(0) , qd_hd(0) #endif + ,imHints(Qt::ImhNone) { if (!qApp) { qFatal("QWidget: Must construct a QApplication before a QPaintDevice"); @@ -399,6 +404,7 @@ void QWidget::setEditFocus(bool on) QApplication::sendEvent(f, &event); QApplication::sendEvent(f->style(), &event); } + f->repaint(); // Widget might want to repaint a focus indicator } #endif @@ -887,6 +893,30 @@ void QWidget::setAutoFillBackground(bool enabled) \endlist \sa QEvent, QPainter, QGridLayout, QBoxLayout + + \section1 SoftKeys + \since 4.6 + \preliminary + + Softkeys API is a platform independent way of mapping actions to (hardware)keys + and toolbars provided by the underlying platform. + + There are three major use cases supported. First one is a mobile device + with keypad navigation and no touch ui. Second use case is a mobile + device with touch ui. Third use case is desktop. For now the softkey API is + only implemented for Series60. + + QActions are set to widget(s) via softkey API. Actions in focused widget are + mapped to native toolbar or hardware keys. Even though the API allows to set + any amount of widgets there might be physical restrictions to amount of + softkeys that can be used by the device. + + \o Series60: For series60 menu button is automatically mapped to left + soft key if there is QMainWindow with QMenuBar in widgets parent hierarchy. + + \sa softKeys() + \sa setSoftKey() + */ QWidgetMapper *QWidgetPrivate::mapper = 0; // widget with wid @@ -930,6 +960,23 @@ QRegion qt_dirtyRegion(QWidget *widget) \endlist */ +struct QWidgetExceptionCleaner +{ + /* this cleans up when the constructor throws an exception */ + static inline void cleanup(QWidget *that, QWidgetPrivate *d) + { +#ifndef QT_NO_EXCEPTIONS + QWidgetPrivate::uncreatedWidgets->remove(that); + if (d->focus_next != that) { + if (d->focus_next) + d->focus_next->d_func()->focus_prev = d->focus_prev; + if (d->focus_prev) + d->focus_prev->d_func()->focus_next = d->focus_next; + } +#endif + } +}; + /*! Constructs a widget which is a child of \a parent, with widget flags set to \a f. @@ -959,7 +1006,12 @@ QRegion qt_dirtyRegion(QWidget *widget) QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, 0), QPaintDevice() { - d_func()->init(parent, f); + QT_TRY { + d_func()->init(parent, f); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } } #ifdef QT3_SUPPORT @@ -970,8 +1022,13 @@ QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) QWidget::QWidget(QWidget *parent, const char *name, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, 0), QPaintDevice() { - d_func()->init(parent , f); - setObjectName(QString::fromAscii(name)); + QT_TRY { + d_func()->init(parent , f); + setObjectName(QString::fromAscii(name)); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } } #endif @@ -980,7 +1037,13 @@ QWidget::QWidget(QWidget *parent, const char *name, Qt::WindowFlags f) QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, 0), QPaintDevice() { - d_func()->init(parent, f); + Q_D(QWidget); + QT_TRY { + d->init(parent, f); + } QT_CATCH(...) { + QWidgetExceptionCleaner::cleanup(this, d_func()); + QT_RETHROW; + } } /*! @@ -1262,7 +1325,7 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) d->create_sys(window, initializeWindow, destroyOldWindow); // a real toplevel window needs a backing store - if (isWindow()) { + if (isWindow() && windowType() != Qt::Desktop) { delete d->topData()->backingStore; // QWidgetBackingStore will check this variable, hence it must be 0 d->topData()->backingStore = 0; @@ -1930,6 +1993,9 @@ void QWidgetPrivate::setOpaque(bool opaque) #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_WS_S60 + s60UpdateIsOpaque(); +#endif } void QWidgetPrivate::updateIsTranslucent() @@ -1943,6 +2009,9 @@ void QWidgetPrivate::updateIsTranslucent() #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_WS_S60 + s60UpdateIsOpaque(); +#endif } /*! @@ -1978,11 +2047,19 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QPoin extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush); qt_mac_fill_background(painter, rgn, offset, brush); #else - const QRegion translated = rgn.translated(offset); - const QRect rect(translated.boundingRect()); - painter->setClipRegion(translated); - painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); -#endif +#if !defined(QT_NO_STYLE_S60) + // Defined in qs60style.cpp + extern bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, + const QPoint &offset, const QBrush &brush); + if (!qt_s60_fill_background(painter, rgn, offset, brush)) +#endif // !defined(QT_NO_STYLE_S60) + { + const QRegion translated = rgn.translated(offset); + const QRect rect(translated.boundingRect()); + painter->setClipRegion(translated); + painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); + } +#endif // Q_WS_MAC } else { const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) @@ -2004,6 +2081,7 @@ void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, cons painter->setCompositionMode(QPainter::CompositionMode_Source); //copy alpha straight in #endif fillRegion(painter, rgn, offset, bg); + } if (q->autoFillBackground()) @@ -2555,7 +2633,7 @@ bool QWidget::isMaximized() const */ Qt::WindowStates QWidget::windowState() const { - return (Qt::WindowStates)data->window_state; + return Qt::WindowStates(data->window_state); } /*!\internal @@ -2567,7 +2645,7 @@ Qt::WindowStates QWidget::windowState() const */ void QWidget::overrideWindowState(Qt::WindowStates newstate) { - QWindowStateChangeEvent e((Qt::WindowStates)data->window_state, true); + QWindowStateChangeEvent e(Qt::WindowStates(data->window_state), true); data->window_state = newstate; QApplication::sendEvent(this, &e); } @@ -4807,6 +4885,13 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, d->extra->inRenderWithPainter = false; } +#if !defined(Q_WS_S60) +void QWidgetPrivate::setSoftKeys_sys(const QList<QAction*> &softkeys) +{ + Q_UNUSED(softkeys) +} +#endif // !defined(Q_WS_S60) + bool QWidgetPrivate::isAboutToShow() const { if (data.in_show) @@ -4995,7 +5080,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP #ifndef QT_NO_SCROLLAREA QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(parent); if (scrollArea && scrollArea->viewport() == q) { - QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr; + QObjectData *scrollPrivate = static_cast<QWidget *>(scrollArea)->d_ptr.data(); QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(scrollPrivate); scrollAreaOffset = priv->contentsOffset(); p.translate(-scrollAreaOffset); @@ -5642,9 +5727,11 @@ bool QWidget::hasFocus() const void QWidget::setFocus(Qt::FocusReason reason) { + Q_D(QWidget); + if (!isEnabled()) return; - + QWidget *f = this; while (f->d_func()->extra && f->d_func()->extra->focus_proxy) f = f->d_func()->extra->focus_proxy; @@ -6700,7 +6787,7 @@ void QWidgetPrivate::show_helper() // On Windows, show the popup now so that our own focus handling // stores the correct old focus widget even if it's stolen in the // showevent -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) if (!isEmbedded && q->windowType() == Qt::Popup) qApp->d_func()->openPopup(q); #endif @@ -6717,7 +6804,7 @@ void QWidgetPrivate::show_helper() show_sys(); -#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) if (!isEmbedded && q->windowType() == Qt::Popup) qApp->d_func()->openPopup(q); #endif @@ -7287,7 +7374,7 @@ QSize QWidgetPrivate::adjustedSize() const #else // all others QRect screen = QApplication::desktop()->screenGeometry(q->pos()); #endif -#if defined (Q_WS_WINCE) +#if defined (Q_WS_WINCE) || defined (Q_OS_SYMBIAN) s.setWidth(qMin(s.width(), screen.width())); s.setHeight(qMin(s.height(), screen.height())); #else @@ -7595,6 +7682,7 @@ bool QWidget::event(QEvent *event) } break; case QEvent::FocusIn: + d->setSoftKeys_sys(softKeys()); focusInEvent((QFocusEvent*)event); break; @@ -7744,6 +7832,10 @@ bool QWidget::event(QEvent *event) if (w && w->isVisible() && !w->isWindow()) QApplication::sendEvent(w, event); } + + if (isWindow() && isActiveWindow()) + d->setSoftKeys_sys(softKeys()); + break; } case QEvent::LanguageChange: @@ -8419,7 +8511,7 @@ void QWidget::inputMethodEvent(QInputMethodEvent *event) \a query specifies which property is queried. - \sa inputMethodEvent(), QInputMethodEvent, QInputContext + \sa inputMethodEvent(), QInputMethodEvent, QInputContext, inputMethodHints */ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const { @@ -8428,11 +8520,54 @@ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const return QRect(width()/2, 0, 1, height()); case Qt::ImFont: return font(); + case Qt::ImAnchorPosition: + // Fallback. + return inputMethodQuery(Qt::ImCursorPosition); default: return QVariant(); } } +/*! + \property QWidget::inputMethodHints + \brief What input method specific hints the widget has. + + This is only relevant for input widgets. It is used by + the input method to retrieve hints as to how the input method + should operate. For example, if the Qt::ImhFormattedNumbersOnly flag + is set, the input method may change its visual components to reflect + that only numbers can be entered. + + \note The flags are only hints, so the particular input method + implementation is free to ignore them. If you want to be + sure that a certain type of characters are entered, + you should also set a QValidator on the widget. + + The default value is Qt::ImhNone. + + \since 4.6 + + \sa inputMethodQuery(), QInputContext +*/ +Qt::InputMethodHints QWidget::inputMethodHints() const +{ + Q_D(const QWidget); + return d->imHints; +} + +void QWidget::setInputMethodHints(Qt::InputMethodHints hints) +{ + Q_D(QWidget); + d->imHints = hints; + // Optimisation to update input context only it has already been created. + if (d->ic || qApp->d_func()->inputContext) { + QInputContext *ic = inputContext(); + if (ic) + ic->update(); + } +} + + #ifndef QT_NO_DRAGANDDROP /*! @@ -10236,7 +10371,7 @@ void QWidget::setShortcutAutoRepeat(int id, bool enable) */ void QWidget::updateMicroFocus() { -#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS)) +#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60)) Q_D(QWidget); // and optimisation to update input context only it has already been created. if (d->ic || qApp->d_func()->inputContext) { @@ -11370,6 +11505,68 @@ void QWidget::clearMask() setMask(QRegion()); } +/*! + \preliminary + \since 4.6 + + Returns the (possibly empty) list of this widget's softkeys. + Returned list cannot be changed. Softkeys should be added + and removed via method called setSoftKeys + + \sa setSoftKey(), setSoftKeys() +*/ +const QList<QAction*>& QWidget::softKeys() const +{ + Q_D(const QWidget); + if( d->softKeys.count() > 0) + return d->softKeys; + if (isWindow() || !parentWidget()) + return d->softKeys; + + return parentWidget()->softKeys(); +} + +/*! + \preliminary + \since 4.6 + + Sets the softkey \a softkey to this widget's list of softkeys, + Setting 0 as softkey will clear all the existing softkeys set + to the widget + A QWidget can have 0 or more softkeys + + \sa softKeys(), setSoftKeys() +*/ +void QWidget::setSoftKey(QAction *softKey) +{ + Q_D(QWidget); + qDeleteAll(d->softKeys); + d->softKeys.clear(); + if (softKey) + d->softKeys.append(softKey); + if ((!QApplication::focusWidget() && this == QApplication::activeWindow()) + || QApplication::focusWidget() == this) + d->setSoftKeys_sys(this->softKeys()); +} + +/*! + Sets the list of softkeys \a softkeys to this widget's list of softkeys, + A QWidget can have 0 or more softkeys + + \sa softKeys(), setSoftKey() +*/ +void QWidget::setSoftKeys(const QList<QAction*> &softKeys) +{ + Q_D(QWidget); + qDeleteAll(d->softKeys); + d->softKeys.clear(); + d->softKeys = softKeys; + + if ((!QApplication::focusWidget() && this == QApplication::activeWindow()) + || QApplication::focusWidget() == this) + d->setSoftKeys_sys(this->softKeys()); +} + /*! \fn const QX11Info &QWidget::x11Info() const Returns information about the configuration of the X display used to display the widget. diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index 6703d26..cd56149 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -212,6 +212,7 @@ class Q_GUI_EXPORT QWidget : public QObject, public QPaintDevice #endif Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET unsetLocale) Q_PROPERTY(QString windowFilePath READ windowFilePath WRITE setWindowFilePath DESIGNABLE isWindow) + Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints) public: enum RenderFlag { @@ -554,6 +555,9 @@ public: void removeAction(QAction *action); QList<QAction*> actions() const; #endif + const QList<QAction*>& softKeys() const; + void setSoftKey(QAction *softKey); + void setSoftKeys(const QList<QAction*> &softKeys); QWidget *parentWidget() const; @@ -674,6 +678,10 @@ protected: virtual void inputMethodEvent(QInputMethodEvent *); public: virtual QVariant inputMethodQuery(Qt::InputMethodQuery) const; + + Qt::InputMethodHints inputMethodHints() const; + void setInputMethodHints(Qt::InputMethodHints hints); + protected: void resetInputContext(); protected Q_SLOTS: @@ -724,6 +732,7 @@ private: friend class QGraphicsProxyWidget; friend class QGraphicsProxyWidgetPrivate; friend class QStyleSheetStyle; + friend struct QWidgetExceptionCleaner; #ifdef Q_WS_MAC friend class QCoreGraphicsPaintEnginePrivate; @@ -745,6 +754,10 @@ private: friend bool isWidgetOpaque(const QWidget *); friend class QGLWidgetPrivate; #endif +#ifdef Q_WS_S60 + friend class QSymbianControl; + friend class QS60WindowSurface; +#endif #ifdef Q_WS_X11 friend void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp); friend void qt_net_remove_user_time(QWidget *tlw); diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index f5a8c5f..63105b3 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -1223,7 +1223,7 @@ OSStatus QWidgetPrivate::qt_widget_event(EventHandlerCallRef er, EventRef event, QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget->parent()); QPoint scrollAreaOffset; if (scrollArea && scrollArea->viewport() == widget) { - QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(static_cast<QWidget *>(scrollArea)->d_ptr); + QAbstractScrollAreaPrivate *priv = static_cast<QAbstractScrollAreaPrivate *>(static_cast<QWidget *>(scrollArea)->d_ptr.data()); scrollAreaOffset = priv->contentsOffset(); p.translate(-scrollAreaOffset); } diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 2bc4da6..527e331 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -79,6 +79,16 @@ #include "QtGui/qscreen_qws.h" #endif +#if defined(Q_WS_S60) +class RDrawableWindow; +class CCoeControl; +class CAknTitlePane; +class CAknContextPane; +// The following 2 defines may only be needed for s60. To be seen. +const int SOFTKEYSTART=5000; +const int SOFTKEYEND=5004; +#endif + QT_BEGIN_NAMESPACE // Extra QWidget data @@ -161,6 +171,9 @@ struct QTLWExtra { #ifndef QT_NO_QWS_MANAGER QWSManager *qwsManager; #endif +#elif defined(Q_WS_S60) // <--------------------------------------------------------- SYMBIAN + uint activated : 1; // RWindowBase::Activated has been called + RDrawableWindow *rwindow; #endif }; @@ -242,6 +255,7 @@ public: explicit QWidgetPrivate(int version = QObjectPrivateVersion); ~QWidgetPrivate(); + void setSoftKeys_sys(const QList<QAction*> &softkeys); QWExtra *extraData() const; QTLWExtra *topData() const; QTLWExtra *maybeTopData() const; @@ -268,6 +282,10 @@ public: QPalette naturalWidgetPalette(uint inheritedMask) const; void setMask_sys(const QRegion &); +#ifdef Q_WS_S60 + void s60UpdateIsOpaque(); +#endif + void raise_sys(); void lower_sys(); void stackUnder_sys(QWidget *); @@ -466,6 +484,7 @@ public: QWidget *focus_next; QWidget *focus_prev; QWidget *focus_child; + QList<QAction*> softKeys; QLayout *layout; QRegion *needsFlush; QPaintDevice *redirectDev; @@ -478,6 +497,7 @@ public: static QWidgetSet *uncreatedWidgets; #if !defined(QT_NO_IM) QPointer<QInputContext> ic; + Qt::InputMethodHints imHints; #endif #ifdef QT_KEYPAD_NAVIGATION static QPointer<QWidget> editingWidget; @@ -635,7 +655,11 @@ public: void updateCursor() const; #endif QScreen* getScreen() const; +#elif defined(Q_WS_S60) // <--------------------------------------------------------- SYMBIAN + static QWidget *mouseGrabber; + static QWidget *keyboardGrabber; #endif + }; inline QWExtra *QWidgetPrivate::extraData() const diff --git a/src/gui/kernel/qwidget_qws.cpp b/src/gui/kernel/qwidget_qws.cpp index 94bdb85..40fce4a 100644 --- a/src/gui/kernel/qwidget_qws.cpp +++ b/src/gui/kernel/qwidget_qws.cpp @@ -638,7 +638,8 @@ void QWidgetPrivate::hide_sys() q->releaseMouse(); // requestWindowRegion(QRegion()); - extra->topextra->backingStore->releaseBuffer(); + if (extra->topextra->backingStore) + extra->topextra->backingStore->releaseBuffer(); QWidget::qwsDisplay()->requestFocus(data.winid,false); diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp new file mode 100644 index 0000000..6109f17 --- /dev/null +++ b/src/gui/kernel/qwidget_s60.cpp @@ -0,0 +1,1094 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwidget_p.h" +#include "qdesktopwidget.h" +#include "qapplication.h" +#include "qapplication_p.h" +#include "private/qbackingstore_p.h" +#include "qevent.h" +#include "qt_s60_p.h" + +#include "qbitmap.h" +#include "private/qwindowsurface_s60_p.h" + +#include <qinputcontext.h> + +#include <aknappui.h> + +QT_BEGIN_NAMESPACE + +extern bool qt_nograb(); + +QWidget *QWidgetPrivate::mouseGrabber = 0; +QWidget *QWidgetPrivate::keyboardGrabber = 0; + +static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b) +{ + if ( a.count() != b.count()) + return false; + int index=0; + while (index<a.count()) { + if (a.at(index)->softKeyRole() != b.at(index)->softKeyRole()) + return false; + if (a.at(index)->text().compare(b.at(index)->text())!=0) + return false; + index++; + } + return true; +} + + +void QWidgetPrivate::setSoftKeys_sys(const QList<QAction*> &softkeys) +{ + Q_Q(QWidget); + if (QApplication::focusWidget() && q!=QApplication::focusWidget()) { + QList<QAction *> old = QApplication::focusWidget()->softKeys(); + if (isEqual(old, softkeys )) + return; + } + CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); + nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS); + + int position = -1; + int command; + bool needsExitButton = true; + + for (int index = 0; index < softkeys.count(); index++) { + const QAction* softKeyAction = softkeys.at(index); + switch (softKeyAction->softKeyRole()) { + // Positive Actions go on LSK + case QAction::OptionsSoftKey: + case QAction::MenuSoftKey: + case QAction::ContextMenuSoftKey: + command = EAknSoftkeyOptions; //Calls DynInitMenuPane in AppUI + position = 0; + break; + case QAction::SelectSoftKey: + case QAction::PreviousSoftKey: + case QAction::OkSoftKey: + case QAction::EditSoftKey: + case QAction::ViewSoftKey: + case QAction::EndEditSoftKey: + case QAction::FinishSoftKey: + command = SOFTKEYSTART + index; + position = 0; + break; + // Negative Actions on the RSK + case QAction::BackSoftKey: + case QAction::NextSoftKey: + case QAction::CancelSoftKey: + case QAction::BackSpaceSoftKey: + case QAction::RevertEditSoftKey: + case QAction::DeselectSoftKey: + needsExitButton = false; + command = SOFTKEYSTART + index; + position = 2; + break; + case QAction::ExitSoftKey: + needsExitButton = false; + command = EAknSoftkeyExit; //Calls HandleCommand in AppUI + position = 2; + break; + default: + break; + } + + if (position != -1) { + TPtrC text = qt_QString2TPtrC(softKeyAction->text()); + nativeContainer->SetCommandL(position, command, text); + } + } + + if (needsExitButton) + nativeContainer->SetCommandL(2, EAknSoftkeyExit, qt_QString2TPtrC(QObject::tr("Exit"))); + + nativeContainer->DrawDeferred(); // 3.1 needs an extra invitation +} + +void QWidgetPrivate::setWSGeometry(bool dontShow) +{ + +} + +void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + if ((q->windowType() == Qt::Desktop)) + return; + if (extra) { // any size restrictions? + w = qMin(w,extra->maxw); + h = qMin(h,extra->maxh); + w = qMax(w,extra->minw); + h = qMax(h,extra->minh); + } + + if (q->isWindow()) + topData()->normalGeometry = QRect(0, 0, -1, -1); + else { + uint s = data.window_state; + s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen); + data.window_state = s; + } + + QPoint oldPos(q->pos()); + QSize oldSize(q->size()); + QRect oldGeom(data.crect); + + bool isResize = w != oldSize.width() || h != oldSize.height(); + if (!isMove && !isResize) + return; + + if (isResize) + data.window_state &= ~Qt::WindowMaximized; + + if(q->isWindow()) { + if (w == 0 || h == 0) { + q->setAttribute(Qt::WA_OutsideWSRange, true); + if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) + hide_sys(); + data.crect = QRect(x, y, w, h); + data.window_state &= ~Qt::WindowFullScreen; + } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) { + q->setAttribute(Qt::WA_OutsideWSRange, false); + + // put the window in its place and show it + q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); + data.crect.setRect(x, y, w, h); + + show_sys(); + } else { + QRect r = QRect(x, y, w, h); + data.crect = r; + q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); + topData()->normalGeometry = data.crect; + } + } else { + data.crect.setRect(x, y, w, h); + + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false; + + if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) { + // Top-level resize optimization does not work for native child widgets; + // disable it for this particular widget. + if (inTopLevelResize) + tlwExtra->inTopLevelResize = false; + if (!isResize && maybeBackingStore()) + moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y()); + else + invalidateBuffer_resizeHelper(oldPos, oldSize); + + if (inTopLevelResize) + tlwExtra->inTopLevelResize = true; + } + if (q->testAttribute(Qt::WA_WState_Created)) + setWSGeometry(); + } + + if (q->isVisible()) { + if (isMove && q->pos() != oldPos) { + QMoveEvent e(q->pos(), oldPos); + QApplication::sendEvent(q, &e); + } + if (isResize) { + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra + && !extra->topextra->inTopLevelResize; + if (setTopLevelResize) + extra->topextra->inTopLevelResize = true; + QResizeEvent e(q->size(), oldSize); + QApplication::sendEvent(q, &e); + if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId()) + q->internalWinId()->DrawDeferred(); + if (setTopLevelResize) + extra->topextra->inTopLevelResize = false; + } + } else { + if (isMove && q->pos() != oldPos) + q->setAttribute(Qt::WA_PendingMoveEvent, true); + if (isResize) + q->setAttribute(Qt::WA_PendingResizeEvent, true); + } +} + +void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) +{ + Q_Q(QWidget); + + Qt::WindowType type = q->windowType(); + Qt::WindowFlags &flags = data.window_flags; + QWidget *parentWidget = q->parentWidget(); + + bool topLevel = (flags & Qt::Window); + bool popup = (type == Qt::Popup); + bool dialog = (type == Qt::Dialog + || type == Qt::Sheet + || (flags & Qt::MSWindowsFixedSizeDialogHint)); + bool desktop = (type == Qt::Desktop); + bool tool = (type == Qt::Tool || type == Qt::Drawer); + + WId id = 0; + + if (popup) + flags |= Qt::WindowStaysOnTopHint; // a popup stays on top + + // always initialize + if (!window) + initializeWindow = true; + + TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + int sw = clientRect.Width(); + int sh = clientRect.Height(); + + if (desktop) { + TSize screenSize = S60->screenDevice()->SizeInPixels(); + data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight); + q->setAttribute(Qt::WA_DontShowOnScreen); + } else if(topLevel && !q->testAttribute(Qt::WA_Resized)){ + int width = sw; + int height = sh; + if (extra) { + width = qMax(qMin(width, extra->maxw), extra->minw); + height = qMax(qMin(height, extra->maxh), extra->minh); + } + data.crect.setSize(QSize(width, height)); + } + + CCoeControl *destroyw = 0; + + if(window) { + if (destroyOldWindow) + destroyw = data.winid; + id = window; + setWinId(window); + TRect tr = window->Rect(); + data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); + + } else if (topLevel) { + if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen)) + data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY)); + QSymbianControl *control= new QSymbianControl(q); + control->ConstructL(true,desktop); + if (!desktop) { + QTLWExtra *topExtra = topData(); + topExtra->rwindow = control->DrawableWindow(); + // Request mouse move events. + topExtra->rwindow->PointerFilter(EPointerFilterEnterExit + | EPointerFilterMove | EPointerFilterDrag, 0); + topExtra->rwindow->EnableVisibilityChangeEvents(); + + if (!isOpaque) { + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); + if (rwindow->SetTransparencyAlphaChannel() == KErrNone) + rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } + } + + + id = (WId)control; + + setWinId(id); + + q->setAttribute(Qt::WA_WState_Created); + + int x, y, w, h; + data.crect.getRect(&x, &y, &w, &h); + control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget + QSymbianControl *control = new QSymbianControl(q); + control->ConstructL(!parentWidget); + setWinId(control); + WId parentw = parentWidget->effectiveWinId(); + control->SetContainerWindowL(*parentw); + + q->setAttribute(Qt::WA_WState_Created); + int x, y, w, h; + data.crect.getRect(&x, &y, &w, &h); + control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + } + + if (destroyw) { + destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); + CBase::Delete(destroyw); + } +} + + +void QWidgetPrivate::show_sys() +{ + Q_Q(QWidget); + + if (q->testAttribute(Qt::WA_OutsideWSRange)) + return; + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + q->setAttribute(Qt::WA_Mapped); + + if (q->testAttribute(Qt::WA_DontShowOnScreen)) { + invalidateBuffer(q->rect()); + return; + } + + if (q->isWindow() && q->internalWinId()) { + + WId id = q->internalWinId(); + if (!extra->topextra->activated) { + id->ActivateL(); + extra->topextra->activated = 1; + } + TInt stackingFlags; + if ((q->windowType() & Qt::Popup) == Qt::Popup) { + stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; + } else { + stackingFlags = ECoeStackFlagStandard; + } + id->ControlEnv()->AppUi()->AddToStackL(id, ECoeStackPriorityDefault, stackingFlags); + id->MakeVisible(true); + + // Force setting of the icon after window is made visible, + // this is needed even WA_SetWindowIcon is not set, as in that case we need + // to reset to the application level window icon + setWindowIcon_sys(true); + } + + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::hide_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + deactivateWidgetCleanup(); + WId id = q->internalWinId(); + if (q->isWindow() && id) { + if(id->IsFocused()) // Avoid unnecessry calls to FocusChanged() + id->SetFocus(false); + id->MakeVisible(false); + id->ControlEnv()->AppUi()->RemoveFromStack(id); + if (QWidgetBackingStore *bs = maybeBackingStore()) + bs->releaseBuffer(); + } else { + invalidateBuffer(q->rect()); + } + + q->setAttribute(Qt::WA_Mapped, false); +} + +void QWidgetPrivate::setFocus_sys() +{ + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup) + if(!q->effectiveWinId()->IsFocused()) // Avoid unnecessry calls to FocusChanged() + q->effectiveWinId()->SetFocus(true); +} + +void QWidgetPrivate::raise_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + if (q->internalWinId() && tlwExtra) { + tlwExtra->rwindow->SetOrdinalPosition(0); + } +} + +void QWidgetPrivate::lower_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + if (q->internalWinId() && tlwExtra) { + tlwExtra->rwindow->SetOrdinalPosition(-1); + } + if(!q->isWindow()) + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::setModal_sys() +{ + +} + +void QWidgetPrivate::stackUnder_sys(QWidget* w) +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + QTLWExtra *tlwExtraSibling = w->d_func()->maybeTopData(); + if (q->internalWinId() && tlwExtra && w->internalWinId() && tlwExtraSibling) + tlwExtra->rwindow->SetOrdinalPosition(tlwExtraSibling->rwindow->OrdinalPosition() + 1); + if(!q->isWindow() || !w->internalWinId()) + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::reparentChildren() +{ + Q_Q(QWidget); + QObjectList chlist = q->children(); + for (int i = 0; i < chlist.size(); ++i) { // reparent children + QObject *obj = chlist.at(i); + if (obj->isWidgetType()) { + QWidget *w = (QWidget *)obj; + if (!w->testAttribute(Qt::WA_WState_Created)) + continue; + if (!w->isWindow()) { + w->d_func()->invalidateBuffer(w->rect()); + WId parent = q->effectiveWinId(); + WId child = w->effectiveWinId(); + if (parent != child) + child->SetParent(parent); + // ### TODO: We probably also need to update the component array here + w->d_func()->reparentChildren(); + } else { + bool showIt = w->isVisible(); + QPoint old_pos = w->pos(); + w->setParent(q, w->windowFlags()); + w->move(old_pos); + if (showIt) + w->show(); + } + } + } +} + +void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) +{ + Q_Q(QWidget); + bool wasCreated = q->testAttribute(Qt::WA_WState_Created); + + if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) + q->parentWidget()->d_func()->invalidateBuffer(q->geometry()); + + if (q->testAttribute(Qt::WA_DropSiteRegistered)) + q->setAttribute(Qt::WA_DropSiteRegistered, false); + + WId old_winid = wasCreated ? data.winid : 0; + if ((q->windowType() == Qt::Desktop)) + old_winid = 0; + setWinId(0); + + // hide and reparent our own window away. Otherwise we might get + // destroyed when emitting the child remove event below. See QWorkspace. + if (wasCreated && old_winid) { + old_winid->MakeVisible(false); + old_winid->ControlEnv()->AppUi()->RemoveFromStack(old_winid); + old_winid->SetParent(0); + } + + QObjectPrivate::setParent_helper(parent); + bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); + + data.window_flags = f; + data.fstrut_dirty = true; + q->setAttribute(Qt::WA_WState_Created, false); + q->setAttribute(Qt::WA_WState_Visible, false); + q->setAttribute(Qt::WA_WState_Hidden, false); + adjustFlags(data.window_flags, q); + // keep compatibility with previous versions, we need to preserve the created state + // (but we recreate the winId for the widget being reparented, again for compatibility) + if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created))) + createWinId(); + if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden) + q->setAttribute(Qt::WA_WState_Hidden); + q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden); + + if (wasCreated) + reparentChildren(); + + if (old_winid) { + CBase::Delete(old_winid); + } + + if (q->testAttribute(Qt::WA_AcceptDrops) + || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) + q->setAttribute(Qt::WA_DropSiteRegistered, true); + + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::setConstraints_sys() +{ + +} + + +void QWidgetPrivate::s60UpdateIsOpaque() +{ + Q_Q(QWidget); + + if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground)) + return; + + if ((data.window_flags & Qt::FramelessWindowHint) == 0) + return; + + if (!isOpaque) { + QTLWExtra *topExtra = topData(); + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); + if (rwindow->SetTransparencyAlphaChannel() == KErrNone) + rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } else { + QTLWExtra *topExtra = topData(); + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + rwindow->SetTransparentRegion(TRegionFix<1>()); + } +} + +CFbsBitmap* qt_pixmapToNativeBitmapL(QPixmap pixmap, bool invert) +{ + CFbsBitmap* fbsBitmap = new(ELeave)CFbsBitmap; + TSize size(pixmap.size().width(), pixmap.size().height()); + TDisplayMode mode(EColor16MU); + + bool isNull = pixmap.isNull(); + int depth = pixmap.depth(); + + // TODO: dummy assumptions from bit amounts for each color + // Will fix later on when native pixmap is implemented + switch(pixmap.depth()) { + case 1: + mode = EGray2; + break; + case 4: + mode = EColor16; + break; + case 8: + mode = EColor256; + break; + case 12: + mode = EColor4K; + break; + case 16: + mode = EColor64K; + break; + case 24: + mode = EColor16M; + break; + case 32: + case EColor16MU: + break; + default: + qFatal("Unsupported pixmap depth"); + break; + } + + User::LeaveIfError(fbsBitmap->Create(size, mode)); + fbsBitmap->LockHeap(); + QImage image = pixmap.toImage(); + + if(invert) + image.invertPixels(); + + int height = pixmap.size().height(); + for(int i=0;i<height;i++ ) + { + TPtr8 scanline(image.scanLine(i), image.bytesPerLine(), image.bytesPerLine()); + fbsBitmap->SetScanLine( scanline, i ); + } + + fbsBitmap->UnlockHeap(); + return fbsBitmap; +} + +void QWidgetPrivate::setWindowIcon_sys(bool forceReset) +{ + Q_Q(QWidget); + + if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() ) + return; + + QTLWExtra* topData = this->topData(); + if (topData->iconPixmap && !forceReset) + // already been set + return; + + TRect cPaneRect; + TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect ); + CAknContextPane* contextPane = S60->contextPane(); + if( found && contextPane ) { // We have context pane with valid metrics + QIcon icon = q->windowIcon(); + if (!icon.isNull()) { + // Valid icon -> set it as an context pane picture + QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight)); + QPixmap pm = icon.pixmap(size); + QBitmap mask = pm.mask(); + if (mask.isNull()) { + mask = QBitmap(pm.size()); + mask.fill(Qt::color1); + } + + // Convert to CFbsBitmp + // TODO: When QPixmap is adapted to use native CFbsBitmap, + // it could be set directly to context pane + CFbsBitmap* nBitmap = qt_pixmapToNativeBitmapL(pm, false); + CFbsBitmap* nMask = qt_pixmapToNativeBitmapL(mask, true); + + contextPane->SetPicture(nBitmap,nMask); + } else { + // Icon set to null -> set context pane picture to default + contextPane->SetPictureToDefaultL(); + } + } +} + +void QWidgetPrivate::setWindowTitle_sys(const QString &caption) +{ + Q_Q(QWidget); + if(q->isWindow()) { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + CAknTitlePane* titlePane = S60->titlePane(); + if(titlePane) + titlePane->SetTextL(qt_QString2TPtrC(caption)); + } +} + +void QWidgetPrivate::setWindowIconText_sys(const QString &iconText) +{ + +} + +void QWidgetPrivate::scroll_sys(int dx, int dy) +{ + Q_Q(QWidget); + + scrollChildren(dx, dy); + if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) { + scrollRect(q->rect(), dx, dy); + } else { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + RDrawableWindow* rw = topData()->rwindow; + rw->Scroll(TPoint(dx, dy)); + } +} + +void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) +{ + Q_Q(QWidget); + + if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) { + scrollRect(r, dx, dy); + } else { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + RDrawableWindow* rw = topData()->rwindow; + rw->Scroll(TPoint(dx, dy), qt_QRect2TRect(r)); + } +} + +/*! + For this function to work in the emulator, you must add: + TRANSPARENCY + To a line in the wsini.ini file. +*/ +void QWidgetPrivate::setWindowOpacity_sys(qreal) +{ + // ### TODO: Implement uniform window transparency +} + +void QWidgetPrivate::updateFrameStrut() +{ + +} + +void QWidgetPrivate::updateSystemBackground() +{ + +} + +void QWidgetPrivate::registerDropSite(bool on) +{ + +} + +void QWidgetPrivate::createTLSysExtra() +{ + extra->topextra->backingStore = 0; + extra->topextra->activated = 0; + extra->topextra->rwindow = 0; +} + +void QWidgetPrivate::deleteTLSysExtra() +{ + delete extra->topextra->backingStore; + extra->topextra->backingStore = 0; +} + +void QWidgetPrivate::createSysExtra() +{ + +} + +void QWidgetPrivate::deleteSysExtra() +{ + +} + +QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() +{ + return new QS60WindowSurface(q_func()); +} + +void QWidgetPrivate::setMask_sys(const QRegion& region) +{ + +} + +int QWidget::metric(PaintDeviceMetric m) const +{ + Q_D(const QWidget); + int val; + if (m == PdmWidth) { + val = data->crect.width(); + } else if (m == PdmHeight) { + val = data->crect.height(); + } else { + CWsScreenDevice *scr = S60->screenDevice(); + switch(m) { + case PdmDpiX: + case PdmPhysicalDpiX: + if (d->extra && d->extra->customDpiX) { + val = d->extra->customDpiX; + } else { + const QWidgetPrivate *p = d; + while (p->parent) { + p = static_cast<const QWidget *>(p->parent)->d_func(); + if (p->extra && p->extra->customDpiX) { + val = p->extra->customDpiX; + break; + } + } + if (p == d || !(p->extra && p->extra->customDpiX)) + val = S60->defaultDpiX; + } + break; + case PdmDpiY: + case PdmPhysicalDpiY: + if (d->extra && d->extra->customDpiY) { + val = d->extra->customDpiY; + } else { + const QWidgetPrivate *p = d; + while (p->parent) { + p = static_cast<const QWidget *>(p->parent)->d_func(); + if (p->extra && p->extra->customDpiY) { + val = p->extra->customDpiY; + break; + } + } + if (p == d || !(p->extra && p->extra->customDpiY)) + val = S60->defaultDpiY; + } + break; + case PdmWidthMM: + { + TInt twips = scr->HorizontalPixelsToTwips(data->crect.width()); + val = (int)(twips * (25.4/KTwipsPerInch)); + break; + } + case PdmHeightMM: + { + TInt twips = scr->VerticalPixelsToTwips(data->crect.height()); + val = (int)(twips * (25.4/KTwipsPerInch)); + break; + } + case PdmNumColors: + val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode()); + break; + case PdmDepth: + val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode()); + break; + default: + val = 0; + qWarning("QWidget::metric: Invalid metric command"); + } + } + return val; +} + +QPaintEngine *QWidget::paintEngine() const +{ + return 0; +} + +QPoint QWidget::mapToGlobal(const QPoint &pos) const +{ + Q_D(const QWidget); + if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) { + + QPoint p = pos + data->crect.topLeft(); + return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p); + + } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel + QPoint tp = geometry().topLeft(); + return pos + tp; + } + + // This is the native window case. Consider using CCoeControl::PositionRelativeToScreen() + // if we decide to go with CCoeControl + return QPoint(); +} + +QPoint QWidget::mapFromGlobal(const QPoint &pos) const +{ + Q_D(const QWidget); + if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) { + QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos); + return p - data->crect.topLeft(); + } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel + QPoint tp = geometry().topLeft(); + return pos - tp; + } + + // ### TODO native window + return QPoint(); +} + +void QWidget::setWindowState(Qt::WindowStates newstate) +{ + Q_D(QWidget); + Qt::WindowStates oldstate = windowState(); + if (oldstate == newstate) + return; + + if (isWindow()) { + createWinId(); + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + QTLWExtra *top = d->topData(); + + // Ensure the initial size is valid, since we store it as normalGeometry below. + if (!testAttribute(Qt::WA_Resized) && !isVisible()) + adjustSize(); + + if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) { + if ((newstate & Qt::WindowMaximized)) { + const QRect normalGeometry = geometry(); + + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->availableGeometry(this)); + top->normalGeometry = r; + + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } else { + // restore original geometry + setGeometry(top->normalGeometry); + } + } + if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) { + CEikStatusPane* statusPane = S60->statusPane(); + CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer(); + if (newstate & Qt::WindowFullScreen) { + const QRect normalGeometry = geometry(); + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->screenGeometry(this)); + if (statusPane) + statusPane->MakeVisible(false); + if (buttonGroup) + buttonGroup->MakeVisible(false); + top->normalGeometry = r; + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } else { + if (statusPane) + statusPane->MakeVisible(true); + if (buttonGroup) + buttonGroup->MakeVisible(true); + if (newstate & Qt::WindowMaximized) { + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->availableGeometry(this)); + top->normalGeometry = r; + } else { + setGeometry(top->normalGeometry); + } + } + } + if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) { + if (newstate & Qt::WindowMinimized) { + if (isVisible()) { + WId id = effectiveWinId(); + id->MakeVisible(false); + id->ControlEnv()->AppUi()->RemoveFromStack(id); + } + } else { + if (isVisible()) { + WId id = effectiveWinId(); + id->MakeVisible(true); + id->ControlEnv()->AppUi()->AddToStackL(id); + } + const QRect normalGeometry = geometry(); + const QRect r = top->normalGeometry; + top->normalGeometry = r; + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } + } + } + + data->window_state = newstate; + + if (newstate & Qt::WindowActive) + activateWindow(); + + QWindowStateChangeEvent e(oldstate); + QApplication::sendEvent(this, &e); +} + + +void QWidget::destroy(bool destroyWindow, bool destroySubWindows) +{ + Q_D(QWidget); + if (!isWindow() && parentWidget()) + parentWidget()->d_func()->invalidateBuffer(geometry()); + d->deactivateWidgetCleanup(); + if (testAttribute(Qt::WA_WState_Created)) { + +#ifndef QT_NO_IM + if (d->ic) { + delete d->ic; + } else { + QInputContext *ic = inputContext(); + if (ic) { + ic->widgetDestroyed(this); + } + } +#endif + + setAttribute(Qt::WA_WState_Created, false); + QObjectList childList = children(); + for (int i = 0; i < childList.size(); ++i) { // destroy all widget children + register QObject *obj = childList.at(i); + if (obj->isWidgetType()) + static_cast<QWidget*>(obj)->destroy(destroySubWindows, + destroySubWindows); + } + if (QWidgetPrivate::mouseGrabber == this) + releaseMouse(); + if (QWidgetPrivate::keyboardGrabber == this) + releaseKeyboard(); + if (destroyWindow && !(windowType() == Qt::Desktop) && internalWinId()) { + WId id = internalWinId(); + if(id->IsFocused()) // Avoid unnecessry calls to FocusChanged() + id->SetFocus(false); + id->ControlEnv()->AppUi()->RemoveFromStack(id); + CBase::Delete(id); + + // Hack to activate window under destroyed one. With this activation + // the next visible window will get keyboard focus + WId wid = CEikonEnv::Static()->AppUi()->TopFocusedControl(); + if (wid) { + QWidget *widget = QWidget::find(wid); + QApplication::setActiveWindow(widget); + } + + } + + d->setWinId(0); + } +} + +QWidget *QWidget::mouseGrabber() +{ + return QWidgetPrivate::mouseGrabber; +} + +QWidget *QWidget::keyboardGrabber() +{ + return QWidgetPrivate::keyboardGrabber; +} + +void QWidget::grabKeyboard() +{ + if (!qt_nograb()) { + if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this) + QWidgetPrivate::keyboardGrabber->releaseKeyboard(); + + // ### TODO: Native keyboard grab + + QWidgetPrivate::keyboardGrabber = this; + } +} + +void QWidget::releaseKeyboard() +{ + if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) { + // ### TODO: Native keyboard release + QWidgetPrivate::keyboardGrabber = 0; + } +} + +void QWidget::grabMouse() +{ + if (!qt_nograb()) { + if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this) + QWidgetPrivate::mouseGrabber->releaseMouse(); + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + WId id = effectiveWinId(); + id->SetPointerCapture(true); + QWidgetPrivate::mouseGrabber = this; + } +} + +void QWidget::releaseMouse() +{ + if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) { + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + WId id = effectiveWinId(); + id->SetPointerCapture(false); + QWidgetPrivate::mouseGrabber = 0; + } +} + +void QWidget::activateWindow() +{ + Q_D(QWidget); + QWidget *tlw = window(); + if (tlw->isVisible()) { + S60->windowGroup().SetOrdinalPosition(0); + window()->createWinId(); + RDrawableWindow* rw = tlw->d_func()->topData()->rwindow; + rw->SetOrdinalPosition(0); + } +} +QT_END_NAMESPACE diff --git a/src/gui/kernel/qwindowdefs.h b/src/gui/kernel/qwindowdefs.h index 8598030..0fe8e1a 100644 --- a/src/gui/kernel/qwindowdefs.h +++ b/src/gui/kernel/qwindowdefs.h @@ -131,6 +131,11 @@ QT_END_HEADER #endif // Q_WS_QWS +#if defined(Q_WS_S60) +class CCoeControl; +typedef CCoeControl * WId; +#endif // Q_WS_S60 + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 34d1779..d153215 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -82,6 +82,7 @@ SOURCES += \ DEFINES += QT_RASTER_IMAGEENGINE win32:DEFINES += QT_RASTER_PAINTENGINE embedded:DEFINES += QT_RASTER_PAINTENGINE + symbian:DEFINES += QT_RASTER_PAINTENGINE SOURCES += \ painting/qpaintengine_raster.cpp \ painting/qdrawhelper.cpp \ @@ -156,14 +157,14 @@ unix:x11 { painting/qprintengine_mac.mm \ } -unix:!mac { +unix:!mac:!symbian { HEADERS += \ painting/qprinterinfo_unix_p.h SOURCES += \ painting/qprinterinfo_unix.cpp } -win32|x11|mac|embedded { +win32|x11|mac|embedded|symbian { SOURCES += painting/qbackingstore.cpp HEADERS += painting/qbackingstore_p.h } @@ -180,6 +181,13 @@ embedded { painting/qpaintdevice_qws.cpp } +symbian { + SOURCES += \ + painting/qpaintdevice_s60.cpp \ + painting/qregion_s60.cpp \ + painting/qcolormap_s60.cpp +} + x11|embedded { contains(QT_CONFIG,qtopia) { DEFINES += QT_NO_CUPS QT_NO_LPR @@ -357,3 +365,18 @@ embedded { } +symbian { + HEADERS += painting/qwindowsurface_s60_p.h + SOURCES += painting/qwindowsurface_s60.cpp + armccIfdefBlock = \ + "$${LITERAL_HASH}if defined(ARMV6)" \ + "MACRO QT_HAVE_ARMV6" \ + "SOURCEPATH painting" \ + "SOURCE qblendfunctions_armv6_rvct.s" \ + "SOURCE qdrawhelper_armv6_rvct.s" \ + "$${LITERAL_HASH}endif" + + MMP_RULES += armccIfdefBlock + QMAKE_CXXFLAGS.ARMCC *= -O3 +} + diff --git a/src/gui/painting/qblendfunctions_armv6_rvct.s b/src/gui/painting/qblendfunctions_armv6_rvct.s new file mode 100644 index 0000000..312bd07 --- /dev/null +++ b/src/gui/painting/qblendfunctions_armv6_rvct.s @@ -0,0 +1,223 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +;** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +;** Beta Release License Agreement. +;** +;** 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.0, included in the file LGPL_EXCEPTION.txt in this +;** package. +;** +;** GNU General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU +;** General Public License version 3.0 as published by the Free Software +;** Foundation and appearing in the file LICENSE.GPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU General Public License version 3.0 requirements will be +;** met: http://www.gnu.org/copyleft/gpl.html. +;** +;** If you are unsure which license is appropriate for your use, please +;** contact the sales department at qt-sales@nokia.com. +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + +; +; 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. +; + + + ARM + PRESERVE8 + + INCLUDE qdrawhelper_armv6_rvct.inc + + +;----------------------------------------------------------------------------- +; qt_blend_rgb32_on_rgb32_arm +; +; @brief +; +; @param dest Destination pixels (r0) +; @param dbpl Destination bytes per line (r1) +; @param src Source pixels (r2) +; @param sbpl Source bytes per line (r3) +; @param w Width (s0 -> r4) +; @param h Height (s1 -> r5) +; @param const_alpha Constant alpha (s2 -> r6) +; +;--------------------------------------------------------------------------- +qt_blend_rgb32_on_rgb32_armv6 Function + stmfd sp!, {r4-r12, r14} + + ; read arguments off the stack + add r8, sp, #10 * 4 + ldmia r8, {r9-r11} + + ; Reorganize registers + + mov r4, r10 + mov r5, r1 + mov r6, r3 + + mov r1, r2 + mov r2, r9 + mov r3, r11 + + ; Now we have registers + ; @param dest Destination pixels (r0) + ; @param src Source pixels (r1) + ; @param w Width (r2) + ; @param const_alpha Constant alpha (r3) + ; @param h Height (r4) + ; @param dbpl Destination bytes per line (r5) + ; @param sbpl Source bytes per line (r6) + + cmp r3, #256 ; test if we have fully opaque constant alpha value + bne rgb32_blend_const_alpha ; branch if not + +rgb32_blend_loop + + subs r4, r4, #1 + bmi rgb32_blend_exit ; while(h--) + +rgb321 PixCpySafe r0, r1, r2 + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b rgb32_blend_loop + + +rgb32_blend_const_alpha + + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + + sub r3, r3, #1 ; const_alpha -= 1; + +rgb32_blend_loop_const_alpha + + subs r4, r4, #1 + bmi rgb32_blend_exit ; while(h--) + +rgb322 BlendRowSafe PixelSourceOverConstAlpha + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b rgb32_blend_loop_const_alpha + +rgb32_blend_exit + + ldmfd sp!, {r4-r12, pc} ; pop and return + + + +;----------------------------------------------------------------------------- +; qt_blend_argb32_on_argb32_arm +; +; @brief +; +; @param dest Destination pixels (r0) +; @param dbpl Destination bytes per line (r1) +; @param src Source pixels (r2) +; @param sbpl Source bytes per line (r3) +; @param w Width (s0 -> r4) +; @param h Height (s1 -> r5) +; @param const_alpha Constant alpha (s2 -> r6) +; +;--------------------------------------------------------------------------- +qt_blend_argb32_on_argb32_armv6 Function + stmfd sp!, {r4-r12, r14} + + ; read arguments off the stack + add r8, sp, #10 * 4 + ldmia r8, {r9-r11} + + ; Reorganize registers + + mov r4, r10 + mov r5, r1 + mov r6, r3 + + mov r1, r2 + mov r2, r9 + mov r3, r11 + + ; Now we have registers + ; @param dest Destination pixels (r0) + ; @param src Source pixels (r1) + ; @param w Width (r2) + ; @param const_alpha Constant alpha (r3) + ; @param h Height (r4) + ; @param dbpl Destination bytes per line (r5) + ; @param sbpl Source bytes per line (r6) + + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + + cmp r3, #256 ; test if we have fully opaque constant alpha value + bne argb32_blend_const_alpha ; branch if not + +argb32_blend_loop + + subs r4, r4, #1 + bmi argb32_blend_exit ; while(h--) + +argb321 BlendRowSafe PixelSourceOver + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b argb32_blend_loop + +argb32_blend_const_alpha + + sub r3, r3, #1 ; const_alpha -= 1; + +argb32_blend_loop_const_alpha + + subs r4, r4, #1 + bmi argb32_blend_exit ; while(h--) + +argb322 BlendRowSafe PixelSourceOverConstAlpha + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b argb32_blend_loop_const_alpha + +argb32_blend_exit + + ldmfd sp!, {r4-r12, pc} ; pop and return + + + END ; File end + diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index 591f63e..8e4cc68 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -221,7 +221,7 @@ bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush) { if (brush.style() != Qt::TexturePattern) return false; - QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d); + QTexturedBrushData *tx_data = static_cast<QTexturedBrushData *>(brush.d.data()); return tx_data->m_has_pixmap_texture; } @@ -230,6 +230,37 @@ struct QGradientBrushData : public QBrushData QGradient gradient; }; +struct QBrushDataPointerHandler +{ + static inline void deleteData(QBrushData *d) + { + switch (d->style) { + case Qt::TexturePattern: + delete static_cast<QTexturedBrushData*>(d); + break; + case Qt::LinearGradientPattern: + case Qt::RadialGradientPattern: + case Qt::ConicalGradientPattern: + delete static_cast<QGradientBrushData*>(d); + break; + default: + delete d; + } + } + + static inline void cleanup(QBrushData *d) + { + if (d && !d->ref.deref()) { + deleteData(d); + } + } + + static inline void reset(QBrushData *&d, QBrushData *other) + { + cleanup(d); + d = other; + } +}; /*! \class QBrush @@ -364,20 +395,20 @@ void QBrush::init(const QColor &color, Qt::BrushStyle style) { switch(style) { case Qt::NoBrush: - d = nullBrushInstance(); + d.data_ptr() = nullBrushInstance(); d->ref.ref(); if (d->color != color) setColor(color); return; case Qt::TexturePattern: - d = new QTexturedBrushData; + d.data_ptr() = new QTexturedBrushData; break; case Qt::LinearGradientPattern: case Qt::RadialGradientPattern: case Qt::ConicalGradientPattern: - d = new QGradientBrushData; + d.data_ptr() = new QGradientBrushData; break; default: - d = new QBrushData; + d.data_ptr() = new QBrushData; break; } d->ref = 1; @@ -391,8 +422,8 @@ void QBrush::init(const QColor &color, Qt::BrushStyle style) */ QBrush::QBrush() + : d(nullBrushInstance()) { - d = nullBrushInstance(); Q_ASSERT(d); d->ref.ref(); } @@ -435,7 +466,7 @@ QBrush::QBrush(Qt::BrushStyle style) if (qbrush_check_type(style)) init(Qt::black, style); else { - d = nullBrushInstance(); + d.data_ptr() = nullBrushInstance(); d->ref.ref(); } } @@ -451,7 +482,7 @@ QBrush::QBrush(const QColor &color, Qt::BrushStyle style) if (qbrush_check_type(style)) init(color, style); else { - d = nullBrushInstance(); + d.data_ptr() = nullBrushInstance(); d->ref.ref(); } } @@ -468,7 +499,7 @@ QBrush::QBrush(Qt::GlobalColor color, Qt::BrushStyle style) if (qbrush_check_type(style)) init(color, style); else { - d = nullBrushInstance(); + d.data_ptr() = nullBrushInstance(); d->ref.ref(); } } @@ -510,8 +541,8 @@ QBrush::QBrush(Qt::GlobalColor color, const QPixmap &pixmap) */ QBrush::QBrush(const QBrush &other) + : d(other.d.data()) { - d = other.d; d->ref.ref(); } @@ -535,7 +566,7 @@ QBrush::QBrush(const QGradient &gradient) }; init(QColor(), enum_table[gradient.type()]); - QGradientBrushData *grad = static_cast<QGradientBrushData *>(d); + QGradientBrushData *grad = static_cast<QGradientBrushData *>(d.data()); grad->gradient = gradient; } @@ -545,24 +576,11 @@ QBrush::QBrush(const QGradient &gradient) QBrush::~QBrush() { - if (!d->ref.deref()) - cleanUp(d); } void QBrush::cleanUp(QBrushData *x) { - switch (x->style) { - case Qt::TexturePattern: - delete static_cast<QTexturedBrushData*>(x); - break; - case Qt::LinearGradientPattern: - case Qt::RadialGradientPattern: - case Qt::ConicalGradientPattern: - delete static_cast<QGradientBrushData*>(x); - break; - default: - delete x; - } + QBrushDataPointerHandler::deleteData(x); } @@ -571,38 +589,36 @@ void QBrush::detach(Qt::BrushStyle newStyle) if (newStyle == d->style && d->ref == 1) return; - QBrushData *x; + QScopedPointer<QBrushData> x; switch(newStyle) { case Qt::TexturePattern: { QTexturedBrushData *tbd = new QTexturedBrushData; if (d->style == Qt::TexturePattern) { - QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d); + QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data()); if (data->m_has_pixmap_texture) tbd->setPixmap(data->pixmap()); else tbd->setImage(data->image()); } - x = tbd; + x.reset(tbd); break; } case Qt::LinearGradientPattern: case Qt::RadialGradientPattern: case Qt::ConicalGradientPattern: - x = new QGradientBrushData; - static_cast<QGradientBrushData *>(x)->gradient = - static_cast<QGradientBrushData *>(d)->gradient; + x.reset(new QGradientBrushData); + static_cast<QGradientBrushData *>(x.data())->gradient = + static_cast<QGradientBrushData *>(d.data())->gradient; break; default: - x = new QBrushData; + x.reset(new QBrushData); break; } x->ref = 1; x->style = newStyle; x->color = d->color; x->transform = d->transform; - if (!d->ref.deref()) - cleanUp(d); - d = x; + d.reset(x.take()); } @@ -615,10 +631,11 @@ void QBrush::detach(Qt::BrushStyle newStyle) QBrush &QBrush::operator=(const QBrush &b) { + if (this == &b) + return *this; + b.d->ref.ref(); - if (!d->ref.deref()) - cleanUp(d); - d = b.d; + d.reset(b.d.data()); return *this; } @@ -713,7 +730,7 @@ QPixmap *QBrush::pixmap() const { if (d->style != Qt::TexturePattern) return 0; - QTexturedBrushData *data = static_cast<QTexturedBrushData*>(d); + QTexturedBrushData *data = static_cast<QTexturedBrushData*>(d.data()); QPixmap &pixmap = data->pixmap(); return pixmap.isNull() ? 0 : &pixmap; } @@ -730,7 +747,7 @@ QPixmap *QBrush::pixmap() const QPixmap QBrush::texture() const { return d->style == Qt::TexturePattern - ? ((QTexturedBrushData*) d)->pixmap() + ? (static_cast<QTexturedBrushData *>(d.data()))->pixmap() : QPixmap(); } @@ -748,7 +765,7 @@ void QBrush::setTexture(const QPixmap &pixmap) { if (!pixmap.isNull()) { detach(Qt::TexturePattern); - QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d); + QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data()); data->setPixmap(pixmap); } else { detach(Qt::NoBrush); @@ -771,7 +788,7 @@ void QBrush::setTexture(const QPixmap &pixmap) QImage QBrush::textureImage() const { return d->style == Qt::TexturePattern - ? ((QTexturedBrushData *) d)->image() + ? (static_cast<QTexturedBrushData *>(d.data()))->image() : QImage(); } @@ -796,7 +813,7 @@ void QBrush::setTextureImage(const QImage &image) { if (!image.isNull()) { detach(Qt::TexturePattern); - QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d); + QTexturedBrushData *data = static_cast<QTexturedBrushData *>(d.data()); data->setImage(image); } else { detach(Qt::NoBrush); @@ -812,7 +829,7 @@ const QGradient *QBrush::gradient() const if (d->style == Qt::LinearGradientPattern || d->style == Qt::RadialGradientPattern || d->style == Qt::ConicalGradientPattern) { - return &static_cast<const QGradientBrushData *>(d)->gradient; + return &static_cast<const QGradientBrushData *>(d.data())->gradient; } return 0; } @@ -925,16 +942,16 @@ bool QBrush::operator==(const QBrush &b) const if (b.d->style == d->style && b.d->color == d->color) { switch (d->style) { case Qt::TexturePattern: { - QPixmap &us = ((QTexturedBrushData *) d)->pixmap(); - QPixmap &them = ((QTexturedBrushData *) b.d)->pixmap(); + QPixmap &us = (static_cast<QTexturedBrushData *>(d.data()))->pixmap(); + QPixmap &them = (static_cast<QTexturedBrushData *>(b.d.data()))->pixmap(); return ((us.isNull() && them.isNull()) || us.cacheKey() == them.cacheKey()); } case Qt::LinearGradientPattern: case Qt::RadialGradientPattern: case Qt::ConicalGradientPattern: { - QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d); - QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d); + QGradientBrushData *d1 = static_cast<QGradientBrushData *>(d.data()); + QGradientBrushData *d2 = static_cast<QGradientBrushData *>(b.d.data()); return d1->gradient == d2->gradient; } default: diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h index 404569a..2e82246 100644 --- a/src/gui/painting/qbrush.h +++ b/src/gui/painting/qbrush.h @@ -45,6 +45,7 @@ #include <QtCore/qpair.h> #include <QtCore/qpoint.h> #include <QtCore/qvector.h> +#include <QtCore/qscopedpointer.h> #include <QtGui/qcolor.h> #include <QtGui/qmatrix.h> #include <QtGui/qtransform.h> @@ -61,6 +62,7 @@ struct QBrushData; class QPixmap; class QGradient; class QVariant; +struct QBrushDataPointerHandler; class Q_GUI_EXPORT QBrush { @@ -126,13 +128,13 @@ private: friend bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush& brush); void detach(Qt::BrushStyle newStyle); void init(const QColor &color, Qt::BrushStyle bs); - QBrushData *d; + QScopedCustomPointer<QBrushData, QBrushDataPointerHandler> d; void cleanUp(QBrushData *x); public: inline bool isDetached() const; typedef QBrushData * DataPtr; - inline DataPtr &data_ptr() { return d; } + inline DataPtr &data_ptr() { return d.data_ptr(); } }; inline void QBrush::setColor(Qt::GlobalColor acolor) diff --git a/src/gui/painting/qcolormap_s60.cpp b/src/gui/painting/qcolormap_s60.cpp new file mode 100644 index 0000000..1b58598 --- /dev/null +++ b/src/gui/painting/qcolormap_s60.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcolormap.h" +#include "qcolor.h" + +QT_BEGIN_NAMESPACE + +class QColormapPrivate +{ +public: + inline QColormapPrivate() + : ref(1) + { } + + QAtomicInt ref; +}; + +void QColormap::initialize() +{ +} + +void QColormap::cleanup() +{ +} + +QColormap QColormap::instance(int) +{ + return QColormap(); +} + +QColormap::QColormap() : d(new QColormapPrivate) +{} + +QColormap::QColormap(const QColormap &colormap) :d (colormap.d) +{ d->ref.ref(); } + +QColormap::~QColormap() +{ + if (!d->ref.deref()) + delete d; +} + +QColormap::Mode QColormap::mode() const +{ return QColormap::Direct; } + +int QColormap::depth() const +{ + return 32; +} + +int QColormap::size() const +{ + return -1; +} + +uint QColormap::pixel(const QColor &color) const +{ return color.rgba(); } + +const QColor QColormap::colorAt(uint pixel) const +{ return QColor(pixel); } + +const QVector<QColor> QColormap::colormap() const +{ return QVector<QColor>(); } + +QColormap &QColormap::operator=(const QColormap &colormap) +{ qAtomicAssign(d, colormap.d); return *this; } + +QT_END_NAMESPACE + diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 0d1da54..23fc1b1 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -38,15 +38,18 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #include <private/qdrawhelper_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qpainter_p.h> #include <private/qdrawhelper_x86_p.h> +#include <private/qdrawhelper_armv6_p.h> #include <private/qmath_p.h> #include <qmath.h> QT_BEGIN_NAMESPACE + #define MASK(src, a) src = BYTE_MUL(src, a) #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) && __GNUC__ == 3 && __GNUC__ < 4 && QT_POINTER_SIZE == 8 @@ -1203,7 +1206,35 @@ static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operato return b; } - +#if defined(Q_CC_RVCT) +// Force ARM code generation for comp_func_* -methods +# pragma push +# pragma arm +# if defined(QT_HAVE_ARMV6) +static __forceinline void preload(const uint *start) +{ + asm( "pld [start]" ); +} +static const uint L2CacheLineLength = 32; +static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint); +# define PRELOAD_INIT(x) preload(x); +# define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y) +# define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); +// Two consecutive preloads stall, so space them out a bit by using different modulus. +# define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \ + if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts); +# else +# define PRELOAD_INIT(x) +# define PRELOAD_INIT2(x,y) +# define PRELOAD_COND(x) +# define PRELOAD_COND2(x,y) +# endif +#else +# define PRELOAD_INIT(x) +# define PRELOAD_INIT2(x,y) +# define PRELOAD_COND(x) +# define PRELOAD_COND2(x,y) +#endif /* The constant alpha factor describes an alpha factor that gets applied to the result of the composition operation combining it with the destination. @@ -1236,8 +1267,11 @@ static void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint QT_MEMFILL_UINT(dest, length, 0); } else { int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], ialpha); + } } } @@ -1247,8 +1281,11 @@ static void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, ui QT_MEMFILL_UINT(dest, length, 0); } else { int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], ialpha); + } } } @@ -1263,8 +1300,11 @@ static void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint colo } else { int ialpha = 255 - const_alpha; color = BYTE_MUL(color, const_alpha); - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = color + BYTE_MUL(dest[i], ialpha); + } } } @@ -1274,8 +1314,11 @@ static void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length ::memcpy(dest, src, length * sizeof(uint)); } else { int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); + } } } @@ -1300,20 +1343,26 @@ static void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint } else { if (const_alpha != 255) color = BYTE_MUL(color, const_alpha); - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); + } } } static void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = src[i]; dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); } @@ -1329,7 +1378,9 @@ static void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, { if (const_alpha != 255) color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = d + BYTE_MUL(color, qAlpha(~d)); } @@ -1337,13 +1388,16 @@ static void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, static void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = BYTE_MUL(src[i], const_alpha); dest[i] = d + BYTE_MUL(s, qAlpha(~d)); @@ -1357,13 +1411,17 @@ static void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, i */ static void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) { + PRELOAD_INIT(dest) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(color, qAlpha(dest[i])); + } } else { color = BYTE_MUL(color, const_alpha); uint cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); } @@ -1372,12 +1430,16 @@ static void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint co static void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); + } } else { uint cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = BYTE_MUL(src[i], const_alpha); dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); @@ -1396,19 +1458,25 @@ static void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, ui if (const_alpha != 255) { a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; } + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], a); } } static void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); + } } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; dest[i] = BYTE_MUL(dest[i], a); } @@ -1422,13 +1490,17 @@ static void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int static void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) { + PRELOAD_INIT(dest) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); + } } else { color = BYTE_MUL(color, const_alpha); int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); } @@ -1437,12 +1509,16 @@ static void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint c static void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); + } } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); @@ -1460,18 +1536,25 @@ static void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, u uint a = qAlpha(~color); if (const_alpha != 255) a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], a); + } } static void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); + } } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; dest[i] = BYTE_MUL(dest[i], sia); } @@ -1490,20 +1573,26 @@ static void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color = BYTE_MUL(color, const_alpha); } uint sia = qAlpha(~color); - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); + } } static void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = src[i]; uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); @@ -1523,7 +1612,9 @@ static void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, color = BYTE_MUL(color, const_alpha); a = qAlpha(color) + 255 - const_alpha; } + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); } @@ -1531,8 +1622,10 @@ static void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, static void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = src[i]; uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); @@ -1540,6 +1633,7 @@ static void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, i } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); uint d = dest[i]; uint a = qAlpha(s) + cia; @@ -1560,7 +1654,9 @@ static void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, color = BYTE_MUL(color, const_alpha); uint sia = qAlpha(~color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); } @@ -1568,14 +1664,17 @@ static void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, static void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = BYTE_MUL(src[i], const_alpha); dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); @@ -1626,7 +1725,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int { uint s = color; + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; #define MIX(mask) (qMin(((qint64(s)&mask) + (qint64(d)&mask)), qint64(mask))) d = (MIX(AMASK) | MIX(RMASK) | MIX(GMASK) | MIX(BMASK)); @@ -1646,7 +1747,9 @@ static void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -1682,7 +1785,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -1708,7 +1813,9 @@ static void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint co template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -1746,7 +1853,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, i int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -1772,7 +1881,9 @@ static void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint colo template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -1821,7 +1932,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -1847,7 +1960,9 @@ static void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint col template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -1890,7 +2005,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, i int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -1916,7 +2033,9 @@ static void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint colo template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -1959,7 +2078,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -1985,7 +2106,9 @@ static void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint col template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2038,7 +2161,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *des int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2064,7 +2189,9 @@ static void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2117,7 +2244,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2143,7 +2272,9 @@ static void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2193,7 +2324,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2219,7 +2352,9 @@ static void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2278,7 +2413,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2304,7 +2441,9 @@ static void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2347,7 +2486,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *des int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2373,7 +2514,9 @@ static void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2410,7 +2553,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_imp int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2436,7 +2581,9 @@ static void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2462,6 +2609,11 @@ static void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int len comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#if defined(Q_CC_RVCT) +// Restore pragma state from previous #pragma arm +# pragma pop +#endif + static void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, int length, uint color, @@ -7709,6 +7861,96 @@ static uint detectCPUFeatures() #endif } +#if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6) +// Move these to qdrawhelper_arm.c when all +// functions are implemented using arm assembly. +static CompositionFunctionSolid qt_functionForModeSolid_ARMv6[numCompositionFunctions] = { + comp_func_solid_SourceOver, + comp_func_solid_DestinationOver, + comp_func_solid_Clear, + comp_func_solid_Source, + comp_func_solid_Destination, + comp_func_solid_SourceIn, + comp_func_solid_DestinationIn, + comp_func_solid_SourceOut, + comp_func_solid_DestinationOut, + comp_func_solid_SourceAtop, + comp_func_solid_DestinationAtop, + comp_func_solid_XOR, + comp_func_solid_Plus, + comp_func_solid_Multiply, + comp_func_solid_Screen, + comp_func_solid_Overlay, + comp_func_solid_Darken, + comp_func_solid_Lighten, + comp_func_solid_ColorDodge, + comp_func_solid_ColorBurn, + comp_func_solid_HardLight, + comp_func_solid_SoftLight, + comp_func_solid_Difference, + comp_func_solid_Exclusion, + rasterop_solid_SourceOrDestination, + rasterop_solid_SourceAndDestination, + rasterop_solid_SourceXorDestination, + rasterop_solid_NotSourceAndNotDestination, + rasterop_solid_NotSourceOrNotDestination, + rasterop_solid_NotSourceXorDestination, + rasterop_solid_NotSource, + rasterop_solid_NotSourceAndDestination, + rasterop_solid_SourceAndNotDestination +}; + +static CompositionFunction qt_functionForMode_ARMv6[numCompositionFunctions] = { + comp_func_SourceOver_armv6, + comp_func_DestinationOver, + comp_func_Clear, + comp_func_Source_armv6, + comp_func_Destination, + comp_func_SourceIn, + comp_func_DestinationIn, + comp_func_SourceOut, + comp_func_DestinationOut, + comp_func_SourceAtop, + comp_func_DestinationAtop, + comp_func_XOR, + comp_func_Plus, + comp_func_Multiply, + comp_func_Screen, + comp_func_Overlay, + comp_func_Darken, + comp_func_Lighten, + comp_func_ColorDodge, + comp_func_ColorBurn, + comp_func_HardLight, + comp_func_SoftLight, + comp_func_Difference, + comp_func_Exclusion, + rasterop_SourceOrDestination, + rasterop_SourceAndDestination, + rasterop_SourceXorDestination, + rasterop_NotSourceAndNotDestination, + rasterop_NotSourceOrNotDestination, + rasterop_NotSourceXorDestination, + rasterop_NotSource, + rasterop_NotSourceAndDestination, + rasterop_SourceAndNotDestination +}; + +static void qt_blend_color_argb_armv6(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + + CompositionFunctionSolid func = qt_functionForModeSolid_ARMv6[data->rasterBuffer->compositionMode]; + while (count--) { + uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x; + func(target, spans->len, data->solid.color, spans->coverage); + ++spans; + } +} + +#endif // Q_CC_RVCT && QT_HAVE_ARMV6 + + void qInitDrawhelperAsm() { static uint features = 0xffffffff; @@ -7824,6 +8066,20 @@ void qInitDrawhelperAsm() #endif // QT_NO_DEBUG +#if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6) + functionForModeAsm = qt_functionForMode_ARMv6; + functionForModeSolidAsm = qt_functionForModeSolid_ARMv6; + + qt_memfill32 = qt_memfill32_armv6; + + qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_armv6; + + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_armv6; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_armv6; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6; +#endif // Q_CC_RVCT && QT_HAVE_ARMV6 + if (functionForModeSolidAsm) { const int destinationMode = QPainter::CompositionMode_Destination; functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode]; diff --git a/src/gui/painting/qdrawhelper_armv6_p.h b/src/gui/painting/qdrawhelper_armv6_p.h new file mode 100644 index 0000000..a4c1df2 --- /dev/null +++ b/src/gui/painting/qdrawhelper_armv6_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDRAWHELPER_ARMV6_P_H +#define QDRAWHELPER_ARMV6_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/qdrawhelper_p.h> + +QT_BEGIN_NAMESPACE + +#if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6) + +extern "C" void qt_blend_rgb32_on_rgb32_armv6(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +extern "C" void qt_blend_argb32_on_argb32_armv6(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +extern "C" void qt_memfill32_armv6(quint32 *dest, quint32 value, int count); + +extern "C" void comp_func_Source_armv6(uint *dest, const uint *src, int length, uint const_alpha); +extern "C" void comp_func_SourceOver_armv6(uint *dest, const uint *src, int length, uint const_alpha); + +#endif // QT_HAVE_ARMV6 + +QT_END_NAMESPACE + +#endif // QDRAWHELPER_ARMV6_P_H diff --git a/src/gui/painting/qdrawhelper_armv6_rvct.inc b/src/gui/painting/qdrawhelper_armv6_rvct.inc new file mode 100644 index 0000000..b3e0605 --- /dev/null +++ b/src/gui/painting/qdrawhelper_armv6_rvct.inc @@ -0,0 +1,496 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +;** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +;** Beta Release License Agreement. +;** +;** 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.0, included in the file LGPL_EXCEPTION.txt in this +;** package. +;** +;** GNU General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU +;** General Public License version 3.0 as published by the Free Software +;** Foundation and appearing in the file LICENSE.GPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU General Public License version 3.0 requirements will be +;** met: http://www.gnu.org/copyleft/gpl.html. +;** +;** If you are unsure which license is appropriate for your use, please +;** contact the sales department at qt-sales@nokia.com. +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + +; +; 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. +; + +;----------------------------------------------------------------------------- +; Globals. +; Earch marcro expects that caller has loaded 0x800080 to r14. +;----------------------------------------------------------------------------- + +ComponentHalf EQU 0x800080 + +;----------------------------------------------------------------------------- +; ARM assembly implementations of accelerated graphics operations. +; +; Conventions: +; +; - r0 = Target buffer pointer +; - r1 = Source buffer pointer +; - r2 = Length of the buffer to blend +; - r3 = Constant alpha for source buffer +; +;----------------------------------------------------------------------------- + +; A macro for transparently defining ARM functions + MACRO +$func Function + AREA Function_$func, CODE + GLOBAL $func + ALIGN 4 + CODE32 +$func + MEND + + +;----------------------------------------------------------------------------- +; Armv6 boosted implementation of BYTE_MUL(...) function found in qdrawhelper_p.h. +; +; @param dst Destination register where to store the result +; @param x Value to multiply +; @param a Multiplicator byte +; @param r14 Component half 0x800080 +; +; @note Trashes x, r8 +;----------------------------------------------------------------------------- + MACRO + ByteMul $dst, $x, $a + + ; static inline uint BYTE_MUL(uint x, uint a) + + ; uint r8 = (x & 0xff00ff) * a + 0x800080 + uxtb16 r8, $x ; r8 = r8 & 0x00FF00FF + mla r8, r8, $a, r14 + + ; x = ((r >> 8) & 0xff00ff) * a + 0x800080 + uxtb16 $x, $x, ror #8 + mla $x, $x, $a, r14 + + + ; r8 = (r8 + ((r8 >> 8) & 0xff00ff) ) >> 8 + ; r8 &= 0xff00ff + uxtab16 r8, r8, r8, ror #8 + uxtb16 r8, r8, ror #8 + + ; x = x + ((x >>8) & 0xff00ff) + uxtab16 $x, $x, $x, ror #8 + + ; x &= 0xff00ff00 + ; x |= r8 + uxtb16 $x, $x, ror #8 + orr $dst, r8, $x, lsl #8 + + MEND + +;----------------------------------------------------------------------------- +; Armv6 boosted implementation of INTERPOLATE_PIXEL_255(...) function found in +; qdrawhelper_p.h. +; +; @param dst Destination register where to store the result +; @param x First value to multiply +; @param a Multiplicator byte for first value +; @param y Second value to multiply +; @param b Multiplicator byte for second value +; @param r14 Component half 0x800080 +; +; +; @note Trashes x, r8, r14 +;----------------------------------------------------------------------------- + MACRO + InterpolatePixel255 $dst, $x, $a, $y, $b + + ; static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) + + ; First calculate the parts where we need 0x800080 + + ; uint r8 = (((x & 0xff00ff) * a) + 0x800080) + uxtb16 r8, $x ; r8 = r8 & 0x00FF00FF + mla r8, r8, $a, r14 + + ; x = ((((x >> 8) & 0xff00ff) * a) + 0x800080) + uxtb16 $x, $x, ror #8 + mla $x, $x, $a, r14 + + ; Now we are trashing r14 to free it for other purposes + + ; uint r14 = (y & 0xff00ff) * b + uxtb16 r14, $y ; r14 = y & 0x00FF00FF + mul r14, r14, $b + + ; r8 = r8 + r14 + add r8, r8, r14 + + ; r8 = (r8 + ((r8 >> 8) & 0xff00ff) ) >> 8 + ; r8 &= 0xff00ff + uxtab16 r8, r8, r8, ror #8 + uxtb16 r8, r8, ror #8 + + ; r14 = ((y >> 8) & 0xff00ff) * b + uxtb16 r14, $y, ror #8 ; r14 = ((y >> 8) & 0xFF00FF) + mul r14, r14, $b + + ; x = x + r14 + add $x, $x, r14 + + ; x = x + ((x >>8) & 0xff00ff) + uxtab16 $x, $x, $x, ror #8 + + ; x &= 0xff00ff00 + ; x |= r8 + uxtb16 $x, $x, ror #8 + orr $dst, r8, $x, lsl #8 + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend4Pixels $BlendPixel + + ; Blend first 4 pixels + + ldmia r1!, {r4-r7} + ldm r0, {r9-r12} + +b4p1_$label $BlendPixel r9, r4, r3 +b4p2_$label $BlendPixel r10, r5, r3 +b4p3_$label $BlendPixel r11, r6, r3 +b4p4_$label $BlendPixel r12, r7, r3 + + stmia r0!, {r9-r12} + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend8Pixels $BlendPixel + +b8p1_$label Blend4Pixels $BlendPixel +b8p2_$label Blend4Pixels $BlendPixel + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend16Pixels $BlendPixel + +b16p1_$label Blend8Pixels $BlendPixel +b16p2_$label Blend8Pixels $BlendPixel + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend32Pixels $BlendPixel + +b32p1_$label Blend16Pixels $BlendPixel +b32p2_$label Blend16Pixels $BlendPixel + + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one row of pixels and saving the results +; to destination buffer. +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; @param r14 Component Half (0x800080) (r14) +; +; @note Advances r0, r1 +; @note Trashes r2, r4-r12 +;----------------------------------------------------------------------------- + MACRO +$label BlendRow $BlendPixel + + pld [r1] + +bloop_$label + ; Blend 32 pixels per loop iteration + subs r2, r2, #32 + bmi b_remaining_$label + +brp1_$label Blend32Pixels $BlendPixel + + b bloop_$label + +b_remaining_$label + + ; Remaining 31 pixels + + addmi r2, r2, #32 + + ; Blend 16 pixels + tst r2, #16 + beq b_remaining8_$label + +brp2_$label Blend16Pixels $BlendPixel + +b_remaining8_$label + + ; Blend 8 pixels + tst r2, #8 + beq b_remaining4_$label + +brp3_$label Blend8Pixels $BlendPixel + +b_remaining4_$label + + ; Blend 4 pixels + tst r2, #4 + beq b_remaining3_$label + +brp4_$label Blend4Pixels $BlendPixel + +b_remaining3_$label + + ; Remaining 3 pixels + + tst r2, #2 + beq b_last_$label + + ldmia r1!, {r4-r5} + ldm r0, {r9-r10} + +brp5_$label $BlendPixel r9, r4, r3 +brp6_$label $BlendPixel r10, r5, r3 + + stmia r0!, {r9-r10} + +b_last_$label + + tst r2, #1 + beq bexit_$label + + ldr r4, [r1] + ldr r9, [r0] + +bpl_$label $BlendPixel r9, r4, r3 + + str r9, [r0] + +bexit_$label + + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one row of pixels and saving the results +; to destination buffer. Restores all registers. +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; @param r14 Component Half (0x800080) (r14) +; +; @note Advances r0, r1 +; @note Trashes r2, r4-r12 +;----------------------------------------------------------------------------- + MACRO +$label BlendRowSafe $BlendPixel + + stmfd sp!, {r0-r6} ; Preserves registers only up to r6 + +brs_$label BlendRow $BlendPixel + + ldmfd sp!, {r0-r6} + + MEND + + +;----------------------------------------------------------------------------- +; Pix Copy. +; NOTE! Cache line size of ARM1136JF-S and ARM1136J-S is 32 bytes (8 pixels). +; +; @param dst Destination pixels (r0) +; @param src Source pixels (r1) +; @param len Length (r2) +; +; @note Trashes r3-r10 +;----------------------------------------------------------------------------- + MACRO +$label PixCpy $dst, $src, $len + + pld [$src] + +pcpy_loop_$label + ; Copy 8 pixels per loop iteration + pld [$src, #96] + subs $len, $len, #8 + ldmgeia $src!, {r3-r10} + stmgeia $dst!, {r3-r10} + bgt pcpy_loop_$label + +pcpy_remaining_$label + + ; Copy up to 7 remaining pixels + + ; Copy 4 pixels + tst $len, #4 + ldmneia $src!, {r3-r6} + stmneia $dst!, {r3-r6} + + tst $len, #2 + ldmneia $src!, {r3-r4} + stmneia $dst!, {r3-r4} + + tst $len, #1 + ldrne r3, [$src] + strne r3, [$dst] + + MEND + +;----------------------------------------------------------------------------- +; General Pix Copy. Maximum 8 pixels at time. Restores all registers. +; +; @param dst Destination pixels (r0) +; @param src Source pixels (r1) +; @param len Length (r2) +; +; @note Trashes r3-r10 +;----------------------------------------------------------------------------- + MACRO +$label PixCpySafe $dst, $src, $len + + stmfd sp!, {r0-r6} ; Preserves registers only up to r6 + +pcs_$label PixCpy $dst, $src, $len + + ldmfd sp!, {r0-r6} ; pop + + MEND + + +;----------------------------------------------------------------------------- +; A macro for source over compositing one pixel and saving the result to +; dst register. +; +; @param dst Destination register, must contain destination pixel upon entry +; @param src Source register, must contain source pixel upon entry +; @param const_alpha Constant source alpha +; @param r14 Component half 0x800080 +; +; @note Trashes const_alpha, r8 +;----------------------------------------------------------------------------- + MACRO +$label PixelSourceOver $dst, $src, $const_alpha + + ; Negate src and extract alpha + mvn $const_alpha, $src ; bitwise not + uxtb $const_alpha, $const_alpha, ror #24 ; r3 = ((r3 & 0xFF000000) >> 24); + + ;cmp $const_alpha, #255 ; test for full transparency ( negated ) + ;beq exit_$label + cmp $const_alpha, #0 ; test for full opacity ( negated ) + moveq $dst, $src + beq exit_$label + + ByteMul $dst, $dst, $const_alpha + add $dst, $src, $dst + +exit_$label + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one pixel and saving the result to +; dst register. +; +; @param dst Destination register, must contain destination pixel upon entry +; @param src Source register, must contain source pixel upon entry +; @param const_alpha Constant source alpha +; @param r14 Component half 0x800080 +; +; @note Trashes src, const_alpha, r8 +;----------------------------------------------------------------------------- + MACRO +$label PixelSourceOverConstAlpha $dst, $src, $const_alpha + + ; store alpha because we are going to trash it + stmfd sp!, {$const_alpha} + + ByteMul $src, $src, $const_alpha + + ; Negate src and extract alpha + mvn $const_alpha, $src ; bitwise not + uxtb $const_alpha, $const_alpha, ror #24 ; r3 = ((r3 & 0xFF000000) >> 24); + + ByteMul $dst, $dst, $const_alpha + + add $dst, $src, $dst + + ; recover alpha + ldmfd sp!, {$const_alpha} + + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one pixel and saving the result to +; a register. +; +; @param dst Destination register, must contain destination pixel upon entry +; @param src Source register, must contain source pixel upon entry +; @param const_alpha Constant source alpha +; @param r14 Component half 0x800080 +; +; @note Trashes src, r8 +;----------------------------------------------------------------------------- + MACRO +$label PixelSourceConstAlpha $dst, $src, $const_alpha + + ; store r2 and r14 because we are going to trash them + stmfd sp!, {r2, r14} + + rsb r2, $const_alpha, #255 + InterpolatePixel255 $dst, $src, $const_alpha, $dst, r2 + + ; recover r2 and r14 + ldmfd sp!, {r2, r14} + + MEND + + END ; File end diff --git a/src/gui/painting/qdrawhelper_armv6_rvct.s b/src/gui/painting/qdrawhelper_armv6_rvct.s new file mode 100644 index 0000000..3ffe48b --- /dev/null +++ b/src/gui/painting/qdrawhelper_armv6_rvct.s @@ -0,0 +1,178 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +;** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +;** Beta Release License Agreement. +;** +;** 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.0, included in the file LGPL_EXCEPTION.txt in this +;** package. +;** +;** GNU General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU +;** General Public License version 3.0 as published by the Free Software +;** Foundation and appearing in the file LICENSE.GPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU General Public License version 3.0 requirements will be +;** met: http://www.gnu.org/copyleft/gpl.html. +;** +;** If you are unsure which license is appropriate for your use, please +;** contact the sales department at qt-sales@nokia.com. +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + +; +; 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. +; + + ARM + PRESERVE8 + + INCLUDE qdrawhelper_armv6_rvct.inc + +;----------------------------------------------------------------------------- +; qt_memfill32_armv6 +; +; @brief Not yet in use! +; +; @param dest Destination buffer (r0) +; @param value Value (r1) +; @param count Count (r2) +; +;--------------------------------------------------------------------------- +qt_memfill32_armv6 Function + stmfd sp!, {r4-r12, r14} + + mov r3, r1 + mov r4, r1 + mov r5, r1 + mov r6, r1 + mov r7, r1 + mov r8, r1 + mov r9, r1 + +mfill_loop + ; Fill 32 pixels per loop iteration + subs r2, r2, #32 + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + bgt mfill_loop + +mfill_remaining + + ; Fill up to 31 remaining pixels + + ; Fill 16 pixels + tst r2, #16 + stmneia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmneia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + + ; Fill 8 pixels + tst r2, #8 + stmneia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + + ; Fill 4 pixels + tst r2, #4 + stmneia r0!, {r1, r3, r4, r5} + + ; Fill 2 pixels + tst r2, #2 + stmneia r0!, {r1, r3} + + ; Fill last one + tst r2, #1 + strne r1, [r0] + + ldmfd sp!, {r4-r12, pc} ; pop and return + +;----------------------------------------------------------------------------- +; comp_func_Source_arm +; +; @brief +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; +;--------------------------------------------------------------------------- +comp_func_Source_armv6 Function + stmfd sp!, {r4-r12, r14} + + cmp r3, #255 ; if(r3 == 255) + bne src2 ; branch if not + +src1 PixCpy r0, r1, r2 + + ldmfd sp!, {r4-r12, pc} ; pop and return + +src2 + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + +src22 BlendRow PixelSourceConstAlpha + + ldmfd sp!, {r4-r12, pc} ; pop and return + +;----------------------------------------------------------------------------- +; comp_func_SourceOver_arm +; +; @brief +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; +;--------------------------------------------------------------------------- +comp_func_SourceOver_armv6 Function + stmfd sp!, {r4-r12, r14} + + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + + cmp r3, #255 ; if(r3 == 255) + bne srcovr2 ; branch if not + +srcovr1 BlendRow PixelSourceOver + + ldmfd sp!, {r4-r12, pc} ; pop and return + +srcovr2 + +srcovr22 BlendRow PixelSourceOverConstAlpha + + ldmfd sp!, {r4-r12, pc} ; pop and return + + + END ; File end + diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index 38fee8d..8849128 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -87,7 +87,7 @@ QT_BEGIN_NAMESPACE #if defined(Q_CC_RVCT) // RVCT doesn't like static template functions # define Q_STATIC_TEMPLATE_FUNCTION -# define Q_STATIC_INLINE_FUNCTION inline +# define Q_STATIC_INLINE_FUNCTION static __forceinline #else # define Q_STATIC_TEMPLATE_FUNCTION static # define Q_STATIC_INLINE_FUNCTION static inline @@ -301,19 +301,23 @@ struct QSpanData }; -static inline uint BYTE_MUL_RGB16(uint x, uint a) { +Q_STATIC_INLINE_FUNCTION uint BYTE_MUL_RGB16(uint x, uint a) { a += 1; uint t = (((x & 0x07e0)*a) >> 8) & 0x07e0; t |= (((x & 0xf81f)*(a>>2)) >> 6) & 0xf81f; return t; } -static inline uint BYTE_MUL_RGB16_32(uint x, uint a) { +Q_STATIC_INLINE_FUNCTION uint BYTE_MUL_RGB16_32(uint x, uint a) { uint t = (((x & 0xf81f07e0) >> 5)*a) & 0xf81f07e0; t |= (((x & 0x07e0f81f)*a) >> 5) & 0x07e0f81f; return t; } +#if defined(Q_CC_RVCT) +# pragma push +# pragma arm +#endif Q_STATIC_INLINE_FUNCTION uint BYTE_MUL(uint x, uint a) { uint t = (x & 0xff00ff) * a; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; @@ -325,8 +329,11 @@ Q_STATIC_INLINE_FUNCTION uint BYTE_MUL(uint x, uint a) { x |= t; return x; } +#if defined(Q_CC_RVCT) +# pragma pop +#endif -static inline uint PREMUL(uint x) { +Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x) { uint a = x >> 24; uint t = (x & 0xff00ff) * a; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; @@ -391,7 +398,7 @@ public: return qt_colorConvert<quint16, quint32>(data, 0); } - static inline quint32p fromRawData(quint32 v) + Q_STATIC_INLINE_FUNCTION quint32p fromRawData(quint32 v) { quint32p p; p.data = v; @@ -422,7 +429,7 @@ class qrgb565; class qargb8565 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } inline qargb8565() {} inline qargb8565(quint32 v); @@ -439,8 +446,8 @@ public: data[1] &= 0xdf; return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline qargb8565 byte_mul(quint8 a) const; inline qargb8565 operator+(qargb8565 v) const; @@ -458,7 +465,7 @@ private: class qrgb565 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } qrgb565(int v = 0) : data(v) {} @@ -473,8 +480,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb565 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline qrgb565 byte_mul(quint8 a) const; @@ -654,7 +661,7 @@ class qrgb555; class qargb8555 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } qargb8555() {} inline qargb8555(quint32 v); @@ -666,8 +673,8 @@ public: inline quint8 alpha() const { return data[0]; } inline qargb8555 truncedAlpha() { data[0] &= 0xf8; return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline qargb8555 operator+(qargb8555 v) const; inline qargb8555 byte_mul(quint8 a) const; @@ -684,7 +691,7 @@ private: class qrgb555 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb555(int v = 0) : data(v) {} @@ -733,8 +740,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb555 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline bool operator==(const qrgb555 &v) const { return v.data == data; } inline bool operator!=(const qrgb555 &v) const { return v.data != data; } @@ -882,7 +889,7 @@ class qrgb666; class qargb6666 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } inline qargb6666() {} inline qargb6666(quint32 v) { *this = qargb6666(quint32p(v)); } @@ -894,8 +901,8 @@ public: inline quint8 alpha() const; inline qargb6666 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 2; } - static inline quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } inline qargb6666 byte_mul(quint8 a) const; inline qargb6666 operator+(qargb6666 v) const; @@ -912,7 +919,7 @@ private: class qrgb666 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb666() {} inline qrgb666(quint32 v); @@ -922,8 +929,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb666 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 2; } - static inline quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } inline qrgb666 operator+(qrgb666 v) const; inline qrgb666 byte_mul(quint8 a) const; @@ -1080,7 +1087,7 @@ quint32 qargb6666::rawValue() const class qrgb888 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb888() {} inline qrgb888(quint32 v); @@ -1089,8 +1096,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb888 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return a; } - static inline quint8 ialpha(quint8 a) { return 255 - a; } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return a; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 255 - a; } inline qrgb888 byte_mul(quint8 a) const; inline qrgb888 operator+(qrgb888 v) const; @@ -1269,7 +1276,7 @@ class qrgb444; class qargb4444 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } inline qargb4444() {} inline qargb4444(quint32 v) { *this = qargb4444(quint32p(v)); } @@ -1283,8 +1290,8 @@ public: inline quint8 alpha() const { return ((data & 0xf000) >> 8) | ((data & 0xf000) >> 12); } inline qargb4444 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 4; } - static inline quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 4; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } inline qargb4444 byte_mul(quint8 a) const; inline bool operator==(const qargb4444 &v) const { return data == v.data; } @@ -1300,7 +1307,7 @@ private: class qrgb444 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb444() {} inline qrgb444(quint32 v); @@ -1312,8 +1319,8 @@ public: inline qrgb444 operator+(qrgb444 v) const; inline quint8 alpha() const { return 0xff; } inline qrgb444 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 4; } - static inline quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 4; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } inline qrgb444 byte_mul(quint8 a) const; inline bool operator==(const qrgb444 &v) const { return data == v.data; } @@ -1774,7 +1781,14 @@ do { \ } \ } while (0) +#if defined(Q_CC_RVCT) +# pragma push +# pragma arm +#endif Q_STATIC_INLINE_FUNCTION int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; } +#if defined(Q_CC_RVCT) +# pragma pop +#endif inline ushort qConvertRgb32To16(uint c) { @@ -1817,7 +1831,7 @@ inline int qBlue565(quint16 rgb) { } #if 1 -static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t >>= 8; t &= 0xff00ff; @@ -1828,7 +1842,11 @@ static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { return x; } -static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { +#if defined(Q_CC_RVCT) +# pragma push +# pragma arm +#endif +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; t &= 0xff00ff; @@ -1839,9 +1857,12 @@ static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { x |= t; return x; } +#if defined(Q_CC_RVCT) +# pragma pop +#endif #else // possible implementation for 64 bit -static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { ulong t = (((ulong(x)) | ((ulong(x)) << 24)) & 0x00ff00ff00ff00ff) * a; t += (((ulong(y)) | ((ulong(y)) << 24)) & 0x00ff00ff00ff00ff) * b; t >>= 8; @@ -1849,7 +1870,7 @@ static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { return (uint(t)) | (uint(t >> 24)); } -static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { ulong t = (((ulong(x)) | ((ulong(x)) << 24)) & 0x00ff00ff00ff00ff) * a; t += (((ulong(y)) | ((ulong(y)) << 24)) & 0x00ff00ff00ff00ff) * b; t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080); @@ -1864,7 +1885,7 @@ Q_STATIC_INLINE_FUNCTION uint BYTE_MUL(uint x, uint a) { return (uint(t)) | (uint(t >> 24)); } -static inline uint PREMUL(uint x) { +Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x) { uint a = x >> 24; ulong t = (((ulong(x)) | ((ulong(x)) << 24)) & 0x00ff00ff00ff00ff) * a; t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080); diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp index 7b1f637..7248d27 100644 --- a/src/gui/painting/qgraphicssystem.cpp +++ b/src/gui/painting/qgraphicssystem.cpp @@ -44,7 +44,7 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#ifdef Q_WS_WIN +#if defined(Q_WS_WIN) || defined(Q_WS_S60) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC @@ -64,7 +64,7 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ #endif #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) +#elif defined(Q_WS_WIN) || defined(Q_WS_S60) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp index d6afa53..99158c8 100644 --- a/src/gui/painting/qgraphicssystemfactory.cpp +++ b/src/gui/painting/qgraphicssystemfactory.cpp @@ -64,7 +64,7 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) if (system.isEmpty()) { system = QLatin1String("opengl"); } -#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) +#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_WS_S60) if (system.isEmpty()) { system = QLatin1String("raster"); } diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.c index 73e50da..b057b5f 100644 --- a/src/gui/painting/qgrayraster.c +++ b/src/gui/painting/qgrayraster.c @@ -158,7 +158,12 @@ #include <private/qrasterdefs_p.h> #include <private/qgrayraster_p.h> +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else #include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus #include <stdio.h> /* This macro is used to indicate that a function parameter is unused. */ diff --git a/src/gui/painting/qpaintdevice_s60.cpp b/src/gui/painting/qpaintdevice_s60.cpp new file mode 100644 index 0000000..a2c4499 --- /dev/null +++ b/src/gui/painting/qpaintdevice_s60.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintdevice.h" +#include "qpainter.h" +#include "qwidget.h" +#include "qbitmap.h" +#include "qapplication.h" +#include <private/qapplication_p.h> +#include "qprinter.h" + +QT_BEGIN_NAMESPACE + +QPaintDevice::QPaintDevice() +{ + painters = 0; +} + + +QPaintDevice::~QPaintDevice() +{ + if (paintingActive()) + qWarning("QPaintDevice: Cannot destroy paint device that is being " + "painted. Be sure to QPainter::end() painters!"); +} + +int QPaintDevice::metric(PaintDeviceMetric) const +{ + qWarning("QPaintDevice::metrics: Device has no metric information"); + return 0; +} + + +QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp index 9859425..e70d524 100644 --- a/src/gui/painting/qpaintengine.cpp +++ b/src/gui/painting/qpaintengine.cpp @@ -717,7 +717,6 @@ QPaintEngine::QPaintEngine(QPaintEnginePrivate &dptr, PaintEngineFeatures caps) */ QPaintEngine::~QPaintEngine() { - delete d_ptr; } /*! diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h index 520f71f..6f56adb 100644 --- a/src/gui/painting/qpaintengine.h +++ b/src/gui/painting/qpaintengine.h @@ -44,6 +44,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qobjectdefs.h> +#include <QtCore/qscopedpointer.h> #include <QtGui/qpainter.h> QT_BEGIN_HEADER @@ -239,7 +240,7 @@ protected: uint selfDestruct : 1; uint extended : 1; - QPaintEnginePrivate *d_ptr; + QScopedPointer<QPaintEnginePrivate> d_ptr; private: void setAutoDestruct(bool autoDestr) { selfDestruct = autoDestr; } diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 4711455..14ce18b 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -91,6 +91,8 @@ # include <private/qfontengine_qpf_p.h> # endif # include <private/qabstractfontengine_p.h> +#elif defined(Q_WS_S60) && defined(QT_NO_FREETYPE) +# include <private/qfontengine_s60_p.h> #endif #if defined(Q_WS_WIN64) @@ -346,6 +348,7 @@ void QRasterPaintEngine::init() #else (unsigned char *) malloc(d->rasterPoolSize); #endif + Q_CHECK_PTR(d->rasterPoolBase); // The antialiasing raster. d->grayRaster = new QT_FT_Raster; @@ -3226,7 +3229,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte ensurePen(); ensureState(); -#if defined (Q_WS_WIN) || defined(Q_WS_MAC) +#if defined (Q_WS_WIN) || defined(Q_WS_MAC) || (defined(Q_WS_S60) && defined(QT_NO_FREETYPE)) bool drawCached = true; @@ -3259,7 +3262,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte return; } -#else // Q_WS_WIN || Q_WS_MAC +#else // Q_WS_WIN || Q_WS_MAC || Q_WS_S60 && QT_NO_FREETYPE QFontEngine *fontEngine = ti.fontEngine; @@ -3279,7 +3282,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte } #endif // Q_WS_QWS -#if (defined(Q_WS_X11) || defined(Q_WS_QWS)) && !defined(QT_NO_FREETYPE) +#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60)) && !defined(QT_NO_FREETYPE) #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2) if (fontEngine->type() == QFontEngine::QPF2) { @@ -3942,7 +3945,7 @@ static void qt_merge_clip(const QClipData *c1, const QClipData *c2, QClipData *r // find required length int max = qMax(c1_spans[c1_count - 1].x + c1_spans[c1_count - 1].len, - c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len); + c2_spans[c2_count - 1].x + c2_spans[c2_count - 1].len); buffer.resize(max); memset(buffer.data(), 0, buffer.size() * sizeof(short)); @@ -3996,7 +3999,7 @@ void QRasterPaintEnginePrivate::initializeRasterizer(QSpanData *data) const QClipData *c = clip(); if (c) { const QRect r(QPoint(c->xmin, c->ymin), - QPoint(c->xmax, c->ymax)); + QPoint(c->xmax, c->ymax)); clipRect = clipRect.intersected(r); blend = data->blend; } else { @@ -4104,6 +4107,7 @@ void QRasterPaintEnginePrivate::rasterize(QT_FT_Outline *outline, #else (unsigned char *) malloc(rasterPoolSize); #endif + Q_CHECK_PTR(rasterPoolBase); // note: we just freed the old rasterPoolBase. I hope it's not fatal. qt_ft_grays_raster.raster_done(*grayRaster); qt_ft_grays_raster.raster_new(0, grayRaster); @@ -4226,8 +4230,14 @@ int QCustomRasterPaintDevice::bytesPerLine() const { return (width() * depth() + 7) / 8; } -#endif // Q_WS_QWS +#elif defined(Q_WS_S60) + +void QRasterBuffer::prepareBuffer(int width, int height) +{ +} + +#endif // Q_WS_S60 /*! \class QCustomRasterPaintDevice @@ -4335,95 +4345,108 @@ void QClipData::initialize() if (!m_clipLines) m_clipLines = (ClipLine *)calloc(sizeof(ClipLine), clipSpanHeight); - m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan)); - allocated = clipSpanHeight; - - if (hasRectClip) { - int y = 0; - while (y < ymin) { - m_clipLines[y].spans = 0; - m_clipLines[y].count = 0; - ++y; - } + Q_CHECK_PTR(m_clipLines); + QT_TRY { + m_spans = (QSpan *)malloc(clipSpanHeight*sizeof(QSpan)); + allocated = clipSpanHeight; + Q_CHECK_PTR(m_spans); + + QT_TRY { + if (hasRectClip) { + int y = 0; + while (y < ymin) { + m_clipLines[y].spans = 0; + m_clipLines[y].count = 0; + ++y; + } - const int len = clipRect.width(); - count = 0; - while (y < ymax) { - QSpan *span = m_spans + count; - span->x = xmin; - span->len = len; - span->y = y; - span->coverage = 255; - ++count; - - m_clipLines[y].spans = span; - m_clipLines[y].count = 1; - ++y; - } + const int len = clipRect.width(); + count = 0; + while (y < ymax) { + QSpan *span = m_spans + count; + span->x = xmin; + span->len = len; + span->y = y; + span->coverage = 255; + ++count; - while (y < clipSpanHeight) { - m_clipLines[y].spans = 0; - m_clipLines[y].count = 0; - ++y; - } - } else if (hasRegionClip) { + m_clipLines[y].spans = span; + m_clipLines[y].count = 1; + ++y; + } - const QVector<QRect> rects = clipRegion.rects(); - const int numRects = rects.size(); + while (y < clipSpanHeight) { + m_clipLines[y].spans = 0; + m_clipLines[y].count = 0; + ++y; + } + } else if (hasRegionClip) { + + const QVector<QRect> rects = clipRegion.rects(); + const int numRects = rects.size(); + + { // resize + const int maxSpans = (ymax - ymin) * numRects; + if (maxSpans > allocated) { + QSpan *newSpans = (QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)); + Q_CHECK_PTR(newSpans); + m_spans = newSpans; + allocated = maxSpans; + } + } - { // resize - const int maxSpans = (ymax - ymin) * numRects; - if (maxSpans > allocated) { - m_spans = (QSpan *)realloc(m_spans, maxSpans * sizeof(QSpan)); - allocated = maxSpans; - } - } + int y = 0; + int firstInBand = 0; + while (firstInBand < numRects) { + const int currMinY = rects.at(firstInBand).y(); + const int currMaxY = currMinY + rects.at(firstInBand).height(); - int y = 0; - int firstInBand = 0; - count = 0; - while (firstInBand < numRects) { - const int currMinY = rects.at(firstInBand).y(); - const int currMaxY = currMinY + rects.at(firstInBand).height(); + while (y < currMinY) { + m_clipLines[y].spans = 0; + m_clipLines[y].count = 0; + ++y; + } - while (y < currMinY) { - m_clipLines[y].spans = 0; - m_clipLines[y].count = 0; - ++y; - } + int lastInBand = firstInBand; + while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y) + ++lastInBand; - int lastInBand = firstInBand; - while (lastInBand + 1 < numRects && rects.at(lastInBand+1).top() == y) - ++lastInBand; + while (y < currMaxY) { - while (y < currMaxY) { + m_clipLines[y].spans = m_spans + count; + m_clipLines[y].count = lastInBand - firstInBand + 1; - m_clipLines[y].spans = m_spans + count; - m_clipLines[y].count = lastInBand - firstInBand + 1; + for (int r = firstInBand; r <= lastInBand; ++r) { + const QRect &currRect = rects.at(r); + QSpan *span = m_spans + count; + span->x = currRect.x(); + span->len = currRect.width(); + span->y = y; + span->coverage = 255; + ++count; + } + ++y; + } - for (int r = firstInBand; r <= lastInBand; ++r) { - const QRect &currRect = rects.at(r); - QSpan *span = m_spans + count; - span->x = currRect.x(); - span->len = currRect.width(); - span->y = y; - span->coverage = 255; - ++count; + firstInBand = lastInBand + 1; } - ++y; - } - firstInBand = lastInBand + 1; - } + Q_ASSERT(count <= allocated); - Q_ASSERT(count <= allocated); + while (y < clipSpanHeight) { + m_clipLines[y].spans = 0; + m_clipLines[y].count = 0; + ++y; + } - while (y < clipSpanHeight) { - m_clipLines[y].spans = 0; - m_clipLines[y].count = 0; - ++y; + } + } QT_CATCH(...) { + free(m_spans); + QT_RETHROW; } - + } QT_CATCH(...) { + free(m_clipLines); + QT_RETHROW; } } @@ -4796,8 +4819,10 @@ static void qt_span_clip(int count, const QSpan *spans, void *userData) &newspans, newClip->allocated - newClip->count); newClip->count = newspans - newClip->m_spans; if (spans < end) { + QSpan *newSpan = (QSpan *)realloc(newClip->m_spans, newClip->allocated*2*sizeof(QSpan)); + Q_CHECK_PTR(newSpan); + newClip->m_spans = newSpan; newClip->allocated *= 2; - newClip->m_spans = (QSpan *)realloc(newClip->m_spans, newClip->allocated*sizeof(QSpan)); } } } diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 1094206..18361d8 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -83,6 +83,21 @@ static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; bool qt_show_painter_debug_output = true; #endif +class QPainterPrivateCleaner +{ +public: + static inline void cleanup(QPainterPrivate *d) + { + delete d; + } + + static inline void reset(QPainterPrivate *&d, QPainterPrivate *other) + { + delete d; + d = other; + } +}; + extern QPixmap qt_pixmapForBrush(int style, bool invert); void qt_format_text(const QFont &font, @@ -259,14 +274,17 @@ bool QPainterPrivate::attachPainterPrivate(QPainter *q, QPaintDevice *pdev) // in 99% of all cases). E.g: A renders B which renders C which renders D. sp->d_ptr->d_ptrs_size = 4; sp->d_ptr->d_ptrs = (QPainterPrivate **)malloc(4 * sizeof(QPainterPrivate *)); + Q_CHECK_PTR(sp->d_ptr->d_ptrs); } else if (sp->d_ptr->refcount - 1 == sp->d_ptr->d_ptrs_size) { // However, to support corner cases we grow the array dynamically if needed. sp->d_ptr->d_ptrs_size <<= 1; const int newSize = sp->d_ptr->d_ptrs_size * sizeof(QPainterPrivate *); - sp->d_ptr->d_ptrs = (QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize); + QPainterPrivate ** newPointers = (QPainterPrivate **)realloc(sp->d_ptr->d_ptrs, newSize); + Q_CHECK_PTR(newPointers); + sp->d_ptr->d_ptrs = newPointers; } - sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr; - q->d_ptr = sp->d_ptr; + sp->d_ptr->d_ptrs[++sp->d_ptr->refcount - 2] = q->d_ptr.data(); + q->d_ptr.data_ptr() = sp->d_ptr.data(); Q_ASSERT(q->d_ptr->state); @@ -319,7 +337,7 @@ void QPainterPrivate::detachPainterPrivate(QPainter *q) d_ptrs[refcount - 1] = 0; q->restore(); - q->d_ptr = original; + q->d_ptr.data_ptr() = original; if (emulationEngine) { extended = emulationEngine->real_engine; @@ -1354,8 +1372,8 @@ void QPainterPrivate::updateState(QPainterState *newState) */ QPainter::QPainter() + : d_ptr(new QPainterPrivate(this)) { - d_ptr = new QPainterPrivate(this); } /*! @@ -1387,7 +1405,7 @@ QPainter::QPainter(QPaintDevice *pd) { Q_ASSERT(pd != 0); if (!QPainterPrivate::attachPainterPrivate(this, pd)) { - d_ptr = new QPainterPrivate(this); + d_ptr.reset(new QPainterPrivate(this)); begin(pd); } Q_ASSERT(d_ptr); @@ -1399,11 +1417,14 @@ QPainter::QPainter(QPaintDevice *pd) QPainter::~QPainter() { d_ptr->inDestructor = true; - if (isActive()) - end(); - else if (d_ptr->refcount > 1) - d_ptr->detachPainterPrivate(this); - + QT_TRY { + if (isActive()) + end(); + else if (d_ptr->refcount > 1) + d_ptr->detachPainterPrivate(this); + } QT_CATCH(...) { + // don't throw anything in the destructor. + } if (d_ptr) { // Make sure we haven't messed things up. Q_ASSERT(d_ptr->inDestructor); @@ -1411,7 +1432,6 @@ QPainter::~QPainter() Q_ASSERT(d_ptr->refcount == 1); if (d_ptr->d_ptrs) free(d_ptr->d_ptrs); - delete d_ptr; } } @@ -7397,8 +7417,21 @@ QPaintDevice *QPainter::redirected(const QPaintDevice *device, QPoint *offset) void qt_painter_removePaintDevice(QPaintDevice *dev) { - QMutexLocker locker(globalRedirectionsMutex()); - if(QPaintDeviceRedirectionList *redirections = globalRedirections()) { + QMutex *mutex = 0; + QT_TRY { + mutex = globalRedirectionsMutex(); + } QT_CATCH(...) { + // ignore the missing mutex, since we could be called from + // a destructor, and destructors shall not throw + } + QMutexLocker locker(mutex); + QPaintDeviceRedirectionList *redirections = 0; + QT_TRY { + redirections = globalRedirections(); + } QT_CATCH(...) { + // do nothing - code below is safe with redirections being 0. + } + if (redirections) { for (int i = 0; i < redirections->size(); ) { if(redirections->at(i) == dev || redirections->at(i).replacement == dev) redirections->removeAt(i); diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index 78cd713..4ca8923 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -45,6 +45,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qrect.h> #include <QtCore/qpoint.h> +#include <QtCore/qscopedpointer.h> #include <QtGui/qpixmap.h> #include <QtGui/qimage.h> #include <QtGui/qtextoption.h> @@ -78,6 +79,8 @@ class QTextItem; class QMatrix; class QTransform; +class QPainterPrivateCleaner; + class Q_GUI_EXPORT QPainter { Q_DECLARE_PRIVATE(QPainter) @@ -497,7 +500,7 @@ private: Q_DISABLE_COPY(QPainter) friend class Q3Painter; - QPainterPrivate *d_ptr; + QScopedCustomPointer<QPainterPrivate, QPainterPrivateCleaner> d_ptr; friend class QFontEngine; friend class QFontEngineBox; diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 2f3a0cb..57fa979 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -73,6 +73,24 @@ QT_BEGIN_NAMESPACE +struct QPainterPathPrivateHandler +{ + static inline void cleanup(QPainterPathPrivate *d) + { + // note - we must up-cast to QPainterPathData since QPainterPathPrivate + // has a non-virtual destructor! + if (d && !d->ref.deref()) + delete static_cast<QPainterPathData *>(d); + } + + static inline void reset(QPainterPathPrivate *&d, QPainterPathPrivate *other) + { + QPainterPathPrivate *oldD = d; + d = other; + cleanup(oldD); + } +}; + // This value is used to determine the length of control point vectors // when approximating arc segments as curves. The factor is multiplied // with the radius of the circle. @@ -506,10 +524,10 @@ QPainterPath::QPainterPath() \sa operator=() */ QPainterPath::QPainterPath(const QPainterPath &other) - : d_ptr(other.d_ptr) + : d_ptr(other.d_ptr.data()) { - if (d_func()) - d_func()->ref.ref(); + if (d_ptr) + d_ptr->ref.ref(); } /*! @@ -530,9 +548,7 @@ QPainterPath::QPainterPath(const QPointF &startPoint) void QPainterPath::detach_helper() { QPainterPathPrivate *data = new QPainterPathData(*d_func()); - if (d_ptr && !d_ptr->ref.deref()) - delete d_ptr; - d_ptr = data; + d_ptr.reset(data); } /*! @@ -544,9 +560,7 @@ void QPainterPath::ensureData_helper() data->elements.reserve(16); QPainterPath::Element e = { 0, 0, QPainterPath::MoveToElement }; data->elements << e; - if (d_ptr && !d_ptr->ref.deref()) - delete d_ptr; - d_ptr = data; + d_ptr.reset(data); Q_ASSERT(d_ptr != 0); } @@ -563,9 +577,7 @@ QPainterPath &QPainterPath::operator=(const QPainterPath &other) QPainterPathPrivate *data = other.d_func(); if (data) data->ref.ref(); - if (d_ptr && !d_ptr->ref.deref()) - delete d_ptr; - d_ptr = data; + d_ptr.reset(data); } return *this; } @@ -575,8 +587,6 @@ QPainterPath &QPainterPath::operator=(const QPainterPath &other) */ QPainterPath::~QPainterPath() { - if (d_func() && !d_func()->ref.deref()) - delete d_func(); } /*! @@ -2464,7 +2474,6 @@ QPainterPathStroker::QPainterPathStroker() */ QPainterPathStroker::~QPainterPathStroker() { - delete d_ptr; } diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h index e343a28..cb3347a 100644 --- a/src/gui/painting/qpainterpath.h +++ b/src/gui/painting/qpainterpath.h @@ -47,6 +47,7 @@ #include <QtCore/qrect.h> #include <QtCore/qline.h> #include <QtCore/qvector.h> +#include <QtCore/qscopedpointer.h> QT_BEGIN_HEADER @@ -56,6 +57,7 @@ QT_MODULE(Gui) class QFont; class QPainterPathPrivate; +struct QPainterPathPrivateHandler; class QPainterPathData; class QPainterPathStrokerPrivate; class QPolygonF; @@ -201,7 +203,7 @@ public: QPainterPath &operator-=(const QPainterPath &other); private: - QPainterPathPrivate *d_ptr; + QScopedCustomPointer<QPainterPathPrivate, QPainterPathPrivateHandler> d_ptr; inline void ensureData() { if (!d_ptr) ensureData_helper(); } void ensureData_helper(); @@ -211,7 +213,7 @@ private: void computeBoundingRect() const; void computeControlPointRect() const; - QPainterPathData *d_func() const { return reinterpret_cast<QPainterPathData *>(d_ptr); } + QPainterPathData *d_func() const { return reinterpret_cast<QPainterPathData *>(d_ptr.data()); } friend class QPainterPathData; friend class QPainterPathStroker; @@ -235,6 +237,7 @@ public: friend class QPainterPathStrokerPrivate; friend class QMatrix; friend class QTransform; + friend struct QPainterPathPrivateHandler; #ifndef QT_NO_DATASTREAM friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QPainterPath &); friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QPainterPath &); @@ -285,7 +288,7 @@ public: private: friend class QX11PaintEngine; - QPainterPathStrokerPrivate *d_ptr; + QScopedPointer<QPainterPathStrokerPrivate> d_ptr; }; inline void QPainterPath::moveTo(qreal x, qreal y) diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h index 981ca84..8e14eb5 100644 --- a/src/gui/painting/qpathclipper_p.h +++ b/src/gui/painting/qpathclipper_p.h @@ -160,8 +160,6 @@ public: Direction directionTo(int vertex) const; int vertex(Direction direction) const; - bool isBezier() const; - private: int m_next[2][2]; }; @@ -347,11 +345,6 @@ inline int QPathEdge::vertex(Direction direction) const return direction == Backward ? first : second; } -inline bool QPathEdge::isBezier() const -{ - return bezier >= 0; -} - inline QPathVertex::QPathVertex(const QPointF &p, int e) : edge(e) , x(p.x()) diff --git a/src/gui/painting/qprinter.cpp b/src/gui/painting/qprinter.cpp index ce33893..0699de9 100644 --- a/src/gui/painting/qprinter.cpp +++ b/src/gui/painting/qprinter.cpp @@ -712,7 +712,6 @@ QPrinter::~QPrinter() #ifndef QT_NO_PRINTPREVIEWWIDGET delete d->previewEngine; #endif - delete d; } /*! diff --git a/src/gui/painting/qprinter.h b/src/gui/painting/qprinter.h index 949c8f9..24e867b 100644 --- a/src/gui/painting/qprinter.h +++ b/src/gui/painting/qprinter.h @@ -42,8 +42,9 @@ #ifndef QPRINTER_H #define QPRINTER_H -#include <QtGui/qpaintdevice.h> #include <QtCore/qstring.h> +#include <QtCore/qscopedpointer.h> +#include <QtGui/qpaintdevice.h> QT_BEGIN_HEADER @@ -288,7 +289,7 @@ private: Q_DISABLE_COPY(QPrinter) - QPrinterPrivate *d_ptr; + QScopedPointer<QPrinterPrivate> d_ptr; friend class QPrintDialogPrivate; friend class QAbstractPrintDialog; diff --git a/src/gui/painting/qprinterinfo.h b/src/gui/painting/qprinterinfo.h index b826306..d188d73 100644 --- a/src/gui/painting/qprinterinfo.h +++ b/src/gui/painting/qprinterinfo.h @@ -53,6 +53,7 @@ QT_MODULE(Gui) #ifndef QT_NO_PRINTER class QPrinterInfoPrivate; +class QPrinterInfoPrivateCleanup; class Q_GUI_EXPORT QPrinterInfo { Q_DECLARE_PRIVATE(QPrinterInfo) @@ -76,7 +77,7 @@ public: private: QPrinterInfo(const QString& name); - QPrinterInfoPrivate* d_ptr; + QScopedCustomPointer<QPrinterInfoPrivate, QPrinterInfoPrivateCleanup> d_ptr; }; #endif // QT_NO_PRINTER diff --git a/src/gui/painting/qprinterinfo_mac.cpp b/src/gui/painting/qprinterinfo_mac.cpp index ecd4b5b..ae689f4 100644 --- a/src/gui/painting/qprinterinfo_mac.cpp +++ b/src/gui/painting/qprinterinfo_mac.cpp @@ -65,6 +65,22 @@ private: static QPrinterInfoPrivate nullQPrinterInfoPrivate; +class QPrinterInfoPrivateCleanup +{ +public: + static inline void cleanup(QPrinterInfoPrivate *d) + { + if (d != &nullQPrinterInfoPrivate) + delete d; + } + + static inline void reset(QPrinterInfoPrivate *&d, QPrinterInfoPrivate *other) + { + cleanup(d); + d = other; + } +}; + extern QPrinter::PaperSize qSizeFTopaperSize(const QSizeF& size); ///////////////////////////////////////////////////////////////////////////// @@ -106,8 +122,8 @@ QPrinterInfo QPrinterInfo::defaultPrinter(){ ///////////////////////////////////////////////////////////////////////////// QPrinterInfo::QPrinterInfo(const QPrinter& prn) + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; QList<QPrinterInfo> list = availablePrinters(); for (int c = 0; c < list.size(); ++c) { if (prn.printerName() == list[c].printerName()) { @@ -115,39 +131,33 @@ QPrinterInfo::QPrinterInfo(const QPrinter& prn) return; } } - - *this = QPrinterInfo(); } QPrinterInfo::~QPrinterInfo() { - if (d_ptr != &nullQPrinterInfoPrivate) - delete d_ptr; } QPrinterInfo::QPrinterInfo() + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; } QPrinterInfo::QPrinterInfo(const QString& name) + : d_ptr(new QPrinterInfoPrivate(name)) { - d_ptr = new QPrinterInfoPrivate(name); d_ptr->q_ptr = this; } QPrinterInfo::QPrinterInfo(const QPrinterInfo& src) + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; *this = src; } QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src) { Q_ASSERT(d_ptr); - if (d_ptr != &nullQPrinterInfoPrivate) - delete d_ptr; - d_ptr = new QPrinterInfoPrivate(*src.d_ptr); + d_ptr.reset(new QPrinterInfoPrivate(*src.d_ptr)); d_ptr->q_ptr = this; return *this; } diff --git a/src/gui/painting/qprinterinfo_unix.cpp b/src/gui/painting/qprinterinfo_unix.cpp index 5724173..4887cf8 100644 --- a/src/gui/painting/qprinterinfo_unix.cpp +++ b/src/gui/painting/qprinterinfo_unix.cpp @@ -82,6 +82,22 @@ private: static QPrinterInfoPrivate nullQPrinterInfoPrivate; +class QPrinterInfoPrivateCleanup +{ +public: + static inline void cleanup(QPrinterInfoPrivate *d) + { + if (d != &nullQPrinterInfoPrivate) + delete d; + } + + static inline void reset(QPrinterInfoPrivate *&d, QPrinterInfoPrivate *other) + { + cleanup(d); + d = other; + } +}; + ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// @@ -867,19 +883,19 @@ QPrinterInfo QPrinterInfo::defaultPrinter() } QPrinterInfo::QPrinterInfo() + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; } QPrinterInfo::QPrinterInfo(const QPrinterInfo& src) + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; *this = src; } QPrinterInfo::QPrinterInfo(const QPrinter& printer) + : d_ptr(new QPrinterInfoPrivate(printer.printerName())) { - d_ptr = new QPrinterInfoPrivate(printer.printerName()); Q_D(QPrinterInfo); d->q_ptr = this; @@ -929,28 +945,23 @@ QPrinterInfo::QPrinterInfo(const QPrinter& printer) #endif // Printer not found. - delete d; - d_ptr = &nullQPrinterInfoPrivate; + d_ptr.reset(&nullQPrinterInfoPrivate); } QPrinterInfo::QPrinterInfo(const QString& name) + : d_ptr(new QPrinterInfoPrivate(name)) { - d_ptr = new QPrinterInfoPrivate(name); d_ptr->q_ptr = this; } QPrinterInfo::~QPrinterInfo() { - if (d_ptr != &nullQPrinterInfoPrivate) - delete d_ptr; } QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src) { Q_ASSERT(d_ptr); - if (d_ptr != &nullQPrinterInfoPrivate) - delete d_ptr; - d_ptr = new QPrinterInfoPrivate(*src.d_ptr); + d_ptr.reset(new QPrinterInfoPrivate(*src.d_ptr)); d_ptr->q_ptr = this; return *this; } diff --git a/src/gui/painting/qprinterinfo_win.cpp b/src/gui/painting/qprinterinfo_win.cpp index 7cd3cf3..7607391 100644 --- a/src/gui/painting/qprinterinfo_win.cpp +++ b/src/gui/painting/qprinterinfo_win.cpp @@ -69,6 +69,22 @@ private: static QPrinterInfoPrivate nullQPrinterInfoPrivate; +class QPrinterInfoPrivateCleanup +{ +public: + static inline void cleanup(QPrinterInfoPrivate *d) + { + if (d != &nullQPrinterInfoPrivate) + delete d; + } + + static inline void reset(QPrinterInfoPrivate *&d, QPrinterInfoPrivate *other) + { + cleanup(d); + d = other; + } +}; + ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// @@ -155,25 +171,25 @@ QPrinterInfo QPrinterInfo::defaultPrinter() ///////////////////////////////////////////////////////////////////////////// QPrinterInfo::QPrinterInfo() + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; } QPrinterInfo::QPrinterInfo(const QString& name) + : d_ptr(new QPrinterInfoPrivate(name)) { - d_ptr = new QPrinterInfoPrivate(name); d_ptr->q_ptr = this; } QPrinterInfo::QPrinterInfo(const QPrinterInfo& src) + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; *this = src; } QPrinterInfo::QPrinterInfo(const QPrinter& prn) + : d_ptr(&nullQPrinterInfoPrivate) { - d_ptr = &nullQPrinterInfoPrivate; QList<QPrinterInfo> list = availablePrinters(); for (int c = 0; c < list.size(); ++c) { if (prn.printerName() == list[c].printerName()) { @@ -187,16 +203,12 @@ QPrinterInfo::QPrinterInfo(const QPrinter& prn) QPrinterInfo::~QPrinterInfo() { - if (d_ptr != &nullQPrinterInfoPrivate) - delete d_ptr; } QPrinterInfo& QPrinterInfo::operator=(const QPrinterInfo& src) { Q_ASSERT(d_ptr); - if (d_ptr != &nullQPrinterInfoPrivate) - delete d_ptr; - d_ptr = new QPrinterInfoPrivate(*src.d_ptr); + d_ptr.reset(new QPrinterInfoPrivate(*src.d_ptr)); d_ptr->q_ptr = this; return *this; } diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index 583885c..3c06bb4 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -436,8 +436,11 @@ void QScanConverter::end() inline void QScanConverter::allocate(int size) { if (m_alloc < size) { - m_alloc = qMax(size, 2 * m_alloc); - m_intersections = (Intersection *)realloc(m_intersections, m_alloc * sizeof(Intersection)); + int newAlloc = qMax(size, 2 * m_alloc); + Intersection *newIntersections = (Intersection *)realloc(m_intersections, newAlloc * sizeof(Intersection)); + Q_CHECK_PTR(newIntersections); + m_alloc = newAlloc; + m_intersections = newIntersections; } } diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index c4cd77a..55f009f 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -3167,6 +3167,7 @@ static void InsertEdgeInET(EdgeTable *ET, EdgeTableEntry *ETE, int scanline, { tmpSLLBlock = (ScanLineListBlock *)malloc(sizeof(ScanLineListBlock)); + Q_CHECK_PTR(tmpSLLBlock); (*SLLBlock)->next = tmpSLLBlock; tmpSLLBlock->next = (ScanLineListBlock *)NULL; *SLLBlock = tmpSLLBlock; @@ -3553,6 +3554,8 @@ static void PtsToRegion(register int numFullPtBlocks, register int iCurPtBlock, * Scan converts a polygon by returning a run-length * encoding of the resultant bitmap -- the run-length * encoding is in the form of an array of rectangles. + * + * Can return 0 in case of errors. */ static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule) //Point *Pts; /* the pts */ @@ -3624,75 +3627,28 @@ static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule) } - if (rule == EvenOddRule) { - /* - * for each scanline - */ - for (y = ET.ymin; y < ET.ymax; ++y) { - - /* - * Add a new edge to the active edge table when we - * get to the next edge. - */ - if (pSLL && y == pSLL->scanline) { - loadAET(&AET, pSLL->edgelist); - pSLL = pSLL->next; - } - pPrevAET = &AET; - pAET = AET.next; - + QT_TRY { + if (rule == EvenOddRule) { /* - * for each active edge + * for each scanline */ - while (pAET) { - pts->setX(pAET->bres.minor_axis); - pts->setY(y); - ++pts; - ++iPts; + for (y = ET.ymin; y < ET.ymax; ++y) { /* - * send out the buffer + * Add a new edge to the active edge table when we + * get to the next edge. */ - if (iPts == NUMPTSTOBUFFER) { - tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK)); - tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data); - curPtBlock->next = tmpPtBlock; - curPtBlock = tmpPtBlock; - pts = curPtBlock->pts; - ++numFullPtBlocks; - iPts = 0; + if (pSLL && y == pSLL->scanline) { + loadAET(&AET, pSLL->edgelist); + pSLL = pSLL->next; } - EVALUATEEDGEEVENODD(pAET, pPrevAET, y) - } - InsertionSort(&AET); - } - } else { - /* - * for each scanline - */ - for (y = ET.ymin; y < ET.ymax; ++y) { - /* - * Add a new edge to the active edge table when we - * get to the next edge. - */ - if (pSLL && y == pSLL->scanline) { - loadAET(&AET, pSLL->edgelist); - computeWAET(&AET); - pSLL = pSLL->next; - } - pPrevAET = &AET; - pAET = AET.next; - pWETE = pAET; + pPrevAET = &AET; + pAET = AET.next; - /* - * for each active edge - */ - while (pAET) { /* - * add to the buffer only those edges that - * are in the Winding active edge table. + * for each active edge */ - if (pWETE == pAET) { + while (pAET) { pts->setX(pAET->bres.minor_axis); pts->setY(y); ++pts; @@ -3702,7 +3658,8 @@ static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule) * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { - tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK))); + tmpPtBlock = (POINTBLOCK *)malloc(sizeof(POINTBLOCK)); + Q_CHECK_PTR(tmpPtBlock); tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data); curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; @@ -3710,21 +3667,81 @@ static QRegionPrivate *PolygonRegion(const QPoint *Pts, int Count, int rule) ++numFullPtBlocks; iPts = 0; } - pWETE = pWETE->nextWETE; + EVALUATEEDGEEVENODD(pAET, pPrevAET, y) } - EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) + InsertionSort(&AET); } - + } else { /* - * recompute the winding active edge table if - * we just resorted or have exited an edge. + * for each scanline */ - if (InsertionSort(&AET) || fixWAET) { - computeWAET(&AET); - fixWAET = false; + for (y = ET.ymin; y < ET.ymax; ++y) { + /* + * Add a new edge to the active edge table when we + * get to the next edge. + */ + if (pSLL && y == pSLL->scanline) { + loadAET(&AET, pSLL->edgelist); + computeWAET(&AET); + pSLL = pSLL->next; + } + pPrevAET = &AET; + pAET = AET.next; + pWETE = pAET; + + /* + * for each active edge + */ + while (pAET) { + /* + * add to the buffer only those edges that + * are in the Winding active edge table. + */ + if (pWETE == pAET) { + pts->setX(pAET->bres.minor_axis); + pts->setY(y); + ++pts; + ++iPts; + + /* + * send out the buffer + */ + if (iPts == NUMPTSTOBUFFER) { + tmpPtBlock = static_cast<POINTBLOCK *>(malloc(sizeof(POINTBLOCK))); + tmpPtBlock->pts = reinterpret_cast<QPoint *>(tmpPtBlock->data); + curPtBlock->next = tmpPtBlock; + curPtBlock = tmpPtBlock; + pts = curPtBlock->pts; + ++numFullPtBlocks; + iPts = 0; + } + pWETE = pWETE->nextWETE; + } + EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) + } + + /* + * recompute the winding active edge table if + * we just resorted or have exited an edge. + */ + if (InsertionSort(&AET) || fixWAET) { + computeWAET(&AET); + fixWAET = false; + } } } + } QT_CATCH(...) { + FreeStorage(SLLBlock.next); + PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region); + for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { + tmpPtBlock = curPtBlock->next; + free(curPtBlock); + curPtBlock = tmpPtBlock; + } + free(pETEs); + return 0; // this function returns 0 in case of an error } + FreeStorage(SLLBlock.next); PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region); for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { @@ -3923,11 +3940,10 @@ QRegion &QRegion::operator=(const QRegion &r) /*! \internal */ - QRegion QRegion::copy() const { QRegion r; - QRegionData *x = new QRegionData; + QScopedPointer<QRegionData> x(new QRegionData); x->ref = 1; #if defined(Q_WS_X11) x->rgn = 0; @@ -3941,7 +3957,7 @@ QRegion QRegion::copy() const x->qt_rgn = new QRegionPrivate; if (!r.d->ref.deref()) cleanUp(r.d); - r.d = x; + r.d = x.take(); return r; } diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index c090877..f67b2b7 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -59,7 +59,7 @@ QT_MODULE(Gui) template <class T> class QVector; class QVariant; -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) +#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) struct QRegionPrivate; #endif @@ -199,7 +199,7 @@ private: #elif defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) mutable RgnHandle unused; // Here for binary compatability reasons. ### Qt 5 remove. #endif -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) +#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) QRegionPrivate *qt_rgn; #endif }; diff --git a/src/gui/painting/qregion_s60.cpp b/src/gui/painting/qregion_s60.cpp new file mode 100644 index 0000000..4d96910 --- /dev/null +++ b/src/gui/painting/qregion_s60.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbitmap.h" +#include "qbuffer.h" +#include "qimage.h" +#include "qpolygon.h" +#include "qregion.h" + +QT_BEGIN_NAMESPACE + +QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0 }; + +QT_END_NAMESPACE diff --git a/src/gui/painting/qtessellator.cpp b/src/gui/painting/qtessellator.cpp index 9b5efee..b3b636a 100644 --- a/src/gui/painting/qtessellator.cpp +++ b/src/gui/painting/qtessellator.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE #ifdef DEBUG #define QDEBUG qDebug #else -#define QDEBUG if (1); else qDebug +#define QDEBUG if (1){} else qDebug #endif static const bool emit_clever = true; @@ -703,7 +703,6 @@ struct QCoincidingEdge { } }; - static void cancelEdges(QCoincidingEdge &e1, QCoincidingEdge &e2) { if (e1.before) { diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp index 6d0d155..d1c8d4d 100644 --- a/src/gui/painting/qwindowsurface_raster.cpp +++ b/src/gui/painting/qwindowsurface_raster.cpp @@ -115,8 +115,6 @@ QRasterWindowSurface::~QRasterWindowSurface() #endif if (d_ptr->image) delete d_ptr->image; - - delete d_ptr; } diff --git a/src/gui/painting/qwindowsurface_raster_p.h b/src/gui/painting/qwindowsurface_raster_p.h index 2a3535f..c10bec3 100644 --- a/src/gui/painting/qwindowsurface_raster_p.h +++ b/src/gui/painting/qwindowsurface_raster_p.h @@ -112,7 +112,7 @@ public: private: void prepareBuffer(QImage::Format format, QWidget *widget); Q_DECLARE_PRIVATE(QRasterWindowSurface) - QRasterWindowSurfacePrivate *d_ptr; + QScopedPointer<QRasterWindowSurfacePrivate> d_ptr; }; QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp new file mode 100644 index 0000000..2a20b44 --- /dev/null +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> // for Q_WS_WIN define (non-PCH) + +#include <QtGui/qpaintdevice.h> +#include <private/qwidget_p.h> +#include "qwindowsurface_s60_p.h" +#include "qt_s60_p.h" +#include "private/qdrawhelper_p.h" + +QT_BEGIN_NAMESPACE + +struct QS60WindowSurfacePrivate +{ + QImage device; + CFbsBitmap *bitmap; + uchar* bytes; + + // Since only one CFbsBitmap is allowed to be locked at a time, this is static. + static QS60WindowSurface* lockedSurface; +}; +QS60WindowSurface* QS60WindowSurfacePrivate::lockedSurface = NULL; + +QS60WindowSurface::QS60WindowSurface(QWidget* widget) + : QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate) +{ + d_ptr->bytes = 0; + d_ptr->bitmap = 0; + + TDisplayMode mode = S60->screenDevice()->DisplayMode(); + bool isOpaque = qt_widget_private(widget)->isOpaque; + if (mode == EColor16MA && isOpaque) + mode = EColor16MU; // Faster since 16MU -> 16MA is typically accelerated + else if (mode == EColor16MU && !isOpaque) + mode = EColor16MA; // Try for transparency anyway + + + // We create empty CFbsBitmap here -> it will be resized in setGeometry + d_ptr->bitmap = new (ELeave) CFbsBitmap; + User::LeaveIfError( d_ptr->bitmap->Create(TSize(0, 0), mode ) ); + + updatePaintDeviceOnBitmap(); + + setStaticContentsSupport(true); +} + +QS60WindowSurface::~QS60WindowSurface() +{ + // Ensure that locking and unlocking of this surface were symmetrical + Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface != this); + + delete d_ptr->bitmap; + delete d_ptr; +} + +void QS60WindowSurface::beginPaint(const QRegion &rgn) +{ + if(!d_ptr->bitmap) + return; + + Q_ASSERT(!QS60WindowSurfacePrivate::lockedSurface); + QS60WindowSurfacePrivate::lockedSurface = this; + lockBitmapHeap(); + + if (!qt_widget_private(window())->isOpaque) { + QRgb *data = reinterpret_cast<QRgb *>(d_ptr->device.bits()); + const int row_stride = d_ptr->device.bytesPerLine() / 4; + + const QVector<QRect> rects = rgn.rects(); + for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { + const int x_start = it->x(); + const int width = it->width(); + + const int y_start = it->y(); + const int height = it->height(); + + QRgb *row = data + row_stride * y_start; + for (int y = 0; y < height; ++y) { + qt_memfill(row + x_start, 0U, width); + row += row_stride; + } + } + } +} + +void QS60WindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &) +{ + const QVector<QRect> subRects = region.rects(); + for (int i = 0; i < subRects.count(); ++i) { + TRect tr = qt_QRect2TRect(subRects[i]); + widget->winId()->DrawNow(tr); + } +} + +bool QS60WindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + QRect rect = area.boundingRect(); + + if (dx == 0 && dy == 0) + return false; + + if (d_ptr->device.isNull()) + return false; + + CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(d_ptr->bitmap); + CBitmapContext *bitmapContext; + TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); + if (err != KErrNone) { + CBase::Delete(bitmapDevice); + return false; + } + bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect)); + CBase::Delete(bitmapContext); + CBase::Delete(bitmapDevice); + return true; +} + +void QS60WindowSurface::endPaint(const QRegion &rgn) +{ + if(!d_ptr->bitmap) + return; + + Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface); + unlockBitmapHeap(); + QS60WindowSurfacePrivate::lockedSurface = NULL; +} + +QPaintDevice* QS60WindowSurface::paintDevice() +{ + return &d_ptr->device; +} + +void QS60WindowSurface::setGeometry(const QRect& rect) +{ + if (rect == geometry()) + return; + + QWindowSurface::setGeometry(rect); + + TRect nativeRect(qt_QRect2TRect(rect)); + User::LeaveIfError(d_ptr->bitmap->Resize(nativeRect.Size())); + + if (!rect.isNull()) + updatePaintDeviceOnBitmap(); +} + +void QS60WindowSurface::lockBitmapHeap() +{ + if (!QS60WindowSurfacePrivate::lockedSurface) + return; + + // Get some local variables to make later code lines more clear to read + CFbsBitmap*& bitmap = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap; + QImage& device = QS60WindowSurfacePrivate::lockedSurface->d_ptr->device; + uchar*& bytes = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bytes; + + bitmap->LockHeap(); + uchar *newBytes = (uchar*)bitmap->DataAddress(); + if (newBytes != bytes) { + bytes = newBytes; + + // Get some values for QImage creation + TDisplayMode mode = bitmap->DisplayMode(); + if (mode == EColor16MA + && qt_widget_private(QS60WindowSurfacePrivate::lockedSurface->window())->isOpaque) + mode = EColor16MU; + QImage::Format format = qt_TDisplayMode2Format( mode ); + TSize bitmapSize = bitmap->SizeInPixels(); + int bytesPerLine = CFbsBitmap::ScanLineLength( bitmapSize.iWidth, mode); + + device = QImage( bytes, bitmapSize.iWidth, bitmapSize.iHeight, bytesPerLine, format ); + } +} + +void QS60WindowSurface::unlockBitmapHeap() +{ + if (!QS60WindowSurfacePrivate::lockedSurface) + return; + + QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap->UnlockHeap(); +} + +void QS60WindowSurface::updatePaintDeviceOnBitmap() +{ + // This forces the actual device to be updated based on CFbsBitmap + beginPaint(QRegion()); + endPaint(QRegion()); +} + +CFbsBitmap *QS60WindowSurface::symbianBitmap() const +{ + return d_ptr->bitmap; +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_s60_p.h b/src/gui/painting/qwindowsurface_s60_p.h new file mode 100644 index 0000000..40a866d --- /dev/null +++ b/src/gui/painting/qwindowsurface_s60_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_S60_P_H +#define QWINDOWSURFACE_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qglobal.h> +#include "private/qwindowsurface_p.h" + +class CFbsBitmap; + +QT_BEGIN_NAMESPACE + +struct QS60WindowSurfacePrivate; + +class QS60WindowSurface : public QWindowSurface +{ +public: + QS60WindowSurface(QWidget *widget); + ~QS60WindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion &); + void endPaint(const QRegion &); + + void setGeometry(const QRect &rect); + + static void lockBitmapHeap(); + static void unlockBitmapHeap(); + + CFbsBitmap *symbianBitmap() const; + +private: + void updatePaintDeviceOnBitmap(); + +private: + QS60WindowSurfacePrivate* d_ptr; + +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSURFACE_S60_P_H diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp new file mode 100644 index 0000000..794e19f --- /dev/null +++ b/src/gui/styles/qs60style.cpp @@ -0,0 +1,2897 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qs60style_p.h" + +#include "qapplication.h" +#include "qpainter.h" +#include "qstyleoption.h" +#include "qevent.h" +#include "qpixmapcache.h" + +#include "qcalendarwidget.h" +#include "qdial.h" +#include "qdialog.h" +#include "qgroupbox.h" +#include "qheaderview.h" +#include "qlist.h" +#include "qlistwidget.h" +#include "qlistview.h" +#include "qmenu.h" +#include "qmenubar.h" +#include "qpushbutton.h" +#include "qscrollarea.h" +#include "qscrollbar.h" +#include "qtabbar.h" +#include "qtablewidget.h" +#include "qtableview.h" +#include "qtextedit.h" +#include "qtoolbar.h" +#include "qtoolbutton.h" +#include "qtreeview.h" + +#include "private/qtoolbarextension_p.h" +#include "private/qcombobox_p.h" +#include "private/qwidget_p.h" +#include "private/qapplication_p.h" + +#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +// from text/qfont.cpp +extern Q_GUI_EXPORT int qt_defaultDpiY(); + +const QS60StylePrivate::SkinElementFlags QS60StylePrivate::KDefaultSkinElementFlags = + SkinElementFlags(SF_PointNorth | SF_StateEnabled); + +static const QByteArray propertyKeyLayouts = "layouts"; +static const QByteArray propertyKeyCurrentlayout = "currentlayout"; + +const layoutHeader QS60StylePrivate::m_layoutHeaders[] = { +// *** generated layout data *** +{240,320,1,14,true,QLatin1String("QVGA Landscape Mirrored")}, +{240,320,1,14,false,QLatin1String("QVGA Landscape")}, +{320,240,1,14,true,QLatin1String("QVGA Portrait Mirrored")}, +{320,240,1,14,false,QLatin1String("QVGA Portrait")}, +{360,640,1,14,true,QLatin1String("NHD Landscape Mirrored")}, +{360,640,1,14,false,QLatin1String("NHD Landscape")}, +{640,360,1,14,true,QLatin1String("NHD Portrait Mirrored")}, +{640,360,1,14,false,QLatin1String("NHD Portrait")}, +{352,800,1,12,true,QLatin1String("E90 Landscape Mirrored")}, +{352,800,1,12,false,QLatin1String("E90 Landscape")} +// *** End of generated data *** +}; +const int QS60StylePrivate::m_numberOfLayouts = + (int)sizeof(QS60StylePrivate::m_layoutHeaders)/sizeof(QS60StylePrivate::m_layoutHeaders[0]); + +const short QS60StylePrivate::data[][MAX_PIXELMETRICS] = { +// *** generated pixel metrics *** +{5,0,-909,0,0,1,0,0,-1,8,15,22,15,15,7,198,-909,-909,-909,19,15,2,0,0,21,-909,21,-909,4,4,1,-909,-909,0,2,0,0,13,23,17,17,21,21,2,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,51,27,51,4,4,5,10,15,-909,5,58,12,5,0,7,4,4,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{5,0,-909,0,0,1,0,0,-1,8,15,22,15,15,7,198,-909,-909,-909,19,15,2,0,0,21,-909,21,-909,4,4,1,-909,-909,0,2,0,0,13,23,17,17,21,21,2,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,51,27,51,4,4,5,10,15,-909,5,58,12,5,0,4,4,7,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{5,0,-909,0,0,1,0,0,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,-909,27,-909,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,4,4,5,10,15,-909,5,58,13,5,0,7,4,4,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{5,0,-909,0,0,1,0,0,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,-909,27,-909,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,4,4,5,10,15,-909,5,58,13,5,0,4,4,7,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,53,28,19,19,9,258,-909,-909,-909,29,19,26,0,0,32,-909,72,-909,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,5,5,6,8,19,-909,7,74,19,7,0,8,5,5,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,53,28,19,19,9,258,-909,-909,-909,29,19,26,0,0,32,-909,72,-909,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,5,5,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,52,28,19,19,9,258,-909,-909,-909,29,19,6,0,0,32,-909,60,-909,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,98,35,98,5,5,6,8,19,-909,7,74,22,7,0,8,5,5,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,52,28,19,19,9,258,-909,-909,-909,29,19,6,0,0,32,-909,60,-909,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,98,35,98,5,5,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,-909,32,-909,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,5,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,8,6,5,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1}, +{7,0,-909,0,0,2,0,0,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,-909,32,-909,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,6,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,5,6,8,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1} +// *** End of generated data *** +}; + +const short *QS60StylePrivate::m_pmPointer = QS60StylePrivate::data[0]; + +// theme background texture +QPixmap *QS60StylePrivate::m_background = 0; + +// theme palette +QPalette *QS60StylePrivate::m_themePalette = 0; + +const struct QS60StylePrivate::frameElementCenter QS60StylePrivate::m_frameElementsData[] = { + {SE_ButtonNormal, QS60StyleEnums::SP_QsnFrButtonTbCenter}, + {SE_ButtonPressed, QS60StyleEnums::SP_QsnFrButtonTbCenterPressed}, + {SE_FrameLineEdit, QS60StyleEnums::SP_QsnFrInputCenter}, + {SE_ListHighlight, QS60StyleEnums::SP_QsnFrListCenter}, + {SE_OptionsMenu, QS60StyleEnums::SP_QsnFrPopupCenter}, + {SE_SettingsList, QS60StyleEnums::SP_QsnFrSetOptCenter}, + {SE_TableItem, QS60StyleEnums::SP_QsnFrCaleCenter}, + {SE_TableHeaderItem, QS60StyleEnums::SP_QsnFrCaleHeadingCenter}, + {SE_ToolTip, QS60StyleEnums::SP_QsnFrPopupPreviewCenter}, + {SE_ToolBar, QS60StyleEnums::SP_QsnFrPopupSubCenter}, + {SE_ToolBarButton, QS60StyleEnums::SP_QsnFrSctrlButtonCenter}, + {SE_ToolBarButtonPressed, QS60StyleEnums::SP_QsnFrSctrlButtonCenterPressed}, + {SE_PanelBackground, QS60StyleEnums::SP_QsnFrSetOptCenter}, + {SE_ButtonInactive, QS60StyleEnums::SP_QsnFrButtonCenterInactive}, + {SE_Editor, QS60StyleEnums::SP_QsnFrNotepadCenter}, +}; + +static const int frameElementsCount = + int(sizeof(QS60StylePrivate::m_frameElementsData)/sizeof(QS60StylePrivate::m_frameElementsData[0])); + +const int KNotFound = -909; +const double KTabFontMul = 0.72; + +QS60StylePrivate::~QS60StylePrivate() +{ + clearCaches(); //deletes also background image + deleteThemePalette(); +} + +void QS60StylePrivate::drawSkinElement(SkinElements element, QPainter *painter, + const QRect &rect, SkinElementFlags flags) +{ + switch (element) { + case SE_ButtonNormal: + drawFrame(SF_ButtonNormal, painter, rect, flags | SF_PointNorth); + break; + case SE_ButtonPressed: + drawFrame(SF_ButtonPressed, painter, rect, flags | SF_PointNorth); + break; + case SE_FrameLineEdit: + drawFrame(SF_FrameLineEdit, painter, rect, flags | SF_PointNorth); + break; + case SE_ProgressBarGrooveHorizontal: + drawRow(QS60StyleEnums::SP_QgnGrafBarFrameSideL, QS60StyleEnums::SP_QgnGrafBarFrameCenter, + QS60StyleEnums::SP_QgnGrafBarFrameSideR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); + break; + case SE_ProgressBarGrooveVertical: + drawRow(QS60StyleEnums::SP_QgnGrafBarFrameSideL, QS60StyleEnums::SP_QgnGrafBarFrameCenter, + QS60StyleEnums::SP_QgnGrafBarFrameSideR, Qt::Vertical, painter, rect, flags | SF_PointEast); + break; + case SE_ProgressBarIndicatorHorizontal: + drawPart(QS60StyleEnums::SP_QgnGrafBarProgress, painter, rect, flags | SF_PointNorth); + break; + case SE_ProgressBarIndicatorVertical: + drawPart(QS60StyleEnums::SP_QgnGrafBarProgress, painter, rect, flags | SF_PointWest); + break; + case SE_ScrollBarGrooveHorizontal: + drawRow(QS60StyleEnums::SP_QsnCpScrollBgBottom, QS60StyleEnums::SP_QsnCpScrollBgMiddle, + QS60StyleEnums::SP_QsnCpScrollBgTop, Qt::Horizontal, painter, rect, flags | SF_PointEast); + break; + case SE_ScrollBarGrooveVertical: + drawRow(QS60StyleEnums::SP_QsnCpScrollBgTop, QS60StyleEnums::SP_QsnCpScrollBgMiddle, + QS60StyleEnums::SP_QsnCpScrollBgBottom, Qt::Vertical, painter, rect, flags | SF_PointNorth); + break; + case SE_ScrollBarHandleHorizontal: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleBottom, QS60StyleEnums::SP_QsnCpScrollHandleMiddle, + QS60StyleEnums::SP_QsnCpScrollHandleTop, Qt::Horizontal, painter, rect, flags | SF_PointEast); + break; + case SE_ScrollBarHandleVertical: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleTop, QS60StyleEnums::SP_QsnCpScrollHandleMiddle, + QS60StyleEnums::SP_QsnCpScrollHandleBottom, Qt::Vertical, painter, rect, flags | SF_PointNorth); + break; + case SE_SliderHandleHorizontal: + drawPart(QS60StyleEnums::SP_QgnIndiSliderEdit, painter, rect, flags | SF_PointNorth); + break; + case SE_SliderHandleVertical: + drawPart(QS60StyleEnums::SP_QgnIndiSliderEdit, painter, rect, flags | SF_PointEast); + break; + case SE_TabBarTabEastActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveL, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveR, Qt::Vertical, painter, rect, flags | SF_PointEast); + break; + case SE_TabBarTabEastInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveL, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveR, Qt::Vertical, painter, rect, flags | SF_PointEast); + break; + case SE_TabBarTabNorthActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveL, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); + break; + case SE_TabBarTabNorthInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveL, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); + break; + case SE_TabBarTabSouthActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveR, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveL, Qt::Horizontal, painter, rect, flags | SF_PointSouth); + break; + case SE_TabBarTabSouthInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveR, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveL, Qt::Horizontal, painter, rect, flags | SF_PointSouth); + break; + case SE_TabBarTabWestActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveR, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveL, Qt::Vertical, painter, rect, flags | SF_PointWest); + break; + case SE_TabBarTabWestInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveR, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveL, Qt::Vertical, painter, rect, flags | SF_PointWest); + break; + case SE_ListHighlight: + drawFrame(SF_ListHighlight, painter, rect, flags | SF_PointNorth); + break; + case SE_OptionsMenu: + drawFrame(SF_OptionsMenu, painter, rect, flags | SF_PointNorth); + break; + case SE_SettingsList: + drawFrame(SF_SettingsList, painter, rect, flags | SF_PointNorth); + break; + case SE_TableItem: + drawFrame(SF_TableItem, painter, rect, flags | SF_PointNorth); + break; + case SE_TableHeaderItem: + drawFrame(SF_TableHeaderItem, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolTip: + drawFrame(SF_ToolTip, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolBar: + drawFrame(SF_ToolBar, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolBarButton: + drawFrame(SF_ToolBarButton, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolBarButtonPressed: + drawFrame(SF_ToolBarButtonPressed, painter, rect, flags | SF_PointNorth); + break; + case SE_PanelBackground: + drawFrame(SF_PanelBackground, painter, rect, flags | SF_PointNorth); + break; + case SE_ScrollBarHandlePressedHorizontal: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed, QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed, + QS60StyleEnums::SP_QsnCpScrollHandleTopPressed, Qt::Horizontal, painter, rect, flags | SF_PointEast); + break; + case SE_ScrollBarHandlePressedVertical: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleTopPressed, QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed, + QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed, Qt::Vertical, painter, rect, flags | SF_PointNorth); + break; + case SE_ButtonInactive: + drawFrame(SF_ButtonInactive, painter, rect, flags | SF_PointNorth); + break; + case SE_Editor: + drawFrame(SF_Editor, painter, rect, flags | SF_PointNorth); + break; + default: + break; + } +} + +void QS60StylePrivate::drawSkinPart(QS60StyleEnums::SkinParts part, + QPainter *painter, const QRect &rect, SkinElementFlags flags) +{ + drawPart(part, painter, rect, flags); +} + +short QS60StylePrivate::pixelMetric(int metric) +{ + Q_ASSERT(metric < MAX_PIXELMETRICS); + const short returnValue = m_pmPointer[metric]; + return returnValue; +} + +void QS60StylePrivate::setStyleProperty(const char *name, const QVariant &value) +{ + if (name == propertyKeyCurrentlayout) { + static const QStringList layouts = styleProperty(propertyKeyLayouts).toStringList(); + const QString layout = value.toString(); + Q_ASSERT(layouts.contains(layout)); + const int layoutIndex = layouts.indexOf(layout); + setCurrentLayout(layoutIndex); + QApplication::setLayoutDirection(m_layoutHeaders[layoutIndex].mirroring ? Qt::RightToLeft : Qt::LeftToRight); + clearCaches(); + refreshUI(); + } +} + +QVariant QS60StylePrivate::styleProperty(const char *name) const +{ + if (name == propertyKeyLayouts) { + static QStringList layouts; + if (layouts.isEmpty()) + for (int i = 0; i < m_numberOfLayouts; i++) + layouts.append(m_layoutHeaders[i].layoutName); + return layouts; + } + return QVariant(); +} + +QColor QS60StylePrivate::stateColor(const QColor &color, const QStyleOption *option) +{ + QColor retColor (color); + if (option && !(option->state & QStyle::State_Enabled)) { + QColor hsvColor = retColor.toHsv(); + int colorSat = hsvColor.saturation(); + int colorVal = hsvColor.value(); + colorSat = (colorSat!=0) ? (colorSat>>1) : 128; + colorVal = (colorVal!=0) ? (colorVal>>1) : 128; + hsvColor.setHsv(hsvColor.hue(), colorSat, colorVal); + retColor = hsvColor.toRgb(); + } + return retColor; +} + +QColor QS60StylePrivate::lighterColor(const QColor &baseColor) +{ + QColor result(baseColor); + bool modifyColor = false; + if (result.saturation() == 0) { + result.setHsv(result.hue(), 128, result.value()); + modifyColor = true; + } + if (result.value() == 0) { + result.setHsv(result.hue(), result.saturation(), 128); + modifyColor = true; + } + if (modifyColor) + result = result.lighter(175); + else + result = result.lighter(225); + return result; +} + +bool QS60StylePrivate::drawsOwnThemeBackground(const QWidget *widget) +{ + return qobject_cast<const QDialog *> (widget); +} + +QFont QS60StylePrivate::s60Font( + QS60StyleEnums::FontCategories fontCategory, int pointSize) const +{ + QFont result; + int actualPointSize = pointSize; + if (actualPointSize <= 0) { + const QFont appFont = QApplication::font(); + actualPointSize = appFont.pointSize(); + if (actualPointSize <= 0) + actualPointSize = appFont.pixelSize() * 72 / qt_defaultDpiY(); + } + Q_ASSERT(actualPointSize > 0); + const QPair<QS60StyleEnums::FontCategories, int> key(fontCategory, actualPointSize); + if (!m_mappedFontsCache.contains(key)) { + result = s60Font_specific(fontCategory, actualPointSize); + m_mappedFontsCache.insert(key, result); + } else { + result = m_mappedFontsCache.value(key); + if (result.pointSize() != actualPointSize) + result.setPointSize(actualPointSize); + } + return result; +} + +void QS60StylePrivate::clearCaches(CacheClearReason reason) +{ + switch(reason){ + case CC_LayoutChange: + // when layout changes, the colors remain in cache, but graphics and fonts can change + m_mappedFontsCache.clear(); + deleteBackground(); + QPixmapCache::clear(); + break; + case CC_ThemeChange: + m_colorCache.clear(); + QPixmapCache::clear(); + deleteBackground(); + break; + case CC_UndefinedChange: + default: + m_colorCache.clear(); + m_mappedFontsCache.clear(); + QPixmapCache::clear(); + deleteBackground(); + break; + } +} + +// Since S60Style has 'button' and 'tooltip' as a graphic, we don't have any native color which to use +// for QPalette::Button and QPalette::ToolTipBase. Therefore S60Style needs to guesstimate +// palette colors by calculating average rgb values for button pixels. +// Returns Qt::black if there is an issue with the graphics (image is NULL, or no bits() found). +QColor QS60StylePrivate::colorFromFrameGraphics(SkinFrameElements frame) const +{ + const bool cachedColorExists = m_colorCache.contains(frame); + if (!cachedColorExists) { + const int frameCornerWidth = pixelMetric(PM_Custom_FrameCornerWidth); + const int frameCornerHeight = pixelMetric(PM_Custom_FrameCornerHeight); + Q_ASSERT(2*frameCornerWidth<32); + Q_ASSERT(2*frameCornerHeight<32); + + const QImage frameImage = QS60StylePrivate::frame(frame, QSize(32,32)).toImage(); + if (frameImage.isNull()) + return Qt::black; + + const QRgb *pixelRgb = (const QRgb*)frameImage.bits(); + const int pixels = frameImage.numBytes()/sizeof(QRgb); + const int bytesPerLine = frameImage.bytesPerLine(); + Q_ASSERT(bytesPerLine); + + int estimatedRed = 0; + int estimatedGreen = 0; + int estimatedBlue = 0; + + int skips = 0; + int estimations = 0; + + const int topBorderLastPixel = frameCornerHeight*frameImage.width()-1; + const int bottomBorderFirstPixel = frameImage.width()*frameImage.height()-frameCornerHeight*frameImage.width()-1; + const int rightBorderFirstPixel = frameImage.width()-frameCornerWidth; + const int leftBorderLastPixel = frameCornerWidth; + + while ((skips + estimations) < pixels) { + if ((skips+estimations) > topBorderLastPixel && + (skips+estimations) < bottomBorderFirstPixel) { + for (int rowIndex = 0; rowIndex < frameImage.width(); rowIndex++) { + if (rowIndex > leftBorderLastPixel && + rowIndex < rightBorderFirstPixel) { + estimatedRed += qRed(*pixelRgb); + estimatedGreen += qGreen(*pixelRgb); + estimatedBlue += qBlue(*pixelRgb); + } + pixelRgb++; + estimations++; + } + } else { + pixelRgb++; + skips++; + } + } + QColor frameColor(estimatedRed/estimations, estimatedGreen/estimations, estimatedBlue/estimations); + m_colorCache.insert(frame, frameColor); + return !estimations ? Qt::black : frameColor; + } else { + return m_colorCache.value(frame); + } + +} + +void QS60StylePrivate::setThemePalette(QApplication *app) const +{ + Q_UNUSED(app) + QPalette widgetPalette = QPalette(Qt::white); + setThemePalette(&widgetPalette); + QApplication::setPalette(widgetPalette); //calling QApplication::setPalette clears palette hash + setThemePaletteHash(&widgetPalette); + storeThemePalette(&widgetPalette); +} + +void QS60StylePrivate::setThemePalette(QStyleOption *option) const +{ + setThemePalette(&option->palette); +} + +QPalette* QS60StylePrivate::themePalette() +{ + return m_themePalette; +} + +void QS60StylePrivate::setBackgroundTexture(QApplication *app) const +{ + Q_UNUSED(app) + QPalette applicationPalette = QApplication::palette(); + applicationPalette.setBrush(QPalette::Window, backgroundTexture()); + QApplication::setPalette(applicationPalette); +} + +void QS60StylePrivate::deleteBackground() +{ + if (m_background) { + delete m_background; + m_background = 0; + } +} + +int QS60StylePrivate::focusRectPenWidth() +{ + return pixelMetric(QS60Style::PM_DefaultFrameWidth); +} + +void QS60StylePrivate::setCurrentLayout(int index) +{ + m_pmPointer = data[index]; +} + +void QS60StylePrivate::drawPart(QS60StyleEnums::SkinParts skinPart, + QPainter *painter, const QRect &rect, SkinElementFlags flags) +{ + static const bool doCache = +#if defined(Q_WS_S60) + // Freezes on 3.1. Anyways, caching is only really needed on touch UI + !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); +#else + true; +#endif + const QPixmap skinPartPixMap((doCache ? cachedPart : part)(skinPart, rect.size(), flags)); + if (!skinPartPixMap.isNull()) + painter->drawPixmap(rect.topLeft(), skinPartPixMap); +} + +void QS60StylePrivate::drawFrame(SkinFrameElements frameElement, QPainter *painter, const QRect &rect, SkinElementFlags flags) +{ + static const bool doCache = +#if defined(Q_WS_S60) + // Freezes on 3.1. Anyways, caching is only really needed on touch UI + !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); +#else + true; +#endif + const QPixmap frameElementPixMap((doCache ? cachedFrame : frame)(frameElement, rect.size(), flags)); + if (!frameElementPixMap.isNull()) + painter->drawPixmap(rect.topLeft(), frameElementPixMap); +} + +void QS60StylePrivate::drawRow(QS60StyleEnums::SkinParts start, + QS60StyleEnums::SkinParts middle, QS60StyleEnums::SkinParts end, + Qt::Orientation orientation, QPainter *painter, const QRect &rect, + SkinElementFlags flags) +{ + QSize startEndSize(partSize(start, flags)); + startEndSize.scale(rect.size(), Qt::KeepAspectRatio); + + QRect startRect = QRect(rect.topLeft(), startEndSize); + QRect middleRect = rect; + QRect endRect; + + if (orientation == Qt::Horizontal) { + startRect.setWidth(qMin((rect.width() >> 1) - 1, startRect.width())); + endRect = startRect.translated(rect.width() - startRect.width(), 0); + middleRect.adjust(startRect.width(), 0, -startRect.width(), 0); + if (startRect.bottomRight().x() > endRect.topLeft().x()) { + const int overlap = (startRect.bottomRight().x() - endRect.topLeft().x())>>1; + startRect.setWidth(startRect.width()-overlap); + endRect.adjust(overlap,0,0,0); + } + } else { + startRect.setHeight(qMin((rect.height() >> 1) - 1, startRect.height())); + endRect = startRect.translated(0, rect.height() - startRect.height()); + middleRect.adjust(0, startRect.height(), 0, -startRect.height()); + if (startRect.topRight().y() > endRect.bottomLeft().y()) { + const int overlap = (startRect.topRight().y() - endRect.bottomLeft().y())>>1; + startRect.setHeight(startRect.height()-overlap); + endRect.adjust(0,overlap,0,0); + } + } + +#if 0 + painter->save(); + painter->setOpacity(.3); + painter->fillRect(startRect, Qt::red); + painter->fillRect(middleRect, Qt::green); + painter->fillRect(endRect, Qt::blue); + painter->restore(); +#else + drawPart(start, painter, startRect, flags); + if (middleRect.isValid()) + drawPart(middle, painter, middleRect, flags); + drawPart(end, painter, endRect, flags); +#endif +} + +QPixmap QS60StylePrivate::cachedPart(QS60StyleEnums::SkinParts part, + const QSize &size, SkinElementFlags flags) +{ + QPixmap result; + const QString cacheKey = + QString::fromLatin1("S60Style: SkinParts=%1 QSize=%2|%3 SkinPartFlags=%4") + .arg((int)part).arg(size.width()).arg(size.height()).arg((int)flags); + if (!QPixmapCache::find(cacheKey, result)) { + result = QS60StylePrivate::part(part, size, flags); + QPixmapCache::insert(cacheKey, result); + } + return result; +} + +QPixmap QS60StylePrivate::cachedFrame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags) +{ + QPixmap result; + const QString cacheKey = + QString::fromLatin1("S60Style: SkinFrameElements=%1 QSize=%2|%3 SkinElementFlags=%4") + .arg((int)frame).arg(size.width()).arg(size.height()).arg((int)flags); + if (!QPixmapCache::find(cacheKey, result)) { + result = QS60StylePrivate::frame(frame, size, flags); + QPixmapCache::insert(cacheKey, result); + } + return result; +} + +void QS60StylePrivate::refreshUI() +{ + QList<QWidget *> widgets = QApplication::allWidgets(); + + for (int i = 0; i < widgets.size(); ++i) { + QWidget *widget = widgets.at(i); + if (widget == 0) + continue; + + if (widget->style()) { + widget->style()->polish(widget); + QEvent event(QEvent::StyleChange); + qApp->sendEvent(widget, &event); + } + widget->update(); + widget->updateGeometry(); + } +} + +void QS60StylePrivate::setFont(QWidget *widget) const +{ + QS60StyleEnums::FontCategories fontCategory = QS60StyleEnums::FC_Undefined; + if (!widget) + return; + if (qobject_cast<QPushButton *>(widget)){ + fontCategory = QS60StyleEnums::FC_Primary; + } else if (qobject_cast<QToolButton *>(widget)){ + fontCategory = QS60StyleEnums::FC_Primary; + } else if (qobject_cast<QHeaderView *>(widget)){ + fontCategory = QS60StyleEnums::FC_Secondary; + } else if (qobject_cast<QGroupBox *>(widget)){ + fontCategory = QS60StyleEnums::FC_Title; + } + if (fontCategory != QS60StyleEnums::FC_Undefined) { + const QFont suggestedFont = + s60Font(fontCategory, widget->font().pointSizeF()); + widget->setFont(suggestedFont); + } +} + +void QS60StylePrivate::setThemePalette(QWidget *widget) const +{ + if(!widget) + return; + QPalette widgetPalette = QApplication::palette(widget); + + //header view and its viewport need to be set 100% transparent button color, since drawing code will + //draw transparent theme graphics to table column and row headers. + if (qobject_cast<QHeaderView *>(widget)){ + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 23, 0)); + QHeaderView* header = qobject_cast<QHeaderView *>(widget); + widgetPalette.setColor(QPalette::Button, Qt::transparent ); + if ( header->viewport() ) + header->viewport()->setPalette(widgetPalette); + QApplication::setPalette(widgetPalette, "QHeaderView"); + } +} + +void QS60StylePrivate::setThemePalette(QPalette *palette) const +{ + if (!palette) + return; + + // basic colors + palette->setColor(QPalette::WindowText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + palette->setColor(QPalette::ButtonText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + palette->setColor(QPalette::Text, + s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + palette->setColor(QPalette::ToolTipText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 55, 0)); + palette->setColor(QPalette::BrightText, palette->color(QPalette::WindowText).lighter()); + palette->setColor(QPalette::HighlightedText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 10, 0)); + palette->setColor(QPalette::Link, + s60Color(QS60StyleEnums::CL_QsnHighlightColors, 3, 0)); + palette->setColor(QPalette::LinkVisited, palette->color(QPalette::Link).darker()); + palette->setColor(QPalette::Highlight, + s60Color(QS60StyleEnums::CL_QsnHighlightColors, 2, 0)); + // set background image as a texture brush + palette->setBrush(QPalette::Window, backgroundTexture()); + // set these as transparent so that styled full screen theme background is visible + palette->setColor(QPalette::AlternateBase, Qt::transparent); + palette->setBrush(QPalette::Base, Qt::transparent); + // set button and tooltipbase based on pixel colors + const QColor buttonColor = this->colorFromFrameGraphics(SF_ButtonNormal); + palette->setColor(QPalette::Button, buttonColor ); + const QColor toolTipColor = this->colorFromFrameGraphics(SF_ToolTip); + palette->setColor(QPalette::ToolTipBase, toolTipColor ); + palette->setColor(QPalette::Light, palette->color(QPalette::Button).lighter()); + palette->setColor(QPalette::Dark, palette->color(QPalette::Button).darker()); + palette->setColor(QPalette::Midlight, palette->color(QPalette::Button).lighter(125)); + palette->setColor(QPalette::Mid, palette->color(QPalette::Button).darker(150)); + palette->setColor(QPalette::Shadow, Qt::black); +} + +void QS60StylePrivate::deleteThemePalette() +{ + if (m_themePalette) { + delete m_themePalette; + m_themePalette = 0; + } +} + +void QS60StylePrivate::storeThemePalette(QPalette *palette) +{ + deleteThemePalette(); + //store specified palette for latter use. + m_themePalette = new QPalette(*palette); +} + +// set widget specific palettes +void QS60StylePrivate::setThemePaletteHash(QPalette *palette) const +{ + if (!palette) + return; + + //store the original palette + QPalette widgetPalette = *palette; + const QColor mainAreaTextColor = + s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0); + + widgetPalette.setColor(QPalette::All, QPalette::WindowText, + s60Color(QS60StyleEnums::CL_QsnLineColors, 8, 0)); + QApplication::setPalette(widgetPalette, "QSlider"); + // return to original palette after each widget + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, mainAreaTextColor); + widgetPalette.setColor(QPalette::Inactive, QPalette::ButtonText, mainAreaTextColor); + const QStyleOption opt; + widgetPalette.setColor(QPalette::Disabled, QPalette::ButtonText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 6, &opt)); + QApplication::setPalette(widgetPalette, "QPushButton"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, mainAreaTextColor); + widgetPalette.setColor(QPalette::Inactive, QPalette::ButtonText, mainAreaTextColor); + QApplication::setPalette(widgetPalette, "QToolButton"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 23, 0)); + QApplication::setPalette(widgetPalette, "QHeaderView"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::ButtonText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 8, 0)); + QApplication::setPalette(widgetPalette, "QMenuBar"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::WindowText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 4, 0)); + QApplication::setPalette(widgetPalette, "QTabBar"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::Text, + s60Color(QS60StyleEnums::CL_QsnTextColors, 22, 0)); + QApplication::setPalette(widgetPalette, "QTableView"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::HighlightedText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); + QApplication::setPalette(widgetPalette, "QLineEdit"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::Text, + s60Color(QS60StyleEnums::CL_QsnTextColors, 34, 0)); + widgetPalette.setColor(QPalette::All, QPalette::HighlightedText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); + QApplication::setPalette(widgetPalette, "QTextEdit"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::HighlightedText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); + QApplication::setPalette(widgetPalette, "QComboBox"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::WindowText, mainAreaTextColor); + widgetPalette.setColor(QPalette::Button, QApplication::palette().color(QPalette::Button)); + widgetPalette.setColor(QPalette::Dark, mainAreaTextColor.darker()); + widgetPalette.setColor(QPalette::Light, mainAreaTextColor.lighter()); + QApplication::setPalette(widgetPalette, "QDial"); + widgetPalette = *palette; + + widgetPalette.setBrush(QPalette::Window, QBrush()); + QApplication::setPalette(widgetPalette, "QScrollArea"); + widgetPalette = *palette; +} + +QSize QS60StylePrivate::partSize(QS60StyleEnums::SkinParts part, SkinElementFlags flags) +{ + QSize result(20, 20); + switch (part) + { + case QS60StyleEnums::SP_QgnGrafBarProgress: + result.setWidth(pixelMetric(QStyle::PM_ProgressBarChunkWidth)); + break; + case QS60StyleEnums::SP_QgnGrafTabActiveM: + case QS60StyleEnums::SP_QgnGrafTabPassiveM: + case QS60StyleEnums::SP_QgnGrafTabActiveR: + case QS60StyleEnums::SP_QgnGrafTabPassiveR: + case QS60StyleEnums::SP_QgnGrafTabPassiveL: + case QS60StyleEnums::SP_QgnGrafTabActiveL: + break; + case QS60StyleEnums::SP_QgnIndiSliderEdit: + result.scale(pixelMetric(QStyle::PM_SliderLength), + pixelMetric(QStyle::PM_SliderControlThickness), Qt::IgnoreAspectRatio); + break; + + case QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed: + case QS60StyleEnums::SP_QsnCpScrollHandleTopPressed: + case QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed: + case QS60StyleEnums::SP_QsnCpScrollBgBottom: + case QS60StyleEnums::SP_QsnCpScrollBgMiddle: + case QS60StyleEnums::SP_QsnCpScrollBgTop: + case QS60StyleEnums::SP_QsnCpScrollHandleBottom: + case QS60StyleEnums::SP_QsnCpScrollHandleMiddle: + case QS60StyleEnums::SP_QsnCpScrollHandleTop: + result.setHeight(pixelMetric(QStyle::PM_ScrollBarExtent)); + result.setWidth(pixelMetric(QStyle::PM_ScrollBarExtent)); + break; + default: + // Generic frame part size gathering. + for (int i = 0; i < frameElementsCount; ++i) + { + switch (m_frameElementsData[i].center - part) { + case 8: /* CornerTl */ + case 7: /* CornerTr */ + case 6: /* CornerBl */ + case 5: /* CornerBr */ + result.setWidth(pixelMetric(PM_Custom_FrameCornerWidth)); + // Falltrough intended... + case 4: /* SideT */ + case 3: /* SideB */ + result.setHeight(pixelMetric(PM_Custom_FrameCornerHeight)); + break; + case 2: /* SideL */ + case 1: /* SideR */ + result.setWidth(pixelMetric(PM_Custom_FrameCornerWidth)); + break; + case 0: /* center */ + default: + break; + } + } + break; + } + if (flags & (SF_PointEast | SF_PointWest)) { + const int temp = result.width(); + result.setWidth(result.height()); + result.setHeight(temp); + } + return result; +} + +/*! + \class QS60Style + \brief The QS60Style class provides a look and feel suitable for applications on S60. + \since 4.6 + \ingroup appearance + + \sa QMacStyle, QWindowsStyle, QWindowsXPStyle, QWindowsVistaStyle, QPlastiqueStyle, QCleanlooksStyle, QMotifStyle +*/ + +QS60Style::~QS60Style() +{ +} + +/*! + \reimp +*/ +void QS60Style::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; + SubControls sub = option->subControls; + + switch (control) { +#ifndef QT_NO_SCROLLBAR + case CC_ScrollBar: + if (const QStyleOptionSlider *optionSlider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { + const bool horizontal = optionSlider->orientation == Qt::Horizontal; + + const QRect scrollBarSlider = subControlRect(control, optionSlider, SC_ScrollBarSlider, widget); + const QRect grooveRect = subControlRect(control, optionSlider, SC_ScrollBarGroove, widget); + + const QS60StylePrivate::SkinElements grooveElement = + horizontal ? QS60StylePrivate::SE_ScrollBarGrooveHorizontal : QS60StylePrivate::SE_ScrollBarGrooveVertical; + QS60StylePrivate::drawSkinElement(grooveElement, painter, grooveRect, flags); + + const QStyle::SubControls subControls = optionSlider->subControls; + + // select correct slider (horizontal/vertical/pressed) + const bool sliderPressed = ((optionSlider->state & QStyle::State_Sunken) && (subControls & SC_ScrollBarSlider)); + const QS60StylePrivate::SkinElements handleElement = + horizontal ? + ( sliderPressed ? + QS60StylePrivate::SE_ScrollBarHandlePressedHorizontal : + QS60StylePrivate::SE_ScrollBarHandleHorizontal ) : + ( sliderPressed ? + QS60StylePrivate::SE_ScrollBarHandlePressedVertical : + QS60StylePrivate::SE_ScrollBarHandleVertical); + QS60StylePrivate::drawSkinElement(handleElement, painter, scrollBarSlider, flags); + } + break; +#endif // QT_NO_SCROLLBAR +#ifndef QT_NO_SLIDER + case CC_Slider: + if (const QStyleOptionSlider *optionSlider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { + + // The groove is just a centered line. Maybe a qgn_graf_line_* at some point + const QRect sliderGroove = subControlRect(control, optionSlider, SC_SliderGroove, widget); + const QPoint sliderGrooveCenter = sliderGroove.center(); + const bool horizontal = optionSlider->orientation == Qt::Horizontal; + painter->save(); + if (widget) + painter->setPen(widget->palette().windowText().color()); + if (horizontal) + painter->drawLine(0, sliderGrooveCenter.y(), sliderGroove.right(), sliderGrooveCenter.y()); + else + painter->drawLine(sliderGrooveCenter.x(), 0, sliderGrooveCenter.x(), sliderGroove.bottom()); + painter->restore(); + + const QRect sliderHandle = subControlRect(control, optionSlider, SC_SliderHandle, widget); + const QS60StylePrivate::SkinElements handleElement = + horizontal ? QS60StylePrivate::SE_SliderHandleHorizontal : QS60StylePrivate::SE_SliderHandleVertical; + QS60StylePrivate::drawSkinElement(handleElement, painter, sliderHandle, flags); + + if (optionSlider->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*optionSlider); + fropt.rect = subElementRect(SE_SliderFocusRect, optionSlider, widget); + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + break; +#endif // QT_NO_SLIDER +#ifndef QT_NO_COMBOBOX + case CC_ComboBox: + if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + const QRect cmbxEditField = subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget); + const QRect cmbxFrame = subControlRect(CC_ComboBox, option, SC_ComboBoxFrame, widget); + const bool direction = cmb->direction == Qt::LeftToRight; + + // Button frame + QStyleOptionFrame buttonOption; + buttonOption.QStyleOption::operator=(*cmb); + const int maxHeight = cmbxFrame.height(); + const int maxWidth = cmbxFrame.width() - cmbxEditField.width(); + const int topLeftPoint = direction ? cmbxEditField.right()+1 : cmbxEditField.left()+1-maxWidth; + const QRect buttonRect(topLeftPoint, cmbxEditField.top(), maxWidth, maxHeight); + buttonOption.rect = buttonRect; + buttonOption.state = cmb->state & (State_Enabled | State_MouseOver); + drawPrimitive(PE_PanelButtonCommand, &buttonOption, painter, widget); + + // draw label background - label itself is drawn separately + const QS60StylePrivate::SkinElements skinElement = QS60StylePrivate::SE_FrameLineEdit; + QS60StylePrivate::drawSkinElement(skinElement, painter, cmbxEditField, flags); + + // Draw the combobox arrow + if (sub & SC_ComboBoxArrow) { + // Make rect slightly smaller + buttonOption.rect.adjust(1, 1, -1, -1); + painter->save(); + painter->setPen(option->palette.buttonText().color()); + drawPrimitive(PE_IndicatorSpinDown, &buttonOption, painter, widget); + painter->restore(); + } + + if (cmb->subControls & SC_ComboBoxEditField) { + if (cmb->state & State_HasFocus && !cmb->editable) { + QStyleOptionFocusRect focus; + focus.QStyleOption::operator=(*cmb); + focus.rect = cmbxEditField; + focus.state |= State_FocusAtBorder; + focus.backgroundColor = cmb->palette.highlight().color(); + drawPrimitive(PE_FrameFocusRect, &focus, painter, widget); + } + } + } + break; +#endif // QT_NO_COMBOBOX +#ifndef QT_NO_TOOLBUTTON + case CC_ToolButton: + if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast<const QStyleOptionToolButton *>(option)) { + const State bflags = toolBtn->state; + const QRect button(subControlRect(control, toolBtn, SC_ToolButton, widget)); + QStyleOptionToolButton toolButton = *toolBtn; + + if (sub&SC_ToolButton) { + QStyleOption tool(0); + tool.palette = toolBtn->palette; + + // Check if toolbutton is in toolbar. + QToolBar *toolBar = 0; + if (widget) + toolBar = qobject_cast<QToolBar *>(widget->parentWidget()); + + if (bflags & (State_Sunken | State_On | State_Raised)) { + tool.rect = button; + tool.state = bflags; + + // todo: I'd like to move extension button next to where last button is + // however, the painter seems to want to clip the button rect even if I turn of the clipping. + if (toolBar && (qobject_cast<const QToolBarExtension *>(widget))){ + /*QList<QAction *> actionList = toolBar->actions(); + const int actionCount = actionList.count(); + const int toolbarWidth = toolBar->width(); + const int extButtonWidth = pixelMetric(PM_ToolBarExtensionExtent, option, widget); + const int toolBarButtonWidth = pixelMetric(PM_ToolBarIconSize, option, widget); + const int frame = pixelMetric(PM_ToolBarFrameWidth, option, widget); + const int margin = pixelMetric(PM_ToolBarItemMargin, option, widget); + const int border = frame + margin; + const int spacing = pixelMetric(PM_ToolBarItemSpacing, option, widget); + const int toolBarButtonArea = toolbarWidth - extButtonWidth - spacing - 2*border; + const int numberOfVisibleButtons = toolBarButtonArea / toolBarButtonWidth; + // new extension button place is after border and all the other visible buttons (with spacings) + const int newXForExtensionButton = numberOfVisibleButtons * toolBarButtonWidth + (numberOfVisibleButtons-1)*spacing + border; + painter->save(); + painter->setClipping(false); + tool.rect.translate(-newXForExtensionButton,0); + painter->restore();*/ + } + + if (toolBar){ + /*if (toolBar->orientation() == Qt::Vertical){ + // todo: I'd like to make all vertical buttons the same size, but again the painter + // prefers to use clipping for button rects, even though clipping has been set off. + painter->save(); + painter->setClipping(false); + + const int origWidth = tool.rect.width(); + const int newWidth = toolBar->width()-2*pixelMetric(PM_ToolBarFrameWidth, option, widget); + painter->translate(origWidth-newWidth,0); + tool.rect.translate(origWidth-tool.rect.width(),0); + tool.rect.setWidth(newWidth); + + if (option->state & QStyle::State_Sunken) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButtonPressed, painter, tool.rect, flags); + else + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButton, painter, tool.rect, flags); + + }*/ + if (option->state & QStyle::State_Sunken) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButtonPressed, painter, tool.rect, flags); + else + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButton, painter, tool.rect, flags); + /* + if (toolBar->orientation() == Qt::Vertical) + painter->restore(); + */ + } else { + drawPrimitive(PE_PanelButtonTool, &tool, painter, widget); + } + } + } + if (toolBtn->state & State_HasFocus) { + QStyleOptionFocusRect fr; + fr.QStyleOption::operator=(*toolBtn); + const int frameWidth = pixelMetric(PM_DefaultFrameWidth, option, widget); + fr.rect.adjust(frameWidth, frameWidth, -frameWidth, -frameWidth); + drawPrimitive(PE_FrameFocusRect, &fr, painter, widget); + } + + if (toolBtn->features & QStyleOptionToolButton::Arrow) { + QStyle::PrimitiveElement pe; + switch (toolBtn->arrowType) { + case Qt::LeftArrow: + pe = QStyle::PE_IndicatorArrowLeft; + break; + case Qt::RightArrow: + pe = QStyle::PE_IndicatorArrowRight; + break; + case Qt::UpArrow: + pe = QStyle::PE_IndicatorArrowUp; + break; + case Qt::DownArrow: + pe = QStyle::PE_IndicatorArrowDown; + break; + default: + break; } + toolButton.rect = button; + drawPrimitive(pe, &toolButton, painter, widget); + } + + if (toolBtn->text.length()>0 || + !toolBtn->icon.isNull()) { + const int frameWidth = pixelMetric(PM_DefaultFrameWidth, option, widget); + toolButton.rect = button.adjusted(frameWidth, frameWidth, -frameWidth, -frameWidth); + drawControl(CE_ToolButtonLabel, &toolButton, painter, widget); + } + } + break; +#endif //QT_NO_TOOLBUTTON +#ifndef QT_NO_SPINBOX + case CC_SpinBox: + if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + QStyleOptionSpinBox copy = *spinBox; + PrimitiveElement pe; + + if (spinBox->subControls & SC_SpinBoxUp) { + copy.subControls = SC_SpinBoxUp; + QPalette spinBoxPal = spinBox->palette; + if (!(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled)) { + spinBoxPal.setCurrentColorGroup(QPalette::Disabled); + copy.state &= ~State_Enabled; + copy.palette = spinBoxPal; + } + + if (spinBox->activeSubControls == SC_SpinBoxUp && (spinBox->state & State_Sunken)) { + copy.state |= State_On; + copy.state |= State_Sunken; + } else { + copy.state |= State_Raised; + copy.state &= ~State_Sunken; + } + pe = (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) ? + PE_IndicatorSpinPlus : + PE_IndicatorSpinUp; + + copy.rect = subControlRect(CC_SpinBox, spinBox, SC_SpinBoxUp, widget); + drawPrimitive(PE_PanelButtonBevel, ©, painter, widget); + copy.rect.adjust(1, 1, -1, -1); + drawPrimitive(pe, ©, painter, widget); + } + + if (spinBox->subControls & SC_SpinBoxDown) { + copy.subControls = SC_SpinBoxDown; + copy.state = spinBox->state; + QPalette spinBoxPal = spinBox->palette; + if (!(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled)) { + spinBoxPal.setCurrentColorGroup(QPalette::Disabled); + copy.state &= ~State_Enabled; + copy.palette = spinBoxPal; + } + + if (spinBox->activeSubControls == SC_SpinBoxDown && (spinBox->state & State_Sunken)) { + copy.state |= State_On; + copy.state |= State_Sunken; + } else { + copy.state |= State_Raised; + copy.state &= ~State_Sunken; + } + pe = (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) ? + PE_IndicatorSpinMinus : + PE_IndicatorSpinDown; + + copy.rect = subControlRect(CC_SpinBox, spinBox, SC_SpinBoxDown, widget); + drawPrimitive(PE_PanelButtonBevel, ©, painter, widget); + copy.rect.adjust(1, 1, -1, -1); + drawPrimitive(pe, ©, painter, widget); + } + } + break; +#endif //QT_NO_SPINBOX +#ifndef QT_NO_GROUPBOX + case CC_GroupBox: + if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) { + // Draw frame + const QRect textRect = subControlRect(CC_GroupBox, option, SC_GroupBoxLabel, widget); + const QRect checkBoxRect = subControlRect(CC_GroupBox, option, SC_GroupBoxCheckBox, widget); + if (groupBox->subControls & QStyle::SC_GroupBoxFrame) { + QStyleOptionFrameV2 frame; + frame.QStyleOption::operator=(*groupBox); + frame.features = groupBox->features; + frame.lineWidth = groupBox->lineWidth; + frame.midLineWidth = groupBox->midLineWidth; + frame.rect = subControlRect(CC_GroupBox, option, SC_GroupBoxFrame, widget); + drawPrimitive(PE_FrameGroupBox, &frame, painter, widget); + } + + // Draw title + if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) { + const QColor textColor = groupBox->textColor; + painter->save(); + + if (textColor.isValid()) + painter->setPen(textColor); + int alignment = int(groupBox->textAlignment); + if (!styleHint(QStyle::SH_UnderlineShortcut, option, widget)) + alignment |= Qt::TextHideMnemonic; + + drawItemText(painter, textRect, Qt::TextShowMnemonic | Qt::AlignHCenter | Qt::AlignVCenter | alignment, + groupBox->palette, groupBox->state & State_Enabled, groupBox->text, + textColor.isValid() ? QPalette::NoRole : QPalette::WindowText); + painter->restore(); + + if (groupBox->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*groupBox); + fropt.rect = textRect; + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + + // Draw checkbox + if (groupBox->subControls & SC_GroupBoxCheckBox) { + QStyleOptionButton box; + box.QStyleOption::operator=(*groupBox); + box.rect = checkBoxRect; + drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget); + } + } + break; +#endif //QT_NO_GROUPBOX + default: + QCommonStyle::drawComplexControl(control, option, painter, widget); + } +} + +/*! + \reimp +*/ +void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + Q_D(const QS60Style); + const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; + switch (element) { + case CE_PushButton: + if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) { + + drawControl(CE_PushButtonBevel, btn, painter, widget); + QStyleOptionButton subopt = *btn; + subopt.rect = subElementRect(SE_PushButtonContents, btn, widget); + + drawControl(CE_PushButtonLabel, &subopt, painter, widget); + if (btn->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*btn); + fropt.rect = subElementRect(SE_PushButtonFocusRect, btn, widget); + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + break; + case CE_PushButtonBevel: + if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) { + const bool isDisabled = !(option->state & QStyle::State_Enabled); + const bool isFlat = button->features & QStyleOptionButton::Flat; + QS60StyleEnums::SkinParts skinPart; + QS60StylePrivate::SkinElements skinElement; + if (!isDisabled) { + const bool isPressed = (option->state & QStyle::State_Sunken) || + (option->state & QStyle::State_On); + if (isFlat) { + skinPart = + isPressed ? QS60StyleEnums::SP_QsnFrButtonTbCenterPressed : QS60StyleEnums::SP_QsnFrButtonTbCenter; + } else { + skinElement = + isPressed ? QS60StylePrivate::SE_ButtonPressed : QS60StylePrivate::SE_ButtonNormal; + } + } else { + if (isFlat) + skinPart =QS60StyleEnums::SP_QsnFrButtonCenterInactive; + else + skinElement = QS60StylePrivate::SE_ButtonInactive; + } + if (isFlat) + QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); + else + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; +#ifndef QT_NO_TOOLBUTTON + case CE_ToolButtonLabel: + if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast<const QStyleOptionToolButton *>(option)) { + QStyleOptionToolButton optionToolButton = *toolBtn; + + if (!optionToolButton.icon.isNull() && (optionToolButton.state & QStyle::State_Sunken) + && (optionToolButton.state & State_Enabled)) { + + const QIcon::State state = optionToolButton.state & State_On ? QIcon::On : QIcon::Off; + const QPixmap pm(optionToolButton.icon.pixmap(optionToolButton.rect.size().boundedTo(optionToolButton.iconSize), + QIcon::Normal, state)); + optionToolButton.icon = generatedIconPixmap(QIcon::Selected, pm, &optionToolButton); + } + + QCommonStyle::drawControl(element, &optionToolButton, painter, widget); + } + break; +#endif //QT_NO_TOOLBUTTON +#ifndef QT_NO_COMBOBOX + case CE_ComboBoxLabel: + if (const QStyleOptionComboBox *comboBox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + QStyleOption optionComboBox = *comboBox; + optionComboBox.palette.setColor(QPalette::Active, QPalette::WindowText, + optionComboBox.palette.text().color() ); + optionComboBox.palette.setColor(QPalette::Inactive, QPalette::WindowText, + optionComboBox.palette.text().color() ); + QRect editRect = subControlRect(CC_ComboBox, comboBox, SC_ComboBoxEditField, widget); + painter->save(); + painter->setClipRect(editRect); + + if (!comboBox->currentIcon.isNull()) { + QIcon::Mode mode = comboBox->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; + QPixmap pixmap = comboBox->currentIcon.pixmap(comboBox->iconSize, mode); + QRect iconRect(editRect); + iconRect.setWidth(comboBox->iconSize.width() + 4); + iconRect = alignedRect(comboBox->direction, + Qt::AlignLeft | Qt::AlignVCenter, + iconRect.size(), editRect); + if (comboBox->editable) + painter->fillRect(iconRect, optionComboBox.palette.brush(QPalette::Base)); + drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + + if (comboBox->direction == Qt::RightToLeft) + editRect.translate(-4 - comboBox->iconSize.width(), 0); + else + editRect.translate(comboBox->iconSize.width() + 4, 0); + } + if (!comboBox->currentText.isEmpty() && !comboBox->editable) { + QCommonStyle::drawItemText(painter, + editRect.adjusted(QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth), 0, -1, 0), + visualAlignment(comboBox->direction, Qt::AlignLeft | Qt::AlignVCenter), + comboBox->palette, comboBox->state & State_Enabled, comboBox->currentText); + } + painter->restore(); + } + break; +#endif //QT_NO_COMBOBOX +#ifndef QT_NO_ITEMVIEWS + case CE_ItemViewItem: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) { + QStyleOptionViewItemV4 voptAdj = *vopt; + painter->save(); + + painter->setClipRect(voptAdj.rect); + const bool isSelected = (voptAdj.state & QStyle::State_HasFocus); + + bool isVisible = false; + int scrollBarWidth = 0; + QList<QScrollBar *> scrollBars = qFindChildren<QScrollBar *>(widget); + for (int i = 0; i < scrollBars.size(); ++i) { + QScrollBar *scrollBar = scrollBars.at(i); + if (scrollBar && scrollBar->orientation() == Qt::Vertical) { + isVisible = scrollBar->isVisible(); + scrollBarWidth = scrollBar->size().width(); + break; + } + } + + int rightValue = widget ? widget->contentsRect().right() : 0; + + if (isVisible) + rightValue -= scrollBarWidth; + + if (voptAdj.rect.right() > rightValue) + voptAdj.rect.setRight(rightValue); + + const QRect iconRect = subElementRect(SE_ItemViewItemDecoration, &voptAdj, widget); + QRect textRect = subElementRect(SE_ItemViewItemText, &voptAdj, widget); + + // draw themed background for table unless background brush has been defined. + if (vopt->backgroundBrush == Qt::NoBrush) { + const QStyleOptionViewItemV4 *tableOption = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option); + const QTableView *table = qobject_cast<const QTableView *>(widget); + if (table && tableOption) { + const QModelIndex index = tableOption->index; + //todo: Draw cell background only once - for the first cell. + QStyleOptionViewItemV4 voptAdj2 = voptAdj; + const QModelIndex indexFirst = table->model()->index(0,0); + const QModelIndex indexLast = table->model()->index( + table->model()->rowCount()-1,table->model()->columnCount()-1); + if (table->viewport()) + voptAdj2.rect = QRect( table->visualRect(indexFirst).topLeft(), + table->visualRect(indexLast).bottomRight()).intersect(table->viewport()->rect()); + drawPrimitive(PE_PanelItemViewItem, &voptAdj2, painter, widget); + } + } else { QCommonStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget);} + + // draw the focus rect + if (isSelected) { + const QRect highlightRect = option->rect.adjusted(1,1,-1,-1); + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ListHighlight, painter, highlightRect, flags); + } + + // draw the icon + const QIcon::Mode mode = (voptAdj.state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled; + const QIcon::State state = voptAdj.state & QStyle::State_Open ? QIcon::On : QIcon::Off; + voptAdj.icon.paint(painter, iconRect, voptAdj.decorationAlignment, mode, state); + + // Draw selection check mark. Show check mark only in multi selection modes. + if (const QListView *listView = (qobject_cast<const QListView *>(widget))) { + const bool singleSelection = + listView && + (listView->selectionMode() == QAbstractItemView::SingleSelection || + listView->selectionMode() == QAbstractItemView::NoSelection); + const QRect selectionRect = subElementRect(SE_ItemViewItemCheckIndicator, &voptAdj, widget); + if (voptAdj.state & QStyle::State_Selected && !singleSelection) { + QStyleOptionViewItemV4 option(voptAdj); + option.rect = selectionRect; + // Draw selection mark. + drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &option, painter, widget); + if ( textRect.right() > selectionRect.left() ) + textRect.setRight(selectionRect.left()); + } else if (singleSelection && + voptAdj.features & QStyleOptionViewItemV2::HasCheckIndicator) { + // draw the check mark + if (selectionRect.isValid()) { + QStyleOptionViewItemV4 option(*vopt); + option.rect = selectionRect; + option.state = option.state & ~QStyle::State_HasFocus; + + switch (vopt->checkState) { + case Qt::Unchecked: + option.state |= QStyle::State_Off; + break; + case Qt::PartiallyChecked: + option.state |= QStyle::State_NoChange; + break; + case Qt::Checked: + option.state |= QStyle::State_On; + break; + } + drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &option, painter, widget); + } + } + } + + // draw the text + if (!voptAdj.text.isEmpty()) { + const QStyleOptionViewItemV4 *tableOption = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option); + if (isSelected) { + if (qobject_cast<const QTableView *>(widget) && tableOption) + voptAdj.palette.setColor( + QPalette::Text, QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 11, 0)); + else + voptAdj.palette.setColor( + QPalette::Text, QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 10, 0)); + } + painter->setPen(voptAdj.palette.text().color()); + d->viewItemDrawText(painter, &voptAdj, textRect); + } + painter->restore(); + } + break; +#endif // QT_NO_ITEMVIEWS +#ifndef QT_NO_TABBAR + case CE_TabBarTabShape: + if (const QStyleOptionTabV3 *optionTab = qstyleoption_cast<const QStyleOptionTabV3 *>(option)) { + QStyleOptionTabV3 optionTabAdj = *optionTab; + const bool isSelected = optionTab->state & QStyle::State_Selected; + const bool directionMirrored = (optionTab->direction == Qt::RightToLeft); + QS60StylePrivate::SkinElements skinElement; + switch (optionTab->shape) { + case QTabBar::TriangularEast: + case QTabBar::RoundedEast: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabEastActive: + QS60StylePrivate::SE_TabBarTabEastInactive; + break; + case QTabBar::TriangularSouth: + case QTabBar::RoundedSouth: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabSouthActive: + QS60StylePrivate::SE_TabBarTabSouthInactive; + break; + case QTabBar::TriangularWest: + case QTabBar::RoundedWest: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabWestActive: + QS60StylePrivate::SE_TabBarTabWestInactive; + break; + case QTabBar::TriangularNorth: + case QTabBar::RoundedNorth: + default: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabNorthActive: + QS60StylePrivate::SE_TabBarTabNorthInactive; + break; + } + if (skinElement==QS60StylePrivate::SE_TabBarTabEastInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabNorthInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabSouthInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabEastActive|| + skinElement==QS60StylePrivate::SE_TabBarTabNorthActive|| + skinElement==QS60StylePrivate::SE_TabBarTabSouthActive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestActive) { + const int borderThickness = + QS60StylePrivate::pixelMetric(QStyle::PM_DefaultFrameWidth); + const int tabOverlap = + QS60StylePrivate::pixelMetric(QStyle::PM_TabBarTabOverlap) - borderThickness; + //todo: draw navi wipe behind tabbar - must be drawn with first draw + + if (skinElement==QS60StylePrivate::SE_TabBarTabEastInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabEastActive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestActive){ + optionTabAdj.rect.adjust(0, 0, 0, tabOverlap); + } else { + if (directionMirrored) + optionTabAdj.rect.adjust(-tabOverlap, 0, 0, 0); + else + optionTabAdj.rect.adjust(0, 0, tabOverlap, 0); + } + } + QS60StylePrivate::drawSkinElement(skinElement, painter, optionTabAdj.rect, flags); + } + break; + case CE_TabBarTabLabel: + if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(option)) { + QStyleOptionTabV3 optionTab = *tab; + QRect tr = optionTab.rect; + const bool directionMirrored = (optionTab.direction == Qt::RightToLeft); + const int borderThickness = QS60StylePrivate::pixelMetric(QStyle::PM_DefaultFrameWidth); + const int tabOverlap = + QS60StylePrivate::pixelMetric(QStyle::PM_TabBarTabOverlap) - borderThickness; + const QRect windowRect = painter->window(); + + switch (tab->shape) { + case QTabBar::TriangularWest: + case QTabBar::RoundedWest: + case QTabBar::TriangularEast: + case QTabBar::RoundedEast: + tr.adjust(0, 0, 0, tabOverlap); + break; + case QTabBar::TriangularSouth: + case QTabBar::RoundedSouth: + case QTabBar::TriangularNorth: + case QTabBar::RoundedNorth: + default: + if (directionMirrored) + tr.adjust(-tabOverlap, 0, 0, 0); + else + tr.adjust(0, 0, tabOverlap, 0); + break; + } + painter->save(); + QFont f = painter->font(); + f.setPointSizeF(f.pointSizeF() * KTabFontMul); + painter->setFont(f); + + if (option->state & QStyle::State_Selected){ + optionTab.palette.setColor(QPalette::Active, QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 3, option)); + } + + const bool verticalTabs = optionTab.shape == QTabBar::RoundedEast + || optionTab.shape == QTabBar::RoundedWest + || optionTab.shape == QTabBar::TriangularEast + || optionTab.shape == QTabBar::TriangularWest; + const bool selected = optionTab.state & State_Selected; + if (verticalTabs) { + painter->save(); + int newX, newY, newRotation; + if (optionTab.shape == QTabBar::RoundedEast || optionTab.shape == QTabBar::TriangularEast) { + newX = tr.width(); + newY = tr.y(); + newRotation = 90; + } else { + newX = 0; + newY = tr.y() + tr.height(); + newRotation = -90; + } + tr.setRect(0, 0, tr.height(), tr.width()); + QTransform m; + m.translate(newX, newY); + m.rotate(newRotation); + painter->setTransform(m, true); + } + tr.adjust(0, 0, pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget), + pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget)); + + if (selected) { + tr.setBottom(tr.bottom() - pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget)); + tr.setRight(tr.right() - pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget)); + } + + int alignment = Qt::AlignCenter | Qt::TextShowMnemonic; + if (!styleHint(SH_UnderlineShortcut, &optionTab, widget)) + alignment |= Qt::TextHideMnemonic; + if (!optionTab.icon.isNull()) { + QSize iconSize = optionTab.iconSize; + int iconExtent = pixelMetric(PM_TabBarIconSize); + if (iconSize.height() > iconExtent || iconSize.width() > iconExtent) + iconSize = QSize(iconExtent, iconExtent); + QPixmap tabIcon = optionTab.icon.pixmap(iconSize, + (optionTab.state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); + if (tab->text.isEmpty()) + painter->drawPixmap(tr.center().x() - (tabIcon.height() >>1), + tr.center().y() - (tabIcon.height() >>1), + tabIcon); + else + painter->drawPixmap(tr.left() + tabOverlap, + tr.center().y() - (tabIcon.height() >>1), + tabIcon); + tr.setLeft(tr.left() + iconSize.width() + 4); + } + + QCommonStyle::drawItemText(painter, tr, alignment, optionTab.palette, tab->state & State_Enabled, tab->text, QPalette::WindowText); + if (verticalTabs) + painter->restore(); + + if (optionTab.state & State_HasFocus) { + const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth); + const int leftBorder = optionTab.rect.left(); + const int rightBorder = optionTab.rect.right() - 1; + + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*tab); + fropt.rect.setRect(leftBorder + 1 + OFFSET, optionTab.rect.y() + OFFSET, + rightBorder - leftBorder - 2*OFFSET, optionTab.rect.height() - 2*OFFSET); + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + + painter->restore(); + } + break; +#endif // QT_NO_TABBAR +#ifndef QT_NO_PROGRESSBAR + case CE_ProgressBarContents: + if (const QStyleOptionProgressBarV2 *optionProgressBar = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { + QRect progressRect = optionProgressBar->rect; + + if (optionProgressBar->minimum == optionProgressBar->maximum && optionProgressBar->minimum == 0) { + // busy indicator + QS60StylePrivate::drawSkinPart(QS60StyleEnums::SP_QgnGrafBarWait, painter, progressRect,flags); + } else { + const qreal progressFactor = (optionProgressBar->minimum == optionProgressBar->maximum) ? 1.0 + : (qreal)optionProgressBar->progress / optionProgressBar->maximum; + if (optionProgressBar->orientation == Qt::Horizontal) { + progressRect.setWidth(int(progressRect.width() * progressFactor)); + if(optionProgressBar->direction == Qt::RightToLeft) + progressRect.translate(optionProgressBar->rect.width()-progressRect.width(),0); + progressRect.adjust(1, 0, -1, 0); + } else { + progressRect.adjust(0, 1, 0, -1); + progressRect.setTop(progressRect.bottom() - int(progressRect.height() * progressFactor)); + } + + const QS60StylePrivate::SkinElements skinElement = optionProgressBar->orientation == Qt::Horizontal ? + QS60StylePrivate::SE_ProgressBarIndicatorHorizontal : QS60StylePrivate::SE_ProgressBarIndicatorVertical; + QS60StylePrivate::drawSkinElement(skinElement, painter, progressRect, flags); + } + } + break; + case CE_ProgressBarGroove: + if (const QStyleOptionProgressBarV2 *optionProgressBar = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { + const QS60StylePrivate::SkinElements skinElement = optionProgressBar->orientation == Qt::Horizontal ? + QS60StylePrivate::SE_ProgressBarGrooveHorizontal : QS60StylePrivate::SE_ProgressBarGrooveVertical; + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; + case CE_ProgressBarLabel: + if (const QStyleOptionProgressBarV2 *progressbar = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { + QStyleOptionProgressBarV2 optionProgressBar = *progressbar; + QCommonStyle::drawItemText(painter, progressbar->rect, flags | Qt::AlignCenter | Qt::TextSingleLine, optionProgressBar.palette, + progressbar->state & State_Enabled, progressbar->text, QPalette::WindowText); + } + break; +#endif // QT_NO_PROGRESSBAR +#ifndef QT_NO_MENU + case CE_MenuItem: + if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { + QStyleOptionMenuItem optionMenuItem = *menuItem; + + bool drawSubMenuIndicator = false; + switch(menuItem->menuItemType) { + case QStyleOptionMenuItem::Scroller: + case QStyleOptionMenuItem::Separator: + return; // no separators or scrollers in S60 menus + case QStyleOptionMenuItem::SubMenu: + drawSubMenuIndicator = true; + break; + default: + break; + } + const bool enabled = optionMenuItem.state & State_Enabled; + const bool checkable = optionMenuItem.checkType != QStyleOptionMenuItem::NotCheckable; + + uint text_flags = Qt::AlignLeading | Qt::TextShowMnemonic | Qt::TextDontClip + | Qt::TextSingleLine | Qt::AlignVCenter; + if (!styleHint(SH_UnderlineShortcut, menuItem, widget)) + text_flags |= Qt::TextHideMnemonic; + + QRect iconRect = + subElementRect(SE_ItemViewItemDecoration, &optionMenuItem, widget); + QRect textRect = subElementRect(SE_ItemViewItemText, &optionMenuItem, widget); + + if ((option->state & State_Selected) && (option->state & State_Enabled)) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ListHighlight, painter, option->rect, flags); + + //todo: move the vertical spacing stuff into subElementRect + const int vSpacing = QS60StylePrivate::pixelMetric(QStyle::PM_LayoutVerticalSpacing); + if (checkable){ + QStyleOptionMenuItem optionCheckBox; + optionCheckBox.QStyleOption::operator=(*menuItem); + optionCheckBox.rect.setWidth(pixelMetric(PM_IndicatorWidth)); + optionCheckBox.rect.setHeight(pixelMetric(PM_IndicatorHeight)); + const int moveByX = optionCheckBox.rect.width()+vSpacing; + if (optionMenuItem.direction == Qt::LeftToRight) { + textRect.translate(moveByX,0); + iconRect.translate(moveByX, 0); + iconRect.setWidth(iconRect.width()+vSpacing); + textRect.setWidth(textRect.width()-moveByX-vSpacing); + } else { + textRect.setWidth(textRect.width()-moveByX); + iconRect.setWidth(iconRect.width()+vSpacing); + iconRect.translate(-optionCheckBox.rect.width()-vSpacing, 0); + optionCheckBox.rect.translate(textRect.width()+iconRect.width(),0); + } + drawPrimitive(PE_IndicatorMenuCheckMark, &optionCheckBox, painter, widget); + } + //draw icon and/or checkState + QPixmap pix = menuItem->icon.pixmap(pixelMetric(PM_SmallIconSize), + enabled ? QIcon::Normal : QIcon::Disabled); + const bool itemWithIcon = !pix.isNull(); + if (itemWithIcon) { + drawItemPixmap(painter, iconRect, text_flags, pix); + if (optionMenuItem.direction == Qt::LeftToRight) + textRect.translate(vSpacing,0); + else + textRect.translate(-vSpacing,0); + textRect.setWidth(textRect.width()-vSpacing); + } + + //draw indicators + if (drawSubMenuIndicator) { + QStyleOptionMenuItem arrowOptions; + arrowOptions.QStyleOption::operator=(*menuItem); + const int indicatorWidth = (pixelMetric(PM_ListViewIconSize, option, widget)>>1) + + pixelMetric(QStyle::PM_LayoutVerticalSpacing, option, widget); + if (optionMenuItem.direction == Qt::LeftToRight) + arrowOptions.rect.setLeft(textRect.right()); + arrowOptions.rect.setWidth(indicatorWidth); + //by default sub menu indicator in S60 points to east,so here icon + // direction is set to north (and south when in RightToLeft) + const QS60StylePrivate::SkinElementFlag arrowDirection = (arrowOptions.direction == Qt::LeftToRight) ? + QS60StylePrivate::SF_PointNorth : QS60StylePrivate::SF_PointSouth; + QS60StylePrivate::drawSkinPart(QS60StyleEnums::SP_QgnIndiSubMenu, painter, arrowOptions.rect, + (flags | QS60StylePrivate::SF_ColorSkinned | arrowDirection)); + } + + //draw text + if (!enabled){ + //In s60, if something becomes disabled, it is removed from menu, so no native look-alike available. + optionMenuItem.palette.setColor(QPalette::Disabled, QPalette::Text, QS60StylePrivate::lighterColor( + optionMenuItem.palette.color(QPalette::Disabled, QPalette::Text))); + painter->save(); + painter->setOpacity(0.5); + } + QCommonStyle::drawItemText(painter, textRect, text_flags, + optionMenuItem.palette, enabled, + optionMenuItem.text, QPalette::Text); + if (!enabled) + painter->restore(); + } + break; + case CE_MenuEmptyArea: + break; +#endif //QT_NO_MENU + +#ifndef QT_NO_MENUBAR + case CE_MenuBarEmptyArea: + break; +#endif //QT_NO_MENUBAR + + case CE_HeaderSection: + if ( const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + painter->save(); + QPen linePen = QPen(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 1, header)); + const int penWidth = (header->orientation == Qt::Horizontal) ? + linePen.width()+QS60StylePrivate::pixelMetric(PM_Custom_BoldLineWidth) + : linePen.width()+QS60StylePrivate::pixelMetric(PM_Custom_ThinLineWidth); + linePen.setWidth(penWidth); + painter->setPen(linePen); + if (header->orientation == Qt::Horizontal){ + painter->drawLine(header->rect.bottomLeft(), header->rect.bottomRight()); + } else { + if ( header->direction == Qt::LeftToRight ) { + painter->drawLine(header->rect.topRight(), header->rect.bottomRight()); + } else { + painter->drawLine(header->rect.topLeft(), header->rect.bottomLeft()); + } + } + painter->restore(); + } + break; + case CE_HeaderEmptyArea: // no need to draw this + break; + case CE_Header: + if ( const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + QS60StylePrivate::SkinElementFlags adjFlags = flags; + QRect mtyRect = header->rect; + const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + if (header->orientation == Qt::Horizontal) { + if (header->position == QStyleOptionHeader::OnlyOneSection) + mtyRect.adjust(frameWidth,1,frameWidth,-frameWidth); + else + mtyRect.adjust(-frameWidth,1,frameWidth,-frameWidth); + } else { + if ( header->direction == Qt::LeftToRight ) { + mtyRect.adjust(1,-frameWidth,0,frameWidth); + adjFlags |= QS60StylePrivate::SF_PointWest; + } else { + mtyRect.adjust(-1,frameWidth,0,-frameWidth); + adjFlags |= QS60StylePrivate::SF_PointEast; + } + } + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableHeaderItem, painter, mtyRect, adjFlags); + + QRegion clipRegion = painter->clipRegion(); + painter->setClipRect(option->rect); + drawControl(CE_HeaderSection, header, painter, widget); + QStyleOptionHeader subopt = *header; + subopt.rect = subElementRect(SE_HeaderLabel, header, widget); + if (subopt.rect.isValid()) + drawControl(CE_HeaderLabel, &subopt, painter, widget); + if (header->sortIndicator != QStyleOptionHeader::None) { + subopt.rect = subElementRect(SE_HeaderArrow, option, widget); + drawPrimitive(PE_IndicatorHeaderArrow, &subopt, painter, widget); + } + painter->setClipRegion(clipRegion); + } + break; +#ifndef QT_NO_TOOLBAR + case CE_ToolBar: + if (const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) { + const QToolBar *tbWidget = qobject_cast<const QToolBar *>(widget); + + //toolbar within a toolbar, skip + if (!tbWidget || (widget && qobject_cast<QToolBar *>(widget->parentWidget()))) + break; + + // Normally in S60 5.0+ there is no background for toolbar, but in some cases with versatile QToolBar, + // it looks a bit strange. So, lets fillRect with Button. + if (!QS60StylePrivate::isToolBarBackground()) { + QList<QAction *> actions = tbWidget->actions(); + bool justToolButtonsInToolBar = true; + for (int i = 0; i < actions.size(); ++i) { + QWidget *childWidget = tbWidget->widgetForAction(actions.at(i)); + const QToolButton *button = qobject_cast<const QToolButton *>(childWidget); + if (!button){ + justToolButtonsInToolBar = false; + } + } + + // Draw frame background + // for vertical toolbars with text only and + // for toolbars with extension buttons and + // for toolbars with widgets in them. + if (!justToolButtonsInToolBar || + (tbWidget && + (tbWidget->orientation() == Qt::Vertical) && + (tbWidget->toolButtonStyle() == Qt::ToolButtonTextOnly))) { + painter->save(); + if (widget) + painter->setBrush(widget->palette().button()); + painter->setOpacity(0.3); + painter->fillRect(toolBar->rect, painter->brush()); + painter->restore(); + } + } else { + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBar, painter, toolBar->rect, flags); + } + } + break; +#endif //QT_NO_TOOLBAR + case CE_ShapedFrame: + if (qobject_cast<const QTextEdit *>(widget)) { + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_Editor, painter, option->rect, flags); + } else if (qobject_cast<const QAbstractScrollArea *>(widget) && qobject_cast<const QTableView *>(widget)) { + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableItem, painter, option->rect, flags); + } + if (option->state & State_HasFocus) + drawPrimitive(PE_FrameFocusRect, option, painter, widget); + break; + case CE_MenuScroller: + break; + default: + QCommonStyle::drawControl(element, option, painter, widget); + } +} + +/*! + \reimp +*/ +void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; + switch (element) { +#ifndef QT_NO_LINEEDIT + case PE_PanelLineEdit: + if (const QStyleOptionFrame *lineEdit = qstyleoption_cast<const QStyleOptionFrame *>(option)) { +#ifndef QT_NO_COMBOBOX + if (widget && qobject_cast<const QComboBox *>(widget->parentWidget())) + break; +#endif + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_FrameLineEdit, + painter, option->rect, flags); + + if (lineEdit->state & State_HasFocus) + drawPrimitive(PE_FrameFocusRect, lineEdit, painter, widget); + } + break; +#endif // QT_NO_LINEEDIT + case PE_IndicatorCheckBox: + { + const QRect indicatorRect = option->rect; + // Draw checkbox indicator as color skinned graphics. + const QS60StyleEnums::SkinParts skinPart = (option->state & QStyle::State_On) ? + QS60StyleEnums::SP_QgnIndiCheckboxOn : QS60StyleEnums::SP_QgnIndiCheckboxOff; + QS60StylePrivate::drawSkinPart(skinPart, painter, indicatorRect, + (flags | QS60StylePrivate::SF_ColorSkinned)); + } + break; + case PE_IndicatorViewItemCheck: +#ifndef QT_NO_ITEMVIEWS + if (const QListView *listItem = (qobject_cast<const QListView *>(widget))) { + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) { + const bool checkBoxVisible = vopt->features & QStyleOptionViewItemV2::HasCheckIndicator; + const bool singleSelection = listItem->selectionMode() == + QAbstractItemView::SingleSelection || listItem->selectionMode() == QAbstractItemView::NoSelection; + // draw either checkbox at the beginning + if (checkBoxVisible && singleSelection) { + drawPrimitive(PE_IndicatorCheckBox, option, painter, widget); + // ... or normal "tick" selection at the end. + } else if (option->state & QStyle::State_Selected) { + QRect tickRect = option->rect; + const int frameBorderWidth = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth); + // adjust tickmark rect to exclude frame border + tickRect.adjust(0,-frameBorderWidth,0,-frameBorderWidth); + QS60StyleEnums::SkinParts skinPart = QS60StyleEnums::SP_QgnIndiMarkedAdd; + QS60StylePrivate::drawSkinPart(skinPart, painter, tickRect, + (flags | QS60StylePrivate::SF_ColorSkinned)); + } + } + } +#endif //QT_NO_ITEMVIEWS + break; + case PE_IndicatorRadioButton: { + QRect buttonRect = option->rect; + //there is empty (a. 33%) space in svg graphics for radiobutton + const qreal reduceWidth = (qreal)buttonRect.width()/3.0; + const qreal rectWidth = (qreal)option->rect.width() != 0 ? option->rect.width() : 1.0; + // Try to occupy the full area + const qreal scaler = 1 + (reduceWidth/rectWidth); + buttonRect.setWidth((int)((buttonRect.width()-reduceWidth) * scaler)); + buttonRect.setHeight((int)(buttonRect.height() * scaler)); + // move the rect up for half of the new height-gain + const int newY = (buttonRect.bottomRight().y() - option->rect.bottomRight().y()) >> 1 ; + buttonRect.adjust(0,-newY,0,-newY); + + // Draw radiobutton indicator as color skinned graphics. + QS60StyleEnums::SkinParts skinPart = (option->state & QStyle::State_On) ? + QS60StyleEnums::SP_QgnIndiRadiobuttOn : QS60StyleEnums::SP_QgnIndiRadiobuttOff; + QS60StylePrivate::drawSkinPart(skinPart, painter, buttonRect, + (flags | QS60StylePrivate::SF_ColorSkinned)); + } + break; + case PE_PanelButtonCommand: + case PE_PanelButtonTool: + case PE_PanelButtonBevel: + case PE_FrameButtonBevel: { + const bool isPressed = option->state & QStyle::State_Sunken; + const QS60StylePrivate::SkinElements skinElement = + isPressed ? QS60StylePrivate::SE_ButtonPressed : QS60StylePrivate::SE_ButtonNormal; + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; +#ifndef QT_NO_TOOLBUTTON + case PE_IndicatorArrowDown: + case PE_IndicatorArrowLeft: + case PE_IndicatorArrowRight: + case PE_IndicatorArrowUp: { + QS60StyleEnums::SkinParts skinPart; + if (element==PE_IndicatorArrowDown) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowDown; + else if (element==PE_IndicatorArrowLeft) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowLeft; + else if (element==PE_IndicatorArrowRight) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowRight; + else if (element==PE_IndicatorArrowUp) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowUp; + + QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); + } + break; +#endif //QT_NO_TOOLBUTTON +#ifndef QT_NO_SPINBOX + case PE_IndicatorSpinDown: + case PE_IndicatorSpinUp: + if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + QStyleOptionSpinBox optionSpinBox = *spinBox; + const QS60StyleEnums::SkinParts part = (element == PE_IndicatorSpinUp) ? + QS60StyleEnums::SP_QgnGrafScrollArrowUp : + QS60StyleEnums::SP_QgnGrafScrollArrowDown; + const int adjustment = qMin(optionSpinBox.rect.width(), optionSpinBox.rect.height())/6; + optionSpinBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? adjustment : -adjustment ); + QS60StylePrivate::drawSkinPart(part, painter, optionSpinBox.rect,flags); + } +#ifndef QT_NO_COMBOBOX + else if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { + // We want to draw down arrow here for comboboxes as well. + const QS60StyleEnums::SkinParts part = QS60StyleEnums::SP_QgnGrafScrollArrowDown; + QStyleOptionFrame comboBox = *cmb; + const int adjustment = qMin(comboBox.rect.width(), comboBox.rect.height())/6; + comboBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? adjustment : -adjustment ); + QS60StylePrivate::drawSkinPart(part, painter, comboBox.rect,flags); + } +#endif //QT_NO_COMBOBOX + break; + case PE_IndicatorSpinMinus: + case PE_IndicatorSpinPlus: + if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + QStyleOptionSpinBox optionSpinBox = *spinBox; + QCommonStyle::drawPrimitive(element, &optionSpinBox, painter, widget); + } +#ifndef QT_NO_COMBOBOX + else if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { + // We want to draw down arrow here for comboboxes as well. + QStyleOptionFrame comboBox = *cmb; + const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + comboBox.rect.adjust(0,frameWidth,0,-frameWidth); + QCommonStyle::drawPrimitive(element, &comboBox, painter, widget); + } +#endif //QT_NO_COMBOBOX + break; +#endif //QT_NO_SPINBOX + case PE_FrameFocusRect: +// Calendar widget and combox both do not use styled itemDelegate + if (widget && !(false +#ifndef QT_NO_CALENDARWIDGET + || qobject_cast<const QCalendarWidget *>(widget->parent()) +#endif //QT_NO_CALENDARWIDGET +#ifndef QT_NO_COMBOBOX + || qobject_cast<const QComboBoxListView *>(widget) +#endif //QT_NO_COMBOBOX + )) { + // no focus selection for touch + if (option->state & State_HasFocus && !QS60StylePrivate::isTouchSupported()) { + painter->save(); + const int penWidth = QS60StylePrivate::focusRectPenWidth(); +#ifdef QT_KEYPAD_NAVIGATION + const Qt::PenStyle penStyle = widget->hasEditFocus() ? Qt::SolidLine :Qt::DotLine; + const qreal opacity = widget->hasEditFocus() ? 0.6 : 0.4; +#else + const Qt::PenStyle penStyle = Qt::SolidLine; + const qreal opacity = 0.5; +#endif + painter->setPen(QPen(option->palette.color(QPalette::Text), penWidth, penStyle)); + painter->setRenderHint(QPainter::Antialiasing); + painter->setOpacity(opacity); + // Because of Qts coordinate system, we need to tweak the rect by .5 pixels, otherwise it gets blurred. + const qreal rectAdjustment = penWidth % 2?.5:0; + // Also we try to stay inside the option->rect, with penWidth > 1. Therefore these +1/-1 + const QRectF adjustedRect = QRectF(option->rect).adjusted( + rectAdjustment + penWidth - 1, + rectAdjustment + penWidth - 1, + -rectAdjustment - penWidth + 1, + -rectAdjustment - penWidth + 1); + painter->drawRoundedRect(adjustedRect, penWidth * 1.5, penWidth * 1.5); + painter->restore(); + } + } + break; + case PE_Widget: + if (QS60StylePrivate::drawsOwnThemeBackground(widget) +#ifndef QT_NO_COMBOBOX + || qobject_cast<const QComboBoxListView *>(widget) +#endif //QT_NO_COMBOBOX +#ifndef QT_NO_MENU + || qobject_cast<const QMenu *> (widget) +#endif //QT_NO_MENU + ) { + QS60StylePrivate::SkinElements skinElement = QS60StylePrivate::SE_OptionsMenu; + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; + case PE_FrameWindow: + case PE_FrameTabWidget: + if (const QStyleOptionTabWidgetFrame *tabFrame = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) { + QStyleOptionTabWidgetFrame optionTabFrame = *tabFrame; + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PanelBackground, painter, optionTabFrame.rect, flags); + } + break; + case PE_IndicatorHeaderArrow: + if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + if (header->sortIndicator & QStyleOptionHeader::SortUp) + drawPrimitive(PE_IndicatorArrowUp, header, painter, widget); + else if (header->sortIndicator & QStyleOptionHeader::SortDown) + drawPrimitive(PE_IndicatorArrowDown, header, painter, widget); + } // QStyleOptionHeader::None is not drawn => not needed + break; +#ifndef QT_NO_GROUPBOX + case PE_FrameGroupBox: + if (const QStyleOptionFrameV2 *frame = qstyleoption_cast<const QStyleOptionFrameV2 *>(option)) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_SettingsList, painter, frame->rect, flags); + break; +#endif //QT_NO_GROUPBOX + + // Qt3 primitives are not supported + case PE_Q3CheckListController: + case PE_Q3CheckListExclusiveIndicator: + case PE_Q3CheckListIndicator: + case PE_Q3DockWindowSeparator: + case PE_Q3Separator: + Q_ASSERT(false); + break; + case PE_Frame: + if (const QStyleOptionFrameV3 *frame = qstyleoption_cast<const QStyleOptionFrameV3 *>(option)) + drawPrimitive(PE_FrameFocusRect, frame, painter, widget); + break; +#ifndef QT_NO_ITEMVIEWS + case PE_PanelItemViewItem: + case PE_PanelItemViewRow: // ### Qt 5: remove + break; +#endif //QT_NO_ITEMVIEWS + + case PE_IndicatorMenuCheckMark: + if (const QStyleOptionMenuItem *checkBox = qstyleoption_cast<const QStyleOptionMenuItem *>(option)){ + QStyleOptionMenuItem optionCheckBox = *checkBox; + if (optionCheckBox.checked) + optionCheckBox.state = (optionCheckBox.state | State_On); + drawPrimitive(PE_IndicatorCheckBox, &optionCheckBox, painter, widget); + } + break; +#ifndef QT_NO_TOOLBAR + case PE_IndicatorToolBarHandle: + // no toolbar handles in S60/AVKON UI + case PE_IndicatorToolBarSeparator: + // no separators in S60/AVKON UI + break; +#endif //QT_NO_TOOLBAR + + case PE_PanelMenuBar: + case PE_FrameMenu: + break; //disable frame in menu + + case PE_IndicatorBranch: +#if defined(Q_WS_S60) + // 3.1 AVKON UI does not have tree view component, use common style for drawing there + if (QSysInfo::s60Version() == QSysInfo::SV_S60_3_1) { +#else + if (true) { +#endif + QCommonStyle::drawPrimitive(element, option, painter, widget); + } else { + const bool rightLine = option->state & State_Item; + const bool downLine = option->state & State_Sibling; + const bool upLine = option->state & (State_Open | State_Children | State_Item | State_Sibling); + + QS60StyleEnums::SkinParts skinPart; + bool drawSkinPart = false; + if (rightLine && downLine && upLine) { + skinPart = QS60StyleEnums::SP_QgnIndiHlLineBranch; + drawSkinPart = true; + } else if (rightLine && upLine) { + skinPart = QS60StyleEnums::SP_QgnIndiHlLineEnd; + drawSkinPart = true; + } else if (upLine && downLine) { + skinPart = QS60StyleEnums::SP_QgnIndiHlLineStraight; + drawSkinPart = true; + } + + if ( drawSkinPart ) + QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); + + if (option->state & State_Children) { + QS60StyleEnums::SkinParts skinPart = + (option->state & State_Open) ? QS60StyleEnums::SP_QgnIndiHlColSuper : QS60StyleEnums::SP_QgnIndiHlExpSuper; + int minDimension = qMin(option->rect.width(), option->rect.height()); + const int resizeValue = minDimension >> 1; + minDimension += resizeValue; // Adjust the icon bigger because of empty space in svg icon. + QRect iconRect(option->rect.topLeft(), QSize(minDimension, minDimension)); + int verticalMagic(0); + // magic values for positioning svg icon. + if (option->rect.width() <= option->rect.height()) + verticalMagic = 3; + iconRect.translate(3, verticalMagic - resizeValue); + QS60StylePrivate::drawSkinPart(skinPart, painter, iconRect, flags); + } + } + break; + + // todo: items are below with #ifdefs "just in case". in final version, remove all non-required cases + case PE_FrameLineEdit: + case PE_IndicatorButtonDropDown: + case PE_IndicatorDockWidgetResizeHandle: + case PE_PanelTipLabel: + case PE_PanelScrollAreaCorner: + +#ifndef QT_NO_TABBAR + case PE_IndicatorTabTear: // No tab tear in S60 +#endif // QT_NO_TABBAR + case PE_FrameDefaultButton: +#ifndef QT_NO_DOCKWIDGET + case PE_FrameDockWidget: +#endif //QT_NO_DOCKWIDGET +#ifndef QT_NO_PROGRESSBAR + case PE_IndicatorProgressChunk: +#endif //QT_NO_PROGRESSBAR +#ifndef QT_NO_TOOLBAR + case PE_PanelToolBar: +#endif //QT_NO_TOOLBAR +#ifndef QT_NO_COLUMNVIEW + case PE_IndicatorColumnViewArrow: + case PE_IndicatorItemViewItemDrop: +#endif //QT_NO_COLUMNVIEW + case PE_FrameTabBarBase: // since tabs are in S60 always in navipane, let's use common style for tab base in Qt. + default: + QCommonStyle::drawPrimitive(element, option, painter, widget); + } +} + +/*! \reimp */ +int QS60Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + int metricValue = QS60StylePrivate::pixelMetric(metric); + if (metricValue == KNotFound) + metricValue = QCommonStyle::pixelMetric(metric, option, widget); + + if (metric == PM_SubMenuOverlap && widget){ + const QMenu *menu = qobject_cast<const QMenu *>(widget); + if (menu && menu->activeAction() && menu->activeAction()->menu()) { + const int menuWidth = menu->activeAction()->menu()->sizeHint().width(); + metricValue = -menuWidth; + } + } + return metricValue; +} + +/*! \reimp */ +QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, + const QSize &csz, const QWidget *widget) const +{ + QSize sz(csz); + switch (ct) { + case CT_PushButton: + sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); + if (const QAbstractButton *buttonWidget = (qobject_cast<const QAbstractButton *>(widget))) + if (buttonWidget->isCheckable()) + sz += QSize(pixelMetric(PM_IndicatorWidth) + pixelMetric(PM_CheckBoxLabelSpacing), 0); + break; + case CT_LineEdit: + if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) + sz += QSize(2*f->lineWidth, 4*f->lineWidth); + break; + default: + sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); + break; + } + return sz; +} + +/*! \reimp */ +int QS60Style::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget, + QStyleHintReturn *hret) const +{ + int retValue = -1; + switch (sh) { + case SH_Table_GridLineColor: + retValue = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors,2,0).rgb(); + break; + case SH_GroupBox_TextLabelColor: + retValue = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors,6,0).rgb(); + break; + case SH_ScrollBar_ScrollWhenPointerLeavesControl: + retValue = true; + break; + case SH_Slider_SnapToValue: + retValue = true; + break; + case SH_Slider_StopMouseOverSlider: + retValue = true; + break; + case SH_LineEdit_PasswordCharacter: + retValue = '*'; + break; + case SH_ComboBox_PopupFrameStyle: + retValue = QFrame::NoFrame | QFrame::Plain; + break; + case SH_Dial_BackgroundRole: + retValue = QPalette::Base; + break; + case SH_ItemView_ActivateItemOnSingleClick: + retValue = true; + break; + case SH_ProgressDialog_TextLabelAlignment: + retValue = (QApplication::layoutDirection() == Qt::LeftToRight) ? + Qt::AlignLeft : + Qt::AlignRight; + break; + case SH_Menu_SubMenuPopupDelay: + retValue = 300; + break; + case SH_Menu_Scrollable: + retValue = true; + break; + case SH_Menu_SelectionWrap: + retValue = true; + break; + case SH_ItemView_ShowDecorationSelected: + retValue = true; + break; + case SH_ToolBar_Movable: + retValue = false; + break; + case SH_BlinkCursorWhenTextSelected: + retValue = true; + break; + case SH_UnderlineShortcut: + retValue = 0; + break; + default: + break; + } + if (retValue == -1) + retValue = QCommonStyle::styleHint(sh, opt, widget, hret); + return retValue; +} + +/*! \reimp */ +QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl scontrol, const QWidget *widget) const +{ + QRect ret; + switch (control) { +#ifndef QT_NO_SCROLLBAR + // This implementation of subControlRect(CC_ScrollBar..) basically just removes the SC_ScrollBarSubLine and SC_ScrollBarAddLine + case CC_ScrollBar: + if (const QStyleOptionSlider *scrollbarOption = qstyleoption_cast<const QStyleOptionSlider *>(option)) { + const QRect scrollBarRect = scrollbarOption->rect; + const bool isHorizontal = scrollbarOption->orientation == Qt::Horizontal; + const int maxlen = isHorizontal ? scrollBarRect.width() : scrollBarRect.height(); + int sliderlen; + + // calculate slider length + if (scrollbarOption->maximum != scrollbarOption->minimum) { + const uint range = scrollbarOption->maximum - scrollbarOption->minimum; + sliderlen = (qint64(scrollbarOption->pageStep) * maxlen) / (range + scrollbarOption->pageStep); + + int slidermin = pixelMetric(PM_ScrollBarSliderMin, scrollbarOption, widget); + if (isHorizontal && slidermin < scrollBarRect.height()) + slidermin = scrollBarRect.height(); + else if (!isHorizontal && slidermin < scrollBarRect.width()) + slidermin = scrollBarRect.width(); + + if (sliderlen < slidermin || range > (INT_MAX>>1)) + sliderlen = slidermin; + if (sliderlen > maxlen) + sliderlen = maxlen; + } else { + sliderlen = maxlen; + } + + const int sliderstart = sliderPositionFromValue(scrollbarOption->minimum, + scrollbarOption->maximum, + scrollbarOption->sliderPosition, + maxlen - sliderlen, + scrollbarOption->upsideDown); + + switch (scontrol) { + case SC_ScrollBarSubPage: // between top/left button and slider + if (isHorizontal) + ret.setRect(0, 0, sliderstart, scrollBarRect.height()); + else + ret.setRect(0, 0, scrollBarRect.width(), sliderstart); + break; + case SC_ScrollBarAddPage: { // between bottom/right button and slider + const int addPageLength = sliderstart + sliderlen; + if (isHorizontal) + ret = scrollBarRect.adjusted(addPageLength, 0, 0, 0); + else + ret = scrollBarRect.adjusted(0, addPageLength, 0, 0); + } + break; + case SC_ScrollBarGroove: + ret = scrollBarRect; + break; + case SC_ScrollBarSlider: + if (scrollbarOption->orientation == Qt::Horizontal) + ret.setRect(sliderstart, 0, sliderlen, scrollBarRect.height()); + else + ret.setRect(0, sliderstart, scrollBarRect.width(), sliderlen); + break; + case SC_ScrollBarSubLine: // top/left button + case SC_ScrollBarAddLine: // bottom/right button + default: + break; + } + ret = visualRect(scrollbarOption->direction, scrollBarRect, ret); + } + break; +#endif // QT_NO_SCROLLBAR + case CC_SpinBox: + if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + const int frameThickness = spinbox->frame ? pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0; + const int buttonMargin = spinbox->frame ? 2 : 0; + const int buttonWidth = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize) + 2*buttonMargin; + QSize buttonSize; + buttonSize.setHeight(qMax(8, spinbox->rect.height() - frameThickness)); + buttonSize.setWidth(buttonWidth); + buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); + + const int y = frameThickness + spinbox->rect.y(); + const int x = spinbox->rect.x() + spinbox->rect.width() - frameThickness - 2*buttonSize.width(); + + switch (scontrol) { + case SC_SpinBoxUp: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + return QRect(); + ret = QRect(x, y, buttonWidth, buttonSize.height()); + break; + case SC_SpinBoxDown: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + return QRect(); + ret = QRect(x+buttonSize.width(), y, buttonWidth, buttonSize.height()); + break; + case SC_SpinBoxEditField: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + ret = QRect( + frameThickness, + frameThickness, + spinbox->rect.width() - 2*frameThickness, + spinbox->rect.height() - 2*frameThickness); + else + ret = QRect( + frameThickness, + frameThickness, + x - frameThickness, + spinbox->rect.height() - 2*frameThickness); + break; + case SC_SpinBoxFrame: + ret = spinbox->rect; + break; + default: + break; + } + ret = visualRect(spinbox->direction, spinbox->rect, ret); + } + break; + case CC_ComboBox: + if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + ret = cmb->rect; + const int width = cmb->rect.width(); + const int height = cmb->rect.height(); + const int buttonMargin = cmb->frame ? 2 : 0; + // lets use spinbox frame here as well, as no combobox specific value available. + const int frameThickness = cmb->frame ? pixelMetric(PM_SpinBoxFrameWidth, cmb, widget) : 0; + const int buttonWidth = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize); + const int xposMod = (cmb->rect.x()) + width - buttonMargin - buttonWidth; + const int ypos = cmb->rect.y(); + + QSize buttonSize; + buttonSize.setHeight(qMax(8, (cmb->rect.height()>>1) - frameThickness)); //minimum of 8 pixels + buttonSize.setWidth(buttonWidth+2*buttonMargin); + buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); + switch (scontrol) { + case SC_ComboBoxArrow: + ret.setRect(xposMod, ypos + buttonMargin, buttonWidth, height - 2*buttonMargin); + break; + case SC_ComboBoxEditField: { + const int withFrameX = cmb->rect.x() + cmb->rect.width() - frameThickness - buttonSize.width(); + ret = QRect( + frameThickness, + frameThickness, + withFrameX - frameThickness, + cmb->rect.height() - 2*frameThickness); + } + break; + default: + break; + } + } + break; + case CC_GroupBox: + if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) { + ret = QCommonStyle::subControlRect(control, option, scontrol, widget); + switch (scontrol) { + case SC_GroupBoxCheckBox: //fallthrough + case SC_GroupBoxLabel: { + //slightly indent text and boxes, so that dialog border does not mess with them. + const int horizontalSpacing = + QS60StylePrivate::pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + ret.adjust(2,horizontalSpacing-3,0,0); + } + break; + case SC_GroupBoxFrame: { + const QRect textBox = subControlRect(control, option, SC_GroupBoxLabel, widget); + const int tbHeight = textBox.height(); + ret.translate(0, -ret.y()); + // include title to within the groupBox frame + ret.setHeight(ret.height()+tbHeight); + if (widget && ret.bottom() > widget->rect().bottom()) + ret.setBottom(widget->rect().bottom()); + } + break; + default: + break; + } + } + break; + default: + ret = QCommonStyle::subControlRect(control, option, scontrol, widget); + } + return ret; +} + +QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, const QWidget *widget) const +{ + QRect ret; + switch (element) { + case SE_LineEditContents: { + // in S60 the input text box doesn't start from line Edit's TL, but + // a bit indented. + QRect lineEditRect = opt->rect; + const int adjustment = opt->rect.height()>>2; + lineEditRect.adjust(adjustment,0,0,0); + ret = lineEditRect; + } + break; + case SE_TabBarTearIndicator: + ret = QRect(0,0,0,0); + break; + case SE_TabWidgetTabBar: + if (const QStyleOptionTabWidgetFrame *optionTab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) { + ret = QCommonStyle::subElementRect(element, opt, widget); + + if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) { + const int tabOverlapNoBorder = + QS60StylePrivate::pixelMetric(QStyle::PM_TabBarTabOverlap); + const int tabOverlap = + tabOverlapNoBorder-QS60StylePrivate::pixelMetric(QStyle::PM_DefaultFrameWidth); + const QTabWidget *tab = qobject_cast<const QTabWidget *>(widget); + int gain = (tab) ? tabOverlap * tab->count() : 0; + switch (twf->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: { + if (widget) { + // make sure that gain does not set the rect outside of widget boundaries + if (twf->direction == Qt::RightToLeft) { + if ((ret.left() - gain) < widget->rect().left()) + gain = widget->rect().left()-ret.left(); + ret.adjust(-gain,0,0,0); + } else { + if ((ret.right() + gain) > widget->rect().right()) + gain = widget->rect().right()-ret.right(); + ret.adjust(0,0,gain,0); + } + } + break; + } + default: { + if (widget) { + if ((ret.bottom() + gain) > widget->rect().bottom()) + gain = widget->rect().bottom()-ret.bottom(); + ret.adjust(0,0,0,gain); + } + break; + } + } + } + } + break; + case SE_ItemViewItemText: + case SE_ItemViewItemDecoration: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) { + const QListWidget *listItem = qobject_cast<const QListWidget *>(widget); + const bool multiSelection = !listItem ? false : + listItem->selectionMode() == QAbstractItemView::MultiSelection || + listItem->selectionMode() == QAbstractItemView::ExtendedSelection || + listItem->selectionMode() == QAbstractItemView::ContiguousSelection; + ret = QCommonStyle::subElementRect(element, opt, widget); + // If both multiselect & check-state, then remove checkbox and move + // text and decoration towards the beginning + if (listItem && + multiSelection && + (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator)) { + const int verticalSpacing = + QS60StylePrivate::pixelMetric(QStyle::PM_LayoutVerticalSpacing); + //const int horizontalSpacing = QS60StylePrivate::pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + const int checkBoxRectWidth = subElementRect(SE_ItemViewItemCheckIndicator, opt, widget).width(); + ret.adjust(-checkBoxRectWidth-verticalSpacing,0,-checkBoxRectWidth-verticalSpacing,0); + } + } else if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { + const bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable; + const int indicatorWidth = checkable ? + pixelMetric(PM_ListViewIconSize, opt, widget) : + pixelMetric(PM_SmallIconSize, opt, widget); + ret = menuItem->rect; + + if (element == SE_ItemViewItemDecoration) { + if (menuItem->direction == Qt::RightToLeft) + ret.translate(ret.width()-indicatorWidth, 0); + ret.setWidth(indicatorWidth); + } else { + ret = menuItem->rect; + if (!menuItem->icon.isNull()) + if (menuItem->direction == Qt::LeftToRight) + ret.adjust(indicatorWidth, 0, 0, 0); + else + ret.adjust(0, 0, -indicatorWidth, 0); + + // Make room for submenu indicator + if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu){ + // submenu indicator is very small, so lets halve the rect + if (menuItem->direction == Qt::LeftToRight) + ret.adjust(0,0,-(indicatorWidth >> 1),0); + else + ret.adjust((indicatorWidth >> 1),0,0,0); + } + } + } + break; + case SE_ItemViewItemCheckIndicator: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) { + const QListWidget *listItem = qobject_cast<const QListWidget *>(widget); + + const bool singleSelection = listItem && + (listItem->selectionMode() == QAbstractItemView::SingleSelection || + listItem->selectionMode() == QAbstractItemView::NoSelection); + const bool checkBoxOnly = (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator) && + listItem && + singleSelection; + + // Selection check mark rect. + const int indicatorWidth = QS60StylePrivate::pixelMetric(QStyle::PM_IndicatorWidth); + const int indicatorHeight = QS60StylePrivate::pixelMetric(QStyle::PM_IndicatorHeight); + const int spacing = QS60StylePrivate::pixelMetric(QStyle::PM_CheckBoxLabelSpacing); + + const int itemHeight = opt->rect.height(); + int heightOffset = 0; + if (indicatorHeight < itemHeight) + heightOffset = ((itemHeight - indicatorHeight)>>1); + if (checkBoxOnly) { + // Move rect and make it slightly smaller, so that + // a) highlight border does not cross the rect + // b) in s60 list checkbox is smaller than normal checkbox + //todo; magic three + ret.setRect(opt->rect.left()+3, opt->rect.top() + heightOffset, + indicatorWidth-3, indicatorHeight-3); + } else { + ret.setRect(opt->rect.right() - indicatorWidth - spacing, opt->rect.top() + heightOffset, + indicatorWidth, indicatorHeight); + } + } else { + ret = QCommonStyle::subElementRect(element, opt, widget); + } + break; + case SE_HeaderLabel: + ret = QCommonStyle::subElementRect(element, opt, widget); + if (qstyleoption_cast<const QStyleOptionHeader *>(opt)) { + // Subtract area needed for line + if (opt->state & State_Horizontal) + ret.setHeight(ret.height() - QS60StylePrivate::pixelMetric(PM_Custom_BoldLineWidth)); + else + ret.setWidth(ret.width() - QS60StylePrivate::pixelMetric(PM_Custom_ThinLineWidth)); + } + ret = visualRect(opt->direction, opt->rect, ret); + break; + case SE_FrameContents: + if (QS60StylePrivate::isTouchSupported()) { + return QCommonStyle::subElementRect(element, opt, widget); + } else if (const QStyleOptionFrameV2 *f = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt)) { + // We shrink the frame contents by focusFrameWidth, so that we can draw the frame around it in keypad navigation mode. + const int frameWidth = QS60StylePrivate::focusRectPenWidth(); + ret = opt->rect.adjusted(frameWidth, frameWidth, -frameWidth, -frameWidth); + ret = visualRect(opt->direction, opt->rect, ret); + } + break; + default: + ret = QCommonStyle::subElementRect(element, opt, widget); + } + return ret; +} + +void QS60Style::polish(QWidget *widget) +{ + Q_D(const QS60Style); + QCommonStyle::polish(widget); + + if (!widget) + return; + + if (false +#ifndef QT_NO_SCROLLBAR + || qobject_cast<QScrollBar *>(widget) +#endif + ) { + widget->setAttribute(Qt::WA_OpaquePaintEvent, false); + } + + if (QS60StylePrivate::drawsOwnThemeBackground(widget)) { + widget->setAttribute(Qt::WA_StyledBackground); + } else if (false +#ifndef QT_NO_MENU + || qobject_cast<const QMenu *> (widget) +#endif // QT_NO_MENU + ) { + widget->setAttribute(Qt::WA_StyledBackground); + } else if (false +#ifndef QT_NO_COMBOBOX + || qobject_cast<const QComboBoxListView *>(widget) +#endif //QT_NO_COMBOBOX + ) { + widget->setAttribute(Qt::WA_StyledBackground); + } + d->setThemePalette(widget); + d->setFont(widget); +} + +void QS60Style::unpolish(QWidget *widget) +{ + if (false + #ifndef QT_NO_SCROLLBAR + || qobject_cast<QScrollBar *>(widget) + #endif + ) + widget->setAttribute(Qt::WA_OpaquePaintEvent); + + if (QS60StylePrivate::drawsOwnThemeBackground(widget)) { + widget->setAttribute(Qt::WA_StyledBackground, false); + } else if (false +#ifndef QT_NO_MENU + || qobject_cast<const QMenu *> (widget) +#endif // QT_NO_MENU + ) { + widget->setAttribute(Qt::WA_StyledBackground, false); + } else if (false +#ifndef QT_NO_COMBOBOX + || qobject_cast<const QComboBoxListView *>(widget) +#endif //QT_NO_COMBOBOX + ) { + widget->setAttribute(Qt::WA_StyledBackground, false); + } + + if (widget) + widget->setPalette(QPalette()); + + QCommonStyle::unpolish(widget); +} + +void QS60Style::polish(QApplication *application) +{ + Q_D(QS60Style); + d->m_originalPalette = application->palette(); + d->setThemePalette(application); +} + +void QS60Style::unpolish(QApplication *application) +{ + Q_UNUSED(application) + Q_D(QS60Style); + const QPalette newPalette = QApplication::style()->standardPalette(); + QApplication::setPalette(newPalette); + QApplicationPrivate::setSystemPalette(d->m_originalPalette); +} + +void QS60Style::setStyleProperty(const char *name, const QVariant &value) +{ + Q_D(QS60Style); + d->setStyleProperty_specific(name, value); +} + +QVariant QS60Style::styleProperty(const char *name) const +{ + Q_D(const QS60Style); + return d->styleProperty_specific(name); +} + +QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, + const QStyleOption *option, const QWidget *widget) const +{ + const int iconDimension = QS60StylePrivate::pixelMetric(QStyle::PM_ToolBarIconSize); + const QRect iconSize = (!option) ? QRect(0,0,iconDimension,iconDimension) : option->rect; + QS60StyleEnums::SkinParts part; + QS60StylePrivate::SkinElementFlags adjustedFlags; + if (option) + adjustedFlags = (option->state & State_Enabled) ? + QS60StylePrivate::SF_StateEnabled : + QS60StylePrivate::SF_StateDisabled; + + switch(standardIcon) { + case QStyle::SP_MessageBoxWarning: + part = QS60StyleEnums::SP_QgnNoteWarning; + break; + case QStyle::SP_MessageBoxInformation: + part = QS60StyleEnums::SP_QgnNoteInfo; + break; + case QStyle::SP_MessageBoxCritical: + part = QS60StyleEnums::SP_QgnNoteError; + break; + case QStyle::SP_MessageBoxQuestion: + part = QS60StyleEnums::SP_QgnNoteQuery; + break; + case QStyle::SP_ArrowRight: + part = QS60StyleEnums::SP_QgnIndiNaviArrowRight; + break; + case QStyle::SP_ArrowLeft: + part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; + break; + case QStyle::SP_ArrowUp: + part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; + adjustedFlags |= QS60StylePrivate::SF_PointEast; + break; + case QStyle::SP_ArrowDown: + part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; + adjustedFlags |= QS60StylePrivate::SF_PointWest; + break; + case QStyle::SP_ArrowBack: + if (QApplication::layoutDirection() == Qt::RightToLeft) + return QS60Style::standardIcon(SP_ArrowRight, option, widget); + return QS60Style::standardIcon(SP_ArrowLeft, option, widget); + case QStyle::SP_ArrowForward: + if (QApplication::layoutDirection() == Qt::RightToLeft) + return QS60Style::standardIcon(SP_ArrowLeft, option, widget); + return QS60Style::standardIcon(SP_ArrowRight, option, widget); + case QStyle::SP_ComputerIcon: + part = QS60StyleEnums::SP_QgnPropPhoneMemcLarge; + break; + case QStyle::SP_DirClosedIcon: + part = QS60StyleEnums::SP_QgnPropFolderSmall; + break; + case QStyle::SP_DirOpenIcon: + part = QS60StyleEnums::SP_QgnPropFolderCurrent; + break; + case QStyle::SP_DirIcon: + part = QS60StyleEnums::SP_QgnPropFolderSmall; + break; + case QStyle::SP_FileDialogNewFolder: + part = QS60StyleEnums::SP_QgnPropFolderSmallNew; + break; + case QStyle::SP_FileIcon: + part = QS60StyleEnums::SP_QgnPropFileSmall; + break; + case QStyle::SP_TrashIcon: + part = QS60StyleEnums::SP_QgnNoteErased; + break; + case QStyle::SP_ToolBarHorizontalExtensionButton: + part = QS60StyleEnums::SP_QgnIndiSubMenu; + if (QApplication::layoutDirection() == Qt::RightToLeft) + adjustedFlags |= QS60StylePrivate::SF_PointSouth; + break; + case QStyle::SP_ToolBarVerticalExtensionButton: + adjustedFlags |= QS60StylePrivate::SF_PointEast; + part = QS60StyleEnums::SP_QgnIndiSubMenu; + break; + + default: + return QCommonStyle::standardIconImplementation(standardIcon, option, widget); + } + const QS60StylePrivate::SkinElementFlags flags = adjustedFlags; + const QPixmap cachedPixMap(QS60StylePrivate::cachedPart(part, iconSize.size(), flags)); + return cachedPixMap.isNull() ? + QCommonStyle::standardIconImplementation(standardIcon, option, widget) : QIcon(cachedPixMap); +} + +extern QPoint qt_s60_fill_background_offset(const QWidget *targetWidget); + +bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, + const QBrush &brush) +{ + const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture()); + if (backgroundTexture.cacheKey() != brush.texture().cacheKey()) + return false; + + const QPaintDevice *target = painter->device(); + if (target->devType() == QInternal::Widget) { + const QWidget *widget = static_cast<const QWidget *>(target); + const QRegion translated = rgn.translated(offset); + const QVector<QRect> &rects = translated.rects(); + for (int i = 0; i < rects.size(); ++i) { + const QRect rect(rects.at(i)); + painter->drawPixmap(rect.topLeft(), backgroundTexture, + rect.translated(qt_s60_fill_background_offset(widget))); + } + } + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_STYLE_S60 || QT_PLUGIN diff --git a/src/gui/styles/qs60style.h b/src/gui/styles/qs60style.h new file mode 100644 index 0000000..d8e9a40 --- /dev/null +++ b/src/gui/styles/qs60style.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QS60STYLE_H +#define QS60STYLE_H + +#include <QtGui/qcommonstyle.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#if !defined(QT_NO_STYLE_S60) + +class QS60StylePrivate; + +class Q_GUI_EXPORT QS60Style : public QCommonStyle +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QS60Style) + +public: + QS60Style(); + ~QS60Style(); + + void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = 0) const; + void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; + int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const; + QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize, const QWidget *w = 0) const; + int styleHint(StyleHint sh, const QStyleOption *opt = 0, const QWidget *w = 0, + QStyleHintReturn *shret = 0) const; + QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl scontrol, const QWidget *widget = 0) const; + QRect subElementRect(SubElement element, const QStyleOption *opt, const QWidget *widget = 0) const; + void polish(QWidget *widget); + void unpolish(QWidget *widget); + void polish(QApplication *application); + void unpolish(QApplication *application); + + void setStyleProperty(const char *name, const QVariant &value); + QVariant styleProperty(const char *name) const; + +#ifndef Q_WS_S60 + static QStringList partKeys(); + static QStringList colorListKeys(); + void setS60Theme(const QHash<QString, QPicture> &parts, + const QHash<QPair<QString , int>, QColor> &colors); + bool loadS60ThemeFromBlob(const QString &blobFile); + bool saveS60ThemeToBlob(const QString &blobFile) const; +#endif // !Q_WS_S60 + +#ifdef Q_WS_S60 +public Q_SLOTS: + void handleDynamicLayoutVariantSwitch(); + void handleSkinChange(); +#endif // Q_WS_S60 + +protected Q_SLOTS: + QIcon standardIconImplementation( + StandardPixmap standardIcon, const QStyleOption * option = 0, const QWidget * widget = 0 ) const; + +private: + Q_DISABLE_COPY(QS60Style) + friend class QStyleFactory; +}; + +#endif // QT_NO_STYLE_S60 + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QS60STYLE_H diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h new file mode 100644 index 0000000..7240978 --- /dev/null +++ b/src/gui/styles/qs60style_p.h @@ -0,0 +1,501 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QS60STYLE_P_H +#define QS60STYLE_P_H + +#include "qs60style.h" +#include "qcommonstyle_p.h" +#include <QtCore/qhash.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. +// + +QT_BEGIN_NAMESPACE + +const int MAX_NON_CUSTOM_PIXELMETRICS = 92; +const int CUSTOMVALUESCOUNT = 4; +enum { + PM_Custom_FrameCornerWidth = MAX_NON_CUSTOM_PIXELMETRICS, + PM_Custom_FrameCornerHeight, + PM_Custom_BoldLineWidth, + PM_Custom_ThinLineWidth + }; +const int MAX_PIXELMETRICS = MAX_NON_CUSTOM_PIXELMETRICS + CUSTOMVALUESCOUNT; + +typedef struct { + unsigned short height; + unsigned short width; + int major_version; + int minor_version; + bool mirroring; // TODO: (nice to have) Use Qt::LayoutDirection + QString layoutName; +} layoutHeader; + +#ifdef Q_OS_SYMBIAN +NONSHARABLE_CLASS (QS60StyleEnums) +#else +class QS60StyleEnums +#endif +: public QObject +{ +#ifndef Q_WS_S60 + Q_OBJECT + Q_ENUMS(FontCategories) + Q_ENUMS(SkinParts) + Q_ENUMS(ColorLists) +#endif // !Q_WS_S60 + +public: + // S60 look-and-feel font categories + enum FontCategories { + FC_Undefined, + FC_Primary, + FC_Secondary, + FC_Title, + FC_PrimarySmall, + FC_Digital + }; + + enum SkinParts { + SP_QgnGrafBarWait, + SP_QgnGrafBarFrameCenter, + SP_QgnGrafBarFrameSideL, + SP_QgnGrafBarFrameSideR, + SP_QgnGrafBarProgress, + SP_QgnGrafScrollArrowDown, + SP_QgnGrafScrollArrowLeft, + SP_QgnGrafScrollArrowRight, + SP_QgnGrafScrollArrowUp, + SP_QgnGrafTabActiveL, + SP_QgnGrafTabActiveM, + SP_QgnGrafTabActiveR, + SP_QgnGrafTabPassiveL, + SP_QgnGrafTabPassiveM, + SP_QgnGrafTabPassiveR, + SP_QgnIndiCheckboxOff, + SP_QgnIndiCheckboxOn, + SP_QgnIndiHlColSuper, // Available in S60 release 3.2 and later. + SP_QgnIndiHlExpSuper, // Available in S60 release 3.2 and later. + SP_QgnIndiHlLineBranch, // Available in S60 release 3.2 and later. + SP_QgnIndiHlLineEnd, // Available in S60 release 3.2 and later. + SP_QgnIndiHlLineStraight, // Available in S60 release 3.2 and later. + SP_QgnIndiMarkedAdd, + SP_QgnIndiNaviArrowLeft, + SP_QgnIndiNaviArrowRight, + SP_QgnIndiRadiobuttOff, + SP_QgnIndiRadiobuttOn, + SP_QgnIndiSliderEdit, + SP_QgnIndiSubMenu, + SP_QgnNoteErased, + SP_QgnNoteError, + SP_QgnNoteInfo, + SP_QgnNoteOk, + SP_QgnNoteQuery, + SP_QgnNoteWarning, + SP_QgnPropFileSmall, + SP_QgnPropFolderCurrent, + SP_QgnPropFolderSmall, + SP_QgnPropFolderSmallNew, + SP_QgnPropPhoneMemcLarge, + SP_QsnCpScrollHandleBottomPressed, //ScrollBar handle, pressed state + SP_QsnCpScrollHandleMiddlePressed, + SP_QsnCpScrollHandleTopPressed, + SP_QsnBgScreen, + SP_QsnCpScrollBgBottom, + SP_QsnCpScrollBgMiddle, + SP_QsnCpScrollBgTop, + SP_QsnCpScrollHandleBottom, + SP_QsnCpScrollHandleMiddle, + SP_QsnCpScrollHandleTop, + SP_QsnFrButtonTbCornerTl, // Button, normal state + SP_QsnFrButtonTbCornerTr, + SP_QsnFrButtonTbCornerBl, + SP_QsnFrButtonTbCornerBr, + SP_QsnFrButtonTbSideT, + SP_QsnFrButtonTbSideB, + SP_QsnFrButtonTbSideL, + SP_QsnFrButtonTbSideR, + SP_QsnFrButtonTbCenter, + SP_QsnFrButtonTbCornerTlPressed, // Button, pressed state + SP_QsnFrButtonTbCornerTrPressed, + SP_QsnFrButtonTbCornerBlPressed, + SP_QsnFrButtonTbCornerBrPressed, + SP_QsnFrButtonTbSideTPressed, + SP_QsnFrButtonTbSideBPressed, + SP_QsnFrButtonTbSideLPressed, + SP_QsnFrButtonTbSideRPressed, + SP_QsnFrButtonTbCenterPressed, + SP_QsnFrCaleCornerTl, // calendar grid item + SP_QsnFrCaleCornerTr, + SP_QsnFrCaleCornerBl, + SP_QsnFrCaleCornerBr, + SP_QsnFrCaleGSideT, + SP_QsnFrCaleGSideB, + SP_QsnFrCaleGSideL, + SP_QsnFrCaleGSideR, + SP_QsnFrCaleCenter, + SP_QsnFrCaleHeadingCornerTl, // calendar grid header + SP_QsnFrCaleHeadingCornerTr, + SP_QsnFrCaleHeadingCornerBl, + SP_QsnFrCaleHeadingCornerBr, + SP_QsnFrCaleHeadingSideT, + SP_QsnFrCaleHeadingSideB, + SP_QsnFrCaleHeadingSideL, + SP_QsnFrCaleHeadingSideR, + SP_QsnFrCaleHeadingCenter, + SP_QsnFrInputCornerTl, // Text input field + SP_QsnFrInputCornerTr, + SP_QsnFrInputCornerBl, + SP_QsnFrInputCornerBr, + SP_QsnFrInputSideT, + SP_QsnFrInputSideB, + SP_QsnFrInputSideL, + SP_QsnFrInputSideR, + SP_QsnFrInputCenter, + SP_QsnFrListCornerTl, // List background + SP_QsnFrListCornerTr, + SP_QsnFrListCornerBl, + SP_QsnFrListCornerBr, + SP_QsnFrListSideT, + SP_QsnFrListSideB, + SP_QsnFrListSideL, + SP_QsnFrListSideR, + SP_QsnFrListCenter, + SP_QsnFrPopupCornerTl, // Option menu background + SP_QsnFrPopupCornerTr, + SP_QsnFrPopupCornerBl, + SP_QsnFrPopupCornerBr, + SP_QsnFrPopupSideT, + SP_QsnFrPopupSideB, + SP_QsnFrPopupSideL, + SP_QsnFrPopupSideR, + SP_QsnFrPopupCenter, + SP_QsnFrPopupPreviewCornerTl, // tool tip background + SP_QsnFrPopupPreviewCornerTr, + SP_QsnFrPopupPreviewCornerBl, + SP_QsnFrPopupPreviewCornerBr, + SP_QsnFrPopupPreviewSideT, + SP_QsnFrPopupPreviewSideB, + SP_QsnFrPopupPreviewSideL, + SP_QsnFrPopupPreviewSideR, + SP_QsnFrPopupPreviewCenter, + SP_QsnFrSetOptCornerTl, // Settings list + SP_QsnFrSetOptCornerTr, + SP_QsnFrSetOptCornerBl, + SP_QsnFrSetOptCornerBr, + SP_QsnFrSetOptSideT, + SP_QsnFrSetOptSideB, + SP_QsnFrSetOptSideL, + SP_QsnFrSetOptSideR, + SP_QsnFrSetOptCenter, + SP_QsnFrPopupSubCornerTl, // Toolbar background + SP_QsnFrPopupSubCornerTr, + SP_QsnFrPopupSubCornerBl, + SP_QsnFrPopupSubCornerBr, + SP_QsnFrPopupSubSideT, + SP_QsnFrPopupSubSideB, + SP_QsnFrPopupSubSideL, + SP_QsnFrPopupSubSideR, + SP_QsnFrPopupSubCenter, + SP_QsnFrSctrlButtonCornerTl, // Toolbar button + SP_QsnFrSctrlButtonCornerTr, + SP_QsnFrSctrlButtonCornerBl, + SP_QsnFrSctrlButtonCornerBr, + SP_QsnFrSctrlButtonSideT, + SP_QsnFrSctrlButtonSideB, + SP_QsnFrSctrlButtonSideL, + SP_QsnFrSctrlButtonSideR, + SP_QsnFrSctrlButtonCenter, + SP_QsnFrSctrlButtonCornerTlPressed, // Toolbar button, pressed + SP_QsnFrSctrlButtonCornerTrPressed, + SP_QsnFrSctrlButtonCornerBlPressed, + SP_QsnFrSctrlButtonCornerBrPressed, + SP_QsnFrSctrlButtonSideTPressed, + SP_QsnFrSctrlButtonSideBPressed, + SP_QsnFrSctrlButtonSideLPressed, + SP_QsnFrSctrlButtonSideRPressed, + SP_QsnFrSctrlButtonCenterPressed, + SP_QsnFrButtonCornerTlInactive, // Inactive button + SP_QsnFrButtonCornerTrInactive, + SP_QsnFrButtonCornerBlInactive, + SP_QsnFrButtonCornerBrInactive, + SP_QsnFrButtonSideTInactive, + SP_QsnFrButtonSideBInactive, + SP_QsnFrButtonSideLInactive, + SP_QsnFrButtonSideRInactive, + SP_QsnFrButtonCenterInactive, + SP_QsnFrNotepadCornerTl, + SP_QsnFrNotepadCornerTr, + SP_QsnFrNotepadCornerBl, + SP_QsnFrNotepadCornerBr, + SP_QsnFrNotepadSideT, + SP_QsnFrNotepadSideB, + SP_QsnFrNotepadSideL, + SP_QsnFrNotepadSideR, + SP_QsnFrNotepadCenter + }; + + enum ColorLists { + CL_QsnHighlightColors, + CL_QsnIconColors, + CL_QsnLineColors, + CL_QsnOtherColors, + CL_QsnParentColors, + CL_QsnTextColors + }; +}; + +// Private class +#ifdef Q_OS_SYMBIAN +NONSHARABLE_CLASS (QS60StylePrivate) +#else +class QS60StylePrivate +#endif +: public QCommonStylePrivate +{ + Q_DECLARE_PUBLIC(QS60Style) + +public: + QS60StylePrivate(); + ~QS60StylePrivate(); + + enum SkinElements { + SE_ButtonNormal, + SE_ButtonPressed, + SE_FrameLineEdit, + SE_ProgressBarGrooveHorizontal, + SE_ProgressBarIndicatorHorizontal, + SE_ProgressBarGrooveVertical, + SE_ProgressBarIndicatorVertical, + SE_ScrollBarGrooveHorizontal, + SE_ScrollBarGrooveVertical, + SE_ScrollBarHandleHorizontal, + SE_ScrollBarHandleVertical, + SE_SliderHandleHorizontal, + SE_SliderHandleVertical, + SE_TabBarTabEastActive, + SE_TabBarTabEastInactive, + SE_TabBarTabNorthActive, + SE_TabBarTabNorthInactive, + SE_TabBarTabSouthActive, + SE_TabBarTabSouthInactive, + SE_TabBarTabWestActive, + SE_TabBarTabWestInactive, + SE_ListHighlight, + SE_OptionsMenu, + SE_SettingsList, + SE_TableItem, + SE_TableHeaderItem, + SE_ToolTip, //own graphic available on 3.2+ releases, + SE_ToolBar, + SE_ToolBarButton, + SE_ToolBarButtonPressed, + SE_PanelBackground, + SE_ScrollBarHandlePressedHorizontal, //only for 5.0+ + SE_ScrollBarHandlePressedVertical, + SE_ButtonInactive, + SE_Editor, + }; + + enum SkinFrameElements { + SF_ButtonNormal, + SF_ButtonPressed, + SF_FrameLineEdit, + SF_ListHighlight, + SF_OptionsMenu, + SF_SettingsList, + SF_TableItem, + SF_TableHeaderItem, + SF_ToolTip, + SF_ToolBar, + SF_ToolBarButton, + SF_ToolBarButtonPressed, + SF_PanelBackground, + SF_ButtonInactive, + SF_Editor, + }; + + enum SkinElementFlag { + SF_PointNorth = 0x0001, // North = the default + SF_PointEast = 0x0002, + SF_PointSouth = 0x0004, + SF_PointWest = 0x0008, + + SF_StateEnabled = 0x0010, // Enabled = the default + SF_StateDisabled = 0x0020, + SF_ColorSkinned = 0x0040, + }; + + enum CacheClearReason { + CC_UndefinedChange = 0, + CC_LayoutChange, + CC_ThemeChange + }; + + Q_DECLARE_FLAGS(SkinElementFlags, SkinElementFlag) + + // draws skin element + static void drawSkinElement(SkinElements element, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + // draws a specific skin part + static void drawSkinPart(QS60StyleEnums::SkinParts part, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + // sets style property + void setStyleProperty(const char *name, const QVariant &value); + // sets specific style property + void setStyleProperty_specific(const char *name, const QVariant &value); + // gets style property + QVariant styleProperty(const char *name) const; + // gets specific style property + QVariant styleProperty_specific(const char *name) const; + // gets pixel metrics value + static short pixelMetric(int metric); + // gets color. 'index' is NOT 0-based. + // It corresponds to the enum key 1-based numbers of TAknsQsnXYZColorsIndex, not the values. + static QColor s60Color(QS60StyleEnums::ColorLists list, + int index, const QStyleOption *option); + // gets state specific color + static QColor stateColor(const QColor &color, const QStyleOption *option); + // gets lighter color than base color + static QColor lighterColor(const QColor &baseColor); + //deduces if the given widget should have separately themeable background + static bool drawsOwnThemeBackground(const QWidget *widget); + + QFont s60Font(QS60StyleEnums::FontCategories fontCategory, + int pointSize = -1) const; + // clears all style caches (fonts, colors, pixmaps) + void clearCaches(CacheClearReason reason = CC_UndefinedChange); + + // themed main background oprations + void setBackgroundTexture(QApplication *application) const; + static void deleteBackground(); + + static bool isTouchSupported(); + static bool isToolBarBackground(); + + // calculates average color based on button skin graphics (minus borders). + QColor colorFromFrameGraphics(SkinFrameElements frame) const; + + //set theme palette for application + void setThemePalette(QApplication *application) const; + //set theme palette for style option + void setThemePalette(QStyleOption *option) const; + //access to theme palette + static QPalette* themePalette(); + + static int focusRectPenWidth(); + + static const layoutHeader m_layoutHeaders[]; + static const short data[][MAX_PIXELMETRICS]; + + void setCurrentLayout(int layoutIndex); + void setActiveLayout(); + // Pointer + static short const *m_pmPointer; + // number of layouts supported by the style + static const int m_numberOfLayouts; + + mutable QHash<QPair<QS60StyleEnums::FontCategories , int>, QFont> m_mappedFontsCache; + mutable QHash<SkinFrameElements, QColor> m_colorCache; + + // Has one entry per SkinFrameElements + static const struct frameElementCenter { + SkinElements element; + QS60StyleEnums::SkinParts center; + } m_frameElementsData[]; + + static QPixmap frame(SkinFrameElements frame, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + static QPixmap backgroundTexture(); + +private: + static void drawPart(QS60StyleEnums::SkinParts part, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + static void drawRow(QS60StyleEnums::SkinParts start, QS60StyleEnums::SkinParts middle, + QS60StyleEnums::SkinParts end, Qt::Orientation orientation, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + static void drawFrame(SkinFrameElements frame, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + + static QPixmap cachedPart(QS60StyleEnums::SkinParts part, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + static QPixmap cachedFrame(SkinFrameElements frame, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + + static void refreshUI(); + + // set S60 font for widget + void setFont(QWidget *widget) const; + void setThemePalette(QWidget *widget) const; + void setThemePalette(QPalette *palette) const; + void setThemePaletteHash(QPalette *palette) const; + static void storeThemePalette(QPalette *palette); + static void deleteThemePalette(); + + static QSize partSize(QS60StyleEnums::SkinParts part, + SkinElementFlags flags = KDefaultSkinElementFlags); + static QPixmap part(QS60StyleEnums::SkinParts part, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + + static QFont s60Font_specific(QS60StyleEnums::FontCategories fontCategory, int pointSize); + + static QSize screenSize(); + + // Contains background texture. + static QPixmap *m_background; + const static SkinElementFlags KDefaultSkinElementFlags; + // defined theme palette + static QPalette *m_themePalette; + QPalette m_originalPalette; +}; + +QT_END_NAMESPACE + +#endif // QS60STYLE_P_H diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp new file mode 100644 index 0000000..63346da --- /dev/null +++ b/src/gui/styles/qs60style_s60.cpp @@ -0,0 +1,1372 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qs60style.h" +#include "qs60style_p.h" +#include "qpainter.h" +#include "qstyleoption.h" +#include "qstyle.h" +#include "private/qwindowsurface_s60_p.h" +#include "private/qt_s60_p.h" +#include "private/qcore_symbian_p.h" +#include "qapplication.h" + +#include <w32std.h> +#include <aknsconstants.h> +#include <aknconsts.h> +#include <aknsitemid.h> +#include <aknsutils.h> +#include <aknsdrawutils.h> +#include <aknsskininstance.h> +#include <aknsbasicbackgroundcontrolcontext.h> +#include <avkon.mbg> +#include <AknFontAccess.h> +#include <AknLayoutFont.h> +#include <aknutils.h> + +#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +enum TDrawType { + EDrawIcon, + EDrawBackground, + ENoDraw +}; + +enum TSupportRelease { + ES60_None = 0x0000, //indicates that the commonstyle should draw the graphics + ES60_3_1 = 0x0001, + ES60_3_2 = 0x0002, + ES60_5_0 = 0x0004, + ES60_5_1 = 0x0008, + ES60_5_2 = 0x0010, + // Add all new releases here + ES60_AllReleases = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 +}; + +typedef struct { + const TAknsItemID &skinID; + TDrawType drawType; + int supportInfo; + int newMajorSkinId; + int newMinorSkinId; +} partMapEntry; + +class QS60StyleModeSpecifics +{ +public: + static QPixmap skinnedGraphics(QS60StyleEnums::SkinParts stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap skinnedGraphics(QS60StylePrivate::SkinFrameElements frameElement, const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap colorSkinnedGraphics(const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QColor colorValue(const TAknsItemID &colorGroup, int colorIndex); + static QPixmap fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, QImage::Format format); + static bool disabledPartGraphic(QS60StyleEnums::SkinParts &part); + static bool disabledFrameGraphic(QS60StylePrivate::SkinFrameElements &frame); + static QPixmap generateMissingThemeGraphic(QS60StyleEnums::SkinParts &part, const QSize &size, QS60StylePrivate::SkinElementFlags flags); + +private: + static QPixmap createSkinnedGraphicsL(QS60StyleEnums::SkinParts part, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap createSkinnedGraphicsL(QS60StylePrivate::SkinFrameElements frameElement, const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap colorSkinnedGraphicsL(const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static void frameIdAndCenterId(QS60StylePrivate::SkinFrameElements frameElement, TAknsItemID &frameId, TAknsItemID ¢erId); + static TRect innerRectFromElement(QS60StylePrivate::SkinFrameElements frameElement, const TRect &outerRect); + static void checkAndUnCompressBitmapL(CFbsBitmap*& aOriginalBitmap); + static void checkAndUnCompressBitmap(CFbsBitmap*& aOriginalBitmap); + static void unCompressBitmapL(const TRect& aTrgRect, CFbsBitmap* aTrgBitmap, CFbsBitmap* aSrcBitmap); + static void colorGroupAndIndex(QS60StyleEnums::SkinParts skinID, + TAknsItemID &colorGroup, int colorIndex); + static void fallbackInfo(const QS60StyleEnums::SkinParts &stylepart, TDes& fallbackFileName, TInt& fallbackIndex); + static bool checkSupport(const int supportedRelease); + static TAknsItemID checkAndUpdateReleaseSpecificGraphics(int part); + // Array to match the skin ID, fallback graphics and Qt widget graphics. + static const partMapEntry m_partMap[]; +}; + +const partMapEntry QS60StyleModeSpecifics::m_partMap[] = { + /* SP_QgnGrafBarWait */ {KAknsIIDQgnGrafBarWaitAnim, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarFrameCenter */ {KAknsIIDQgnGrafBarFrameCenter, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarFrameSideL */ {KAknsIIDQgnGrafBarFrameSideL, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarFrameSideR */ {KAknsIIDQgnGrafBarFrameSideR, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarProgress */ {KAknsIIDQgnGrafBarProgress, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowDown */ {KAknsIIDQgnGrafScrollArrowDown, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowUp */ {KAknsIIDQgnGrafScrollArrowUp, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiCheckboxOff */ {KAknsIIDQgnIndiCheckboxOff, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiCheckboxOn */ {KAknsIIDQgnIndiCheckboxOn, EDrawIcon, ES60_AllReleases, -1,-1}, + // Following 5 items (SP_QgnIndiHlColSuper - SP_QgnIndiHlLineStraight) are available starting from S60 release 3.2. + // In 3.1 CommonStyle drawing is used for these QTreeView elements, since no similar icons in AVKON UI. + /* SP_QgnIndiHlColSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d5 /* KAknsIIDQgnIndiHlColSuper */}, + /* SP_QgnIndiHlExpSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d6 /* KAknsIIDQgnIndiHlExpSuper */}, + /* SP_QgnIndiHlLineBranch */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d7 /* KAknsIIDQgnIndiHlLineBranch */}, + /* SP_QgnIndiHlLineEnd */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d8 /* KAknsIIDQgnIndiHlLineEnd */}, + /* SP_QgnIndiHlLineStraight */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d9 /* KAknsIIDQgnIndiHlLineStraight */}, + /* SP_QgnIndiMarkedAdd */ {KAknsIIDQgnIndiMarkedAdd, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiNaviArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiNaviArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiRadiobuttOff */ {KAknsIIDQgnIndiRadiobuttOff, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiRadiobuttOn */ {KAknsIIDQgnIndiRadiobuttOn, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiSliderEdit */ {KAknsIIDQgnIndiSliderEdit, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiSubMenu */ {KAknsIIDQgnIndiSubmenu, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteErased */ {KAknsIIDQgnNoteErased, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteError */ {KAknsIIDQgnNoteError, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteInfo */ {KAknsIIDQgnNoteInfo, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteOk */ {KAknsIIDQgnNoteOk, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteQuery */ {KAknsIIDQgnNoteQuery, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteWarning */ {KAknsIIDQgnNoteWarning, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFileSmall */ {KAknsIIDQgnPropFileSmall, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFolderCurrent */ {KAknsIIDQgnPropFolderCurrent, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFolderSmall */ {KAknsIIDQgnPropFolderSmall, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFolderSmallNew */ {KAknsIIDQgnPropFolderSmallNew, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropPhoneMemcLarge */ {KAknsIIDQgnPropPhoneMemcLarge, EDrawIcon, ES60_AllReleases, -1,-1}, + + // 3.1 & 3.2 do not have pressed state for scrollbar, so use normal scrollbar graphics instead. + /* SP_QsnCpScrollHandleBottomPressed*/ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20f8}, /*KAknsIIDQsnCpScrollHandleBottomPressed*/ + /* SP_QsnCpScrollHandleMiddlePressed*/ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20f9}, /*KAknsIIDQsnCpScrollHandleMiddlePressed*/ + /* SP_QsnCpScrollHandleTopPressed*/ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20fa}, /*KAknsIIDQsnCpScrollHandleTopPressed*/ + + /* SP_QsnBgScreen */ {KAknsIIDQsnBgScreen, EDrawBackground, ES60_AllReleases, -1,-1}, + + /* SP_QsnCpScrollBgBottom */ {KAknsIIDQsnCpScrollBgBottom, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollBgMiddle */ {KAknsIIDQsnCpScrollBgMiddle, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollBgTop */ {KAknsIIDQsnCpScrollBgTop, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnCpScrollHandleBottom */ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollHandleMiddle */ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollHandleTop */ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrButtonTbCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, //todo: use "normal button" from 5.0 onwards + /* SP_QsnFrButtonTbCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCenter */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrButtonTbCornerTlPressed */{KAknsIIDQsnFrButtonTbCornerTlPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerTrPressed */{KAknsIIDQsnFrButtonTbCornerTrPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBlPressed */{KAknsIIDQsnFrButtonTbCornerBlPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBrPressed */{KAknsIIDQsnFrButtonTbCornerBrPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideTPressed */ {KAknsIIDQsnFrButtonTbSideTPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideBPressed */ {KAknsIIDQsnFrButtonTbSideBPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideLPressed */ {KAknsIIDQsnFrButtonTbSideLPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideRPressed */ {KAknsIIDQsnFrButtonTbSideRPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCenterPressed */ {KAknsIIDQsnFrButtonTbCenterPressed, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrCaleCornerTl */ {KAknsIIDQsnFrCaleCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCornerTr */ {KAknsIIDQsnFrCaleCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCornerBl */ {KAknsIIDQsnFrCaleCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCornerBr */ {KAknsIIDQsnFrCaleCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideT */ {KAknsIIDQsnFrCaleSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideB */ {KAknsIIDQsnFrCaleSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideL */ {KAknsIIDQsnFrCaleSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideR */ {KAknsIIDQsnFrCaleSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCenter */ {KAknsIIDQsnFrCaleCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrCaleHeadingCornerTl */ {KAknsIIDQsnFrCaleHeadingCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCornerTr */ {KAknsIIDQsnFrCaleHeadingCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCornerBl */ {KAknsIIDQsnFrCaleHeadingCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCornerBr */ {KAknsIIDQsnFrCaleHeadingCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideT */ {KAknsIIDQsnFrCaleHeadingSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideB */ {KAknsIIDQsnFrCaleHeadingSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideL */ {KAknsIIDQsnFrCaleHeadingSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideR */ {KAknsIIDQsnFrCaleHeadingSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCenter */ {KAknsIIDQsnFrCaleHeadingCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrInputCornerTl */ {KAknsIIDQsnFrInputCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCornerTr */ {KAknsIIDQsnFrInputCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCornerBl */ {KAknsIIDQsnFrInputCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCornerBr */ {KAknsIIDQsnFrInputCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideT */ {KAknsIIDQsnFrInputSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideB */ {KAknsIIDQsnFrInputSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideL */ {KAknsIIDQsnFrInputSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideR */ {KAknsIIDQsnFrInputSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCenter */ {KAknsIIDQsnFrInputCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrListCornerTl */ {KAknsIIDQsnFrListCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCornerTr */ {KAknsIIDQsnFrListCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCornerBl */ {KAknsIIDQsnFrListCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCornerBr */ {KAknsIIDQsnFrListCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideT */ {KAknsIIDQsnFrListSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideB */ {KAknsIIDQsnFrListSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideL */ {KAknsIIDQsnFrListSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideR */ {KAknsIIDQsnFrListSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCenter */ {KAknsIIDQsnFrListCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrPopupCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + // ToolTip graphics different in 3.1 vs. 3.2+. + /* SP_QsnFrPopupPreviewCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c5}, /* KAknsIIDQsnFrPopupPreviewCornerTl */ + /* SP_QsnFrPopupPreviewCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c6}, + /* SP_QsnFrPopupPreviewCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c3}, + /* SP_QsnFrPopupPreviewCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c4}, + /* SP_QsnFrPopupPreviewSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19ca}, + /* SP_QsnFrPopupPreviewSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c7}, + /* SP_QsnFrPopupPreviewSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c8}, + /* SP_QsnFrPopupPreviewSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c9}, + /* SP_QsnFrPopupPreviewCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c2}, + + /* SP_QsnFrSetOptCornerTl */ {KAknsIIDQsnFrSetOptCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCornerTr */ {KAknsIIDQsnFrSetOptCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCornerBl */ {KAknsIIDQsnFrSetOptCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCornerBr */ {KAknsIIDQsnFrSetOptCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideT */ {KAknsIIDQsnFrSetOptSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideB */ {KAknsIIDQsnFrSetOptSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideL */ {KAknsIIDQsnFrSetOptSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideR */ {KAknsIIDQsnFrSetOptSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCenter */ {KAknsIIDQsnFrSetOptCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + // No toolbar frame for 5.0+ releases. + /* SP_QsnFrPopupSubCornerTl */ {KAknsIIDQsnFrPopupSubCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCornerTr */ {KAknsIIDQsnFrPopupSubCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCornerBl */ {KAknsIIDQsnFrPopupSubCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCornerBr */ {KAknsIIDQsnFrPopupSubCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideT */ {KAknsIIDQsnFrPopupSubSideT, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideB */ {KAknsIIDQsnFrPopupSubSideB, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideL */ {KAknsIIDQsnFrPopupSubSideL, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideR */ {KAknsIIDQsnFrPopupSubSideR, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCenter */ {KAknsIIDQsnFrPopupCenterSubmenu, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + + // Toolbar graphics is different in 3.1/3.2 vs. 5.0 + /* SP_QsnFrSctrlButtonCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2301}, /* KAknsIIDQgnFrSctrlButtonCornerTl*/ + /* SP_QsnFrSctrlButtonCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2302}, + /* SP_QsnFrSctrlButtonCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2303}, + /* SP_QsnFrSctrlButtonCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2304}, + /* SP_QsnFrSctrlButtonSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2305}, + /* SP_QsnFrSctrlButtonSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2306}, + /* SP_QsnFrSctrlButtonSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2307}, + /* SP_QsnFrSctrlButtonSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2308}, + /* SP_QsnFrSctrlButtonCenter */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2309}, /*KAknsIIDQgnFrSctrlButtonCenter*/ + + // No pressed state for toolbar button in 3.1/3.2. + /* SP_QsnFrSctrlButtonCornerTlPressed */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2621}, /*KAknsIIDQsnFrSctrlButtonCornerTlPressed*/ + /* SP_QsnFrSctrlButtonCornerTrPressed */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2622}, + /* SP_QsnFrSctrlButtonCornerBlPressed */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2623}, + /* SP_QsnFrSctrlButtonCornerBrPressed */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2624}, + /* SP_QsnFrSctrlButtonSideTPressed */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2625}, + /* SP_QsnFrSctrlButtonSideBPressed */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2626}, + /* SP_QsnFrSctrlButtonSideLPressed */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2627}, + /* SP_QsnFrSctrlButtonSideRPressed */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2628}, + /* SP_QsnFrSctrlButtonCenterPressed */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2629}, + + // No inactive button graphics in 3.1/3.2 + /* SP_QsnFrButtonCornerTlInactive */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b1}, /*KAknsIIDQsnFrButtonCornerTlInactive*/ + /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b2}, + /* SP_QsnFrButtonCornerBlInactive */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b3}, + /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b4}, + /* SP_QsnFrButtonSideTInactive */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b5}, + /* SP_QsnFrButtonSideBInactive */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b6}, + /* SP_QsnFrButtonSideLInactive */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b7}, + /* SP_QsnFrButtonSideRInactive */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b8}, + /* SP_QsnFrButtonCenterInactive */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b9}, + + /* SP_QsnFrNotepadCornerTl */ {KAknsIIDQsnFrNotepadContCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCornerTr */ {KAknsIIDQsnFrNotepadContCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCornerBl */ {KAknsIIDQsnFrNotepadCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCornerBr */ {KAknsIIDQsnFrNotepadCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideT */ {KAknsIIDQsnFrNotepadContSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideB */ {KAknsIIDQsnFrNotepadSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideL */ {KAknsIIDQsnFrNotepadSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideR */ {KAknsIIDQsnFrNotepadSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCenter */ {KAknsIIDQsnFrNotepadCenter, EDrawIcon, ES60_AllReleases, -1,-1}, + +}; + +QPixmap QS60StyleModeSpecifics::skinnedGraphics( + QS60StyleEnums::SkinParts stylepart, const QSize &size, + QS60StylePrivate::SkinElementFlags flags) +{ + QPixmap themedImage; + TRAPD( error, { + const QPixmap skinnedImage = createSkinnedGraphicsL(stylepart, size, flags); + themedImage = skinnedImage; + }); + if (error) + return themedImage = QPixmap(); + return themedImage; +} + +QPixmap QS60StyleModeSpecifics::skinnedGraphics( + QS60StylePrivate::SkinFrameElements frame, const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + QPixmap themedImage; + TRAPD( error, { + const QPixmap skinnedImage = createSkinnedGraphicsL(frame, size, flags); + themedImage = skinnedImage; + }); + if (error) + return themedImage = QPixmap(); + return themedImage; +} + +QPixmap QS60StyleModeSpecifics::colorSkinnedGraphics( + const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + QPixmap colorGraphics; + TRAPD(error, colorGraphics = colorSkinnedGraphicsL(stylepart, size, flags)); + return error ? QPixmap() : colorGraphics; +} + +void QS60StyleModeSpecifics::fallbackInfo(const QS60StyleEnums::SkinParts &stylepart, TDes& fallbackFileName, TInt& fallbackIndex) +{ + switch(stylepart) { + case QS60StyleEnums::SP_QgnGrafBarWait: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_wait_1; + break; + case QS60StyleEnums::SP_QgnGrafBarFrameCenter: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_frame_center; + break; + case QS60StyleEnums::SP_QgnGrafBarFrameSideL: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_frame_side_l; + break; + case QS60StyleEnums::SP_QgnGrafBarFrameSideR: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_frame_side_r; + break; + case QS60StyleEnums::SP_QgnGrafBarProgress: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_progress; + break; + case QS60StyleEnums::SP_QgnGrafTabActiveL: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_active_l; + break; + case QS60StyleEnums::SP_QgnGrafTabActiveM: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_active_m; + break; + case QS60StyleEnums::SP_QgnGrafTabActiveR: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_active_r; + break; + case QS60StyleEnums::SP_QgnGrafTabPassiveL: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_passive_l; + break; + case QS60StyleEnums::SP_QgnGrafTabPassiveM: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_passive_m; + break; + case QS60StyleEnums::SP_QgnGrafTabPassiveR: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_passive_r; + break; + case QS60StyleEnums::SP_QgnIndiCheckboxOff: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_checkbox_off; + break; + case QS60StyleEnums::SP_QgnIndiCheckboxOn: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_checkbox_on; + break; + case QS60StyleEnums::SP_QgnIndiHlColSuper: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x4456; /* EMbmAvkonQgn_indi_hl_col_super */ + break; + case QS60StyleEnums::SP_QgnIndiHlExpSuper: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x4458; /* EMbmAvkonQgn_indi_hl_exp_super */ + break; + case QS60StyleEnums::SP_QgnIndiHlLineBranch: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x445A; /* EMbmAvkonQgn_indi_hl_line_branch */ + break; + case QS60StyleEnums::SP_QgnIndiHlLineEnd: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x445C; /* EMbmAvkonQgn_indi_hl_line_end */ + break; + case QS60StyleEnums::SP_QgnIndiHlLineStraight: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x445E; /* EMbmAvkonQgn_indi_hl_line_straight */ + break; + case QS60StyleEnums::SP_QgnIndiMarkedAdd: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_marked_add; + break; + case QS60StyleEnums::SP_QgnIndiNaviArrowLeft: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_navi_arrow_left; + break; + case QS60StyleEnums::SP_QgnIndiNaviArrowRight: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_navi_arrow_right; + break; + case QS60StyleEnums::SP_QgnIndiRadiobuttOff: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_radiobutt_off; + break; + case QS60StyleEnums::SP_QgnIndiRadiobuttOn: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_radiobutt_on; + break; + case QS60StyleEnums::SP_QgnIndiSliderEdit: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_slider_edit; + break; + case QS60StyleEnums::SP_QgnIndiSubMenu: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_submenu; + break; + case QS60StyleEnums::SP_QgnNoteErased: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_erased; + break; + case QS60StyleEnums::SP_QgnNoteError: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_error; + break; + case QS60StyleEnums::SP_QgnNoteInfo: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_info; + break; + case QS60StyleEnums::SP_QgnNoteOk: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_ok; + break; + case QS60StyleEnums::SP_QgnNoteQuery: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_query; + break; + case QS60StyleEnums::SP_QgnNoteWarning: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_warning; + break; + case QS60StyleEnums::SP_QgnPropFileSmall: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_file_small; + break; + case QS60StyleEnums::SP_QgnPropFolderCurrent: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_folder_current; + break; + case QS60StyleEnums::SP_QgnPropFolderSmall: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_folder_small; + break; + case QS60StyleEnums::SP_QgnPropFolderSmallNew: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_folder_small_new; + break; + case QS60StyleEnums::SP_QgnPropPhoneMemcLarge: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_phone_memc_large; + break; + default: + fallbackFileName = KNullDesC(); + fallbackIndex = -1; + break; + } +} + +QPixmap QS60StyleModeSpecifics::colorSkinnedGraphicsL( + const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + const int stylepartIndex = (int)stylepart; + const TAknsItemID skinId = m_partMap[stylepartIndex].skinID; + + TInt fallbackGraphicID = -1; + HBufC* iconFile = HBufC::NewLC( KMaxFileName ); + TPtr fileNamePtr = iconFile->Des(); + fallbackInfo(stylepart, fileNamePtr, fallbackGraphicID); + + TAknsItemID colorGroup = KAknsIIDQsnIconColors; + int colorIndex = 0; + colorGroupAndIndex(stylepart, colorGroup, colorIndex); + + const bool rotatedBy90or270 = + (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)); + const TSize targetSize = + rotatedBy90or270?TSize(size.height(), size.width()):TSize(size.width(), size.height()); + CFbsBitmap *icon = 0; + CFbsBitmap *iconMask = 0; + const TInt fallbackGraphicsMaskID = + fallbackGraphicID == KErrNotFound?KErrNotFound:fallbackGraphicID+1; //masks are auto-generated as next in mif files + MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + AknsUtils::CreateColorIconLC( + skinInstance, skinId, colorGroup, colorIndex, icon, iconMask, fileNamePtr, fallbackGraphicID , fallbackGraphicsMaskID, KRgbBlack); + User::LeaveIfError(AknIconUtils::SetSize(icon, targetSize, EAspectRatioNotPreserved)); + User::LeaveIfError(AknIconUtils::SetSize(iconMask, targetSize, EAspectRatioNotPreserved)); + QPixmap result = fromFbsBitmap(icon, iconMask, flags, qt_TDisplayMode2Format(icon->DisplayMode())); + CleanupStack::PopAndDestroy(3); //icon, iconMask, iconFile + return result; +} + +QColor QS60StyleModeSpecifics::colorValue(const TAknsItemID &colorGroup, int colorIndex) +{ + TRgb skinnedColor; + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + AknsUtils::GetCachedColor(skin, skinnedColor, colorGroup, colorIndex); + return QColor(skinnedColor.Red(),skinnedColor.Green(),skinnedColor.Blue()); +} + +QPixmap QS60StyleModeSpecifics::fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, QImage::Format format) +{ + Q_ASSERT(icon); + const TSize iconSize = icon->SizeInPixels(); + const int iconBytesPerLine = CFbsBitmap::ScanLineLength(iconSize.iWidth, icon->DisplayMode()); + const int iconBytesCount = iconBytesPerLine * iconSize.iHeight; + + QImage iconImage(qt_TSize2QSize(iconSize), format); + if (iconImage.isNull()) + return QPixmap(); + + checkAndUnCompressBitmap(icon); + if (!icon) //checkAndUnCompressBitmap might set icon to NULL + return QPixmap(); + + icon->LockHeap(); + const uchar *const iconBytes = (uchar*)icon->DataAddress(); + // The icon data needs to be copied, since the color format will be + // automatically converted to Format_ARGB32 when setAlphaChannel is called. + memcpy(iconImage.bits(), iconBytes, iconBytesCount); + icon->UnlockHeap(); + if (mask) { + checkAndUnCompressBitmap(mask); + if (mask) { //checkAndUnCompressBitmap might set mask to NULL + const TSize maskSize = icon->SizeInPixels(); + const int maskBytesPerLine = CFbsBitmap::ScanLineLength(maskSize.iWidth, mask->DisplayMode()); + mask->LockHeap(); + const uchar *const maskBytes = (uchar *)mask->DataAddress(); + // Since no other bitmap should be locked, we can just "borrow" the mask data for setAlphaChannel + const QImage maskImage(maskBytes, maskSize.iWidth, maskSize.iHeight, maskBytesPerLine, QImage::Format_Indexed8); + if (!maskImage.isNull()) + iconImage.setAlphaChannel(maskImage); + mask->UnlockHeap(); + } + } + + QTransform imageTransform; + if (flags & QS60StylePrivate::SF_PointEast) { + imageTransform.rotate(90); + } else if (flags & QS60StylePrivate::SF_PointSouth) { + imageTransform.rotate(180); + iconImage = iconImage.transformed(imageTransform); + } else if (flags & QS60StylePrivate::SF_PointWest) { + imageTransform.rotate(270); + } + if (imageTransform.isRotating()) + iconImage = iconImage.transformed(imageTransform); + + return QPixmap::fromImage(iconImage); +} + +bool QS60StylePrivate::isTouchSupported() +{ + return bool(AknLayoutUtils::PenEnabled()); +} + +bool QS60StylePrivate::isToolBarBackground() +{ + return (QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); +} + +QPoint qt_s60_fill_background_offset(const QWidget *targetWidget) +{ + CCoeControl *control = targetWidget->effectiveWinId(); + TPoint globalPos = control ? control->PositionRelativeToScreen() : TPoint(0,0); + return QPoint(globalPos.iX, globalPos.iY); +} + +QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsL( + QS60StyleEnums::SkinParts part, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + if (!size.isValid()) + return QPixmap(); + + // Check release support and change part, if necessary. + const TAknsItemID skinId = checkAndUpdateReleaseSpecificGraphics((int)part); + const int stylepartIndex = (int)part; + const TDrawType drawType = m_partMap[stylepartIndex].drawType; + Q_ASSERT(drawType != ENoDraw); + const bool rotatedBy90or270 = + (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)); + const TSize targetSize = + rotatedBy90or270 ? TSize(size.height(), size.width()) : qt_QSize2TSize(size); + + MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + + QPixmap result; + + switch (drawType) { + case EDrawIcon: { + TInt fallbackGraphicID = -1; + HBufC* iconFile = HBufC::NewLC( KMaxFileName ); + TPtr fileNamePtr = iconFile->Des(); + fallbackInfo(part, fileNamePtr, fallbackGraphicID); + // todo: could we instead use AknIconUtils::AvkonIconFileName(); to avoid allocating each time? + + CFbsBitmap *icon = 0; + CFbsBitmap *iconMask = 0; + const TInt fallbackGraphicsMaskID = + fallbackGraphicID == KErrNotFound?KErrNotFound:fallbackGraphicID+1; //masks are auto-generated as next in mif files + // QS60WindowSurface::unlockBitmapHeap(); + AknsUtils::CreateIconLC(skinInstance, skinId, icon, iconMask, fileNamePtr, fallbackGraphicID , fallbackGraphicsMaskID); + User::LeaveIfError(AknIconUtils::SetSize(icon, targetSize, EAspectRatioNotPreserved)); + User::LeaveIfError(AknIconUtils::SetSize(iconMask, targetSize, EAspectRatioNotPreserved)); + result = fromFbsBitmap(icon, iconMask, flags, qt_TDisplayMode2Format(icon->DisplayMode())); + CleanupStack::PopAndDestroy(3); // iconMask, icon, iconFile + // QS60WindowSurface::lockBitmapHeap(); + break; + } + case EDrawBackground: { + // QS60WindowSurface::unlockBitmapHeap(); + CFbsBitmap *background = new (ELeave) CFbsBitmap(); //offscreen + CleanupStack::PushL(background); + User::LeaveIfError(background->Create(targetSize, EColor16MA)); + + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(background); + CleanupStack::PushL(dev); + CFbsBitGc* gc = NULL; + User::LeaveIfError(dev->CreateContext(gc)); + CleanupStack::PushL(gc); + + CAknsBasicBackgroundControlContext* bgContext = CAknsBasicBackgroundControlContext::NewL( + skinId, + targetSize, + EFalse); + CleanupStack::PushL(bgContext); + + const TBool drawn = AknsDrawUtils::DrawBackground( + skinInstance, + bgContext, + NULL, + *gc, + TPoint(), + targetSize, + KAknsDrawParamDefault | KAknsDrawParamRGBOnly); + + if (drawn) + result = fromFbsBitmap(background, NULL, flags, QImage::Format_RGB32); + + CleanupStack::PopAndDestroy(4, background); //background, dev, gc, bgContext + // QS60WindowSurface::lockBitmapHeap(); + break; + } + } + + return result; +} + +QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsL(QS60StylePrivate::SkinFrameElements frameElement, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + if (!size.isValid()) + return QPixmap(); + + const bool rotatedBy90or270 = + (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)); + const TSize targetSize = + rotatedBy90or270 ? TSize(size.height(), size.width()) : qt_QSize2TSize(size); + + MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + QPixmap result; + +// QS60WindowSurface::unlockBitmapHeap(); + static const bool canDoEColor16MAP = !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); + static const TDisplayMode displayMode = canDoEColor16MAP ? TDisplayMode(13) : EColor16MA; // 13 = EColor16MAP + static const TInt drawParam = canDoEColor16MAP ? KAknsDrawParamDefault : KAknsDrawParamNoClearUnderImage|KAknsDrawParamRGBOnly; + + CFbsBitmap *frame = new (ELeave) CFbsBitmap(); //offscreen + CleanupStack::PushL(frame); + User::LeaveIfError(frame->Create(targetSize, displayMode)); + + CFbsBitmapDevice* bitmapDev = CFbsBitmapDevice::NewL(frame); + CleanupStack::PushL(bitmapDev); + CFbsBitGc* bitmapGc = NULL; + User::LeaveIfError(bitmapDev->CreateContext(bitmapGc)); + CleanupStack::PushL(bitmapGc); + + frame->LockHeap(); + memset(frame->DataAddress(), 0, frame->SizeInPixels().iWidth * frame->SizeInPixels().iHeight * 4); // 4: argb bytes + frame->UnlockHeap(); + + const TRect outerRect(TPoint(0, 0), targetSize); + const TRect innerRect = innerRectFromElement(frameElement, outerRect); + + TAknsItemID frameSkinID, centerSkinID; + frameSkinID = centerSkinID = checkAndUpdateReleaseSpecificGraphics(QS60StylePrivate::m_frameElementsData[frameElement].center); + frameIdAndCenterId(frameElement, frameSkinID, centerSkinID); + const TBool drawn = AknsDrawUtils::DrawFrame( skinInstance, + *bitmapGc, outerRect, innerRect, + frameSkinID, centerSkinID, + drawParam ); + + if (canDoEColor16MAP) { + if (drawn) + result = fromFbsBitmap(frame, NULL, flags, QImage::Format_ARGB32_Premultiplied); + } else { + TDisplayMode maskDepth = EGray2; + // Query the skin item for possible frame graphics mask details. + if (skinInstance) { + CAknsMaskedBitmapItemData* skinMaskedBmp = static_cast<CAknsMaskedBitmapItemData*>( + skinInstance->GetCachedItemData(frameSkinID,EAknsITMaskedBitmap)); + if (skinMaskedBmp && skinMaskedBmp->Mask()) + maskDepth = skinMaskedBmp->Mask()->DisplayMode(); + } + if (maskDepth != ENone) { + CFbsBitmap *frameMask = new (ELeave) CFbsBitmap(); //offscreen + CleanupStack::PushL(frameMask); + User::LeaveIfError(frameMask->Create(targetSize, maskDepth)); + + CFbsBitmapDevice* maskBitmapDevice = CFbsBitmapDevice::NewL(frameMask); + CleanupStack::PushL(maskBitmapDevice); + CFbsBitGc* maskBitGc = NULL; + User::LeaveIfError(maskBitmapDevice->CreateContext(maskBitGc)); + CleanupStack::PushL(maskBitGc); + + if (drawn) { + //ensure that the mask is really transparent + maskBitGc->Activate( maskBitmapDevice ); + maskBitGc->SetPenStyle(CGraphicsContext::ENullPen); + maskBitGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + maskBitGc->SetBrushColor(KRgbWhite); + maskBitGc->Clear(); + maskBitGc->SetBrushStyle(CGraphicsContext::ENullBrush); + + AknsDrawUtils::DrawFrame(skinInstance, + *maskBitGc, outerRect, innerRect, + frameSkinID, centerSkinID, + KAknsSDMAlphaOnly |KAknsDrawParamNoClearUnderImage); + result = fromFbsBitmap(frame, frameMask, flags, QImage::Format_ARGB32); + } + CleanupStack::PopAndDestroy(3, frameMask); + } + } + CleanupStack::PopAndDestroy(3, frame); //frame, bitmapDev, bitmapGc + return result; +} + +void QS60StyleModeSpecifics::frameIdAndCenterId(QS60StylePrivate::SkinFrameElements frameElement, TAknsItemID &frameId, TAknsItemID ¢erId) +{ +// There are some major mix-ups in skin declarations for some frames. +// First, the frames are not declared in sequence. +// Second, the parts use different major than the frame-master. + + switch(frameElement) { + case QS60StylePrivate::SF_ToolTip: + if (QSysInfo::s60Version()!=QSysInfo::SV_S60_3_1) { + centerId.Set(EAknsMajorGeneric, 0x19c2); + frameId.Set(EAknsMajorSkin, 0x5300); + } else { + centerId.Set(KAknsIIDQsnFrPopupCenter); + frameId.iMinor = centerId.iMinor - 9; + } + break; + case QS60StylePrivate::SF_ToolBar: + if (QSysInfo::s60Version()==QSysInfo::SV_S60_3_1 || QSysInfo::s60Version()==QSysInfo::SV_S60_3_2) { + centerId.Set(KAknsIIDQsnFrPopupCenterSubmenu); + frameId.Set(KAknsIIDQsnFrPopupSub); + } + break; + case QS60StylePrivate::SF_PanelBackground: + // remove center piece for panel graphics, so that only border is drawn + centerId.Set(KAknsIIDNone); + frameId.Set(KAknsIIDQsnFrSetOpt); + break; + case QS60StylePrivate::SF_Editor: + centerId.Set(KAknsIIDQsnFrNotepadCenter); + frameId.Set(KAknsIIDQsnFrNotepadCont); + break; + default: + // center should be correct here + frameId.iMinor = centerId.iMinor - 9; + break; + } +} + +TRect QS60StyleModeSpecifics::innerRectFromElement(QS60StylePrivate::SkinFrameElements frameElement, const TRect &outerRect) +{ + TInt widthShrink = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth); + TInt heightShrink = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerHeight); + switch(frameElement) { + case QS60StylePrivate::SF_PanelBackground: + // panel should have slightly slimmer border to enable thin line of background graphics between closest component + widthShrink = widthShrink-2; + heightShrink = heightShrink-2; + break; + case QS60StylePrivate::SF_ToolTip: + widthShrink = widthShrink>>1; + heightShrink = heightShrink>>1; + break; + case QS60StylePrivate::SF_ListHighlight: + widthShrink = widthShrink-2; + heightShrink = heightShrink-2; + break; + default: + break; + } + TRect innerRect(outerRect); + innerRect.Shrink(widthShrink, heightShrink); + return innerRect; +} + +bool QS60StyleModeSpecifics::checkSupport(const int supportedRelease) +{ + const QSysInfo::S60Version currentRelease = QSysInfo::s60Version(); + return ( (currentRelease == QSysInfo::SV_S60_3_1 && supportedRelease & ES60_3_1) || + (currentRelease == QSysInfo::SV_S60_3_2 && supportedRelease & ES60_3_2) || + (currentRelease == QSysInfo::SV_S60_5_0 && supportedRelease & ES60_5_0)); +} + +TAknsItemID QS60StyleModeSpecifics::checkAndUpdateReleaseSpecificGraphics(int part) +{ + TAknsItemID newSkinId; + if (!checkSupport(m_partMap[(int)part].supportInfo)) + newSkinId.Set(m_partMap[(int)part].newMajorSkinId, m_partMap[(int)part].newMinorSkinId); + else + newSkinId.Set(m_partMap[(int)part].skinID); + return newSkinId; +} + +void QS60StyleModeSpecifics::checkAndUnCompressBitmap(CFbsBitmap*& aOriginalBitmap) +{ + TRAPD(error, checkAndUnCompressBitmapL(aOriginalBitmap)); + if (error) + aOriginalBitmap = NULL; +} + +void QS60StyleModeSpecifics::checkAndUnCompressBitmapL(CFbsBitmap*& aOriginalBitmap) +{ + if (aOriginalBitmap->IsCompressedInRAM()) { + const TSize iconSize(aOriginalBitmap->SizeInPixels().iWidth, + aOriginalBitmap->SizeInPixels().iHeight); + CFbsBitmap* uncompressedBitmap = new (ELeave) CFbsBitmap(); + CleanupStack::PushL(uncompressedBitmap); + User::LeaveIfError(uncompressedBitmap->Create(iconSize, + aOriginalBitmap->DisplayMode())); + unCompressBitmapL(iconSize, uncompressedBitmap, aOriginalBitmap); + CleanupStack::Pop(uncompressedBitmap); + User::LeaveIfError(aOriginalBitmap->Duplicate( + uncompressedBitmap->Handle())); + delete uncompressedBitmap; + } +} + +QFont QS60StylePrivate::s60Font_specific( + QS60StyleEnums::FontCategories fontCategory, int pointSize) +{ + TAknFontCategory aknFontCategory = EAknFontCategoryUndefined; + switch (fontCategory) { + case QS60StyleEnums::FC_Primary: + aknFontCategory = EAknFontCategoryPrimary; + break; + case QS60StyleEnums::FC_Secondary: + aknFontCategory = EAknFontCategorySecondary; + break; + case QS60StyleEnums::FC_Title: + aknFontCategory = EAknFontCategoryTitle; + break; + case QS60StyleEnums::FC_PrimarySmall: + aknFontCategory = EAknFontCategoryPrimarySmall; + break; + case QS60StyleEnums::FC_Digital: + aknFontCategory = EAknFontCategoryDigital; + break; + case QS60StyleEnums::FC_Undefined: + default: + break; + } + + // Create AVKON font according the given parameters + CWsScreenDevice* dev = CCoeEnv::Static()->ScreenDevice(); + TAknFontSpecification spec(aknFontCategory, TFontSpec(), NULL); + if (pointSize > 0) { + const TInt pixelSize = dev->VerticalTwipsToPixels(pointSize * KTwipsPerPoint); + spec.SetTextPaneHeight(pixelSize + 4); // TODO: Is 4 a reasonable top+bottom margin? + } + + QFont result; + TRAPD( error, { + const CAknLayoutFont* aknFont = + AknFontAccess::CreateLayoutFontFromSpecificationL(*dev, spec); + + result = qt_TFontSpec2QFontL(aknFont->DoFontSpecInTwips()); + if (result.pointSize() != pointSize) + result.setPointSize(pointSize); // Correct the font size returned by CreateLayoutFontFromSpecificationL() + + delete aknFont; + }); + if (error) result = QFont(); + return result; +} + +void QS60StylePrivate::setActiveLayout() +{ + const QSize activeScreenSize(screenSize()); + int activeLayoutIndex = -1; + const bool mirrored = !QApplication::isLeftToRight(); + const short screenHeight = (short)activeScreenSize.height(); + const short screenWidth = (short)activeScreenSize.width(); + for (int i=0; i<m_numberOfLayouts; i++) { + if (screenHeight==m_layoutHeaders[i].height && + screenWidth==m_layoutHeaders[i].width && + mirrored==m_layoutHeaders[i].mirroring) { + activeLayoutIndex = i; + break; + } + } + + //not found, lets try without mirroring info + if (activeLayoutIndex==-1){ + for (int i=0; i<m_numberOfLayouts; i++) { + if (screenHeight==m_layoutHeaders[i].height && + screenWidth==m_layoutHeaders[i].width) { + activeLayoutIndex = i; + break; + } + } + } + + //not found, lets try with either of dimensions + if (activeLayoutIndex==-1){ + const QSysInfo::S60Version currentRelease = QSysInfo::s60Version(); + const bool landscape = screenHeight < screenWidth; + + activeLayoutIndex = (currentRelease == QSysInfo::SV_S60_3_1 || currentRelease == QSysInfo::SV_S60_3_2) ? 0 : 4; + activeLayoutIndex += (!landscape) ? 2 : 0; + activeLayoutIndex += (!mirrored) ? 1 : 0; + } + + m_pmPointer = data[activeLayoutIndex]; +} + +QS60StylePrivate::QS60StylePrivate() +{ + // No need to set active layout, if dynamic metrics API is available + setActiveLayout(); +} + +void QS60StylePrivate::setStyleProperty_specific(const char *name, const QVariant &value) +{ + if (name == QLatin1String("foo")) { + // BaR + } else { + setStyleProperty(name, value); + } +} + +QVariant QS60StylePrivate::styleProperty_specific(const char *name) const +{ + if (name == QLatin1String("foo")) + return QLatin1String("Bar"); + else + return styleProperty(name); +} + +QColor QS60StylePrivate::s60Color(QS60StyleEnums::ColorLists list, + int index, const QStyleOption *option) +{ + static const TAknsItemID *idMap[] = { + &KAknsIIDQsnHighlightColors, + &KAknsIIDQsnIconColors, + &KAknsIIDQsnLineColors, + &KAknsIIDQsnOtherColors, + &KAknsIIDQsnParentColors, + &KAknsIIDQsnTextColors + }; + Q_ASSERT((int)list <= (int)sizeof(idMap)/sizeof(idMap[0])); + const QColor color = QS60StyleModeSpecifics::colorValue(*idMap[(int) list], index - 1); + return option ? QS60StylePrivate::stateColor(color, option) : color; +} + +// In some cases, the AVKON UI themegraphic is already in 'disabled state'. +// If so, return true for these parts. +bool QS60StyleModeSpecifics::disabledPartGraphic(QS60StyleEnums::SkinParts &part) +{ + bool disabledGraphic = false; + switch(part){ + // inactive button graphics are available from 5.0 onwards + case QS60StyleEnums::SP_QsnFrButtonCornerTlInactive: + case QS60StyleEnums::SP_QsnFrButtonCornerTrInactive: + case QS60StyleEnums::SP_QsnFrButtonCornerBlInactive: + case QS60StyleEnums::SP_QsnFrButtonCornerBrInactive: + case QS60StyleEnums::SP_QsnFrButtonSideTInactive: + case QS60StyleEnums::SP_QsnFrButtonSideBInactive: + case QS60StyleEnums::SP_QsnFrButtonSideLInactive: + case QS60StyleEnums::SP_QsnFrButtonSideRInactive: + case QS60StyleEnums::SP_QsnFrButtonCenterInactive: + if (!(QSysInfo::s60Version()==QSysInfo::SV_S60_3_1 || + QSysInfo::s60Version()==QSysInfo::SV_S60_3_2)) + disabledGraphic = true; + break; + default: + break; + } + return disabledGraphic; +} + +// In some cases, the AVKON UI themegraphic is already in 'disabled state'. +// If so, return true for these frames. +bool QS60StyleModeSpecifics::disabledFrameGraphic(QS60StylePrivate::SkinFrameElements &frame) +{ + bool disabledGraphic = false; + switch(frame){ + // inactive button graphics are available from 5.0 onwards + case QS60StylePrivate::SF_ButtonInactive: + if (!(QSysInfo::s60Version()==QSysInfo::SV_S60_3_1 || + QSysInfo::s60Version()==QSysInfo::SV_S60_3_2)) + disabledGraphic = true; + break; + default: + break; + } + return disabledGraphic; +} + +QPixmap QS60StyleModeSpecifics::generateMissingThemeGraphic(QS60StyleEnums::SkinParts &part, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + if (!QS60StylePrivate::isTouchSupported()) + return QPixmap(); + + QS60StyleEnums::SkinParts updatedPart = part; + switch(part){ + // AVKON UI has a abnormal handling for scrollbar graphics. It is possible that the root + // skin does not contain mandatory graphics for scrollbar pressed states. Therefore, AVKON UI + // creates dynamically these graphics by modifying the normal state scrollbar graphics slightly. + // S60Style needs to work similarly. Therefore if skingraphics call provides to be a miss + // (i.e. result is not valid), style needs to draw normal graphics instead and apply some + // modifications (similar to generatedIconPixmap()) to the result. + case QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed: + updatedPart = QS60StyleEnums::SP_QsnCpScrollHandleBottom; + break; + case QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed: + updatedPart = QS60StyleEnums::SP_QsnCpScrollHandleMiddle; + break; + case QS60StyleEnums::SP_QsnCpScrollHandleTopPressed: + updatedPart = QS60StyleEnums::SP_QsnCpScrollHandleTop; + break; + default: + break; + } + if (part==updatedPart) { + return QPixmap(); + } else { + QPixmap result = skinnedGraphics(updatedPart, size, flags); + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + + // For now, always generate new icon based on "selected". In the future possibly, expand + // this to consist other possibilities as well. + result = QApplication::style()->generatedIconPixmap(QIcon::Selected, result, &opt); + return result; + } +} + +QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, + const QSize &size, SkinElementFlags flags) +{ + QS60WindowSurface::unlockBitmapHeap(); + QPixmap result = (flags & SF_ColorSkinned)? + QS60StyleModeSpecifics::colorSkinnedGraphics(part, size, flags) + : QS60StyleModeSpecifics::skinnedGraphics(part, size, flags); + QS60WindowSurface::lockBitmapHeap(); + + if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledPartGraphic(part)) { + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + + if (!result) + result = QS60StyleModeSpecifics::generateMissingThemeGraphic(part, size, flags); + + return result; +} + +QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags) +{ + QS60WindowSurface::unlockBitmapHeap(); + QPixmap result = QS60StyleModeSpecifics::skinnedGraphics(frame, size, flags); + QS60WindowSurface::lockBitmapHeap(); + + if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledFrameGraphic(frame)) { + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + return result; +} + +QPixmap QS60StylePrivate::backgroundTexture() +{ + if (!m_background) { + QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen, + QSize(S60->screenWidthInPixels, S60->screenHeightInPixels), SkinElementFlags()); + m_background = new QPixmap(background); + } + return *m_background; +} + +// If the public SDK returns compressed images, please let us also uncompress those! +void QS60StyleModeSpecifics::unCompressBitmapL(const TRect& aTrgRect, CFbsBitmap* aTrgBitmap, CFbsBitmap* aSrcBitmap) +{ + if (!aSrcBitmap) + User::Leave(KErrArgument); + if (!aTrgBitmap) + User::Leave(KErrArgument); + + // Note! aSrcBitmap->IsCompressedInRAM() is always ETrue, since this method is called only if that applies! + ASSERT(aSrcBitmap->IsCompressedInRAM()); + + TDisplayMode displayMode = aSrcBitmap->DisplayMode(); + + if (displayMode != aTrgBitmap->DisplayMode()) + User::Leave(KErrArgument); + + const TSize trgSize = aTrgBitmap->SizeInPixels(); + const TSize srcSize = aSrcBitmap->SizeInPixels(); + + // calculate the valid drawing area + TRect drawRect = aTrgRect; + drawRect.Intersection(TRect(TPoint(0, 0), trgSize)); + + if (drawRect.IsEmpty()) + return; + + CFbsBitmap* realSource = new (ELeave) CFbsBitmap(); + CleanupStack::PushL(realSource); + User::LeaveIfError(realSource->Create(srcSize, displayMode)); + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(realSource); + CleanupStack::PushL(dev); + CFbsBitGc* gc = NULL; + User::LeaveIfError(dev->CreateContext(gc)); + CleanupStack::PushL(gc); + gc->BitBlt(TPoint(0, 0), aSrcBitmap); + CleanupStack::PopAndDestroy(2); // dev, gc + + // Heap lock for FBServ large chunk is only needed with large bitmaps. + if (realSource->IsLargeBitmap() || aTrgBitmap->IsLargeBitmap()) { + aTrgBitmap->LockHeapLC(ETrue); // fbsheaplock + } else { + CleanupStack::PushL((TAny*) NULL); + } + + TUint32* srcAddress = realSource->DataAddress(); + TUint32* trgAddress = aTrgBitmap->DataAddress(); + + const TInt xSkip = (srcSize.iWidth << 8) / aTrgRect.Width(); + const TInt ySkip = (srcSize.iHeight << 8) / aTrgRect.Height(); + + const TInt drawWidth = drawRect.Width(); + const TInt drawHeight = drawRect.Height(); + + const TRect offsetRect(aTrgRect.iTl, drawRect.iTl); + const TInt yPosOffset = ySkip * offsetRect.Height(); + const TInt xPosOffset = xSkip * offsetRect.Width(); + + if ((displayMode == EGray256) || (displayMode == EColor256)) { + const TInt srcScanLen8 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode); + const TInt trgScanLen8 = CFbsBitmap::ScanLineLength(trgSize.iWidth, + displayMode); + + TUint8* trgAddress8 = reinterpret_cast<TUint8*> (trgAddress); + + TInt yPos = yPosOffset; + // skip left and top margins in the beginning + trgAddress8 += trgScanLen8 * drawRect.iTl.iY + drawRect.iTl.iX; + + for (TInt y = 0; y < drawHeight; y++) { + const TUint8* srcAddress8 = reinterpret_cast<const TUint8*> (srcAddress) + + (srcScanLen8 * (yPos >> 8)); + + TInt xPos = xPosOffset; + for (TInt x = 0; x < drawWidth; x++) { + *(trgAddress8++) = srcAddress8[xPos >> 8]; + xPos += xSkip; + } + + yPos += ySkip; + + trgAddress8 += trgScanLen8 - drawWidth; + } + } else if (displayMode == EColor4K || displayMode == EColor64K) { + const TInt srcScanLen16 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode) >>1; + const TInt trgScanLen16 = CFbsBitmap::ScanLineLength(trgSize.iWidth, + displayMode) >>1; + + TUint16* trgAddress16 = reinterpret_cast<TUint16*> (trgAddress); + + TInt yPos = yPosOffset; + // skip left and top margins in the beginning + trgAddress16 += trgScanLen16 * drawRect.iTl.iY + drawRect.iTl.iX; + + for (TInt y = 0; y < drawHeight; y++) { + const TUint16* srcAddress16 = reinterpret_cast<const TUint16*> (srcAddress) + + (srcScanLen16 * (yPos >> 8)); + + TInt xPos = xPosOffset; + for (TInt x = 0; x < drawWidth; x++) { + *(trgAddress16++) = srcAddress16[xPos >> 8]; + xPos += xSkip; + } + + yPos += ySkip; + + trgAddress16 += trgScanLen16 - drawWidth; + } + } else if (displayMode == EColor16MU || displayMode == EColor16MA) { + const TInt srcScanLen32 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode) >>2; + const TInt trgScanLen32 = CFbsBitmap::ScanLineLength(trgSize.iWidth, + displayMode) >>2; + + TUint32* trgAddress32 = reinterpret_cast<TUint32*> (trgAddress); + + TInt yPos = yPosOffset; + // skip left and top margins in the beginning + trgAddress32 += trgScanLen32 * drawRect.iTl.iY + drawRect.iTl.iX; + + for (TInt y = 0; y < drawHeight; y++) { + const TUint32* srcAddress32 = reinterpret_cast<const TUint32*> (srcAddress) + + (srcScanLen32 * (yPos >> 8)); + + TInt xPos = xPosOffset; + for (TInt x = 0; x < drawWidth; x++) { + *(trgAddress32++) = srcAddress32[xPos >> 8]; + xPos += xSkip; + } + + yPos += ySkip; + + trgAddress32 += trgScanLen32 - drawWidth; + } + } else { User::Leave(KErrUnknown);} + + CleanupStack::PopAndDestroy(2); // fbsheaplock, realSource +} + +QSize QS60StylePrivate::screenSize() +{ + const TSize screenSize = QS60Data::screenDevice()->SizeInPixels(); + return QSize(screenSize.iWidth, screenSize.iHeight); +} + +void QS60StyleModeSpecifics::colorGroupAndIndex( + QS60StyleEnums::SkinParts skinID, TAknsItemID &colorGroup, int colorIndex) +{ + switch(skinID) { + case QS60StyleEnums::SP_QgnIndiSubMenu: + colorGroup = KAknsIIDQsnIconColors; + colorIndex = EAknsCIQsnIconColorsCG1; + break; + case QS60StyleEnums::SP_QgnIndiRadiobuttOff: + case QS60StyleEnums::SP_QgnIndiRadiobuttOn: + case QS60StyleEnums::SP_QgnIndiCheckboxOff: + case QS60StyleEnums::SP_QgnIndiCheckboxOn: + colorGroup = KAknsIIDQsnIconColors; + colorIndex = EAknsCIQsnIconColorsCG14; + break; + default: + break; + } +} + +/*! + Constructs a QS60Style object. +*/ +QS60Style::QS60Style() + : QCommonStyle(*new QS60StylePrivate) +{ +} + +void QS60Style::handleDynamicLayoutVariantSwitch() +{ + Q_D(QS60Style); + d->clearCaches(QS60StylePrivate::CC_LayoutChange); + d->setActiveLayout(); + d->refreshUI(); + d->setBackgroundTexture(qApp); + foreach (QWidget *widget, QApplication::allWidgets()) + widget->ensurePolished(); +} + +void QS60Style::handleSkinChange() +{ + Q_D(QS60Style); + d->clearCaches(QS60StylePrivate::CC_ThemeChange); + d->setThemePalette(qApp); + foreach (QWidget *topLevelWidget, QApplication::allWidgets()){ + QEvent e(QEvent::StyleChange); + QApplication::sendEvent(topLevelWidget, &e); + d->setThemePalette(topLevelWidget); + topLevelWidget->ensurePolished(); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_STYLE_S60 || QT_PLUGIN diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp new file mode 100644 index 0000000..684f232 --- /dev/null +++ b/src/gui/styles/qs60style_simulated.cpp @@ -0,0 +1,449 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qs60style.h" +#include "qs60style_p.h" +#include "qfile.h" +#include "qhash.h" +#include "qapplication.h" +#include "qpainter.h" +#include "qpicture.h" +#include "qstyleoption.h" +#include "qtransform.h" +#include "qlayout.h" +#include "qpixmapcache.h" +#include "qmetaobject.h" +#include "qdebug.h" +#include "qbuffer.h" +#include "qdesktopwidget.h" + +#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +static const quint32 blobVersion = 1; +static const int pictureSize = 256; + +#if defined(Q_CC_GNU) +#if __GNUC__ >= 2 +#define __FUNCTION__ __func__ +#endif +#endif + + +bool saveThemeToBlob(const QString &themeBlob, + const QHash<QString, QPicture> &partPictures, + const QHash<QPair<QString, int>, QColor> &colors) +{ + QFile blob(themeBlob); + if (!blob.open(QIODevice::WriteOnly)) { + qWarning() << __FUNCTION__ << ": Could not create blob: " << themeBlob; + return false; + } + + QByteArray data; + QBuffer dataBuffer(&data); + dataBuffer.open(QIODevice::WriteOnly); + QDataStream dataOut(&dataBuffer); + + const int colorsCount = colors.count(); + dataOut << colorsCount; + const QList<QPair<QString, int> > colorKeys = colors.keys(); + for (int i = 0; i < colorsCount; ++i) { + const QPair<QString, int> &key = colorKeys.at(i); + dataOut << key; + const QColor color = colors.value(key); + dataOut << color; + } + + const int picturesCount = partPictures.count(); + dataOut << picturesCount; + foreach (const QString &key, partPictures.keys()) { + const QPicture picture = partPictures.value(key); + dataOut << key; + dataOut << picture; + } + + QDataStream blobOut(&blob); + blobOut << blobVersion; + blobOut << qCompress(data); + return blobOut.status() == QDataStream::Ok; +} + +bool loadThemeFromBlob(const QString &themeBlob, + QHash<QString, QPicture> &partPictures, + QHash<QPair<QString, int>, QColor> &colors) +{ + QFile blob(themeBlob); + if (!blob.open(QIODevice::ReadOnly)) { + qWarning() << __FUNCTION__ << ": Could not read blob: " << themeBlob; + return false; + } + QDataStream blobIn(&blob); + + quint32 version; + blobIn >> version; + + if (version != blobVersion) { + qWarning() << __FUNCTION__ << ": Invalid blob version: " << version << " ...expected: " << blobVersion; + return false; + } + + QByteArray data; + blobIn >> data; + data = qUncompress(data); + QBuffer dataBuffer(&data); + dataBuffer.open(QIODevice::ReadOnly); + QDataStream dataIn(&dataBuffer); + + int colorsCount; + dataIn >> colorsCount; + for (int i = 0; i < colorsCount; ++i) { + QPair<QString, int> key; + dataIn >> key; + QColor value; + dataIn >> value; + colors.insert(key, value); + } + + int picturesCount; + dataIn >> picturesCount; + for (int i = 0; i < picturesCount; ++i) { + QString key; + dataIn >> key; + QPicture value; + dataIn >> value; + value.setBoundingRect(QRect(0, 0, pictureSize, pictureSize)); // Bug? The forced bounding rect was not deserialized. + partPictures.insert(key, value); + } + + if (dataIn.status() != QDataStream::Ok) { + qWarning() << __FUNCTION__ << ": Invalid data blob: " << themeBlob; + return false; + } + return true; +} + +class QS60StyleModeSpecifics +{ +public: + static QPixmap skinnedGraphics(QS60StyleEnums::SkinParts stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QHash<QString, QPicture> m_partPictures; + static QHash<QPair<QString , int>, QColor> m_colors; +}; +QHash<QString, QPicture> QS60StyleModeSpecifics::m_partPictures; +QHash<QPair<QString , int>, QColor> QS60StyleModeSpecifics::m_colors; + +QS60StylePrivate::QS60StylePrivate() +{ + setCurrentLayout(0); +} + +QColor QS60StylePrivate::s60Color(QS60StyleEnums::ColorLists list, + int index, const QStyleOption *option) +{ + const QString listKey = QS60Style::colorListKeys().at(list); + return QS60StylePrivate::stateColor( + QS60StyleModeSpecifics::m_colors.value(QPair<QString, int>(listKey, index)), + option + ); +} + +QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, const QSize &size, + QS60StylePrivate::SkinElementFlags flags) +{ + const QString partKey = QS60Style::partKeys().at(part); + const QPicture partPicture = QS60StyleModeSpecifics::m_partPictures.value(partKey); + QSize partSize(partPicture.boundingRect().size()); + if (flags & (SF_PointEast | SF_PointWest)) { + const int temp = partSize.width(); + partSize.setWidth(partSize.height()); + partSize.setHeight(temp); + } + const qreal scaleX = size.width() / (qreal)partSize.width(); + const qreal scaleY = size.height() / (qreal)partSize.height(); + + QImage partImage(size, QImage::Format_ARGB32); + partImage.fill(Qt::transparent); + QPainter resultPainter(&partImage); + QTransform t; + + if (flags & SF_PointEast) + t.translate(size.width(), 0); + else if (flags & SF_PointSouth) + t.translate(size.width(), size.height()); + else if (flags & SF_PointWest) + t.translate(0, size.height()); + + t.scale(scaleX, scaleY); + + if (flags & SF_PointEast) + t.rotate(90); + else if (flags & SF_PointSouth) + t.rotate(180); + else if (flags & SF_PointWest) + t.rotate(270); + + resultPainter.setTransform(t, true); + const_cast<QPicture *>(&partPicture)->play(&resultPainter); + resultPainter.end(); + + QPixmap result = QPixmap::fromImage(partImage); + if (flags & SF_StateDisabled) { + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + + return result; +} + +QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, + SkinElementFlags flags) +{ + const QS60StyleEnums::SkinParts center = m_frameElementsData[frame].center; + const QS60StyleEnums::SkinParts topLeft = QS60StyleEnums::SkinParts(center - 8); + const QS60StyleEnums::SkinParts topRight = QS60StyleEnums::SkinParts(center - 7); + const QS60StyleEnums::SkinParts bottomLeft = QS60StyleEnums::SkinParts(center - 6); + const QS60StyleEnums::SkinParts bottomRight = QS60StyleEnums::SkinParts(center - 5); + const QS60StyleEnums::SkinParts top = QS60StyleEnums::SkinParts(center - 4); + const QS60StyleEnums::SkinParts bottom = QS60StyleEnums::SkinParts(center - 3); + const QS60StyleEnums::SkinParts left = QS60StyleEnums::SkinParts(center - 2); + const QS60StyleEnums::SkinParts right = QS60StyleEnums::SkinParts(center - 1); + + // The size of topLeft defines all other sizes + const QSize cornerSize(partSize(topLeft)); + // if frame is so small that corners would cover it completely, draw only center piece + const bool drawOnlyCenter = + 2 * cornerSize.width() + 1 >= size.width() || 2 * cornerSize.height() + 1 >= size.height(); + + const int cornerWidth = cornerSize.width(); + const int cornerHeight = cornerSize.height(); + const int rectWidth = size.width(); + const int rectHeight = size.height(); + const QRect rect(QPoint(), size); + + const QRect topLeftRect = QRect(rect.topLeft(), cornerSize); + const QRect topRect = rect.adjusted(cornerWidth, 0, -cornerWidth, -(rectHeight - cornerHeight)); + const QRect topRightRect = topLeftRect.translated(rectWidth - cornerWidth, 0); + const QRect rightRect = rect.adjusted(rectWidth - cornerWidth, cornerHeight, 0, -cornerHeight); + const QRect bottomRightRect = topRightRect.translated(0, rectHeight - cornerHeight); + const QRect bottomRect = topRect.translated(0, rectHeight - cornerHeight); + const QRect bottomLeftRect = topLeftRect.translated(0, rectHeight - cornerHeight); + const QRect leftRect = rightRect.translated(cornerWidth - rectWidth, 0); + const QRect centerRect = drawOnlyCenter ? rect : rect.adjusted(cornerWidth, cornerWidth, -cornerWidth, -cornerWidth); + + QPixmap result(size); + result.fill(Qt::transparent); + QPainter painter(&result); + +#if 0 + painter.save(); + painter.setOpacity(.3); + painter.fillRect(topLeftRect, Qt::red); + painter.fillRect(topRect, Qt::green); + painter.fillRect(topRightRect, Qt::blue); + painter.fillRect(rightRect, Qt::green); + painter.fillRect(bottomRightRect, Qt::red); + painter.fillRect(bottomRect, Qt::blue); + painter.fillRect(bottomLeftRect, Qt::green); + painter.fillRect(leftRect, Qt::blue); + painter.fillRect(centerRect, Qt::red); + painter.restore(); +#else + drawPart(topLeft, &painter, topLeftRect, flags); + drawPart(top, &painter, topRect, flags); + drawPart(topRight, &painter, topRightRect, flags); + drawPart(right, &painter, rightRect, flags); + drawPart(bottomRight, &painter, bottomRightRect, flags); + drawPart(bottom, &painter, bottomRect, flags); + drawPart(bottomLeft, &painter, bottomLeftRect, flags); + drawPart(left, &painter, leftRect, flags); + drawPart(center, &painter, centerRect, flags); +#endif + + return result; +} + +void QS60StylePrivate::setStyleProperty_specific(const char *name, const QVariant &value) +{ + setStyleProperty(name, value); +} + +QVariant QS60StylePrivate::styleProperty_specific(const char *name) const +{ + return styleProperty(name); +} + +QPixmap QS60StylePrivate::backgroundTexture() +{ + if (!m_background) { + const QSize size = QApplication::desktop()->screen()->size(); + QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen, size); + m_background = new QPixmap(background); + } + return *m_background; +} + + +bool QS60StylePrivate::isTouchSupported() +{ +#ifdef QT_KEYPAD_NAVIGATION + return !QApplication::keypadNavigationEnabled(); +#else + return true; +#endif +} + +bool QS60StylePrivate::isToolBarBackground() +{ + return true; +} + +QFont QS60StylePrivate::s60Font_specific(QS60StyleEnums::FontCategories fontCategory, int pointSize) +{ + QFont result; + result.setPointSize(pointSize); + switch (fontCategory) { + case QS60StyleEnums::FC_Primary: + result.setBold(true); + break; + case QS60StyleEnums::FC_Secondary: + case QS60StyleEnums::FC_Title: + case QS60StyleEnums::FC_PrimarySmall: + case QS60StyleEnums::FC_Digital: + case QS60StyleEnums::FC_Undefined: + default: + break; + } + return result; +} + +/*! + Constructs a QS60Style object. +*/ +QS60Style::QS60Style() + : QCommonStyle(*new QS60StylePrivate) +{ + // Assume, that the resource system has a ':/s60Stylethemes/Default.blob' + const QString defaultBlob = QString::fromLatin1(":/s60Stylethemes/Default.blob"); + if (QFile::exists(defaultBlob)) + loadS60ThemeFromBlob(defaultBlob); +} + +Q_GLOBAL_STATIC_WITH_INITIALIZER(QStringList, enumPartKeys, { + const int enumIndex = QS60StyleEnums::staticMetaObject.indexOfEnumerator("SkinParts"); + Q_ASSERT(enumIndex >= 0); + const QMetaEnum metaEnum = QS60StyleEnums::staticMetaObject.enumerator(enumIndex); + for (int i = 0; i < metaEnum.keyCount(); ++i) { + const QString enumKey = QString::fromLatin1(metaEnum.key(i)); + QString partKey; + // Following loop does following conversions: "SP_QgnNoteInfo" to "qgn_note_info"... + for (int charPosition = 3; charPosition < enumKey.length(); charPosition++) { + if (charPosition > 3 && enumKey[charPosition].isUpper()) + partKey.append(QChar::fromLatin1('_')); + partKey.append(enumKey[charPosition].toLower()); + } + x->append(partKey); + } +}) + +QStringList QS60Style::partKeys() +{ + return *enumPartKeys(); +} + +Q_GLOBAL_STATIC_WITH_INITIALIZER(QStringList, enumColorListKeys, { + const int enumIndex = QS60StyleEnums::staticMetaObject.indexOfEnumerator("ColorLists"); + Q_ASSERT(enumIndex >= 0); + const QMetaEnum metaEnum = QS60StyleEnums::staticMetaObject.enumerator(enumIndex); + for (int i = 0; i < metaEnum.keyCount(); i++) { + const QString enumKey = QString::fromLatin1(metaEnum.key(i)); + // Following line does following conversions: CL_QsnTextColors to "text"... + x->append(enumKey.mid(6, enumKey.length() - 12).toLower()); + } +}) + +QStringList QS60Style::colorListKeys() +{ + return *enumColorListKeys(); +} + +void QS60Style::setS60Theme(const QHash<QString, QPicture> &parts, + const QHash<QPair<QString , int>, QColor> &colors) +{ + Q_D(QS60Style); + QS60StyleModeSpecifics::m_partPictures = parts; + QS60StyleModeSpecifics::m_colors = colors; + d->clearCaches(QS60StylePrivate::CC_ThemeChange); + d->setBackgroundTexture(qApp); + d->setThemePalette(qApp); +} + +bool QS60Style::loadS60ThemeFromBlob(const QString &blobFile) +{ + QHash<QString, QPicture> partPictures; + QHash<QPair<QString, int>, QColor> colors; + + if (!loadThemeFromBlob(blobFile, partPictures, colors)) + return false; + setS60Theme(partPictures, colors); + return true; +} + +bool QS60Style::saveS60ThemeToBlob(const QString &blobFile) const +{ + return saveThemeToBlob(blobFile, + QS60StyleModeSpecifics::m_partPictures, QS60StyleModeSpecifics::m_colors); +} + +QPoint qt_s60_fill_background_offset(const QWidget *targetWidget) +{ + Q_UNUSED(targetWidget) + return QPoint(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_STYLE_S60 || QT_PLUGIN diff --git a/src/gui/styles/qstyle_s60_simulated.qrc b/src/gui/styles/qstyle_s60_simulated.qrc new file mode 100644 index 0000000..72aab9e --- /dev/null +++ b/src/gui/styles/qstyle_s60_simulated.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource prefix="/trolltech/styles/s60style"> + <file>images/s60themes.dat</file> + </qresource> +</RCC> diff --git a/src/gui/styles/qstylefactory.cpp b/src/gui/styles/qstylefactory.cpp index 376aa0f..2e0448c 100644 --- a/src/gui/styles/qstylefactory.cpp +++ b/src/gui/styles/qstylefactory.cpp @@ -69,6 +69,9 @@ #ifndef QT_NO_STYLE_WINDOWSMOBILE #include "qwindowsmobilestyle.h" #endif +#ifndef QT_NO_STYLE_S60 +#include "qs60style.h" +#endif QT_BEGIN_NAMESPACE @@ -154,6 +157,11 @@ QStyle *QStyleFactory::create(const QString& key) ret = new QCDEStyle; else #endif +#ifndef QT_NO_STYLE_S60 + if (style == QLatin1String("s60")) + ret = new QS60Style; + else +#endif #ifndef QT_NO_STYLE_PLASTIQUE if (style == QLatin1String("plastique")) ret = new QPlastiqueStyle; @@ -233,6 +241,10 @@ QStringList QStyleFactory::keys() if (!list.contains(QLatin1String("CDE"))) list << QLatin1String("CDE"); #endif +#ifndef QT_NO_STYLE_S60 + if (!list.contains(QLatin1String("S60"))) + list << QLatin1String("S60"); +#endif #ifndef QT_NO_STYLE_PLASTIQUE if (!list.contains(QLatin1String("Plastique"))) list << QLatin1String("Plastique"); diff --git a/src/gui/styles/qstylesheetstyle_default.cpp b/src/gui/styles/qstylesheetstyle_default.cpp index 742cfe1..74e23b8 100644 --- a/src/gui/styles/qstylesheetstyle_default.cpp +++ b/src/gui/styles/qstylesheetstyle_default.cpp @@ -154,11 +154,12 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const Value value; Pseudo pseudo; AttributeSelector attr; - + // pixmap based style doesn't support any features bool styleIsPixmapBased = baseStyle()->inherits("QMacStyle") || baseStyle()->inherits("QWindowsXPStyle") - || baseStyle()->inherits("QGtkStyle"); + || baseStyle()->inherits("QGtkStyle") + || baseStyle()->inherits("QS60Style"); /*QLineEdit { @@ -212,7 +213,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const ADD_BASIC_SELECTOR; ADD_SELECTOR; - + SET_PROPERTY(QLatin1String("padding-top"), PaddingTop); ADD_VALUE(Value::Identifier, QString::fromLatin1("2px")); ADD_DECLARATION; diff --git a/src/gui/styles/styles.pri b/src/gui/styles/styles.pri index d255f80..fcc9125 100644 --- a/src/gui/styles/styles.pri +++ b/src/gui/styles/styles.pri @@ -161,3 +161,19 @@ contains( styles, windowsmobile ) { DEFINES += QT_NO_STYLE_WINDOWSMOBILE } +contains( styles, s60 ) { + HEADERS += \ + styles/qs60style.h \ + styles/qs60style_p.h + SOURCES += styles/qs60style.cpp + symbian { + SOURCES += styles/qs60style_s60.cpp + # TODO: fix the following LIBS hack. Line 1 is for armv5, 2 for winscw + LIBS += aknicon aknskins aknskinsrv fontutils + LIBS += -laknicon -laknskins -laknskinsrv -lfontutils + } else { + SOURCES += styles/qs60style_simulated.cpp + } +} else { + DEFINES += QT_NO_STYLE_S60 +} diff --git a/src/gui/text/qabstractfontengine_p.h b/src/gui/text/qabstractfontengine_p.h index 4752de5..59b54bd 100644 --- a/src/gui/text/qabstractfontengine_p.h +++ b/src/gui/text/qabstractfontengine_p.h @@ -91,7 +91,7 @@ public: virtual Type type() const { return Proxy; } virtual const char *name() const { return "proxy engine"; } -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) virtual void draw(QPaintEngine *, qreal, qreal, const QTextItemInt &); #endif diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index a05e5a1..e1b39a0 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -48,6 +48,7 @@ #include <qfontmetrics.h> #include <qbrush.h> #include <qimagereader.h> +#include "private/qfunctions_p.h" #ifndef QT_NO_CSSPARSER @@ -338,12 +339,12 @@ static const QCssKnownValue styleFeatures[NumKnownStyleFeatures - 1] = { { "none", StyleFeature_None } }; -static bool operator<(const QString &name, const QCssKnownValue &prop) +Q_STATIC_GLOBAL_OPERATOR bool operator<(const QString &name, const QCssKnownValue &prop) { return QString::compare(name, QLatin1String(prop.name), Qt::CaseInsensitive) < 0; } -static bool operator<(const QCssKnownValue &prop, const QString &name) +Q_STATIC_GLOBAL_OPERATOR bool operator<(const QCssKnownValue &prop, const QString &name) { return QString::compare(QLatin1String(prop.name), name, Qt::CaseInsensitive) < 0; } diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index c5096bf..e324db6 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -72,6 +72,9 @@ #include "qfontengine_qpf_p.h" #endif #endif +#ifdef Q_WS_S60 +#include "qt_s60_p.h" +#endif #include <QMutexLocker> @@ -169,6 +172,8 @@ Q_GUI_EXPORT int qt_defaultDpiX() if (!subScreens.isEmpty()) screen = subScreens.at(0); dpi = qRound(screen->width() / (screen->physicalWidth() / qreal(25.4))); +#elif defined(Q_WS_S60) + dpi = S60->defaultDpiX; #endif // Q_WS_X11 return dpi; @@ -195,6 +200,8 @@ Q_GUI_EXPORT int qt_defaultDpiY() if (!subScreens.isEmpty()) screen = subScreens.at(0); dpi = qRound(screen->height() / (screen->physicalHeight() / qreal(25.4))); +#elif defined(Q_WS_S60) + dpi = S60->defaultDpiY; #endif // Q_WS_X11 return dpi; @@ -307,7 +314,7 @@ QFontPrivate *QFontPrivate::smallCapsFontPrivate() const font.setPointSizeF(pointSize * .7); else font.setPixelSize((font.pixelSize() * 7 + 5) / 10); - scFont = font.d; + scFont = font.d.data(); if (scFont != this) scFont->ref.ref(); return scFont; @@ -714,12 +721,11 @@ QFont::QFont(const QFont &font, QPaintDevice *pd) const int screen = 0; #endif if (font.d->dpi != dpi || font.d->screen != screen ) { - d = new QFontPrivate(*font.d); + d.reset(new QFontPrivate(*font.d)); d->dpi = dpi; d->screen = screen; } else { - d = font.d; - d->ref.ref(); + d.assign(font.d.data()); } #ifdef Q_WS_WIN if (pd->devType() == QInternal::Printer && pd->getDC()) @@ -733,8 +739,7 @@ QFont::QFont(const QFont &font, QPaintDevice *pd) QFont::QFont(QFontPrivate *data) : resolve_mask(QFont::AllPropertiesResolved) { - d = data; - d->ref.ref(); + d.assign(data); } /*! \internal @@ -746,13 +751,13 @@ void QFont::detach() if (d->engineData) d->engineData->ref.deref(); d->engineData = 0; - if (d->scFont && d->scFont != d) + if (d->scFont && d->scFont != d.data()) d->scFont->ref.deref(); d->scFont = 0; return; } - qAtomicDetach(d); + d.detach(); } /*! @@ -761,9 +766,9 @@ void QFont::detach() \sa QApplication::setFont(), QApplication::font() */ QFont::QFont() - :d(QApplication::font().d), resolve_mask(0) + :resolve_mask(0) { - d->ref.ref(); + d.assign(QApplication::font().d.data()); } /*! @@ -783,12 +788,16 @@ QFont::QFont() setStyleHint() QApplication::font() */ QFont::QFont(const QString &family, int pointSize, int weight, bool italic) - :d(new QFontPrivate) { + d.reset(new QFontPrivate()); resolve_mask = QFont::FamilyResolved; if (pointSize <= 0) { +#ifdef Q_WS_S60 + pointSize = 7; +#else pointSize = 12; +#endif } else { resolve_mask |= QFont::SizeResolved; } @@ -811,8 +820,7 @@ QFont::QFont(const QString &family, int pointSize, int weight, bool italic) */ QFont::QFont(const QFont &font) { - d = font.d; - d->ref.ref(); + d.assign(font.d.data()); resolve_mask = font.resolve_mask; } @@ -821,8 +829,6 @@ QFont::QFont(const QFont &font) */ QFont::~QFont() { - if (!d->ref.deref()) - delete d; } /*! @@ -830,7 +836,7 @@ QFont::~QFont() */ QFont &QFont::operator=(const QFont &font) { - qAtomicAssign(d, font.d); + d.assign(font.d.data()); resolve_mask = font.resolve_mask; return *this; } @@ -1713,7 +1719,7 @@ QFont QFont::resolve(const QFont &other) const QFont font(*this); font.detach(); - font.d->resolve(resolve_mask, other.d); + font.d->resolve(resolve_mask, other.d.data()); return font; } @@ -2166,11 +2172,11 @@ QDataStream &operator<<(QDataStream &s, const QFont &font) s << (quint8) font.d->request.styleStrategy; s << (quint8) 0 << (quint8) font.d->request.weight - << get_font_bits(s.version(), font.d); + << get_font_bits(s.version(), font.d.data()); if (s.version() >= QDataStream::Qt_4_3) s << (quint16)font.d->request.stretch; if (s.version() >= QDataStream::Qt_4_4) - s << get_extended_font_bits(font.d); + s << get_extended_font_bits(font.d.data()); if (s.version() >= QDataStream::Qt_4_5) { s << font.d->letterSpacing.value(); s << font.d->wordSpacing.value(); @@ -2189,10 +2195,8 @@ QDataStream &operator<<(QDataStream &s, const QFont &font) */ QDataStream &operator>>(QDataStream &s, QFont &font) { - if (!font.d->ref.deref()) - delete font.d; - - font.d = new QFontPrivate; + font.d.assign(0); + font.d.reset(new QFontPrivate); font.resolve_mask = QFont::AllPropertiesResolved; quint8 styleHint, styleStrategy = QFont::PreferDefault, charSet, weight, bits; @@ -2233,7 +2237,7 @@ QDataStream &operator>>(QDataStream &s, QFont &font) font.d->request.styleStrategy = styleStrategy; font.d->request.weight = weight; - set_font_bits(s.version(), bits, font.d); + set_font_bits(s.version(), bits, font.d.data()); if (s.version() >= QDataStream::Qt_4_3) { quint16 stretch; @@ -2244,7 +2248,7 @@ QDataStream &operator>>(QDataStream &s, QFont &font) if (s.version() >= QDataStream::Qt_4_4) { quint8 extendedBits; s >> extendedBits; - set_extended_font_bits(extendedBits, font.d); + set_extended_font_bits(extendedBits, font.d.data()); } if (s.version() >= QDataStream::Qt_4_5) { int value; @@ -2326,7 +2330,7 @@ QDataStream &operator>>(QDataStream &s, QFont &font) that is not screen-compatible. */ QFontInfo::QFontInfo(const QFont &font) - : d(font.d) + : d(font.d.data()) { d->ref.ref(); } /*! @@ -2599,7 +2603,14 @@ QFontCache *QFontCache::instance() void QFontCache::cleanup() { - theFontCache()->setLocalData(0); + QThreadStorage<QFontCache *> *cache = 0; + QT_TRY { + cache = theFontCache(); + } QT_CATCH (const std::bad_alloc &) { + // no cache - just ignore + } + if (cache && cache->hasLocalData()) + cache->setLocalData(0); } #endif // QT_NO_THREAD @@ -2612,8 +2623,8 @@ QFontCache::QFontCache() QFontCache::~QFontCache() { { - EngineDataCache::Iterator it = engineDataCache.begin(), - end = engineDataCache.end(); + EngineDataCache::ConstIterator it = engineDataCache.constBegin(), + end = engineDataCache.constEnd(); while (it != end) { if (it.value()->ref == 0) delete it.value(); @@ -2623,8 +2634,8 @@ QFontCache::~QFontCache() ++it; } } - EngineCache::Iterator it = engineCache.begin(), - end = engineCache.end(); + EngineCache::ConstIterator it = engineCache.constBegin(), + end = engineCache.constEnd(); while (it != end) { if (--it.value().data->cache_count == 0) { if (it.value().data->ref == 0) { diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h index eec83b5..a513b7a 100644 --- a/src/gui/text/qfont.h +++ b/src/gui/text/qfont.h @@ -44,6 +44,7 @@ #include <QtGui/qwindowdefs.h> #include <QtCore/qstring.h> +#include <QtCore/qscopedpointer.h> #if defined(Q_WS_X11) || defined(Q_WS_QWS) typedef struct FT_FaceRec_* FT_Face; @@ -312,7 +313,7 @@ private: friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QFont &); #endif - QFontPrivate *d; + QScopedSharedPointer<QFontPrivate> d; uint resolve_mask; }; diff --git a/src/gui/text/qfont_s60.cpp b/src/gui/text/qfont_s60.cpp new file mode 100644 index 0000000..533e51f --- /dev/null +++ b/src/gui/text/qfont_s60.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfont.h" +#include "qt_s60_p.h" +#include <private/qwindowsurface_s60_p.h> +#include "qmutex.h" + +QT_BEGIN_NAMESPACE + +#if 1 +#ifdef QT_NO_FREETYPE +Q_GLOBAL_STATIC(QMutex, lastResortFamilyMutex); +#endif // QT_NO_FREETYPE + +QString QFont::lastResortFamily() const +{ +#ifdef QT_NO_FREETYPE + QMutexLocker locker(lastResortFamilyMutex()); + static QString family; + if (family.isEmpty()) { + QS60WindowSurface::unlockBitmapHeap(); + CFont *font; + const TInt err = S60->screenDevice()->GetNearestFontInTwips(font, TFontSpec()); + Q_ASSERT(err == KErrNone); + const TFontSpec spec = font->FontSpecInTwips(); + family = QString((const QChar *)spec.iTypeface.iName.Ptr(), spec.iTypeface.iName.Length()); + S60->screenDevice()->ReleaseFont(font); + QS60WindowSurface::lockBitmapHeap(); + } + return family; +#else + // For the FreeType case we just hard code the face name, since otherwise on + // East Asian systems we may get a name for a stroke based (non-ttf) font. + + // TODO: Get the type face name in a proper way + + const bool isJapaneseOrChineseSystem = + User::Language() == ELangJapanese || User::Language() == ELangPrcChinese; + + return QLatin1String(isJapaneseOrChineseSystem?"Heisei Kaku Gothic S60":"Series 60 Sans"); +#endif // QT_NO_FREETYPE +} +#else // 0 +QString QFont::lastResortFamily() const +{ + return QLatin1String("Series 60 Sans"); +} +#endif // 0 + +QString QFont::defaultFamily() const +{ + return lastResortFamily(); +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index e9f067a..76f5c39 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -56,6 +56,11 @@ #include <stdlib.h> #include <limits.h> +#if (defined(Q_WS_QWS) || defined(Q_WS_S60)) && !defined(QT_NO_FREETYPE) +# include <ft2build.h> +# include FT_TRUETYPE_TABLES_H +#endif + // #define QFONTDATABASE_DEBUG #ifdef QFONTDATABASE_DEBUG # define FD_DEBUG qDebug @@ -76,6 +81,8 @@ QT_BEGIN_NAMESPACE +#define SMOOTH_SCALABLE 0xffff + extern int qt_defaultDpiY(); // in qfont.cpp Q_GUI_EXPORT bool qt_enable_test_font = false; @@ -141,10 +148,10 @@ struct QtFontSize QtFontEncoding *encodingID(int id, uint xpoint = 0, uint xres = 0, uint yres = 0, uint avgwidth = 0, bool add = false); #endif // Q_WS_X11 -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) QByteArray fileName; int fileIndex; -#endif +#endif // defined(Q_WS_QWS) || defined(Q_WS_S60) }; @@ -160,10 +167,13 @@ QtFontEncoding *QtFontSize::encodingID(int id, uint xpoint, uint xres, if (!add) return 0; - if (!(count % 4)) - encodings = (QtFontEncoding *) + if (!(count % 4)) { + QtFontEncoding *newEncodings = (QtFontEncoding *) realloc(encodings, (((count+4) >> 2) << 2) * sizeof(QtFontEncoding)); + Q_CHECK_PTR(newEncodings); + encodings = newEncodings; + } encodings[count].encoding = id; encodings[count].xpoint = xpoint; encodings[count].xres = xres; @@ -215,12 +225,12 @@ struct QtFontStyle delete [] weightName; delete [] setwidthName; #endif -#if defined(Q_WS_X11) || defined(Q_WS_QWS) +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60) while (count--) { #ifdef Q_WS_X11 free(pixelSizes[count].encodings); #endif -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) pixelSizes[count].fileName.~QByteArray(); #endif } @@ -238,7 +248,7 @@ struct QtFontStyle const char *weightName; const char *setwidthName; #endif // Q_WS_X11 -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) bool antialiased; #endif @@ -267,16 +277,19 @@ QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add) if (!add) return 0; - if (!(count % 8)) - pixelSizes = (QtFontSize *) + if (!(count % 8)) { + QtFontSize *newPixelSizes = (QtFontSize *) realloc(pixelSizes, (((count+8) >> 3) << 3) * sizeof(QtFontSize)); + Q_CHECK_PTR(newPixelSizes); + pixelSizes = newPixelSizes; + } pixelSizes[count].pixelSize = size; #ifdef Q_WS_X11 pixelSizes[count].count = 0; pixelSizes[count].encodings = 0; #endif -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) new (&pixelSizes[count].fileName) QByteArray; pixelSizes[count].fileIndex = 0; #endif @@ -321,12 +334,16 @@ QtFontStyle *QtFontFoundry::style(const QtFontStyle::Key &key, bool create) return 0; // qDebug("adding key (weight=%d, style=%d, oblique=%d stretch=%d) at %d", key.weight, key.style, key.oblique, key.stretch, pos); - if (!(count % 8)) - styles = (QtFontStyle **) + if (!(count % 8)) { + QtFontStyle **newStyles = (QtFontStyle **) realloc(styles, (((count+8) >> 3) << 3) * sizeof(QtFontStyle *)); + Q_CHECK_PTR(newStyles); + styles = newStyles; + } + QtFontStyle *style = new QtFontStyle(key); memmove(styles + pos + 1, styles + pos, (count-pos)*sizeof(QtFontStyle *)); - styles[pos] = new QtFontStyle(key); + styles[pos] = style; count++; return styles[pos]; } @@ -358,7 +375,7 @@ struct QtFontFamily fixedPitchComputed(false), #endif name(n), count(0), foundries(0) -#if defined(Q_WS_QWS) +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) , bogusWritingSystems(false) #endif { @@ -388,7 +405,7 @@ struct QtFontFamily #endif QString name; -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) QByteArray fontFilename; int fontFileIndex; #endif @@ -398,7 +415,7 @@ struct QtFontFamily int count; QtFontFoundry **foundries; -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) bool bogusWritingSystems; QStringList fallbackFamilies; #endif @@ -431,10 +448,13 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) if (!create) return 0; - if (!(count % 8)) - foundries = (QtFontFoundry **) + if (!(count % 8)) { + QtFontFoundry **newFoundries = (QtFontFoundry **) realloc(foundries, (((count+8) >> 3) << 3) * sizeof(QtFontFoundry *)); + Q_CHECK_PTR(newFoundries); + foundries = newFoundries; + } foundries[count] = new QtFontFoundry(f); return foundries[count++]; @@ -442,7 +462,7 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) // ### copied to tools/makeqpf/qpf2.cpp -#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_WS_MAC) +#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) // see the Unicode subset bitfields in the MSDN docs static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { // Any, @@ -563,6 +583,15 @@ static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBi } #endif +#if defined(Q_WS_S60) && defined(QT_NO_FREETYPE) +// class with virtual destructor, derived in qfontdatabase_s60.cpp +class QFontDatabaseS60Store +{ +public: + virtual ~QFontDatabaseS60Store() {}; +}; +#endif + class QFontDatabasePrivate { public: @@ -571,6 +600,9 @@ public: #if defined(Q_WS_QWS) , stream(0) #endif +#if defined(Q_WS_S60) && defined(QT_NO_FREETYPE) + , s60Store(0) +#endif { } ~QFontDatabasePrivate() { free(); @@ -582,6 +614,12 @@ public: ::free(families); families = 0; count = 0; +#if defined(Q_WS_S60) && defined(QT_NO_FREETYPE) + if (s60Store) { + delete s60Store; + s60Store = 0; + } +#endif // don't clear the memory fonts! } @@ -609,17 +647,22 @@ public: #if defined(Q_WS_QWS) bool loadFromCache(const QString &fontPath); + void addQPF2File(const QByteArray &file); +#endif // Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) void addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, const QByteArray &file, int fileIndex, bool antialiased, const QList<QFontDatabase::WritingSystem> &writingSystems = QList<QFontDatabase::WritingSystem>()); - void addQPF2File(const QByteArray &file); #ifndef QT_NO_FREETYPE QStringList addTTFile(const QByteArray &file, const QByteArray &fontData = QByteArray()); +#endif // QT_NO_FREETYPE #endif - +#if defined(Q_WS_QWS) QDataStream *stream; QStringList fallbackFamilies; +#elif defined(Q_WS_S60) && defined(QT_NO_FREETYPE) + const QFontDatabaseS60Store *s60Store; #endif }; @@ -654,17 +697,133 @@ QtFontFamily *QFontDatabasePrivate::family(const QString &f, bool create) pos++; // qDebug("adding family %s at %d total=%d", f.latin1(), pos, count); - if (!(count % 8)) - families = (QtFontFamily **) + if (!(count % 8)) { + QtFontFamily **newFamilies = (QtFontFamily **) realloc(families, (((count+8) >> 3) << 3) * sizeof(QtFontFamily *)); + Q_CHECK_PTR(newFamilies); + families = newFamilies; + } + QtFontFamily *family = new QtFontFamily(f); memmove(families + pos + 1, families + pos, (count-pos)*sizeof(QtFontFamily *)); - families[pos] = new QtFontFamily(f); + families[pos] = family; count++; return families[pos]; } +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) +void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, + const QByteArray &file, int fileIndex, bool antialiased, + const QList<QFontDatabase::WritingSystem> &writingSystems) +{ +// qDebug() << "Adding font" << familyname << weight << italic << pixelSize << file << fileIndex << antialiased; + QtFontStyle::Key styleKey; + styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal; + styleKey.weight = weight; + styleKey.stretch = 100; + QtFontFamily *f = family(familyname, true); + + if (writingSystems.isEmpty()) { + for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) { + f->writingSystems[ws] = QtFontFamily::Supported; + } + f->bogusWritingSystems = true; + } else { + for (int i = 0; i < writingSystems.count(); ++i) { + f->writingSystems[writingSystems.at(i)] = QtFontFamily::Supported; + } + } + + QtFontFoundry *foundry = f->foundry(QString::fromLatin1(foundryname), true); + QtFontStyle *style = foundry->style(styleKey, true); + style->smoothScalable = (pixelSize == 0); + style->antialiased = antialiased; + QtFontSize *size = style->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true); + size->fileName = file; + size->fileIndex = fileIndex; + +#if defined(Q_WS_QWS) + if (stream) { + *stream << familyname << foundry->name << weight << quint8(italic) << pixelSize + << file << fileIndex << quint8(antialiased); + *stream << quint8(writingSystems.count()); + for (int i = 0; i < writingSystems.count(); ++i) + *stream << quint8(writingSystems.at(i)); + } +#else // ..in case of defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) + f->fontFilename = file; + f->fontFileIndex = fileIndex; +#endif +} +#endif + +#if (defined(Q_WS_QWS) || defined(Q_WS_S60)) && !defined(QT_NO_FREETYPE) +QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteArray &fontData) +{ + QStringList families; + extern FT_Library qt_getFreetype(); + FT_Library library = qt_getFreetype(); + + int index = 0; + int numFaces = 0; + do { + FT_Face face; + FT_Error error; + if (!fontData.isEmpty()) { + error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); + } else { + error = FT_New_Face(library, file, index, &face); + } + if (error != FT_Err_Ok) { + qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; + break; + } + numFaces = face->num_faces; + + int weight = QFont::Normal; + bool italic = face->style_flags & FT_STYLE_FLAG_ITALIC; + + if (face->style_flags & FT_STYLE_FLAG_BOLD) + weight = QFont::Bold; + + QList<QFontDatabase::WritingSystem> writingSystems; + // detect symbol fonts + for (int i = 0; i < face->num_charmaps; ++i) { + FT_CharMap cm = face->charmaps[i]; + if (cm->encoding == ft_encoding_adobe_custom + || cm->encoding == ft_encoding_symbol) { + writingSystems.append(QFontDatabase::Symbol); + break; + } + } + if (writingSystems.isEmpty()) { + TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); + if (os2) { + quint32 unicodeRange[4] = { + os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 + }; + quint32 codePageRange[2] = { + os2->ulCodePageRange1, os2->ulCodePageRange2 + }; + + writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + //for (int i = 0; i < writingSystems.count(); ++i) + // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i)); + } + } + + QString family = QString::fromAscii(face->family_name); + families.append(family); + addFont(family, /*foundry*/ "", weight, italic, + /*pixelsize*/ 0, file, index, /*antialias*/ true, writingSystems); + + FT_Done_Face(face); + ++index; + } while (index < numFaces); + return families; +} +#endif static const int scriptForWritingSystem[] = { QUnicodeTables::Common, // Any @@ -814,7 +973,7 @@ static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDe #endif #endif -#if defined(Q_WS_X11) || defined(Q_WS_WIN) +#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_S60) static void getEngineData(const QFontPrivate *d, const QFontCache::Key &key) { // look for the requested font in the engine data cache @@ -866,8 +1025,6 @@ QMutex *qt_fontdatabase_mutex() return fontDatabaseMutex(); } -#define SMOOTH_SCALABLE 0xffff - QT_BEGIN_INCLUDE_NAMESPACE #if defined(Q_WS_X11) # include "qfontdatabase_x11.cpp" @@ -877,6 +1034,8 @@ QT_BEGIN_INCLUDE_NAMESPACE # include "qfontdatabase_win.cpp" #elif defined(Q_WS_QWS) # include "qfontdatabase_qws.cpp" +#elif defined(Q_WS_S60) +# include "qfontdatabase_s60.cpp" #endif QT_END_INCLUDE_NAMESPACE @@ -2254,7 +2413,16 @@ QString QFontDatabase::writingSystemSample(WritingSystem writingSystem) sample += QChar(0xac2f); break; case Vietnamese: + { + static const char vietnameseUtf8[] = { + char(0xef), char(0xbb), char(0xbf), char(0xe1), char(0xbb), char(0x97), + char(0xe1), char(0xbb), char(0x99), + char(0xe1), char(0xbb), char(0x91), + char(0xe1), char(0xbb), char(0x93), + }; + sample += QString::fromUtf8(vietnameseUtf8, sizeof(vietnameseUtf8)); break; + } case Ogham: sample += QChar(0x1681); sample += QChar(0x1682); diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index eadb6ba..c169e29 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -151,7 +151,7 @@ public: private: static void createDatabase(); static void parseFontName(const QString &name, QString &foundry, QString &family); -#if defined(Q_WS_QWS) +#if defined(Q_WS_QWS) || defined(Q_WS_S60) static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request); #endif static void load(const QFontPrivate *d, int script); @@ -165,6 +165,7 @@ private: friend class QFontDialogPrivate; friend class QFontEngineMultiXLFD; friend class QFontEngineMultiQWS; + friend class QFontEngineMultiS60; QFontDatabasePrivate *d; }; diff --git a/src/gui/text/qfontdatabase_qws.cpp b/src/gui/text/qfontdatabase_qws.cpp index 9a29de2..7f97cf2 100644 --- a/src/gui/text/qfontdatabase_qws.cpp +++ b/src/gui/text/qfontdatabase_qws.cpp @@ -50,7 +50,6 @@ #include <ft2build.h> #include FT_FREETYPE_H -#include FT_TRUETYPE_TABLES_H #endif #include "qfontengine_qpf_p.h" @@ -82,44 +81,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, const quint8 DatabaseVersion = 4; -void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, - const QByteArray &file, int fileIndex, bool antialiased, - const QList<QFontDatabase::WritingSystem> &writingSystems) -{ -// qDebug() << "Adding font" << familyname << weight << italic << pixelSize << file << fileIndex << antialiased; - QtFontStyle::Key styleKey; - styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal; - styleKey.weight = weight; - styleKey.stretch = 100; - QtFontFamily *f = family(familyname, true); - - if (writingSystems.isEmpty()) { - for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) { - f->writingSystems[ws] = QtFontFamily::Supported; - } - f->bogusWritingSystems = true; - } else { - for (int i = 0; i < writingSystems.count(); ++i) { - f->writingSystems[writingSystems.at(i)] = QtFontFamily::Supported; - } - } - - QtFontFoundry *foundry = f->foundry(QString::fromLatin1(foundryname), true); - QtFontStyle *style = foundry->style(styleKey, true); - style->smoothScalable = (pixelSize == 0); - style->antialiased = antialiased; - QtFontSize *size = style->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true); - size->fileName = file; - size->fileIndex = fileIndex; - - if (stream) { - *stream << familyname << foundry->name << weight << quint8(italic) << pixelSize - << file << fileIndex << quint8(antialiased); - *stream << quint8(writingSystems.count()); - for (int i = 0; i < writingSystems.count(); ++i) - *stream << quint8(writingSystems.at(i)); - } -} +// QFontDatabasePrivate::addFont() went into qfontdatabase.cpp #ifndef QT_NO_QWS_QPF2 void QFontDatabasePrivate::addQPF2File(const QByteArray &file) @@ -179,74 +141,9 @@ void QFontDatabasePrivate::addQPF2File(const QByteArray &file) ::close(f); #endif } -#endif - -#ifndef QT_NO_FREETYPE -QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteArray &fontData) -{ - QStringList families; - extern FT_Library qt_getFreetype(); - FT_Library library = qt_getFreetype(); - - int index = 0; - int numFaces = 0; - do { - FT_Face face; - FT_Error error; - if (!fontData.isEmpty()) { - error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); - } else { - error = FT_New_Face(library, file, index, &face); - } - if (error != FT_Err_Ok) { - qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; - break; - } - numFaces = face->num_faces; - - int weight = QFont::Normal; - bool italic = face->style_flags & FT_STYLE_FLAG_ITALIC; - - if (face->style_flags & FT_STYLE_FLAG_BOLD) - weight = QFont::Bold; - - QList<QFontDatabase::WritingSystem> writingSystems; - // detect symbol fonts - for (int i = 0; i < face->num_charmaps; ++i) { - FT_CharMap cm = face->charmaps[i]; - if (cm->encoding == ft_encoding_adobe_custom - || cm->encoding == ft_encoding_symbol) { - writingSystems.append(QFontDatabase::Symbol); - break; - } - } - if (writingSystems.isEmpty()) { - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (os2) { - quint32 unicodeRange[4] = { - os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 - }; - quint32 codePageRange[2] = { - os2->ulCodePageRange1, os2->ulCodePageRange2 - }; - - writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - //for (int i = 0; i < writingSystems.count(); ++i) - // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i)); - } - } +#endif // QT_NO_QWS_QPF2 - QString family = QString::fromAscii(face->family_name); - families.append(family); - addFont(family, /*foundry*/ "", weight, italic, - /*pixelsize*/ 0, file, index, /*antialias*/ true, writingSystems); - - FT_Done_Face(face); - ++index; - } while (index < numFaces); - return families; -} -#endif +// QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt); @@ -670,8 +567,8 @@ QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp, QFontEngineQPF *fe = new QFontEngineQPF(request, res.data(), res.size()); if (fe->isValid()) return fe; - qDebug() << "fontengine is not valid! " << size->fileName; delete fe; + qDebug() << "fontengine is not valid! " << size->fileName; } else { qDebug() << "Resource not valid" << size->fileName; } @@ -681,8 +578,8 @@ QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp, QFontEngineQPF *fe = new QFontEngineQPF(request, f); if (fe->isValid()) return fe; - qDebug() << "fontengine is not valid!"; delete fe; // will close f + qDebug() << "fontengine is not valid!"; } #endif } else @@ -696,70 +593,67 @@ QFontEngine *loadSingleEngine(int script, const QFontPrivate *fp, static bool dontShareFonts = !qgetenv("QWS_NO_SHARE_FONTS").isEmpty(); bool shareFonts = !dontShareFonts; - QFontEngine *engine = 0; + QScopedPointer<QFontEngine> engine; #ifndef QT_NO_LIBRARY QFontEngineFactoryInterface *factory = qobject_cast<QFontEngineFactoryInterface *>(loader()->instance(foundry->name)); - if (factory) { - QFontEngineInfo info; - info.setFamily(request.family); - info.setPixelSize(request.pixelSize); - info.setStyle(QFont::Style(request.style)); - info.setWeight(request.weight); - // #### antialiased - - QAbstractFontEngine *customEngine = factory->create(info); - if (customEngine) { - engine = new QProxyFontEngine(customEngine, def); - - if (shareFonts) { - QVariant hint = customEngine->fontProperty(QAbstractFontEngine::CacheGlyphsHint); - if (hint.isValid()) - shareFonts = hint.toBool(); - else - shareFonts = (pixelSize < 64); - } + if (factory) { + QFontEngineInfo info; + info.setFamily(request.family); + info.setPixelSize(request.pixelSize); + info.setStyle(QFont::Style(request.style)); + info.setWeight(request.weight); + // #### antialiased + + QAbstractFontEngine *customEngine = factory->create(info); + if (customEngine) { + engine.reset(new QProxyFontEngine(customEngine, def)); + + if (shareFonts) { + QVariant hint = customEngine->fontProperty(QAbstractFontEngine::CacheGlyphsHint); + if (hint.isValid()) + shareFonts = hint.toBool(); + else + shareFonts = (pixelSize < 64); } + } } #endif // QT_NO_LIBRARY - if (!engine && !file.isEmpty() && QFile::exists(file) || privateDb()->isApplicationFont(file)) { + if ((engine.isNull() && !file.isEmpty() && QFile::exists(file)) || privateDb()->isApplicationFont(file)) { QFontEngine::FaceId faceId; faceId.filename = file.toLocal8Bit(); faceId.index = size->fileIndex; #ifndef QT_NO_FREETYPE - QFontEngineFT *fte = new QFontEngineFT(def); + QScopedPointer<QFontEngineFT> fte(new QFontEngineFT(def)); if (fte->init(faceId, style->antialiased, style->antialiased ? QFontEngineFT::Format_A8 : QFontEngineFT::Format_Mono)) { #ifdef QT_NO_QWS_QPF2 - return fte; + return fte.take(); #else - engine = fte; // try to distinguish between bdf and ttf fonts we can pre-render // and don't try to share outline fonts shareFonts = shareFonts && !fte->defaultGlyphs()->outline_drawing && !fte->getSfntTable(MAKE_TAG('h', 'e', 'a', 'd')).isEmpty(); + engine.reset(fte.take()); #endif - } else { - delete fte; } #endif // QT_NO_FREETYPE } - if (engine) { + if (!engine.isNull()) { #if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES) if (shareFonts) { - QFontEngineQPF *fe = new QFontEngineQPF(def, -1, engine); - engine = 0; + QScopedPointer<QFontEngineQPF> fe(new QFontEngineQPF(def, -1, engine.data())); + engine.take(); if (fe->isValid()) - return fe; + return fe.take(); qWarning("Initializing QFontEngineQPF failed for %s", qPrintable(file)); - engine = fe->takeRenderingEngine(); - delete fe; + engine.reset(fe->takeRenderingEngine()); } #endif - return engine; + return engine.take(); } } else { @@ -786,20 +680,22 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, QtFontFamily *family, QtFontFoundry *foundry, QtFontStyle *style, QtFontSize *size) { - QFontEngine *fe = loadSingleEngine(script, fp, request, family, foundry, - style, size); - if (fe + QScopedPointer<QFontEngine> engine(loadSingleEngine(script, fp, request, family, foundry, + style, size)); + if (!engine.isNull() && script == QUnicodeTables::Common - && !(request.styleStrategy & QFont::NoFontMerging) && !fe->symbol) { + && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) { QStringList fallbacks = privateDb()->fallbackFamilies; if (family && !family->fallbackFamilies.isEmpty()) fallbacks = family->fallbackFamilies; - fe = new QFontEngineMultiQWS(fe, script, fallbacks); + QFontEngine *fe = new QFontEngineMultiQWS(engine.data(), script, fallbacks); + engine.take(); + engine.reset(fe); } - return fe; + return engine.take(); } static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp new file mode 100644 index 0000000..416c3d1 --- /dev/null +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qapplication_p.h> +#include "qdir.h" +#include "qfont_p.h" +#include "qfontengine_s60_p.h" +#include "qabstractfileengine.h" +#include "qdesktopservices.h" +#include "qt_s60_p.h" +#include "qendian.h" +#include <private/qwindowsurface_s60_p.h> +#include <private/qcore_symbian_p.h> +#if defined(QT_NO_FREETYPE) +#include <OPENFONT.H> +#endif + +QT_BEGIN_NAMESPACE + +QFileInfoList alternativeFilePaths(const QString &path, const QStringList &nameFilters, + QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort, + bool uniqueFileNames = true) +{ + QFileInfoList result; + + // Prepare a 'soft to hard' drive list: W:, X: ... A:, Z: + QStringList driveStrings; + foreach (const QFileInfo &drive, QDir::drives()) + driveStrings.append(drive.absolutePath()); + driveStrings.sort(); + const QString zDriveString("Z:/"); + driveStrings.removeAll(zDriveString); + driveStrings.prepend(zDriveString); + + QStringList uniqueFileNameList; + for (int i = driveStrings.count() - 1; i >= 0; --i) { + const QDir dirOnDrive(driveStrings.at(i) + path); + const QFileInfoList entriesOnDrive = dirOnDrive.entryInfoList(nameFilters, filters, sort); + if (uniqueFileNames) { + foreach(const QFileInfo &entry, entriesOnDrive) { + if (!uniqueFileNameList.contains(entry.fileName())) { + uniqueFileNameList.append(entry.fileName()); + result.append(entry); + } + } + } else { + result.append(entriesOnDrive); + } + } + return result; +} + +#if defined(QT_NO_FREETYPE) +class QFontDatabaseS60StoreImplementation : public QFontDatabaseS60Store +{ +public: + QFontDatabaseS60StoreImplementation(); + ~QFontDatabaseS60StoreImplementation(); + + const QFontEngineS60Extensions *extension(const QString &typeface) const; + +private: + RHeap* m_heap; + CFontStore *m_store; + COpenFontRasterizer *m_rasterizer; + mutable QHash<QString, const QFontEngineS60Extensions *> m_extensions; +}; + +QFontDatabaseS60StoreImplementation::QFontDatabaseS60StoreImplementation() +{ + m_heap = User::ChunkHeap(NULL, 0x1000, 0x100000); + m_store = CFontStore::NewL(m_heap); + m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E)); + m_store->InstallRasterizerL(m_rasterizer); + + QStringList filters; + filters.append(QString::fromLatin1("*.ttf")); + filters.append(QString::fromLatin1("*.ccc")); + const QFileInfoList fontFiles = alternativeFilePaths(QString::fromLatin1("resource\\Fonts"), filters); + foreach (const QFileInfo &fontFileInfo, fontFiles) { + const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath()); + m_store->AddFileL(qt_QString2TPtrC(fontFile)); + } +} +QFontDatabaseS60StoreImplementation::~QFontDatabaseS60StoreImplementation() +{ + qDeleteAll(m_extensions); + delete m_rasterizer; + delete m_store; + m_heap->Close(); +} + +const QFontEngineS60Extensions *QFontDatabaseS60StoreImplementation::extension(const QString &typeface) const +{ + if (!m_extensions.contains(typeface)) { + CFont* font = NULL; + TFontSpec spec(qt_QString2TPtrC(typeface), 1); + spec.iHeight = 1; + const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, spec); + Q_ASSERT(err == KErrNone && font); + CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font); + m_extensions.insert(typeface, new QFontEngineS60Extensions(bitmapFont->OpenFont())); + } + return m_extensions.value(typeface); +} +#else +class QFontEngineFTS60 : public QFontEngineFT +{ +public: + QFontEngineFTS60(const QFontDef &fd); +}; + +QFontEngineFTS60::QFontEngineFTS60(const QFontDef &fd) + : QFontEngineFT(fd) +{ + default_hint_style = HintFull; +} +#endif // defined(QT_NO_FREETYPE) + +/* + QFontEngineS60::pixelsToPoints, QFontEngineS60::pointsToPixels, QFontEngineMultiS60::QFontEngineMultiS60 + and QFontEngineMultiS60::QFontEngineMultiS60 should be in qfontengine_s60.cpp. But since also the + Freetype based font rendering need them, they are here. +*/ +qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation) +{ + return (orientation == Qt::Horizontal? + S60->screenDevice()->HorizontalPixelsToTwips(pixels) + :S60->screenDevice()->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint; +} + +qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation) +{ + const int twips = points * KTwipsPerPoint; + return orientation == Qt::Horizontal? + S60->screenDevice()->HorizontalTwipsToPixels(twips) + :S60->screenDevice()->VerticalTwipsToPixels(twips); +} + +QFontEngineMultiS60::QFontEngineMultiS60(QFontEngine *first, int script, const QStringList &fallbackFamilies) + : QFontEngineMulti(fallbackFamilies.size() + 1) + , m_script(script) + , m_fallbackFamilies(fallbackFamilies) +{ + engines[0] = first; + first->ref.ref(); + fontDef = engines[0]->fontDef; +} + +void QFontEngineMultiS60::loadEngine(int at) +{ + Q_ASSERT(at < engines.size()); + Q_ASSERT(engines.at(at) == 0); + + QFontDef request = fontDef; + request.styleStrategy |= QFont::NoFontMerging; + request.family = m_fallbackFamilies.at(at-1); + engines[at] = QFontDatabase::findFont(m_script, + /*fontprivate*/0, + request); + Q_ASSERT(engines[at]); +} + +static void initializeDb() +{ + QFontDatabasePrivate *db = privateDb(); + if(!db || db->count) + return; + +#if defined(QT_NO_FREETYPE) + if (!db->s60Store) + db->s60Store = new QFontDatabaseS60StoreImplementation; + + QS60WindowSurface::unlockBitmapHeap(); + const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces(); + const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store); + Q_ASSERT(store); + for (int i = 0; i < numTypeFaces; i++) { + TTypefaceSupport typefaceSupport; + QS60Data::screenDevice()->TypefaceSupport(typefaceSupport, i); + CFont *font; // We have to get a font instance in order to know all the details + TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11); + QS60Data::screenDevice()->GetNearestFontInPixels(font, fontSpec); + if (font->TypeUid() == KCFbsFontUid) { + TOpenFontFaceAttrib faceAttrib; + const CFbsFont *cfbsFont = dynamic_cast<const CFbsFont *>(font); + Q_ASSERT(cfbsFont); + cfbsFont->GetFaceAttrib(faceAttrib); + + QtFontStyle::Key styleKey; + styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal; + styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal; + + QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length()); + QtFontFamily *family = db->family(familyName, true); + family->fixedPitch = faceAttrib.IsMonoWidth(); + QtFontFoundry *foundry = family->foundry(QString(), true); + QtFontStyle *style = foundry->style(styleKey, true); + style->smoothScalable = typefaceSupport.iIsScalable; + style->pixelSize(0, true); + + const QFontEngineS60Extensions *extension = store->extension(familyName); + const QByteArray os2Table = extension->getSfntTable(MAKE_TAG('O', 'S', '/', '2')); + const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData()); + const unsigned char* ulUnicodeRange = data + 42; + quint32 unicodeRange[4] = { + qFromBigEndian<quint32>(ulUnicodeRange), + qFromBigEndian<quint32>(ulUnicodeRange + 4), + qFromBigEndian<quint32>(ulUnicodeRange + 8), + qFromBigEndian<quint32>(ulUnicodeRange + 12) + }; + const unsigned char* ulCodePageRange = data + 78; + quint32 codePageRange[2] = { + qFromBigEndian<quint32>(ulCodePageRange), + qFromBigEndian<quint32>(ulCodePageRange + 4) + }; + const QList<QFontDatabase::WritingSystem> writingSystems = + determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + foreach (const QFontDatabase::WritingSystem system, writingSystems) + family->writingSystems[system] = QtFontFamily::Supported; + } + QS60Data::screenDevice()->ReleaseFont(font); + } + QS60WindowSurface::lockBitmapHeap(); +#else // defined(QT_NO_FREETYPE) + QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation)); + dir.setNameFilters(QStringList() << QLatin1String("*.ttf") + << QLatin1String("*.ttc") << QLatin1String("*.pfa") + << QLatin1String("*.pfb")); + for (int i = 0; i < int(dir.count()); ++i) { + const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i])); + db->addTTFile(file); + } +#endif // defined(QT_NO_FREETYPE) +} + +static inline void load(const QString &family = QString(), int script = -1) +{ + Q_UNUSED(family) + Q_UNUSED(script) + initializeDb(); +} + +static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) +{ + Q_UNUSED(fnt); +} + +bool QFontDatabase::supportsThreadedFontRendering() +{ + return false; +} + +static +QFontDef cleanedFontDef(const QFontDef &req) +{ + QFontDef result = req; + if (result.pixelSize <= 0) { + result.pixelSize = QFontEngineS60::pointsToPixels(qMax(qreal(1.0), result.pointSize)); + result.pointSize = 0; + } + return result; +} + +QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req) +{ + const QFontCache::Key key(cleanedFontDef(req), script); + + if (!privateDb()->count) + initializeDb(); + + QFontEngine *fe = QFontCache::instance()->findEngine(key); + if (!fe) { + // Making sure that fe->fontDef.family will be an existing font. + initializeDb(); + QFontDatabasePrivate *db = privateDb(); + QtFontDesc desc; + QList<int> blacklistedFamilies; + match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies); + if (!desc.family) // falling back to application font + desc.family = db->family(QApplication::font().defaultFamily()); + Q_ASSERT(desc.family); + + // Making sure that desc.family supports the requested script + QtFontDesc mappedDesc; + bool supportsScript = false; + do { + match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies); + if (mappedDesc.family == desc.family) { + supportsScript = true; + break; + } + blacklistedFamilies.append(mappedDesc.familyIndex); + } while (mappedDesc.family); + if (!supportsScript) { + blacklistedFamilies.clear(); + match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies); + if (mappedDesc.family) + desc = mappedDesc; + } + + const QString fontFamily = desc.family->name; + QFontDef request = req; + request.family = fontFamily; +#if defined(QT_NO_FREETYPE) + const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store); + Q_ASSERT(store); + const QFontEngineS60Extensions *extension = store->extension(fontFamily); + fe = new QFontEngineS60(request, extension); +#else + QFontEngine::FaceId faceId; + const QtFontFamily * const reqQtFontFamily = db->family(fontFamily); + faceId.filename = reqQtFontFamily->fontFilename; + faceId.index = reqQtFontFamily->fontFileIndex; + + QFontEngineFTS60 *fte = new QFontEngineFTS60(cleanedFontDef(request)); + if (fte->init(faceId, true, QFontEngineFT::Format_A8)) + fe = fte; + else + delete fte; +#endif + + Q_ASSERT(fe); + if (script == QUnicodeTables::Common + && !(req.styleStrategy & QFont::NoFontMerging) + && !fe->symbol) { + + QStringList commonFonts; + for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) { + if (scriptForWritingSystem[ws] != script) + continue; + for (int i = 0; i < db->count; ++i) { + if (db->families[i]->writingSystems[ws] & QtFontFamily::Supported) + commonFonts.append(db->families[i]->name); + } + } + + // Hack: Prioritize .ccc fonts + const QString niceEastAsianFont(QLatin1String("Sans MT 936_S60")); + if (commonFonts.removeAll(niceEastAsianFont) > 0) + commonFonts.prepend(niceEastAsianFont); + + fe = new QFontEngineMultiS60(fe, script, commonFonts); + } + } + fe->ref.ref(); + QFontCache::instance()->insertEngine(key, fe); + return fe; +} + +void QFontDatabase::load(const QFontPrivate *d, int script) +{ + QFontEngine *fe = 0; + QFontDef req = d->request; + + if (!d->engineData) { + const QFontCache::Key key(cleanedFontDef(req), script); + getEngineData(d, key); + } + + // the cached engineData could have already loaded the engine we want + if (d->engineData->engines[script]) + fe = d->engineData->engines[script]; + + if (!fe) { + if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) { + fe = new QTestFontEngine(req.pixelSize); + fe->fontDef = req; + } else { + fe = findFont(script, d, req); + } + d->engineData->engines[script] = fe; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 79e341a..f09e726 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -185,18 +185,20 @@ QFontEngine::QFontEngine() QFontEngine::~QFontEngine() { - for (GlyphPointerHash::iterator it = m_glyphPointerHash.begin(), end = m_glyphPointerHash.end(); - it != end; ++it) { - for (QList<QFontEngineGlyphCache*>::iterator it2 = it.value().begin(), end2 = it.value().end(); - it2 != end2; ++it2) - delete *it2; + for (GlyphPointerHash::const_iterator it = m_glyphPointerHash.constBegin(), + end = m_glyphPointerHash.constEnd(); it != end; ++it) { + for (QList<QFontEngineGlyphCache*>::const_iterator it2 = it.value().constBegin(), + end2 = it.value().constEnd(); it2 != end2; ++it2) { + delete *it2; + } } m_glyphPointerHash.clear(); - for (GlyphIntHash::iterator it = m_glyphIntHash.begin(), end = m_glyphIntHash.end(); - it != end; ++it) { - for (QList<QFontEngineGlyphCache*>::iterator it2 = it.value().begin(), end2 = it.value().end(); - it2 != end2; ++it2) - delete *it2; + for (GlyphIntHash::const_iterator it = m_glyphIntHash.constBegin(), + end = m_glyphIntHash.constEnd(); it != end; ++it) { + for (QList<QFontEngineGlyphCache*>::const_iterator it2 = it.value().constBegin(), + end2 = it.value().constEnd(); it2 != end2; ++it2) { + delete *it2; + } } m_glyphIntHash.clear(); qHBFreeFace(hbFace); @@ -813,7 +815,7 @@ QFontEngineGlyphCache *QFontEngine::glyphCache(QFontEngineGlyphCache::Type key, return 0; } -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60) static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs) { uint left_right = (left << 16) + right; @@ -1104,6 +1106,18 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) return 0; } +Q_GLOBAL_STATIC_WITH_INITIALIZER(QVector<QRgb>, qt_grayPalette, { + x->resize(256); + QRgb *it = x->data(); + for (int i = 0; i < x->size(); ++i, ++it) + *it = 0xff000000 | i | (i<<8) | (i<<16); +}); + +const QVector<QRgb> &QFontEngine::grayPalette() +{ + return *qt_grayPalette(); +} + // ------------------------------------------------------------------ // The box font engine // ------------------------------------------------------------------ diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index a93c391..ef0cdca 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -191,6 +191,9 @@ HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 p /* * One font file can contain more than one font (bold/italic for example) * find the right one and return it. + * + * Returns the freetype face or 0 in case of an empty file or any other problems + * (like not being able to open the file) */ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) { @@ -203,7 +206,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0); if (!freetype) { - freetype = new QFreetypeFace; + QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace); FT_Face face; QFile file(QString::fromUtf8(face_id.filename)); if (face_id.filename.startsWith(":qmemoryfonts/")) { @@ -212,84 +215,82 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) QByteArray idx = face_id.filename; idx.remove(0, 14); // remove ':qmemoryfonts/' bool ok = false; - freetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); + newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); if (!ok) - freetype->fontData = QByteArray(); + newFreetype->fontData = QByteArray(); } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) { if (!file.open(QIODevice::ReadOnly)) { - delete freetype; return 0; } - freetype->fontData = file.readAll(); + newFreetype->fontData = file.readAll(); } - if (!freetype->fontData.isEmpty()) { - if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)freetype->fontData.constData(), freetype->fontData.size(), face_id.index, &face)) { - delete freetype; + if (!newFreetype->fontData.isEmpty()) { + if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) { return 0; } } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) { - delete freetype; return 0; } - freetype->face = face; - - freetype->hbFace = qHBNewFace(face, hb_getSFntTable); - freetype->ref = 0; - freetype->xsize = 0; - freetype->ysize = 0; - freetype->matrix.xx = 0x10000; - freetype->matrix.yy = 0x10000; - freetype->matrix.xy = 0; - freetype->matrix.yx = 0; - freetype->unicode_map = 0; - freetype->symbol_map = 0; + newFreetype->face = face; + + newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable); + newFreetype->ref = 0; + newFreetype->xsize = 0; + newFreetype->ysize = 0; + newFreetype->matrix.xx = 0x10000; + newFreetype->matrix.yy = 0x10000; + newFreetype->matrix.xy = 0; + newFreetype->matrix.yx = 0; + newFreetype->unicode_map = 0; + newFreetype->symbol_map = 0; #ifndef QT_NO_FONTCONFIG - freetype->charset = 0; + newFreetype->charset = 0; #endif - memset(freetype->cmapCache, 0, sizeof(freetype->cmapCache)); + memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache)); - for (int i = 0; i < freetype->face->num_charmaps; ++i) { - FT_CharMap cm = freetype->face->charmaps[i]; + for (int i = 0; i < newFreetype->face->num_charmaps; ++i) { + FT_CharMap cm = newFreetype->face->charmaps[i]; switch(cm->encoding) { case FT_ENCODING_UNICODE: - freetype->unicode_map = cm; + newFreetype->unicode_map = cm; break; case FT_ENCODING_APPLE_ROMAN: case FT_ENCODING_ADOBE_LATIN_1: - if (!freetype->unicode_map || freetype->unicode_map->encoding != FT_ENCODING_UNICODE) - freetype->unicode_map = cm; + if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE) + newFreetype->unicode_map = cm; break; case FT_ENCODING_ADOBE_CUSTOM: case FT_ENCODING_MS_SYMBOL: - if (!freetype->symbol_map) - freetype->symbol_map = cm; + if (!newFreetype->symbol_map) + newFreetype->symbol_map = cm; break; default: break; } } - if (!FT_IS_SCALABLE(freetype->face) && freetype->face->num_fixed_sizes == 1) - FT_Set_Char_Size (face, X_SIZE(freetype->face, 0), Y_SIZE(freetype->face, 0), 0, 0); + if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1) + FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0); # if 0 FcChar8 *name; FcPatternGetString(pattern, FC_FAMILY, 0, &name); qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name, - freetype->face->charmap ? freetype->face->charmap->encoding : 0, - freetype->unicode_map ? freetype->unicode_map->encoding : 0, - freetype->symbol_map ? freetype->symbol_map->encoding : 0); + newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0, + newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0, + newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0); for (int i = 0; i < 256; i += 8) qDebug(" %x: %d %d %d %d %d %d %d %d", i, - FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), - FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), - FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i), - FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i)); + FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i), + FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i), + FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i), + FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i)); #endif - FT_Set_Charmap(freetype->face, freetype->unicode_map); - freetypeData->faces.insert(face_id, freetype); + FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map); + freetypeData->faces.insert(face_id, newFreetype.data()); + freetype = newFreetype.take(); } freetype->ref.ref(); return freetype; @@ -606,6 +607,7 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd) kerning_pairs_loaded = false; transform = false; antialias = true; + freetype = 0; default_load_flags = 0; default_hint_style = HintNone; subpixelType = Subpixel_None; diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 284904b..b67895b 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -119,6 +119,7 @@ struct QFreetypeFace static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false); private: + friend class QScopedPointer<QFreetypeFace>; QFreetypeFace() : _lock(QMutex::Recursive) {} ~QFreetypeFace() {} QAtomicInt ref; @@ -255,7 +256,7 @@ public: QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix); bool loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format = Format_Render); -#if defined(Q_WS_QWS) +#if defined(Q_WS_QWS) || defined(Q_WS_S60) virtual void draw(QPaintEngine * /*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt & /*si*/) {} #endif diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 3ef9d5f..fc5ff20 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -112,6 +112,10 @@ public: QPF1, QPF2, Proxy, + + // S60 types + S60FontEngine, // Cannot be simply called "S60". Reason is qt_s60Data.h + TestFontEngine = 0x1000 }; @@ -163,7 +167,7 @@ public: virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const {} virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const; -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) virtual void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si) = 0; #endif virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, @@ -230,7 +234,7 @@ public: bool symbol; mutable HB_FontRec hbFont; mutable HB_Face hbFace; -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60) struct KernPair { uint left_right; QFixed adjust; @@ -246,6 +250,9 @@ public: int glyphFormat; +protected: + static const QVector<QRgb> &grayPalette(); + private: /// remove old entries from the glyph cache. Helper method for the setGlyphCache ones. void expireGlyphCache(); @@ -321,7 +328,7 @@ public: virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si); #endif virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags); @@ -618,4 +625,8 @@ QT_END_NAMESPACE # include "private/qfontengine_win_p.h" #endif +#if defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) +# include "private/qfontengine_ft_p.h" +#endif + #endif // QFONTENGINE_P_H diff --git a/src/gui/text/qfontengine_qpf.cpp b/src/gui/text/qfontengine_qpf.cpp index 8222b7f..97d3847 100644 --- a/src/gui/text/qfontengine_qpf.cpp +++ b/src/gui/text/qfontengine_qpf.cpp @@ -325,21 +325,21 @@ QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEng fileName.replace(QLatin1Char(' '), QLatin1Char('_')); fileName.prepend(qws_fontCacheDir()); - const QByteArray encodedName = QFile::encodeName(fileName); - if (::access(encodedName, F_OK) == 0) { + encodedFileName = QFile::encodeName(fileName); + if (::access(encodedFileName, F_OK) == 0) { #if defined(DEBUG_FONTENGINE) qDebug() << "found existing qpf:" << fileName; #endif - if (::access(encodedName, W_OK | R_OK) == 0) - fd = ::open(encodedName, O_RDWR, 0); - else if (::access(encodedName, R_OK) == 0) - fd = ::open(encodedName, O_RDONLY, 0); + if (::access(encodedFileName, W_OK | R_OK) == 0) + fd = ::open(encodedFileName, O_RDWR, 0); + else if (::access(encodedFileName, R_OK) == 0) + fd = ::open(encodedFileName, O_RDONLY, 0); } else { #if defined(DEBUG_FONTENGINE) qDebug() << "creating qpf on the fly:" << fileName; #endif if (::access(QFile::encodeName(qws_fontCacheDir()), W_OK) == 0) { - fd = ::open(encodedName, O_RDWR | O_EXCL | O_CREAT, 0644); + fd = ::open(encodedFileName, O_RDWR | O_EXCL | O_CREAT, 0644); QBuffer buffer; buffer.open(QIODevice::ReadWrite); @@ -474,15 +474,21 @@ QFontEngineQPF::QFontEngineQPF(const QFontDef &def, int fileDescriptor, QFontEng #endif #if defined(Q_WS_QWS) if (isValid() && renderingFontEngine) - qt_fbdpy->sendFontCommand(QWSFontCommand::StartedUsingFont, QFile::encodeName(fileName)); + qt_fbdpy->sendFontCommand(QWSFontCommand::StartedUsingFont, encodedFileName); #endif } QFontEngineQPF::~QFontEngineQPF() { #if defined(Q_WS_QWS) - if (isValid() && renderingFontEngine) - qt_fbdpy->sendFontCommand(QWSFontCommand::StoppedUsingFont, QFile::encodeName(fileName)); + if (isValid() && renderingFontEngine) { + QT_TRY { + qt_fbdpy->sendFontCommand(QWSFontCommand::StoppedUsingFont, encodedFileName); + } QT_CATCH(...) { + qDebug("QFontEngineQPF::~QFontEngineQPF: Out of memory"); + // ignore. + } + } #endif delete renderingFontEngine; if (fontData) @@ -1128,6 +1134,11 @@ void QPFGenerator::writeTaggedQFixed(QFontEngineQPF::HeaderTag tag, QFixed value #endif // QT_NO_QWS_QPF2 +/* + Creates a new multi qws engine. + + This function takes ownership of the QFontEngine, increasing it's refcount. +*/ QFontEngineMultiQWS::QFontEngineMultiQWS(QFontEngine *fe, int _script, const QStringList &fallbacks) : QFontEngineMulti(fallbacks.size() + 1), fallbackFamilies(fallbacks), script(_script) diff --git a/src/gui/text/qfontengine_qpf_p.h b/src/gui/text/qfontengine_qpf_p.h index a9b87ff..629f5c6 100644 --- a/src/gui/text/qfontengine_qpf_p.h +++ b/src/gui/text/qfontengine_qpf_p.h @@ -243,6 +243,7 @@ private: quint32 glyphDataOffset; quint32 glyphDataSize; QString fileName; + QByteArray encodedFileName; bool readOnly; QFreetypeFace *freetype; diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp new file mode 100644 index 0000000..2e1abb2 --- /dev/null +++ b/src/gui/text/qfontengine_s60.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfontengine_s60_p.h" +#include "qtextengine_p.h" +#include "qglobal.h" +#include <private/qapplication_p.h> +#include <private/qwindowsurface_s60_p.h> +#include "qimage.h" +#include "qt_s60_p.h" + +#include <e32base.h> +#include <e32std.h> +#include <EIKENV.H> +#include <GDI.H> + +QT_BEGIN_NAMESPACE + +static const int maxFontSizeInPixels = 60; + +QFontEngineS60Extensions::QFontEngineS60Extensions(COpenFont *font) + : m_font(font) + , m_cmap(0) + , m_symbolCMap(false) +{ + TAny *shapingExtension = NULL; + m_font->ExtendedInterface(KUidOpenFontShapingExtension, shapingExtension); + m_shapingExtension = static_cast<MOpenFontShapingExtension*>(shapingExtension); + TAny *trueTypeExtension = NULL; + m_font->ExtendedInterface(KUidOpenFontTrueTypeExtension, trueTypeExtension); + m_trueTypeExtension = static_cast<MOpenFontTrueTypeExtension*>(trueTypeExtension); + Q_ASSERT(m_shapingExtension && m_trueTypeExtension); +} + +QByteArray QFontEngineS60Extensions::getSfntTable(uint tag) const +{ + Q_ASSERT(m_trueTypeExtension->HasTrueTypeTable(tag)); + TInt error = KErrNone; + TInt tableByteLength = 0; + TAny *table = m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength); + QByteArray result(static_cast<const char*>(table), tableByteLength); + m_trueTypeExtension->ReleaseTrueTypeTable(table); + return result; +} + +const unsigned char *QFontEngineS60Extensions::cmap() const +{ + if (!m_cmap) { + m_cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); + int size = 0; + m_cmap = QFontEngineS60::getCMap(reinterpret_cast<const uchar *>(m_cmapTable.constData()), m_cmapTable.size(), &m_symbolCMap, &size); + } + return m_cmap; +} + +QPainterPath QFontEngineS60Extensions::glyphOutline(glyph_t glyph) const +{ + QPainterPath result; + QPolygonF polygon; + TInt glyphIndex = glyph; + TInt pointNumber = 0; + TInt x, y; + while (m_shapingExtension->GlyphPointInFontUnits(glyphIndex, pointNumber++, x, y)) { + const QPointF point(qreal(x) / 0xffff, qreal(y) / 0xffff); + if (polygon.contains(point)) { + result.addPolygon(polygon); + result.closeSubpath(); + polygon.clear(); + } else { + polygon.append(point); + } + } + return result; +} + +// duplicated from qfontengine_xyz.cpp +static inline unsigned int getChar(const QChar *str, int &i, const int len) +{ + unsigned int uc = str[i].unicode(); + if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) { + uint low = str[i+1].unicode(); + if (low >= 0xdc00 && low < 0xe000) { + uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; + ++i; + } + } + return uc; +} + +QFontEngineS60::QFontEngineS60(const QFontDef &request, const QFontEngineS60Extensions *extensions) + : m_extensions(extensions) +{ + QFontEngine::fontDef = request; + m_fontSizeInPixels = (request.pixelSize >= 0)? + request.pixelSize:pointsToPixels(request.pointSize); + QS60WindowSurface::unlockBitmapHeap(); + m_textRenderBitmap = new (ELeave) CFbsBitmap(); + const TSize bitmapSize(1, 1); // It is just a dummy bitmap that I need to keep the font alive (or maybe not) + User::LeaveIfError(m_textRenderBitmap->Create(bitmapSize, EGray256)); + m_textRenderBitmapDevice = CFbsBitmapDevice::NewL(m_textRenderBitmap); + User::LeaveIfError(m_textRenderBitmapDevice->CreateContext(m_textRenderBitmapGc)); + cache_cost = sizeof(QFontEngineS60) + bitmapSize.iHeight * bitmapSize.iWidth * 4; + + TFontSpec fontSpec(qt_QString2TPtrC(request.family), m_fontSizeInPixels); + fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap); + fontSpec.iFontStyle.SetPosture(request.style == QFont::StyleNormal?EPostureUpright:EPostureItalic); + fontSpec.iFontStyle.SetStrokeWeight(request.weight > QFont::Normal?EStrokeWeightBold:EStrokeWeightNormal); + const TInt errorCode = m_textRenderBitmapDevice->GetNearestFontInPixels(m_font, fontSpec); + Q_ASSERT(errorCode == 0); + m_textRenderBitmapGc->UseFont(m_font); + QS60WindowSurface::lockBitmapHeap(); +} + +QFontEngineS60::~QFontEngineS60() +{ + QS60WindowSurface::unlockBitmapHeap(); + m_textRenderBitmapGc->DiscardFont(); + delete m_textRenderBitmapGc; + m_textRenderBitmapGc = NULL; + m_textRenderBitmapDevice->ReleaseFont(m_font); + delete m_textRenderBitmapDevice; + m_textRenderBitmapDevice = NULL; + delete m_textRenderBitmap; + m_textRenderBitmap = NULL; + QS60WindowSurface::lockBitmapHeap(); +} + +bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + if (*nglyphs < len) { + *nglyphs = len; + return false; + } + + HB_Glyph *g = glyphs->glyphs; + const unsigned char* cmap = m_extensions->cmap(); + for (int i = 0; i < len; ++i) { + const unsigned int uc = getChar(characters, i, len); + *g++ = QFontEngine::getTrueTypeGlyphIndex(cmap, uc); + } + + glyphs->numGlyphs = g - glyphs->glyphs; + *nglyphs = glyphs->numGlyphs; + + if (flags & QTextEngine::GlyphIndicesOnly) + return true; + + recalcAdvances(glyphs, flags); + return true; +} + +void QFontEngineS60::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const +{ + Q_UNUSED(flags); + for (int i = 0; i < glyphs->numGlyphs; i++) { + const glyph_metrics_t bbox = boundingBox_const(glyphs->glyphs[i]); + glyphs->advances_x[i] = glyphs->offsets[i].x = bbox.xoff; + glyphs->advances_y[i] = glyphs->offsets[i].y = bbox.yoff; + } +} + +QImage QFontEngineS60::alphaMapForGlyph(glyph_t glyph) +{ + TOpenFontCharMetrics metrics; + const TUint8 *glyphBitmapBytes; + TSize glyphBitmapSize; + getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize); + QImage result(glyphBitmapBytes, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight, glyphBitmapSize.iWidth, QImage::Format_Indexed8); + result.setColorTable(grayPalette()); + + // The above setColorTable() call detached the image data anyway, so why not shape tha data a bit, while we can. + // CFont::GetCharacterData() returns 8-bit data that obviously was 4-bit data before, and converted to 8-bit incorrectly. + // The data values are 0x00, 0x10 ... 0xe0, 0xf0. So, a real opaque 0xff is never reached, which we get punished + // for every time we want to blit this glyph in the raster paint engine. + // "Fix" is to convert all 0xf0 to 0xff. Is fine, quality wise, and I assume faster than correcting all values. + // Blitting is however, evidentially faster now. + const int bpl = result.bytesPerLine(); + for (int row = 0; row < result.height(); ++row) { + uchar *scanLine = result.scanLine(row); + for (int column = 0; column < bpl; ++column) { + if (*scanLine == 0xf0) + *scanLine = 0xff; + scanLine++; + } + } + + return result; +} + +glyph_metrics_t QFontEngineS60::boundingBox(const QGlyphLayout &glyphs) +{ + if (glyphs.numGlyphs == 0) + return glyph_metrics_t(); + + QFixed w = 0; + for (int i = 0; i < glyphs.numGlyphs; ++i) + w += glyphs.effectiveAdvance(i); + + return glyph_metrics_t(0, -ascent(), w, ascent()+descent()+1, w, 0); +} + +glyph_metrics_t QFontEngineS60::boundingBox_const(glyph_t glyph) const +{ + TOpenFontCharMetrics metrics; + const TUint8 *glyphBitmapBytes; + TSize glyphBitmapSize; + getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize); + TRect glyphBounds; + metrics.GetHorizBounds(glyphBounds); + const glyph_metrics_t result( + glyphBounds.iTl.iX, + glyphBounds.iTl.iY, + glyphBounds.Width(), + glyphBounds.Height(), + metrics.HorizAdvance(), + 0 + ); + return result; +} + +glyph_metrics_t QFontEngineS60::boundingBox(glyph_t glyph) +{ + return boundingBox_const(glyph); +} + +QFixed QFontEngineS60::ascent() const +{ + return m_font->FontMaxAscent(); +} + +QFixed QFontEngineS60::descent() const +{ + return m_font->FontMaxDescent(); +} + +QFixed QFontEngineS60::leading() const +{ + return 0; +} + +qreal QFontEngineS60::maxCharWidth() const +{ + return m_font->MaxCharWidthInPixels(); +} + +const char *QFontEngineS60::name() const +{ + return "QFontEngineS60"; +} + +bool QFontEngineS60::canRender(const QChar *string, int len) +{ + const unsigned char *cmap = m_extensions->cmap(); + for (int i = 0; i < len; ++i) { + const unsigned int uc = getChar(string, i, len); + if (QFontEngine::getTrueTypeGlyphIndex(cmap, uc) == 0) + return false; + } + return true; +} + +QByteArray QFontEngineS60::getSfntTable(uint tag) const +{ + return m_extensions->getSfntTable(tag); +} + +QFontEngine::Type QFontEngineS60::type() const +{ + return QFontEngine::S60FontEngine; +} + +void QFontEngineS60::getCharacterData(glyph_t glyph, TOpenFontCharMetrics& metrics, const TUint8*& bitmap, TSize& bitmapSize) const +{ + // Setting the most significant bit tells GetCharacterData + // that 'code' is a Glyph ID, rather than a UTF-16 value + const TUint specialCode = (TUint)glyph | 0x80000000; + + const CFont::TCharacterDataAvailability availability = + m_font->GetCharacterData(specialCode, metrics, bitmap, bitmapSize); + const glyph_t fallbackGlyph = '?'; + if (availability != CFont::EAllCharacterData) { + const CFont::TCharacterDataAvailability fallbackAvailability = + m_font->GetCharacterData(fallbackGlyph, metrics, bitmap, bitmapSize); + Q_ASSERT(fallbackAvailability == CFont::EAllCharacterData); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine_s60_p.h b/src/gui/text/qfontengine_s60_p.h new file mode 100644 index 0000000..2998de8 --- /dev/null +++ b/src/gui/text/qfontengine_s60_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONTENGINE_S60_P_H +#define QFONTENGINE_S60_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 "qconfig.h" +#include "qfontengine_p.h" +#include "qsize.h" +#include <OPENFONT.H> + +class CFbsBitmap; +class CFbsBitmapDevice; +class CFbsBitGc; +class CFont; + +QT_BEGIN_NAMESPACE + +// ..gives us access to truetype tables, UTF-16<->GlyphID mapping, and glyph outlines +class QFontEngineS60Extensions +{ +public: + QFontEngineS60Extensions(COpenFont *font); + + QByteArray getSfntTable(uint tag) const; + const unsigned char *cmap() const; + QPainterPath glyphOutline(glyph_t glyph) const; + +private: + COpenFont *m_font; + const MOpenFontShapingExtension *m_shapingExtension; + mutable MOpenFontTrueTypeExtension *m_trueTypeExtension; + mutable const unsigned char *m_cmap; + mutable bool m_symbolCMap; + mutable QByteArray m_cmapTable; +}; + +class QFontEngineS60 : public QFontEngine +{ +public: + QFontEngineS60(const QFontDef &fontDef, const QFontEngineS60Extensions *extensions); + ~QFontEngineS60(); + + bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; + void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const; + + QImage alphaMapForGlyph(glyph_t glyph); + + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); + glyph_metrics_t boundingBox_const(glyph_t glyph) const; // Const correctnes quirk. + glyph_metrics_t boundingBox(glyph_t glyph); + + QFixed ascent() const; + QFixed descent() const; + QFixed leading() const; + qreal maxCharWidth() const; + qreal minLeftBearing() const { return 0; } + qreal minRightBearing() const { return 0; } + + QByteArray getSfntTable(uint tag) const; + + static qreal pixelsToPoints(qreal pixels, Qt::Orientation orientation = Qt::Horizontal); + static qreal pointsToPixels(qreal points, Qt::Orientation orientation = Qt::Horizontal); + + const char *name() const; + + bool canRender(const QChar *string, int len); + + Type type() const; + +private: + friend class QFontPrivate; + + QFixed glyphAdvance(HB_Glyph glyph) const; + void getCharacterData(glyph_t glyph, TOpenFontCharMetrics& metrics, const TUint8*& bitmap, TSize& bitmapSize) const; + + CFbsBitmap *m_textRenderBitmap; + CFbsBitmapDevice *m_textRenderBitmapDevice; + CFbsBitGc *m_textRenderBitmapGc; + CFont* m_font; + const QFontEngineS60Extensions *m_extensions; + qreal m_fontSizeInPixels; +}; + +class QFontEngineMultiS60 : public QFontEngineMulti +{ +public: + QFontEngineMultiS60(QFontEngine *first, int script, const QStringList &fallbackFamilies); + void loadEngine(int at); + + int m_script; + QStringList m_fallbackFamilies; +}; + +QT_END_NAMESPACE + +#endif // QFONTENGINE_S60_P_H diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 87da628..991fed7 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -164,7 +164,7 @@ extern int qt_defaultDpi(); metrics that are compatible with a certain paint device. */ QFontMetrics::QFontMetrics(const QFont &font) - : d(font.d) + : d(font.d.data()) { d->ref.ref(); } @@ -196,7 +196,7 @@ QFontMetrics::QFontMetrics(const QFont &font, QPaintDevice *paintdevice) d->dpi = dpi; d->screen = screen; } else { - d = font.d; + d = font.d.data(); d->ref.ref(); } @@ -1006,7 +1006,7 @@ QFontMetricsF &QFontMetricsF::operator=(const QFontMetrics &other) metrics that are compatible with a certain paint device. */ QFontMetricsF::QFontMetricsF(const QFont &font) - : d(font.d) + : d(font.d.data()) { d->ref.ref(); } @@ -1038,7 +1038,7 @@ QFontMetricsF::QFontMetricsF(const QFont &font, QPaintDevice *paintdevice) d->dpi = dpi; d->screen = screen; } else { - d = font.d; + d = font.d.data(); d->ref.ref(); } diff --git a/src/gui/text/qfragmentmap_p.h b/src/gui/text/qfragmentmap_p.h index 737a717..0f0e0ff 100644 --- a/src/gui/text/qfragmentmap_p.h +++ b/src/gui/text/qfragmentmap_p.h @@ -214,6 +214,7 @@ private: template <class Fragment> QFragmentMapData<Fragment>::QFragmentMapData() + : fragments(0) { init(); } @@ -222,6 +223,7 @@ template <class Fragment> void QFragmentMapData<Fragment>::init() { fragments = (Fragment *)malloc(64*fragmentSize); + Q_CHECK_PTR(fragments); head->tag = (((quint32)'p') << 24) | (((quint32)'m') << 16) | (((quint32)'a') << 8) | 'p'; //TAG('p', 'm', 'a', 'p'); head->root = 0; head->freelist = 1; @@ -247,7 +249,9 @@ uint QFragmentMapData<Fragment>::createFragment() // need to create some free space uint needed = qAllocMore((freePos+1)*fragmentSize, 0); Q_ASSERT(needed/fragmentSize > head->allocated); - fragments = (Fragment *)realloc(fragments, needed); + Fragment *newFragments = (Fragment *)realloc(fragments, needed); + Q_CHECK_PTR(newFragments); + fragments = newFragments; head->allocated = needed/fragmentSize; F(freePos).right = 0; } @@ -787,6 +791,8 @@ public: QFragmentMap() {} ~QFragmentMap() { + if (!data.fragments) + return; // in case of out-of-memory, we won't have fragments for (Iterator it = begin(); !it.atEnd(); ++it) it.value()->free(); } diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 8573fc9..a3b6085 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1611,6 +1611,9 @@ void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF if (cursor.position() != oldCursorPos) emit q->cursorPositionChanged(); _q_updateCurrentCharFormatAndSelection(); + if (QInputContext *ic = inputContext()) { + ic->update(); + } } else { //emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1))); if (cursor.position() != oldCursorPos) @@ -1813,13 +1816,18 @@ bool QTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPointF &po void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) { + Q_Q(QTextControl); if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) { e->ignore(); return; } - cursor.beginEditBlock(); + bool isGettingInput = !e->commitString().isEmpty() || !e->preeditString().isEmpty() + || e->replacementLength() > 0; - cursor.removeSelectedText(); + if (isGettingInput) { + cursor.beginEditBlock(); + cursor.removeSelectedText(); + } // insert commit string if (!e->commitString().isEmpty() || e->replacementLength()) { @@ -1829,6 +1837,18 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) c.insertText(e->commitString()); } + for (int i = 0; i < e->attributes().size(); ++i) { + const QInputMethodEvent::Attribute &a = e->attributes().at(i); + if (a.type == QInputMethodEvent::Selection) { + QTextCursor oldCursor = cursor; + int blockStart = a.start + cursor.block().position(); + cursor.setPosition(blockStart, QTextCursor::MoveAnchor); + cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor); + q->ensureCursorVisible(); + repaintOldAndNewSelection(oldCursor); + } + } + QTextBlock block = cursor.block(); QTextLayout *layout = block.layout(); layout->setPreeditArea(cursor.position() - block.position(), e->preeditString()); @@ -1852,7 +1872,9 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } } layout->setAdditionalFormats(overrides); - cursor.endEditBlock(); + + if (isGettingInput) + cursor.endEditBlock(); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const @@ -1865,11 +1887,15 @@ QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const case Qt::ImFont: return QVariant(d->cursor.charFormat().font()); case Qt::ImCursorPosition: - return QVariant(d->cursor.selectionEnd() - block.position()); + return QVariant(d->cursor.position() - block.position()); case Qt::ImSurroundingText: return QVariant(block.text()); case Qt::ImCurrentSelection: return QVariant(d->cursor.selectedText()); + case Qt::ImMaximumTextLength: + return QVariant(); // No limit. + case Qt::ImAnchorPosition: + return QVariant(qBound(0, d->cursor.anchor() - block.position(), block.length())); default: return QVariant(); } diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index a28c655..3b102c3 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -2069,10 +2069,12 @@ void QTextEngine::LayoutData::reallocate(int totalGlyphs) int newAllocated = space_charAttributes + space_glyphs + space_logClusters; Q_ASSERT(newAllocated >= allocated); - void **old_mem = memory; - memory = (void **)::realloc(memory_on_stack ? 0 : old_mem, newAllocated*sizeof(void *)); - if (memory_on_stack && memory) - memcpy(memory, old_mem, allocated*sizeof(void *)); + void **newMem = memory; + newMem = (void **)::realloc(memory_on_stack ? 0 : memory, newAllocated*sizeof(void *)); + Q_CHECK_PTR(newMem); + if (memory_on_stack && newMem) + memcpy(newMem, memory, allocated*sizeof(void *)); + memory = newMem; memory_on_stack = false; void **m = memory; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index fa624ef..6c67a68 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -367,7 +367,7 @@ QTextLayout::QTextLayout(const QString& text, const QFont &font, QPaintDevice *p QFont f(font); if (paintdevice) f = QFont(font, paintdevice); - d = new QTextEngine((text.isNull() ? (const QString&)QString::fromLatin1("") : text), f.d); + d = new QTextEngine((text.isNull() ? (const QString&)QString::fromLatin1("") : text), f.d.data()); } /*! diff --git a/src/gui/text/qtextoption.cpp b/src/gui/text/qtextoption.cpp index e1b9844..0f24d9b 100644 --- a/src/gui/text/qtextoption.cpp +++ b/src/gui/text/qtextoption.cpp @@ -117,7 +117,13 @@ QTextOption &QTextOption::operator=(const QTextOption &o) { if (this == &o) return *this; - delete d; d = 0; + + QTextOptionPrivate* dNew = 0; + if (o.d) + dNew = new QTextOptionPrivate(*o.d); + delete d; + d = dNew; + align = o.align; wordWrap = o.wordWrap; design = o.design; @@ -125,8 +131,6 @@ QTextOption &QTextOption::operator=(const QTextOption &o) unused = o.unused; f = o.f; tab = o.tab; - if (o.d) - d = new QTextOptionPrivate(*o.d); return *this; } diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index 48708c9..edba2c4 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -432,6 +432,13 @@ void QTextTablePrivate::fragmentRemoved(const QChar &type, uint fragment) QTextFramePrivate::fragmentRemoved(type, fragment); } +/*! + /fn void QTextTablePrivate::update() const + + This function is usually called when the table is "dirty". + It seems to update all kind of table information. + +*/ void QTextTablePrivate::update() const { Q_Q(const QTextTable); @@ -439,7 +446,9 @@ void QTextTablePrivate::update() const nRows = (cells.size() + nCols-1)/nCols; // qDebug(">>>> QTextTablePrivate::update, nRows=%d, nCols=%d", nRows, nCols); - grid = (int *)realloc(grid, nRows*nCols*sizeof(int)); + int* newGrid = (int *)realloc(grid, nRows*nCols*sizeof(int)); + Q_CHECK_PTR(newGrid); + grid = newGrid; memset(grid, 0, nRows*nCols*sizeof(int)); QTextDocumentPrivate *p = pieceTable; @@ -463,7 +472,9 @@ void QTextTablePrivate::update() const cellIndices[i] = cell; if (r + rowspan > nRows) { - grid = (int *)realloc(grid, sizeof(int)*(r + rowspan)*nCols); + newGrid = (int *)realloc(grid, sizeof(int)*(r + rowspan)*nCols); + Q_CHECK_PTR(newGrid); + grid = newGrid; memset(grid + (nRows*nCols), 0, sizeof(int)*(r+rowspan-nRows)*nCols); nRows = r + rowspan; } diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp index c6c2e69..04f081e 100644 --- a/src/gui/text/qzip.cpp +++ b/src/gui/text/qzip.cpp @@ -695,7 +695,7 @@ void QZipWriterPrivate::addEntry(EntryType type, const QString &fileName, const */ QZipReader::QZipReader(const QString &archive, QIODevice::OpenMode mode) { - QFile *f = new QFile(archive); + QScopedPointer<QFile> f(new QFile(archive)); f->open(mode); QZipReader::Status status; if (f->error() == QFile::NoError) @@ -711,7 +711,8 @@ QZipReader::QZipReader(const QString &archive, QIODevice::OpenMode mode) status = FileError; } - d = new QZipReaderPrivate(f, /*ownDevice=*/true); + d = new QZipReaderPrivate(f.data(), /*ownDevice=*/true); + f.take(); d->status = status; } @@ -969,7 +970,7 @@ void QZipReader::close() */ QZipWriter::QZipWriter(const QString &fileName, QIODevice::OpenMode mode) { - QFile *f = new QFile(fileName); + QScopedPointer<QFile> f(new QFile(fileName)); f->open(mode); QZipWriter::Status status; if (f->error() == QFile::NoError) @@ -985,7 +986,8 @@ QZipWriter::QZipWriter(const QString &fileName, QIODevice::OpenMode mode) status = QZipWriter::FileError; } - d = new QZipWriterPrivate(f, /*ownDevice=*/true); + d = new QZipWriterPrivate(f.data(), /*ownDevice=*/true); + f.take(); d->status = status; } diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index fc33d43..e4d24ff 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -106,9 +106,27 @@ embedded { DEFINES += QT_NO_FONTCONFIG } +symbian { + SOURCES += \ + text/qfont_s60.cpp + contains(QT_CONFIG, freetype) { + SOURCES += \ + text/qfontengine_ft.cpp + HEADERS += \ + text/qfontengine_ft_p.h + DEFINES += \ + QT_NO_FONTCONFIG + } else { + SOURCES += \ + text/qfontengine_s60.cpp + HEADERS += \ + text/qfontengine_s60_p.h + LIBS += -lfntstr -lecom + } +} + contains(QT_CONFIG, freetype) { SOURCES += \ - ../3rdparty/freetype/builds/unix/ftsystem.c \ ../3rdparty/freetype/src/base/ftbase.c \ ../3rdparty/freetype/src/base/ftbbox.c \ ../3rdparty/freetype/src/base/ftdebug.c \ @@ -152,10 +170,19 @@ contains(QT_CONFIG, freetype) { ../3rdparty/freetype/src/autofit/afloader.c\ ../3rdparty/freetype/src/autofit/autofit.c + symbian { + SOURCES += \ + ../3rdparty/freetype/src/base/ftsystem.c + } else { + SOURCES += \ + ../3rdparty/freetype/builds/unix/ftsystem.c + INCLUDEPATH += \ + ../3rdparty/freetype/builds/unix + } + INCLUDEPATH += \ ../3rdparty/freetype/src \ - ../3rdparty/freetype/include \ - ../3rdparty/freetype/builds/unix + ../3rdparty/freetype/include DEFINES += FT2_BUILD_LIBRARY FT_CONFIG_OPTION_SYSTEM_ZLIB diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index bed10dc..aba0245 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -482,7 +482,7 @@ QMatchData QCompletionEngine::filterHistory() for (int i = 0; i < source->rowCount(); i++) { QString str = source->index(i, c->column).data().toString(); if (str.startsWith(c->prefix, c->cs) -#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) && (!dirModel || QDir::toNativeSeparators(str) != QDir::separator()) #endif ) @@ -987,7 +987,7 @@ void QCompleter::setModel(QAbstractItemModel *model) delete oldModel; #ifndef QT_NO_DIRMODEL if (qobject_cast<QDirModel *>(model)) { -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) setCaseSensitivity(Qt::CaseInsensitive); #else setCaseSensitivity(Qt::CaseSensitive); @@ -1620,7 +1620,7 @@ QString QCompleter::pathFromIndex(const QModelIndex& index) const idx = parent.sibling(parent.row(), index.column()); } while (idx.isValid()); -#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) if (list.count() == 1) // only the separator or some other text return list[0]; list[0].clear() ; // the join below will provide the separator @@ -1654,7 +1654,10 @@ QStringList QCompleter::splitPath(const QString& path) const QString pathCopy = QDir::toNativeSeparators(path); QString sep = QDir::separator(); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_SYMBIAN) + if (pathCopy == QLatin1String("\\")) + return QStringList(pathCopy); +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\")) return QStringList(pathCopy); QString doubleSlash(QLatin1String("\\\\")); @@ -1667,7 +1670,9 @@ QStringList QCompleter::splitPath(const QString& path) const QRegExp re(QLatin1Char('[') + QRegExp::escape(sep) + QLatin1Char(']')); QStringList parts = pathCopy.split(re); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_SYMBIAN) + // Do nothing +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (!doubleSlash.isEmpty()) parts[0].prepend(doubleSlash); #else diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp index 84aa16e..b84b63f 100644 --- a/src/gui/util/qdesktopservices.cpp +++ b/src/gui/util/qdesktopservices.cpp @@ -53,6 +53,8 @@ #include "qdesktopservices_win.cpp" #elif defined(Q_WS_MAC) #include "qdesktopservices_mac.cpp" +#elif defined(Q_WS_S60) +#include "qdesktopservices_s60.cpp" #endif #include <qhash.h> @@ -285,6 +287,11 @@ void QDesktopServices::unsetUrlHandler(const QString &scheme) \note The storage location returned can be a directory that does not exist; i.e., it may need to be created by the system or the user. + + \note On Symbian OS, DataLocation and ApplicationsLocation always point to appropriate + folder on same drive with executable. FontsLocation always points to folder on ROM drive. + Rest of the standard locations point to folder on same drive with executable, except + that if executable is in ROM the folder from C drive is returned. \note On Mac OS X, DataLocation does not include QCoreApplication::organizationName. Use code like this to add it: diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp new file mode 100644 index 0000000..3588ec9 --- /dev/null +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -0,0 +1,394 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This flag changes the implementation to use S60 CDcoumentHandler +// instead of apparch when opening the files +#undef USE_DOCUMENTHANDLER + +#include <qcoreapplication.h> +#include <qdir.h> +#include <qurl.h> +#include <private/qcore_symbian_p.h> + +#include <miutset.h> // KUidMsgTypeSMTP +#include <txtrich.h> // CRichText +#include <f32file.h> // TDriveUnit etc +#include <eikenv.h> // CEikonEnv +#include <apgcli.h> // RApaLsSession +#include <apgtask.h> // TApaTaskList, TApaTask +#include <rsendas.h> // RSendAs +#include <rsendasmessage.h> // RSendAsMessage +#include <pathinfo.h> // PathInfo +#ifdef USE_DOCUMENTHANDLER +#include <documenthandler.h> // CDocumentHandler +#endif + +QT_BEGIN_NAMESPACE + +_LIT(KSysBin, "\\Sys\\Bin\\"); +_LIT(KTempDir, "\\System\\Temp\\"); +_LIT(KBrowserPrefix, "4 " ); +_LIT(KFontsDir, "z:\\resource\\Fonts\\"); +const TUid KUidBrowser = { 0x10008D39 }; + +static void handleMailtoSchemeL(const QUrl &url) +{ + QString recipient = url.path(); + QString subject = url.queryItemValue("subject"); + QString body = url.queryItemValue("body"); + QString to = url.queryItemValue("to"); + QString cc = url.queryItemValue("cc"); + QString bcc = url.queryItemValue("bcc"); + + // these fields might have comma separated addresses + QStringList recipients = recipient.split(","); + QStringList tos = to.split(","); + QStringList ccs = cc.split(","); + QStringList bccs = bcc.split(","); + + + RSendAs sendAs; + User::LeaveIfError(sendAs.Connect()); + CleanupClosePushL(sendAs); + + + CSendAsAccounts* accounts = CSendAsAccounts::NewL(); + CleanupStack::PushL(accounts); + sendAs.AvailableAccountsL(KUidMsgTypeSMTP, *accounts); + TInt count = accounts->Count(); + CleanupStack::PopAndDestroy(accounts); + + if(!count) { + // TODO: we should try to create account if count == 0 + // CSendUi would provide account creation service for us, but it requires ridicilous + // capabilities: LocalServices NetworkServices ReadDeviceData ReadUserData WriteDeviceData WriteUserData + User::Leave(KErrNotSupported); + } else { + RSendAsMessage sendAsMessage; + sendAsMessage.CreateL(sendAs, KUidMsgTypeSMTP); + CleanupClosePushL(sendAsMessage); + + + // Subject + sendAsMessage.SetSubjectL(qt_QString2TPtrC(subject)); + + // Body + sendAsMessage.SetBodyTextL(qt_QString2TPtrC(body)); + + // To + foreach(QString item, recipients) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientTo ); + + foreach(QString item, tos) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientTo ); + + // Cc + foreach(QString item, ccs) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientCc ); + + // Bcc + foreach(QString item, bccs) + sendAsMessage.AddRecipientL(qt_QString2TPtrC(item), RSendAsMessage::ESendAsRecipientBcc ); + + // send the message + sendAsMessage.LaunchEditorAndCloseL(); + + // sendAsMessage (already closed) + CleanupStack::Pop(); + } + // sendAs + CleanupStack::PopAndDestroy(); +} + +static bool handleMailtoScheme(const QUrl &url) +{ + TRAPD(err, handleMailtoSchemeL(url)); + return err ? false : true; +} + +static void handleOtherSchemesL(const TDesC& aUrl) +{ + // Other schemes are at the moment passed to WEB browser + HBufC* buf16 = HBufC::NewLC( aUrl.Length() + KBrowserPrefix.iTypeLength ); + buf16->Des().Copy( KBrowserPrefix ); // Prefix used to launch correct browser view + buf16->Des().Append( aUrl ); + + TApaTaskList taskList( CEikonEnv::Static()->WsSession() ); + TApaTask task = taskList.FindApp( KUidBrowser ); + if ( task.Exists() ) + { + // Switch to existing browser instance + HBufC8* param8 = HBufC8::NewLC( buf16->Length() ); + param8->Des().Append( buf16->Des() ); + task.SendMessage( TUid::Uid( 0 ), *param8 ); // Uid is not used + CleanupStack::PopAndDestroy( param8 ); + } + else + { + // Start a new browser instance + RApaLsSession appArcSession; + User::LeaveIfError( appArcSession.Connect() ); + CleanupClosePushL<RApaLsSession>( appArcSession ); + TThreadId id; + appArcSession.StartDocument( *buf16, KUidBrowser , id ); + CleanupStack::PopAndDestroy(); // appArcSession + } + + CleanupStack::PopAndDestroy( buf16 ); +} + +static bool handleOtherSchemes(const QUrl &url) +{ + TRAPD( err, handleOtherSchemesL(qt_QString2TPtrC(url.toEncoded()))); + return err ? false : true; +} + +static TDriveUnit exeDrive() +{ + RProcess me; + TFileName processFileName = me.FileName(); + TDriveUnit drive(processFileName); + return drive; +} + +static TDriveUnit writableExeDrive() +{ + TDriveUnit drive = exeDrive(); + if( drive.operator TInt() == EDriveZ ) + return TDriveUnit( EDriveC ); + return drive; +} + +static TPtrC writableDataRoot() +{ + TDriveUnit drive = exeDrive(); + switch( drive.operator TInt() ){ + case EDriveC: + return PathInfo::PhoneMemoryRootPath(); + break; + case EDriveE: + return PathInfo::MemoryCardRootPath(); + break; + case EDriveZ: + // It is not possible to write on ROM drive -> + // return phone mem root path instead + return PathInfo::PhoneMemoryRootPath(); + break; + default: + // TODO: Should we return drive root similar to MemoryCardRootPath + return PathInfo::PhoneMemoryRootPath(); + break; + } +} + +static void openDocumentL(const TDesC& aUrl) +{ +#ifndef USE_DOCUMENTHANDLER + // Start app associated to file MIME type by using RApaLsSession + // Apparc base method cannot be used to open app in embedded mode, + // but seems to be most stable way at the moment + RApaLsSession appArcSession; + User::LeaveIfError( appArcSession.Connect() ); + CleanupClosePushL<RApaLsSession>( appArcSession ); + TThreadId id; + // ESwitchFiles means do not start another instance + // Leaves if file does not exist, leave is trapped in openDocument and false returned to user. + User::LeaveIfError( appArcSession.StartDocument( aUrl, id, + RApaLsSession::ESwitchFiles ) ); // ELaunchNewApp + CleanupStack::PopAndDestroy(); // appArcSession +#else + // This is an alternative way to launch app associated to MIME type + // CDocumentHandler would support opening apps in embedded mode, + // but our Qt application window group seems to always get switched on top of embedded one + // -> Cannot use menus etc of embedded app -> used + + CDocumentHandler* docHandler = CDocumentHandler::NewLC(); + TDataType temp; + //Standalone file opening fails for some file-types at least in S60 3.1 emulator + //For example .txt file fails with KErrAlreadyInUse and music files with KERN-EXEC 0 + //Workaround is to use OpenFileEmbeddedL + //docHandler->OpenFileL(aUrl, temp); + + // Opening file with CDocumentHandler will leave if file does not exist + // Leave is trapped in openDocument and false returned to user. + docHandler->OpenFileEmbeddedL(aUrl, temp); + CleanupStack::PopAndDestroy(docHandler); +#endif +} + +#ifdef USE_SCHEMEHANDLER +// The schemehandler component only exist in private SDK. This implementation +// exist here just for convenience in case that we need to use it later on +// The schemehandle based implementation is not yet tested. + +// The biggest advantage of schemehandler is that it can handle +// wide range of schemes and is extensible by plugins +static bool handleUrl(const QUrl &url) +{ + if (!url.isValid()) + return false; + + TRAPD( err, handleUrlL(qt_QString2TPtrC(url.toString()))); + return err ? false : true; +} + +static void handleUrlL(const TDesC& aUrl) +{ + CSchemeHandler* schemeHandler = CSchemeHandler::NewL( aUrl ); + CleanupStack::PushL( schemeHandler ); + schemeHandler->HandleUrlStandaloneL(); // Process the Url in standalone mode + CleanupStack::PopAndDestroy(); +} +static bool launchWebBrowser(const QUrl &url) +{ + return handleUrl(url); +} + +static bool openDocument(const QUrl &file) +{ + return handleUrl(url); +} +#endif + +static bool launchWebBrowser(const QUrl &url) +{ + if (!url.isValid()) + return false; + + if (url.scheme() == QLatin1String("mailto")) { + return handleMailtoScheme(url); + } + return handleOtherSchemes( url ); +} + +static bool openDocument(const QUrl &file) +{ + if (!file.isValid()) + return false; + + QString filePath = file.toLocalFile(); + filePath = QDir::toNativeSeparators(filePath); + TRAPD(err, openDocumentL(qt_QString2TPtrC(filePath))); + return err ? false : true; +} + +QString QDesktopServices::storageLocation(StandardLocation type) +{ + TFileName path; + + switch (type) { + case DesktopLocation: + qWarning("QDesktopServices::storageLocation %d not implemented", type); + break; + case DocumentsLocation: + path.Append(writableDataRoot()); + break; + case FontsLocation: + path.Append(KFontsDir); + break; + case ApplicationsLocation: + path.Append(exeDrive().Name()); + path.Append(KSysBin); + break; + case MusicLocation: + path.Append(writableDataRoot()); + path.Append(PathInfo::SoundsPath()); + break; + case MoviesLocation: + path.Append(writableDataRoot()); + path.Append(PathInfo::VideosPath()); + break; + case PicturesLocation: + path.Append(writableDataRoot()); + path.Append(PathInfo::ImagesPath()); + break; + case TempLocation: + path.Append(writableExeDrive().Name()); + path.Append(KTempDir); + //return QDir::tempPath(); break; + break; + case HomeLocation: + path.Append(writableDataRoot()); + //return QDir::homePath(); break; + break; + case DataLocation: + CEikonEnv::Static()->FsSession().PrivatePath( path ); + // TODO: Should we actually return phone mem if data is on ROM? + path.Insert( 0, exeDrive().Name() ); + break; + default: + break; + } + + // Convert to cross-platform format and clean the path + QString nativePath = QString::fromUtf16(path.Ptr(), path.Length()); + QString qtPath = QDir::fromNativeSeparators(nativePath); + qtPath = QDir::cleanPath(qtPath); + + // Note: The storage location returned can be a directory that does not exist; + // i.e., it may need to be created by the system or the user. + return qtPath; +} + +typedef QString (*LocalizerFunc)(QString&); + +static QString defaultLocalizedDirectoryName(QString&) +{ + return QString(); +} + +QString QDesktopServices::displayName(StandardLocation type) +{ + static LocalizerFunc ptrLocalizerFunc = NULL; + + if (!ptrLocalizerFunc) { + ptrLocalizerFunc = reinterpret_cast<LocalizerFunc> + (qt_resolveS60PluginFunc(S60Plugin_LocalizedDirectoryName)); + if (!ptrLocalizerFunc) + ptrLocalizerFunc = &defaultLocalizedDirectoryName; + } + + QString rawPath = storageLocation(type); + return ptrLocalizerFunc(rawPath); +} + + +QT_END_NAMESPACE diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index 5eed745..de43616 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -281,8 +281,8 @@ void QAbstractScrollAreaPrivate::init() scrollBarContainers[Qt::Vertical]->setVisible(false); QObject::connect(vbar, SIGNAL(valueChanged(int)), q, SLOT(_q_vslide(int))); QObject::connect(vbar, SIGNAL(rangeChanged(int,int)), q, SLOT(_q_showOrHideScrollBars()), Qt::QueuedConnection); - viewportFilter = new QAbstractScrollAreaFilter(this); - viewport->installEventFilter(viewportFilter); + viewportFilter.reset(new QAbstractScrollAreaFilter(this)); + viewport->installEventFilter(viewportFilter.data()); viewport->setFocusProxy(q); q->setFocusPolicy(Qt::WheelFocus); q->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); @@ -471,7 +471,12 @@ QAbstractScrollArea::QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget :QFrame(dd, parent) { Q_D(QAbstractScrollArea); - d->init(); + QT_TRY { + d->init(); + } QT_CATCH(...) { + d->viewportFilter.reset(); + QT_RETHROW; + } } /*! @@ -483,7 +488,12 @@ QAbstractScrollArea::QAbstractScrollArea(QWidget *parent) :QFrame(*new QAbstractScrollAreaPrivate, parent) { Q_D(QAbstractScrollArea); - d->init(); + QT_TRY { + d->init(); + } QT_CATCH(...) { + d->viewportFilter.reset(); + QT_RETHROW; + } } @@ -493,7 +503,8 @@ QAbstractScrollArea::QAbstractScrollArea(QWidget *parent) QAbstractScrollArea::~QAbstractScrollArea() { Q_D(QAbstractScrollArea); - delete d->viewportFilter; + // reset it here, otherwise we'll have a dangling pointer in ~QWidget + d->viewportFilter.reset(); } @@ -517,7 +528,7 @@ void QAbstractScrollArea::setViewport(QWidget *widget) d->viewport = widget; d->viewport->setParent(this); d->viewport->setFocusProxy(this); - d->viewport->installEventFilter(d->viewportFilter); + d->viewport->installEventFilter(d->viewportFilter.data()); d->layoutChildren(); if (isVisible()) d->viewport->show(); diff --git a/src/gui/widgets/qabstractscrollarea_p.h b/src/gui/widgets/qabstractscrollarea_p.h index f153711..ebdd281 100644 --- a/src/gui/widgets/qabstractscrollarea_p.h +++ b/src/gui/widgets/qabstractscrollarea_p.h @@ -98,7 +98,7 @@ public: inline bool viewportEvent(QEvent *event) { return q_func()->viewportEvent(event); } - QObject *viewportFilter; + QScopedPointer<QObject> viewportFilter; }; class QAbstractScrollAreaFilter : public QObject diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index 8028fdc..abe592d 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -687,8 +687,9 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) Q_D(QAbstractSlider); e->ignore(); if (e->orientation() != d->orientation && !rect().contains(e->pos())) + { return; - + } static qreal offset = 0; static QAbstractSlider *offset_owner = 0; if (offset_owner != this){ diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index 09accc7..d52af19 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -660,7 +660,6 @@ void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit) d->edit->setParent(this); d->edit->setFrame(false); - d->edit->setAttribute(Qt::WA_InputMethodEnabled, false); d->edit->setFocusProxy(this); d->edit->setAcceptDrops(false); @@ -691,6 +690,18 @@ void QAbstractSpinBox::interpretText() d->interpret(EmitIfChanged); } +/* + Reimplemented in 4.6, so be careful. + */ +/*! + \reimp +*/ +QVariant QAbstractSpinBox::inputMethodQuery(Qt::InputMethodQuery query) const +{ + Q_D(const QAbstractSpinBox); + return d->edit->inputMethodQuery(query); +} + /*! \reimp */ diff --git a/src/gui/widgets/qabstractspinbox.h b/src/gui/widgets/qabstractspinbox.h index 4e7fc3f..aa8905f 100644 --- a/src/gui/widgets/qabstractspinbox.h +++ b/src/gui/widgets/qabstractspinbox.h @@ -122,6 +122,8 @@ public: void interpretText(); bool event(QEvent *event); + QVariant inputMethodQuery(Qt::InputMethodQuery) const; + virtual QValidator::State validate(QString &input, int &pos) const; virtual void fixup(QString &input) const; diff --git a/src/gui/widgets/qactiontokeyeventmapper.cpp b/src/gui/widgets/qactiontokeyeventmapper.cpp new file mode 100644 index 0000000..280b1c6 --- /dev/null +++ b/src/gui/widgets/qactiontokeyeventmapper.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" +#include "qevent.h" +#include "qactiontokeyeventmapper_p.h" + +QT_BEGIN_NAMESPACE + +QActionToKeyEventMapper::QActionToKeyEventMapper(QAction *softKeyAction, Qt::Key key, QObject *parent) + : QObject(parent) + , m_softKeyAction(softKeyAction) + , m_key(key) +{ + +} + +QString QActionToKeyEventMapper::roleText(QAction::SoftKeyRole role) +{ + switch (role) { + case QAction::OptionsSoftKey: + return QAction::tr("Options"); + case QAction::SelectSoftKey: + return QAction::tr("Select"); + case QAction::BackSoftKey: + return QAction::tr("Back"); + case QAction::NextSoftKey: + return QAction::tr("Next"); + case QAction::PreviousSoftKey: + return QAction::tr("Previous"); + case QAction::OkSoftKey: + return QAction::tr("Ok"); + case QAction::CancelSoftKey: + return QAction::tr("Cancel"); + case QAction::EditSoftKey: + return QAction::tr("Edit"); + case QAction::ViewSoftKey: + return QAction::tr("View"); + default: + return QString(); + }; +} +void QActionToKeyEventMapper::addSoftKey(QAction::SoftKeyRole standardRole, Qt::Key key, QWidget *actionWidget) +{ + QAction *action = new QAction(actionWidget); + action->setSoftKeyRole(standardRole); + action->setText(roleText(standardRole)); + QActionToKeyEventMapper *softKey = new QActionToKeyEventMapper(action, key, actionWidget); + connect(action, SIGNAL(triggered()), softKey, SLOT(sendKeyEvent())); + connect(action, SIGNAL(destroyed()), softKey, SLOT(deleteLater())); + actionWidget->setSoftKey(action); +} + +void QActionToKeyEventMapper::removeSoftkey(QWidget *focussedWidget) +{ + focussedWidget->setSoftKey(0); +} + +void QActionToKeyEventMapper::sendKeyEvent() +{ + QApplication::postEvent(parent(), new QKeyEvent(QEvent::KeyPress, m_key, Qt::NoModifier)); +} + +QT_END_NAMESPACE + diff --git a/src/gui/widgets/qactiontokeyeventmapper_p.h b/src/gui/widgets/qactiontokeyeventmapper_p.h new file mode 100644 index 0000000..c54e612 --- /dev/null +++ b/src/gui/widgets/qactiontokeyeventmapper_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QACTIONTOKEYEVENTMAPPER_P_H +#define QACTIONTOKEYEVENTMAPPER_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 <QtCore/qobject.h> +#include "QtGui/qaction.h" +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QActionToKeyEventMapper : public QObject +{ + Q_OBJECT +public: + QActionToKeyEventMapper(QAction *softKeyAction, Qt::Key key, QObject *parent); + static QString roleText(QAction::SoftKeyRole role); + static void addSoftKey(QAction::SoftKeyRole standardRole, Qt::Key key, QWidget *actionWidget); + static void removeSoftkey(QWidget *focussedWidget); +private: + QAction *m_softKeyAction; + Qt::Key m_key; +private Q_SLOTS: + void sendKeyEvent(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QACTIONTOKEYEVENTMAPPER_P_H diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 01fe9d2..bd01da0 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -63,7 +63,7 @@ #include <private/qabstractitemmodel_p.h> #include <private/qabstractscrollarea_p.h> #include <qdebug.h> - +#include <private/qactiontokeyeventmapper_p.h> #ifdef Q_WS_X11 #include <private/qt_x11_p.h> #endif @@ -628,6 +628,9 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) case Qt::Key_Select: #endif if (view->currentIndex().isValid() && (view->currentIndex().flags() & Qt::ItemIsEnabled) ) { +#ifdef QT_KEYPAD_NAVIGATION + QActionToKeyEventMapper::removeSoftkey(this); +#endif combo->hidePopup(); emit itemSelected(view->currentIndex()); } @@ -640,6 +643,7 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) case Qt::Key_Escape: #ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Back: + QActionToKeyEventMapper::removeSoftkey(this); #endif combo->hidePopup(); return true; @@ -2453,6 +2457,11 @@ void QComboBox::showPopup() container->setUpdatesEnabled(updatesEnabled); container->update(); +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) + view()->setEditFocus(true); + QActionToKeyEventMapper::addSoftKey(QAction::CancelSoftKey, Qt::Key_Back, view()); +#endif } /*! diff --git a/src/gui/widgets/qdatetimeedit.cpp b/src/gui/widgets/qdatetimeedit.cpp index e7afea0..4d47a50 100644 --- a/src/gui/widgets/qdatetimeedit.cpp +++ b/src/gui/widgets/qdatetimeedit.cpp @@ -2390,6 +2390,7 @@ void QDateTimeEditPrivate::init(const QVariant &var) q->setCalendarPopup(true); #endif updateTimeSpec(); + q->setInputMethodHints(Qt::ImhPreferNumbers); setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem); } diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index a4b0b4f..1778308 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -97,8 +97,7 @@ extern void qt_mac_secure_keyboard(bool); //qapplication_mac.cpp static inline bool shouldEnableInputMethod(QLineEdit *lineedit) { - const QLineEdit::EchoMode mode = lineedit->echoMode(); - return !lineedit->isReadOnly() && (mode == QLineEdit::Normal || mode == QLineEdit::PasswordEchoOnEdit); + return !lineedit->isReadOnly(); } /*! @@ -544,7 +543,13 @@ void QLineEdit::setEchoMode(EchoMode mode) Q_D(QLineEdit); if (mode == (EchoMode)d->echoMode) return; - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); + Qt::InputMethodHints imHints = inputMethodHints(); + if (mode == Password) { + imHints |= Qt::ImhHiddenText; + } else { + imHints &= ~Qt::ImhHiddenText; + } + setInputMethodHints(imHints); d->echoMode = mode; d->passwordEchoEditing = false; d->updateTextLayout(); @@ -1768,6 +1773,13 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) } } #endif + + if (e->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!d->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(this, &event); + } + d->clickCausedFocus = 0; } /*! \reimp @@ -2262,8 +2274,16 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) } #endif - int priorState = d->undoState; - d->removeSelectedText(); + int priorState = 0; + bool isGettingInput = !e->commitString().isEmpty() || !e->preeditString().isEmpty() + || e->replacementLength() > 0; + bool cursorPositionChanged = false; + + if (isGettingInput) { + // If any text is being input, remove selected text. + priorState = d->undoState; + d->removeSelectedText(); + } int c = d->cursor; // cursor position after insertion of commit string if (e->replacementStart() <= 0) @@ -2277,11 +2297,30 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) d->selend = d->selstart + e->replacementLength(); d->removeSelectedText(); } - if (!e->commitString().isEmpty()) + if (!e->commitString().isEmpty()) { d->insert(e->commitString()); + cursorPositionChanged = true; + } d->cursor = qMin(c, d->text.length()); + for (int i = 0; i < e->attributes().size(); ++i) { + const QInputMethodEvent::Attribute &a = e->attributes().at(i); + if (a.type == QInputMethodEvent::Selection) { + d->cursor = qBound(0, a.start + a.length, d->text.length()); + if (a.length) { + d->selstart = qMax(0, qMin(a.start, d->text.length())); + d->selend = d->cursor; + if (d->selend < d->selstart) { + qSwap(d->selstart, d->selend); + } + } else { + d->selstart = d->selend = 0; + } + cursorPositionChanged = true; + } + } + d->textLayout.setPreeditArea(d->cursor, e->preeditString()); d->preeditCursor = e->preeditString().length(); d->hideCursor = false; @@ -2305,9 +2344,12 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) d->textLayout.setAdditionalFormats(formats); d->updateTextLayout(); update(); - if (!e->commitString().isEmpty()) + if (cursorPositionChanged) d->emitCursorPositionChanged(); - d->finishChange(priorState); + + if (isGettingInput) + d->finishChange(priorState); + #ifndef QT_NO_COMPLETER if (!e->commitString().isEmpty()) d->complete(Qt::Key_unknown); @@ -2325,11 +2367,20 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const case Qt::ImFont: return font(); case Qt::ImCursorPosition: - return QVariant((d->selend - d->selstart == 0) ? d->cursor : d->selend); + return QVariant(d->cursor); case Qt::ImSurroundingText: return QVariant(d->text); case Qt::ImCurrentSelection: return QVariant(selectedText()); + case Qt::ImMaximumTextLength: + return QVariant(maxLength()); + case Qt::ImAnchorPosition: + if (d->selstart == d->selend) + return QVariant(d->cursor); + else if (d->selstart == d->cursor) + return QVariant(d->selend); + else + return QVariant(d->selstart); default: return QVariant(); } @@ -2348,6 +2399,8 @@ void QLineEdit::focusInEvent(QFocusEvent *e) d->moveCursor(d->nextMaskBlank(0)); else if (!d->hasSelectedText()) selectAll(); + } else if (e->reason() == Qt::MouseFocusReason) { + d->clickCausedFocus = 1; } #ifdef QT_KEYPAD_NAVIGATION if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && e->reason() == Qt::PopupFocusReason)) @@ -2926,6 +2979,7 @@ void QLineEditPrivate::moveCursor(int pos, bool mark) selDirty = false; emit q->selectionChanged(); } + q->updateMicroFocus(); emitCursorPositionChanged(); } diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index 532528b..3db903f 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -76,7 +76,8 @@ public: : cursor(0), preeditCursor(0), cursorTimer(0), frame(1), cursorVisible(0), hideCursor(false), separator(0), readOnly(0), dragEnabled(0), contextMenuEnabled(1), echoMode(0), textDirty(0), - selDirty(0), validInput(1), alignment(Qt::AlignLeading | Qt::AlignVCenter), ascent(0), + selDirty(0), validInput(1), clickCausedFocus(0), + alignment(Qt::AlignLeading | Qt::AlignVCenter), ascent(0), maxLength(32767), hscroll(0), vscroll(0), lastCursorPos(-1), maskData(0), modifiedState(0), undoState(0), selstart(0), selend(0), userInput(false), emitingEditingFinished(false), passwordEchoEditing(false) @@ -110,6 +111,7 @@ public: uint textDirty : 1; uint selDirty : 1; uint validInput : 1; + uint clickCausedFocus : 1; uint alignment; int ascent; int maxLength; diff --git a/src/gui/widgets/qmacnativewidget_mac.h b/src/gui/widgets/qmacnativewidget_mac.h index 4db65e0..d36d74f 100644 --- a/src/gui/widgets/qmacnativewidget_mac.h +++ b/src/gui/widgets/qmacnativewidget_mac.h @@ -64,7 +64,7 @@ protected: bool event(QEvent *ev); private: - Q_DECLARE_PRIVATE_D(QWidget::d_ptr, QMacNativeWidget) + Q_DECLARE_PRIVATE(QMacNativeWidget) }; QT_END_NAMESPACE diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp index 558ba42..394523a 100644 --- a/src/gui/widgets/qmainwindow.cpp +++ b/src/gui/widgets/qmainwindow.cpp @@ -481,6 +481,11 @@ void QMainWindow::setMenuBar(QMenuBar *menuBar) oldMenuBar->deleteLater(); } d->layout->setMenuBar(menuBar); + if (menuBar) { + QAction* menu = new QAction(QString::fromLatin1("Options"), this); + menu->setSoftKeyRole(QAction::MenuSoftKey); + setSoftKey(menu); + } } /*! @@ -1391,7 +1396,16 @@ bool QMainWindow::event(QEvent *event) } break; #endif - +#ifndef QT_NO_MENUBAR + case QEvent::WindowActivate: + if (d->layout->menuBar()) { + // ### TODO: This is evil, there is no need to create a new action every time + QAction* menu = new QAction(QString::fromLatin1("Options"), this); + menu->setSoftKeyRole(QAction::MenuSoftKey); + setSoftKey(menu); + } + break; +#endif default: break; } diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index aa601cb..278a6cd 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -60,6 +60,7 @@ #ifndef QT_NO_WHATSTHIS # include <qwhatsthis.h> #endif +#include <private/qactiontokeyeventmapper_p.h> #include "qmenu_p.h" #include "qmenubar_p.h" @@ -592,8 +593,14 @@ void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason //when the action has no QWidget, the QMenu itself should // get the focus // Since the menu is a pop-up, it uses the popup reason. - if (!q->hasFocus()) + if (!q->hasFocus()) { q->setFocus(Qt::PopupFocusReason); +#ifdef QT_KEYPAD_NAVIGATION + // TODO: aportale, remove KEYPAD_NAVIGATION_HACK when softkey stack + // handles focus related and user related actions separately... + QActionToKeyEventMapper::addSoftKey(QAction::CancelSoftKey, Qt::Key_Back, q); +#endif + } } } } else { //action is a separator @@ -1808,6 +1815,22 @@ void QMenu::popup(const QPoint &p, QAction *atAction) QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen); +#ifdef QT_KEYPAD_NAVIGATION + if (!atAction && QApplication::keypadNavigationEnabled()) { + // Try to have one item activated + if (d->defaultAction && d->defaultAction->isEnabled()) { + atAction = d->defaultAction; + // TODO: This works for first level menus, not yet sub menus + } else { + foreach (QAction *action, d->actionList) + if (action->isEnabled()) { + atAction = action; + break; + } + } + d->currentAction = atAction; + } +#endif if (d->ncols > 1) { pos.setY(screen.top()+desktopFrame); } else if (atAction) { @@ -1935,6 +1958,9 @@ void QMenu::popup(const QPoint &p, QAction *atAction) #ifndef QT_NO_ACCESSIBILITY QAccessible::updateAccessibility(this, 0, QAccessible::PopupMenuStart); #endif +#ifdef QT_KEYPAD_NAVIGATION + QActionToKeyEventMapper::addSoftKey(QAction::CancelSoftKey, Qt::Key_Back, this); +#endif } /*! @@ -2585,6 +2611,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) case Qt::Key_Escape: #ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Back: + QActionToKeyEventMapper::removeSoftkey(this); #endif key_consumed = true; if (d->tornoff) { @@ -2862,6 +2889,16 @@ void QMenu::actionEvent(QActionEvent *e) d->wce_menu->syncAction(e->action()); #endif +#ifdef Q_OS_SYMBIAN + if (!d->symbian_menu) + d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate; + if (e->type() == QEvent::ActionAdded) + d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before())); + else if (e->type() == QEvent::ActionRemoved) + d->symbian_menu->removeAction(e->action()); + else if (e->type() == QEvent::ActionChanged) + d->symbian_menu->syncAction(e->action()); +#endif if (isVisible()) { d->updateActions(); resize(sizeHint()); diff --git a/src/gui/widgets/qmenu.h b/src/gui/widgets/qmenu.h index e1a6256..d26dd76 100644 --- a/src/gui/widgets/qmenu.h +++ b/src/gui/widgets/qmenu.h @@ -52,11 +52,19 @@ #endif QT_BEGIN_HEADER +#ifdef Q_OS_SYMBIAN + class CEikMenuPane; +#endif QT_BEGIN_NAMESPACE QT_MODULE(Gui) +#ifdef Q_OS_SYMBIAN + IMPORT_C void qt_symbian_show_toplevel(CEikMenuPane* menuPane); + IMPORT_C void qt_symbian_show_submenu(CEikMenuPane* menuPane, int id); +#endif + #ifndef QT_NO_MENU class QMenuPrivate; @@ -145,7 +153,6 @@ public: HMENU wceMenu(bool create = false); #endif - bool separatorsCollapsible() const; void setSeparatorsCollapsible(bool collapse); diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index 1dfe701..d5674c8 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -61,6 +61,9 @@ #include "QtCore/qbasictimer.h" #include "private/qwidget_p.h" +#ifdef Q_OS_SYMBIAN +class CEikMenuPane; +#endif QT_BEGIN_NAMESPACE #ifndef QT_NO_MENU @@ -120,6 +123,15 @@ struct QWceMenuAction { QWceMenuAction() : menuHandle(0), command(0) {} }; #endif +#ifdef Q_OS_SYMBIAN +struct QSymbianMenuAction { + uint command; + int parent; + CEikMenuPane* menuPane; + QPointer<QAction> action; + QSymbianMenuAction() : command(0) {} +}; +#endif class QMenuPrivate : public QWidgetPrivate { @@ -135,6 +147,9 @@ public: #if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR) ,wce_menu(0) #endif +#ifdef Q_OS_SYMBIAN + ,symbian_menu(0) +#endif #ifdef QT3_SUPPORT ,emitHighlighted(false) #endif @@ -148,6 +163,10 @@ public: #if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR) delete wce_menu; #endif +#ifdef Q_OS_SYMBIAN + delete symbian_menu; +#endif + } void init(); @@ -318,7 +337,28 @@ public: HMENU wceMenu(bool create = false); QAction* wceCommands(uint command); #endif - +#if defined(Q_OS_SYMBIAN) + struct QSymbianMenuPrivate { + QList<QSymbianMenuAction*> actionItems; + QSymbianMenuPrivate(); + ~QSymbianMenuPrivate(); + void addAction(QAction *, QSymbianMenuAction* =0); + void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); + void syncAction(QSymbianMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QSymbianMenuAction *); + void rebuild(bool reCreate = false); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QSymbianMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QSymbianMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + } *symbian_menu; +#endif QPointer<QWidget> noReplayFor; }; diff --git a/src/gui/widgets/qmenu_symbian.cpp b/src/gui/widgets/qmenu_symbian.cpp new file mode 100644 index 0000000..69ce981 --- /dev/null +++ b/src/gui/widgets/qmenu_symbian.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** $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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmenu.h" +#include "qapplication.h" +#include "qevent.h" +#include "qstyle.h" +#include "qdebug.h" +#include "qwidgetaction.h" +#include <eikmenub.h> +#include <eikmenup.h> +#include <private/qapplication_p.h> +#include <private/qmenu_p.h> +#include <private/qmenubar_p.h> +#include <qt_s60_p.h> +#include <eikaufty.h> +#include <eikbtgpc.h> +#include <QtCore/qlibrary.h> +#include <avkon.rsg> +#ifndef QT_NO_MENUBAR + +QT_BEGIN_NAMESPACE + +typedef QMultiHash<QWidget *, QMenuBarPrivate *> MenuBarHash; +Q_GLOBAL_STATIC(MenuBarHash, menubars) + +#define QT_FIRST_MENU_ITEM 32000 + +struct SymbianMenuItem +{ + int id; + CEikMenuPaneItem::SData menuItemData; + QList<SymbianMenuItem*> children; + QAction* action; +}; + +static QList<SymbianMenuItem*> symbianMenus; +static QList<QMenuBar*> nativeMenuBars; +static uint qt_symbian_menu_static_cmd_id = QT_FIRST_MENU_ITEM; +static QPointer<QWidget> widgetWithContextMenu; +static QList<QAction*> contextMenuActionList; +static QAction contextAction(0); +static int contexMenuCommand=0; + +bool menuExists() +{ + QWidget *w = qApp->activeWindow(); + QMenuBarPrivate *mb = menubars()->value(w); + if ((!mb) && !menubars()->count()) + return false; + return true; +} + +static bool hasContextMenu(QWidget* widget) +{ + if (!widget) + return false; + const Qt::ContextMenuPolicy policy = widget->contextMenuPolicy(); + if (policy != Qt::NoContextMenu && policy != Qt::PreventContextMenu ) { + return true; + } + return false; +} +// ### FIX THIS, copy/paste of original (faulty) stripped text implementation. +// Implementation should be removed from QAction implementation to some generic place +static QString qt_strippedText_copy_from_qaction(QString s) +{ + s.remove(QString::fromLatin1("...")); + int i = 0; + while (i < s.size()) { + ++i; + if (s.at(i-1) != QLatin1Char('&')) + continue; + if (i < s.size() && s.at(i) == QLatin1Char('&')) + ++i; + s.remove(i-1,1); + } + return s.trimmed(); +}; + +static SymbianMenuItem* qt_symbian_find_menu(int id, const QList<SymbianMenuItem*> &parent) +{ + int index=0; + while (index < parent.count()) { + SymbianMenuItem* temp = parent[index]; + if (temp->menuItemData.iCascadeId == id) + return temp; + else if (temp->menuItemData.iCascadeId != 0) { + SymbianMenuItem* result = qt_symbian_find_menu( id, temp->children); + if (result) + return result; + } + index++; + } + return 0; +} + +static SymbianMenuItem* qt_symbian_find_menu_item(int id, const QList<SymbianMenuItem*> &parent) +{ + int index=0; + while (index < parent.count()) { + SymbianMenuItem* temp = parent[index]; + if (temp->menuItemData.iCascadeId != 0) { + SymbianMenuItem* result = qt_symbian_find_menu_item( id, temp->children); + if (result) + return result; + } + else if (temp->menuItemData.iCommandId == id) + return temp; + index++; + + } + return 0; +} + +static void qt_symbian_insert_action(QSymbianMenuAction* action, QList<SymbianMenuItem*>* parent) +{ + if (action->action->isVisible()) { + if (action->action->isSeparator()) + return; + +// ### FIX THIS, the qt_strippedText2 doesn't work perfectly for stripping & marks. Same bug is in QAction +// New really working method is needed in a place where the implementation isn't copy/pasted + QString text = qt_strippedText_copy_from_qaction(action->action->text()); + TPtrC menuItemText(qt_QString2TPtrC(text)); + + if (action->action->menu()) { + SymbianMenuItem* menuItem = new SymbianMenuItem(); + menuItem->menuItemData.iCascadeId = action->command; + menuItem->menuItemData.iCommandId = action->command; + menuItem->menuItemData.iFlags = 0; + menuItem->menuItemData.iText = menuItemText; + menuItem->action = action->action; + if (action->action->menu()->actions().size() == 0 || !action->action->isEnabled() ) + menuItem->menuItemData.iFlags |= EEikMenuItemDimmed; + parent->append(menuItem); + + if (action->action->menu()->actions().size() > 0) { + for (int c2= 0; c2 < action->action->menu()->actions().size(); ++c2) { + QSymbianMenuAction *symbianAction2 = new QSymbianMenuAction; + symbianAction2->action = action->action->menu()->actions().at(c2); + QMenu * menu = symbianAction2->action->menu(); + symbianAction2->command = qt_symbian_menu_static_cmd_id++; + qt_symbian_insert_action(symbianAction2, &(menuItem->children)); + } + } + + } else { + SymbianMenuItem* menuItem = new SymbianMenuItem(); + menuItem->menuItemData.iCascadeId = 0; + menuItem->menuItemData.iCommandId = action->command; + menuItem->menuItemData.iFlags = 0; + menuItem->menuItemData.iText = menuItemText; + menuItem->action = action->action; + if (!action->action->isEnabled()){ + menuItem->menuItemData.iFlags += EEikMenuItemDimmed; + } + + if (action->action->isCheckable()) { + if (action->action->isChecked()) + menuItem->menuItemData.iFlags += EEikMenuItemCheckBox | EEikMenuItemSymbolOn; + else + menuItem->menuItemData.iFlags += EEikMenuItemCheckBox; + } + parent->append(menuItem); + } + } +} + +void deleteAll(QList<SymbianMenuItem*> *items) +{ + while (!items->isEmpty()) { + SymbianMenuItem* temp = items->takeFirst(); + deleteAll(&temp->children); + delete temp; + } +} + +static void rebuildMenu() +{ + widgetWithContextMenu = 0; + QMenuBarPrivate *mb = 0; + QWidget *w = qApp->activeWindow(); + QWidget* focusWidget = QApplication::focusWidget(); + if (focusWidget) { + if (hasContextMenu(focusWidget)) + widgetWithContextMenu = focusWidget; + } + + if (w) { + mb = menubars()->value(w); + qt_symbian_menu_static_cmd_id = QT_FIRST_MENU_ITEM; + deleteAll( &symbianMenus ); + if (!mb) + return; + mb->symbian_menubar->rebuild(); + } +} + +Q_GUI_EXPORT void qt_symbian_show_toplevel( CEikMenuPane* menuPane) +{ + if (!menuExists()) + return; + rebuildMenu(); + for (int i = 0; i < symbianMenus.count(); ++i) + menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData); +} + +Q_GUI_EXPORT void qt_symbian_show_submenu( CEikMenuPane* menuPane, int id) +{ + SymbianMenuItem* menu = qt_symbian_find_menu(id, symbianMenus); + if (menu) { + for (int i = 0; i < menu->children.count(); ++i) + menuPane->AddMenuItemL(menu->children.at(i)->menuItemData); + } +} + +void QMenuBarPrivate::symbianCommands(int command) +{ + if (command == contexMenuCommand && !widgetWithContextMenu.isNull()) { + QContextMenuEvent* event = new QContextMenuEvent(QContextMenuEvent::Keyboard, QPoint(0,0)); + QCoreApplication::postEvent(widgetWithContextMenu, event); + } + + int size = nativeMenuBars.size(); + for (int i = 0; i < nativeMenuBars.size(); ++i) { + SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus); + if (!menu) + continue; + + emit nativeMenuBars.at(i)->triggered(menu->action); + menu->action->activate(QAction::Trigger); + break; + } +} + +void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent) +{ + Q_Q(QMenuBar); + if (parent && parent->isWindow()){ + menubars()->insert(q->window(), this); + symbian_menubar = new QSymbianMenuBarPrivate(this); + nativeMenuBars.append(q); + } +} + +void QMenuBarPrivate::symbianDestroyMenuBar() +{ + Q_Q(QMenuBar); + int index = nativeMenuBars.indexOf(q); + nativeMenuBars.removeAt(index); + menubars()->remove(q->window(), this); + rebuildMenu(); + if (symbian_menubar) + delete symbian_menubar; + symbian_menubar = 0; +} + +QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar) +{ + d = menubar; +} + +QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate() +{ + deleteAll( &symbianMenus ); + symbianMenus.clear(); + d = 0; + rebuild(); +} + +QMenuPrivate::QSymbianMenuPrivate::QSymbianMenuPrivate() +{ +} + +QMenuPrivate::QSymbianMenuPrivate::~QSymbianMenuPrivate() +{ + +} + +void QMenuPrivate::QSymbianMenuPrivate::addAction(QAction *a, QSymbianMenuAction *before) +{ + QSymbianMenuAction *action = new QSymbianMenuAction; + action->action = a; + action->command = qt_symbian_menu_static_cmd_id++; + addAction(action, before); +} + +void QMenuPrivate::QSymbianMenuPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) +{ + if (!action) + return; + int before_index = actionItems.indexOf(before); + if (before_index < 0) { + before = 0; + before_index = actionItems.size(); + } + actionItems.insert(before_index, action); +} + + +void QMenuPrivate::QSymbianMenuPrivate::syncAction(QSymbianMenuAction *) +{ + rebuild(); +} + +void QMenuPrivate::QSymbianMenuPrivate::removeAction(QSymbianMenuAction *action) +{ + actionItems.removeAll(action); + delete action; + action = 0; + rebuild(); +} + +void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool) +{ +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before) +{ + QSymbianMenuAction *action = new QSymbianMenuAction; + action->action = a; + action->command = qt_symbian_menu_static_cmd_id++; + addAction(action, before); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) +{ + if (!action) + return; + int before_index = actionItems.indexOf(before); + if (before_index < 0) { + before = 0; + before_index = actionItems.size(); + } + actionItems.insert(before_index, action); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::syncAction(QSymbianMenuAction*) +{ + rebuild(); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::removeAction(QSymbianMenuAction *action) +{ + actionItems.removeAll(action); + delete action; + rebuild(); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::insertNativeMenuItems(const QList<QAction*> &actions) +{ + for (int i = 0; i <actions.size(); ++i) { + QSymbianMenuAction *symbianActionTopLevel = new QSymbianMenuAction; + symbianActionTopLevel->action = actions.at(i); + symbianActionTopLevel->parent = 0; + symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++; + qt_symbian_insert_action(symbianActionTopLevel, &symbianMenus); + } +} + + + +void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild() +{ + contexMenuCommand = 0; + qt_symbian_menu_static_cmd_id = QT_FIRST_MENU_ITEM; + deleteAll( &symbianMenus ); + if (d) + insertNativeMenuItems(d->actions); + + contextMenuActionList.clear(); + if (widgetWithContextMenu) { + contexMenuCommand = qt_symbian_menu_static_cmd_id; + contextAction.setText(QMenuBar::tr("Actions")); + contextMenuActionList.append(&contextAction); + insertNativeMenuItems(contextMenuActionList); + } +} +QT_END_NAMESPACE + +#endif //QT_NO_MENUBAR diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index 68a0233..09742d2 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -730,6 +730,12 @@ void QMenuBarPrivate::init() q->hide(); } #endif +#ifdef Q_OS_SYMBIAN + symbianCreateMenuBar(q->parentWidget()); + if(symbian_menubar) + q->hide(); +#endif + q->setBackgroundRole(QPalette::Button); oldWindow = oldParent = 0; #ifdef QT3_SUPPORT @@ -779,6 +785,10 @@ QMenuBar::~QMenuBar() if (qt_wince_is_mobile()) d->wceDestroyMenuBar(); #endif +#ifdef Q_OS_SYMBIAN + Q_D(QMenuBar); + d->symbianDestroyMenuBar(); +#endif } /*! @@ -1027,6 +1037,12 @@ void QMenuBar::setVisible(bool visible) if (isNativeMenuBar()) return; #endif +#ifdef Q_OS_SYMBIAN + Q_D(QMenuBar); + if(d->symbian_menubar) + return; +#endif + QWidget::setVisible(visible); } @@ -1281,6 +1297,17 @@ void QMenuBar::actionEvent(QActionEvent *e) nativeMenuBar->syncAction(e->action()); } #endif +#ifdef Q_OS_SYMBIAN + if(d->symbian_menubar) { + if(e->type() == QEvent::ActionAdded) + d->symbian_menubar->addAction(e->action(), d->symbian_menubar->findAction(e->before())); + else if(e->type() == QEvent::ActionRemoved) + d->symbian_menubar->removeAction(e->action()); + else if(e->type() == QEvent::ActionChanged) + d->symbian_menubar->syncAction(e->action()); + } +#endif + if(e->type() == QEvent::ActionAdded) { connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered())); @@ -1367,6 +1394,11 @@ void QMenuBarPrivate::handleReparent() if (qt_wince_is_mobile() && wce_menubar) wce_menubar->rebuild(); #endif +#ifdef Q_OS_SYMBIAN + if (symbian_menubar) + symbian_menubar->rebuild(); +#endif + } #ifdef QT3_SUPPORT @@ -1601,7 +1633,7 @@ QRect QMenuBar::actionGeometry(QAction *act) const QSize QMenuBar::minimumSizeHint() const { Q_D(const QMenuBar); -#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) +#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN) const bool as_gui_menubar = !isNativeMenuBar(); #else const bool as_gui_menubar = true; @@ -1659,7 +1691,7 @@ QSize QMenuBar::minimumSizeHint() const QSize QMenuBar::sizeHint() const { Q_D(const QMenuBar); -#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) +#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN) const bool as_gui_menubar = !isNativeMenuBar(); #else const bool as_gui_menubar = true; @@ -1721,7 +1753,7 @@ QSize QMenuBar::sizeHint() const int QMenuBar::heightForWidth(int) const { Q_D(const QMenuBar); -#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) +#if defined(Q_WS_MAC) || defined(Q_WS_WINCE) || defined(Q_OS_SYMBIAN) const bool as_gui_menubar = !isNativeMenuBar(); #else const bool as_gui_menubar = true; diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index 5dab310..0421736 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -61,6 +61,13 @@ #include "qguifunctions_wince.h" #endif +#ifndef QT_NO_MENUBAR +#ifdef Q_OS_SYMBIAN +class CCoeControl; +class CEikMenuBar; +#endif +#endif + QT_BEGIN_NAMESPACE #ifndef QT_NO_MENUBAR @@ -79,7 +86,11 @@ public: #ifdef Q_WS_WINCE , wce_menubar(0), wceClassicMenu(false) #endif - { } +#ifdef Q_OS_SYMBIAN + , symbian_menubar(0) +#endif + + { } ~QMenuBarPrivate() { #ifdef Q_WS_MAC @@ -88,6 +99,9 @@ public: #ifdef Q_WS_WINCE delete wce_menubar; #endif +#ifdef Q_OS_SYMBIAN + delete symbian_menubar; +#endif } void init(); @@ -223,6 +237,35 @@ public: void wceRefresh(); bool wceEmitSignals(QList<QWceMenuAction*> actions, uint command); #endif +#ifdef Q_OS_SYMBIAN + void symbianCreateMenuBar(QWidget *); + void symbianDestroyMenuBar(); + struct QSymbianMenuBarPrivate { + QList<QSymbianMenuAction*> actionItems; + QMenuBarPrivate *d; + QSymbianMenuBarPrivate(QMenuBarPrivate *menubar); + ~QSymbianMenuBarPrivate(); + void addAction(QAction *, QSymbianMenuAction* =0); + void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); + void syncAction(QSymbianMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QSymbianMenuAction *); + void rebuild(); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QSymbianMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QSymbianMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + void insertNativeMenuItems(const QList<QAction*> &actions); + + } *symbian_menubar; + static void symbianCommands(int command); + +#endif }; #endif diff --git a/src/gui/widgets/qmenudata.h b/src/gui/widgets/qmenudata.h index 24d960a..d570f20 100644 --- a/src/gui/widgets/qmenudata.h +++ b/src/gui/widgets/qmenudata.h @@ -67,6 +67,8 @@ private: friend class QMenuBar; void setId(int); void setSignalValue(int); + + Q_DISABLE_COPY(QMenuItem); }; QT_END_NAMESPACE diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index af11aa7..36bac84 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -72,6 +72,11 @@ QT_BEGIN_NAMESPACE +static inline bool shouldEnableInputMethod(QPlainTextEdit *plaintextedit) +{ + return !plaintextedit->isReadOnly(); +} + class QPlainTextDocumentLayoutPrivate : public QAbstractTextDocumentLayoutPrivate { Q_DECLARE_PUBLIC(QPlainTextDocumentLayout) @@ -720,7 +725,8 @@ QPlainTextEditPrivate::QPlainTextEditPrivate() tabChangesFocus(false), lineWrap(QPlainTextEdit::WidgetWidth), wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), - topLine(0), pageUpDownLastCursorYIsValid(false) + clickCausedFocus(0),topLine(0), + pageUpDownLastCursorYIsValid(false) { showCursorOnInitialShow = true; backgroundVisible = false; @@ -1920,6 +1926,13 @@ void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e) d->autoScrollTimer.stop(); d->ensureCursorVisible(); } + + if (e->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!d->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(this, &event); + } + d->clickCausedFocus = 0; } /*! \reimp @@ -2053,6 +2066,9 @@ QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const void QPlainTextEdit::focusInEvent(QFocusEvent *e) { Q_D(QPlainTextEdit); + if (e->reason() == Qt::MouseFocusReason) { + d->clickCausedFocus = 1; + } QAbstractScrollArea::focusInEvent(e); d->sendControlEvent(e); } @@ -2319,7 +2335,7 @@ void QPlainTextEdit::setReadOnly(bool ro) } else { flags = Qt::TextEditorInteraction; } - setAttribute(Qt::WA_InputMethodEnabled, !ro); + setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); d->control->setTextInteractionFlags(flags); } diff --git a/src/gui/widgets/qplaintextedit_p.h b/src/gui/widgets/qplaintextedit_p.h index 0739d53..56a3aa9 100644 --- a/src/gui/widgets/qplaintextedit_p.h +++ b/src/gui/widgets/qplaintextedit_p.h @@ -91,7 +91,10 @@ public: return r; } inline QRectF cursorRect() { return cursorRect(textCursor()); } - void ensureCursorVisible() { textEdit->ensureCursorVisible(); } + void ensureCursorVisible() { + textEdit->ensureCursorVisible(); + emit microFocusChanged(); + } QPlainTextEdit *textEdit; @@ -148,6 +151,7 @@ public: uint backgroundVisible : 1; uint centerOnScroll : 1; uint inDrag : 1; + uint clickCausedFocus : 1; int topLine; diff --git a/src/gui/widgets/qprintpreviewwidget.cpp b/src/gui/widgets/qprintpreviewwidget.cpp index d4e5122..24d81e0 100644 --- a/src/gui/widgets/qprintpreviewwidget.cpp +++ b/src/gui/widgets/qprintpreviewwidget.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qprintpreviewwidget.h" +#include "private/qwidget_p.h" #include <private/qprinter_p.h> #include <QtCore/qmath.h> @@ -170,12 +171,12 @@ protected: } // anonymous namespace -class QPrintPreviewWidgetPrivate +class QPrintPreviewWidgetPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QPrintPreviewWidget) public: - QPrintPreviewWidgetPrivate(QPrintPreviewWidget *q) - : q_ptr(q), scene(0), curPage(1), + QPrintPreviewWidgetPrivate() + : scene(0), curPage(1), viewMode(QPrintPreviewWidget::SinglePageView), zoomMode(QPrintPreviewWidget::FitInView), zoomFactor(1), initialized(false), fitting(true) @@ -194,7 +195,6 @@ public: void setZoomFactor(qreal zoomFactor); int calcCurrentPage(); - QPrintPreviewWidget *q_ptr; GraphicsView *graphicsView; QGraphicsScene *scene; @@ -518,7 +518,7 @@ void QPrintPreviewWidgetPrivate::setZoomFactor(qreal _zoomFactor) \sa QWidget::setWindowFlags() */ QPrintPreviewWidget::QPrintPreviewWidget(QPrinter *printer, QWidget *parent, Qt::WindowFlags flags) - : QWidget(parent, flags), d_ptr(new QPrintPreviewWidgetPrivate(this)) + : QWidget(*new QPrintPreviewWidgetPrivate, parent, flags) { Q_D(QPrintPreviewWidget); d->printer = printer; @@ -534,7 +534,7 @@ QPrintPreviewWidget::QPrintPreviewWidget(QPrinter *printer, QWidget *parent, Qt: preview. */ QPrintPreviewWidget::QPrintPreviewWidget(QWidget *parent, Qt::WindowFlags flags) - : QWidget(parent, flags), d_ptr(new QPrintPreviewWidgetPrivate(this)) + : QWidget(*new QPrintPreviewWidgetPrivate, parent, flags) { Q_D(QPrintPreviewWidget); d->printer = new QPrinter; @@ -551,7 +551,6 @@ QPrintPreviewWidget::~QPrintPreviewWidget() Q_D(QPrintPreviewWidget); if (d->ownPrinter) delete d->printer; - delete d_ptr; } /*! diff --git a/src/gui/widgets/qprintpreviewwidget.h b/src/gui/widgets/qprintpreviewwidget.h index 27110a4..9f7ea6e 100644 --- a/src/gui/widgets/qprintpreviewwidget.h +++ b/src/gui/widgets/qprintpreviewwidget.h @@ -111,7 +111,7 @@ Q_SIGNALS: void previewChanged(); private: - QPrintPreviewWidgetPrivate *d_ptr; + void *dummy; // ### remove in Qt 5.0 Q_PRIVATE_SLOT(d_func(), void _q_fit()) Q_PRIVATE_SLOT(d_func(), void _q_updateCurrentPage()) }; diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp index a9b9a84..7906022 100644 --- a/src/gui/widgets/qspinbox.cpp +++ b/src/gui/widgets/qspinbox.cpp @@ -77,6 +77,8 @@ public: QChar thousand; inline void init() { + Q_Q(QSpinBox); + q->setInputMethodHints(Qt::ImhDigitsOnly); setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem); } }; @@ -97,6 +99,11 @@ public: // variables int decimals; QChar delimiter, thousand; + + inline void init() { + Q_Q(QDoubleSpinBox); + q->setInputMethodHints(Qt::ImhFormattedNumbersOnly); + } }; @@ -592,6 +599,8 @@ void QSpinBox::fixup(QString &input) const QDoubleSpinBox::QDoubleSpinBox(QWidget *parent) : QAbstractSpinBox(*new QDoubleSpinBoxPrivate(parent), parent) { + Q_D(QDoubleSpinBox); + d->init(); } /*! diff --git a/src/gui/widgets/qtextedit.cpp b/src/gui/widgets/qtextedit.cpp index 1c4df93..c1ec5c2 100644 --- a/src/gui/widgets/qtextedit.cpp +++ b/src/gui/widgets/qtextedit.cpp @@ -74,6 +74,10 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_TEXTEDIT +static inline bool shouldEnableInputMethod(QTextEdit *textedit) +{ + return !textedit->isReadOnly(); +} class QTextEditControl : public QTextControl { @@ -104,7 +108,7 @@ public: QTextEditPrivate::QTextEditPrivate() : control(0), autoFormatting(QTextEdit::AutoNone), tabChangesFocus(false), - lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0), + lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0), clickCausedFocus(0), wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), textFormat(Qt::AutoText) { ignoreAutomaticScrollbarAdjustment = false; @@ -1559,6 +1563,12 @@ void QTextEdit::mouseReleaseEvent(QMouseEvent *e) d->autoScrollTimer.stop(); ensureCursorVisible(); } + if (e->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!d->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(this, &event); + } + d->clickCausedFocus = 0; } /*! \reimp @@ -1694,6 +1704,9 @@ QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const void QTextEdit::focusInEvent(QFocusEvent *e) { Q_D(QTextEdit); + if (e->reason() == Qt::MouseFocusReason) { + d->clickCausedFocus = 1; + } QAbstractScrollArea::focusInEvent(e); d->sendControlEvent(e); } @@ -2058,7 +2071,7 @@ void QTextEdit::setReadOnly(bool ro) } else { flags = Qt::TextEditorInteraction; } - setAttribute(Qt::WA_InputMethodEnabled, !ro); + setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); d->control->setTextInteractionFlags(flags); } diff --git a/src/gui/widgets/qtextedit_p.h b/src/gui/widgets/qtextedit_p.h index 3c37868..594174a 100644 --- a/src/gui/widgets/qtextedit_p.h +++ b/src/gui/widgets/qtextedit_p.h @@ -123,6 +123,7 @@ public: uint preferRichText : 1; uint showCursorOnInitialShow : 1; uint inDrag : 1; + uint clickCausedFocus : 1; // Qt3 COMPAT only, for setText Qt::TextFormat textFormat; diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index 86dc453..9e226e2 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -78,8 +78,8 @@ HEADERS += \ widgets/qtoolbararealayout_p.h \ widgets/qplaintextedit.h \ widgets/qplaintextedit_p.h \ - widgets/qprintpreviewwidget.h - + widgets/qprintpreviewwidget.h \ + widgets/qactiontokeyeventmapper_p.h SOURCES += \ widgets/qabstractbutton.cpp \ widgets/qabstractslider.cpp \ @@ -138,8 +138,8 @@ SOURCES += \ widgets/qwidgetanimator.cpp \ widgets/qtoolbararealayout.cpp \ widgets/qplaintextedit.cpp \ - widgets/qprintpreviewwidget.cpp - + widgets/qprintpreviewwidget.cpp \ + widgets/qactiontokeyeventmapper.cpp !embedded:mac { HEADERS += widgets/qmacnativewidget_mac.h \ @@ -160,3 +160,7 @@ wince*: { RC_FILE = widgets/qmenu_wince.rc !static: QMAKE_WRITE_DEFAULT_RC = 1 } + +symbian*: { + SOURCES += widgets/qmenu_symbian.cpp +} |