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