| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. | 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 | 66 |
| 67 static const int kMaxVisibleRows = 20; | 67 static const int kMaxVisibleRows = 20; |
| 68 static const int kMaxHeight = 500; | 68 static const int kMaxHeight = 500; |
| 69 static const int kBorderSize = 1; | 69 static const int kBorderSize = 1; |
| 70 static const TimeStamp kTypeAheadTimeoutMs = 1000; | 70 static const TimeStamp kTypeAheadTimeoutMs = 1000; |
| 71 | 71 |
| 72 // This class uses WebCore code to paint and handle events for a drop-down list | 72 // This class uses WebCore code to paint and handle events for a drop-down list |
| 73 // box ("combobox" on Windows). | 73 // box ("combobox" on Windows). |
| 74 class PopupListBox : public FramelessScrollView, public RefCounted<PopupListBox>
{ | 74 class PopupListBox : public FramelessScrollView, public RefCounted<PopupListBox>
{ |
| 75 public: | 75 public: |
| 76 static PassRefPtr<PopupListBox> create(PopupMenuClient* client) |
| 77 { |
| 78 return adoptRef(new PopupListBox(client)); |
| 79 } |
| 80 |
| 76 // FramelessScrollView | 81 // FramelessScrollView |
| 77 virtual void paint(GraphicsContext*, const IntRect&); | 82 virtual void paint(GraphicsContext*, const IntRect&); |
| 78 virtual bool handleMouseDownEvent(const PlatformMouseEvent&); | 83 virtual bool handleMouseDownEvent(const PlatformMouseEvent&); |
| 79 virtual bool handleMouseMoveEvent(const PlatformMouseEvent&); | 84 virtual bool handleMouseMoveEvent(const PlatformMouseEvent&); |
| 80 virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&); | 85 virtual bool handleMouseReleaseEvent(const PlatformMouseEvent&); |
| 81 virtual bool handleWheelEvent(const PlatformWheelEvent&); | 86 virtual bool handleWheelEvent(const PlatformWheelEvent&); |
| 82 virtual bool handleKeyEvent(const PlatformKeyboardEvent&); | 87 virtual bool handleKeyEvent(const PlatformKeyboardEvent&); |
| 83 | 88 |
| 84 // ScrollView | 89 // ScrollView |
| 85 virtual HostWindow* hostWindow() const; | 90 virtual HostWindow* hostWindow() const; |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 // PopupContainer implementation | 321 // PopupContainer implementation |
| 317 | 322 |
| 318 // static | 323 // static |
| 319 PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client, | 324 PassRefPtr<PopupContainer> PopupContainer::create(PopupMenuClient* client, |
| 320 bool focusOnShow) | 325 bool focusOnShow) |
| 321 { | 326 { |
| 322 return adoptRef(new PopupContainer(client, focusOnShow)); | 327 return adoptRef(new PopupContainer(client, focusOnShow)); |
| 323 } | 328 } |
| 324 | 329 |
| 325 PopupContainer::PopupContainer(PopupMenuClient* client, bool focusOnShow) | 330 PopupContainer::PopupContainer(PopupMenuClient* client, bool focusOnShow) |
| 326 : m_listBox(new PopupListBox(client)), | 331 : m_listBox(PopupListBox::create(client)) |
| 327 m_focusOnShow(focusOnShow) | 332 , m_focusOnShow(focusOnShow) |
| 328 { | 333 { |
| 329 // FrameViews are created with a refcount of 1 so it needs releasing after w
e | |
| 330 // assign it to a RefPtr. | |
| 331 m_listBox->deref(); | |
| 332 | |
| 333 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); | 334 setScrollbarModes(ScrollbarAlwaysOff, ScrollbarAlwaysOff); |
| 334 } | 335 } |
| 335 | 336 |
| 336 PopupContainer::~PopupContainer() | 337 PopupContainer::~PopupContainer() |
| 337 { | 338 { |
| 338 if (m_listBox) | 339 if (m_listBox) |
| 339 removeChild(m_listBox.get()); | 340 removeChild(m_listBox.get()); |
| 340 } | 341 } |
| 341 | 342 |
| 342 void PopupContainer::showPopup(FrameView* view) | 343 void PopupContainer::showPopup(FrameView* view) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 354 // If the popup would extend past the bottom of the screen, open upwards | 355 // If the popup would extend past the bottom of the screen, open upwards |
| 355 // instead. | 356 // instead. |
| 356 FloatRect screen = screenRect(view); | 357 FloatRect screen = screenRect(view); |
| 357 IntRect widgetRect = chromeClient->windowToScreen(frameRect()); | 358 IntRect widgetRect = chromeClient->windowToScreen(frameRect()); |
| 358 if (widgetRect.bottom() > static_cast<int>(screen.bottom())) | 359 if (widgetRect.bottom() > static_cast<int>(screen.bottom())) |
| 359 widgetRect.move(0, -(widgetRect.height() + selectHeight)); | 360 widgetRect.move(0, -(widgetRect.height() + selectHeight)); |
| 360 | 361 |
| 361 chromeClient->popupOpened(this, widgetRect, m_focusOnShow); | 362 chromeClient->popupOpened(this, widgetRect, m_focusOnShow); |
| 362 } | 363 } |
| 363 | 364 |
| 364 // Must get called after we have a client and containingWindow. | 365 if (!m_listBox->parent()) |
| 365 addChild(m_listBox.get()); | 366 addChild(m_listBox.get()); |
| 366 | 367 |
| 367 // Enable scrollbars after the listbox is inserted into the hierarchy, so | 368 // Enable scrollbars after the listbox is inserted into the hierarchy, |
| 368 // it has a proper WidgetClient. | 369 // so it has a proper WidgetClient. |
| 369 m_listBox->setVerticalScrollbarMode(ScrollbarAuto); | 370 m_listBox->setVerticalScrollbarMode(ScrollbarAuto); |
| 370 | 371 |
| 371 m_listBox->scrollToRevealSelection(); | 372 m_listBox->scrollToRevealSelection(); |
| 372 | 373 |
| 373 invalidate(); | 374 invalidate(); |
| 374 } | 375 } |
| 375 | 376 |
| 376 void PopupContainer::hidePopup() | 377 void PopupContainer::hidePopup() |
| 377 { | 378 { |
| 378 invalidate(); | |
| 379 | |
| 380 m_listBox->disconnectClient(); | |
| 381 removeChild(m_listBox.get()); | |
| 382 m_listBox = 0; | |
| 383 | |
| 384 if (client()) | 379 if (client()) |
| 385 client()->popupClosed(this); | 380 client()->popupClosed(this); |
| 386 } | 381 } |
| 387 | 382 |
| 388 void PopupContainer::layout() | 383 void PopupContainer::layout() |
| 389 { | 384 { |
| 390 m_listBox->layout(); | 385 m_listBox->layout(); |
| 391 | 386 |
| 392 // Place the listbox within our border. | 387 // Place the listbox within our border. |
| 393 m_listBox->move(kBorderSize, kBorderSize); | 388 m_listBox->move(kBorderSize, kBorderSize); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 849 | 844 |
| 850 return itemFont; | 845 return itemFont; |
| 851 } | 846 } |
| 852 | 847 |
| 853 void PopupListBox::abandon() | 848 void PopupListBox::abandon() |
| 854 { | 849 { |
| 855 RefPtr<PopupListBox> keepAlive(this); | 850 RefPtr<PopupListBox> keepAlive(this); |
| 856 | 851 |
| 857 m_selectedIndex = m_originalIndex; | 852 m_selectedIndex = m_originalIndex; |
| 858 | 853 |
| 854 m_popupClient->hidePopup(); |
| 855 |
| 859 if (m_willAcceptOnAbandon) | 856 if (m_willAcceptOnAbandon) |
| 860 m_popupClient->valueChanged(m_selectedIndex); | 857 m_popupClient->valueChanged(m_selectedIndex); |
| 861 | |
| 862 // valueChanged may have torn down the popup! | |
| 863 if (m_popupClient) | |
| 864 m_popupClient->hidePopup(); | |
| 865 } | 858 } |
| 866 | 859 |
| 867 int PopupListBox::pointToRowIndex(const IntPoint& point) | 860 int PopupListBox::pointToRowIndex(const IntPoint& point) |
| 868 { | 861 { |
| 869 int y = scrollY() + point.y(); | 862 int y = scrollY() + point.y(); |
| 870 | 863 |
| 871 // FIXME: binary search if perf matters. | 864 // FIXME: binary search if perf matters. |
| 872 for (int i = 0; i < numItems(); ++i) { | 865 for (int i = 0; i < numItems(); ++i) { |
| 873 if (y < m_items[i]->y) | 866 if (y < m_items[i]->y) |
| 874 return i-1; | 867 return i-1; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 886 ASSERT(index >= -1 && index < numItems()); | 879 ASSERT(index >= -1 && index < numItems()); |
| 887 if (index == -1 && m_popupClient) { | 880 if (index == -1 && m_popupClient) { |
| 888 // Enter pressed with no selection, just close the popup. | 881 // Enter pressed with no selection, just close the popup. |
| 889 m_popupClient->hidePopup(); | 882 m_popupClient->hidePopup(); |
| 890 return; | 883 return; |
| 891 } | 884 } |
| 892 | 885 |
| 893 if (isSelectableItem(index)) { | 886 if (isSelectableItem(index)) { |
| 894 RefPtr<PopupListBox> keepAlive(this); | 887 RefPtr<PopupListBox> keepAlive(this); |
| 895 | 888 |
| 896 // Tell the <select> PopupMenuClient what index was selected, and hide o
urself. | 889 // Hide ourselves first since valueChanged may have numerous side-effect
s. |
| 890 m_popupClient->hidePopup(); |
| 891 |
| 892 // Tell the <select> PopupMenuClient what index was selected. |
| 897 m_popupClient->valueChanged(index); | 893 m_popupClient->valueChanged(index); |
| 898 | |
| 899 // valueChanged may have torn down the popup! | |
| 900 if (m_popupClient) | |
| 901 m_popupClient->hidePopup(); | |
| 902 } | 894 } |
| 903 } | 895 } |
| 904 | 896 |
| 905 void PopupListBox::selectIndex(int index) | 897 void PopupListBox::selectIndex(int index) |
| 906 { | 898 { |
| 907 ASSERT(index >= 0 && index < numItems()); | 899 ASSERT(index >= 0 && index < numItems()); |
| 908 | 900 |
| 909 if (index != m_selectedIndex && isSelectableItem(index)) { | 901 if (index != m_selectedIndex && isSelectableItem(index)) { |
| 910 invalidateRow(m_selectedIndex); | 902 invalidateRow(m_selectedIndex); |
| 911 m_selectedIndex = index; | 903 m_selectedIndex = index; |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 { | 1142 { |
| 1151 } | 1143 } |
| 1152 | 1144 |
| 1153 PopupMenu::~PopupMenu() | 1145 PopupMenu::~PopupMenu() |
| 1154 { | 1146 { |
| 1155 hide(); | 1147 hide(); |
| 1156 } | 1148 } |
| 1157 | 1149 |
| 1158 void PopupMenu::show(const IntRect& r, FrameView* v, int index) | 1150 void PopupMenu::show(const IntRect& r, FrameView* v, int index) |
| 1159 { | 1151 { |
| 1160 p.popup = PopupContainer::create(client(), true); | 1152 if (!p.popup) |
| 1153 p.popup = PopupContainer::create(client(), true); |
| 1161 p.popup->show(r, v, index); | 1154 p.popup->show(r, v, index); |
| 1162 } | 1155 } |
| 1163 | 1156 |
| 1164 void PopupMenu::hide() | 1157 void PopupMenu::hide() |
| 1165 { | 1158 { |
| 1166 if (p.popup) { | 1159 if (p.popup) |
| 1167 p.popup->hidePopup(); | 1160 p.popup->hidePopup(); |
| 1168 p.popup = 0; | |
| 1169 } | |
| 1170 } | 1161 } |
| 1171 | 1162 |
| 1172 void PopupMenu::updateFromElement() | 1163 void PopupMenu::updateFromElement() |
| 1173 { | 1164 { |
| 1174 p.popup->listBox()->updateFromElement(); | 1165 p.popup->listBox()->updateFromElement(); |
| 1175 } | 1166 } |
| 1176 | 1167 |
| 1177 bool PopupMenu::itemWritingDirectionIsNatural() | 1168 bool PopupMenu::itemWritingDirectionIsNatural() |
| 1178 { | 1169 { |
| 1179 return false; | 1170 return false; |
| 1180 } | 1171 } |
| 1181 | 1172 |
| 1182 } // namespace WebCore | 1173 } // namespace WebCore |
| OLD | NEW |