From 4bd46ec67162e0443bc12d4aa47778f4ef5554d7 Mon Sep 17 00:00:00 2001 From: Marc Englund Date: Wed, 31 Oct 2007 07:41:08 +0000 Subject: [PATCH] Select refactor initial commit; not done. svn changeset:2629/svn branch:trunk --- src/com/itmill/toolkit/demo/FilterSelect.java | 75 +- src/com/itmill/toolkit/demo/SelectDemo.java | 35 +- .../tests/TestForMultipleStyleNames.java | 73 +- .../tests/TestForPreconfiguredComponents.java | 101 +- .../itmill/toolkit/tests/TestForUpload.java | 1 - .../toolkit/tests/TestForWindowing.java | 63 +- src/com/itmill/toolkit/ui/AbstractSelect.java | 1502 +++++++++++++++++ src/com/itmill/toolkit/ui/NativeSelect.java | 6 +- src/com/itmill/toolkit/ui/OptionGroup.java | 2 +- src/com/itmill/toolkit/ui/Select.java | 1446 ++-------------- src/com/itmill/toolkit/ui/Table.java | 561 +++--- src/com/itmill/toolkit/ui/Tree.java | 195 ++- src/com/itmill/toolkit/ui/TwinColSelect.java | 6 +- .../toolkit/ui/select/ContainsFilter.java | 71 - .../toolkit/ui/select/OptionFilter.java | 20 - .../toolkit/ui/select/StartsWithFilter.java | 71 - 16 files changed, 2255 insertions(+), 1973 deletions(-) create mode 100644 src/com/itmill/toolkit/ui/AbstractSelect.java delete mode 100644 src/com/itmill/toolkit/ui/select/ContainsFilter.java delete mode 100644 src/com/itmill/toolkit/ui/select/OptionFilter.java delete mode 100644 src/com/itmill/toolkit/ui/select/StartsWithFilter.java diff --git a/src/com/itmill/toolkit/demo/FilterSelect.java b/src/com/itmill/toolkit/demo/FilterSelect.java index 81e702dfeb..8abda479a2 100644 --- a/src/com/itmill/toolkit/demo/FilterSelect.java +++ b/src/com/itmill/toolkit/demo/FilterSelect.java @@ -1,16 +1,9 @@ package com.itmill.toolkit.demo; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.itmill.toolkit.data.Item; import com.itmill.toolkit.ui.OrderedLayout; import com.itmill.toolkit.ui.Panel; import com.itmill.toolkit.ui.Select; import com.itmill.toolkit.ui.Window; -import com.itmill.toolkit.ui.select.ContainsFilter; -import com.itmill.toolkit.ui.select.OptionFilter; /** * The classic "hello, world!" example for IT Mill Toolkit. The class simply @@ -50,33 +43,33 @@ public class FilterSelect extends com.itmill.toolkit.Application { // default filter Select s1 = new Select(); - for (int i = 0; i < 105; i++) + for (int i = 0; i < 105; i++) { s1 .addItem(firstnames[(int) (Math.random() * (firstnames.length - 1))] + " " + lastnames[(int) (Math.random() * (lastnames.length - 1))]); - s1.setLazyLoading(true); + } s1.setImmediate(true); // contains filter Select s2 = new Select(); - for (int i = 0; i < 500; i++) + for (int i = 0; i < 500; i++) { s2 .addItem(firstnames[(int) (Math.random() * (firstnames.length - 1))] + " " + lastnames[(int) (Math.random() * (lastnames.length - 1))]); - s2.setLazyLoading(true); - s2.setOptionFilter(new ContainsFilter(s2)); + } + s2.setFilteringMode(Select.FILTERINGMODE_CONTAINS); - // custom filter + // startswith filter Select s3 = new Select(); - for (int i = 0; i < 500; i++) + for (int i = 0; i < 500; i++) { s3 .addItem(firstnames[(int) (Math.random() * (firstnames.length - 1))] + " " + lastnames[(int) (Math.random() * (lastnames.length - 1))]); - s3.setLazyLoading(true); - s3.setOptionFilter(new FilterSelect.EndsWithFilter(s3)); + } + s3.setFilteringMode(Select.FILTERINGMODE_STARTSWITH); // Add selects to UI using ordered layout and panels OrderedLayout orderedLayout = new OrderedLayout( @@ -97,54 +90,4 @@ public class FilterSelect extends com.itmill.toolkit.Application { } - /** - * Custom filter that implements "ends with" functionality. - * - * @author IT Mill Ltd. - * - */ - public class EndsWithFilter implements OptionFilter { - private Select s; - - private ArrayList filteredItemsBuffer; - - public EndsWithFilter(Select s) { - this.s = s; - } - - public List filter(String filterstring, int pagelength, int page) { - // prefix MUST be in lowercase - if (filterstring == null || "".equals(filterstring)) { - this.filteredItemsBuffer = new ArrayList(s.getItemIds()); - return this.filteredItemsBuffer; - - } else if (s.getContainerDataSource() != null) { - // all items will be iterated and tested. - // SLOW when there are lot of items. - this.filteredItemsBuffer = new ArrayList(); - for (Iterator iter = s.getItemIds().iterator(); iter.hasNext();) { - Object id = iter.next(); - - Item item = s.getItem(id); - String test = ""; - if (s.getItemCaptionMode() == Select.ITEM_CAPTION_MODE_PROPERTY) - test = item.getItemProperty( - s.getItemCaptionPropertyId()).getValue() - .toString().trim(); - else - test = String.valueOf(id); - - if (test.toLowerCase().endsWith(filterstring)) { - this.filteredItemsBuffer.add(id); - } - } - } - return this.filteredItemsBuffer; - } - - public int getMatchCount() { - return filteredItemsBuffer.size(); - } - } - } diff --git a/src/com/itmill/toolkit/demo/SelectDemo.java b/src/com/itmill/toolkit/demo/SelectDemo.java index 7170d7aacd..20128ea9da 100644 --- a/src/com/itmill/toolkit/demo/SelectDemo.java +++ b/src/com/itmill/toolkit/demo/SelectDemo.java @@ -1,9 +1,13 @@ package com.itmill.toolkit.demo; import java.sql.SQLException; + import com.itmill.toolkit.data.util.QueryContainer; import com.itmill.toolkit.demo.util.SampleDatabase; -import com.itmill.toolkit.ui.*; +import com.itmill.toolkit.ui.Label; +import com.itmill.toolkit.ui.Panel; +import com.itmill.toolkit.ui.Select; +import com.itmill.toolkit.ui.Window; /** * This example demonstrates what is lazy loading feature on Select component. @@ -16,9 +20,9 @@ import com.itmill.toolkit.ui.*; public class SelectDemo extends com.itmill.toolkit.Application { // Select component where SQL rows are attached (using QueryContainer) - private Select select = new Select(); + private final Select select = new Select(); - private Select lazySelect = new Select(); + private final Select lazySelect = new Select(); // Database provided with sample data private SampleDatabase sampleDatabase; @@ -32,40 +36,41 @@ public class SelectDemo extends com.itmill.toolkit.Application { // Main window contains heading, table, select and tree Panel panel = new Panel("Select demo (a.k.a Google Suggests)"); - panel.addComponent(lazySelect); + panel.addComponent(this.lazySelect); panel.addComponent(new Label("
", Label.CONTENT_XHTML)); - panel.addComponent(select); + panel.addComponent(this.select); main.addComponent(panel); // create demo database - sampleDatabase = new SampleDatabase(); + this.sampleDatabase = new SampleDatabase(); initSelects(); } private void initSelects() { // init select - select.setCaption("All employees default functionality."); - select.setItemCaptionPropertyId("WORKER"); + this.select.setCaption("All employees default functionality."); + this.select.setItemCaptionPropertyId("WORKER"); // populate Toolkit select component with test SQL table rows try { QueryContainer qc = new QueryContainer( "SELECT ID, UNIT||', '||LASTNAME||' '||FIRSTNAME" + " AS WORKER FROM employee ORDER BY WORKER", - sampleDatabase.getConnection()); - select.setContainerDataSource(qc); + this.sampleDatabase.getConnection()); + this.select.setContainerDataSource(qc); } catch (SQLException e) { e.printStackTrace(); } // init lazySelect - lazySelect.setCaption("All employees with lazy loading " + this.lazySelect.setCaption("All employees with lazy loading " + "(a.k.a Google Suggests) activated."); - lazySelect.setItemCaptionPropertyId("WORKER"); - // use lazy loading (a.k.a Google Suggest) - lazySelect.setLazyLoading(true); + this.lazySelect.setItemCaptionPropertyId("WORKER"); + this.lazySelect.setFilteringMode(Select.FILTERINGMODE_CONTAINS); + // use same datasource as select object uses - lazySelect.setContainerDataSource(select.getContainerDataSource()); + this.lazySelect.setContainerDataSource(this.select + .getContainerDataSource()); } } diff --git a/src/com/itmill/toolkit/tests/TestForMultipleStyleNames.java b/src/com/itmill/toolkit/tests/TestForMultipleStyleNames.java index 9eac70f48c..a87f53ae10 100644 --- a/src/com/itmill/toolkit/tests/TestForMultipleStyleNames.java +++ b/src/com/itmill/toolkit/tests/TestForMultipleStyleNames.java @@ -7,81 +7,78 @@ import java.util.Iterator; import com.itmill.toolkit.data.Property.ValueChangeEvent; import com.itmill.toolkit.data.Property.ValueChangeListener; import com.itmill.toolkit.data.util.IndexedContainer; -import com.itmill.toolkit.ui.Button; import com.itmill.toolkit.ui.CustomComponent; import com.itmill.toolkit.ui.Label; import com.itmill.toolkit.ui.OrderedLayout; -import com.itmill.toolkit.ui.RichTextArea; -import com.itmill.toolkit.ui.Select; import com.itmill.toolkit.ui.TwinColSelect; /** * * @author IT Mill Ltd. */ -public class TestForMultipleStyleNames extends CustomComponent implements ValueChangeListener { +public class TestForMultipleStyleNames extends CustomComponent implements + ValueChangeListener { + + private final OrderedLayout main = new OrderedLayout(); - private OrderedLayout main = new OrderedLayout(); - private Label l; - - private Select s = new TwinColSelect(); + + private final TwinColSelect s = new TwinColSelect(); private ArrayList styleNames2; public TestForMultipleStyleNames() { - setCompositionRoot(main); + setCompositionRoot(this.main); createNewView(); } public void createNewView() { - main.removeAllComponents(); - main - .addComponent(new Label( - "TK5 supports multiple stylenames for components.")); - - - styleNames2 = new ArrayList(); - - styleNames2.add("red"); - styleNames2.add("bold"); - styleNames2.add("italic"); - - s.setContainerDataSource(new IndexedContainer(styleNames2)); - s.addListener(this); - s.setImmediate(true); - main.addComponent(s); - - l = new Label("Test labele"); - main.addComponent(l); + this.main.removeAllComponents(); + this.main.addComponent(new Label( + "TK5 supports multiple stylenames for components.")); + + this.styleNames2 = new ArrayList(); + + this.styleNames2.add("red"); + this.styleNames2.add("bold"); + this.styleNames2.add("italic"); + + this.s.setContainerDataSource(new IndexedContainer(this.styleNames2)); + this.s.addListener(this); + this.s.setImmediate(true); + this.main.addComponent(this.s); + + this.l = new Label("Test labele"); + this.main.addComponent(this.l); } public void valueChange(ValueChangeEvent event) { - - String currentStyle = l.getStyle(); + + String currentStyle = this.l.getStyle(); String[] tmp = currentStyle.split(" "); ArrayList curStyles = new ArrayList(); for (int i = 0; i < tmp.length; i++) { - if(tmp[i] != "") + if (tmp[i] != "") { curStyles.add(tmp[i]); + } } - - Collection styles = (Collection) s.getValue(); - + + Collection styles = (Collection) this.s.getValue(); + for (Iterator iterator = styles.iterator(); iterator.hasNext();) { String styleName = (String) iterator.next(); - if(curStyles.contains(styleName)) { + if (curStyles.contains(styleName)) { // already added curStyles.remove(styleName); } else { - l.addStyleName(styleName); + this.l.addStyleName(styleName); } } for (Iterator iterator2 = curStyles.iterator(); iterator2.hasNext();) { String object = (String) iterator2.next(); - l.removeStyleName(object); + this.l.removeStyleName(object); } } - + } diff --git a/src/com/itmill/toolkit/tests/TestForPreconfiguredComponents.java b/src/com/itmill/toolkit/tests/TestForPreconfiguredComponents.java index 69d06c869b..e108756c59 100644 --- a/src/com/itmill/toolkit/tests/TestForPreconfiguredComponents.java +++ b/src/com/itmill/toolkit/tests/TestForPreconfiguredComponents.java @@ -2,6 +2,7 @@ package com.itmill.toolkit.tests; import com.itmill.toolkit.event.Action; import com.itmill.toolkit.event.Action.Handler; +import com.itmill.toolkit.ui.AbstractSelect; import com.itmill.toolkit.ui.Button; import com.itmill.toolkit.ui.CheckBox; import com.itmill.toolkit.ui.Component; @@ -11,7 +12,6 @@ import com.itmill.toolkit.ui.NativeSelect; import com.itmill.toolkit.ui.OptionGroup; import com.itmill.toolkit.ui.OrderedLayout; import com.itmill.toolkit.ui.Panel; -import com.itmill.toolkit.ui.Select; import com.itmill.toolkit.ui.Tree; import com.itmill.toolkit.ui.TwinColSelect; import com.itmill.toolkit.ui.Button.ClickEvent; @@ -32,9 +32,9 @@ public class TestForPreconfiguredComponents extends CustomComponent implements "Smith", "Jones", "Beck", "Sheridan", "Picard", "Hill", "Fielding", "Einstein" }; - private OrderedLayout main = new OrderedLayout(); + private final OrderedLayout main = new OrderedLayout(); - private Action[] actions = new Action[] { new Action("edit"), + private final Action[] actions = new Action[] { new Action("edit"), new Action("delete") }; private Panel al; @@ -43,73 +43,73 @@ public class TestForPreconfiguredComponents extends CustomComponent implements public TestForPreconfiguredComponents() { - setCompositionRoot(main); + setCompositionRoot(this.main); createNewView(); } public void createNewView() { - main.removeAllComponents(); - main + this.main.removeAllComponents(); + this.main .addComponent(new Label( - "In TK5 we introduce some \"new\" componens. Earlier one" + - " usually used setStyle or some other methods on possibly " + - "multiple steps to configure component for ones needs. These new " + - "server side components are mostly just classes that in constructor " + - "set base class to state that programmer wants. This ought to help " + - "newcomers and make code more readable.")); + "In TK5 we introduce some \"new\" componens. Earlier one" + + " usually used setStyle or some other methods on possibly " + + "multiple steps to configure component for ones needs. These new " + + "server side components are mostly just classes that in constructor " + + "set base class to state that programmer wants. This ought to help " + + "newcomers and make code more readable.")); - main.addComponent(new Button("commit")); + this.main.addComponent(new Button("commit")); Panel test = createTestBench(new CheckBox()); test.setCaption("CheckBox (configured from button)"); - main.addComponent(test); + this.main.addComponent(test); - Select s = new TwinColSelect(); + AbstractSelect s = new TwinColSelect(); fillSelect(s, 20); test = createTestBench(s); test.setCaption("TwinColSelect (configured from select)"); - main.addComponent(test); + this.main.addComponent(test); s = new NativeSelect(); fillSelect(s, 20); test = createTestBench(s); test.setCaption("Native (configured from select)"); - main.addComponent(test); + this.main.addComponent(test); s = new OptionGroup(); fillSelect(s, 20); test = createTestBench(s); test.setCaption("OptionGroup (configured from select)"); - main.addComponent(test); + this.main.addComponent(test); s = new OptionGroup(); fillSelect(s, 20); s.setMultiSelect(true); test = createTestBench(s); - test.setCaption("OptionGroup + multiselect manually (configured from select)"); - main.addComponent(test); - - -// Tree t = createTestTree(); -// t.setCaption("with actions"); -// t.setImmediate(true); -// t.addActionHandler(this); -// Panel ol = (Panel) createTestBench(t); -// al = new Panel("action log"); -// ol.addComponent(al); -// main.addComponent(ol); -// contextTree = t; + test + .setCaption("OptionGroup + multiselect manually (configured from select)"); + this.main.addComponent(test); + + // Tree t = createTestTree(); + // t.setCaption("with actions"); + // t.setImmediate(true); + // t.addActionHandler(this); + // Panel ol = (Panel) createTestBench(t); + // al = new Panel("action log"); + // ol.addComponent(al); + // main.addComponent(ol); + // contextTree = t; Button b = new Button("refresh view", this, "createNewView"); - main.addComponent(b); + this.main.addComponent(b); } - - public static void fillSelect(Select s, int items) { + + public static void fillSelect(AbstractSelect s, int items) { for (int i = 0; i < items; i++) { String name = firstnames[(int) (Math.random() * (firstnames.length - 1))] - + " " - + lastnames[(int) (Math.random() * (lastnames.length - 1))]; + + " " + + lastnames[(int) (Math.random() * (lastnames.length - 1))]; s.addItem(name); } } @@ -117,24 +117,28 @@ public class TestForPreconfiguredComponents extends CustomComponent implements public Tree createTestTree() { Tree t = new Tree("Tree"); String[] names = new String[100]; - for (int i = 0; i < names.length; i++) + for (int i = 0; i < names.length; i++) { names[i] = firstnames[(int) (Math.random() * (firstnames.length - 1))] + " " + lastnames[(int) (Math.random() * (lastnames.length - 1))]; + } // Create tree t = new Tree("Organization Structure"); for (int i = 0; i < 100; i++) { t.addItem(names[i]); String parent = names[(int) (Math.random() * (names.length - 1))]; - if (t.containsId(parent)) + if (t.containsId(parent)) { t.setParent(names[i], parent); + } } // Forbid childless people to have children (makes them leaves) - for (int i = 0; i < 100; i++) - if (!t.hasChildren(names[i])) + for (int i = 0; i < 100; i++) { + if (!t.hasChildren(names[i])) { t.setChildrenAllowed(names[i], false); + } + } return t; } @@ -144,7 +148,8 @@ public class TestForPreconfiguredComponents extends CustomComponent implements ol.addComponent(t); - final OrderedLayout ol2 = new OrderedLayout(OrderedLayout.ORIENTATION_HORIZONTAL); + final OrderedLayout ol2 = new OrderedLayout( + OrderedLayout.ORIENTATION_HORIZONTAL); final Panel status = new Panel("Events"); final Button clear = new Button("clear event log"); clear.addListener(new ClickListener() { @@ -165,9 +170,7 @@ public class TestForPreconfiguredComponents extends CustomComponent implements t.addListener(new Listener() { public void componentEvent(Event event) { - status - .addComponent(new Label(event.getClass() - .getName())); + status.addComponent(new Label(event.getClass().getName())); status.addComponent(new Label("selected: " + event.getSource().toString())); } @@ -177,16 +180,16 @@ public class TestForPreconfiguredComponents extends CustomComponent implements } public Action[] getActions(Object target, Object sender) { - return actions; + return this.actions; } public void handleAction(Action action, Object sender, Object target) { - if (action == actions[1]) { - al.addComponent(new Label("Delete selected on " + target)); - contextTree.removeItem(target); + if (action == this.actions[1]) { + this.al.addComponent(new Label("Delete selected on " + target)); + this.contextTree.removeItem(target); } else { - al.addComponent(new Label("Edit selected on " + target)); + this.al.addComponent(new Label("Edit selected on " + target)); } } } diff --git a/src/com/itmill/toolkit/tests/TestForUpload.java b/src/com/itmill/toolkit/tests/TestForUpload.java index 91d79f40a0..05b8970411 100644 --- a/src/com/itmill/toolkit/tests/TestForUpload.java +++ b/src/com/itmill/toolkit/tests/TestForUpload.java @@ -86,7 +86,6 @@ public class TestForUpload extends CustomComponent implements this.main.addComponent(c); this.uploadBufferSelector = new Select("Receiver type"); - this.uploadBufferSelector.setColumns(6); this.uploadBufferSelector.setImmediate(true); this.uploadBufferSelector.addItem("memory"); this.uploadBufferSelector.setValue("memory"); diff --git a/src/com/itmill/toolkit/tests/TestForWindowing.java b/src/com/itmill/toolkit/tests/TestForWindowing.java index 2239dad873..1c20c81c87 100644 --- a/src/com/itmill/toolkit/tests/TestForWindowing.java +++ b/src/com/itmill/toolkit/tests/TestForWindowing.java @@ -2,6 +2,7 @@ package com.itmill.toolkit.tests; import com.itmill.toolkit.data.Property.ValueChangeEvent; import com.itmill.toolkit.data.Property.ValueChangeListener; +import com.itmill.toolkit.ui.AbstractSelect; import com.itmill.toolkit.ui.Button; import com.itmill.toolkit.ui.CustomComponent; import com.itmill.toolkit.ui.Label; @@ -12,60 +13,60 @@ import com.itmill.toolkit.ui.Window; import com.itmill.toolkit.ui.Button.ClickEvent; import com.itmill.toolkit.ui.Button.ClickListener; -public class TestForWindowing extends CustomComponent { - +public class TestForWindowing extends CustomComponent { + private Select s2; public TestForWindowing() { - + OrderedLayout main = new OrderedLayout(); - - main.addComponent(new Label("Click the button to create a new inline window.")); - + + main.addComponent(new Label( + "Click the button to create a new inline window.")); + Button create = new Button("Create a new window", new ClickListener() { public void buttonClick(ClickEvent event) { Window w = new Window("Testing Window"); - - Select s1 = new OptionGroup(); + + AbstractSelect s1 = new OptionGroup(); s1.setCaption("1. Select output format"); s1.addItem("Excel sheet"); s1.addItem("CSV plain text"); s1.setValue("Excel sheet"); - - s2 = new Select(); - s2.addItem("Separate by comma (,)"); - s2.addItem("Separate by colon (:)"); - s2.addItem("Separate by semicolon (;)"); - s2.setColumns(14); - s2.setEnabled(false); - + + TestForWindowing.this.s2 = new Select(); + TestForWindowing.this.s2.addItem("Separate by comma (,)"); + TestForWindowing.this.s2.addItem("Separate by colon (:)"); + TestForWindowing.this.s2.addItem("Separate by semicolon (;)"); + TestForWindowing.this.s2.setEnabled(false); + s1.addListener(new ValueChangeListener() { public void valueChange(ValueChangeEvent event) { - String v = (String) event.getProperty().getValue(); - if(v.equals("CSV plain text")) - s2.setEnabled(true); - else - s2.setEnabled(false); + String v = (String) event.getProperty().getValue(); + if (v.equals("CSV plain text")) { + TestForWindowing.this.s2.setEnabled(true); + } else { + TestForWindowing.this.s2.setEnabled(false); + } } - + }); - + w.addComponent(s1); - w.addComponent(s2); - + w.addComponent(TestForWindowing.this.s2); + getApplication().getMainWindow().addWindow(w); - + } - + }); - + main.addComponent(create); - + setCompositionRoot(main); - - } + } } diff --git a/src/com/itmill/toolkit/ui/AbstractSelect.java b/src/com/itmill/toolkit/ui/AbstractSelect.java new file mode 100644 index 0000000000..0d0fa88a4a --- /dev/null +++ b/src/com/itmill/toolkit/ui/AbstractSelect.java @@ -0,0 +1,1502 @@ +/* ************************************************************************* + + IT Mill Toolkit + + Development of Browser User Interfaces Made Easy + + Copyright (C) 2000-2006 IT Mill Ltd + + ************************************************************************* + + This product is distributed under commercial license that can be found + from the product package on license.pdf. Use of this product might + require purchasing a commercial license from IT Mill Ltd. For guidelines + on usage, see licensing-guidelines.html + + ************************************************************************* + + For more information, contact: + + IT Mill Ltd phone: +358 2 4802 7180 + Ruukinkatu 2-4 fax: +358 2 4802 7181 + 20540, Turku email: info@itmill.com + Finland company www: www.itmill.com + + Primary source for information and releases: www.itmill.com + + ********************************************************************** */ + +package com.itmill.toolkit.ui; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +import com.itmill.toolkit.data.Container; +import com.itmill.toolkit.data.Item; +import com.itmill.toolkit.data.Property; +import com.itmill.toolkit.data.util.IndexedContainer; +import com.itmill.toolkit.terminal.KeyMapper; +import com.itmill.toolkit.terminal.PaintException; +import com.itmill.toolkit.terminal.PaintTarget; +import com.itmill.toolkit.terminal.Resource; + +/** + *

