]> source.dussan.org Git - vaadin-framework.git/commitdiff
Client side context menu implementation and context menus for scroll tables rows
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 10 Jul 2007 10:59:10 +0000 (10:59 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Tue, 10 Jul 2007 10:59:10 +0000 (10:59 +0000)
svn changeset:1827/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/client/Client.java
src/com/itmill/toolkit/terminal/gwt/client/UIDL.java
src/com/itmill/toolkit/terminal/gwt/client/ui/IAction.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/client/ui/IContextMenu.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/client/ui/IScrollTable.java

index b1151e0ac8cadf1f8dcbac5a1474520232951c9f..02a613fa46ad688677e53bb675c3d8f2801e7de2 100755 (executable)
@@ -19,6 +19,7 @@ import com.google.gwt.json.client.JSONValue;
 import com.google.gwt.user.client.ui.FocusWidget;
 import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ui.IContextMenu;
 
 /**
  * Entry point classes define <code>onModuleLoad()</code>.
@@ -45,6 +46,8 @@ public class Client implements EntryPoint {
        
        private LocaleService locale;
 
+       private IContextMenu contextMenu = null;
+
        /**
         * This is the entry point method.
         */
@@ -370,4 +373,16 @@ public class Client implements EntryPoint {
        public String getResource(String name) {
                return (String) resourcesMap.get(name);
        }
+       
+       /**
+        * Singleton method to get instance of app's context menu.
+        * 
+        * @return IContextMenu object
+        */
+       public IContextMenu getContextMenu() {
+               if(contextMenu  == null) {
+                       contextMenu = new IContextMenu();
+               }
+               return contextMenu;
+       }
 }
index cee8c8aa2ec59673e04f2b4b65f1f0184306ac0c..ed8ca237a024e479bdc9058994c997d85a35d352 100644 (file)
@@ -68,6 +68,14 @@ public class UIDL {
                        return false;
                return ((JSONBoolean) val).booleanValue();
        }
+       
+       public String[] getStringArrayAttribute(String name) {
+               JSONArray a = (JSONArray) ((JSONObject) json.get(1)).get(name);
+               String[] s = new String[a.size()];
+               for (int i = 0; i < a.size(); i++)
+                       s[i] = ((JSONString) a.get(i)).stringValue();
+               return s;
+       }
 
        /**
         * Get attributes value as string whateever the type is
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IAction.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IAction.java
new file mode 100644 (file)
index 0000000..af75a49
--- /dev/null
@@ -0,0 +1,97 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.Command;
+import com.itmill.toolkit.terminal.gwt.client.Client;
+
+/**
+ *
+ */
+public class IAction implements Command {
+       
+       IActionOwner owner;
+       
+       String targetKey = "";
+       String actionKey = "";
+       
+       String iconUrl = null;
+       
+       String caption = "";
+       
+       public IAction(IActionOwner owner) {
+               this.owner = owner;
+       }
+       
+       public IAction(IActionOwner owner, String target, String action) {
+               this(owner);
+               this.targetKey = target;
+               this.actionKey = action;
+       }
+       
+       
+       /**
+        * Sends message to server that this action has been fired.
+        * Messages are "standard" Toolkit messages whose value is comma
+        * separated pair of targetKey (row, treeNod ...) and actions id.
+        * 
+        * Variablename is always "action".
+        * 
+        * Actions are always sent immediatedly to server.
+        */
+       public void execute() {
+               owner.getClient().updateVariable(
+                               owner.getPaintableId(), 
+                               "action", 
+                               targetKey + "," + actionKey, 
+                               true);
+               owner.getClient().getContextMenu().hide();
+       }
+
+       public String getActionKey() {
+               return actionKey;
+       }
+
+       public void setActionKey(String actionKey) {
+               this.actionKey = actionKey;
+       }
+
+       public String getTargetKey() {
+               return targetKey;
+       }
+
+       public void setTargetKey(String targetKey) {
+               this.targetKey = targetKey;
+       }
+
+       public String getHTMLRepresentation() {
+               StringBuffer sb = new StringBuffer();
+               if(iconUrl != null) {
+                       sb.append("<img src=\""+iconUrl+"\" alt=\"icon\" />");
+               }
+               sb.append(caption);
+               return sb.toString();
+       }
+
+       public String getCaption() {
+               return caption;
+       }
+
+       public void setCaption(String caption) {
+               this.caption = caption;
+       }
+}
+
+/**
+ * Action owner must provide a set of actions for context menu
+ * and IAction objects.
+ */
+interface IActionOwner {
+       
+       /**
+        * @return Array of IActions
+        */
+       public IAction[] getActions();
+
+       public Client getClient();
+       
+       public String getPaintableId();
+}
\ No newline at end of file
diff --git a/src/com/itmill/toolkit/terminal/gwt/client/ui/IContextMenu.java b/src/com/itmill/toolkit/terminal/gwt/client/ui/IContextMenu.java
new file mode 100644 (file)
index 0000000..d18120f
--- /dev/null
@@ -0,0 +1,75 @@
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+public class IContextMenu extends PopupPanel {
+       
+       private IActionOwner actionOwner;
+       
+       private CMenuBar menu = new CMenuBar();
+       
+       /**
+        * This method should be used only by Client object as
+        * only one per client should exists. Request an instance
+        * via client.getContextMenu();
+        * 
+        * @param cli to be set as an owner of menu
+        */
+       public IContextMenu() {
+               super(true);
+               setWidget(menu);
+               setStyleName("i-contextmenu");
+       }
+       
+       /**
+        * Sets the element from which to build menu
+        * @param ao
+        */
+       public void setActionOwner(IActionOwner ao) {
+               this.actionOwner = ao;
+       }
+       
+       /**
+        * Shows context menu at given location.
+        * 
+        * @param left
+        * @param top
+        */
+       public void showAt(int left, int top) {
+               menu.clearItems();
+               IAction[] actions = actionOwner.getActions();
+               for (int i = 0; i < actions.length; i++) {
+                       IAction a = actions[i];
+                       menu.addItem(new MenuItem(a.getHTMLRepresentation(), true, a));
+               }
+               
+               setPopupPosition(left, top);
+               
+               show();
+       }
+
+       public void showAt(IActionOwner ao, int left, int top) {
+               setActionOwner(ao);
+               showAt(left, top);
+               
+       }
+
+       /**
+        * Extend standard Gwt MenuBar to set proper settings and 
+        * to override onPopupClosed method so that PopupPanel gets
+        * closed.
+        */
+       class CMenuBar extends MenuBar {
+               public CMenuBar() {
+                       super(true);
+               }
+
+               public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
+                       super.onPopupClosed(sender, autoClosed);
+                       IContextMenu.this.hide();
+               }
+       }
+}
index ed4a4dc192722b17d4013a6ee807cf988758ff65..ec81c750c29b5e5cea5fad4fbc57deb247962134 100644 (file)
@@ -12,7 +12,6 @@ import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.ClickListener;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.Panel;
 import com.google.gwt.user.client.ui.ScrollListener;
