1. eckig
  2. ControlsFX

Commits

Jonathan Giles  committed a042623

Fix for CheckBoxTreeView (issue #199): The CheckModel for the CheckBoxTreeView is simplified and only deals with TreeItem<T> - it no longer supports integer indexing.

  • Participants
  • Parent commits 49362c1
  • Branches default

Comments (0)

Files changed (9)

File controlsfx-samples/src/main/java/org/controlsfx/samples/checked/HelloCheckComboBox.java

View file
 
 import org.controlsfx.ControlsFXSample;
 import org.controlsfx.control.CheckComboBox;
-import org.controlsfx.control.CheckModel;
+import org.controlsfx.control.IndexedCheckModel;
 import org.controlsfx.samples.Utils;
 
 public class HelloCheckComboBox extends ControlsFXSample {
         final CheckBox checkItem2Btn = new CheckBox();
         checkItem2Btn.setOnAction(new EventHandler<ActionEvent>() {
             @Override public void handle(ActionEvent e) {
-                CheckModel<String> cm = checkComboBox.getCheckModel();
+                IndexedCheckModel<String> cm = checkComboBox.getCheckModel();
                 if (cm.isChecked(2)) {
                     cm.clearCheck(2);
                 } else {

File controlsfx-samples/src/main/java/org/controlsfx/samples/checked/HelloCheckListView.java

View file
 
 import org.controlsfx.ControlsFXSample;
 import org.controlsfx.control.CheckListView;
-import org.controlsfx.control.CheckModel;
+import org.controlsfx.control.IndexedCheckModel;
 import org.controlsfx.samples.Utils;
 
 public class HelloCheckListView extends ControlsFXSample {
         final CheckBox checkItem2Btn = new CheckBox();
         checkItem2Btn.setOnAction(new EventHandler<ActionEvent>() {
             @Override public void handle(ActionEvent e) {
-                CheckModel<String> cm = checkListView.getCheckModel();
+                IndexedCheckModel<String> cm = checkListView.getCheckModel();
                 if (cm.isChecked(2)) {
                     cm.clearCheck(2);
                 } else {

File controlsfx-samples/src/main/java/org/controlsfx/samples/checked/HelloCheckTreeView.java

View file
 
 import org.controlsfx.ControlsFXSample;
 import org.controlsfx.control.CheckModel;
+import org.controlsfx.control.IndexedCheckModel;
 import org.controlsfx.control.CheckTreeView;
 import org.controlsfx.samples.Utils;
 
     private final Label selectedItemsLabel = new Label();
     
     private CheckTreeView<String> checkTreeView;
+    
+    private CheckBoxTreeItem<String> treeItem_Jonathan = new CheckBoxTreeItem<>("Jonathan");
+    private CheckBoxTreeItem<String> treeItem_Eugene = new CheckBoxTreeItem<>("Eugene");
+    private CheckBoxTreeItem<String> treeItem_Henry = new CheckBoxTreeItem<>("Henry");
+    private CheckBoxTreeItem<String> treeItem_Samir = new CheckBoxTreeItem<>("Samir");
 
     @Override public String getSampleName() {
         return "CheckTreeView";
         CheckBoxTreeItem<String> root = new CheckBoxTreeItem<String>("Root");
         root.setExpanded(true);
         root.getChildren().addAll(
-                new CheckBoxTreeItem<String>("Jonathan"),
-                new CheckBoxTreeItem<String>("Eugene"),
-                new CheckBoxTreeItem<String>("Henri"),
-                new CheckBoxTreeItem<String>("Samir"));
+                treeItem_Jonathan,
+                treeItem_Eugene,
+                treeItem_Henry,
+                treeItem_Samir);
         
         // lets check Eugene to make sure that it shows up in the tree
-        ((CheckBoxTreeItem<String>)root.getChildren().get(1)).setSelected(true);
+        treeItem_Eugene.setSelected(true);
         
         // CheckListView
         checkTreeView = new CheckTreeView<>(root);
         checkItem2Label.getStyleClass().add("property");
         grid.add(checkItem2Label, 0, row);
         final CheckBox checkItem2Btn = new CheckBox();
-        checkItem2Btn.setOnAction(new EventHandler<ActionEvent>() {
-            @Override public void handle(ActionEvent e) {
-                CheckModel<TreeItem<String>> cm = checkTreeView.getCheckModel();
-                if (cm.isChecked(1)) {
-                    cm.clearCheck(1);
-                } else {
-                    cm.check(1);
-                }
-            }
-        });
+        checkItem2Btn.selectedProperty().bindBidirectional(treeItem_Jonathan.selectedProperty());
         grid.add(checkItem2Btn, 1, row++);
         
         return grid;

File controlsfx/src/main/java/org/controlsfx/control/CheckBitSetModelBase.java

View file
 import com.sun.javafx.scene.control.ReadOnlyUnbackedObservableList;
 
 // not public API
-abstract class CheckBitSetModelBase<T> implements CheckModel<T> { // extends MultipleSelectionModel<T> {
+abstract class CheckBitSetModelBase<T> implements IndexedCheckModel<T> { 
     
     /***********************************************************************
      *                                                                     *
             check(indices[i]);
         }
     }
+    
+    /** {@inheritDoc} */
+    @Override public void clearCheck(T item) {
+        int index = getItemIndex(item);
+        clearCheck(index);        
+    }
 
     /** {@inheritDoc} */
     @Override
     public boolean isEmpty() {
         return checkedIndices.isEmpty();
     }
+    
+    /** {@inheritDoc} */
+    @Override public boolean isChecked(T item) {
+        int index = getItemIndex(item);
+        return isChecked(index);
+    }
 
     /** {@inheritDoc} */
     @Override

File controlsfx/src/main/java/org/controlsfx/control/CheckComboBox.java

View file
      **************************************************************************/
 
     // --- Check Model
-    private ObjectProperty<CheckModel<T>> checkModel = 
+    private ObjectProperty<IndexedCheckModel<T>> checkModel = 
             new SimpleObjectProperty<>(this, "checkModel"); //$NON-NLS-1$
     
     /**
      * selection model concept, which is used in the ComboBox control to 
      * represent the selection state of each row).. 
      */
-    public final void setCheckModel(CheckModel<T> value) {
+    public final void setCheckModel(IndexedCheckModel<T> value) {
         checkModelProperty().set(value);
     }
 
     /**
      * Returns the currently installed check model.
      */
-    public final CheckModel<T> getCheckModel() {
+    public final IndexedCheckModel<T> getCheckModel() {
         return checkModel == null ? null : checkModel.get();
     }
 
      * which items have been checked by the user. Note that it has a generic
      * type that must match the type of the CheckComboBox itself.
      */
-    public final ObjectProperty<CheckModel<T>> checkModelProperty() {
+    public final ObjectProperty<IndexedCheckModel<T>> checkModelProperty() {
         return checkModel;
     }
     

File controlsfx/src/main/java/org/controlsfx/control/CheckListView.java

View file
      **************************************************************************/
 
     // --- Check Model
-    private ObjectProperty<CheckModel<T>> checkModel = 
+    private ObjectProperty<IndexedCheckModel<T>> checkModel = 
             new SimpleObjectProperty<>(this, "checkModel"); //$NON-NLS-1$
     
     /**
      * selection model concept, which is used in the ListView control to 
      * represent the selection state of each row).. 
      */
-    public final void setCheckModel(CheckModel<T> value) {
+    public final void setCheckModel(IndexedCheckModel<T> value) {
         checkModelProperty().set(value);
     }
 
     /**
      * Returns the currently installed check model.
      */
-    public final CheckModel<T> getCheckModel() {
+    public final IndexedCheckModel<T> getCheckModel() {
         return checkModel == null ? null : checkModel.get();
     }
 
      * which items have been checked by the user. Note that it has a generic
      * type that must match the type of the CheckListView itself.
      */
-    public final ObjectProperty<CheckModel<T>> checkModelProperty() {
+    public final ObjectProperty<IndexedCheckModel<T>> checkModelProperty() {
         return checkModel;
     }
     

File controlsfx/src/main/java/org/controlsfx/control/CheckModel.java

View file
 import javafx.collections.ObservableList;
 
 public interface CheckModel<T> {
-
-    /**
-     * Returns the item in the given index in the control.
-     */
-    public T getItem(int index);
-
+    
     /**
      * Returns the count of items in the control.
      */
     public int getItemCount();
 
     /**
-     * Returns the index of the given item.
-     */
-    public int getItemIndex(T item);
-
-    /**
-     * Returns a read-only list of the currently checked indices in the control.
-     */
-    public ObservableList<Integer> getCheckedIndices();
-
-    /**
      * Returns a read-only list of the currently checked items in the control.
      */
     public ObservableList<T> getCheckedItems();
      * Checks all items in the control
      */
     public void checkAll();
-
-    /**
-     * Checks the given indices in the control
-     */
-    public void checkIndices(int... indices);
-
+    
+    public void clearCheck(T item);
+    
     /**
      * Unchecks all items in the control
      */
     public void clearChecks();
-
-    /**
-     * Unchecks the given index in the control
-     */
-    public void clearCheck(int index);
-
+    
     /**
      * Returns true if there are no checked items in the control.
      */
     public boolean isEmpty();
-
-    /**
-     * Returns true if the given index represents an item that is checked in the control.
-     */
-    public boolean isChecked(int index);
-
-    /**
-     * Checks the item in the given index in the control.
-     */
-    public void check(int index);
-
+    
+    public boolean isChecked(T item);
+    
     /**
      * Checks the given item in the control.
      */
     public void check(T item);
-
-}
+}

File controlsfx/src/main/java/org/controlsfx/control/CheckTreeView.java

View file
  */
 package org.controlsfx.control;
 
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.function.Consumer;
+
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
 import javafx.event.EventHandler;
 import javafx.scene.control.CheckBox;
 import javafx.scene.control.CheckBoxTreeItem;
     public CheckTreeView(final CheckBoxTreeItem<T> root) {
         super(root);
         
-        setCheckModel(new CheckTreeViewBitSetCheckModel<T>(this));
+        setCheckModel(new CheckTreeViewCheckModel<T>(this));
         setCellFactory(CheckBoxTreeCell.<T>forTreeView());
     }
     
      * 
      **************************************************************************/
     
-    private static class CheckTreeViewBitSetCheckModel<T> extends CheckBitSetModelBase<TreeItem<T>> {
+    private static class CheckTreeViewCheckModel<T> implements CheckModel<TreeItem<T>> {// extends CheckBitSetModelBase<TreeItem<T>> {
         
         /***********************************************************************
          *                                                                     *
         private final CheckTreeView<T> treeView;
         private final TreeItem<T> root;
         
+        private ObservableList<TreeItem<T>> checkedItems = FXCollections.observableArrayList();
+        
         
         
         /***********************************************************************
          *                                                                     *
          **********************************************************************/
         
-        CheckTreeViewBitSetCheckModel(final CheckTreeView<T> treeView) {
-            super(null);
-            
+        CheckTreeViewCheckModel(final CheckTreeView<T> treeView) {
             this.treeView = treeView;
             this.root = treeView.getRoot();
             this.root.addEventHandler(CheckBoxTreeItem.<T>checkBoxSelectionChangedEvent(), new EventHandler<TreeModificationEvent<T>>() {
                 public void handle(TreeModificationEvent<T> e) {
                     CheckBoxTreeItem<T> treeItem = e.getTreeItem();
                     
-                    final int index = getItemIndex(treeItem);
-                    if (treeItem.isSelected() && ! treeItem.isIndeterminate()) {
-                        check(index);
+                    if (treeItem.isSelected()) { // && ! treeItem.isIndeterminate()) {
+                        check(treeItem);
                     } else { 
-                        clearCheck(index);
+                        clearCheck(treeItem);
                     }
                 }
             });
             for (int i = 0; i < treeView.getExpandedItemCount(); i++) {
                 CheckBoxTreeItem<T> treeItem = (CheckBoxTreeItem<T>) treeView.getTreeItem(i);
                 if (treeItem.isSelected() && ! treeItem.isIndeterminate()) {
-                    check(i);
+                    check(treeItem);
                 }
             }
         }
          *                                                                     *
          **********************************************************************/
 
-        @Override public TreeItem<T> getItem(int index) {
-            return treeView.getTreeItem(index);
-        }
-        
         @Override public int getItemCount() {
             return treeView.getExpandedItemCount();
         }
-        
-        @Override public int getItemIndex(TreeItem<T> item) {
-            return treeView.getRow(item);
+
+
+        // TODO make read-only
+        @Override public ObservableList<TreeItem<T>> getCheckedItems() {
+            return checkedItems;
         }
-        
-        @Override BooleanProperty getItemBooleanProperty(TreeItem<T> item) {
-            if (item == null) return null;
-            return ((CheckBoxTreeItem<T>)item).selectedProperty();
+
+        @Override public void checkAll() {
+            iterateOverTree(this::check);
+        }
+
+        @Override public void clearCheck(TreeItem<T> item) {
+            if (item instanceof CheckBoxTreeItem) {
+                ((CheckBoxTreeItem<T>)item).setSelected(false);
+            }
+            checkedItems.remove(item);
+        }
+
+        @Override public void clearChecks() {
+            checkedItems.stream().forEach(this::clearCheck);
+        }
+
+        @Override public boolean isEmpty() {
+            return checkedItems.isEmpty();
+        }
+
+        @Override public boolean isChecked(TreeItem<T> item) {
+            return checkedItems.contains(item);
+        }
+
+        @Override public void check(TreeItem<T> item) {
+            if (item instanceof CheckBoxTreeItem) {
+                ((CheckBoxTreeItem<T>)item).setSelected(true);
+            }
+            if (!checkedItems.contains(item)) {
+                checkedItems.add(item);
+            }
         }
         
         
         
         /***********************************************************************
          *                                                                     *
-         * Overriding public API                                               *
+         * Private Implementation                                              *
          *                                                                     *
          **********************************************************************/
         
-        @Override protected void updateMap() {
-            // no-op
+        private void iterateOverTree(Consumer<TreeItem<T>> consumer) {
+            processNode(consumer, root);
+        }
+        
+        private void processNode(Consumer<TreeItem<T>> consumer, TreeItem<T> node) {
+            if (node == null) return;
+            consumer.accept(node);
+            processChildren(consumer, node.getChildren());
+        }
+        
+        private void processChildren(Consumer<TreeItem<T>> consumer, List<TreeItem<T>> children) {
+            if (children == null) return;
+            for (TreeItem<T> child : children) {
+                processNode(consumer, child);
+            }
         }
     }
 }

File controlsfx/src/main/java/org/controlsfx/control/IndexedCheckModel.java

View file
+package org.controlsfx.control;
+
+import javafx.collections.ObservableList;
+
+public interface IndexedCheckModel<T> extends CheckModel<T> {
+
+    /**
+     * Returns the item in the given index in the control.
+     */
+    public T getItem(int index);
+
+    /**
+     * Returns the index of the given item.
+     */
+    public int getItemIndex(T item);
+
+    /**
+     * Returns a read-only list of the currently checked indices in the control.
+     */
+    public ObservableList<Integer> getCheckedIndices();
+
+    /**
+     * Checks the given indices in the control
+     */
+    public void checkIndices(int... indices);
+
+    /**
+     * Unchecks the given index in the control
+     */
+    public void clearCheck(int index);
+
+    /**
+     * Returns true if the given index represents an item that is checked in the control.
+     */
+    public boolean isChecked(int index);
+
+    /**
+     * Checks the item in the given index in the control.
+     */
+    public void check(int index);
+
+}