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