@@ -45,7 +44,7 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
        private String[] columnOrder;
        
        private Client client;
-       private String id;
+       private String paintableId;
        
        private boolean immediate;
 
@@ -74,6 +73,14 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
        private String sortColumn;
        private boolean columnReordering;
        
+       /**
+        * This map contains captions and icon urls for 
+        * actions like:
+        *   * "33_c" -> "Edit"
+        *   * "33_i" -> "http://dom.com/edit.png"
+        */
+       private HashMap actionMap = new HashMap();
+       
        public IScrollTable() {
                headerContainer.setStyleName("iscrolltable-header");
                headerContainer.add(tHead);
@@ -95,7 +102,7 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
                        return;
 
                this.client = client;
-               this.id = uidl.getStringAttribute("id");
+               this.paintableId = uidl.getStringAttribute("id");
                this.immediate = uidl.getBooleanAttribute("immediate");
                this.totalRows = uidl.getIntAttribute("totalrows");
                this.pageLength = uidl.getIntAttribute("pagelength");
@@ -169,9 +176,28 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
        }
 
        private void updateActionMap(UIDL c) {
-               // TODO Auto-generated method stub
+               Iterator it = c.getChildIterator();
+               while(it.hasNext()) {
+                       UIDL action = (UIDL) it.next();
+                       String key = action.getStringAttribute("key");
+                       String caption = action.getStringAttribute("caption");
+                       actionMap.put(key + "_c", caption);
+                       if(action.hasAttribute("icon")) {
+                               // TODO need some uri handling ??
+                               actionMap.put(key + "_i", action.getStringAttribute("icon"));
+                       }
+               }
                
        }
+       
+       public String getActionCaption(String actionKey) {
+               return (String) actionMap.get(actionKey + "_c");
+       }
+       
+       public String getActionIcon(String actionKey) {
+               return (String) actionMap.get(actionKey + "_i");
+       }
+       
 
        private void updateHeader(UIDL uidl) {
                if(uidl == null)
@@ -303,7 +329,7 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
                        newOrder[index++] = ((HeaderCell) hCells.next()).getColKey();
                }
                columnOrder = newOrder;
-               client.updateVariable(id, "columnorder", newOrder, false);
+               client.updateVariable(paintableId, "columnorder", newOrder, false);
                
        }
 
@@ -333,7 +359,7 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
                int lastRendered = tBody.getLastRendered();
                int firstRendered = tBody.getFirstRendered();
                if( postLimit <= lastRendered && preLimit >= firstRendered ) {
-                       client.updateVariable(this.id, "firstvisible", firstRowInViewPort, false);
+                       client.updateVariable(this.paintableId, "firstvisible", firstRowInViewPort, false);
                        return; // scrolled withing "non-react area"
                }
                
