From bcfdd0d43393dfc3f0d5e19a14043d4e1d6439a5 Mon Sep 17 00:00:00 2001 From: Matti Tahvonen Date: Wed, 12 Sep 2007 12:40:08 +0000 Subject: [PATCH] Better positioning for selects popup svn changeset:2290/svn branch:trunk --- .../terminal/gwt/client/ui/IFilterSelect.java | 304 ++++++++++-------- 1 file changed, 163 insertions(+), 141 deletions(-) diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java index 474f14e7d5..b9bafd2640 100644 --- a/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java +++ b/src/com/itmill/toolkit/terminal/gwt/client/ui/IFilterSelect.java @@ -8,6 +8,7 @@ import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; @@ -17,6 +18,7 @@ import com.google.gwt.user.client.ui.KeyboardListener; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; +import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; import com.google.gwt.user.client.ui.SuggestOracle.Suggestion; import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection; import com.itmill.toolkit.terminal.gwt.client.Paintable; @@ -26,10 +28,11 @@ import com.itmill.toolkit.terminal.gwt.client.UIDL; * * TODO needs major refactoring to be easily expandable */ -public class IFilterSelect extends Composite implements Paintable, KeyboardListener, ClickListener { - +public class IFilterSelect extends Composite implements Paintable, + KeyboardListener, ClickListener { + public class FilterSelectSuggestion implements Suggestion, Command { - + private String key; private String caption; private String iconUri; @@ -37,14 +40,14 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe public FilterSelectSuggestion(UIDL uidl) { this.key = uidl.getStringAttribute("key"); this.caption = uidl.getStringAttribute("caption"); - if(uidl.hasAttribute("icon")) { + if (uidl.hasAttribute("icon")) { this.iconUri = uidl.getStringAttribute("icon"); } } public String getDisplayString() { StringBuffer sb = new StringBuffer(); - if(iconUri != null) { + if (iconUri != null) { sb.append("\"icon\""); @@ -60,19 +63,19 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe public int getOptionKey() { return Integer.parseInt(key); } - + public String getIconUri() { return iconUri; } - + public void execute() { IFilterSelect.this.onSuggestionSelected(this); } } - public class SuggestionPopup extends PopupPanel { + public class SuggestionPopup extends PopupPanel implements PositionCallback { private SuggestionMenu menu; - + private Element up = DOM.createDiv(); private Element down = DOM.createDiv(); private Element status = DOM.createDiv(); @@ -84,10 +87,9 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe this.menu = new SuggestionMenu(); setWidget(menu); setStyleName(CLASSNAME + "-suggestpopup"); - + Element root = getElement(); - - + DOM.setInnerText(up, "prev"); DOM.sinkEvents(up, Event.ONCLICK); DOM.setInnerText(down, "next"); @@ -97,67 +99,74 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe DOM.appendChild(root, status); DOM.setElementProperty(status, "className", CLASSNAME + "-status"); } - - public void showSuggestions(Collection currentSuggestions, int currentPage, int totalSuggestions) { + + public void showSuggestions(Collection currentSuggestions, + int currentPage, int totalSuggestions) { menu.setSuggestions(currentSuggestions); int x = IFilterSelect.this.tb.getAbsoluteLeft(); int y = IFilterSelect.this.tb.getAbsoluteTop(); y += IFilterSelect.this.tb.getOffsetHeight(); this.setPopupPosition(x, y); - int first = currentPage*PAGELENTH + 1; - int last = first + currentSuggestions.size() - 1 ; - DOM.setInnerText(status, first + "-" + last + "/" + totalSuggestions); + int first = currentPage * PAGELENTH + 1; + int last = first + currentSuggestions.size() - 1; + DOM.setInnerText(status, first + "-" + last + "/" + + totalSuggestions); setPrevButtonActive(first > 1); setNextButtonActive(last < totalSuggestions); - - show(); + setPopupPositionAndShow(this); + } - + private void setNextButtonActive(boolean b) { - if(b) { + if (b) { DOM.sinkEvents(down, Event.ONCLICK); - DOM.setElementProperty(down, "className", CLASSNAME + "-nextpage-on"); + DOM.setElementProperty(down, "className", CLASSNAME + + "-nextpage-on"); } else { DOM.sinkEvents(down, 0); - DOM.setElementProperty(down, "className", CLASSNAME + "-nextpage-off"); + DOM.setElementProperty(down, "className", CLASSNAME + + "-nextpage-off"); } } private void setPrevButtonActive(boolean b) { - if(b) { + if (b) { DOM.sinkEvents(up, Event.ONCLICK); - DOM.setElementProperty(up, "className", CLASSNAME + "-prevpage-on"); + DOM.setElementProperty(up, "className", CLASSNAME + + "-prevpage-on"); } else { DOM.sinkEvents(up, 0); - DOM.setElementProperty(up, "className", CLASSNAME + "-prevpage-off"); + DOM.setElementProperty(up, "className", CLASSNAME + + "-prevpage-off"); } - + } public void selectNextItem() { MenuItem cur = menu.getSelectedItem(); int index = 1 + menu.getItems().indexOf(cur); - if(menu.getItems().size() > index) + if (menu.getItems().size() > index) menu.selectItem((MenuItem) menu.getItems().get(index)); else filterOptions(currentPage + 1); } - + public void selectPrevItem() { MenuItem cur = menu.getSelectedItem(); int index = -1 + menu.getItems().indexOf(cur); - if(index > -1) + if (index > -1) menu.selectItem((MenuItem) menu.getItems().get(index)); else if (index == -1) { filterOptions(currentPage - 1); } else { - menu.selectItem((MenuItem) menu.getItems().get(menu.getItems().size()-1)); + menu.selectItem((MenuItem) menu.getItems().get( + menu.getItems().size() - 1)); } } - + public void onBrowserEvent(Event event) { Element target = DOM.eventGetTarget(event); - if(DOM.compare(target, up)) { + if (DOM.compare(target, up)) { filterOptions(currentPage - 1, lastFilter); } else if (DOM.compare(target, down)) { filterOptions(currentPage + 1, lastFilter); @@ -166,9 +175,9 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe } public void setPagingEnabled(boolean paging) { - if(isPagingEnabled == paging) + if (isPagingEnabled == paging) return; - if(paging) { + if (paging) { DOM.setStyleAttribute(this.down, "display", "block"); DOM.setStyleAttribute(this.up, "display", "block"); DOM.setStyleAttribute(this.status, "display", "block"); @@ -178,10 +187,29 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe DOM.setStyleAttribute(this.status, "display", "none"); } } + + public void setPosition(int offsetWidth, int offsetHeight) { + ApplicationConnection.getConsole().log("callback"); + if (offsetHeight > Window.getClientHeight()) { + offsetHeight = Window.getClientHeight(); + menu.setHeight(offsetHeight + "px"); + DOM.setStyleAttribute(menu.getElement(), "overflow", "auto"); + // add scrollbar width + menu + .setWidth((menu.getOffsetWidth() * 2 - DOM + .getElementPropertyInt(menu.getElement(), + "clientWidth")) + + "px"); + } + if (offsetHeight + getPopupTop() > Window.getClientHeight()) { + int top = Window.getClientHeight() - offsetHeight; + setPopupPosition(getPopupLeft(), top); + } + } } public class SuggestionMenu extends MenuBar { - + SuggestionMenu() { super(true); setStyleName(CLASSNAME + "-suggestmenu"); @@ -190,21 +218,18 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe public void setSuggestions(Collection suggestions) { this.clearItems(); Iterator it = suggestions.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { FilterSelectSuggestion s = (FilterSelectSuggestion) it.next(); - MenuItem mi = new MenuItem( - s.getDisplayString(), - true, - s); + MenuItem mi = new MenuItem(s.getDisplayString(), true, s); this.addItem(mi); - if(s == currentSuggestion) + if (s == currentSuggestion) selectItem(mi); } } public void doSelectedItemAction() { MenuItem item = this.getSelectedItem(); - if(item != null) { + if (item != null) { doItemAction(item, true); } suggestionPopup.hide(); @@ -212,23 +237,23 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe } private static final String CLASSNAME = "i-filterselect"; - + public static final int PAGELENTH = 20; private final FlowPanel panel = new FlowPanel(); - + private final TextBox tb = new TextBox(); - + private final SuggestionPopup suggestionPopup = new SuggestionPopup(); - + private final HTML popupOpener = new HTML("v"); - - private final Image selectedItemIcon = new Image(); - + + private final Image selectedItemIcon = new Image(); + private ApplicationConnection client; private String paintableId; - + private int currentPage; private Collection currentSuggestions = new ArrayList(); @@ -248,7 +273,7 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe private boolean clientSideFiltering; private ArrayList allSuggestions; - + public IFilterSelect() { selectedItemIcon.setVisible(false); panel.add(selectedItemIcon); @@ -260,35 +285,37 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe popupOpener.setStyleName(CLASSNAME + "-popupopener"); popupOpener.addClickListener(this); } - + public void filterOptions(int page) { filterOptions(page, tb.getText()); } public void filterOptions(int page, String filter) { if (filter.equals(lastFilter) && currentPage == page) { - if(!suggestionPopup.isAttached()) - suggestionPopup.showSuggestions(currentSuggestions, currentPage, totalSuggestions); + if (!suggestionPopup.isAttached()) + suggestionPopup.showSuggestions(currentSuggestions, + currentPage, totalSuggestions); return; } - if(!filter.equals(lastFilter)) { + if (!filter.equals(lastFilter)) { // we are on subsequant page and text has changed -> reset page page = 0; } - if(clientSideFiltering) { + if (clientSideFiltering) { currentSuggestions.clear(); - for(Iterator it = allSuggestions.iterator();it.hasNext();) { + for (Iterator it = allSuggestions.iterator(); it.hasNext();) { FilterSelectSuggestion s = (FilterSelectSuggestion) it.next(); String string = s.getDisplayString().toLowerCase(); - if(string.startsWith(filter.toLowerCase())) { + if (string.startsWith(filter.toLowerCase())) { currentSuggestions.add(s); } } lastFilter = filter; currentPage = page; - suggestionPopup.showSuggestions(currentSuggestions, page, currentSuggestions.size()); + suggestionPopup.showSuggestions(currentSuggestions, page, + currentSuggestions.size()); } else { - filtering = true; + filtering = true; client.updateVariable(paintableId, "filter", filter, false); client.updateVariable(paintableId, "page", page, true); lastFilter = filter; @@ -299,70 +326,66 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { this.paintableId = uidl.getId(); this.client = client; - - if(client.updateComponent(this, uidl, true)) + + if (client.updateComponent(this, uidl, true)) return; - - if(uidl.hasAttribute("immediate")) + + if (uidl.hasAttribute("immediate")) immediate = true; - else + else immediate = false; - - if(uidl.hasVariable("page")) { + + if (uidl.hasVariable("page")) { this.suggestionPopup.setPagingEnabled(true); clientSideFiltering = false; } else { this.suggestionPopup.setPagingEnabled(false); clientSideFiltering = true; } - + currentSuggestions.clear(); UIDL options = uidl.getChildUIDL(0); totalSuggestions = options.getIntAttribute("totalMatches"); - if(clientSideFiltering) { + if (clientSideFiltering) { allSuggestions = new ArrayList(); } - for(Iterator i = options.getChildIterator(); i.hasNext();) { + for (Iterator i = options.getChildIterator(); i.hasNext();) { UIDL optionUidl = (UIDL) i.next(); - FilterSelectSuggestion suggestion = new FilterSelectSuggestion(optionUidl); + FilterSelectSuggestion suggestion = new FilterSelectSuggestion( + optionUidl); currentSuggestions.add(suggestion); - if(clientSideFiltering) { + if (clientSideFiltering) { allSuggestions.add(suggestion); } - if(optionUidl.hasAttribute("selected")) { + if (optionUidl.hasAttribute("selected")) { tb.setText(suggestion.getReplacementString()); currentSuggestion = suggestion; } } - - if(filtering && lastFilter.equals(uidl.getStringVariable("filter"))) { - suggestionPopup.showSuggestions( - currentSuggestions, - currentPage, + + if (filtering && lastFilter.equals(uidl.getStringVariable("filter"))) { + suggestionPopup.showSuggestions(currentSuggestions, currentPage, totalSuggestions); filtering = false; } } - + public void onSuggestionSelected(FilterSelectSuggestion suggestion) { - currentSuggestion = suggestion; - String newKey = String.valueOf(suggestion.getOptionKey()); - tb.setText(suggestion.getReplacementString()); - setSelectedItemIcon(suggestion.getIconUri()); - if(!newKey.equals(selectedOptionKey)) { - selectedOptionKey = newKey; - client.updateVariable( - paintableId, - "selected", - new String[] {selectedOptionKey} , - immediate); - lastFilter = tb.getText(); - } - suggestionPopup.hide(); + currentSuggestion = suggestion; + String newKey = String.valueOf(suggestion.getOptionKey()); + tb.setText(suggestion.getReplacementString()); + setSelectedItemIcon(suggestion.getIconUri()); + if (!newKey.equals(selectedOptionKey)) { + selectedOptionKey = newKey; + client.updateVariable(paintableId, "selected", + new String[] { selectedOptionKey }, immediate); + lastFilter = tb.getText(); } - + suggestionPopup.hide(); + } + private void setSelectedItemIcon(String iconUri) { - if(iconUri == null) { + if (iconUri == null) { selectedItemIcon.setVisible(false); } else { selectedItemIcon.setUrl(iconUri); @@ -371,57 +394,56 @@ public class IFilterSelect extends Composite implements Paintable, KeyboardListe } public void onKeyDown(Widget sender, char keyCode, int modifiers) { - if (suggestionPopup.isAttached()) { - switch (keyCode) { - case KeyboardListener.KEY_DOWN: - suggestionPopup.selectNextItem(); - break; - case KeyboardListener.KEY_UP: - suggestionPopup.selectPrevItem(); - break; - case KeyboardListener.KEY_PAGEDOWN: - if(totalSuggestions > currentPage*(PAGELENTH+1)) - filterOptions(currentPage + 1, lastFilter); - break; - case KeyboardListener.KEY_PAGEUP: - if(currentPage > 0) - filterOptions(currentPage - 1, lastFilter); - break; - case KeyboardListener.KEY_ENTER: - case KeyboardListener.KEY_TAB: - suggestionPopup.menu.doSelectedItemAction(); - break; - } - } + if (suggestionPopup.isAttached()) { + switch (keyCode) { + case KeyboardListener.KEY_DOWN: + suggestionPopup.selectNextItem(); + break; + case KeyboardListener.KEY_UP: + suggestionPopup.selectPrevItem(); + break; + case KeyboardListener.KEY_PAGEDOWN: + if (totalSuggestions > currentPage * (PAGELENTH + 1)) + filterOptions(currentPage + 1, lastFilter); + break; + case KeyboardListener.KEY_PAGEUP: + if (currentPage > 0) + filterOptions(currentPage - 1, lastFilter); + break; + case KeyboardListener.KEY_ENTER: + case KeyboardListener.KEY_TAB: + suggestionPopup.menu.doSelectedItemAction(); + break; + } + } } public void onKeyPress(Widget sender, char keyCode, int modifiers) { - - + } public void onKeyUp(Widget sender, char keyCode, int modifiers) { - switch (keyCode) { - case KeyboardListener.KEY_ENTER: - case KeyboardListener.KEY_TAB: - ; //NOP - break; - case KeyboardListener.KEY_DOWN: - case KeyboardListener.KEY_UP: - case KeyboardListener.KEY_PAGEDOWN: - case KeyboardListener.KEY_PAGEUP: - if(suggestionPopup.isAttached()) { - break; - } else { - // open popup as from gadget - filterOptions(0, ""); - tb.selectAll(); - break; - } - default: - filterOptions(currentPage); - break; - } + switch (keyCode) { + case KeyboardListener.KEY_ENTER: + case KeyboardListener.KEY_TAB: + ; // NOP + break; + case KeyboardListener.KEY_DOWN: + case KeyboardListener.KEY_UP: + case KeyboardListener.KEY_PAGEDOWN: + case KeyboardListener.KEY_PAGEUP: + if (suggestionPopup.isAttached()) { + break; + } else { + // open popup as from gadget + filterOptions(0, ""); + tb.selectAll(); + break; + } + default: + filterOptions(currentPage); + break; + } } /** -- 2.39.5