+ * A class representing a selection of items the user has selected in a UI. The + * set of choices is presented as a set of {@link com.itmill.toolkit.data.Item}s + * in a {@link com.itmill.toolkit.data.Container}. + *

+ * + *

+ * A Select component may be in single- or multiselect mode. + * Multiselect mode means that more than one item can be selected + * simultaneously. + *

+ * + * @author IT Mill Ltd. + * @version + * @VERSION@ + * @since 3.0 + */ +public abstract class AbstractSelect extends AbstractField implements + Container, Container.Viewer, Container.PropertySetChangeListener, + Container.PropertySetChangeNotifier, Container.ItemSetChangeNotifier, + Container.ItemSetChangeListener { + + /** + * Item caption mode: Item's ID's String representation is + * used as caption. + */ + public static final int ITEM_CAPTION_MODE_ID = 0; + /** + * Item caption mode: Item's String representation is used as + * caption. + */ + public static final int ITEM_CAPTION_MODE_ITEM = 1; + /** + * Item caption mode: Index of the item is used as caption. The index mode + * can only be used with the containers implementing the + * {@link com.itmill.toolkit.data.Container.Indexed} interface. + */ + public static final int ITEM_CAPTION_MODE_INDEX = 2; + /** + * Item caption mode: If an Item has a caption it's used, if not, Item's + * ID's String representation is used as caption. This is + * the default. + */ + public static final int ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = 3; + /** + * Item caption mode: Captions must be explicitly specified. + */ + public static final int ITEM_CAPTION_MODE_EXPLICIT = 4; + /** + * Item caption mode: Only icons are shown, captions are hidden. + */ + public static final int ITEM_CAPTION_MODE_ICON_ONLY = 5; + /** + * Item caption mode: Item captions are read from property specified with + * setItemCaptionPropertyId. + */ + public static final int ITEM_CAPTION_MODE_PROPERTY = 6; + + /** + * Interface for option filtering, used to filter options based on user + * entered value. The value is matched to the item caption. + * FILTERINGMODE_OFF (0) turns the filtering off. + * FILTERINGMODE_STARTSWITH (1) matches from the start of the + * caption. FILTERINGMODE_CONTAINS (1) matches anywhere in + * the caption. + */ + public interface Filtering { + public static final int FILTERINGMODE_OFF = 0; + public static final int FILTERINGMODE_STARTSWITH = 1; + public static final int FILTERINGMODE_CONTAINS = 2; + + /** + * Sets the option filtering mode. + * + * @param filteringMode + * the filtering mode to use + */ + public void setFilteringMode(int filteringMode); + + /** + * Gets the current filtering mode. + * + * @return the filtering mode in use + */ + public int getFilteringMode(); + + } + + /** + * Is the select in multiselect mode? + */ + private boolean multiSelect = false; + + /** + * Select options. + */ + protected Container items; + + /** + * Is the user allowed to add new options? + */ + private boolean allowNewOptions; + + /** + * Keymapper used to map key values. + */ + protected KeyMapper itemIdMapper = new KeyMapper(); + + /** + * Item icons. + */ + private final HashMap itemIcons = new HashMap(); + + /** + * Item captions. + */ + private final HashMap itemCaptions = new HashMap(); + + /** + * Item caption mode. + */ + private int itemCaptionMode = ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID; + + /** + * Item caption source property id. + */ + private Object itemCaptionPropertyId = null; + + /** + * Item icon source property id. + */ + private Object itemIconPropertyId = null; + + /** + * List of property set change event listeners. + */ + private LinkedList propertySetEventListeners = null; + + /** + * List of item set change event listeners. + */ + private LinkedList itemSetEventListeners = null; + + /** + * Item id that represents null selection of this select. + * + *

+ * Data interface does not support nulls as item ids. Selecting the item + * idetified by this id is the same as selecting no items at all. This + * setting only affects the single select mode. + *

+ */ + private Object nullSelectionItemId = null; + + // Null (empty) selection is enabled by default + private boolean nullSelectionAllowed = true; + + /* Constructors ********************************************************* */ + + /** + * Creates an empty Select. The caption is not used. + */ + public AbstractSelect() { + setContainerDataSource(new IndexedContainer()); + } + + /** + * Creates an empty Select with caption. + */ + public AbstractSelect(String caption) { + setContainerDataSource(new IndexedContainer()); + setCaption(caption); + } + + /** + * Creates a new select that is connected to a data-source. + * + * @param caption + * the Caption of the component. + * @param dataSource + * the Container datasource to be selected from by this select. + */ + public AbstractSelect(String caption, Container dataSource) { + setCaption(caption); + setContainerDataSource(dataSource); + } + + /** + * Creates a new select that is filled from a collection of option values. + * + * @param caption + * the Caption of this field. + * @param options + * the Collection containing the options. + */ + public AbstractSelect(String caption, Collection options) { + + // Creates the options container and add given options to it + Container c = new IndexedContainer(); + if (options != null) { + for (Iterator i = options.iterator(); i.hasNext();) { + c.addItem(i.next()); + } + } + + setCaption(caption); + setContainerDataSource(c); + } + + /* Component methods **************************************************** */ + + /** + * Paints the content of this component. + * + * @param target + * the Paint Event. + * @throws PaintException + * if the paint operation failed. + */ + public void paintContent(PaintTarget target) throws PaintException { + + // Paints field properties + super.paintContent(target); + + // Paints select attributes + if (isMultiSelect()) { + target.addAttribute("selectmode", "multi"); + } + if (isNewItemsAllowed()) { + target.addAttribute("allownewitem", true); + } + if (!isNullSelectionAllowed()) { + target.addAttribute("nullselect", false); + } + + // Constructs selected keys array + String[] selectedKeys; + if (isMultiSelect()) { + selectedKeys = new String[((Set) getValue()).size()]; + } else { + selectedKeys = new String[(getValue() == null + && getNullSelectionItemId() == null ? 0 : 1)]; + } + + // == + // Paints the options and create array of selected id keys + target.startTag("options"); + int keyIndex = 0; + // Support for external null selection item id + Collection ids = getItemIds(); + if (getNullSelectionItemId() != null + && (!ids.contains(getNullSelectionItemId()))) { + // Gets the option attribute values + Object id = getNullSelectionItemId(); + String key = this.itemIdMapper.key(id); + String caption = getItemCaption(id); + Resource icon = getItemIcon(id); + // Paints option + target.startTag("so"); + if (icon != null) { + target.addAttribute("icon", icon); + } + target.addAttribute("caption", caption); + target.addAttribute("nullselection", true); + target.addAttribute("key", key); + if (isSelected(id)) { + target.addAttribute("selected", true); + selectedKeys[keyIndex++] = key; + } + target.endTag("so"); + } + + Iterator i = getItemIds().iterator(); + // Paints the available selection options from data source + while (i.hasNext()) { + // Gets the option attribute values + Object id = i.next(); + String key = this.itemIdMapper.key(id); + String caption = getItemCaption(id); + Resource icon = getItemIcon(id); // Paints the option + target.startTag("so"); + if (icon != null) { + target.addAttribute("icon", icon); + } + target.addAttribute("caption", caption); + if (id != null && id.equals(getNullSelectionItemId())) { + target.addAttribute("nullselection", true); + } + target.addAttribute("key", key); + if (isSelected(id) && keyIndex < selectedKeys.length) { + target.addAttribute("selected", true); + selectedKeys[keyIndex++] = key; + } + target.endTag("so"); + } + target.endTag("options"); + // == + + // Paint variables + target.addVariable(this, "selected", selectedKeys); + if (isNewItemsAllowed()) { + target.addVariable(this, "newitem", ""); + } + + } + + /** + * Invoked when the value of a variable has changed. + * + * @see com.itmill.toolkit.ui.AbstractComponent#changeVariables(java.lang.Object, + * java.util.Map) + */ + public void changeVariables(Object source, Map variables) { + // Try to set the property value + + // New option entered (and it is allowed) + String newitem = (String) variables.get("newitem"); + if (newitem != null && newitem.length() > 0) { + + // Checks for readonly + if (isReadOnly()) { + throw new Property.ReadOnlyException(); + } + + // Adds new option + if (addItem(newitem) != null) { + + // Sets the caption property, if used + if (getItemCaptionPropertyId() != null) { + try { + getContainerProperty(newitem, + getItemCaptionPropertyId()).setValue(newitem); + } catch (Property.ConversionException ignored) { + // The conversion exception is safely ignored, the + // caption is + // just missing + } + } + } + } + + // Selection change + if (variables.containsKey("selected")) { + String[] ka = (String[]) variables.get("selected"); + + // Multiselect mode + if (isMultiSelect()) { + + // TODO Optimize by adding repaintNotNeeded when applicable + + // Converts the key-array to id-set + LinkedList s = new LinkedList(); + for (int i = 0; i < ka.length; i++) { + Object id = this.itemIdMapper.get(ka[i]); + if (id != null && containsId(id)) { + s.add(id); + } else if (this.itemIdMapper.isNewIdKey(ka[i]) + && newitem != null && newitem.length() > 0) { + s.add(newitem); + } + } + + // Limits the deselection to the set of visible items + // (non-visible items can not be deselected) + Collection visible = getVisibleItemIds(); + if (visible != null) { + Set newsel = (Set) getValue(); + if (newsel == null) { + newsel = new HashSet(); + } else { + newsel = new HashSet(newsel); + } + newsel.removeAll(visible); + newsel.addAll(s); + setValue(newsel, true); + } + } else { + // Single select mode + if (ka.length == 0) { + // Allows deselection only if the deselected item is visible + Object current = getValue(); + Collection visible = getVisibleItemIds(); + if (visible != null && visible.contains(current)) { + setValue(null, true); + } + } else { + Object id = this.itemIdMapper.get(ka[0]); + if (id != null && id.equals(getNullSelectionItemId())) { + setValue(null, true); + } else if (this.itemIdMapper.isNewIdKey(ka[0])) { + setValue(newitem); + } else { + setValue(id, true); + } + } + } + } + } + + /** + * Gets the component UIDL tag. + * + * @return the Component UIDL tag as string. + */ + public String getTag() { + return "select"; + } + + /** + * Gets the visible item ids. In Select, this returns list of all item ids, + * but can be overriden in subclasses if they paint only part of the items + * to the terminal or null if no items is visible. + */ + public Collection getVisibleItemIds() { + if (isVisible()) { + return getItemIds(); + } + return null; + } + + /* Property methods ***************************************************** */ + + /** + * Returns the type of the property. getValue and + * setValue methods must be compatible with this type: one + * can safely cast getValue to given type and pass any + * variable assignable to this type as a parameter to setValue. + * + * @return the Type of the property. + */ + public Class getType() { + if (isMultiSelect()) { + return Set.class; + } else { + return Object.class; + } + } + + /** + * Gets the selected item id or in multiselect mode a set of selected ids. + * + * @see com.itmill.toolkit.ui.AbstractField#getValue() + */ + public Object getValue() { + Object retValue = super.getValue(); + + if (isMultiSelect()) { + + // If the return value is not a set + if (retValue == null) { + return new HashSet(); + } + if (retValue instanceof Set) { + return Collections.unmodifiableSet((Set) retValue); + } else if (retValue instanceof Collection) { + return new HashSet((Collection) retValue); + } else { + Set s = new HashSet(); + if (this.items.containsId(retValue)) { + s.add(retValue); + } + return s; + } + + } else { + return retValue; + } + } + + /** + * Sets the visible value of the property. + * + *

+ * The value of the select is the selected item id. If the select is in + * multiselect-mode, the value is a set of selected item keys. In + * multiselect mode all collections of id:s can be assigned. + *

+ * + * @param newValue + * the New selected item or collection of selected items. + * @see com.itmill.toolkit.ui.AbstractField#setValue(java.lang.Object) + */ + public void setValue(Object newValue) throws Property.ReadOnlyException, + Property.ConversionException { + setValue(newValue, false); + } + + /** + * Sets the visible value of the property. + * + *

+ * The value of the select is the selected item id. If the select is in + * multiselect-mode, the value is a set of selected item keys. In + * multiselect mode all collections of id:s can be assigned. + *

+ * + * @param newValue + * the New selected item or collection of selected items. + * @param repaintIsNotNeeded + * True if caller is sure that repaint is not needed. + * @see com.itmill.toolkit.ui.AbstractField#setValue(java.lang.Object, + * java.lang.Boolean) + */ + protected void setValue(Object newValue, boolean repaintIsNotNeeded) + throws Property.ReadOnlyException, Property.ConversionException { + + if (isMultiSelect()) { + if (newValue == null) { + super.setValue(new HashSet(), repaintIsNotNeeded); + } else if (Collection.class.isAssignableFrom(newValue.getClass())) { + super.setValue(new HashSet((Collection) newValue), + repaintIsNotNeeded); + } + } else if (newValue == null || this.items.containsId(newValue)) { + super.setValue(newValue, repaintIsNotNeeded); + } + } + + /* Container methods **************************************************** */ + + /** + * Gets the item from the container with given id. If the container does not + * contain the requested item, null is returned. + * + * @param itemId + * the item id. + * @return the item from the container. + */ + public Item getItem(Object itemId) { + return this.items.getItem(itemId); + } + + /** + * Gets the item Id collection from the container. + * + * @return the Collection of item ids. + */ + public Collection getItemIds() { + return this.items.getItemIds(); + } + + /** + * Gets the property Id collection from the container. + * + * @return the Collection of property ids. + */ + public Collection getContainerPropertyIds() { + return this.items.getContainerPropertyIds(); + } + + /** + * Gets the property type. + * + * @param propertyId + * the Id identifying the property. + * @see com.itmill.toolkit.data.Container#getType(java.lang.Object) + */ + public Class getType(Object propertyId) { + return this.items.getType(propertyId); + } + + /* + * Gets the number of items in the container. + * + * @return the Number of items in the container. + * + * @see com.itmill.toolkit.data.Container#size() + */ + public int size() { + return this.items.size(); + } + + /** + * Tests, if the collection contains an item with given id. + * + * @param itemId + * the Id the of item to be tested. + */ + public boolean containsId(Object itemId) { + if (itemId != null) { + return this.items.containsId(itemId); + } else { + return false; + } + } + + /** + * Gets the Property identified by the given itemId and propertyId from the + * Container + * + * @see com.itmill.toolkit.data.Container#getContainerProperty(Object, + * Object) + */ + public Property getContainerProperty(Object itemId, Object propertyId) { + return this.items.getContainerProperty(itemId, propertyId); + } + + /* Container.Managed methods ******************************************** */ + + /** + * Adds the new property to all items. Adds a property with given id, type + * and default value to all items in the container. + * + * This functionality is optional. If the function is unsupported, it always + * returns false. + * + * @return True if the operation succeeded. + * @see com.itmill.toolkit.data.Container#addContainerProperty(java.lang.Object, + * java.lang.Class, java.lang.Object) + */ + public boolean addContainerProperty(Object propertyId, Class type, + Object defaultValue) throws UnsupportedOperationException { + + boolean retval = this.items.addContainerProperty(propertyId, type, + defaultValue); + if (retval + && !(this.items instanceof Container.PropertySetChangeNotifier)) { + firePropertySetChange(); + } + return retval; + } + + /** + * Removes all items from the container. + * + * This functionality is optional. If the function is unsupported, it always + * returns false. + * + * @return True if the operation succeeded. + * @see com.itmill.toolkit.data.Container#removeAllItems() + */ + public boolean removeAllItems() throws UnsupportedOperationException { + + boolean retval = this.items.removeAllItems(); + this.itemIdMapper.removeAll(); + if (retval) { + setValue(null); + if (!(this.items instanceof Container.ItemSetChangeNotifier)) { + fireItemSetChange(); + } + } + return retval; + } + + /** + * Creates a new item into container with container managed id. The id of + * the created new item is returned. The item can be fetched with getItem() + * method. if the creation fails, null is returned. + * + * @return the Id of the created item or null in case of failure. + * @see com.itmill.toolkit.data.Container#addItem() + */ + public Object addItem() throws UnsupportedOperationException { + + Object retval = this.items.addItem(); + if (retval != null + && !(this.items instanceof Container.ItemSetChangeNotifier)) { + fireItemSetChange(); + } + return retval; + } + + /** + * Create a new item into container. The created new item is returned and + * ready for setting property values. if the creation fails, null is + * returned. In case the container already contains the item, null is + * returned. + * + * This functionality is optional. If the function is unsupported, it always + * returns null. + * + * @param itemId + * the Identification of the item to be created. + * @return the Created item with the given id, or null in case of failure. + * @see com.itmill.toolkit.data.Container#addItem(java.lang.Object) + */ + public Item addItem(Object itemId) throws UnsupportedOperationException { + + Item retval = this.items.addItem(itemId); + if (retval != null + && !(this.items instanceof Container.ItemSetChangeNotifier)) { + fireItemSetChange(); + } + return retval; + } + + /** + * Removes the item identified by Id from the container. This functionality + * is optional. If the function is not implemented, the functions allways + * returns false. + * + * @return True if the operation succeeded. + * @see com.itmill.toolkit.data.Container#removeItem(java.lang.Object) + */ + public boolean removeItem(Object itemId) + throws UnsupportedOperationException { + + unselect(itemId); + boolean retval = this.items.removeItem(itemId); + this.itemIdMapper.remove(itemId); + if (retval && !(this.items instanceof Container.ItemSetChangeNotifier)) { + fireItemSetChange(); + } + return retval; + } + + /** + * Removes the property from all items. Removes a property with given id + * from all the items in the container. + * + * This functionality is optional. If the function is unsupported, it always + * returns false. + * + * @return True if the operation succeeded. + * @see com.itmill.toolkit.data.Container#removeContainerProperty(java.lang.Object) + */ + public boolean removeContainerProperty(Object propertyId) + throws UnsupportedOperationException { + + boolean retval = this.items.removeContainerProperty(propertyId); + if (retval + && !(this.items instanceof Container.PropertySetChangeNotifier)) { + firePropertySetChange(); + } + return retval; + } + + /* Container.Viewer methods ********************************************* */ + + /** + * Sets the container as data-source for viewing. + * + * @param newDataSource + * the new data source. + */ + public void setContainerDataSource(Container newDataSource) { + if (newDataSource == null) { + newDataSource = new IndexedContainer(); + } + + if (this.items != newDataSource) { + + // Removes listeners from the old datasource + if (this.items != null) { + try { + ((Container.ItemSetChangeNotifier) this.items) + .removeListener(this); + } catch (ClassCastException ignored) { + // Ignored + } + try { + ((Container.PropertySetChangeNotifier) this.items) + .removeListener(this); + } catch (ClassCastException ignored) { + // Ignored + } + } + + // Assigns new data source + this.items = newDataSource; + + // Clears itemIdMapper also + this.itemIdMapper.removeAll(); + + // Adds listeners + if (this.items != null) { + try { + ((Container.ItemSetChangeNotifier) this.items) + .addListener(this); + } catch (ClassCastException ignored) { + // Ignored + } + try { + ((Container.PropertySetChangeNotifier) this.items) + .addListener(this); + } catch (ClassCastException ignored) { + // Ignored + } + } + + // TODO: This should be conditional + fireValueChange(false); + } + } + + /** + * Gets the viewing data-source container. + * + * @see com.itmill.toolkit.data.Container.Viewer#getContainerDataSource() + */ + public Container getContainerDataSource() { + return this.items; + } + + /* Select attributes **************************************************** */ + + /** + * Is the select in multiselect mode? In multiselect mode + * + * @return the Value of property multiSelect. + */ + public boolean isMultiSelect() { + return this.multiSelect; + } + + /** + * Sets the multiselect mode. Setting multiselect mode false may loose + * selection information: if selected items set contains one or more + * selected items, only one of the selected items is kept as selected. + * + * @param multiSelect + * the New value of property multiSelect. + */ + public void setMultiSelect(boolean multiSelect) { + + if (multiSelect != this.multiSelect) { + + // Selection before mode change + Object oldValue = getValue(); + + this.multiSelect = multiSelect; + + // Convert the value type + if (multiSelect) { + Set s = new HashSet(); + if (oldValue != null) { + s.add(oldValue); + } + setValue(s); + } else { + Set s = (Set) oldValue; + if (s == null || s.isEmpty()) { + setValue(null); + } else { + // Set the single select to contain only the first + // selected value in the multiselect + setValue(s.iterator().next()); + } + } + + requestRepaint(); + } + } + + /** + * Does the select allow adding new options by the user. If true, the new + * options can be added to the Container. The text entered by the user is + * used as id. No that data-source must allow adding new items (it must + * implement Container.Managed). + * + * @return True if additions are allowed. + */ + public boolean isNewItemsAllowed() { + + return this.allowNewOptions; + } + + /** + * Enables or disables possibility to add new options by the user. + * + * @param allowNewOptions + * the New value of property allowNewOptions. + */ + public void setNewItemsAllowed(boolean allowNewOptions) { + + // Only handle change requests + if (this.allowNewOptions != allowNewOptions) { + + this.allowNewOptions = allowNewOptions; + + requestRepaint(); + } + } + + /** + * Override the caption of an item. Setting caption explicitly overrides id, + * item and index captions. + * + * @param itemId + * the id of the item to be recaptioned. + * @param caption + * the New caption. + */ + public void setItemCaption(Object itemId, String caption) { + if (itemId != null) { + this.itemCaptions.put(itemId, caption); + requestRepaint(); + } + } + + /** + * Gets the caption of an item. The caption is generated as specified by the + * item caption mode. See setItemCaptionMode() for more + * details. + * + * @param itemId + * the id of the item to be queried. + * @return the caption for specified item. + */ + public String getItemCaption(Object itemId) { + + // Null items can not be found + if (itemId == null) { + return null; + } + + String caption = null; + + switch (getItemCaptionMode()) { + + case ITEM_CAPTION_MODE_ID: + caption = itemId.toString(); + break; + + case ITEM_CAPTION_MODE_INDEX: + try { + caption = String.valueOf(((Container.Indexed) this.items) + .indexOfId(itemId)); + } catch (ClassCastException ignored) { + } + break; + + case ITEM_CAPTION_MODE_ITEM: + Item i = getItem(itemId); + if (i != null) { + caption = i.toString(); + } + break; + + case ITEM_CAPTION_MODE_EXPLICIT: + caption = (String) this.itemCaptions.get(itemId); + break; + + case ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID: + caption = (String) this.itemCaptions.get(itemId); + if (caption == null) { + caption = itemId.toString(); + } + break; + + case ITEM_CAPTION_MODE_PROPERTY: + Property p = getContainerProperty(itemId, + getItemCaptionPropertyId()); + if (p != null) { + caption = p.toString(); + } + break; + } + + // All items must have some captions + return caption != null ? caption : ""; + } + + /** + * Sets the icon for an item. + * + * @param itemId + * the id of the item to be assigned an icon. + * @param icon + * the New icon. + */ + public void setItemIcon(Object itemId, Resource icon) { + if (itemId != null) { + if (icon == null) { + this.itemIcons.remove(itemId); + } else { + this.itemIcons.put(itemId, icon); + } + requestRepaint(); + } + } + + /** + * Gets the item icon. + * + * @param itemId + * the id of the item to be assigned an icon. + * @return the Icon for the item or null, if not specified. + */ + public Resource getItemIcon(Object itemId) { + Resource explicit = (Resource) this.itemIcons.get(itemId); + if (explicit != null) { + return explicit; + } + + if (getItemIconPropertyId() == null) { + return null; + } + + Property ip = getContainerProperty(itemId, getItemIconPropertyId()); + if (ip == null) { + return null; + } + Object icon = ip.getValue(); + if (icon instanceof Resource) { + return (Resource) icon; + } + + return null; + } + + /** + * Sets the item caption mode. + * + *

+ * The mode can be one of the following ones: + *

+ * The ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID is the default + * mode. + *

+ * + * @param mode + * the One of the modes listed above. + */ + public void setItemCaptionMode(int mode) { + if (ITEM_CAPTION_MODE_ID <= mode && mode <= ITEM_CAPTION_MODE_PROPERTY) { + this.itemCaptionMode = mode; + requestRepaint(); + } + } + + /** + * Gets the item caption mode. + * + *

+ * The mode can be one of the following ones: + *

+ * The ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID is the default + * mode. + *

+ * + * @return the One of the modes listed above. + */ + public int getItemCaptionMode() { + return this.itemCaptionMode; + } + + /** + * Sets the item caption property. + * + *

+ * Setting the id to a existing property implicitly sets the item caption + * mode to ITEM_CAPTION_MODE_PROPERTY. If the object is in + * ITEM_CAPTION_MODE_PROPERTY mode, setting caption property + * id null resets the item caption mode to + * ITEM_CAPTION_EXPLICIT_DEFAULTS_ID. + *

+ * + *

+ * Setting the property id to null disables this feature. The id is null by + * default + *

. + * + * @param propertyId + * the id of the property. + * + */ + public void setItemCaptionPropertyId(Object propertyId) { + if (propertyId != null) { + this.itemCaptionPropertyId = propertyId; + setItemCaptionMode(ITEM_CAPTION_MODE_PROPERTY); + requestRepaint(); + } else { + this.itemCaptionPropertyId = null; + if (getItemCaptionMode() == ITEM_CAPTION_MODE_PROPERTY) { + setItemCaptionMode(ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID); + } + requestRepaint(); + } + } + + /** + * Gets the item caption property. + * + * @return the Id of the property used as item caption source. + */ + public Object getItemCaptionPropertyId() { + return this.itemCaptionPropertyId; + } + + /** + * Sets the item icon property. + * + *

+ * If the property id is set to a valid value, each item is given an icon + * got from the given property of the items. The type of the property must + * be assignable to Icon. + *

+ * + *

+ * Note : The icons set with setItemIcon function override + * the icons from the property. + *

+ * + *

+ * Setting the property id to null disables this feature. The id is null by + * default + *

. + * + * @param propertyId + * the Id of the property that specifies icons for items. + */ + public void setItemIconPropertyId(Object propertyId) { + if ((propertyId != null) + && Resource.class.isAssignableFrom(getType(propertyId))) { + this.itemIconPropertyId = propertyId; + requestRepaint(); + } else { + this.itemIconPropertyId = null; + } + } + + /** + * Gets the item icon property. + * + *

+ * If the property id is set to a valid value, each item is given an icon + * got from the given property of the items. The type of the property must + * be assignable to Icon. + *

+ * + *

+ * Note : The icons set with setItemIcon function override + * the icons from the property. + *

+ * + *

+ * Setting the property id to null disables this feature. The id is null by + * default + *

. + * + * @return the Id of the property containing the item icons. + */ + public Object getItemIconPropertyId() { + return this.itemIconPropertyId; + } + + /** + * Tests if an item is selected. + * + *

+ * In single select mode testing selection status of the item identified by + * {@link #getNullSelectionItemId()} returns true if the value of the + * property is null. + *

+ * + * @param itemId + * the Id the of the item to be tested. + * @see #getNullSelectionItemId() + * @see #setNullSelectionItemId(Object) + * + */ + public boolean isSelected(Object itemId) { + if (itemId == null) { + return false; + } + if (isMultiSelect()) { + return ((Set) getValue()).contains(itemId); + } else { + Object value = getValue(); + return itemId.equals(value == null ? getNullSelectionItemId() + : value); + } + } + + /** + * Selects an item. + * + *

+ * In single select mode selecting item identified by + * {@link #getNullSelectionItemId()} sets the value of the property to null. + *

+ * + * @param itemId + * the tem to be selected. + * @see #getNullSelectionItemId() + * @see #setNullSelectionItemId(Object) + * + */ + public void select(Object itemId) { + if (!isSelected(itemId) && this.items.containsId(itemId)) { + if (isMultiSelect()) { + Set s = new HashSet((Set) getValue()); + s.add(itemId); + setValue(s); + } else if (itemId.equals(getNullSelectionItemId())) { + setValue(null); + } else { + setValue(itemId); + } + } + } + + /** + * Unselects an item. + * + * @param itemId + * the Item to be unselected. + * @see #getNullSelectionItemId() + * @see #setNullSelectionItemId(Object) + * + */ + public void unselect(Object itemId) { + if (isSelected(itemId)) { + if (isMultiSelect()) { + Set s = new HashSet((Set) getValue()); + s.remove(itemId); + setValue(s); + } else { + setValue(null); + } + } + } + + /** + * Notifies this listener that the Containers contents has changed. + * + * @see com.itmill.toolkit.data.Container.PropertySetChangeListener#containerPropertySetChange(com.itmill.toolkit.data.Container.PropertySetChangeEvent) + */ + public void containerPropertySetChange( + Container.PropertySetChangeEvent event) { + firePropertySetChange(); + } + + /** + * Adds a new Property set change listener for this Container. + * + * @see com.itmill.toolkit.data.Container.PropertySetChangeNotifier#addListener(com.itmill.toolkit.data.Container.PropertySetChangeListener) + */ + public void addListener(Container.PropertySetChangeListener listener) { + if (this.propertySetEventListeners == null) { + this.propertySetEventListeners = new LinkedList(); + } + this.propertySetEventListeners.add(listener); + } + + /** + * Removes a previously registered Property set change listener. + * + * @see com.itmill.toolkit.data.Container.PropertySetChangeNotifier#removeListener(com.itmill.toolkit.data.Container.PropertySetChangeListener) + */ + public void removeListener(Container.PropertySetChangeListener listener) { + if (this.propertySetEventListeners != null) { + this.propertySetEventListeners.remove(listener); + if (this.propertySetEventListeners.isEmpty()) { + this.propertySetEventListeners = null; + } + } + } + + /** + * Adds an Item set change listener for the object. + * + * @see com.itmill.toolkit.data.Container.ItemSetChangeNotifier#addListener(com.itmill.toolkit.data.Container.ItemSetChangeListener) + */ + public void addListener(Container.ItemSetChangeListener listener) { + if (this.itemSetEventListeners == null) { + this.itemSetEventListeners = new LinkedList(); + } + this.itemSetEventListeners.add(listener); + } + + /** + * Removes the Item set change listener from the object. + * + * @see com.itmill.toolkit.data.Container.ItemSetChangeNotifier#removeListener(com.itmill.toolkit.data.Container.ItemSetChangeListener) + */ + public void removeListener(Container.ItemSetChangeListener listener) { + if (this.itemSetEventListeners != null) { + this.itemSetEventListeners.remove(listener); + if (this.itemSetEventListeners.isEmpty()) { + this.itemSetEventListeners = null; + } + } + } + + /** + * Lets the listener know a Containers Item set has changed. + * + * @see com.itmill.toolkit.data.Container.ItemSetChangeListener#containerItemSetChange(com.itmill.toolkit.data.Container.ItemSetChangeEvent) + */ + public void containerItemSetChange(Container.ItemSetChangeEvent event) { + // Clears the item id mapping table + this.itemIdMapper.removeAll(); + + // Notify all listeners + fireItemSetChange(); + } + + /** + * Fires the property set change event. + */ + protected void firePropertySetChange() { + if (this.propertySetEventListeners != null + && !this.propertySetEventListeners.isEmpty()) { + Container.PropertySetChangeEvent event = new PropertySetChangeEvent(); + Object[] listeners = this.propertySetEventListeners.toArray(); + for (int i = 0; i < listeners.length; i++) { + ((Container.PropertySetChangeListener) listeners[i]) + .containerPropertySetChange(event); + } + } + requestRepaint(); + } + + /** + * Fires the item set change event. + */ + protected void fireItemSetChange() { + if (this.itemSetEventListeners != null + && !this.itemSetEventListeners.isEmpty()) { + Container.ItemSetChangeEvent event = new ItemSetChangeEvent(); + Object[] listeners = this.itemSetEventListeners.toArray(); + for (int i = 0; i < listeners.length; i++) { + ((Container.ItemSetChangeListener) listeners[i]) + .containerItemSetChange(event); + } + } + requestRepaint(); + } + + /** + * Implementation of item set change event. + */ + private class ItemSetChangeEvent implements Container.ItemSetChangeEvent { + + /** + * Gets the Property where the event occurred. + * + * @see com.itmill.toolkit.data.Container.ItemSetChangeEvent#getContainer() + */ + public Container getContainer() { + return AbstractSelect.this; + } + + } + + /** + * Implementation of property set change event. + */ + private class PropertySetChangeEvent implements + Container.PropertySetChangeEvent { + + /** + * Retrieves the Container whose contents have been modified. + * + * @see com.itmill.toolkit.data.Container.PropertySetChangeEvent#getContainer() + */ + public Container getContainer() { + return AbstractSelect.this; + } + + } + + // TODO javadoc + public void setNullSelectionAllowed(boolean nullSelectionAllowed) { + this.nullSelectionAllowed = nullSelectionAllowed; + } + + // TODO javadoc + public boolean isNullSelectionAllowed() { + return this.nullSelectionAllowed; + } + + /** + * Returns the item id that represents null value of this select in single + * select mode. + * + *

+ * Data interface does not support nulls as item ids. Selecting the item + * idetified by this id is the same as selecting no items at all. This + * setting only affects the single select mode. + *

+ * + * @return the Object Null value item id. + * @see #setNullSelectionItemId(Object) + * @see #isSelected(Object) + * @see #select(Object) + */ + public final Object getNullSelectionItemId() { + return this.nullSelectionItemId; + } + + /** + * Sets the item id that represents null value of this select. + * + *

+ * Data interface does not support nulls as item ids. Selecting the item + * idetified by this id is the same as selecting no items at all. This + * setting only affects the single select mode. + *

+ * + * @param nullSelectionItemId + * the nullSelectionItemId to set. + * @see #getNullSelectionItemId() + * @see #isSelected(Object) + * @see #select(Object) + */ + public void setNullSelectionItemId(Object nullSelectionItemId) { + this.nullSelectionItemId = nullSelectionItemId; + } + + /** + * Notifies the component that it is connected to an application. + * + * @see com.itmill.toolkit.ui.AbstractField#attach() + */ + public void attach() { + super.attach(); + } + + /** + * Detaches the component from application. + * + * @see com.itmill.toolkit.ui.AbstractComponent#detach() + */ + public void detach() { + super.detach(); + } + +} diff --git a/src/com/itmill/toolkit/ui/NativeSelect.java b/src/com/itmill/toolkit/ui/NativeSelect.java index 187069e8c7..8de651ebd6 100644 --- a/src/com/itmill/toolkit/ui/NativeSelect.java +++ b/src/com/itmill/toolkit/ui/NativeSelect.java @@ -10,17 +10,17 @@ import com.itmill.toolkit.terminal.PaintException; import com.itmill.toolkit.terminal.PaintTarget; /** - * Since TK5 default select is customized component with mane advanced features + * Since TK5 default select is customized component with many advanced features * over terminals native select components. Sometimes "native" select may still * be the best option. Terminal renders this select with its native select * widget. */ -public class NativeSelect extends Select { +public class NativeSelect extends AbstractSelect { public NativeSelect() { super(); } - + public NativeSelect(String caption, Collection options) { super(caption, options); } diff --git a/src/com/itmill/toolkit/ui/OptionGroup.java b/src/com/itmill/toolkit/ui/OptionGroup.java index b5bb594563..f58667c43e 100644 --- a/src/com/itmill/toolkit/ui/OptionGroup.java +++ b/src/com/itmill/toolkit/ui/OptionGroup.java @@ -12,7 +12,7 @@ import com.itmill.toolkit.terminal.PaintTarget; /** * Configures select to be used as an option group. */ -public class OptionGroup extends Select { +public class OptionGroup extends AbstractSelect { public OptionGroup() { super(); diff --git a/src/com/itmill/toolkit/ui/Select.java b/src/com/itmill/toolkit/ui/Select.java index 961e0c9b01..e56666f3ad 100644 --- a/src/com/itmill/toolkit/ui/Select.java +++ b/src/com/itmill/toolkit/ui/Select.java @@ -29,24 +29,18 @@ package com.itmill.toolkit.ui; import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; import com.itmill.toolkit.data.Container; -import com.itmill.toolkit.data.Item; import com.itmill.toolkit.data.Property; -import com.itmill.toolkit.data.util.IndexedContainer; -import com.itmill.toolkit.terminal.KeyMapper; import com.itmill.toolkit.terminal.PaintException; import com.itmill.toolkit.terminal.PaintTarget; import com.itmill.toolkit.terminal.Resource; -import com.itmill.toolkit.ui.select.OptionFilter; -import com.itmill.toolkit.ui.select.StartsWithFilter; /** *

@@ -66,199 +60,42 @@ import com.itmill.toolkit.ui.select.StartsWithFilter; * @VERSION@ * @since 3.0 */ -public class Select extends AbstractField implements Container, - Container.Viewer, Container.PropertySetChangeListener, - Container.PropertySetChangeNotifier, Container.ItemSetChangeNotifier, - Container.ItemSetChangeListener { +public class Select extends AbstractSelect implements AbstractSelect.Filtering { /** - * Item caption mode: Item's ID's String representation is - * used as caption. + * Holds value of property pageLength. 0 disables paging. */ - public static final int ITEM_CAPTION_MODE_ID = 0; + protected int pageLength = 15; - /** - * Item caption mode: Item's String representation is used as - * caption. - */ - public static final int ITEM_CAPTION_MODE_ITEM = 1; - - /** - * Item caption mode: Index of the item is used as caption. The index mode - * can only be used with the containers implementing the - * {@link com.itmill.toolkit.data.Container.Indexed} interface. - */ - public static final int ITEM_CAPTION_MODE_INDEX = 2; - - /** - * Item caption mode: If an Item has a caption it's used, if not, Item's - * ID's String representation is used as caption. This is - * the default. - */ - public static final int ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = 3; - - /** - * Item caption mode: Captions must be explicitly specified. - */ - public static final int ITEM_CAPTION_MODE_EXPLICIT = 4; - - /** - * Item caption mode: Only icons are shown, captions are hidden. - */ - public static final int ITEM_CAPTION_MODE_ICON_ONLY = 5; - - /** - * Item caption mode: Item captions are read from property specified with - * setItemCaptionPropertyId. - */ - public static final int ITEM_CAPTION_MODE_PROPERTY = 6; - - /** - * Is the select in multiselect mode? - */ - private boolean multiSelect = false; - - /** - * Select options. - */ - protected Container items; - - /** - * Is the user allowed to add new options? - */ - private boolean allowNewOptions; - - /** - * Keymapper used to map key values. - */ - protected KeyMapper itemIdMapper = new KeyMapper(); - - /** - * Item icons. - */ - private HashMap itemIcons = new HashMap(); + // current page when the user is 'paging' trough options + private int currentPage; - /** - * Item captions. - */ - private HashMap itemCaptions = new HashMap(); - - /** - * Item caption mode. - */ - private int itemCaptionMode = ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID; - - /** - * Item caption source property id. - */ - private Object itemCaptionPropertyId = null; - - /** - * Item icon source property id. - */ - private Object itemIconPropertyId = null; - - /** - * List of property set change event listeners. - */ - private LinkedList propertySetEventListeners = null; - - /** - * List of item set change event listeners. - */ - private LinkedList itemSetEventListeners = null; - - /** - * Item id that represents null selection of this select. - * - *

- * Data interface does not support nulls as item ids. Selecting the item - * idetified by this id is the same as selecting no items at all. This - * setting only affects the single select mode. - *

- */ - private Object nullSelectionItemId = null; - - /** - * Mechanism for streaming select options outside of the UIDL. - * - * By default streaming is not enabled and this is null. Streaming can be - * enabled with setOptionsLoadingLazy(true). - * - */ - // private OptionsStream optionsStream = null; - /** - * Number of options to stream per request ('page size') when lazyLoading - * options. - */ - private int lazyLoadingPageLength = 20; - - private OptionFilter optionFilter; - - private boolean isLazyLoading; - - private int page; + private int filteringMode = FILTERINGMODE_OFF; private String filterstring; - - /** - * How many visible columns (~characters) does select occupy visually. Used - * to size select appropriately. Minus one sets to 100% width. - */ - private int columns = -1; + private String prevfilterstring; + private List filteredOptions; /* Constructors ********************************************************* */ - /** - * Creates an empty Select. The caption is not used. - */ + /* Component methods **************************************************** */ + public Select() { - setContainerDataSource(new IndexedContainer()); + super(); } - /** - * Creates an empty Select with caption. - */ - public Select(String caption) { - setContainerDataSource(new IndexedContainer()); - setCaption(caption); + public Select(String caption, Collection options) { + super(caption, options); } - /** - * Creates a new select that is connected to a data-source. - * - * @param caption - * the Caption of the component. - * @param dataSource - * the Container datasource to be selected from by this select. - */ public Select(String caption, Container dataSource) { - setCaption(caption); - setContainerDataSource(dataSource); + super(caption, dataSource); } - /** - * Creates a new select that is filled from a collection of option values. - * - * @param caption - * the Caption of this field. - * @param options - * the Collection containing the options. - */ - public Select(String caption, Collection options) { - - // Creates the options container and add given options to it - Container c = new IndexedContainer(); - if (options != null) - for (Iterator i = options.iterator(); i.hasNext();) - c.addItem(i.next()); - - setCaption(caption); - setContainerDataSource((Container) c); + public Select(String caption) { + super(caption); } - /* Component methods **************************************************** */ - /** * Paints the content of this component. * @@ -268,84 +105,104 @@ public class Select extends AbstractField implements Container, * if the paint operation failed. */ public void paintContent(PaintTarget target) throws PaintException { + // Focus control id + if (getFocusableId() > 0) { + target.addAttribute("focusid", getFocusableId()); + } + + // The tab ordering number + if (getTabIndex() > 0) { + target.addAttribute("tabindex", getTabIndex()); + } + + // If the field is modified, but not committed, set modified attribute + if (isModified()) { + target.addAttribute("modified", true); + } - // Paints field properties - super.paintContent(target); + // Adds the required attribute + if (isRequired()) { + target.addAttribute("required", true); + } // Paints select attributes - if (isMultiSelect()) + if (isMultiSelect()) { target.addAttribute("selectmode", "multi"); - if (isNewItemsAllowed()) + } + if (isNewItemsAllowed()) { target.addAttribute("allownewitem", true); - if (getColumns() > -1) - target.addAttribute("cols", getColumns()); + } + if (!isNullSelectionAllowed()) { + target.addAttribute("nullselect", false); + } // Constructs selected keys array String[] selectedKeys; - if (isMultiSelect()) + if (isMultiSelect()) { selectedKeys = new String[((Set) getValue()).size()]; - else + } else { selectedKeys = new String[(getValue() == null && getNullSelectionItemId() == null ? 0 : 1)]; + } + + target.addAttribute("filteringmode", getFilteringMode()); // Paints the options and create array of selected id keys - target.startTag("options"); // TODO Also use conventional rendering if lazy loading is not supported // by terminal int keyIndex = 0; - if (!isLazyLoading()) { - // Support for external null selection item id - Collection ids = getItemIds(); - if (getNullSelectionItemId() != null - && (!ids.contains(getNullSelectionItemId()))) { - - // Gets the option attribute values - Object id = getNullSelectionItemId(); - String key = itemIdMapper.key(id); - String caption = getItemCaption(id); - Resource icon = getItemIcon(id); - - // Paints option - target.startTag("so"); - if (icon != null) - target.addAttribute("icon", icon); - target.addAttribute("caption", caption); - target.addAttribute("nullselection", true); - target.addAttribute("key", key); - if (isSelected(id)) { - target.addAttribute("selected", true); - selectedKeys[keyIndex++] = key; - } - target.endTag("so"); + /* + * if (!isLazyLoading()) { // Support for external null selection item + * id Collection ids = getItemIds(); if (getNullSelectionItemId() != + * null && (!ids.contains(getNullSelectionItemId()))) { // Gets the + * option attribute values Object id = getNullSelectionItemId(); String + * key = this.itemIdMapper.key(id); String caption = getItemCaption(id); + * Resource icon = getItemIcon(id); // Paints option + * target.startTag("so"); if (icon != null) { + * target.addAttribute("icon", icon); } target.addAttribute("caption", + * caption); target.addAttribute("nullselection", true); + * target.addAttribute("key", key); if (isSelected(id)) { + * target.addAttribute("selected", true); selectedKeys[keyIndex++] = + * key; } target.endTag("so"); } } + */ + /* + * Iterator i; if (this.filterstring != null) { i = + * this.optionFilter.filter(this.filterstring, + * this.lazyLoadingPageLength, this.page).iterator(); + * target.addAttribute("totalMatches", this.optionFilter + * .getMatchCount()); } else { i = getItemIds().iterator(); } + */ + List options = getFilteredOptions(); + if (options.size() > this.pageLength) { + int first = this.currentPage * this.pageLength; + int last = first + this.pageLength; + if (options.size() < last) { + last = options.size(); } + options = options.subList(first, last); } - - Iterator i; - if (isLazyLoading()) { - i = optionFilter.filter(filterstring, lazyLoadingPageLength, page) - .iterator(); - target.addAttribute("totalMatches", optionFilter.getMatchCount()); - } else { - i = getItemIds().iterator(); - } - + Iterator i = options.iterator(); // Paints the available selection options from data source + + target.startTag("options"); while (i.hasNext()) { // Gets the option attribute values Object id = i.next(); - String key = itemIdMapper.key(id); + String key = this.itemIdMapper.key(id); String caption = getItemCaption(id); Resource icon = getItemIcon(id); // Paints the option target.startTag("so"); - if (icon != null) + if (icon != null) { target.addAttribute("icon", icon); + } target.addAttribute("caption", caption); - if (id != null && id.equals(getNullSelectionItemId())) + if (id != null && id.equals(getNullSelectionItemId())) { target.addAttribute("nullselection", true); + } target.addAttribute("key", key); if (isSelected(id) && keyIndex < selectedKeys.length) { target.addAttribute("selected", true); @@ -355,14 +212,62 @@ public class Select extends AbstractField implements Container, } target.endTag("options"); + target.addAttribute("totalitems", size()); + if (this.filteredOptions != null) { + target.addAttribute("totalMatches", this.filteredOptions.size()); + } + // Paint variables target.addVariable(this, "selected", selectedKeys); - if (isNewItemsAllowed()) + if (isNewItemsAllowed()) { target.addVariable(this, "newitem", ""); - if (isLazyLoading()) { - target.addVariable(this, "filter", filterstring); - target.addVariable(this, "page", page); } + + target.addVariable(this, "filter", this.filterstring); + target.addVariable(this, "page", this.currentPage); + + } + + protected List getFilteredOptions() { + if (this.filterstring == null || this.filterstring.equals("") + || this.filteringMode == FILTERINGMODE_OFF) { + this.filteredOptions = new LinkedList(getItemIds()); + return this.filteredOptions; + } + if (this.filterstring.equals(this.prevfilterstring)) { + return this.filteredOptions; + } + + Collection items; + if (this.filterstring.startsWith(this.prevfilterstring)) { + items = this.filteredOptions; + } else { + items = getItemIds(); + } + + this.filteredOptions = new LinkedList(); + for (Iterator it = items.iterator(); it.hasNext();) { + Object itemId = it.next(); + String caption = getItemCaption(it); + if (caption != null || caption.equals("")) { + continue; + } + switch (this.filteringMode) { + case FILTERINGMODE_CONTAINS: + if (caption.indexOf(this.filterstring) > -1) { + this.filteredOptions.add(itemId); + } + break; + case FILTERINGMODE_STARTSWITH: + default: + if (caption.startsWith(this.filterstring)) { + this.filteredOptions.add(itemId); + } + break; + } + } + + return this.filteredOptions; } /** @@ -375,8 +280,8 @@ public class Select extends AbstractField implements Container, String newFilter; if ((newFilter = (String) variables.get("filter")) != null) { // this is a filter request - page = ((Integer) variables.get("page")).intValue(); - filterstring = newFilter; + this.currentPage = ((Integer) variables.get("page")).intValue(); + this.filterstring = newFilter; requestRepaint(); return; } @@ -388,14 +293,15 @@ public class Select extends AbstractField implements Container, if (newitem != null && newitem.length() > 0) { // Checks for readonly - if (isReadOnly()) + if (isReadOnly()) { throw new Property.ReadOnlyException(); + } // Adds new option if (addItem(newitem) != null) { // Sets the caption property, if used - if (getItemCaptionPropertyId() != null) + if (getItemCaptionPropertyId() != null) { try { getContainerProperty(newitem, getItemCaptionPropertyId()).setValue(newitem); @@ -404,6 +310,7 @@ public class Select extends AbstractField implements Container, // caption is // just missing } + } } } @@ -419,12 +326,13 @@ public class Select extends AbstractField implements Container, // Converts the key-array to id-set LinkedList s = new LinkedList(); for (int i = 0; i < ka.length; i++) { - Object id = itemIdMapper.get(ka[i]); - if (id != null && containsId(id)) + Object id = this.itemIdMapper.get(ka[i]); + if (id != null && containsId(id)) { s.add(id); - else if (itemIdMapper.isNewIdKey(ka[i]) && newitem != null - && newitem.length() > 0) + } else if (this.itemIdMapper.isNewIdKey(ka[i]) + && newitem != null && newitem.length() > 0) { s.add(newitem); + } } // Limits the deselection to the set of visible items @@ -432,10 +340,11 @@ public class Select extends AbstractField implements Container, Collection visible = getVisibleItemIds(); if (visible != null) { Set newsel = (Set) getValue(); - if (newsel == null) + if (newsel == null) { newsel = new HashSet(); - else + } else { newsel = new HashSet(newsel); + } newsel.removeAll(visible); newsel.addAll(s); setValue(newsel, true); @@ -449,16 +358,18 @@ public class Select extends AbstractField implements Container, // Allows deselection only if the deselected item is visible Object current = getValue(); Collection visible = getVisibleItemIds(); - if (visible != null && visible.contains(current)) + if (visible != null && visible.contains(current)) { setValue(null, true); + } } else { - Object id = itemIdMapper.get(ka[0]); - if (id != null && id.equals(getNullSelectionItemId())) + Object id = this.itemIdMapper.get(ka[0]); + if (id != null && id.equals(getNullSelectionItemId())) { setValue(null, true); - else if (itemIdMapper.isNewIdKey(ka[0])) + } else if (this.itemIdMapper.isNewIdKey(ka[0])) { setValue(newitem); - else + } else { setValue(id, true); + } } } } @@ -473,1048 +384,11 @@ public class Select extends AbstractField implements Container, return "select"; } - /** - * Gets the visible item ids. In Select, this returns list of all item ids, - * but can be overriden in subclasses if they paint only part of the items - * to the terminal or null if no items is visible. - */ - public Collection getVisibleItemIds() { - if (isVisible()) - return getItemIds(); - return null; - } - - /* Property methods ***************************************************** */ - - /** - * Returns the type of the property. getValue and - * setValue methods must be compatible with this type: one - * can safely cast getValue to given type and pass any - * variable assignable to this type as a parameter to setValue. - * - * @return the Type of the property. - */ - public Class getType() { - if (isMultiSelect()) - return Set.class; - else - return Object.class; - } - - /** - * Gets the selected item id or in multiselect mode a set of selected ids. - * - * @see com.itmill.toolkit.ui.AbstractField#getValue() - */ - public Object getValue() { - Object retValue = super.getValue(); - - if (isMultiSelect()) { - - // If the return value is not a set - if (retValue == null) - return new HashSet(); - if (retValue instanceof Set) { - return Collections.unmodifiableSet((Set) retValue); - } else if (retValue instanceof Collection) { - return new HashSet((Collection) retValue); - } else { - Set s = new HashSet(); - if (items.containsId(retValue)) - s.add(retValue); - return s; - } - - } else - return retValue; - } - - /** - * Sets the visible value of the property. - * - *

- * The value of the select is the selected item id. If the select is in - * multiselect-mode, the value is a set of selected item keys. In - * multiselect mode all collections of id:s can be assigned. - *

- * - * @param newValue - * the New selected item or collection of selected items. - * @see com.itmill.toolkit.ui.AbstractField#setValue(java.lang.Object) - */ - public void setValue(Object newValue) throws Property.ReadOnlyException, - Property.ConversionException { - setValue(newValue, false); - } - - /** - * Sets the visible value of the property. - * - *

- * The value of the select is the selected item id. If the select is in - * multiselect-mode, the value is a set of selected item keys. In - * multiselect mode all collections of id:s can be assigned. - *

- * - * @param newValue - * the New selected item or collection of selected items. - * @param repaintIsNotNeeded - * True if caller is sure that repaint is not needed. - * @see com.itmill.toolkit.ui.AbstractField#setValue(java.lang.Object, - * java.lang.Boolean) - */ - protected void setValue(Object newValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException, Property.ConversionException { - - if (isMultiSelect()) { - if (newValue == null) - super.setValue(new HashSet(), repaintIsNotNeeded); - else if (Collection.class.isAssignableFrom(newValue.getClass())) - super.setValue(new HashSet((Collection) newValue), - repaintIsNotNeeded); - } else if (newValue == null || items.containsId(newValue)) - super.setValue(newValue, repaintIsNotNeeded); - } - - /* Container methods **************************************************** */ - - /** - * Gets the item from the container with given id. If the container does not - * contain the requested item, null is returned. - * - * @param itemId - * the item id. - * @return the item from the container. - */ - public Item getItem(Object itemId) { - return items.getItem(itemId); - } - - /** - * Gets the item Id collection from the container. - * - * @return the Collection of item ids. - */ - public Collection getItemIds() { - return items.getItemIds(); - } - - /** - * Gets the property Id collection from the container. - * - * @return the Collection of property ids. - */ - public Collection getContainerPropertyIds() { - return items.getContainerPropertyIds(); - } - - /** - * Gets the property type. - * - * @param propertyId - * the Id identifying the property. - * @see com.itmill.toolkit.data.Container#getType(java.lang.Object) - */ - public Class getType(Object propertyId) { - return items.getType(propertyId); - } - - /* - * Gets the number of items in the container. - * - * @return the Number of items in the container. - * - * @see com.itmill.toolkit.data.Container#size() - */ - public int size() { - return items.size(); - } - - /** - * Tests, if the collection contains an item with given id. - * - * @param itemId - * the Id the of item to be tested. - */ - public boolean containsId(Object itemId) { - if (itemId != null) - return items.containsId(itemId); - else - return false; - } - - /** - * Gets the Property identified by the given itemId and propertyId from the - * Container - * - * @see com.itmill.toolkit.data.Container#getContainerProperty(Object, - * Object) - */ - public Property getContainerProperty(Object itemId, Object propertyId) { - return items.getContainerProperty(itemId, propertyId); - } - - /* Container.Managed methods ******************************************** */ - - /** - * Adds the new property to all items. Adds a property with given id, type - * and default value to all items in the container. - * - * This functionality is optional. If the function is unsupported, it always - * returns false. - * - * @return True if the operation succeeded. - * @see com.itmill.toolkit.data.Container#addContainerProperty(java.lang.Object, - * java.lang.Class, java.lang.Object) - */ - public boolean addContainerProperty(Object propertyId, Class type, - Object defaultValue) throws UnsupportedOperationException { - - boolean retval = items.addContainerProperty(propertyId, type, - defaultValue); - if (retval && !(items instanceof Container.PropertySetChangeNotifier)) { - firePropertySetChange(); - } - return retval; - } - - /** - * Removes all items from the container. - * - * This functionality is optional. If the function is unsupported, it always - * returns false. - * - * @return True if the operation succeeded. - * @see com.itmill.toolkit.data.Container#removeAllItems() - */ - public boolean removeAllItems() throws UnsupportedOperationException { - - boolean retval = items.removeAllItems(); - this.itemIdMapper.removeAll(); - if (retval) { - setValue(null); - if (!(items instanceof Container.ItemSetChangeNotifier)) - fireItemSetChange(); - } - return retval; - } - - /** - * Creates a new item into container with container managed id. The id of - * the created new item is returned. The item can be fetched with getItem() - * method. if the creation fails, null is returned. - * - * @return the Id of the created item or null in case of failure. - * @see com.itmill.toolkit.data.Container#addItem() - */ - public Object addItem() throws UnsupportedOperationException { - - Object retval = items.addItem(); - if (retval != null - && !(items instanceof Container.ItemSetChangeNotifier)) - fireItemSetChange(); - return retval; - } - - /** - * Create a new item into container. The created new item is returned and - * ready for setting property values. if the creation fails, null is - * returned. In case the container already contains the item, null is - * returned. - * - * This functionality is optional. If the function is unsupported, it always - * returns null. - * - * @param itemId - * the Identification of the item to be created. - * @return the Created item with the given id, or null in case of failure. - * @see com.itmill.toolkit.data.Container#addItem(java.lang.Object) - */ - public Item addItem(Object itemId) throws UnsupportedOperationException { - - Item retval = items.addItem(itemId); - if (retval != null - && !(items instanceof Container.ItemSetChangeNotifier)) - fireItemSetChange(); - return retval; - } - - /** - * Removes the item identified by Id from the container. This functionality - * is optional. If the function is not implemented, the functions allways - * returns false. - * - * @return True if the operation succeeded. - * @see com.itmill.toolkit.data.Container#removeItem(java.lang.Object) - */ - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - - unselect(itemId); - boolean retval = items.removeItem(itemId); - this.itemIdMapper.remove(itemId); - if (retval && !(items instanceof Container.ItemSetChangeNotifier)) - fireItemSetChange(); - return retval; + public void setFilteringMode(int filteringMode) { + this.filteringMode = filteringMode; } - /** - * Removes the property from all items. Removes a property with given id - * from all the items in the container. - * - * This functionality is optional. If the function is unsupported, it always - * returns false. - * - * @return True if the operation succeeded. - * @see com.itmill.toolkit.data.Container#removeContainerProperty(java.lang.Object) - */ - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - - boolean retval = items.removeContainerProperty(propertyId); - if (retval && !(items instanceof Container.PropertySetChangeNotifier)) - firePropertySetChange(); - return retval; + public int getFilteringMode() { + return this.filteringMode; } - - /* Container.Viewer methods ********************************************* */ - - /** - * Sets the container as data-source for viewing. - * - * @param newDataSource - * the new data source. - */ - public void setContainerDataSource(Container newDataSource) { - if (newDataSource == null) - newDataSource = new IndexedContainer(); - - if (items != newDataSource) { - - // Removes listeners from the old datasource - if (items != null) { - try { - ((Container.ItemSetChangeNotifier) items) - .removeListener((Container.ItemSetChangeListener) this); - } catch (ClassCastException ignored) { - // Ignored - } - try { - ((Container.PropertySetChangeNotifier) items) - .removeListener((Container.PropertySetChangeListener) this); - } catch (ClassCastException ignored) { - // Ignored - } - } - - // Assigns new data source - items = newDataSource; - - // Clears itemIdMapper also - this.itemIdMapper.removeAll(); - - // Adds listeners - if (items != null) { - try { - ((Container.ItemSetChangeNotifier) items) - .addListener((Container.ItemSetChangeListener) this); - } catch (ClassCastException ignored) { - // Ignored - } - try { - ((Container.PropertySetChangeNotifier) items) - .addListener((Container.PropertySetChangeListener) this); - } catch (ClassCastException ignored) { - // Ignored - } - } - - // TODO: This should be conditional - fireValueChange(false); - } - } - - /** - * Gets the viewing data-source container. - * - * @see com.itmill.toolkit.data.Container.Viewer#getContainerDataSource() - */ - public Container getContainerDataSource() { - return items; - } - - /* Select attributes **************************************************** */ - - /** - * Is the select in multiselect mode? In multiselect mode - * - * @return the Value of property multiSelect. - */ - public boolean isMultiSelect() { - return this.multiSelect; - } - - /** - * Sets the multiselect mode. Setting multiselect mode false may loose - * selection information: if selected items set contains one or more - * selected items, only one of the selected items is kept as selected. - * - * @param multiSelect - * the New value of property multiSelect. - */ - public void setMultiSelect(boolean multiSelect) { - - if (multiSelect != this.multiSelect) { - - // Selection before mode change - Object oldValue = getValue(); - - this.multiSelect = multiSelect; - - // Convert the value type - if (multiSelect) { - Set s = new HashSet(); - if (oldValue != null) - s.add(oldValue); - setValue(s); - } else { - Set s = (Set) oldValue; - if (s == null || s.isEmpty()) - setValue(null); - else - - // Set the single select to contain only the first - // selected value in the multiselect - setValue(s.iterator().next()); - } - - requestRepaint(); - } - } - - /** - * Does the select allow adding new options by the user. If true, the new - * options can be added to the Container. The text entered by the user is - * used as id. No that data-source must allow adding new items (it must - * implement Container.Managed). - * - * @return True if additions are allowed. - */ - public boolean isNewItemsAllowed() { - - return this.allowNewOptions; - } - - /** - * Enables or disables possibility to add new options by the user. - * - * @param allowNewOptions - * the New value of property allowNewOptions. - */ - public void setNewItemsAllowed(boolean allowNewOptions) { - - // Only handle change requests - if (this.allowNewOptions != allowNewOptions) { - - this.allowNewOptions = allowNewOptions; - - requestRepaint(); - } - } - - /** - * Override the caption of an item. Setting caption explicitly overrides id, - * item and index captions. - * - * @param itemId - * the id of the item to be recaptioned. - * @param caption - * the New caption. - */ - public void setItemCaption(Object itemId, String caption) { - if (itemId != null) { - itemCaptions.put(itemId, caption); - requestRepaint(); - } - } - - /** - * Gets the caption of an item. The caption is generated as specified by the - * item caption mode. See setItemCaptionMode() for more - * details. - * - * @param itemId - * the id of the item to be queried. - * @return the caption for specified item. - */ - public String getItemCaption(Object itemId) { - - // Null items can not be found - if (itemId == null) - return null; - - String caption = null; - - switch (getItemCaptionMode()) { - - case ITEM_CAPTION_MODE_ID: - caption = itemId.toString(); - break; - - case ITEM_CAPTION_MODE_INDEX: - try { - caption = String.valueOf(((Container.Indexed) items) - .indexOfId(itemId)); - } catch (ClassCastException ignored) { - } - break; - - case ITEM_CAPTION_MODE_ITEM: - Item i = getItem(itemId); - if (i != null) - caption = i.toString(); - break; - - case ITEM_CAPTION_MODE_EXPLICIT: - caption = (String) itemCaptions.get(itemId); - break; - - case ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID: - caption = (String) itemCaptions.get(itemId); - if (caption == null) - caption = itemId.toString(); - break; - - case ITEM_CAPTION_MODE_PROPERTY: - Property p = getContainerProperty(itemId, - getItemCaptionPropertyId()); - if (p != null) - caption = p.toString(); - break; - } - - // All items must have some captions - return caption != null ? caption : ""; - } - - /** - * Sets the icon for an item. - * - * @param itemId - * the id of the item to be assigned an icon. - * @param icon - * the New icon. - */ - public void setItemIcon(Object itemId, Resource icon) { - if (itemId != null) { - if (icon == null) - itemIcons.remove(itemId); - else - itemIcons.put(itemId, icon); - requestRepaint(); - } - } - - /** - * Gets the item icon. - * - * @param itemId - * the id of the item to be assigned an icon. - * @return the Icon for the item or null, if not specified. - */ - public Resource getItemIcon(Object itemId) { - Resource explicit = (Resource) itemIcons.get(itemId); - if (explicit != null) - return explicit; - - if (getItemIconPropertyId() == null) - return null; - - Property ip = getContainerProperty(itemId, getItemIconPropertyId()); - if (ip == null) - return null; - Object icon = ip.getValue(); - if (icon instanceof Resource) - return (Resource) icon; - - return null; - } - - /** - * Sets the item caption mode. - * - *

- * The mode can be one of the following ones: - *

- * The ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID is the default - * mode. - *

- * - * @param mode - * the One of the modes listed above. - */ - public void setItemCaptionMode(int mode) { - if (ITEM_CAPTION_MODE_ID <= mode && mode <= ITEM_CAPTION_MODE_PROPERTY) { - itemCaptionMode = mode; - requestRepaint(); - } - } - - /** - * Gets the item caption mode. - * - *

- * The mode can be one of the following ones: - *

- * The ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID is the default - * mode. - *

- * - * @return the One of the modes listed above. - */ - public int getItemCaptionMode() { - return itemCaptionMode; - } - - /** - * Sets the item caption property. - * - *

- * Setting the id to a existing property implicitly sets the item caption - * mode to ITEM_CAPTION_MODE_PROPERTY. If the object is in - * ITEM_CAPTION_MODE_PROPERTY mode, setting caption property - * id null resets the item caption mode to - * ITEM_CAPTION_EXPLICIT_DEFAULTS_ID. - *

- * - *

- * Setting the property id to null disables this feature. The id is null by - * default - *

. - * - * @param propertyId - * the id of the property. - * - */ - public void setItemCaptionPropertyId(Object propertyId) { - if (propertyId != null) { - itemCaptionPropertyId = propertyId; - setItemCaptionMode(ITEM_CAPTION_MODE_PROPERTY); - requestRepaint(); - } else { - itemCaptionPropertyId = null; - if (getItemCaptionMode() == ITEM_CAPTION_MODE_PROPERTY) - setItemCaptionMode(ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID); - requestRepaint(); - } - } - - /** - * Gets the item caption property. - * - * @return the Id of the property used as item caption source. - */ - public Object getItemCaptionPropertyId() { - return itemCaptionPropertyId; - } - - /** - * Sets the item icon property. - * - *

- * If the property id is set to a valid value, each item is given an icon - * got from the given property of the items. The type of the property must - * be assignable to Icon. - *

- * - *

- * Note : The icons set with setItemIcon function override - * the icons from the property. - *

- * - *

- * Setting the property id to null disables this feature. The id is null by - * default - *

. - * - * @param propertyId - * the Id of the property that specifies icons for items. - */ - public void setItemIconPropertyId(Object propertyId) { - if ((propertyId != null) - && Resource.class.isAssignableFrom(getType(propertyId))) { - itemIconPropertyId = propertyId; - requestRepaint(); - } else - itemIconPropertyId = null; - } - - /** - * Gets the item icon property. - * - *

- * If the property id is set to a valid value, each item is given an icon - * got from the given property of the items. The type of the property must - * be assignable to Icon. - *

- * - *

- * Note : The icons set with setItemIcon function override - * the icons from the property. - *

- * - *

- * Setting the property id to null disables this feature. The id is null by - * default - *

. - * - * @return the Id of the property containing the item icons. - */ - public Object getItemIconPropertyId() { - return itemIconPropertyId; - } - - /** - * Tests if an item is selected. - * - *

- * In single select mode testing selection status of the item identified by - * {@link #getNullSelectionItemId()} returns true if the value of the - * property is null. - *

- * - * @param itemId - * the Id the of the item to be tested. - * @see #getNullSelectionItemId() - * @see #setNullSelectionItemId(Object) - * - */ - public boolean isSelected(Object itemId) { - if (itemId == null) - return false; - if (isMultiSelect()) - return ((Set) getValue()).contains(itemId); - else { - Object value = getValue(); - return itemId.equals(value == null ? getNullSelectionItemId() - : value); - } - } - - /** - * Selects an item. - * - *

- * In single select mode selecting item identified by - * {@link #getNullSelectionItemId()} sets the value of the property to null. - *

- * - * @param itemId - * the tem to be selected. - * @see #getNullSelectionItemId() - * @see #setNullSelectionItemId(Object) - * - */ - public void select(Object itemId) { - if (!isSelected(itemId) && items.containsId(itemId)) { - if (isMultiSelect()) { - Set s = new HashSet((Set) getValue()); - s.add(itemId); - setValue(s); - } else if (itemId.equals(getNullSelectionItemId())) - setValue(null); - else - setValue(itemId); - } - } - - /** - * Unselects an item. - * - * @param itemId - * the Item to be unselected. - * @see #getNullSelectionItemId() - * @see #setNullSelectionItemId(Object) - * - */ - public void unselect(Object itemId) { - if (isSelected(itemId)) { - if (isMultiSelect()) { - Set s = new HashSet((Set) getValue()); - s.remove(itemId); - setValue(s); - } else - setValue(null); - } - } - - /** - * Notifies this listener that the Containers contents has changed. - * - * @see com.itmill.toolkit.data.Container.PropertySetChangeListener#containerPropertySetChange(com.itmill.toolkit.data.Container.PropertySetChangeEvent) - */ - public void containerPropertySetChange( - Container.PropertySetChangeEvent event) { - firePropertySetChange(); - } - - /** - * Adds a new Property set change listener for this Container. - * - * @see com.itmill.toolkit.data.Container.PropertySetChangeNotifier#addListener(com.itmill.toolkit.data.Container.PropertySetChangeListener) - */ - public void addListener(Container.PropertySetChangeListener listener) { - if (propertySetEventListeners == null) - propertySetEventListeners = new LinkedList(); - propertySetEventListeners.add(listener); - } - - /** - * Removes a previously registered Property set change listener. - * - * @see com.itmill.toolkit.data.Container.PropertySetChangeNotifier#removeListener(com.itmill.toolkit.data.Container.PropertySetChangeListener) - */ - public void removeListener(Container.PropertySetChangeListener listener) { - if (propertySetEventListeners != null) { - propertySetEventListeners.remove(listener); - if (propertySetEventListeners.isEmpty()) - propertySetEventListeners = null; - } - } - - /** - * Adds an Item set change listener for the object. - * - * @see com.itmill.toolkit.data.Container.ItemSetChangeNotifier#addListener(com.itmill.toolkit.data.Container.ItemSetChangeListener) - */ - public void addListener(Container.ItemSetChangeListener listener) { - if (itemSetEventListeners == null) - itemSetEventListeners = new LinkedList(); - itemSetEventListeners.add(listener); - } - - /** - * Removes the Item set change listener from the object. - * - * @see com.itmill.toolkit.data.Container.ItemSetChangeNotifier#removeListener(com.itmill.toolkit.data.Container.ItemSetChangeListener) - */ - public void removeListener(Container.ItemSetChangeListener listener) { - if (itemSetEventListeners != null) { - itemSetEventListeners.remove(listener); - if (itemSetEventListeners.isEmpty()) - itemSetEventListeners = null; - } - } - - /** - * Lets the listener know a Containers Item set has changed. - * - * @see com.itmill.toolkit.data.Container.ItemSetChangeListener#containerItemSetChange(com.itmill.toolkit.data.Container.ItemSetChangeEvent) - */ - public void containerItemSetChange(Container.ItemSetChangeEvent event) { - // Clears the item id mapping table - this.itemIdMapper.removeAll(); - - // Notify all listeners - fireItemSetChange(); - } - - /** - * Fires the property set change event. - */ - protected void firePropertySetChange() { - if (propertySetEventListeners != null - && !propertySetEventListeners.isEmpty()) { - Container.PropertySetChangeEvent event = new PropertySetChangeEvent(); - Object[] listeners = propertySetEventListeners.toArray(); - for (int i = 0; i < listeners.length; i++) - ((Container.PropertySetChangeListener) listeners[i]) - .containerPropertySetChange(event); - } - requestRepaint(); - } - - /** - * Fires the item set change event. - */ - protected void fireItemSetChange() { - if (itemSetEventListeners != null && !itemSetEventListeners.isEmpty()) { - Container.ItemSetChangeEvent event = new ItemSetChangeEvent(); - Object[] listeners = itemSetEventListeners.toArray(); - for (int i = 0; i < listeners.length; i++) - ((Container.ItemSetChangeListener) listeners[i]) - .containerItemSetChange(event); - } - requestRepaint(); - } - - /** - * Implementation of item set change event. - */ - private class ItemSetChangeEvent implements Container.ItemSetChangeEvent { - - /** - * Gets the Property where the event occurred. - * - * @see com.itmill.toolkit.data.Container.ItemSetChangeEvent#getContainer() - */ - public Container getContainer() { - return Select.this; - } - - } - - /** - * Implementation of property set change event. - */ - private class PropertySetChangeEvent implements - Container.PropertySetChangeEvent { - - /** - * Retrieves the Container whose contents have been modified. - * - * @see com.itmill.toolkit.data.Container.PropertySetChangeEvent#getContainer() - */ - public Container getContainer() { - return Select.this; - } - - } - - /** - * Returns the item id that represents null value of this select in single - * select mode. - * - *

- * Data interface does not support nulls as item ids. Selecting the item - * idetified by this id is the same as selecting no items at all. This - * setting only affects the single select mode. - *

- * - * @return the Object Null value item id. - * @see #setNullSelectionItemId(Object) - * @see #isSelected(Object) - * @see #select(Object) - */ - public final Object getNullSelectionItemId() { - return nullSelectionItemId; - } - - /** - * Sets the item id that represents null value of this select. - * - *

- * Data interface does not support nulls as item ids. Selecting the item - * idetified by this id is the same as selecting no items at all. This - * setting only affects the single select mode. - *

- * - * @param nullSelectionItemId - * the nullSelectionItemId to set. - * @see #getNullSelectionItemId() - * @see #isSelected(Object) - * @see #select(Object) - */ - public void setNullSelectionItemId(Object nullSelectionItemId) { - this.nullSelectionItemId = nullSelectionItemId; - } - - // TODO javadoc - public boolean isLazyLoading() { - return isLazyLoading; - } - - // TODO javadoc - // TODO What to do when terminal does not support lazy loading? - public void setLazyLoading(boolean useLazyLoading) { - if (useLazyLoading != isLazyLoading) { - isLazyLoading = useLazyLoading; - if (getOptionFilter() == null) - setOptionFilter(new StartsWithFilter(this)); - requestRepaint(); - } - } - - /** - * Notifies the component that it is connected to an application. - * - * @see com.itmill.toolkit.ui.AbstractField#attach() - */ - public void attach() { - super.attach(); - } - - /** - * Detaches the component from application. - * - * @see com.itmill.toolkit.ui.AbstractComponent#detach() - */ - public void detach() { - super.detach(); - } - - /** - * Sets OptionFilter which will do filtering base on query string if Select - * is in lazy loading mode. - * - * @param of - * OptionFilter to be used in filtering - */ - public void setOptionFilter(OptionFilter of) { - optionFilter = of; - } - - /** - * @return reference to option filter - */ - public OptionFilter getOptionFilter() { - return optionFilter; - } - - /** - * Set visible columns. - */ - public void setColumns(int cols) { - this.columns = cols; - } - - /** - * Get visible columns. - */ - public int getColumns() { - return this.columns; - } - } diff --git a/src/com/itmill/toolkit/ui/Table.java b/src/com/itmill/toolkit/ui/Table.java index 2299383366..c36f7bd811 100644 --- a/src/com/itmill/toolkit/ui/Table.java +++ b/src/com/itmill/toolkit/ui/Table.java @@ -60,7 +60,7 @@ import com.itmill.toolkit.terminal.Sizeable; * @VERSION@ * @since 3.0 */ -public class Table extends Select implements Action.Container, +public class Table extends AbstractSelect implements Action.Container, Container.Ordered, Container.Sortable, Sizeable { private static final int CELL_KEY = 0; @@ -192,7 +192,7 @@ public class Table extends Select implements Action.Container, /** * Keymapper for column ids. */ - private KeyMapper columnIdMap = new KeyMapper(); + private final KeyMapper columnIdMap = new KeyMapper(); /** * Holds visible column propertyIds - in order. @@ -202,17 +202,17 @@ public class Table extends Select implements Action.Container, /** * Holds propertyIds of currently collapsed columns. */ - private HashSet collapsedColumns = new HashSet(); + private final HashSet collapsedColumns = new HashSet(); /** * Holds headers for visible columns (by propertyId). */ - private HashMap columnHeaders = new HashMap(); + private final HashMap columnHeaders = new HashMap(); /** * Holds icons for visible columns (by propertyId). */ - private HashMap columnIcons = new HashMap(); + private final HashMap columnIcons = new HashMap(); /** * Holds alignments for visible columns (by propertyId). @@ -222,7 +222,7 @@ public class Table extends Select implements Action.Container, /** * Holds column widths in pixels for visible columns (by propertyId). */ - private HashMap columnWidths = new HashMap(); + private final HashMap columnWidths = new HashMap(); /** * Holds value of property pageLength. 0 disables paging. @@ -387,20 +387,22 @@ public class Table extends Select implements Action.Container, public void setVisibleColumns(Object[] visibleColumns) { // Visible columns must exist - if (visibleColumns == null) + if (visibleColumns == null) { throw new NullPointerException( "Can not set visible columns to null value"); + } // Checks that the new visible columns contains no nulls and properties // exist Collection properties = getContainerPropertyIds(); for (int i = 0; i < visibleColumns.length; i++) { - if (visibleColumns[i] == null) + if (visibleColumns[i] == null) { throw new NullPointerException("Properties must be non-nulls"); - else if (!properties.contains(visibleColumns[i])) + } else if (!properties.contains(visibleColumns[i])) { throw new IllegalArgumentException( "Properties must exist in the Container, missing property: " + visibleColumns[i]); + } } // If this is called befor the constructor is finished, it might be @@ -411,7 +413,7 @@ public class Table extends Select implements Action.Container, } // Removes alignments, icons and headers from hidden columns - if (this.visibleColumns != null) + if (this.visibleColumns != null) { for (Iterator i = this.visibleColumns.iterator(); i.hasNext();) { Object col = i.next(); if (!newVC.contains(col)) { @@ -420,6 +422,7 @@ public class Table extends Select implements Action.Container, setColumnIcon(col, null); } } + } this.visibleColumns = newVC; @@ -471,9 +474,10 @@ public class Table extends Select implements Action.Container, */ public void setColumnHeaders(String[] columnHeaders) { - if (columnHeaders.length != this.visibleColumns.size()) + if (columnHeaders.length != this.visibleColumns.size()) { throw new IllegalArgumentException( "The length of the headers array must match the number of visible columns"); + } this.columnHeaders.clear(); int i = 0; @@ -529,9 +533,10 @@ public class Table extends Select implements Action.Container, */ public void setColumnIcons(Resource[] columnIcons) { - if (columnIcons.length != this.visibleColumns.size()) + if (columnIcons.length != this.visibleColumns.size()) { throw new IllegalArgumentException( "The length of the icons array must match the number of visible columns"); + } this.columnIcons.clear(); int i = 0; @@ -595,17 +600,19 @@ public class Table extends Select implements Action.Container, */ public void setColumnAlignments(String[] columnAlignments) { - if (columnAlignments.length != this.visibleColumns.size()) + if (columnAlignments.length != this.visibleColumns.size()) { throw new IllegalArgumentException( "The length of the alignments array must match the number of visible columns"); + } // Checks all alignments for (int i = 0; i < columnAlignments.length; i++) { String a = columnAlignments[i]; if (a != null && !a.equals(ALIGN_LEFT) && !a.equals(ALIGN_CENTER) - && !a.equals(ALIGN_RIGHT)) + && !a.equals(ALIGN_RIGHT)) { throw new IllegalArgumentException("Column " + i + " aligment '" + a + "' is invalid"); + } } // Resets the alignments @@ -633,7 +640,7 @@ public class Table extends Select implements Action.Container, * @since 4.0.3 */ public void setColumnWidth(Object columnId, int width) { - columnWidths.put(columnId, new Integer(width)); + this.columnWidths.put(columnId, new Integer(width)); } /** @@ -643,9 +650,10 @@ public class Table extends Select implements Action.Container, * @return width of colun or -1 when value not set */ public int getColumnWidth(Object propertyId) { - Integer value = (Integer) columnWidths.get(propertyId); - if (value == null) + Integer value = (Integer) this.columnWidths.get(propertyId); + if (value == null) { return -1; + } return value.intValue(); } @@ -676,7 +684,7 @@ public class Table extends Select implements Action.Container, if (pageLength >= 0 && this.pageLength != pageLength) { this.pageLength = pageLength; // "scroll" to first row - this.setCurrentPageFirstItemIndex(0); + setCurrentPageFirstItemIndex(0); // Assures the visual refresh refreshCurrentPage(); } @@ -690,20 +698,24 @@ public class Table extends Select implements Action.Container, public Object getCurrentPageFirstItemId() { // Priorise index over id if indexes are supported - if (items instanceof Container.Indexed) { + if (this.items instanceof Container.Indexed) { int index = getCurrentPageFirstItemIndex(); Object id = null; - if (index >= 0 && index < size()) - id = ((Container.Indexed) items).getIdByIndex(index); - if (id != null && !id.equals(currentPageFirstItemId)) - currentPageFirstItemId = id; + if (index >= 0 && index < size()) { + id = ((Container.Indexed) this.items).getIdByIndex(index); + } + if (id != null && !id.equals(this.currentPageFirstItemId)) { + this.currentPageFirstItemId = id; + } } // If there is no item id at all, use the first one - if (currentPageFirstItemId == null) - currentPageFirstItemId = ((Container.Ordered) items).firstItemId(); + if (this.currentPageFirstItemId == null) { + this.currentPageFirstItemId = ((Container.Ordered) this.items) + .firstItemId(); + } - return currentPageFirstItemId; + return this.currentPageFirstItemId; } /** @@ -717,19 +729,20 @@ public class Table extends Select implements Action.Container, // Gets the corresponding index int index = -1; try { - index = ((Container.Indexed) items) + index = ((Container.Indexed) this.items) .indexOfId(currentPageFirstItemId); } catch (ClassCastException e) { // If the table item container does not have index, we have to // calculates the index by hand - Object id = ((Container.Ordered) items).firstItemId(); + Object id = ((Container.Ordered) this.items).firstItemId(); while (id != null && !id.equals(currentPageFirstItemId)) { index++; - id = ((Container.Ordered) items).nextItemId(id); + id = ((Container.Ordered) this.items).nextItemId(id); } - if (id == null) + if (id == null) { index = -1; + } } // If the search for item index was successfull @@ -768,10 +781,11 @@ public class Table extends Select implements Action.Container, */ public void setColumnIcon(Object propertyId, Resource icon) { - if (icon == null) + if (icon == null) { this.columnIcons.remove(propertyId); - else + } else { this.columnIcons.put(propertyId, icon); + } // Assures the visual refresh refreshCurrentPage(); @@ -785,12 +799,13 @@ public class Table extends Select implements Action.Container, * @return the header for the specifed column if it has one. */ public String getColumnHeader(Object propertyId) { - if (getColumnHeaderMode() == COLUMN_HEADER_MODE_HIDDEN) + if (getColumnHeaderMode() == COLUMN_HEADER_MODE_HIDDEN) { return null; + } String header = (String) this.columnHeaders.get(propertyId); - if ((header == null && this.getColumnHeaderMode() == COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) - || this.getColumnHeaderMode() == COLUMN_HEADER_MODE_ID) { + if ((header == null && getColumnHeaderMode() == COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) + || getColumnHeaderMode() == COLUMN_HEADER_MODE_ID) { header = propertyId.toString(); } @@ -847,9 +862,10 @@ public class Table extends Select implements Action.Container, // Checks for valid alignments if (alignment != null && !alignment.equals(ALIGN_LEFT) && !alignment.equals(ALIGN_CENTER) - && !alignment.equals(ALIGN_RIGHT)) + && !alignment.equals(ALIGN_RIGHT)) { throw new IllegalArgumentException("Column alignment '" + alignment + "' is not supported."); + } if (alignment == null || alignment.equals(ALIGN_LEFT)) { this.columnAlignments.remove(propertyId); @@ -870,8 +886,8 @@ public class Table extends Select implements Action.Container, * @return true if the column is collapsed; false otherwise; */ public boolean isColumnCollapsed(Object propertyId) { - return collapsedColumns != null - && collapsedColumns.contains(propertyId); + return this.collapsedColumns != null + && this.collapsedColumns.contains(propertyId); } /** @@ -886,14 +902,15 @@ public class Table extends Select implements Action.Container, */ public void setColumnCollapsed(Object propertyId, boolean collapsed) throws IllegalAccessException { - if (!this.isColumnCollapsingAllowed()) { + if (!isColumnCollapsingAllowed()) { throw new IllegalAccessException("Column collapsing not allowed!"); } - if (collapsed) + if (collapsed) { this.collapsedColumns.add(propertyId); - else + } else { this.collapsedColumns.remove(propertyId); + } // Assures the visual refresh refreshCurrentPage(); @@ -917,8 +934,9 @@ public class Table extends Select implements Action.Container, public void setColumnCollapsingAllowed(boolean collapsingAllowed) { this.columnCollapsingAllowed = collapsingAllowed; - if (!collapsingAllowed) - collapsedColumns.clear(); + if (!collapsingAllowed) { + this.collapsedColumns.clear(); + } // Assures the visual refresh refreshCurrentPage(); @@ -953,7 +971,7 @@ public class Table extends Select implements Action.Container, * nothing if columnReordering is not allowed. */ private void setColumnOrder(Object[] columnOrder) { - if (columnOrder == null || !this.isColumnReorderingAllowed()) { + if (columnOrder == null || !isColumnReorderingAllowed()) { return; } LinkedList newOrder = new LinkedList(); @@ -966,8 +984,9 @@ public class Table extends Select implements Action.Container, } for (Iterator it = this.visibleColumns.iterator(); it.hasNext();) { Object columnId = it.next(); - if (!newOrder.contains(columnId)) + if (!newOrder.contains(columnId)) { newOrder.add(columnId); + } } this.visibleColumns = newOrder; @@ -993,18 +1012,20 @@ public class Table extends Select implements Action.Container, public void setCurrentPageFirstItemIndex(int newIndex) { // Ensures that the new value is valid - if (newIndex < 0) + if (newIndex < 0) { newIndex = 0; - if (newIndex >= size()) + } + if (newIndex >= size()) { newIndex = size() - 1; + } // Refresh first item id - if (items instanceof Container.Indexed) { + if (this.items instanceof Container.Indexed) { try { - currentPageFirstItemId = ((Container.Indexed) items) + this.currentPageFirstItemId = ((Container.Indexed) this.items) .getIdByIndex(newIndex); } catch (IndexOutOfBoundsException e) { - currentPageFirstItemId = null; + this.currentPageFirstItemId = null; } this.currentPageFirstItemIndex = newIndex; } else { @@ -1013,49 +1034,52 @@ public class Table extends Select implements Action.Container, // container forwards / backwards // next available item forward or backward - this.currentPageFirstItemId = ((Container.Ordered) items) + this.currentPageFirstItemId = ((Container.Ordered) this.items) .firstItemId(); // Go forwards in the middle of the list (respect borders) while (this.currentPageFirstItemIndex < newIndex - && !((Container.Ordered) items) - .isLastId(currentPageFirstItemId)) { + && !((Container.Ordered) this.items) + .isLastId(this.currentPageFirstItemId)) { this.currentPageFirstItemIndex++; - currentPageFirstItemId = ((Container.Ordered) items) - .nextItemId(currentPageFirstItemId); + this.currentPageFirstItemId = ((Container.Ordered) this.items) + .nextItemId(this.currentPageFirstItemId); } // If we did hit the border - if (((Container.Ordered) items).isLastId(currentPageFirstItemId)) { + if (((Container.Ordered) this.items) + .isLastId(this.currentPageFirstItemId)) { this.currentPageFirstItemIndex = size() - 1; } // Go backwards in the middle of the list (respect borders) while (this.currentPageFirstItemIndex > newIndex - && !((Container.Ordered) items) - .isFirstId(currentPageFirstItemId)) { + && !((Container.Ordered) this.items) + .isFirstId(this.currentPageFirstItemId)) { this.currentPageFirstItemIndex--; - currentPageFirstItemId = ((Container.Ordered) items) - .prevItemId(currentPageFirstItemId); + this.currentPageFirstItemId = ((Container.Ordered) this.items) + .prevItemId(this.currentPageFirstItemId); } // If we did hit the border - if (((Container.Ordered) items).isFirstId(currentPageFirstItemId)) { + if (((Container.Ordered) this.items) + .isFirstId(this.currentPageFirstItemId)) { this.currentPageFirstItemIndex = 0; } // Go forwards once more while (this.currentPageFirstItemIndex < newIndex - && !((Container.Ordered) items) - .isLastId(currentPageFirstItemId)) { + && !((Container.Ordered) this.items) + .isLastId(this.currentPageFirstItemId)) { this.currentPageFirstItemIndex++; - currentPageFirstItemId = ((Container.Ordered) items) - .nextItemId(currentPageFirstItemId); + this.currentPageFirstItemId = ((Container.Ordered) this.items) + .nextItemId(this.currentPageFirstItemId); } // If for some reason we do hit border again, override // the user index request - if (((Container.Ordered) items).isLastId(currentPageFirstItemId)) { + if (((Container.Ordered) this.items) + .isLastId(this.currentPageFirstItemId)) { newIndex = this.currentPageFirstItemIndex = size() - 1; } } @@ -1084,8 +1108,9 @@ public class Table extends Select implements Action.Container, this.pageBuffering = pageBuffering; // If page buffering is disabled, clear the buffer - if (!pageBuffering) - pageBuffer = null; + if (!pageBuffering) { + this.pageBuffer = null; + } } /** @@ -1135,8 +1160,9 @@ public class Table extends Select implements Action.Container, */ public void setColumnHeaderMode(int columnHeaderMode) { if (columnHeaderMode >= COLUMN_HEADER_MODE_HIDDEN - && columnHeaderMode <= COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) + && columnHeaderMode <= COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID) { this.columnHeaderMode = columnHeaderMode; + } // Assures the visual refresh refreshCurrentPage(); @@ -1149,7 +1175,7 @@ public class Table extends Select implements Action.Container, public void refreshCurrentPage() { // Clear page buffer and notify about the change - pageBuffer = null; + this.pageBuffer = null; requestRepaint(); } @@ -1182,10 +1208,10 @@ public class Table extends Select implements Action.Container, * the One of the modes listed above. */ public void setRowHeaderMode(int mode) { - if (ROW_HEADER_MODE_HIDDEN == mode) - rowCaptionsAreHidden = true; - else { - rowCaptionsAreHidden = false; + if (ROW_HEADER_MODE_HIDDEN == mode) { + this.rowCaptionsAreHidden = true; + } else { + this.rowCaptionsAreHidden = false; setItemCaptionMode(mode); } @@ -1200,7 +1226,7 @@ public class Table extends Select implements Action.Container, * @see #setRowHeaderMode(int) */ public int getRowHeaderMode() { - return rowCaptionsAreHidden ? ROW_HEADER_MODE_HIDDEN + return this.rowCaptionsAreHidden ? ROW_HEADER_MODE_HIDDEN : getItemCaptionMode(); } @@ -1223,24 +1249,29 @@ public class Table extends Select implements Action.Container, Object[] cols = getVisibleColumns(); // Checks that a correct number of cells are given - if (cells.length != cols.length) + if (cells.length != cols.length) { return null; + } // Creates new item Item item; if (itemId == null) { - itemId = items.addItem(); - if (itemId == null) + itemId = this.items.addItem(); + if (itemId == null) { return null; - item = items.getItem(itemId); - } else - item = items.addItem(itemId); - if (item == null) + } + item = this.items.getItem(itemId); + } else { + item = this.items.addItem(itemId); + } + if (item == null) { return null; + } // Fills the item properties - for (int i = 0; i < cols.length; i++) + for (int i = 0; i < cols.length; i++) { item.getItemProperty(cols[i]).setValue(cells[i]); + } return itemId; } @@ -1254,24 +1285,27 @@ public class Table extends Select implements Action.Container, */ public void setContainerDataSource(Container newDataSource) { - if (newDataSource == null) + if (newDataSource == null) { newDataSource = new IndexedContainer(); + } // Assures that the data source is ordered by making unordered // containers ordered by wrapping them - if (newDataSource instanceof Container.Ordered) + if (newDataSource instanceof Container.Ordered) { super.setContainerDataSource(newDataSource); - else + } else { super.setContainerDataSource(new ContainerOrderedWrapper( newDataSource)); + } // Resets page position - currentPageFirstItemId = null; - currentPageFirstItemIndex = 0; + this.currentPageFirstItemId = null; + this.currentPageFirstItemIndex = 0; // Resets column properties - if (this.collapsedColumns != null) + if (this.collapsedColumns != null) { this.collapsedColumns.clear(); + } setVisibleColumns(getContainerPropertyIds().toArray()); // Assure visual refresh @@ -1293,20 +1327,23 @@ public class Table extends Select implements Action.Container, // Page start index if (variables.containsKey("firstvisible")) { Integer value = (Integer) variables.get("firstvisible"); - if (value != null) + if (value != null) { setCurrentPageFirstItemIndex(value.intValue()); + } } // Sets requested firstrow and rows for the next paint if (variables.containsKey("reqfirstrow") || variables.containsKey("reqrows")) { Integer value = (Integer) variables.get("reqfirstrow"); - if (value != null) - reqFirstRowToPaint = value.intValue(); + if (value != null) { + this.reqFirstRowToPaint = value.intValue(); + } value = (Integer) variables.get("reqrows"); - if (value != null) - reqRowsToPaint = value.intValue(); - pageBuffer = null; + if (value != null) { + this.reqRowsToPaint = value.intValue(); + } + this.pageBuffer = null; requestRepaint(); } @@ -1315,13 +1352,16 @@ public class Table extends Select implements Action.Container, StringTokenizer st = new StringTokenizer((String) variables .get("action"), ","); if (st.countTokens() == 2) { - Object itemId = itemIdMapper.get(st.nextToken()); - Action action = (Action) actionMapper.get(st.nextToken()); + Object itemId = this.itemIdMapper.get(st.nextToken()); + Action action = (Action) this.actionMapper.get(st.nextToken()); if (action != null && containsId(itemId) - && actionHandlers != null) - for (Iterator i = actionHandlers.iterator(); i.hasNext();) + && this.actionHandlers != null) { + for (Iterator i = this.actionHandlers.iterator(); i + .hasNext();) { ((Action.Handler) i.next()).handleAction(action, this, itemId); + } + } } } @@ -1345,35 +1385,36 @@ public class Table extends Select implements Action.Container, } } } - if (doSort) + if (doSort) { this.sort(); + } // Dynamic column hide/show and order // Update visible columns - if (this.isColumnCollapsingAllowed()) { + if (isColumnCollapsingAllowed()) { if (variables.containsKey("collapsedcolumns")) { try { Object[] ids = (Object[]) variables.get("collapsedcolumns"); for (Iterator it = this.visibleColumns.iterator(); it .hasNext();) { - this.setColumnCollapsed(it.next(), false); + setColumnCollapsed(it.next(), false); } for (int i = 0; i < ids.length; i++) { - this.setColumnCollapsed(columnIdMap.get(ids[i] + setColumnCollapsed(this.columnIdMap.get(ids[i] .toString()), true); } } catch (Exception ignored) { } } } - if (this.isColumnReorderingAllowed()) { + if (isColumnReorderingAllowed()) { if (variables.containsKey("columnorder")) { try { Object[] ids = (Object[]) variables.get("columnorder"); for (int i = 0; i < ids.length; i++) { - ids[i] = columnIdMap.get(ids[i].toString()); + ids[i] = this.columnIdMap.get(ids[i].toString()); } - this.setColumnOrder(ids); + setColumnOrder(ids); } catch (Exception ignored) { } } @@ -1391,21 +1432,24 @@ public class Table extends Select implements Action.Container, public void paintContent(PaintTarget target) throws PaintException { // Focus control id - if (this.getFocusableId() > 0) { - target.addAttribute("focusid", this.getFocusableId()); + if (getFocusableId() > 0) { + target.addAttribute("focusid", getFocusableId()); } // The tab ordering number - if (this.getTabIndex() > 0) - target.addAttribute("tabindex", this.getTabIndex()); + if (getTabIndex() > 0) { + target.addAttribute("tabindex", getTabIndex()); + } // Size - if (getHeight() >= 0) + if (getHeight() >= 0) { target.addAttribute("height", "" + getHeight() + Sizeable.UNIT_SYMBOLS[getHeightUnits()]); - if (getWidth() >= 0) + } + if (getWidth() >= 0) { target.addAttribute("width", "" + getWidth() + Sizeable.UNIT_SYMBOLS[getWidthUnits()]); + } // Initialize temps Object[] colids = getVisibleColumns(); @@ -1417,34 +1461,41 @@ public class Table extends Select implements Action.Container, boolean colheads = colHeadMode != COLUMN_HEADER_MODE_HIDDEN; boolean rowheads = getRowHeaderMode() != ROW_HEADER_MODE_HIDDEN; Object[][] cells = getVisibleCells(); - boolean iseditable = this.isEditable(); + boolean iseditable = isEditable(); // selection support String[] selectedKeys; - if (isMultiSelect()) + if (isMultiSelect()) { selectedKeys = new String[((Set) getValue()).size()]; - else + } else { selectedKeys = new String[(getValue() == null && getNullSelectionItemId() == null ? 0 : 1)]; + } int keyIndex = 0; // Table attributes - if (isSelectable()) + if (isSelectable()) { target.addAttribute("selectmode", (isMultiSelect() ? "multi" : "single")); - else + } else { target.addAttribute("selectmode", "none"); + } target.addAttribute("cols", cols); target.addAttribute("rows", cells[0].length); - target.addAttribute("firstrow", - (reqFirstRowToPaint >= 0 ? reqFirstRowToPaint : first)); + target + .addAttribute("firstrow", + (this.reqFirstRowToPaint >= 0 ? this.reqFirstRowToPaint + : first)); target.addAttribute("totalrows", total); - if (pagelen != 0) + if (pagelen != 0) { target.addAttribute("pagelength", pagelen); - if (colheads) + } + if (colheads) { target.addAttribute("colheaders", true); - if (rowheads) + } + if (rowheads) { target.addAttribute("rowheaders", true); + } // Visible column order Collection sortables = getSortableContainerPropertyIds(); @@ -1476,15 +1527,17 @@ public class Table extends Select implements Action.Container, // tr attributes if (rowheads) { - if (cells[CELL_ICON][i] != null) + if (cells[CELL_ICON][i] != null) { target.addAttribute("icon", (Resource) cells[CELL_ICON][i]); - if (cells[CELL_HEADER][i] != null) + } + if (cells[CELL_HEADER][i] != null) { target.addAttribute("caption", (String) cells[CELL_HEADER][i]); + } } target.addAttribute("key", Integer.parseInt(cells[CELL_KEY][i] .toString())); - if (actionHandlers != null || isSelectable()) { + if (this.actionHandlers != null || isSelectable()) { if (isSelected(itemId) && keyIndex < selectedKeys.length) { target.addAttribute("selected", true); selectedKeys[keyIndex++] = (String) cells[CELL_KEY][i]; @@ -1492,17 +1545,19 @@ public class Table extends Select implements Action.Container, } // Actions - if (actionHandlers != null) { + if (this.actionHandlers != null) { ArrayList keys = new ArrayList(); - for (Iterator ahi = actionHandlers.iterator(); ahi.hasNext();) { + for (Iterator ahi = this.actionHandlers.iterator(); ahi + .hasNext();) { Action[] aa = ((Action.Handler) ahi.next()).getActions( itemId, this); - if (aa != null) + if (aa != null) { for (int ai = 0; ai < aa.length; ai++) { - String key = actionMapper.key(aa[ai]); + String key = this.actionMapper.key(aa[ai]); actionSet.add(aa[ai]); keys.add(key); } + } } target.addAttribute("al", keys.toArray()); } @@ -1511,21 +1566,24 @@ public class Table extends Select implements Action.Container, int currentColumn = 0; for (Iterator it = this.visibleColumns.iterator(); it.hasNext(); currentColumn++) { Object columnId = it.next(); - if (columnId == null || this.isColumnCollapsed(columnId)) + if (columnId == null || isColumnCollapsed(columnId)) { continue; + } if ((iscomponent[currentColumn] || iseditable) && Component.class.isInstance(cells[CELL_FIRSTCOL + currentColumn][i])) { Component c = (Component) cells[CELL_FIRSTCOL + currentColumn][i]; - if (c == null) + if (c == null) { target.addText(""); - else + } else { c.paint(target); - } else + } + } else { target .addText((String) cells[CELL_FIRSTCOL + currentColumn][i]); + } } target.endTag("tr"); @@ -1533,12 +1591,14 @@ public class Table extends Select implements Action.Container, target.endTag("rows"); // The select variable is only enabled if selectable - if (selectable) + if (selectable) { target.addVariable(this, "selected", selectedKeys); + } // The cursors are only shown on pageable table - if (first != 0 || getPageLength() > 0) + if (first != 0 || getPageLength() > 0) { target.addVariable(this, "firstvisible", first); + } // Sorting if (getContainerDataSource() instanceof Container.Sortable) { @@ -1549,11 +1609,11 @@ public class Table extends Select implements Action.Container, // Resets and paints "to be painted next" variables. Also reset // pageBuffer - reqFirstRowToPaint = -1; - reqRowsToPaint = -1; - pageBuffer = null; - target.addVariable(this, "reqrows", reqRowsToPaint); - target.addVariable(this, "reqfirstrow", reqFirstRowToPaint); + this.reqFirstRowToPaint = -1; + this.reqRowsToPaint = -1; + this.pageBuffer = null; + target.addVariable(this, "reqrows", this.reqRowsToPaint); + target.addVariable(this, "reqfirstrow", this.reqFirstRowToPaint); // Actions if (!actionSet.isEmpty()) { @@ -1562,11 +1622,13 @@ public class Table extends Select implements Action.Container, for (Iterator it = actionSet.iterator(); it.hasNext();) { Action a = (Action) it.next(); target.startTag("action"); - if (a.getCaption() != null) + if (a.getCaption() != null) { target.addAttribute("caption", a.getCaption()); - if (a.getIcon() != null) + } + if (a.getIcon() != null) { target.addAttribute("icon", a.getIcon()); - target.addAttribute("key", actionMapper.key(a)); + } + target.addAttribute("key", this.actionMapper.key(a)); target.endTag("action"); } target.endTag("actions"); @@ -1583,17 +1645,18 @@ public class Table extends Select implements Action.Container, // Available columns if (this.columnCollapsingAllowed) { HashSet ccs = new HashSet(); - for (Iterator i = visibleColumns.iterator(); i.hasNext();) { + for (Iterator i = this.visibleColumns.iterator(); i.hasNext();) { Object o = i.next(); - if (isColumnCollapsed(o)) + if (isColumnCollapsed(o)) { ccs.add(o); + } } String[] collapsedkeys = new String[ccs.size()]; int nextColumn = 0; for (Iterator it = this.visibleColumns.iterator(); it.hasNext() && nextColumn < collapsedkeys.length;) { Object columnId = it.next(); - if (this.isColumnCollapsed(columnId)) { + if (isColumnCollapsed(columnId)) { collapsedkeys[nextColumn++] = this.columnIdMap .key(columnId); } @@ -1609,22 +1672,24 @@ public class Table extends Select implements Action.Container, target.addAttribute("cid", this.columnIdMap.key(columnId)); String head = getColumnHeader(columnId); target.addAttribute("caption", (head != null ? head : "")); - if (this.isColumnCollapsed(columnId)) { + if (isColumnCollapsed(columnId)) { target.addAttribute("collapsed", true); } if (colheads) { - if (this.getColumnIcon(columnId) != null) - target.addAttribute("icon", this - .getColumnIcon(columnId)); - if (sortables.contains(columnId)) + if (getColumnIcon(columnId) != null) { + target.addAttribute("icon", getColumnIcon(columnId)); + } + if (sortables.contains(columnId)) { target.addAttribute("sortable", true); + } + } + if (!ALIGN_LEFT.equals(getColumnAlignment(columnId))) { + target.addAttribute("align", getColumnAlignment(columnId)); } - if (!ALIGN_LEFT.equals(this.getColumnAlignment(columnId))) - target.addAttribute("align", this - .getColumnAlignment(columnId)); - if (getColumnWidth(columnId) > -1) + if (getColumnWidth(columnId) > -1) { target.addAttribute("width", String .valueOf(getColumnWidth(columnId))); + } target.endTag("column"); } @@ -1649,25 +1714,27 @@ public class Table extends Select implements Action.Container, private Object[][] getVisibleCells() { // Returns a buffered value if possible - if (pageBuffer != null && isPageBufferingEnabled()) - return pageBuffer; + if (this.pageBuffer != null && isPageBufferingEnabled()) { + return this.pageBuffer; + } // Stops listening the old properties and initialise the list - if (listenedProperties == null) - listenedProperties = new LinkedList(); - else - for (Iterator i = listenedProperties.iterator(); i.hasNext();) { + if (this.listenedProperties == null) { + this.listenedProperties = new LinkedList(); + } else { + for (Iterator i = this.listenedProperties.iterator(); i.hasNext();) { ((Property.ValueChangeNotifier) i.next()).removeListener(this); } + } // Detach old visible component from the table - if (visibleComponents == null) - visibleComponents = new LinkedList(); - else { - for (Iterator i = visibleComponents.iterator(); i.hasNext();) { + if (this.visibleComponents == null) { + this.visibleComponents = new LinkedList(); + } else { + for (Iterator i = this.visibleComponents.iterator(); i.hasNext();) { ((Component) i.next()).setParent(null); } - visibleComponents.clear(); + this.visibleComponents.clear(); } // Collects the basic facts about the table page @@ -1676,48 +1743,56 @@ public class Table extends Select implements Action.Container, int pagelen = getPageLength(); int firstIndex = getCurrentPageFirstItemIndex(); int rows = size(); - if (rows > 0 && firstIndex >= 0) + if (rows > 0 && firstIndex >= 0) { rows -= firstIndex; - if (pagelen > 0 && pagelen < rows) + } + if (pagelen > 0 && pagelen < rows) { rows = pagelen; + } // If "to be painted next" variables are set, use them - if (reqRowsToPaint >= 0) - rows = reqRowsToPaint; + if (this.reqRowsToPaint >= 0) { + rows = this.reqRowsToPaint; + } Object id; - if (reqFirstRowToPaint >= 0 && reqFirstRowToPaint < size()) - firstIndex = reqFirstRowToPaint; + if (this.reqFirstRowToPaint >= 0 && this.reqFirstRowToPaint < size()) { + firstIndex = this.reqFirstRowToPaint; + } if (size() > 0) { - if (rows + firstIndex > size()) + if (rows + firstIndex > size()) { rows = size() - firstIndex; + } } else { rows = 0; } Object[][] cells = new Object[cols + CELL_FIRSTCOL][rows]; - if (rows == 0) + if (rows == 0) { return cells; + } // Gets the first item id - if (items instanceof Container.Indexed) - id = ((Container.Indexed) items).getIdByIndex(firstIndex); - else { - id = ((Container.Ordered) items).firstItemId(); - for (int i = 0; i < firstIndex; i++) - id = ((Container.Ordered) items).nextItemId(id); + if (this.items instanceof Container.Indexed) { + id = ((Container.Indexed) this.items).getIdByIndex(firstIndex); + } else { + id = ((Container.Ordered) this.items).firstItemId(); + for (int i = 0; i < firstIndex; i++) { + id = ((Container.Ordered) this.items).nextItemId(id); + } } int headmode = getRowHeaderMode(); boolean[] iscomponent = new boolean[cols]; - for (int i = 0; i < cols; i++) + for (int i = 0; i < cols; i++) { iscomponent[i] = Component.class .isAssignableFrom(getType(colids[i])); + } // Creates the page contents int filledRows = 0; for (int i = 0; i < rows && id != null; i++) { cells[CELL_ITEMID][i] = id; - cells[CELL_KEY][i] = itemIdMapper.key(id); + cells[CELL_KEY][i] = this.itemIdMapper.key(id); if (headmode != ROW_HEADER_MODE_HIDDEN) { switch (headmode) { case ROW_HEADER_MODE_INDEX: @@ -1736,7 +1811,7 @@ public class Table extends Select implements Action.Container, if (p instanceof Property.ValueChangeNotifier) { ((Property.ValueChangeNotifier) p) .addListener(this); - listenedProperties.add(p); + this.listenedProperties.add(p); } if (iscomponent[j]) { value = p.getValue(); @@ -1751,13 +1826,13 @@ public class Table extends Select implements Action.Container, if (value instanceof Component) { ((Component) value).setParent(this); - visibleComponents.add((Component) value); + this.visibleComponents.add(value); } cells[CELL_FIRSTCOL + j][i] = value; } } - id = ((Container.Ordered) items).nextItemId(id); + id = ((Container.Ordered) this.items).nextItemId(id); filledRows++; } @@ -1765,16 +1840,19 @@ public class Table extends Select implements Action.Container, // Assures that all the rows of the cell-buffer are valid if (filledRows != cells[0].length) { Object[][] temp = new Object[cells.length][filledRows]; - for (int i = 0; i < cells.length; i++) - for (int j = 0; j < filledRows; j++) + for (int i = 0; i < cells.length; i++) { + for (int j = 0; j < filledRows; j++) { temp[i][j] = cells[i][j]; + } + } cells = temp; } // Saves the results to internal buffer iff in buffering mode // to possible conserve memory from large non-buffered pages - if (isPageBufferingEnabled()) - pageBuffer = cells; + if (isPageBufferingEnabled()) { + this.pageBuffer = cells; + } return cells; } @@ -1797,7 +1875,7 @@ public class Table extends Select implements Action.Container, */ protected Object getPropertyValue(Object rowId, Object colId, Property property) { - if (this.isEditable() && this.fieldFactory != null) { + if (isEditable() && this.fieldFactory != null) { Field f = this.fieldFactory.createField(getContainerDataSource(), rowId, colId, this); if (f != null) { @@ -1841,13 +1919,13 @@ public class Table extends Select implements Action.Container, if (actionHandler != null) { - if (actionHandlers == null) { - actionHandlers = new LinkedList(); - actionMapper = new KeyMapper(); + if (this.actionHandlers == null) { + this.actionHandlers = new LinkedList(); + this.actionMapper = new KeyMapper(); } - if (!actionHandlers.contains(actionHandler)) { - actionHandlers.add(actionHandler); + if (!this.actionHandlers.contains(actionHandler)) { + this.actionHandlers.add(actionHandler); requestRepaint(); } @@ -1862,13 +1940,14 @@ public class Table extends Select implements Action.Container, */ public void removeActionHandler(Action.Handler actionHandler) { - if (actionHandlers != null && actionHandlers.contains(actionHandler)) { + if (this.actionHandlers != null + && this.actionHandlers.contains(actionHandler)) { - actionHandlers.remove(actionHandler); + this.actionHandlers.remove(actionHandler); - if (actionHandlers.isEmpty()) { - actionHandlers = null; - actionMapper = null; + if (this.actionHandlers.isEmpty()) { + this.actionHandlers = null; + this.actionMapper = null; } requestRepaint(); @@ -1895,9 +1974,11 @@ public class Table extends Select implements Action.Container, public void attach() { super.attach(); - if (visibleComponents != null) - for (Iterator i = visibleComponents.iterator(); i.hasNext();) + if (this.visibleComponents != null) { + for (Iterator i = this.visibleComponents.iterator(); i.hasNext();) { ((Component) i.next()).attach(); + } + } } /** @@ -1908,9 +1989,11 @@ public class Table extends Select implements Action.Container, public void detach() { super.detach(); - if (visibleComponents != null) - for (Iterator i = visibleComponents.iterator(); i.hasNext();) + if (this.visibleComponents != null) { + for (Iterator i = this.visibleComponents.iterator(); i.hasNext();) { ((Component) i.next()).detach(); + } + } } /** @@ -1930,7 +2013,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container#removeItem(Object) */ public boolean removeItem(Object itemId) { - Object nextItemId = ((Container.Ordered) items).nextItemId(itemId); + Object nextItemId = ((Container.Ordered) this.items).nextItemId(itemId); boolean ret = super.removeItem(itemId); if (ret && (itemId != null) && (itemId.equals(this.currentPageFirstItemId))) { @@ -1970,10 +2053,12 @@ public class Table extends Select implements Action.Container, */ public boolean addContainerProperty(Object propertyId, Class type, Object defaultValue) throws UnsupportedOperationException { - if (!super.addContainerProperty(propertyId, type, defaultValue)) + if (!super.addContainerProperty(propertyId, type, defaultValue)) { return false; - if (!this.visibleColumns.contains(propertyId)) + } + if (!this.visibleColumns.contains(propertyId)) { this.visibleColumns.add(propertyId); + } return true; } @@ -2002,11 +2087,12 @@ public class Table extends Select implements Action.Container, public boolean addContainerProperty(Object propertyId, Class type, Object defaultValue, String columnHeader, Resource columnIcon, String columnAlignment) throws UnsupportedOperationException { - if (!this.addContainerProperty(propertyId, type, defaultValue)) + if (!this.addContainerProperty(propertyId, type, defaultValue)) { return false; - this.setColumnAlignment(propertyId, columnAlignment); - this.setColumnHeader(propertyId, columnHeader); - this.setColumnIcon(propertyId, columnIcon); + } + setColumnAlignment(propertyId, columnAlignment); + setColumnHeader(propertyId, columnHeader); + setColumnIcon(propertyId, columnIcon); return true; } @@ -2020,8 +2106,9 @@ public class Table extends Select implements Action.Container, LinkedList visible = new LinkedList(); Object[][] cells = getVisibleCells(); - for (int i = 0; i < cells[CELL_ITEMID].length; i++) + for (int i = 0; i < cells[CELL_ITEMID].length; i++) { visible.add(cells[CELL_ITEMID][i]); + } return visible; } @@ -2033,9 +2120,9 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container.ItemSetChangeListener#containerItemSetChange(com.itmill.toolkit.data.Container.ItemSetChangeEvent) */ public void containerItemSetChange(Container.ItemSetChangeEvent event) { - pageBuffer = null; + this.pageBuffer = null; super.containerItemSetChange(event); - setCurrentPageFirstItemIndex(this.getCurrentPageFirstItemIndex()); + setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex()); } /** @@ -2046,7 +2133,7 @@ public class Table extends Select implements Action.Container, */ public void containerPropertySetChange( Container.PropertySetChangeEvent event) { - pageBuffer = null; + this.pageBuffer = null; super.containerPropertySetChange(event); } @@ -2059,8 +2146,9 @@ public class Table extends Select implements Action.Container, */ public void setNewItemsAllowed(boolean allowNewOptions) throws UnsupportedOperationException { - if (allowNewOptions) + if (allowNewOptions) { throw new UnsupportedOperationException(); + } } /** @@ -2080,7 +2168,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container.Ordered#nextItemId(java.lang.Object) */ public Object nextItemId(Object itemId) { - return ((Container.Ordered) items).nextItemId(itemId); + return ((Container.Ordered) this.items).nextItemId(itemId); } /** @@ -2090,7 +2178,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container.Ordered#prevItemId(java.lang.Object) */ public Object prevItemId(Object itemId) { - return ((Container.Ordered) items).prevItemId(itemId); + return ((Container.Ordered) this.items).prevItemId(itemId); } /** @@ -2099,7 +2187,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container.Ordered#firstItemId() */ public Object firstItemId() { - return ((Container.Ordered) items).firstItemId(); + return ((Container.Ordered) this.items).firstItemId(); } /** @@ -2108,7 +2196,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container.Ordered#lastItemId() */ public Object lastItemId() { - return ((Container.Ordered) items).lastItemId(); + return ((Container.Ordered) this.items).lastItemId(); } /** @@ -2118,7 +2206,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container.Ordered#isFirstId(java.lang.Object) */ public boolean isFirstId(Object itemId) { - return ((Container.Ordered) items).isFirstId(itemId); + return ((Container.Ordered) this.items).isFirstId(itemId); } /** @@ -2128,7 +2216,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.data.Container.Ordered#isLastId(java.lang.Object) */ public boolean isLastId(Object itemId) { - return ((Container.Ordered) items).isLastId(itemId); + return ((Container.Ordered) this.items).isLastId(itemId); } /** @@ -2138,7 +2226,7 @@ public class Table extends Select implements Action.Container, */ public Object addItemAfter(Object previousItemId) throws UnsupportedOperationException { - return ((Container.Ordered) items).addItemAfter(previousItemId); + return ((Container.Ordered) this.items).addItemAfter(previousItemId); } /** @@ -2149,7 +2237,7 @@ public class Table extends Select implements Action.Container, */ public Item addItemAfter(Object previousItemId, Object newItemId) throws UnsupportedOperationException { - return ((Container.Ordered) items).addItemAfter(previousItemId, + return ((Container.Ordered) this.items).addItemAfter(previousItemId, newItemId); } @@ -2162,7 +2250,7 @@ public class Table extends Select implements Action.Container, * @see #isEditable */ public FieldFactory getFieldFactory() { - return fieldFactory; + return this.fieldFactory; } /** @@ -2200,7 +2288,7 @@ public class Table extends Select implements Action.Container, * */ public boolean isEditable() { - return editable; + return this.editable; } /** @@ -2240,7 +2328,7 @@ public class Table extends Select implements Action.Container, throws UnsupportedOperationException { Container c = getContainerDataSource(); if (c instanceof Container.Sortable) { - int pageIndex = this.getCurrentPageFirstItemIndex(); + int pageIndex = getCurrentPageFirstItemIndex(); ((Container.Sortable) c).sort(propertyId, ascending); setCurrentPageFirstItemIndex(pageIndex); } else if (c != null) { @@ -2257,8 +2345,9 @@ public class Table extends Select implements Action.Container, * Container.Sortable */ public void sort() { - if (getSortContainerPropertyId() == null) + if (getSortContainerPropertyId() == null) { return; + } sort(new Object[] { this.sortContainerPropertyId }, new boolean[] { this.sortAscending }); } @@ -2340,7 +2429,7 @@ public class Table extends Select implements Action.Container, * @return True iff sorting is disabled. */ public boolean isSortDisabled() { - return sortDisabled; + return this.sortDisabled; } /** @@ -2365,7 +2454,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.terminal.Sizeable#getHeightUnits() */ public int getHeightUnits() { - return heightUnit; + return this.heightUnit; } /** @@ -2374,7 +2463,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.terminal.Sizeable#getWidthUnits() */ public int getWidthUnits() { - return widthUnit; + return this.widthUnit; } /** @@ -2395,8 +2484,9 @@ public class Table extends Select implements Action.Container, */ public void setWidthUnits(int units) { if (units != Sizeable.UNITS_PIXELS - && units != Sizeable.UNITS_PERCENTAGE) + && units != Sizeable.UNITS_PERCENTAGE) { throw new IllegalArgumentException(); + } this.widthUnit = units; } @@ -2407,7 +2497,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.terminal.Sizeable#getHeight() */ public int getHeight() { - return height; + return this.height; } /** @@ -2417,7 +2507,7 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.terminal.Sizeable#getWidth() */ public int getWidth() { - return width; + return this.width; } /** @@ -2451,9 +2541,10 @@ public class Table extends Select implements Action.Container, * @see com.itmill.toolkit.ui.Select#setLazyLoading(boolean) */ public void setLazyLoading(boolean useLazyLoading) { - if (useLazyLoading) + if (useLazyLoading) { throw new UnsupportedOperationException( "Lazy options loading is not supported by Table."); + } } } \ No newline at end of file diff --git a/src/com/itmill/toolkit/ui/Tree.java b/src/com/itmill/toolkit/ui/Tree.java index 5d84385b7e..0aaa22a3c7 100644 --- a/src/com/itmill/toolkit/ui/Tree.java +++ b/src/com/itmill/toolkit/ui/Tree.java @@ -57,7 +57,7 @@ import com.itmill.toolkit.terminal.Resource; * @VERSION@ * @since 3.0 */ -public class Tree extends Select implements Container.Hierarchical, +public class Tree extends AbstractSelect implements Container.Hierarchical, Action.Container { /* Static members ***************************************************** */ @@ -85,7 +85,7 @@ public class Tree extends Select implements Container.Hierarchical, /** * Set of expanded nodes. */ - private HashSet expanded = new HashSet(); + private final HashSet expanded = new HashSet(); /** * List of action handlers. @@ -156,7 +156,7 @@ public class Tree extends Select implements Container.Hierarchical, * @return true iff the item is expanded. */ public boolean isExpanded(Object itemId) { - return expanded.contains(itemId); + return this.expanded.contains(itemId); } /** @@ -169,21 +169,24 @@ public class Tree extends Select implements Container.Hierarchical, public boolean expandItem(Object itemId) { // Succeeds if the node is already expanded - if (isExpanded(itemId)) + if (isExpanded(itemId)) { return true; + } // Nodes that can not have children are not expandable - if (!areChildrenAllowed(itemId)) + if (!areChildrenAllowed(itemId)) { return false; + } // Expands - expanded.add(itemId); + this.expanded.add(itemId); - expandedItemId = itemId; - if (initialPaint) + this.expandedItemId = itemId; + if (this.initialPaint) { requestRepaint(); - else + } else { requestPartialRepaint(); + } fireExpandEvent(itemId); return true; @@ -191,12 +194,12 @@ public class Tree extends Select implements Container.Hierarchical, public void requestRepaint() { super.requestRepaint(); - partialUpdate = false; + this.partialUpdate = false; } private void requestPartialRepaint() { super.requestRepaint(); - partialUpdate = true; + this.partialUpdate = true; } /** @@ -240,11 +243,12 @@ public class Tree extends Select implements Container.Hierarchical, public boolean collapseItem(Object itemId) { // Succeeds if the node is already collapsed - if (!isExpanded(itemId)) + if (!isExpanded(itemId)) { return true; + } // Collapse - expanded.remove(itemId); + this.expanded.remove(itemId); requestRepaint(); fireCollapseEvent(itemId); @@ -336,9 +340,9 @@ public class Tree extends Select implements Container.Hierarchical, if (variables.containsKey("collapse")) { String[] keys = (String[]) variables.get("collapse"); for (int i = 0; i < keys.length; i++) { - Object id = itemIdMapper.get(keys[i]); + Object id = this.itemIdMapper.get(keys[i]); if (id != null && isExpanded(id)) { - expanded.remove(id); + this.expanded.remove(id); fireCollapseEvent(id); } } @@ -348,9 +352,10 @@ public class Tree extends Select implements Container.Hierarchical, if (variables.containsKey("expand")) { String[] keys = (String[]) variables.get("expand"); for (int i = 0; i < keys.length; i++) { - Object id = itemIdMapper.get(keys[i]); - if (id != null) + Object id = this.itemIdMapper.get(keys[i]); + if (id != null) { expandItem(id); + } } } @@ -363,13 +368,16 @@ public class Tree extends Select implements Container.Hierarchical, StringTokenizer st = new StringTokenizer((String) variables .get("action"), ","); if (st.countTokens() == 2) { - Object itemId = itemIdMapper.get(st.nextToken()); - Action action = (Action) actionMapper.get(st.nextToken()); + Object itemId = this.itemIdMapper.get(st.nextToken()); + Action action = (Action) this.actionMapper.get(st.nextToken()); if (action != null && containsId(itemId) - && actionHandlers != null) - for (Iterator i = actionHandlers.iterator(); i.hasNext();) + && this.actionHandlers != null) { + for (Iterator i = this.actionHandlers.iterator(); i + .hasNext();) { ((Action.Handler) i.next()).handleAction(action, this, itemId); + } + } } } } @@ -380,53 +388,60 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.ui.AbstractComponent#paintContent(PaintTarget) */ public void paintContent(PaintTarget target) throws PaintException { - initialPaint = false; + this.initialPaint = false; - if (partialUpdate) { + if (this.partialUpdate) { target.addAttribute("partialUpdate", true); - target.addAttribute("rootKey", itemIdMapper.key(expandedItemId)); + target.addAttribute("rootKey", this.itemIdMapper + .key(this.expandedItemId)); } else { // Focus control id - if (this.getFocusableId() > 0) { - target.addAttribute("focusid", this.getFocusableId()); + if (getFocusableId() > 0) { + target.addAttribute("focusid", getFocusableId()); } // The tab ordering number - if (this.getTabIndex() > 0) - target.addAttribute("tabindex", this.getTabIndex()); + if (getTabIndex() > 0) { + target.addAttribute("tabindex", getTabIndex()); + } // Paint tree attributes - if (isSelectable()) + if (isSelectable()) { target.addAttribute("selectmode", (isMultiSelect() ? "multi" : "single")); - else + } else { target.addAttribute("selectmode", "none"); - if (isNewItemsAllowed()) + } + if (isNewItemsAllowed()) { target.addAttribute("allownewitem", true); + } } // Initialize variables Set actionSet = new LinkedHashSet(); String[] selectedKeys; - if (isMultiSelect()) + if (isMultiSelect()) { selectedKeys = new String[((Set) getValue()).size()]; - else + } else { selectedKeys = new String[(getValue() == null ? 0 : 1)]; + } int keyIndex = 0; LinkedList expandedKeys = new LinkedList(); // Iterates through hierarchical tree using a stack of iterators Stack iteratorStack = new Stack(); Collection ids; - if (partialUpdate) - ids = getChildren(expandedItemId); - else + if (this.partialUpdate) { + ids = getChildren(this.expandedItemId); + } else { ids = rootItemIds(); + } - if (ids != null) + if (ids != null) { iteratorStack.push(ids.iterator()); + } while (!iteratorStack.isEmpty()) { @@ -440,8 +455,9 @@ public class Tree extends Select implements Container.Hierarchical, iteratorStack.pop(); // Closes node - if (!iteratorStack.isEmpty()) + if (!iteratorStack.isEmpty()) { target.endTag("node"); + } } // Adds the item on current level @@ -451,17 +467,19 @@ public class Tree extends Select implements Container.Hierarchical, // Starts the item / node boolean isNode = areChildrenAllowed(itemId) && hasChildren(itemId); - if (isNode) + if (isNode) { target.startTag("node"); - else + } else { target.startTag("leaf"); + } // Adds the attributes target.addAttribute("caption", getItemCaption(itemId)); Resource icon = getItemIcon(itemId); - if (icon != null) + if (icon != null) { target.addAttribute("icon", getItemIcon(itemId)); - String key = itemIdMapper.key(itemId); + } + String key = this.itemIdMapper.key(itemId); target.addAttribute("key", key); if (isSelected(itemId)) { target.addAttribute("selected", true); @@ -473,18 +491,19 @@ public class Tree extends Select implements Container.Hierarchical, } // Actions - if (actionHandlers != null) { + if (this.actionHandlers != null) { ArrayList keys = new ArrayList(); - for (Iterator ahi = actionHandlers.iterator(); ahi + for (Iterator ahi = this.actionHandlers.iterator(); ahi .hasNext();) { Action[] aa = ((Action.Handler) ahi.next()).getActions( itemId, this); - if (aa != null) + if (aa != null) { for (int ai = 0; ai < aa.length; ai++) { - String akey = actionMapper.key(aa[ai]); + String akey = this.actionMapper.key(aa[ai]); actionSet.add(aa[ai]); keys.add(akey); } + } } target.addAttribute("al", keys.toArray()); } @@ -494,10 +513,11 @@ public class Tree extends Select implements Container.Hierarchical, && areChildrenAllowed(itemId)) { iteratorStack.push(getChildren(itemId).iterator()); } else { - if (isNode) + if (isNode) { target.endTag("node"); - else + } else { target.endTag("leaf"); + } } } } @@ -509,18 +529,20 @@ public class Tree extends Select implements Container.Hierarchical, for (Iterator i = actionSet.iterator(); i.hasNext();) { Action a = (Action) i.next(); target.startTag("action"); - if (a.getCaption() != null) + if (a.getCaption() != null) { target.addAttribute("caption", a.getCaption()); - if (a.getIcon() != null) + } + if (a.getIcon() != null) { target.addAttribute("icon", a.getIcon()); - target.addAttribute("key", actionMapper.key(a)); + } + target.addAttribute("key", this.actionMapper.key(a)); target.endTag("action"); } target.endTag("actions"); } - if (partialUpdate) { - partialUpdate = false; + if (this.partialUpdate) { + this.partialUpdate = false; } else { // Selected target.addVariable(this, "selected", selectedKeys); @@ -542,7 +564,7 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.data.Container.Hierarchical#areChildrenAllowed(Object) */ public boolean areChildrenAllowed(Object itemId) { - return ((Container.Hierarchical) items).areChildrenAllowed(itemId); + return ((Container.Hierarchical) this.items).areChildrenAllowed(itemId); } /** @@ -551,7 +573,7 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.data.Container.Hierarchical#getChildren(Object) */ public Collection getChildren(Object itemId) { - return ((Container.Hierarchical) items).getChildren(itemId); + return ((Container.Hierarchical) this.items).getChildren(itemId); } /** @@ -560,7 +582,7 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.data.Container.Hierarchical#getParent(Object) */ public Object getParent(Object itemId) { - return ((Container.Hierarchical) items).getParent(itemId); + return ((Container.Hierarchical) this.items).getParent(itemId); } /** @@ -570,7 +592,7 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.data.Container.Hierarchical#hasChildren(Object) */ public boolean hasChildren(Object itemId) { - return ((Container.Hierarchical) items).hasChildren(itemId); + return ((Container.Hierarchical) this.items).hasChildren(itemId); } /** @@ -579,7 +601,7 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.data.Container.Hierarchical#isRoot(Object) */ public boolean isRoot(Object itemId) { - return ((Container.Hierarchical) items).isRoot(itemId); + return ((Container.Hierarchical) this.items).isRoot(itemId); } /** @@ -588,7 +610,7 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.data.Container.Hierarchical#rootItemIds() */ public Collection rootItemIds() { - return ((Container.Hierarchical) items).rootItemIds(); + return ((Container.Hierarchical) this.items).rootItemIds(); } /** @@ -598,10 +620,11 @@ public class Tree extends Select implements Container.Hierarchical, * boolean) */ public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) { - boolean success = ((Container.Hierarchical) items).setChildrenAllowed( - itemId, areChildrenAllowed); - if (success) + boolean success = ((Container.Hierarchical) this.items) + .setChildrenAllowed(itemId, areChildrenAllowed); + if (success) { fireValueChange(false); + } return success; } @@ -612,10 +635,11 @@ public class Tree extends Select implements Container.Hierarchical, * Object) */ public boolean setParent(Object itemId, Object newParentId) { - boolean success = ((Container.Hierarchical) items).setParent(itemId, - newParentId); - if (success) + boolean success = ((Container.Hierarchical) this.items).setParent( + itemId, newParentId); + if (success) { requestRepaint(); + } return success; } @@ -631,11 +655,12 @@ public class Tree extends Select implements Container.Hierarchical, // Assure that the data source is ordered by making unordered // containers ordered by wrapping them if (Container.Hierarchical.class.isAssignableFrom(newDataSource - .getClass())) + .getClass())) { super.setContainerDataSource(newDataSource); - else + } else { super.setContainerDataSource(new ContainerHierarchicalWrapper( newDataSource)); + } } /* Expand event and listener ****************************************** */ @@ -657,7 +682,7 @@ public class Tree extends Select implements Container.Hierarchical, */ private static final long serialVersionUID = 3832624001804481075L; - private Object expandedItemId; + private final Object expandedItemId; /** * New instance of options change event @@ -747,7 +772,7 @@ public class Tree extends Select implements Container.Hierarchical, */ private static final long serialVersionUID = 3257009834783290160L; - private Object collapsedItemId; + private final Object collapsedItemId; /** * New instance of options change event. @@ -767,7 +792,7 @@ public class Tree extends Select implements Container.Hierarchical, * @return the collapsed item id. */ public Object getItemId() { - return collapsedItemId; + return this.collapsedItemId; } } @@ -831,13 +856,13 @@ public class Tree extends Select implements Container.Hierarchical, if (actionHandler != null) { - if (actionHandlers == null) { - actionHandlers = new LinkedList(); - actionMapper = new KeyMapper(); + if (this.actionHandlers == null) { + this.actionHandlers = new LinkedList(); + this.actionMapper = new KeyMapper(); } - if (!actionHandlers.contains(actionHandler)) { - actionHandlers.add(actionHandler); + if (!this.actionHandlers.contains(actionHandler)) { + this.actionHandlers.add(actionHandler); requestRepaint(); } } @@ -850,13 +875,14 @@ public class Tree extends Select implements Container.Hierarchical, */ public void removeActionHandler(Action.Handler actionHandler) { - if (actionHandlers != null && actionHandlers.contains(actionHandler)) { + if (this.actionHandlers != null + && this.actionHandlers.contains(actionHandler)) { - actionHandlers.remove(actionHandler); + this.actionHandlers.remove(actionHandler); - if (actionHandlers.isEmpty()) { - actionHandlers = null; - actionMapper = null; + if (this.actionHandlers.isEmpty()) { + this.actionHandlers = null; + this.actionMapper = null; } requestRepaint(); @@ -875,8 +901,9 @@ public class Tree extends Select implements Container.Hierarchical, // Iterates trough hierarchical tree using a stack of iterators Stack iteratorStack = new Stack(); Collection ids = rootItemIds(); - if (ids != null) + if (ids != null) { iteratorStack.push(ids.iterator()); + } while (!iteratorStack.isEmpty()) { // Gets the iterator for current tree level @@ -914,8 +941,9 @@ public class Tree extends Select implements Container.Hierarchical, */ public void setNewItemsAllowed(boolean allowNewOptions) throws UnsupportedOperationException { - if (allowNewOptions) + if (allowNewOptions) { throw new UnsupportedOperationException(); + } } /** @@ -936,9 +964,10 @@ public class Tree extends Select implements Container.Hierarchical, * @see com.itmill.toolkit.ui.Select#setLazyLoading(boolean) */ public void setLazyLoading(boolean useLazyLoading) { - if (useLazyLoading) + if (useLazyLoading) { throw new UnsupportedOperationException( "Lazy options loading is not supported by Tree."); + } } } diff --git a/src/com/itmill/toolkit/ui/TwinColSelect.java b/src/com/itmill/toolkit/ui/TwinColSelect.java index ec129934ce..70bbf47098 100644 --- a/src/com/itmill/toolkit/ui/TwinColSelect.java +++ b/src/com/itmill/toolkit/ui/TwinColSelect.java @@ -10,10 +10,10 @@ import com.itmill.toolkit.terminal.PaintException; import com.itmill.toolkit.terminal.PaintTarget; /** - * Multiselect component with two lists: left side for available items and right side for - * selected items. + * Multiselect component with two lists: left side for available items and right + * side for selected items. */ -public class TwinColSelect extends Select { +public class TwinColSelect extends AbstractSelect { /** * diff --git a/src/com/itmill/toolkit/ui/select/ContainsFilter.java b/src/com/itmill/toolkit/ui/select/ContainsFilter.java deleted file mode 100644 index 6f4f353175..0000000000 --- a/src/com/itmill/toolkit/ui/select/ContainsFilter.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.itmill.toolkit.ui.select; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.itmill.toolkit.data.Item; -import com.itmill.toolkit.ui.Select; - -public class ContainsFilter implements OptionFilter { - private Select s; - - private ArrayList filteredItemsBuffer; - - private String prevFilter; - - public ContainsFilter(Select s) { - this.s = s; - } - - public List filter(String filterstring, int pageLength, int page) { - if (filterstring == null) { - filterstring = ""; - } - if (this.prevFilter != filterstring || filteredItemsBuffer == null) { - if ("".equals(filterstring)) { - this.filteredItemsBuffer = new ArrayList(s.getItemIds()); - } else if (s.getContainerDataSource() != null) { - // prefix MUST be in lowercase - filterstring = filterstring.toLowerCase(); - - // all items will be iterated and tested. - // SLOW when there are lot of items. - this.filteredItemsBuffer = new ArrayList(); - for (Iterator iter = s.getItemIds().iterator(); iter.hasNext();) { - Object id = iter.next(); - - Item item = s.getItem(id); - String test = ""; - if (s.getItemCaptionMode() == Select.ITEM_CAPTION_MODE_PROPERTY) - test = item.getItemProperty( - s.getItemCaptionPropertyId()).getValue() - .toString().trim(); - else - test = String.valueOf(id); - - if (test.toLowerCase().indexOf(filterstring) > -1) { - this.filteredItemsBuffer.add(id); - } - } - } - } - - prevFilter = filterstring; - - if (filteredItemsBuffer.size() > pageLength) { - int first = page * pageLength; - int last = first + pageLength; - if (filteredItemsBuffer.size() < last) { - last = filteredItemsBuffer.size(); - } - return filteredItemsBuffer.subList(first, last); - } else { - return filteredItemsBuffer; - } - } - - public int getMatchCount() { - return filteredItemsBuffer.size(); - } -} diff --git a/src/com/itmill/toolkit/ui/select/OptionFilter.java b/src/com/itmill/toolkit/ui/select/OptionFilter.java deleted file mode 100644 index 3b56eede4d..0000000000 --- a/src/com/itmill/toolkit/ui/select/OptionFilter.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.itmill.toolkit.ui.select; - -import java.util.List; - -public interface OptionFilter { - /** - * - * @param filterstring - * string to use in filtering - * @return List of filtered item id's - */ - public List filter(String filterstring, int pageLength, int page); - - /** - * Returns total matches in last filtering process - * - * @return - */ - public int getMatchCount(); -} diff --git a/src/com/itmill/toolkit/ui/select/StartsWithFilter.java b/src/com/itmill/toolkit/ui/select/StartsWithFilter.java deleted file mode 100644 index 9972aa5ac4..0000000000 --- a/src/com/itmill/toolkit/ui/select/StartsWithFilter.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.itmill.toolkit.ui.select; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.itmill.toolkit.data.Item; -import com.itmill.toolkit.ui.Select; - -public class StartsWithFilter implements OptionFilter { - private Select s; - - public StartsWithFilter(Select s) { - this.s = s; - } - - ArrayList filteredItemsBuffer; - - private String prevFilter; - - public List filter(String filterstring, int pageLength, int page) { - if (filterstring == null) { - filterstring = ""; - } - if (this.prevFilter != filterstring || filteredItemsBuffer == null) { - if ("".equals(filterstring)) { - this.filteredItemsBuffer = new ArrayList(s.getItemIds()); - } else if (s.getContainerDataSource() != null) { - // prefix MUST be in lowercase - filterstring = filterstring.toLowerCase(); - - // all items will be iterated and tested. - // SLOW when there are lot of items. - this.filteredItemsBuffer = new ArrayList(); - for (Iterator iter = s.getItemIds().iterator(); iter.hasNext();) { - Object id = iter.next(); - - Item item = s.getItem(id); - String test = ""; - if (s.getItemCaptionMode() == Select.ITEM_CAPTION_MODE_PROPERTY) - test = item.getItemProperty( - s.getItemCaptionPropertyId()).getValue() - .toString().trim(); - else - test = String.valueOf(id); - - if (test.toLowerCase().startsWith(filterstring)) { - this.filteredItemsBuffer.add(id); - } - } - } - } - - prevFilter = filterstring; - - if (filteredItemsBuffer.size() > pageLength) { - int first = page * pageLength; - int last = first + pageLength; - if (filteredItemsBuffer.size() < last) { - last = filteredItemsBuffer.size(); - } - return filteredItemsBuffer.subList(first, last); - } else { - return filteredItemsBuffer; - } - } - - public int getMatchCount() { - return filteredItemsBuffer.size(); - } -} -- 2.39.5