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 |