From baecc2e6fb381c85455b828408b3406c9c22febf Mon Sep 17 00:00:00 2001 From: John Alhroos Date: Tue, 13 Apr 2010 07:38:05 +0000 Subject: [PATCH] Implemented CTRL and SHIFT clicking in Table #3520 svn changeset:12494/svn branch:6.4 --- .../terminal/gwt/client/ui/VScrollTable.java | 112 +++++++++++++++++- src/com/vaadin/ui/Table.java | 43 +++++++ 2 files changed, 149 insertions(+), 6 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index 72efa90ab4..37ad81fce5 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@ -12,6 +12,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.NodeList; @@ -166,6 +167,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, private boolean rendering = false; private int dragmode; + private int multiselectmode; + private int lastSelectedRowKey = -1; + public VScrollTable() { bodyContainer.addScrollHandler(this); bodyContainer.setStyleName(CLASSNAME + "-body"); @@ -210,6 +214,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, dragmode = uidl.hasAttribute("dragmode") ? uidl .getIntAttribute("dragmode") : 0; + multiselectmode = uidl.hasAttribute("multiselectmode") ? uidl + .getIntAttribute("multiselectmode") : 0; + setCacheRate(uidl.hasAttribute("cr") ? uidl.getDoubleAttribute("cr") : CACHE_RATE_DEFAULT); @@ -2353,7 +2360,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } if (uidl.hasAttribute("selected") && !isSelected()) { - toggleSelection(); + toggleSelection(true); } } @@ -2484,6 +2491,18 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } + /** + * Add this to the element mouse down event by using + * element.setPropertyJSO + * ("onselectstart",applyDisableTextSelectionIEHack()); Remove it + * then again when the mouse is depressed in the mouse up event. + * + * @return Returns the JSO preventing text selection + */ + private native JavaScriptObject applyDisableTextSelectionIEHack()/*-{ + return function(){ return false; }; + }-*/; + /* * React on click that occur on content cells only */ @@ -2501,7 +2520,26 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, handleClickEvent(event, targetTdOrTr); if (event.getButton() == Event.BUTTON_LEFT && selectMode > Table.SELECT_MODE_NONE) { - toggleSelection(); + + if (event.getCtrlKey() + && selectMode == SELECT_MODE_MULTI + && multiselectmode == 0) { + toggleSelection(true); + } else if (event.getShiftKey() + && selectMode == SELECT_MODE_MULTI + && multiselectmode == 0) { + toggleShiftSelection(); + } else { + if (multiselectmode == 0) { + deselectAll(); + } + toggleSelection(multiselectmode == 0); + } + + // Remove IE text selection hack + event.getTarget().setPropertyJSO( + "onselectstart", null); + // Note: changing the immediateness of this // might // require changes to "clickEvent" immediateness @@ -2567,6 +2605,19 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } event.preventDefault(); event.stopPropagation(); + } else if (event.getCtrlKey() + || event.getShiftKey() + && selectMode == SELECT_MODE_MULTI + && multiselectmode == 0) { + // Prevent default text selection in Firefox + event.preventDefault(); + + // Prevent default text selection in IE + event.getTarget().setPropertyJSO( + "onselectstart", + applyDisableTextSelectionIEHack()); + + event.stopPropagation(); } break; case Event.ONMOUSEOUT: @@ -2646,15 +2697,23 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, event.preventDefault(); } + /** + * Has the row been selected? + * + * @return Returns true if selected, else false + */ public boolean isSelected() { return selected; } - private void toggleSelection() { + /** + * Toggle the selection of the row + */ + public void toggleSelection(boolean ctrlSelect) { selected = !selected; if (selected) { - if (selectMode == Table.SELECT_MODE_SINGLE) { - deselectAll(); + if (ctrlSelect) { + lastSelectedRowKey = rowKey; } selectedRowKeys.add(String.valueOf(rowKey)); addStyleName("v-selected"); @@ -2664,6 +2723,47 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, } } + private void toggleShiftSelection() { + + /* + * Ensures that we are in multiselect mode and that we have a + * previous selection which was not a deselection + */ + if (selectedRowKeys.isEmpty() || lastSelectedRowKey < 0) { + deselectAll(); + toggleSelection(true); + return; + } + + // Set the selectable range + int startKey = lastSelectedRowKey; + int endKey = rowKey; + if (endKey < startKey) { + // Swap keys if in the wrong order + startKey ^= endKey; + endKey ^= startKey; + startKey ^= endKey; + } + + // Select the range (not including this row) + deselectAll(); + for (int r = startKey; r <= endKey; r++) { + if (r != rowKey) { + selectedRowKeys.add(String.valueOf(r)); + VScrollTableRow row = getRenderedRowByKey(String + .valueOf(r)); + if (!row.isSelected()) { + row.toggleSelection(false); + } + } + } + + // Toggle clicked rows selection + toggleSelection(false); + + getElement().focus(); + } + /* * (non-Javadoc) * @@ -2768,7 +2868,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler, for (int i = 0; i < keys.length; i++) { final VScrollTableRow row = getRenderedRowByKey((String) keys[i]); if (row != null && row.isSelected()) { - row.toggleSelection(); + row.toggleSelection(false); } } // still ensure all selects are removed from (not necessary rendered) diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java index 610d638ab4..e2c0a0d80f 100644 --- a/src/com/vaadin/ui/Table.java +++ b/src/com/vaadin/ui/Table.java @@ -93,6 +93,22 @@ public class Table extends AbstractSelect implements Action.Container, MULTIROW } + /** + * Multi select modes that controls how multi select behaves. + */ + public enum MultiSelectMode { + /** + * Simple left clicks only selects one item, CTRL+left click selects + * multiple items and SHIFT-left click selects a range of items. + */ + DEFAULT, + /** + * Uses the old method of selection. CTRL- and SHIFT-clicks are disabled and + * clicking on the items selects/deselects them. + */ + SIMPLE + } + private static final int CELL_KEY = 0; private static final int CELL_HEADER = 1; @@ -368,6 +384,8 @@ public class Table extends AbstractSelect implements Action.Container, private DropHandler dropHandler; + private MultiSelectMode multiSelectMode = MultiSelectMode.DEFAULT; + /* Table constructors */ /** @@ -2065,6 +2083,10 @@ public class Table extends AbstractSelect implements Action.Container, target.addAttribute("dragmode", dragMode.ordinal()); } + if (multiSelectMode != MultiSelectMode.DEFAULT) { + target.addAttribute("multiselectmode", multiSelectMode.ordinal()); + } + // Initialize temps final Object[] colids = getVisibleColumns(); final int cols = colids.length; @@ -3432,6 +3454,27 @@ public class Table extends AbstractSelect implements Action.Container, return new AbstractSelectTargetDetails(clientVariables); } + /** + * Sets the behavior of how the multi-select mode should behave when the + * table is both selectable and in multi-select mode. + * + * @param mode + * The select mode of the table + */ + public void setMultiSelectMode(MultiSelectMode mode) { + multiSelectMode = mode; + requestRepaint(); + } + + /** + * Returns the select mode in which multi-select is used. + * + * @return The multi select mode + */ + public MultiSelectMode getMultiSelectMode() { + return multiSelectMode; + } + /** * Lazy loading accept criterion for Table. Accepted target rows are loaded * from server once per drag and drop operation. Developer must override one -- 2.39.5