Home | History | Annotate | Download | only in android
      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