1 /*
2 * Copyright (C) 2010 Girish Ramakrishnan <girish@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
QtFallbackWebPopupCombo(QtFallbackWebPopup & ownerPopup)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
showPopup()55 void QtFallbackWebPopupCombo::showPopup()
56 {
57 QComboBox::showPopup();
58 m_ownerPopup.m_popupVisible = true;
59 }
60
hidePopup()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
eventFilter(QObject * watched,QEvent * event)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
QtFallbackWebPopup(const ChromeClientQt * chromeClient)99 QtFallbackWebPopup::QtFallbackWebPopup(const ChromeClientQt* chromeClient)
100 : m_popupVisible(false)
101 , m_combo(0)
102 , m_chromeClient(chromeClient)
103 {
104 }
105
~QtFallbackWebPopup()106 QtFallbackWebPopup::~QtFallbackWebPopup()
107 {
108 destroyPopup();
109 }
110
show(const QWebSelectData & data)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
ResetAndDestroy(TAny * aPtr)158 static void ResetAndDestroy(TAny* aPtr)
159 {
160 RPointerArray<HBufC>* items = reinterpret_cast<RPointerArray<HBufC>* >(aPtr);
161 items->ResetAndDestroy();
162 }
163
showS60BrowserDialog()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
hide()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
destroyPopup()216 void QtFallbackWebPopup::destroyPopup()
217 {
218 if (m_combo) {
219 m_combo->deleteLater();
220 m_combo = 0;
221 }
222 }
223
populate(const QWebSelectData & data)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
activeChanged(int index)261 void QtFallbackWebPopup::activeChanged(int index)
262 {
263 if (index < 0)
264 return;
265
266 emit selectItem(index, false, false);
267 }
268
pageClient() const269 QWebPageClient* QtFallbackWebPopup::pageClient() const
270 {
271 return m_chromeClient->platformPageClient();
272 }
273
274 }
275
276 #endif // QT_NO_COMBOBOX
277