Home | History | Annotate | Download | only in WebCoreSupport
      1 /*
      2  * Copyright (C) 2010 Girish Ramakrishnan <girish (at) forwardbias.in>
      3  * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  *
     20  */
     21 #include "config.h"
     22 #include "QtFallbackWebPopup.h"
     23 
     24 #ifndef QT_NO_COMBOBOX
     25 
     26 #include "ChromeClientQt.h"
     27 #include "QWebPageClient.h"
     28 #include "qgraphicswebview.h"
     29 #include <QAbstractItemView>
     30 #include <QApplication>
     31 #include <QGraphicsProxyWidget>
     32 #include <QGraphicsScene>
     33 #include <QGraphicsView>
     34 #include <QInputContext>
     35 #include <QMouseEvent>
     36 #include <QStandardItemModel>
     37 
     38 #if ENABLE(SYMBIAN_DIALOG_PROVIDERS)
     39 #include <BrCtlDialogsProvider.h>
     40 #include <BrowserDialogsProvider.h> // S60 platform private header file
     41 #include <e32base.h>
     42 #endif
     43 
     44 namespace WebCore {
     45 
     46 QtFallbackWebPopupCombo::QtFallbackWebPopupCombo(QtFallbackWebPopup& ownerPopup)
     47     : m_ownerPopup(ownerPopup)
     48 {
     49     // Install an event filter on the view inside the combo box popup to make sure we know
     50     // when the popup got closed. E.g. QComboBox::hidePopup() won't be called when the popup
     51     // is closed by a mouse wheel event outside its window.
     52     view()->installEventFilter(this);
     53 }
     54 
     55 void QtFallbackWebPopupCombo::showPopup()
     56 {
     57     QComboBox::showPopup();
     58     m_ownerPopup.m_popupVisible = true;
     59 }
     60 
     61 void QtFallbackWebPopupCombo::hidePopup()
     62 {
     63 #ifndef QT_NO_IM
     64     QWidget* activeFocus = QApplication::focusWidget();
     65     if (activeFocus && activeFocus == QComboBox::view()
     66         && activeFocus->testAttribute(Qt::WA_InputMethodEnabled)) {
     67         QInputContext* qic = activeFocus->inputContext();
     68         if (qic) {
     69             qic->reset();
     70             qic->setFocusWidget(0);
     71         }
     72     }
     73 #endif // QT_NO_IM
     74 
     75     QComboBox::hidePopup();
     76 
     77     if (!m_ownerPopup.m_popupVisible)
     78         return;
     79 
     80     m_ownerPopup.m_popupVisible = false;
     81     emit m_ownerPopup.didHide();
     82     m_ownerPopup.destroyPopup();
     83 }
     84 
     85 bool QtFallbackWebPopupCombo::eventFilter(QObject* watched, QEvent* event)
     86 {
     87     Q_ASSERT(watched == view());
     88 
     89     if (event->type() == QEvent::Show && !m_ownerPopup.m_popupVisible)
     90         showPopup();
     91     else if (event->type() == QEvent::Hide && m_ownerPopup.m_popupVisible)
     92         hidePopup();
     93 
     94     return false;
     95 }
     96 
     97 // QtFallbackWebPopup
     98 
     99 QtFallbackWebPopup::QtFallbackWebPopup(const ChromeClientQt* chromeClient)
    100     : m_popupVisible(false)
    101     , m_combo(0)
    102     , m_chromeClient(chromeClient)
    103 {
    104 }
    105 
    106 QtFallbackWebPopup::~QtFallbackWebPopup()
    107 {
    108     destroyPopup();
    109 }
    110 
    111 void QtFallbackWebPopup::show(const QWebSelectData& data)
    112 {
    113     if (!pageClient())
    114         return;
    115 
    116 #if ENABLE(SYMBIAN_DIALOG_PROVIDERS)
    117     TRAP_IGNORE(showS60BrowserDialog());
    118 #else
    119 
    120     destroyPopup();
    121     m_combo = new QtFallbackWebPopupCombo(*this);
    122     connect(m_combo, SIGNAL(activated(int)),
    123             SLOT(activeChanged(int)), Qt::QueuedConnection);
    124 
    125     populate(data);
    126 
    127     QColor backgroundColor = data.backgroundColor();
    128     QColor foregroundColor = data.foregroundColor();
    129 
    130     QPalette palette = m_combo->palette();
    131     if (backgroundColor.isValid())
    132         palette.setColor(QPalette::Background, backgroundColor);
    133     if (foregroundColor.isValid())
    134         palette.setColor(QPalette::Foreground, foregroundColor);
    135     m_combo->setPalette(palette);
    136 
    137 
    138     QRect rect = geometry();
    139     if (QGraphicsWebView *webView = qobject_cast<QGraphicsWebView*>(pageClient()->pluginParent())) {
    140         QGraphicsProxyWidget* proxy = new QGraphicsProxyWidget(webView);
    141         proxy->setWidget(m_combo);
    142         proxy->setGeometry(rect);
    143     } else {
    144         m_combo->setParent(pageClient()->ownerWidget());
    145         m_combo->setGeometry(QRect(rect.left(), rect.top(),
    146                                rect.width(), m_combo->sizeHint().height()));
    147 
    148     }
    149 
    150     QMouseEvent event(QEvent::MouseButtonPress, QCursor::pos(), Qt::LeftButton,
    151                       Qt::LeftButton, Qt::NoModifier);
    152     QCoreApplication::sendEvent(m_combo, &event);
    153 #endif
    154 }
    155 
    156 #if ENABLE(SYMBIAN_DIALOG_PROVIDERS)
    157 
    158 static void ResetAndDestroy(TAny* aPtr)
    159 {
    160     RPointerArray<HBufC>* items = reinterpret_cast<RPointerArray<HBufC>* >(aPtr);
    161     items->ResetAndDestroy();
    162 }
    163 
    164 void QtFallbackWebPopup::showS60BrowserDialog()
    165 {
    166     static MBrCtlDialogsProvider* dialogs = CBrowserDialogsProvider::NewL(0);
    167     if (!dialogs)
    168         return;
    169 
    170     int size = itemCount();
    171     CArrayFix<TBrCtlSelectOptionData>* options = new CArrayFixFlat<TBrCtlSelectOptionData>(qMax(1, size));
    172     RPointerArray<HBufC> items(qMax(1, size));
    173     CleanupStack::PushL(TCleanupItem(&ResetAndDestroy, &items));
    174 
    175     for (int i = 0; i < size; i++) {
    176         if (itemType(i) == Separator) {
    177             TBrCtlSelectOptionData data(_L("----------"), false, false, false);
    178             options->AppendL(data);
    179         } else {
    180             HBufC16* itemStr = HBufC16::NewL(itemText(i).length());
    181             itemStr->Des().Copy((const TUint16*)itemText(i).utf16(), itemText(i).length());
    182             CleanupStack::PushL(itemStr);
    183             TBrCtlSelectOptionData data(*itemStr, i == currentIndex(), false, itemIsEnabled(i));
    184             options->AppendL(data);
    185             items.AppendL(itemStr);
    186             CleanupStack::Pop();
    187         }
    188     }
    189 
    190     dialogs->DialogSelectOptionL(KNullDesC(), (TBrCtlSelectOptionType)(ESelectTypeSingle | ESelectTypeWithFindPane), *options);
    191 
    192     CleanupStack::PopAndDestroy(&items);
    193 
    194     int newIndex;
    195     for (newIndex = 0; newIndex < options->Count() && !options->At(newIndex).IsSelected(); newIndex++) {}
    196     if (newIndex == options->Count())
    197         newIndex = currentIndex();
    198 
    199     m_popupVisible = false;
    200     popupDidHide();
    201 
    202     if (currentIndex() != newIndex && newIndex >= 0)
    203         valueChanged(newIndex);
    204 
    205     delete options;
    206 }
    207 #endif
    208 
    209 void QtFallbackWebPopup::hide()
    210 {
    211     // Destroying the QComboBox here cause problems if the popup is in the
    212     // middle of its show animation. Instead we rely on the fact that the
    213     // Qt::Popup window will hide itself on mouse events outside its window.
    214 }
    215 
    216 void QtFallbackWebPopup::destroyPopup()
    217 {
    218     if (m_combo) {
    219         m_combo->deleteLater();
    220         m_combo = 0;
    221     }
    222 }
    223 
    224 void QtFallbackWebPopup::populate(const QWebSelectData& data)
    225 {
    226     QStandardItemModel* model = qobject_cast<QStandardItemModel*>(m_combo->model());
    227     Q_ASSERT(model);
    228 
    229 #if !defined(Q_OS_SYMBIAN)
    230     m_combo->setFont(font());
    231 #endif
    232 
    233     int currentIndex = -1;
    234     for (int i = 0; i < data.itemCount(); ++i) {
    235         switch (data.itemType(i)) {
    236         case QWebSelectData::Separator:
    237             m_combo->insertSeparator(i);
    238             break;
    239         case QWebSelectData::Group:
    240             m_combo->insertItem(i, data.itemText(i));
    241             model->item(i)->setEnabled(false);
    242             break;
    243         case QWebSelectData::Option:
    244             m_combo->insertItem(i, data.itemText(i));
    245             model->item(i)->setEnabled(data.itemIsEnabled(i));
    246 #ifndef QT_NO_TOOLTIP
    247             model->item(i)->setToolTip(data.itemToolTip(i));
    248 #endif
    249             model->item(i)->setBackground(data.itemBackgroundColor(i));
    250             model->item(i)->setForeground(data.itemForegroundColor(i));
    251             if (data.itemIsSelected(i))
    252                 currentIndex = i;
    253             break;
    254         }
    255     }
    256 
    257     if (currentIndex >= 0)
    258         m_combo->setCurrentIndex(currentIndex);
    259 }
    260 
    261 void QtFallbackWebPopup::activeChanged(int index)
    262 {
    263     if (index < 0)
    264         return;
    265 
    266     emit selectItem(index, false, false);
    267 }
    268 
    269 QWebPageClient* QtFallbackWebPopup::pageClient() const
    270 {
    271     return m_chromeClient->platformPageClient();
    272 }
    273 
    274 }
    275 
    276 #endif // QT_NO_COMBOBOX
    277