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 (at) 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: 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 44 virtual ~PopupReply() {} 45 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 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 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 92 PopupMenuAndroid::PopupMenuAndroid(ListPopupMenuClient* menuList) 93 : m_popupClient(menuList) 94 , m_reply(0) 95 { 96 } 97 PopupMenuAndroid::~PopupMenuAndroid() 98 { 99 disconnectClient(); 100 } 101 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. 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 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