1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation. Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javafx.scene.control.test.treetable;
  26 
  27 import com.sun.javafx.scene.control.skin.NestedTableColumnHeader;
  28 import com.sun.javafx.scene.control.skin.TableColumnHeader;
  29 import com.sun.javafx.scene.control.skin.TableHeaderRow;
  30 import com.sun.javafx.scene.control.skin.TreeTableViewSkin;
  31 import java.util.ArrayList;
  32 import java.util.Comparator;
  33 import java.util.HashMap;
  34 import java.util.Iterator;
  35 import java.util.Map;
  36 import javafx.beans.property.SimpleStringProperty;
  37 import javafx.beans.property.StringProperty;
  38 import javafx.beans.value.ChangeListener;
  39 import javafx.beans.value.ObservableValue;
  40 import javafx.collections.FXCollections;
  41 import javafx.collections.ObservableList;
  42 import static javafx.commons.Consts.*;
  43 import javafx.commons.Consts.CellEditorType;
  44 import javafx.event.ActionEvent;
  45 import javafx.event.Event;
  46 import javafx.event.EventHandler;
  47 import javafx.geometry.Insets;
  48 import javafx.geometry.Orientation;
  49 import javafx.scene.Node;
  50 import javafx.scene.Scene;
  51 import javafx.scene.control.*;
  52 import javafx.scene.control.TreeTableColumn.CellDataFeatures;
  53 import javafx.scene.control.cell.ChoiceBoxTreeTableCell;
  54 import javafx.scene.control.cell.ComboBoxTreeTableCell;
  55 import javafx.scene.control.cell.TextFieldTreeTableCell;
  56 import javafx.scene.control.test.tableview.NewTableViewApp;
  57 import javafx.scene.control.test.treeview.TreeViewConstants;
  58 import javafx.scene.control.test.utils.CommonPropertiesScene;
  59 import javafx.scene.control.test.utils.ComponentsFactory.MultipleIndexFormComponent;
  60 import javafx.scene.control.test.utils.ComponentsFactory.MultipleIndexFormComponent.MultipleIndicesAction;
  61 import javafx.scene.control.test.utils.ptables.NodeControllerFactory;
  62 import javafx.scene.control.test.utils.ptables.PropertiesTable;
  63 import javafx.scene.control.test.utils.ptables.PropertyTablesFactory;
  64 import javafx.scene.control.test.utils.ptables.SpecialTablePropertiesProvider;
  65 import javafx.scene.control.test.utils.ptables.TabPaneWithControl;
  66 import javafx.scene.input.KeyCode;
  67 import javafx.scene.input.KeyEvent;
  68 import javafx.scene.layout.HBox;
  69 import javafx.scene.layout.Pane;
  70 import javafx.scene.layout.VBox;
  71 import javafx.util.Callback;
  72 import test.javaclient.shared.InteroperabilityApp;
  73 import test.javaclient.shared.Utils;
  74 import static org.junit.Assert.assertTrue;
  75 
  76 /**
  77  * @author Alexander Kirov
  78  */
  79 public class TreeTableNewApp extends InteroperabilityApp implements TreeViewConstants, ResetButtonNames {
  80 
  81     public final static String TESTED_TREETABLEVIEW_ID = "TESTED_TREETABLEVIEW_ID";
  82     public final static String TREE_DATA_COLUMN_NAME = "TreeData";
  83     public final static String REMOVE_MULTIPLE_COLUMNS_TEXT_FIELD_ID = "REMOVE_MULTIPLE_COLUMNS_TEXT_FIELD_ID";
  84     public final static String REMOVE_MULTIPLE_COLUMNS_ACTION_BUTTON_ID = "REMOVE_MULTIPLE_COLUMNS_ACTION_BUTTON_ID";
  85     public final static String REMOVE_DATA_ITEMS_MULTIPLE_TEXT_FIELD_ID = "REMOVE_DATA_ITEMS_MULTIPLE_TEXT_FIELD_ID";
  86     public final static String REMOVE_DATA_ITEMS_MULTIPLE_ACTION_BUTTON_ID = "REMOVE_DATA_ITEMS_MULTIPLE_ACTION_BUTTON_ID";
  87     public final static String CREATE_NESTED_COLUMN_MULTIPLE_TEXTFIELD_ID = "CREATE_NESTED_COLUMN_MULTIPLE_TEXTFIELD_ID";
  88     public final static String CREATE_NESTED_COLUMN_MULTIPLE_ACTION_BUTTON_ID = "CREATE_NESTED_COLUMN_MULTIPLE_ACTION_BUTTON_ID";
  89     public final static String TREE_TABLE_VIEW_TAB_NAME = "TreeTableView";
  90     public final static Comparator<TreeItem<TreeTableNewApp.DataItem>> DEFAULT_TREE_ITEM_COMPARATOR = new Comparator<TreeItem<TreeTableNewApp.DataItem>>() {
  91         public int compare(TreeItem<TreeTableNewApp.DataItem> t1, TreeItem<TreeTableNewApp.DataItem> t2) {
  92             DataItem first = t1.getValue();
  93             DataItem second = t2.getValue();
  94             return first.compareTo(second);
  95         }
  96     };
  97 
  98     public static void main(String[] args) {
  99         Utils.launch(TreeTableNewApp.class, args);
 100     }
 101 
 102     @Override
 103     protected Scene getScene() {
 104         Utils.setTitleToStage(stage, "TreeTableTestApp");
 105         return new TreeTableScene();
 106     }
 107 
 108     public static TreeItem searchTreeItem(TreeTableView treeView, String content) {
 109         if (treeView.getRoot() != null) {
 110             return recursiveSearch(content, treeView.getRoot());
 111         }
 112         return null;
 113     }
 114 
 115     protected static TreeItem recursiveSearch(String content, TreeItem<? extends DataItem> itemToStart) {
 116         if (null != itemToStart.getValue()
 117                 && (content.equals(itemToStart.getValue().getTreeValue().getValue())
 118                 || itemToStart.getValue().contains(content))) {
 119             return itemToStart;
 120         } else {
 121             for (TreeItem child : itemToStart.getChildren()) {
 122                 TreeItem recResult = recursiveSearch(content, child);
 123                 if (recResult != null) {
 124                     return recResult;
 125                 }
 126             }
 127             return null;
 128         }
 129     }
 130 
 131     protected class TreeTableScene extends CommonPropertiesScene {
 132 
 133         //TreeTableView instance to be tested.
 134         private TreeTableView testedControl;
 135         //TabPane with PropertiesTable.
 136         private TabPaneWithControl tabPane;
 137         //Properties table of the control
 138         private PropertiesTable tb;
 139         //Container for all the data.
 140         private ObservableList<DataItem> allData;
 141         //List of existing columnsin current tableView.
 142         private Map<String, TreeTableColumn> existingColumns = new HashMap<String, TreeTableColumn>();
 143         //This list contains all properties tables, which were created during testing.
 144         private ArrayList<PropertiesTable> allPropertiesTables;
 145 
 146         public TreeTableScene() {
 147             super("TreeTableControl", 800, 600);
 148             prepareScene();
 149         }
 150 
 151         protected TreeTableView getTestedTreeTable() {
 152             TreeTableView tv = new TreeTableView();
 153             DataItem item = new DataItem(ROOT_NAME);
 154             allData.add(item);
 155             tv.setRoot(new TreeItem(item));
 156             tv.setShowRoot(true);
 157             tv.setId(TESTED_TREETABLEVIEW_ID);
 158             return tv;
 159         }
 160 
 161         @Override
 162         final protected void prepareScene() {
 163             allData = FXCollections.observableArrayList();
 164             testedControl = getTestedTreeTable();
 165             tb = new PropertiesTable(testedControl);
 166 
 167             tb.addCounter(EDIT_START_COUNTER);
 168             tb.addCounter(EDIT_COMMIT_COUNTER);
 169             tb.addCounter(EDIT_CANCEL_COUNTER);
 170             tb.addCounter(COUNTER_ON_SORT);
 171             testedControl.setOnSort(new EventHandler<SortEvent<TableView<DataItem>>>() {
 172                 public void handle(SortEvent<TableView<DataItem>> event) {
 173                     tb.incrementCounter(COUNTER_ON_SORT);
 174                 }
 175             });
 176 
 177             allPropertiesTables = new ArrayList<PropertiesTable>();
 178 
 179             PropertyTablesFactory.explorePropertiesList(testedControl, tb);
 180             PropertyTablesFactory.explorePropertiesList(testedControl.getSelectionModel(), tb);
 181             PropertyTablesFactory.explorePropertiesList(testedControl.getFocusModel(), tb);
 182             SpecialTablePropertiesProvider.provideForControl(testedControl, tb);
 183 
 184             tabPane = new TabPaneWithControl(TREE_TABLE_VIEW_TAB_NAME, tb);
 185             getControlOverItem(ROOT_NAME);
 186 
 187             tb.setStyle("-fx-border-color : yellow;");
 188 
 189             VBox vb = new VBox();
 190             vb.setSpacing(5);
 191 
 192             HBox hb = (HBox) getRoot();
 193             hb.setPadding(new Insets(5, 5, 5, 5));
 194             hb.setStyle("-fx-border-color : green;");
 195 
 196             Button resetButton = ButtonBuilder.create().id(HARD_RESET_BUTTON_ID).text("Reset").build();
 197             resetButton.setOnAction(new EventHandler<ActionEvent>() {
 198                 public void handle(ActionEvent t) {
 199                     HBox hb = (HBox) getRoot();
 200                     hb.getChildren().clear();
 201                     prepareMainSceneStructure();
 202                     prepareScene();
 203                 }
 204             });
 205 
 206             Button autosize = new Button("Autosize");
 207             autosize.setId(AUTOSIZE_BUTTON_ID);
 208             autosize.setOnAction(new EventHandler<ActionEvent>() {
 209                 public void handle(ActionEvent t) {
 210                     testedControl.autosize();
 211                 }
 212             });
 213 
 214             VBox vbActionMakers = new VBox();
 215 
 216             vbActionMakers.getChildren().addAll(resetButton, autosize, new Separator(Orientation.HORIZONTAL),
 217                     getAddColumnForm(), new Separator(Orientation.HORIZONTAL),
 218                     getAddNestedColumnVBox(), new Separator(Orientation.HORIZONTAL),
 219                     getChangeDataSizeForm(), new Separator(Orientation.HORIZONTAL),
 220                     getRemoveColumnsVBox(), new Separator(Orientation.HORIZONTAL),
 221                     getTreeViewAddItemController(), new Separator(Orientation.HORIZONTAL),
 222                     getTreeViewRemoveItemController(), new Separator(Orientation.HORIZONTAL),
 223                     getTabOverItemThroughGetItemMethodController(), new Separator(Orientation.HORIZONTAL),
 224                     getTabOverItemController(), new Separator(Orientation.HORIZONTAL),
 225                     getObjectTitleThroughGetItemMethodController(), new Separator(Orientation.HORIZONTAL),
 226                     getLineOfItemController(), new Separator(Orientation.HORIZONTAL),
 227                     getScrollToHBox(), new Separator(Orientation.HORIZONTAL),
 228                     getEditHBox(), new Separator(Orientation.HORIZONTAL),
 229                     getReplaceTableHeaderImplementationButton(), new Separator(Orientation.HORIZONTAL),
 230                     setEventHandlersHBox(), new Separator(Orientation.HORIZONTAL),
 231                     controlsForEditing());
 232 
 233             ScrollPane scrollPaneWithActionMakers = new ScrollPane();
 234             scrollPaneWithActionMakers.setContent(vbActionMakers);
 235             scrollPaneWithActionMakers.setPrefHeight(1000);
 236             scrollPaneWithActionMakers.setPannable(true);
 237 
 238             setTestedControl(testedControl);
 239             setPropertiesContent(tabPane);
 240             setControllersContent(scrollPaneWithActionMakers);
 241             setTestedControlContainerSize(300, 220);
 242         }
 243 
 244         private HBox getChangeDataSizeForm() {
 245             final TextField sizeTf = new TextField();
 246             sizeTf.setId(NEW_DATA_SIZE_TEXTFIELD_ID);
 247             sizeTf.setPromptText("new size (rows)");
 248 
 249             Button button = new Button("set");
 250             button.setId(NEW_DATA_SIZE_BUTTON_ID);
 251             button.setOnAction(new EventHandler<ActionEvent>() {
 252                 public void handle(ActionEvent t) {
 253                     if (!testedControl.getRoot().isExpanded()) {
 254                         testedControl.getRoot().setExpanded(true);
 255                     }
 256                     int actualSize = testedControl.getRoot().getChildren().size();
 257                     int newSize = Integer.parseInt(sizeTf.getText());
 258                     if (actualSize > newSize) {
 259                         int toRemove = actualSize - newSize;
 260                         for (int i = 0; i < toRemove; i++) {
 261                             allData.remove(0);
 262                             testedControl.getRoot().getChildren().remove(0);
 263                         }
 264                     } else if (actualSize < newSize) {
 265                         int toAdd = newSize - actualSize;
 266                         for (int i = 0; i < toAdd; i++) {
 267                             DataItem dataItem = new DataItem();
 268                             for (String columnName : existingColumns.keySet()) {
 269                                 dataItem.add(columnName, new SimpleStringProperty(columnName + "-" + String.valueOf(actualSize + i)));
 270                             }
 271                             allData.add(dataItem);
 272                             testedControl.getRoot().getChildren().add(new TreeItem(dataItem));
 273                         }
 274                     }
 275                 }
 276             });
 277 
 278             HBox hb1 = new HBox(3);
 279             hb1.getChildren().addAll(new Label("New size:"), sizeTf, button);
 280 
 281             Button addSortableRows = new Button("Add sortable rows");
 282             addSortableRows.setId(BTN_CREATE_SORTABLE_ROWS_ID);
 283             addSortableRows.setOnAction(new EventHandler<ActionEvent>() {
 284                 public void handle(ActionEvent t) {
 285                     allData.clear();
 286                     TreeItem root = testedControl.getRoot();
 287                     root.getChildren().clear();
 288                     root.setExpanded(true);
 289 
 290                     ObservableList<TableColumn<DataItem, ?>> columns = testedControl.getColumns();
 291                     String[][] testData = NewTableViewApp.getDataForSorting(columns.size());
 292 
 293                     for (int x = 0; x < testData.length; x++) {
 294                         DataItem dataItem = new DataItem();
 295                         int z = 0;
 296                         //Use the correct order of columns as they are placed.
 297                         //From left to right
 298                         for (int i = 0; i < testData[i].length; i++) {
 299                             TableColumnBase col = columns.get(i);
 300                             dataItem.add(col.getText(), new SimpleStringProperty(testData[x][z++]));
 301                         }
 302                         allData.add(dataItem);
 303 
 304                         root.getChildren().add(new TreeItem(dataItem));
 305                     }
 306                 }
 307             });
 308 
 309             HBox topContainer = new HBox();
 310 
 311             VBox internalContainer = new VBox(5.0);
 312             internalContainer.getChildren().addAll(hb1, addSortableRows);
 313 
 314             topContainer.getChildren().add(internalContainer);
 315             return topContainer;
 316 
 317 //            return hb1;
 318         }
 319 
 320         private VBox getAddColumnForm() {
 321             final TextField tfColumnName = new TextField();
 322             tfColumnName.setPromptText("new column name");
 323             tfColumnName.setId(NEW_COLUMN_NAME_TEXTFIELD_ID);
 324 
 325             final TextField indexTf = new TextField();
 326             indexTf.setPromptText("at index");
 327             indexTf.setId(NEW_COLUMN_INDEX_TEXTFIELD_UD);
 328 
 329             final CheckBox addDataPropertiesTabToTab = new CheckBox("with properties table for data");
 330             addDataPropertiesTabToTab.setId(NEW_COLUMN_GET_DATA_PROPERTIES_TAB_ID);
 331 
 332             final CheckBox addColumnPropertiesTableToTab = new CheckBox("with properties table for column");
 333             addColumnPropertiesTableToTab.setId(NEW_COLUMN_GET_COLUMN_PROPERTIES_TAB_ID);
 334 
 335             Button button = new Button("Add");
 336             button.setId(NEW_COLUMN_ADD_BUTTON_ID);
 337             button.setOnAction(new EventHandler<ActionEvent>() {
 338                 public void handle(ActionEvent t) {
 339                     final String name = tfColumnName.getText();
 340                     int index = Integer.parseInt(indexTf.getText());
 341                     TreeTableColumn column = new TreeTableColumn(name);
 342                     if (TREE_DATA_COLUMN_NAME.equals(name)) {
 343                         column.setCellValueFactory(new Callback<CellDataFeatures<DataItem, String>, ObservableValue<String>>() {
 344                             public ObservableValue<String> call(CellDataFeatures<DataItem, String> p) {
 345                                 return p.getValue().getValue().getTreeValue();
 346                             }
 347                         });
 348                     } else {
 349                         column.setCellValueFactory(new Callback<CellDataFeatures<DataItem, String>, ObservableValue<String>>() {
 350                             public ObservableValue<String> call(CellDataFeatures<DataItem, String> p) {
 351                                 return p.getValue().getValue().get(name);
 352                             }
 353                         });
 354                     }
 355                     introduceColumn(name, column);
 356                     if (addColumnPropertiesTableToTab.isSelected()) {
 357                         tabPane.addPropertiesTable(name, NodeControllerFactory.createFullController(column, tabPane));
 358                     }
 359                     testedControl.getColumns().add(index, column);
 360                     if (addDataPropertiesTabToTab.isSelected()) {
 361                         final PropertiesTable forData = new PropertiesTable(null);
 362                         for (DataItem item : allData) {
 363                             forData.addStringLine(item.get(name), "new value");
 364                         }
 365                         tabPane.addPropertiesTable(name + " data", forData.getVisualRepresentation());
 366                     }
 367                 }
 368             });
 369 
 370             HBox hb1 = new HBox(3);
 371             hb1.getChildren().addAll(new Label("With name"), tfColumnName);
 372 
 373             HBox hb2 = new HBox(3);
 374             hb2.getChildren().addAll(new Label("At index"), indexTf, button);
 375 
 376             VBox vb = new VBox();
 377             vb.getChildren().addAll(hb1, addDataPropertiesTabToTab, addColumnPropertiesTableToTab, hb2);
 378             return vb;
 379         }
 380 
 381         VBox getAddNestedColumnVBox() {
 382             final TextField nestedColumnAtIndexTF = new TextField("0");
 383             nestedColumnAtIndexTF.setPromptText("index");
 384             nestedColumnAtIndexTF.setId(NESTED_COLUMN_INDEX_TEXT_FIELD_ID);
 385 
 386             final TextField nestedColumnNameTF = new TextField();
 387             nestedColumnNameTF.setPromptText("namex");
 388             nestedColumnNameTF.setId(NESTED_COLUMN_NAME_TEXT_FIELD_ID);
 389 
 390             HBox nestedColumnAdditionalNodes = new HBox();
 391             nestedColumnAdditionalNodes.getChildren().addAll(nestedColumnAtIndexTF, nestedColumnNameTF);
 392 
 393             MultipleIndicesAction executor = new MultipleIndexFormComponent.MultipleIndicesAction() {
 394                 public void onAction(int[] indices) {
 395                     int[] reversed = new int[indices.length];
 396                     for (int i = 0; i < indices.length; i++) {
 397                         reversed[i] = indices[indices.length - i - 1];
 398                     }
 399                     TreeTableColumn nestedColumn = new TreeTableColumn(nestedColumnNameTF.getText());
 400                     for (int i : indices) {
 401                         nestedColumn.getColumns().add(testedControl.getColumns().get(i));
 402                     }
 403                     for (int i : reversed) {
 404                         testedControl.getColumns().remove(i);
 405                     }
 406                     tabPane.addPropertiesTable(nestedColumnNameTF.getText(), NodeControllerFactory.createFullController(nestedColumn, tabPane));
 407                     testedControl.getColumns().add(Integer.valueOf(nestedColumnAtIndexTF.getText()), nestedColumn);
 408                 }
 409             };
 410 
 411             MultipleIndexFormComponent multipleIndexForm = new MultipleIndexFormComponent(
 412                     "Add nested column", nestedColumnAdditionalNodes, executor,
 413                     CREATE_NESTED_COLUMN_MULTIPLE_ACTION_BUTTON_ID,
 414                     CREATE_NESTED_COLUMN_MULTIPLE_TEXTFIELD_ID);
 415 
 416             return multipleIndexForm;
 417         }
 418 
 419         protected VBox getRemoveColumnsVBox() {
 420             MultipleIndicesAction executor = new MultipleIndexFormComponent.MultipleIndicesAction() {
 421                 public void onAction(int[] indices) {
 422                     ObservableList onRemoving = FXCollections.observableArrayList();
 423                     for (int index : indices) {
 424                         onRemoving.add(testedControl.getColumns().get(index));
 425                     }
 426                     testedControl.getColumns().removeAll(onRemoving);
 427                 }
 428             };
 429             MultipleIndexFormComponent multipleIndexForm = new MultipleIndexFormComponent(
 430                     "Remove columns", null, executor,
 431                     REMOVE_MULTIPLE_COLUMNS_ACTION_BUTTON_ID,
 432                     REMOVE_MULTIPLE_COLUMNS_TEXT_FIELD_ID);
 433             return multipleIndexForm;
 434         }
 435 //
 436 //        VBox getRemoveDataVBox() {
 437 //            MultipleIndexFormComponent multipleIndexForm = new MultipleIndexFormComponent("Remove data items", null, new MultipleIndexFormComponent.MultipleIndicesAction() {
 438 //                public void onAction(int[] indices) {
 439 //                    ObservableList onRemoving = FXCollections.observableArrayList();
 440 //                    for (int index : indices) {
 441 //                        onRemoving.add(testedControl.getTreeItem(index));
 442 //                    }
 443 //                    testedControl.getItems().removeAll(onRemoving);
 444 //                }
 445 //            });
 446 //
 447 //            REMOVE_DATA_ITEMS_MULTIPLE_TEXT_FIELD_ID = multipleIndexForm.MULTIPLE_INDECES_TEXTFIELD_ID;
 448 //            REMOVE_DATA_ITEMS_MULTIPLE_ACTION_BUTTON_ID = multipleIndexForm.ACTION_BUTTON_ID;
 449 //            return multipleIndexForm;
 450 //        }
 451 
 452         private void introduceColumn(String columnName, TreeTableColumn column) {
 453             existingColumns.put(columnName, column);
 454             int counter = 0;
 455             for (DataItem item : allData) {
 456                 item.add(columnName, new SimpleStringProperty(columnName + "-" + String.valueOf(counter)));
 457                 counter++;
 458             }
 459         }
 460 
 461         protected void getControlOverItem(String name) {
 462             TreeItem<DataItem> treeItem = searchTreeItem(name);
 463             NodeControllerFactory.NodesStorage node = NodeControllerFactory.createFullController(treeItem, tabPane);
 464             allPropertiesTables.add(node.pt);
 465             tabPane.addPropertiesTable(name, node);
 466         }
 467 
 468         protected VBox getTreeViewAddItemController() {
 469             VBox vb = new VBox(3);
 470 
 471             final TextField tfParentName = new TextField();
 472             tfParentName.setId(ADD_ITEM_PARENT_TEXT_FIELD_ID);
 473             tfParentName.setPromptText("parent name");
 474 
 475             final TextField tfName = new TextField();
 476             tfName.setId(ADD_ITEM_TEXT_FIELD_ID);
 477             tfName.setPromptText("new item name");
 478 
 479             final TextField tfPosition = new TextField();
 480             tfPosition.setId(ADD_ITEM_POSITION_TEXT_FIELD_ID);;
 481             tfPosition.setPromptText("position");
 482             tfPosition.setPrefWidth(50);
 483 
 484             Button button = new Button("add to pos");
 485             button.setId(ADD_ITEM_BUTTON_ID);
 486             button.setOnAction(new EventHandler<ActionEvent>() {
 487                 public void handle(ActionEvent t) {
 488                     TreeItem<DataItem> treeItem = searchTreeItem(tfParentName.getText());
 489                     treeItem.getChildren().add(Integer.parseInt(tfPosition.getText()), new TreeItem(new DataItem(tfName.getText())));
 490                 }
 491             });
 492 
 493             HBox hb1 = new HBox(3);
 494             hb1.getChildren().addAll(new Label("Add child to "), tfParentName);
 495 
 496             HBox hb2 = new HBox(3);
 497             hb2.getChildren().addAll(new Label(" named "), tfName);
 498 
 499             HBox hb3 = new HBox(3);
 500             hb3.getChildren().addAll(tfPosition, button);
 501 
 502             vb.getChildren().addAll(hb1, hb2, hb3);
 503 
 504             Button makeHappy = new Button("Fill default data");
 505             makeHappy.setOnAction(new EventHandler<ActionEvent>() {
 506                 public void handle(ActionEvent event) {
 507                     testedControl.setRoot(new TreeItem(new DataItem("ROOT")));
 508                     testedControl.getRoot().setExpanded(true);
 509 
 510                     for (int i = 0; i < 4; i++) {
 511                         TreeItem p = new TreeItem(new DataItem("Item-" + i));
 512                         p.setExpanded(true);
 513                         testedControl.getRoot().getChildren().add(p);
 514                         for (int j = 0; j < 4; j++) {
 515                             p.getChildren().add(new TreeItem(new DataItem("Item-" + i + "-" + j)));
 516                         }
 517                     }
 518 
 519                     TreeTableColumn col = new TreeTableColumn("TreeData");
 520                     col.setCellValueFactory(new Callback<CellDataFeatures<DataItem, String>, ObservableValue<String>>() {
 521                         public ObservableValue<String> call(CellDataFeatures<DataItem, String> p) {
 522                             return p.getValue().getValue().getTreeValue();
 523                         }
 524                     });
 525                     col.setMinWidth(144);
 526                     testedControl.getColumns().clear();
 527                     testedControl.getColumns().add(col);
 528                 }
 529             });
 530 
 531             vb.getChildren().add(makeHappy);
 532 
 533             return vb;
 534         }
 535 
 536         protected VBox getTreeViewRemoveItemController() {
 537             VBox vb = new VBox(3);
 538 
 539             final TextField tfName = new TextField();
 540             tfName.setId(REMOVE_ITEM_TEXT_FIELD_ID);
 541             tfName.setPromptText("new item name");
 542 
 543             Button button = new Button("remove!");
 544             button.setId(REMOVE_ITEM_BUTTON_ID);
 545             button.setOnAction(new EventHandler<ActionEvent>() {
 546                 public void handle(ActionEvent t) {
 547                     TreeItem treeItem = searchTreeItem(tfName.getText());
 548                     if (null != treeItem) {
 549                         if (testedControl.getRoot() == treeItem) {
 550                             testedControl.setRoot(null);
 551                         } else {
 552                             treeItem.getParent().getChildren().remove(treeItem);
 553                         }
 554                     }
 555                 }
 556             });
 557 
 558             HBox hb1 = new HBox(3);
 559             hb1.getChildren().addAll(new Label("Named item"), tfName);
 560 
 561             HBox hb2 = new HBox(3);
 562             hb2.getChildren().addAll(button);
 563 
 564             vb.getChildren().addAll(hb1, hb2);
 565 
 566             return vb;
 567         }
 568 
 569         protected VBox getTabOverItemController() {
 570             final TextField tfParentName = new TextField();
 571             tfParentName.setId(GET_CONTROL_OVER_TREEITEM_TEXTFIELD_ID);
 572             tfParentName.setPromptText("item name");
 573 
 574             Button button = new Button("get table over");
 575             button.setId(GET_CONTROL_OVER_TREEITEM_BUTTON_ID);
 576             button.setOnAction(new EventHandler<ActionEvent>() {
 577                 public void handle(ActionEvent t) {
 578                     getControlOverItem(tfParentName.getText());
 579                 }
 580             });
 581 
 582             HBox hb1 = new HBox(3);
 583             hb1.getChildren().addAll(tfParentName, button);
 584 
 585             VBox vb = new VBox();
 586             vb.getChildren().addAll(hb1);
 587             return vb;
 588         }
 589 
 590         protected VBox getObjectTitleThroughGetItemMethodController() {
 591             final TextField tfParentName = new TextField();
 592             tfParentName.setPromptText("index");
 593             tfParentName.setPrefWidth(50);
 594 
 595             final TextField content = new TextField();
 596             content.setPromptText("content");
 597 
 598             Button button = new Button("getTreeItem! index:");
 599             button.setOnAction(new EventHandler<ActionEvent>() {
 600                 public void handle(ActionEvent t) {
 601                     TreeItem item = testedControl.getTreeItem(Integer.parseInt(tfParentName.getText()));
 602                     if (item == null) {
 603                         content.setText("null");
 604                     } else {
 605                         content.setText(item.getValue().toString());
 606                     }
 607                 }
 608             });
 609 
 610             HBox hb1 = new HBox(3);
 611             hb1.getChildren().addAll(new Label("Get tree item at"), tfParentName);
 612 
 613             HBox hb2 = new HBox(3);
 614             hb2.getChildren().addAll(button, content);
 615 
 616             VBox vb = new VBox();
 617             vb.getChildren().addAll(hb1, hb2);
 618             return vb;
 619         }
 620 
 621         Node getReplaceTableHeaderImplementationButton() {
 622             Button replaceButton = new Button("Replace skin implementation");
 623             replaceButton.setId(REPLACE_SKIN_IMPLEMENTATION_BUTTON_ID);
 624             replaceButton.setOnAction(new EventHandler<ActionEvent>() {
 625                 public void handle(ActionEvent t) {
 626                     testedControl.setSkin(new TreeTableViewSkin(testedControl) {
 627                         @Override
 628                         public String toString() {
 629                             return "CUSTOM " + super.toString();
 630                         }
 631 
 632                         @Override
 633                         protected TableHeaderRow createTableHeaderRow() {
 634                             return new TableHeaderRow(this) {
 635                                 @Override
 636                                 protected NestedTableColumnHeader createRootHeader() {
 637                                     return new NestedTableColumnHeader((TreeTableViewSkin) testedControl.getSkin(), null) {
 638                                         @Override
 639                                         protected TableColumnHeader createTableColumnHeader(TableColumnBase col) {
 640                                             if (col.getColumns().isEmpty()) {
 641                                                 final TableColumnHeader tableColumnHeader = new TableColumnHeader(getTableViewSkin(), col);
 642                                                 tableColumnHeader.setId(CUSTOM_IMPLEMENTATION_MARKER);
 643                                                 return tableColumnHeader;
 644                                             } else {
 645                                                 final NestedTableColumnHeader nestedTableColumnHeader = new NestedTableColumnHeader(getTableViewSkin(), col);
 646                                                 nestedTableColumnHeader.setId(CUSTOM_IMPLEMENTATION_MARKER);
 647                                                 return nestedTableColumnHeader;
 648                                             }
 649                                         }
 650                                     };
 651                                 }
 652                             };
 653                         }
 654                     });
 655                 }
 656             });
 657 
 658             return replaceButton;
 659         }
 660 
 661         protected VBox getTabOverItemThroughGetItemMethodController() {
 662             final TextField tfParentName = new TextField();
 663             tfParentName.setPromptText("index");
 664             tfParentName.setPrefWidth(50);
 665 
 666             Button button = new Button("get table over");
 667             button.setOnAction(new EventHandler<ActionEvent>() {
 668                 public void handle(ActionEvent t) {
 669                     getControlOverItem(testedControl.getTreeItem(Integer.parseInt(tfParentName.getText())).getValue().toString());
 670                 }
 671             });
 672 
 673             HBox hb1 = new HBox(3);
 674             hb1.getChildren().addAll(tfParentName, button);
 675 
 676             VBox vb = new VBox();
 677             vb.getChildren().addAll(hb1);
 678             return vb;
 679         }
 680 
 681         protected VBox getLineOfItemController() {
 682             final TextField tfParentName = new TextField();
 683             tfParentName.setPromptText("name");
 684 
 685             final TextField index = new TextField();
 686             index.setPromptText("found index");
 687             index.setPrefWidth(50);
 688 
 689             Button button = new Button("getRow! index :");
 690             button.setOnAction(new EventHandler<ActionEvent>() {
 691                 public void handle(ActionEvent t) {
 692                     int found = testedControl.getRow(searchTreeItem(tfParentName.getText()));
 693                     index.setText(((Integer) found).toString());
 694                 }
 695             });
 696 
 697             HBox hb1 = new HBox(3);
 698             hb1.getChildren().addAll(new Label("Get index of"), tfParentName);
 699 
 700             HBox hb2 = new HBox(3);
 701             hb2.getChildren().addAll(index, button);
 702 
 703             VBox vb = new VBox();
 704             vb.getChildren().addAll(hb1, hb2);
 705             return vb;
 706         }
 707 
 708         private HBox getScrollToHBox() {
 709             HBox hb = new HBox();
 710             Button button = ButtonBuilder.create().text("ScrollTo").id(SCROLL_TO_BUTTON_ID).build();
 711             final TextField tf = TextFieldBuilder.create().text("0").id(SCROLL_TO_TEXT_FIELD_ID).prefWidth(50).build();
 712 
 713             button.setOnAction(new EventHandler<ActionEvent>() {
 714                 public void handle(ActionEvent t) {
 715                     testedControl.scrollTo(Integer.parseInt(tf.getText()));
 716                 }
 717             });
 718 
 719             hb.getChildren().addAll(tf, button);
 720             return hb;
 721         }
 722 
 723         private HBox getEditHBox() {
 724             HBox hb = new HBox();
 725             Button button = ButtonBuilder.create().text("Edit").id(EDIT_BUTTON_ID).build();
 726             final TextField tf = TextFieldBuilder.create().promptText("name").id(EDIT_TEXT_FIELD_ID).prefWidth(50).build();
 727 
 728             button.setOnAction(new EventHandler<ActionEvent>() {
 729                 public void handle(ActionEvent t) {
 730                     throw new IllegalStateException("In build 101 was changed API of this function. Instead of 0, write index of edited treeItem please.");
 731                     //testedControl.edit(0/* searchTreeItem(tf.getText()) */, (TreeTableColumn) testedControl.getColumns().get(0));
 732                 }
 733             });
 734 
 735             hb.getChildren().addAll(tf, button);
 736             return hb;
 737         }
 738 
 739         private VBox setEventHandlersHBox() {
 740             VBox vb = new VBox();
 741 
 742             Button btn = ButtonBuilder.create()
 743                     .text("Set onEdit event hadlers")
 744                     .id(BTN_SET_ON_EDIT_EVENT_HANDLERS)
 745                     .build();
 746 
 747             btn.setOnAction(new EventHandler<ActionEvent>() {
 748                 final EventHandler eventHandlerOnEditStart = new EventHandler() {
 749                     public void handle(Event t) {
 750                         tb.incrementCounter(COUNTER_EDIT_START);
 751                     }
 752                 };
 753                 final EventHandler eventHandlerOnEditCommit = new EventHandler<TreeTableColumn.CellEditEvent<DataItem, String>>() {
 754                     public void handle(TreeTableColumn.CellEditEvent<DataItem, String> event) {
 755                         tb.incrementCounter(COUNTER_EDIT_COMMIT);
 756                         DataItem data = event.getTreeTablePosition().getTreeItem().getValue();
 757                         StringProperty prop = data.get(event.getTableColumn().getText());
 758                         prop.setValue(event.getNewValue());
 759                     }
 760                 };
 761                 final EventHandler eventHandlerOnEditCancel = new EventHandler() {
 762                     public void handle(Event t) {
 763                         tb.incrementCounter(COUNTER_EDIT_CANCEL);
 764                     }
 765                 };
 766 
 767                 public void handle(ActionEvent t) {
 768                     for (Iterator it = testedControl.getColumns().iterator(); it.hasNext();) {
 769                         TreeTableColumn col = (TreeTableColumn) it.next();
 770 
 771                         col.setOnEditStart(eventHandlerOnEditStart);
 772                         assertTrue(eventHandlerOnEditStart == col.getOnEditStart());
 773 
 774                         col.setOnEditCommit(eventHandlerOnEditCommit);
 775                         assertTrue(eventHandlerOnEditCommit == col.getOnEditCommit());
 776 
 777                         col.setOnEditCancel(eventHandlerOnEditCancel);
 778                         assertTrue(eventHandlerOnEditCancel == col.getOnEditCancel());
 779                     }
 780                 }
 781             });
 782 
 783             Button btnAddFactory = ButtonBuilder.create()
 784                     .text("Set cell factory for editing")
 785                     .id(SET_CELL_FACTORY_FOR_EDITING)
 786                     .build();
 787 
 788             btnAddFactory.setOnAction(new EventHandler<ActionEvent>() {
 789                 public void handle(ActionEvent t) {
 790                     for (Object obj : testedControl.getColumns()) {
 791                         TreeTableColumn col = (TreeTableColumn) obj;
 792                         col.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
 793                     }
 794                 }
 795             });
 796 
 797             vb.getChildren().addAll(btn, btnAddFactory);
 798             return vb;
 799         }
 800 
 801         private TreeItem<DataItem> searchTreeItem(String content) {
 802             return TreeTableNewApp.searchTreeItem(testedControl, content);
 803         }
 804 
 805         private Pane controlsForEditing() {
 806 
 807             VBox topContainer = new VBox(3.5);
 808             HBox hb = new HBox(3.0);
 809 
 810             final ComboBox cmbEditors = new ComboBox();
 811             cmbEditors.setId(CMB_EDITORS_ID);
 812             cmbEditors.getItems().addAll((Object[]) CellEditorType.values());
 813 
 814             final CheckBox chbCustom = new CheckBox("Custom");
 815             chbCustom.setId(CHB_IS_CUSTOM_ID);
 816 
 817             Button btnSetEditor = new Button("Set editor");
 818             btnSetEditor.setId(BTN_SET_CELLS_EDITOR_ID);
 819             btnSetEditor.setOnAction(new EventHandler<ActionEvent>() {
 820                 public void handle(ActionEvent t) {
 821                     CellEditorType editor = (CellEditorType) cmbEditors.getSelectionModel().getSelectedItem();
 822                     setCellEditor(editor, chbCustom.isSelected());
 823                 }
 824             });
 825 
 826             hb.getChildren().addAll(cmbEditors, chbCustom, btnSetEditor);
 827 
 828             topContainer.getChildren().addAll(hb);
 829             return topContainer;
 830         }
 831 
 832         private void setCellEditor(CellEditorType editor, boolean isCustom) {
 833             if (null == editor) {
 834                 System.out.println("Editor is not selected");
 835                 return;
 836             }
 837 
 838             switch (editor) {
 839                 case TEXT_FIELD:
 840                     setTextFieldCellEditor(isCustom);
 841                     break;
 842                 case COMBOBOX:
 843                     setComboboxCellEditor(isCustom);
 844                     break;
 845                 case CHOICEBOX:
 846                     setChoiceboxCellEditor(isCustom);
 847                     break;
 848                 default:
 849                     throw new UnsupportedOperationException(editor.toString());
 850             }
 851 
 852             System.out.println(String.format("Editor set: %s %s",
 853                     isCustom ? "custom" : "",
 854                     editor.toString()));
 855         }
 856 
 857         private void setTextFieldCellEditor(boolean isCustom) {
 858             for (Iterator it = testedControl.getColumns().iterator(); it.hasNext();) {
 859                 TreeTableColumn col = (TreeTableColumn) it.next();
 860                 if (!isCustom) {
 861                     col.setCellFactory(TextFieldTreeTableCell.forTreeTableColumn());
 862                 } else {
 863                     col.setCellFactory(new Callback() {
 864                         public Object call(Object p) {
 865                             return new EditingTextFieldCell();
 866                         }
 867                     });
 868                 }
 869             }
 870         }
 871 
 872         private void setComboboxCellEditor(boolean isCustom) {
 873 
 874             for (Iterator it = testedControl.getColumns().iterator(); it.hasNext();) {
 875                 TreeTableColumn col = (TreeTableColumn) it.next();
 876                 String colName = col.getText();
 877                 final ObservableList<String> items = FXCollections.observableArrayList();
 878 
 879                 for (DataItem dataItem : allData) {
 880                     items.add(dataItem.get(colName).get());
 881                 }
 882                 if (!isCustom) {
 883                     col.setCellFactory(ComboBoxTreeTableCell.forTreeTableColumn(items));
 884                 } else {
 885                     col.setCellFactory(new Callback() {
 886                         public Object call(Object p) {
 887                             return new EditingComboBoxCell(items);
 888                         }
 889                     });
 890                 }
 891             }
 892         }
 893 
 894         private void setChoiceboxCellEditor(boolean isCustom) {
 895 
 896             for (Iterator it = testedControl.getColumns().iterator(); it.hasNext();) {
 897                 TreeTableColumn col = (TreeTableColumn) it.next();
 898                 String colName = col.getText();
 899                 final ObservableList<String> items = FXCollections.observableArrayList();
 900 
 901                 for (DataItem dataItem : allData) {
 902                     items.add(dataItem.get(colName).get());
 903                 }
 904                 if (!isCustom) {
 905                     col.setCellFactory(ChoiceBoxTreeTableCell.forTreeTableColumn(items));
 906                 } else {
 907                     col.setCellFactory(new Callback() {
 908                         public Object call(Object p) {
 909                             return new EditingChoiceBoxCell(items);
 910                         }
 911                     });
 912                 }
 913             }
 914         }
 915 
 916         private class EditingTextFieldCell extends TreeTableCell {
 917 
 918             private TextField textField;
 919 
 920             public EditingTextFieldCell() {
 921             }
 922 
 923             @Override
 924             public void startEdit() {
 925                 if (!isEmpty()) {
 926                     super.startEdit();
 927                     createTextField();
 928 
 929                     super.startEdit();
 930                     setText(null);
 931                     setGraphic(textField);
 932                 }
 933             }
 934 
 935             @Override
 936             public void cancelEdit() {
 937                 super.cancelEdit();
 938 
 939                 setText(getString());
 940                 setGraphic(null);
 941             }
 942 
 943             @Override
 944             public void updateItem(Object item, boolean empty) {
 945                 super.updateItem(item, empty);
 946 
 947                 if (empty) {
 948                     setText(null);
 949                     setGraphic(null);
 950                 } else {
 951                     if (isEditing()) {
 952                         if (textField != null) {
 953                             textField.setText(getString());
 954                         }
 955                         setText(null);
 956                         setGraphic(textField);
 957                     } else {
 958                         setText(getString());
 959                         setGraphic(null);
 960                     }
 961                 }
 962             }
 963 
 964             private void createTextField() {
 965                 textField = new TextField(getString());
 966                 textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
 967 
 968                 textField.setOnKeyReleased(new EventHandler<KeyEvent>() {
 969                     @Override
 970                     public void handle(KeyEvent t) {
 971                         if (t.getCode() == KeyCode.ENTER) {
 972                             commitEdit(textField.getText());
 973                         } else if (t.getCode() == KeyCode.ESCAPE) {
 974                             cancelEdit();
 975                         }
 976                     }
 977                 });
 978             }
 979 
 980             private String getString() {
 981                 return getItem() == null ? "" : getItem().toString();
 982             }
 983         }
 984 
 985         private class EditingComboBoxCell extends TreeTableCell {
 986 
 987             ObservableList items;
 988             ComboBox comboBox;
 989 
 990             public EditingComboBoxCell(ObservableList _items) {
 991                 items = _items;
 992             }
 993 
 994             @Override
 995             public void startEdit() {
 996                 if (isEmpty()) {
 997                     return;
 998                 }
 999 
1000                 createComboBox();
1001 
1002                 comboBox.getSelectionModel().select(getItem());
1003 
1004                 super.startEdit();
1005                 setText(null);
1006                 setGraphic(comboBox);
1007             }
1008 
1009             @Override
1010             public void cancelEdit() {
1011                 super.cancelEdit();
1012                 setGraphic(null);
1013                 setText(getString());
1014             }
1015 
1016             @Override
1017             public void updateItem(Object item, boolean isEmpty) {
1018                 super.updateItem(item, isEmpty);
1019                 if (isEmpty()) {
1020                     setText(null);
1021                     setGraphic(null);
1022                 } else {
1023                     if (isEditing()) {
1024                         if (comboBox != null) {
1025                             comboBox.getSelectionModel().select(getItem());
1026                         }
1027                         setText(null);
1028                         setGraphic(comboBox);
1029                     } else {
1030                         setText(getString());
1031                         setGraphic(null);
1032                     }
1033                 }
1034             }
1035 
1036             private String getString() {
1037                 return getItem() == null ? "" : getItem().toString();
1038             }
1039 
1040             private void createComboBox() {
1041                 if (null == comboBox) {
1042                     comboBox = new ComboBox(items);
1043                     comboBox.setMaxWidth(Double.MAX_VALUE);
1044                     comboBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
1045                         @Override
1046                         public void changed(ObservableValue ov, Object oldValue, Object newValue) {
1047                             if (isEditing()) {
1048                                 commitEdit(newValue);
1049                             }
1050                         }
1051                     });
1052                 }
1053             }
1054         }
1055 
1056         private class EditingChoiceBoxCell extends TreeTableCell {
1057 
1058             ObservableList items;
1059             ChoiceBox choiceBox;
1060 
1061             public EditingChoiceBoxCell(ObservableList _items) {
1062                 items = _items;
1063             }
1064 
1065             @Override
1066             public void startEdit() {
1067                 if (isEmpty()) {
1068                     return;
1069                 }
1070 
1071                 createComboBox();
1072 
1073                 choiceBox.getSelectionModel().select(getItem());
1074 
1075                 super.startEdit();
1076                 setText(null);
1077                 setGraphic(choiceBox);
1078             }
1079 
1080             @Override
1081             public void cancelEdit() {
1082                 super.cancelEdit();
1083                 setGraphic(null);
1084                 setText(getString());
1085             }
1086 
1087             @Override
1088             public void updateItem(Object item, boolean isEmpty) {
1089                 super.updateItem(item, isEmpty);
1090                 if (isEmpty()) {
1091                     setText(null);
1092                     setGraphic(null);
1093                 } else {
1094                     if (isEditing()) {
1095                         if (choiceBox != null) {
1096                             choiceBox.getSelectionModel().select(getItem());
1097                         }
1098                         setText(null);
1099                         setGraphic(choiceBox);
1100                     } else {
1101                         setText(getString());
1102                         setGraphic(null);
1103                     }
1104                 }
1105             }
1106 
1107             private String getString() {
1108                 return getItem() == null ? "" : getItem().toString();
1109             }
1110 
1111             private void createComboBox() {
1112                 if (null == choiceBox) {
1113                     choiceBox = new ChoiceBox(items);
1114                     choiceBox.setMaxWidth(Double.MAX_VALUE);
1115                     choiceBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
1116                         @Override
1117                         public void changed(ObservableValue ov, Object oldValue, Object newValue) {
1118                             if (isEditing()) {
1119                                 commitEdit(newValue);
1120                             }
1121                         }
1122                     });
1123                 }
1124             }
1125         }
1126     }
1127 
1128     /**
1129      * This class contain HashMap, which contain dynamically generated data. For
1130      * each line in the Table, when you add additional column, you should add
1131      * additional key-value pair in map for all dataItems in allData observable
1132      * list.
1133      */
1134     public static class DataItem implements Comparable {
1135 
1136         private StringProperty treeData;
1137         private HashMap<String, StringProperty> data = new HashMap<String, StringProperty>();
1138 
1139         public DataItem() {
1140             this(null);
1141         }
1142 
1143         public DataItem(String treeData) {
1144             this.treeData = new SimpleStringProperty(treeData);
1145         }
1146 
1147         public void add(String string, StringProperty property) {
1148             data.put(string, property);
1149         }
1150 
1151         public StringProperty get(String name) {
1152             return data.get(name);
1153         }
1154 
1155         public StringProperty getTreeValue() {
1156             return treeData;
1157         }
1158 
1159         @Override
1160         public String toString() {
1161             if (treeData != null) {
1162                 return treeData.getValue();
1163             } else {
1164                 return data.toString();
1165             }
1166         }
1167 
1168         public boolean contains(String text) {
1169             boolean res = false;
1170             for (StringProperty prop : data.values()) {
1171                 if (text.equals(prop.get())) {
1172                     res = true;
1173                     break;
1174                 }
1175             }
1176             return res;
1177         }
1178 
1179         public int compareTo(Object t) {
1180             if (!(DataItem.class.isAssignableFrom(t.getClass())
1181                     && ((DataItem) t).data.size() == data.size())) {
1182                 throw new IllegalArgumentException("[It is assumed that"
1183                         + "the data size is equal in botn data items]");
1184             }
1185 
1186             int res = 0;
1187             for (String key : data.keySet()) {
1188                 res = data.get(key).get().compareTo(((DataItem) t).data.get(key).get());
1189                 if (res != 0) {
1190                     return res;
1191                 }
1192             }
1193             if (treeData.getValue() != null) {
1194                 return treeData.getValue().compareTo(((DataItem) t).treeData.get());
1195             }
1196             return 0;
1197         }
1198     }
1199 }