diff options
Diffstat (limited to 'src/gui/widgets')
29 files changed, 945 insertions, 63 deletions
diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index f6c1892..c72c36c 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -287,8 +287,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); @@ -485,7 +485,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; + } } /*! @@ -497,7 +502,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; + } } @@ -507,7 +517,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(); } @@ -531,7 +542,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 8011ed5..a54ba1c 100644 --- a/src/gui/widgets/qabstractscrollarea_p.h +++ b/src/gui/widgets/qabstractscrollarea_p.h @@ -99,7 +99,7 @@ public: inline bool viewportEvent(QEvent *event) { return q_func()->viewportEvent(event); } - QObject *viewportFilter; + QScopedPointer<QObject> viewportFilter; virtual void _q_gestureTriggered(); QPanGesture *panGesture; diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index 6865a56..19712d3 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 7fa26ae..bcc5c92 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -663,7 +663,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); @@ -694,6 +693,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 d8b9757..e65f27b 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..0e1e1bb --- /dev/null +++ b/src/gui/widgets/qactiontokeyeventmapper.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the 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 http://www.qtsoftware.com/contact. +** $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..57b81af --- /dev/null +++ b/src/gui/widgets/qactiontokeyeventmapper_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the 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 http://www.qtsoftware.com/contact. +** $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/qcalendarwidget.cpp b/src/gui/widgets/qcalendarwidget.cpp index 2586c56..7f29ec7 100644 --- a/src/gui/widgets/qcalendarwidget.cpp +++ b/src/gui/widgets/qcalendarwidget.cpp @@ -2142,14 +2142,11 @@ QSize QCalendarWidget::minimumSizeHint() const int end = 53; int rows = 7; int cols = 8; - int startRow = 0; - int startCol = 0; const int marginH = (style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1) * 2; if (horizontalHeaderFormat() == QCalendarWidget::NoHorizontalHeader) { rows = 6; - startRow = 1; } else { for (int i = 1; i <= 7; i++) { QFontMetrics fm(d->m_model->formatForCell(0, i).font()); @@ -2160,7 +2157,6 @@ QSize QCalendarWidget::minimumSizeHint() const if (verticalHeaderFormat() == QCalendarWidget::NoVerticalHeader) { cols = 7; - startCol = 1; } else { for (int i = 1; i <= 6; i++) { QFontMetrics fm(d->m_model->formatForCell(i, 0).font()); @@ -2527,13 +2523,6 @@ void QCalendarWidget::setDateRange(const QDate &min, const QDate &max) if (!min.isValid() || !max.isValid()) return; - QDate minimum = min; - QDate maximum = max; - if (min > max) { - minimum = max; - maximum = min; - } - QDate oldDate = d->m_model->m_date; d->m_model->setRange(min, max); d->yearEdit->setMinimum(d->m_model->m_minimumDate.year()); diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 097f3d0..c4f81d4 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -64,7 +64,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 @@ -629,6 +629,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()); } @@ -641,6 +644,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; @@ -1247,8 +1251,12 @@ QComboBox::~QComboBox() // ### check delegateparent and delete delegate if us? Q_D(QComboBox); - disconnect(d->model, SIGNAL(destroyed()), - this, SLOT(_q_modelDestroyed())); + QT_TRY { + disconnect(d->model, SIGNAL(destroyed()), + this, SLOT(_q_modelDestroyed())); + } QT_CATCH(...) { + ; // objects can't throw in destructor + } } /*! @@ -2454,6 +2462,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 cb76876..1533edb 100644 --- a/src/gui/widgets/qdatetimeedit.cpp +++ b/src/gui/widgets/qdatetimeedit.cpp @@ -1086,6 +1086,7 @@ void QDateTimeEdit::keyPressEvent(QKeyEvent *event) //hide cursor d->edit->d_func()->setCursorVisible(false); + d->edit->d_func()->control->setCursorBlinkPeriod(0); d->setSelected(0); } } @@ -1106,10 +1107,7 @@ void QDateTimeEdit::keyPressEvent(QKeyEvent *event) //hide cursor d->edit->d_func()->setCursorVisible(false); - if (d->edit->d_func()->cursorTimer > 0) - killTimer(d->edit->d_func()->cursorTimer); - d->edit->d_func()->cursorTimer = 0; - + d->edit->d_func()->control->setCursorBlinkPeriod(0); d->setSelected(0); oldCurrent = 0; } @@ -1122,23 +1120,25 @@ void QDateTimeEdit::keyPressEvent(QKeyEvent *event) case Qt::Key_Left: case Qt::Key_Right: if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) { + if ( #ifdef QT_KEYPAD_NAVIGATION - if (!QApplication::keypadNavigationEnabled() || !hasEditFocus()) { - select = false; - break; - } -#else - if (!(event->modifiers() & Qt::ControlModifier)) { + QApplication::keypadNavigationEnabled() && !hasEditFocus() + || !QApplication::keypadNavigationEnabled() && +#endif + !(event->modifiers() & Qt::ControlModifier)) { select = false; break; } #ifdef Q_WS_MAC - else { + else +#ifdef QT_KEYPAD_NAVIGATION + if (!QApplication::keypadNavigationEnabled()) +#endif + { select = (event->modifiers() & Qt::ShiftModifier); break; } #endif -#endif // QT_KEYPAD_NAVIGATION } // else fall through case Qt::Key_Backtab: @@ -2382,6 +2382,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 9f315fd..5b04616 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -509,7 +509,13 @@ void QLineEdit::setEchoMode(EchoMode mode) Q_D(QLineEdit); if (mode == (EchoMode)d->control->echoMode()) return; - setAttribute(Qt::WA_InputMethodEnabled, d->shouldEnableInputMethod()); + Qt::InputMethodHints imHints = inputMethodHints(); + if (mode == Password) { + imHints |= Qt::ImhHiddenText; + } else { + imHints &= ~Qt::ImhHiddenText; + } + setInputMethodHints(imHints); d->control->setEchoMode(mode); update(); #ifdef Q_WS_MAC @@ -1487,6 +1493,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 @@ -1649,6 +1662,15 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const return QVariant(text()); case Qt::ImCurrentSelection: return QVariant(selectedText()); + case Qt::ImMaximumTextLength: + return QVariant(maxLength()); + case Qt::ImAnchorPosition: + if (d->control->selectionStart() == d->control->selectionEnd()) + return QVariant(d->control->cursor()); + else if (d->control->selectionStart() == d->control->cursor()) + return QVariant(d->control->selectionEnd()); + else + return QVariant(d->control->selectionStart()); default: return QVariant(); } @@ -1667,6 +1689,8 @@ void QLineEdit::focusInEvent(QFocusEvent *e) d->control->moveCursor(d->control->nextMaskBlank(0)); else if (!d->control->hasSelectedText()) selectAll(); + } else if (e->reason() == Qt::MouseFocusReason) { + d->clickCausedFocus = 1; } #ifdef QT_KEYPAD_NAVIGATION if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && e->reason() == Qt::PopupFocusReason)){ diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index 976e31f..b21820c 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -76,7 +76,7 @@ public: QLineEditPrivate() : control(0), frame(1), contextMenuEnabled(1), cursorVisible(0), - dragEnabled(0), hscroll(0), vscroll(0), + dragEnabled(0), hscroll(0), vscroll(0), clickCausedFocus(0), alignment(Qt::AlignLeading | Qt::AlignVCenter), leftTextMargin(0), topTextMargin(0), rightTextMargin(0), bottomTextMargin(0) { @@ -110,6 +110,7 @@ public: uint contextMenuEnabled : 1; uint cursorVisible : 1; uint dragEnabled : 1; + uint clickCausedFocus : 1; int hscroll; int vscroll; uint alignment; diff --git a/src/gui/widgets/qmacnativewidget_mac.h b/src/gui/widgets/qmacnativewidget_mac.h index 6b6bee1..5c654b5 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 c51bed9..b75b5ea 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); + } } /*! @@ -1396,7 +1401,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 ccf81f8..1ba6fdc 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" @@ -565,8 +566,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 @@ -1774,6 +1781,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->actions) + if (action->isEnabled()) { + atAction = action; + break; + } + } + d->currentAction = atAction; + } +#endif if (d->ncols > 1) { pos.setY(screen.top()+desktopFrame); } else if (atAction) { @@ -1901,6 +1924,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 } /*! @@ -2559,6 +2585,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) { @@ -2834,6 +2861,16 @@ void QMenu::actionEvent(QActionEvent *e) d->wce_menu->syncAction(e->action()); #endif +#ifdef Q_WS_S60 + 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->updateActionRects(); resize(sizeHint()); diff --git a/src/gui/widgets/qmenu.h b/src/gui/widgets/qmenu.h index c8be540..41890c4 100644 --- a/src/gui/widgets/qmenu.h +++ b/src/gui/widgets/qmenu.h @@ -52,11 +52,19 @@ #endif QT_BEGIN_HEADER +#ifdef Q_WS_S60 + class CEikMenuPane; +#endif QT_BEGIN_NAMESPACE QT_MODULE(Gui) +#ifdef Q_WS_S60 + 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 8697771..0218dc7 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_WS_S60 +class CEikMenuPane; +#endif QT_BEGIN_NAMESPACE #ifndef QT_NO_MENU @@ -120,6 +123,15 @@ struct QWceMenuAction { QWceMenuAction() : menuHandle(0), command(0) {} }; #endif +#ifdef Q_WS_S60 +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_WS_S60 + ,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_WS_S60 + delete symbian_menu; +#endif + } void init(); @@ -319,7 +338,28 @@ public: HMENU wceMenu(bool create = false); QAction* wceCommands(uint command); #endif - +#if defined(Q_WS_S60) + 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..b0cd7c8 --- /dev/null +++ b/src/gui/widgets/qmenu_symbian.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (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 http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmenu.h" +#include "qapplication.h" +#include "qevent.h" +#include "qstyle.h" +#include "qdebug.h" +#include "qwidgetaction.h" +#include <private/qapplication_p.h> +#include <private/qmenu_p.h> +#include <private/qmenubar_p.h> +#include <qt_s60_p.h> +#include <QtCore/qlibrary.h> + +#ifdef Q_WS_S60 +#include <eikmenub.h> +#include <eikmenup.h> +#include <eikaufty.h> +#include <eikbtgpc.h> +#include <avkon.rsg> +#endif + +#if !defined(QT_NO_MENUBAR) && defined(Q_WS_S60) + +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) + QT_TRAP_THROWING(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) + QT_TRAP_THROWING(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 389b65f..a0a2f57 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -741,6 +741,12 @@ void QMenuBarPrivate::init() q->hide(); } #endif +#ifdef Q_WS_S60 + symbianCreateMenuBar(q->parentWidget()); + if(symbian_menubar) + q->hide(); +#endif + q->setBackgroundRole(QPalette::Button); oldWindow = oldParent = 0; #ifdef QT3_SUPPORT @@ -812,6 +818,10 @@ QMenuBar::~QMenuBar() if (qt_wince_is_mobile()) d->wceDestroyMenuBar(); #endif +#ifdef Q_WS_S60 + Q_D(QMenuBar); + d->symbianDestroyMenuBar(); +#endif } /*! @@ -1067,6 +1077,12 @@ void QMenuBar::setVisible(bool visible) if (isNativeMenuBar()) return; #endif +#ifdef Q_WS_S60 + Q_D(QMenuBar); + if(d->symbian_menubar) + return; +#endif + QWidget::setVisible(visible); } @@ -1279,6 +1295,17 @@ void QMenuBar::actionEvent(QActionEvent *e) nativeMenuBar->syncAction(e->action()); } #endif +#ifdef Q_WS_S60 + 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())); @@ -1365,6 +1392,11 @@ void QMenuBarPrivate::handleReparent() if (qt_wince_is_mobile() && wce_menubar) wce_menubar->rebuild(); #endif +#ifdef Q_WS_S60 + if (symbian_menubar) + symbian_menubar->rebuild(); +#endif + } #ifdef QT3_SUPPORT @@ -1599,7 +1631,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_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); #else const bool as_gui_menubar = true; @@ -1655,7 +1687,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_WS_S60) const bool as_gui_menubar = !isNativeMenuBar(); #else const bool as_gui_menubar = true; @@ -1713,7 +1745,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_WS_S60) 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 b890b7b..004562f 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_WS_S60 +class CCoeControl; +class CEikMenuBar; +#endif +#endif + QT_BEGIN_NAMESPACE #ifndef QT_NO_MENUBAR @@ -82,7 +89,11 @@ public: #ifdef Q_WS_WINCE , wce_menubar(0), wceClassicMenu(false) #endif - { } +#ifdef Q_WS_S60 + , symbian_menubar(0) +#endif + + { } ~QMenuBarPrivate() { #ifdef Q_WS_MAC @@ -91,6 +102,9 @@ public: #ifdef Q_WS_WINCE delete wce_menubar; #endif +#ifdef Q_WS_S60 + delete symbian_menubar; +#endif } void init(); @@ -225,6 +239,35 @@ public: void wceRefresh(); bool wceEmitSignals(QList<QWceMenuAction*> actions, uint command); #endif +#ifdef Q_WS_S60 + 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 7d0228f..521b5fc 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 82026d4..7d9d2b5 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -74,6 +74,11 @@ QT_BEGIN_NAMESPACE +static inline bool shouldEnableInputMethod(QPlainTextEdit *plaintextedit) +{ + return !plaintextedit->isReadOnly(); +} + class QPlainTextDocumentLayoutPrivate : public QAbstractTextDocumentLayoutPrivate { Q_DECLARE_PUBLIC(QPlainTextDocumentLayout) @@ -721,7 +726,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; @@ -1925,6 +1931,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 @@ -2059,6 +2072,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); } @@ -2325,7 +2341,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 ae584e0..739fd89 100644 --- a/src/gui/widgets/qplaintextedit_p.h +++ b/src/gui/widgets/qplaintextedit_p.h @@ -92,7 +92,10 @@ public: return r; } inline QRectF cursorRect() { return cursorRect(textCursor()); } - void ensureCursorVisible() { textEdit->ensureCursorVisible(); } + void ensureCursorVisible() { + textEdit->ensureCursorVisible(); + emit microFocusChanged(); + } QPlainTextEdit *textEdit; @@ -149,6 +152,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 fb1b6ea..f5f7e73 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 99b14bf..d74bf93 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 7441df4..193b15c 100644 --- a/src/gui/widgets/qspinbox.cpp +++ b/src/gui/widgets/qspinbox.cpp @@ -78,6 +78,8 @@ public: QChar thousand; inline void init() { + Q_Q(QSpinBox); + q->setInputMethodHints(Qt::ImhDigitsOnly); setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem); } }; @@ -98,6 +100,11 @@ public: // variables int decimals; QChar delimiter, thousand; + + inline void init() { + Q_Q(QDoubleSpinBox); + q->setInputMethodHints(Qt::ImhFormattedNumbersOnly); + } }; @@ -599,6 +606,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 0a41d74..57f43c6 100644 --- a/src/gui/widgets/qtextedit.cpp +++ b/src/gui/widgets/qtextedit.cpp @@ -76,6 +76,10 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_TEXTEDIT +static inline bool shouldEnableInputMethod(QTextEdit *textedit) +{ + return !textedit->isReadOnly(); +} class QTextEditControl : public QTextControl { @@ -107,7 +111,8 @@ QTextEditPrivate::QTextEditPrivate() : control(0), autoFormatting(QTextEdit::AutoNone), tabChangesFocus(false), lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0), - wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), textFormat(Qt::AutoText) + wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), clickCausedFocus(0), + textFormat(Qt::AutoText) { ignoreAutomaticScrollbarAdjustment = false; preferRichText = false; @@ -1564,6 +1569,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 @@ -1700,6 +1711,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); } @@ -2064,7 +2078,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 3d14af6..85b6f7c 100644 --- a/src/gui/widgets/qtextedit_p.h +++ b/src/gui/widgets/qtextedit_p.h @@ -122,6 +122,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 8f24fac..4567902 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -81,8 +81,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 \ @@ -143,8 +143,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 \ @@ -165,3 +165,7 @@ wince*: { RC_FILE = widgets/qmenu_wince.rc !static: QMAKE_WRITE_DEFAULT_RC = 1 } + +symbian*: { + SOURCES += widgets/qmenu_symbian.cpp +} |