@@ -455,9 +481,9 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
 
                public void run() {
                        client.console.log("Getting " + reqRows + " rows from " + reqFirstRow);
-                       client.updateVariable(id, "firstvisible", firstRowInViewPort, false);
-                       client.updateVariable(id, "reqfirstrow", reqFirstRow, false);
-                       client.updateVariable(id, "reqrows", reqRows, true);
+                       client.updateVariable(paintableId, "firstvisible", firstRowInViewPort, false);
+                       client.updateVariable(paintableId, "reqfirstrow", reqFirstRow, false);
+                       client.updateVariable(paintableId, "reqrows", reqRows, true);
                }
 
                public int getReqFirstRow() {
@@ -627,10 +653,10 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
                                        if(sortable) {
                                                if(sortColumn.equals(cid)) {
                                                        // just toggle order
-                                                       client.updateVariable(id, "sortascending", !sortAscending, false);
+                                                       client.updateVariable(paintableId, "sortascending", !sortAscending, false);
                                                } else {
                                                        // set table scrolled by this column
-                                                       client.updateVariable(id, "sortcolumn", cid, false);
+                                                       client.updateVariable(paintableId, "sortcolumn", cid, false);
                                                }
                                                // get also cache columns at the same request
                                                bodyContainer.setScrollPosition(0);
@@ -1047,28 +1073,46 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
 
                }
 
-               public class IScrollTableRow extends Panel {
+               public class IScrollTableRow extends Panel  implements IActionOwner {
                        
                        Vector childWidgets = new Vector();
                        private boolean selected = false;
                        private int rowKey;
                        
+                       private String[] actionKeys = null;
+                       
                        private IScrollTableRow(int rowKey) {
                                this.rowKey = rowKey;
-                               this.selected = selected;
                                setElement(DOM.createElement("tr"));
-                               DOM.sinkEvents(getElement(), Event.BUTTON_RIGHT | Event.ONCLICK);
+                               DOM.sinkEvents(getElement(), Event.ONCLICK);
+                               disableContextMenu(getElement());
                                setStyleName("iscrolltable-row");
                        }
                        
+                       private native void disableContextMenu(Element el) /*-{
+                               var row = this;
+                               el.oncontextmenu = function(e) {
+                                       if(!e)
+                                               e = window.event;
+                                       row.@com.itmill.toolkit.terminal.gwt.client.ui.IScrollTable.IScrollTableBody.IScrollTableRow::showContextMenu(Lcom/google/gwt/user/client/Event;)(e);
+                                       return false;
+                               };
+                       }-*/;
+                       
                        public String getKey() {
                                return String.valueOf(rowKey);
                        }
 
                        public IScrollTableRow(UIDL uidl) {
                                this(uidl.getIntAttribute("key"));
+                               
+                               // row header
                                if(uidl.hasAttribute("caption"))
                                        addCell(uidl.getStringAttribute("caption"));
+                               
+                               if(uidl.hasAttribute("al"))
+                                       actionKeys = uidl.getStringArrayAttribute("al");
+                               
                                Iterator cells = uidl.getChildIterator();
                                while(cells.hasNext()) {
                                        Object cell = cells.next();
@@ -1079,7 +1123,7 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
                                                (( Paintable) cellContent).updateFromUIDL((UIDL) cell, client);
                                        }
                                }
-                               if(uidl.hasAttribute("selected"))
+                               if(uidl.hasAttribute("selected") && !isSelected())
                                        toggleSelection();
                        }
                        
@@ -1114,16 +1158,11 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
 
                        public void onBrowserEvent(Event event) {
                                switch (DOM.eventGetType(event)) {
-                               case Event.BUTTON_RIGHT:
-                                       // TODO
-                                       System.out.println("Context menu");
-                                       break;
-                                       
                                case Event.ONCLICK:
-                                       System.out.println("Row click");
+                                       client.console.log("Row click");
                                        if(selectMode > ITable.SELECT_MODE_NONE) {
                                                toggleSelection();
-                                               client.updateVariable(id, "selected", selectedRowKeys.toArray(), immediate);
+                                               client.updateVariable(paintableId, "selected", selectedRowKeys.toArray(), immediate);
                                        }
                                        break;
 
@@ -1132,6 +1171,15 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
                                }
                                super.onBrowserEvent(event);
                        }
+                       
+                       public void showContextMenu(Event event) {
+                               client.console.log("Context menu");
+                               if(actionKeys != null) {
+                                       int left = DOM.eventGetClientX(event);
+                                       int top = DOM.eventGetClientY(event);
+                                       client.getContextMenu().showAt(this, left, top);
+                               }
+                       }
 
                        public boolean isSelected() {
                                return selected;
@@ -1150,9 +1198,28 @@ public class IScrollTable extends Composite implements Paintable, ITable, Scroll
                                        setStyleName("iscrolltable-row");
                                }
                        }
-                       
-               }
 
+                       public IAction[] getActions() {
+                               if(actionKeys == null)
+                                       return new IAction[] {};
+                               IAction[] actions = new IAction[actionKeys.length];
+                               for (int i = 0; i < actions.length; i++) {
+                                       String actionKey = actionKeys[i];
+                                       IAction a = new IAction(this, String.valueOf(rowKey), actionKey);
+                                       a.setCaption(getActionCaption(actionKey));
+                                       actions[i] = a;
+                               }
+                               return actions;
+                       }
+
+                       public Client getClient() {
+                               return client;
+                       }
+
+                       public String getPaintableId() {
+                               return paintableId;
+                       }
+               }
        }
 
        public void deselectAll() {