1 /*
2 * This file is part of the popup menu implementation for <select> elements in WebCore.
3 *
4 * Copyright 2009, The Android Open Source Project
5 * Copyright (C) 2006 Apple Computer, Inc.
6 * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 */
24
25 #include "config.h"
26 #include "PopupMenuAndroid.h"
27
28 #include "IntRect.h"
29 #include "PopupMenuClient.h"
30 #include "SkTDArray.h"
31 #include "WebViewCore.h"
32
33 using namespace WebCore;
34
35 class PopupReply : public android::WebCoreReply {
36 public:
PopupReply(const IntRect & rect,android::WebViewCore * view,ListPopupMenuClient * client)37 PopupReply(const IntRect& rect, android::WebViewCore* view, ListPopupMenuClient* client)
38 : m_rect(rect)
39 , m_viewImpl(view)
40 , m_popupClient(client)
41 {
42 }
43
~PopupReply()44 virtual ~PopupReply() {}
45
replyInt(int value)46 virtual void replyInt(int value)
47 {
48 if (m_popupClient) {
49 m_popupClient->popupDidHide();
50 // -2 is a special value signaling that the popup was canceled.
51 if (-2 == value)
52 return;
53 m_popupClient->valueChanged(value, true);
54 }
55 if (m_viewImpl)
56 m_viewImpl->contentInvalidate(m_rect);
57 }
58
replyIntArray(const int * values,int count)59 virtual void replyIntArray(const int* values, int count)
60 {
61 if (m_popupClient) {
62 m_popupClient->popupDidHide();
63 if (0 == count) {
64 m_popupClient->valueChanged(-1, true);
65 } else {
66 for (int i = 0; i < count; i++) {
67 m_popupClient->listBoxSelectItem(values[i],
68 i != 0 /* allowMultiplySelection */,
69 false /* shift */,
70 i == count - 1 /* fireOnChangeNow */);
71 }
72 }
73 }
74 if (m_viewImpl)
75 m_viewImpl->contentInvalidate(m_rect);
76 }
77
disconnectClient()78 void disconnectClient()
79 {
80 m_popupClient = 0;
81 m_viewImpl = 0;
82 }
83 private:
84 IntRect m_rect;
85 // FIXME: Do not need this if we handle ChromeClientAndroid::formStateDidChange
86 android::WebViewCore* m_viewImpl;
87 ListPopupMenuClient* m_popupClient;
88 };
89
90 namespace WebCore {
91
PopupMenuAndroid(ListPopupMenuClient * menuList)92 PopupMenuAndroid::PopupMenuAndroid(ListPopupMenuClient* menuList)
93 : m_popupClient(menuList)
94 , m_reply(0)
95 {
96 }
~PopupMenuAndroid()97 PopupMenuAndroid::~PopupMenuAndroid()
98 {
99 disconnectClient();
100 }
101
disconnectClient()102 void PopupMenuAndroid::disconnectClient()
103 {
104 m_popupClient = 0;
105 if (m_reply) {
106 m_reply->disconnectClient();
107 Release(m_reply);
108 m_reply = 0;
109 }
110 }
111
112 // Convert a WTF::String into an array of characters where the first
113 // character represents the length, for easy conversion to java.
stringConverter(const WTF::String & text)114 static uint16_t* stringConverter(const WTF::String& text)
115 {
116 size_t length = text.length();
117 uint16_t* itemName = new uint16_t[length+1];
118 itemName[0] = (uint16_t)length;
119 uint16_t* firstChar = &(itemName[1]);
120 memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
121 return itemName;
122 }
123
show(const IntRect & rect,FrameView * frameView,int)124 void PopupMenuAndroid::show(const IntRect& rect, FrameView* frameView, int)
125 {
126 android::WebViewCore* viewImpl = android::WebViewCore::getWebViewCore(frameView);
127 m_reply = new PopupReply(rect, viewImpl, m_popupClient);
128 Retain(m_reply);
129
130 SkTDArray<const uint16_t*> names;
131 // Possible values for enabledArray. Keep in Sync with values in
132 // InvokeListBox.Container in WebView.java
133 enum OptionStatus {
134 OPTGROUP = -1,
135 OPTION_DISABLED = 0,
136 OPTION_ENABLED = 1,
137 };
138 SkTDArray<int> enabledArray;
139 SkTDArray<int> selectedArray;
140 int size = m_popupClient->listSize();
141 bool multiple = m_popupClient->multiple();
142 for (int i = 0; i < size; i++) {
143 *names.append() = stringConverter(m_popupClient->itemText(i));
144 if (m_popupClient->itemIsSeparator(i)) {
145 *enabledArray.append() = OPTION_DISABLED;
146 } else if (m_popupClient->itemIsLabel(i)) {
147 *enabledArray.append() = OPTGROUP;
148 } else {
149 // Must be an Option
150 *enabledArray.append() = m_popupClient->itemIsEnabled(i)
151 ? OPTION_ENABLED : OPTION_DISABLED;
152 if (multiple && m_popupClient->itemIsSelected(i))
153 *selectedArray.append() = i;
154 }
155 }
156
157 viewImpl->listBoxRequest(m_reply,
158 names.begin(),
159 size,
160 enabledArray.begin(),
161 enabledArray.count(),
162 multiple,
163 selectedArray.begin(),
164 multiple ? selectedArray.count() : m_popupClient->selectedIndex());
165 }
166
167 } // namespace WebCore
168