Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.control;
027
028import javafx.css.CssMetaData;
029import java.util.Collections;
030import java.util.List;
031import java.util.Map;
032import javafx.beans.InvalidationListener;
033import javafx.beans.Observable;
034import javafx.beans.property.ObjectProperty;
035import javafx.beans.property.ReadOnlyObjectProperty;
036import javafx.beans.property.ReadOnlyObjectWrapper;
037import javafx.beans.property.SimpleObjectProperty;
038import javafx.beans.value.ObservableValue;
039import javafx.beans.value.WritableValue;
040import javafx.collections.FXCollections;
041import javafx.collections.ListChangeListener;
042import javafx.collections.ObservableList;
043import javafx.collections.WeakListChangeListener;
044import javafx.event.Event;
045import javafx.event.EventHandler;
046import javafx.event.EventTarget;
047import javafx.event.EventType;
048import javafx.scene.Node;
049import javafx.scene.control.TableColumn.SortType;
050import javafx.util.Callback;
051import javafx.css.Styleable;
052import com.sun.javafx.scene.control.skin.TableViewSkinBase;
053/**
054 * A {@link TreeTableView} is made up of a number of TreeTableColumn instances. Each
055 * TreeTableColumn in a tree table is responsible for displaying (and editing) the contents
056 * of that column. As well as being responsible for displaying and editing data 
057 * for a single column, a TableColumn also contains the necessary properties to:
058 * <ul>
059 *    <li>Be resized (using {@link #minWidthProperty() minWidth}/{@link #prefWidthProperty() prefWidth}/{@link #maxWidthProperty() maxWidth}
060 *      and {@link #widthProperty() width} properties)
061 *    <li>Have its {@link #visibleProperty() visibility} toggled
062 *    <li>Display {@link #textProperty() header text}
063 *    <li>Display any {@link #getColumns() nested columns} it may contain
064 *    <li>Have a {@link #contextMenuProperty() context menu} when the user 
065 *      right-clicks the column header area
066 *    <li>Have the contents of the table be sorted (using 
067 *      {@link #comparatorProperty() comparator}, {@link #sortable sortable} and
068 *      {@link #sortTypeProperty() sortType})
069 * </ul>
070 * </p>
071 * 
072 * When creating a TreeTableColumn instance, perhaps the two most important properties
073 * to set are the column {@link #textProperty() text} (what to show in the column
074 * header area), and the column {@link #cellValueFactory cell value factory}
075 * (which is used to populate individual cells in the column). This can be 
076 * achieved using some variation on the following code:
077 * 
078 * <p>// TODO update example for TreeTableColumn
079 * 
080 * <pre>
081 * {@code 
082 * ObservableList<Person> data = ...
083 * TableView<Person> tableView = new TableView<Person>(data);
084 * 
085 * TableColumn<Person,String> firstNameCol = new TableColumn<Person,String>("First Name");
086 * firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() {
087 *     public ObservableValue<String> call(CellDataFeatures<Person, String> p) {
088 *         // p.getValue() returns the Person instance for a particular TableView row
089 *         return p.getValue().firstNameProperty();
090 *     }
091 *  });
092 * }
093 * tableView.getColumns().add(firstNameCol);}</pre>
094 * 
095 * This approach assumes that the object returned from <code>p.getValue()</code>
096 * has a JavaFX {@link ObservableValue} that can simply be returned. The benefit of this
097 * is that the TableView will internally create bindings to ensure that,
098 * should the returned {@link ObservableValue} change, the cell contents will be
099 * automatically refreshed. 
100 * 
101 * <p>In situations where a TableColumn must interact with classes created before
102 * JavaFX, or that generally do not wish to use JavaFX apis for properties, it is
103 * possible to wrap the returned value in a {@link ReadOnlyObjectWrapper} instance. For
104 * example:
105 * 
106 * <pre>
107 * {@code 
108 * firstNameCol.setCellValueFactory(new Callback<CellDataFeatures<Person, String>, ObservableValue<String>>() {
109 *     public ObservableValue<String> call(CellDataFeatures<Person, String> p) {
110 *         return new ReadOnlyObjectWrapper(p.getValue().getFirstName());
111 *     }
112 *  });}</pre>
113 * 
114 * It is hoped that over time there will be convenience cell value factories 
115 * developed and made available to developers. As of the JavaFX 2.0 release, 
116 * there is one such convenience class: {@link PropertyValueFactory}. This class
117 * removes the need to write the code above, instead relying on reflection to 
118 * look up a given property from a String. Refer to the 
119 * <code>PropertyValueFactory</code> class documentation for more information
120 * on how to use this with a TableColumn.
121 * 
122 * Finally, for more detail on how to use TableColumn, there is further documentation in
123 * the {@link TableView} class documentation.
124 * 
125 * @param <S> The type of the TableView generic type (i.e. S == TableView&lt;S&gt;)
126 * @param <T> The type of the content in all cells in this TableColumn.
127 * @see TableView
128 * @see TableCell
129 * @see TablePosition
130 */
131public class TreeTableColumn<S,T> extends TableColumnBase<TreeItem<S>,T> implements EventTarget {
132    
133    /***************************************************************************
134     *                                                                         *
135     * Static properties and methods                                           *
136     *                                                                         *
137     **************************************************************************/
138    
139    /**
140     * Parent event for any TreeTableColumn edit event.
141     */
142    @SuppressWarnings("unchecked")
143    public static <S,T> EventType<TreeTableColumn.CellEditEvent<S,T>> editAnyEvent() {
144        return (EventType<TreeTableColumn.CellEditEvent<S,T>>) EDIT_ANY_EVENT;
145    }
146    private static final EventType<?> EDIT_ANY_EVENT =
147            new EventType(Event.ANY, "TREE_TABLE_COLUMN_EDIT");
148
149    /**
150     * Indicates that the user has performed some interaction to start an edit
151     * event, or alternatively the 
152     * {@link TreeTableView#edit(int, javafx.scene.control.TreeTableColumn)}
153     * method has been called.
154     */
155    @SuppressWarnings("unchecked")
156    public static <S,T> EventType<TreeTableColumn.CellEditEvent<S,T>> editStartEvent() {
157        return (EventType<TreeTableColumn.CellEditEvent<S,T>>) EDIT_START_EVENT;
158    }
159    private static final EventType<?> EDIT_START_EVENT =
160            new EventType(editAnyEvent(), "EDIT_START");
161
162    /**
163     * Indicates that the editing has been canceled, meaning that no change should
164     * be made to the backing data source.
165     */
166    @SuppressWarnings("unchecked")
167    public static <S,T> EventType<TreeTableColumn.CellEditEvent<S,T>> editCancelEvent() {
168        return (EventType<TreeTableColumn.CellEditEvent<S,T>>) EDIT_CANCEL_EVENT;
169    }
170    private static final EventType<?> EDIT_CANCEL_EVENT =
171            new EventType(editAnyEvent(), "EDIT_CANCEL");
172
173    /**
174     * Indicates that the editing has been committed by the user, meaning that
175     * a change should be made to the backing data source to reflect the new
176     * data.
177     */
178    @SuppressWarnings("unchecked")
179    public static <S,T> EventType<TreeTableColumn.CellEditEvent<S,T>> editCommitEvent() {
180        return (EventType<TreeTableColumn.CellEditEvent<S,T>>) EDIT_COMMIT_EVENT;
181    }
182    private static final EventType<?> EDIT_COMMIT_EVENT =
183            new EventType(editAnyEvent(), "EDIT_COMMIT");
184    
185    
186    
187    /**
188     * If no cellFactory is specified on a TreeTableColumn instance, then this one
189     * will be used by default. At present it simply renders the TableCell item 
190     * property within the {@link TableCell#graphicProperty() graphic} property
191     * if the {@link Cell#item item} is a Node, or it simply calls 
192     * <code>toString()</code> if it is not null, setting the resulting string
193     * inside the {@link Cell#textProperty() text} property.
194     */
195    public static final Callback<TreeTableColumn<?,?>, TreeTableCell<?,?>> DEFAULT_CELL_FACTORY = 
196            new Callback<TreeTableColumn<?,?>, TreeTableCell<?,?>>() {
197        @Override public TreeTableCell<?,?> call(TreeTableColumn<?,?> param) {
198            return new TreeTableCell() {
199                @Override protected void updateItem(Object item, boolean empty) {
200                    if (item == getItem()) return;
201
202                    super.updateItem(item, empty);
203
204                    if (item == null) {
205                        super.setText(null);
206                        super.setGraphic(null);
207                    } else if (item instanceof Node) {
208                        super.setText(null);
209                        super.setGraphic((Node)item);
210                    } else {
211                        super.setText(item.toString());
212                        super.setGraphic(null);
213                    }
214                }
215            };
216        }
217    };
218
219    
220    
221    /***************************************************************************
222     *                                                                         *
223     * Constructors                                                            *
224     *                                                                         *
225     **************************************************************************/    
226
227    /**
228     * Creates a default TreeTableColumn with default cell factory, comparator, and
229     * onEditCommit implementation.
230     */
231    public TreeTableColumn() {
232        getStyleClass().add(DEFAULT_STYLE_CLASS);
233        
234        setOnEditCommit(DEFAULT_EDIT_COMMIT_HANDLER);
235
236        // we listen to the columns list here to ensure that widths are
237        // maintained properly, and to also set the column hierarchy such that
238        // all children columns know that this TreeTableColumn is their parent.
239        getColumns().addListener(weakColumnsListener);
240
241        treeTableViewProperty().addListener(new InvalidationListener() {
242            @Override public void invalidated(Observable observable) {
243                // set all children of this tableView to have the same TableView
244                // as this column
245                for (TreeTableColumn<S, ?> tc : getColumns()) {
246                    tc.setTreeTableView(getTreeTableView());
247                }
248                
249                // This code was commented out due to RT-22391, with this enabled
250                // the parent column will be null, which is not desired
251//                // set the parent of this column to also have this tableView
252//                if (getParentColumn() != null) {
253//                    getParentColumn().setTableView(getTableView());
254//                }
255            }
256        });
257    }
258
259    /**
260     * Creates a TreeTableColumn with the text set to the provided string, with
261     * default cell factory, comparator, and onEditCommit implementation.
262     * 
263     * @param text The string to show when the TreeTableColumn is placed within
264     *      the TreeTableView.
265     */
266    public TreeTableColumn(String text) {
267        this();
268        setText(text);
269    }
270    
271    
272    
273    /***************************************************************************
274     *                                                                         *
275     * Listeners                                                               *
276     *                                                                         *
277     **************************************************************************/
278    
279    private EventHandler<TreeTableColumn.CellEditEvent<S,T>> DEFAULT_EDIT_COMMIT_HANDLER = 
280            new EventHandler<TreeTableColumn.CellEditEvent<S,T>>() {
281        @Override public void handle(TreeTableColumn.CellEditEvent<S,T> t) {
282            ObservableValue<T> ov = getCellObservableValue(t.getRowValue());
283            if (ov instanceof WritableValue) {
284                ((WritableValue)ov).setValue(t.getNewValue());
285            }
286        }
287    };
288    
289    private ListChangeListener columnsListener = new ListChangeListener<TreeTableColumn<S,?>>() {
290        @Override public void onChanged(ListChangeListener.Change<? extends TreeTableColumn<S,?>> c) {
291            while (c.next()) {
292                // update the TreeTableColumn.treeTableView property
293                for (TreeTableColumn<S,?> tc : c.getRemoved()) {
294                    // Fix for RT-16978. In TableColumnHeader we add before we
295                    // remove when moving a TreeTableColumn. This means that for
296                    // a very brief moment the tc is duplicated, and we can prevent
297                    // nulling out the tableview and parent column. Without this
298                    // here, in a very special circumstance it is possible to null
299                    // out the entire content of a column by reordering and then
300                    // sorting another column.
301                    if (getColumns().contains(tc)) continue;
302                    
303                    tc.setTreeTableView(null);
304                    tc.setParentColumn(null);
305                }
306                for (TreeTableColumn<S,?> tc : c.getAddedSubList()) {
307                    tc.setTreeTableView(getTreeTableView());
308                }
309
310                updateColumnWidths();
311            }
312        }
313    };
314    
315    private WeakListChangeListener weakColumnsListener = 
316            new WeakListChangeListener(columnsListener);
317    
318    
319    /***************************************************************************
320     *                                                                         *
321     * Instance Variables                                                      *
322     *                                                                         *
323     **************************************************************************/
324    
325    // Contains any children columns that should be nested within this column
326    private final ObservableList<TreeTableColumn<S,?>> columns = FXCollections.<TreeTableColumn<S,?>>observableArrayList();
327    
328    
329    
330    /***************************************************************************
331     *                                                                         *
332     * Properties                                                              *
333     *                                                                         *
334     **************************************************************************/
335    
336    
337    // --- TreeTableView
338    /**
339     * The TreeTableView that this TreeTableColumn belongs to.
340     */
341    private ReadOnlyObjectWrapper<TreeTableView<S>> treeTableView = 
342            new ReadOnlyObjectWrapper<TreeTableView<S>>(this, "treeTableView");
343    public final ReadOnlyObjectProperty<TreeTableView<S>> treeTableViewProperty() {
344        return treeTableView.getReadOnlyProperty();
345    }
346    final void setTreeTableView(TreeTableView<S> value) { treeTableView.set(value); }
347    public final TreeTableView<S> getTreeTableView() { return treeTableView.get(); }
348
349    
350
351    // --- Cell value factory
352    /**
353     * The cell value factory needs to be set to specify how to populate all
354     * cells within a single TreeTableColumn. A cell value factory is a {@link Callback}
355     * that provides a {@link CellDataFeatures} instance, and expects an
356     * {@link ObservableValue} to be returned. The returned ObservableValue instance
357     * will be observed internally to allow for updates to the value to be 
358     * immediately reflected on screen.
359     * 
360     * <p> // TODO update example
361     * 
362     * An example of how to set a cell value factory is:
363     * 
364     * <pre><code>
365     * lastNameCol.setCellValueFactory(new Callback&lt;CellDataFeatures&lt;Person, String&gt;, ObservableValue&lt;String&gt;&gt;() {
366     *     public ObservableValue&lt;String&gt; call(CellDataFeatures&lt;Person, String&gt; p) {
367     *         // p.getValue() returns the Person instance for a particular TableView row
368     *         return p.getValue().lastNameProperty();
369     *     }
370     *  });
371     * }
372     * </code></pre>
373     * 
374     * A common approach is to want to populate cells in a TreeTableColumn using
375     * a single value from a Java bean. To support this common scenario, there
376     * is the {@link PropertyValueFactory} class. Refer to this class for more 
377     * information on how to use it, but briefly here is how the above use case
378     * could be simplified using the PropertyValueFactory class:
379     * 
380     * <pre><code>
381     * lastNameCol.setCellValueFactory(new PropertyValueFactory&lt;Person,String&gt;("lastName"));
382     * </code></pre>
383     * 
384     * @see PropertyValueFactory
385     */
386    private ObjectProperty<Callback<TreeTableColumn.CellDataFeatures<S,T>, ObservableValue<T>>> cellValueFactory;
387    public final void setCellValueFactory(Callback<TreeTableColumn.CellDataFeatures<S,T>, ObservableValue<T>> value) {
388        cellValueFactoryProperty().set(value);
389    }
390    public final Callback<TreeTableColumn.CellDataFeatures<S,T>, ObservableValue<T>> getCellValueFactory() {
391        return cellValueFactory == null ? null : cellValueFactory.get();
392    }
393    public final ObjectProperty<Callback<TreeTableColumn.CellDataFeatures<S,T>, ObservableValue<T>>> cellValueFactoryProperty() {
394        if (cellValueFactory == null) {
395            cellValueFactory = new SimpleObjectProperty<Callback<TreeTableColumn.CellDataFeatures<S,T>, ObservableValue<T>>>(this, "cellValueFactory");
396        }
397        return cellValueFactory;
398    }
399    
400    
401    // --- Cell Factory
402    /**
403     * The cell factory for all cells in this column. The cell factory
404     * is responsible for rendering the data contained within each TreeTableCell 
405     * for a single TreeTableColumn.
406     * 
407     * <p>By default TreeTableColumn uses a {@link #DEFAULT_CELL_FACTORY default cell
408     * factory}, but this can be replaced with a custom implementation, for 
409     * example to show data in a different way or to support editing. There is a 
410     * lot of documentation on creating custom cell factories
411     * elsewhere (see {@link Cell} and {@link TreeTableView} for example).</p>
412     * 
413     * <p>Finally, there are a number of pre-built cell factories available in the
414     * {@link javafx.scene.control.cell} package.
415     *
416     */
417    private final ObjectProperty<Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>>> cellFactory =
418        new SimpleObjectProperty<Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>>>(
419            this, "cellFactory", (Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>>) ((Callback) DEFAULT_CELL_FACTORY)) {
420                @Override protected void invalidated() {
421                    TreeTableView table = getTreeTableView();
422                    if (table == null) return;
423                    Map properties = table.getProperties();
424                    if (properties.containsKey(TableViewSkinBase.RECREATE)) {
425                        properties.remove(TableViewSkinBase.RECREATE);
426                    }
427                    properties.put(TableViewSkinBase.RECREATE, Boolean.TRUE);
428                }
429            };
430    public final void setCellFactory(Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> value) {
431        cellFactory.set(value);
432    }
433    public final Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>> getCellFactory() {
434        return cellFactory.get();
435    }
436    public final ObjectProperty<Callback<TreeTableColumn<S,T>, TreeTableCell<S,T>>> cellFactoryProperty() {
437        return cellFactory;
438    }
439    
440    
441    // --- Sort Type
442    /**
443     * Used to state whether this column, if it is part of a sort order (see
444     * {@link TreeTableView#getSortOrder()} for more details), should be sorted 
445     * in ascending or descending order. 
446     * Simply toggling this property will result in the sort order changing in 
447     * the TreeTableView, assuming of course that this column is in the 
448     * sortOrder ObservableList to begin with.
449     */
450    private ObjectProperty<SortType> sortType;
451    public final ObjectProperty<SortType> sortTypeProperty() {
452        if (sortType == null) {
453            sortType = new SimpleObjectProperty<SortType>(this, "sortType", SortType.ASCENDING);
454        }
455        return sortType;
456    }
457    public final void setSortType(SortType value) {
458        sortTypeProperty().set(value);
459    }
460    public final SortType getSortType() {
461        return sortType == null ? SortType.ASCENDING : sortType.get();
462    }
463    
464    
465    // --- On Edit Start
466    /**
467     * This event handler will be fired when the user successfully initiates
468     * editing.
469     */
470    private ObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>> onEditStart;
471    public final void setOnEditStart(EventHandler<TreeTableColumn.CellEditEvent<S,T>> value) {
472        onEditStartProperty().set(value);
473    }
474    public final EventHandler<TreeTableColumn.CellEditEvent<S,T>> getOnEditStart() {
475        return onEditStart == null ? null : onEditStart.get();
476    }
477    public final ObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>> onEditStartProperty() {
478        if (onEditStart == null) {
479            onEditStart = new SimpleObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>>(this, "onEditStart") {
480                @Override protected void invalidated() {
481                    eventHandlerManager.setEventHandler(TreeTableColumn.<S,T>editStartEvent(), get());
482                }
483            };
484        }
485        return onEditStart;
486    }
487
488
489    // --- On Edit Commit
490    /**
491     * This event handler will be fired when the user successfully commits their
492     * editing.
493     */
494    private ObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>> onEditCommit;
495    public final void setOnEditCommit(EventHandler<TreeTableColumn.CellEditEvent<S,T>> value) {
496        onEditCommitProperty().set(value);
497    }
498    public final EventHandler<TreeTableColumn.CellEditEvent<S,T>> getOnEditCommit() {
499        return onEditCommit == null ? null : onEditCommit.get();
500    }
501    public final ObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>> onEditCommitProperty() {
502        if (onEditCommit == null) {
503            onEditCommit = new SimpleObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>>(this, "onEditCommit") {
504                @Override protected void invalidated() {
505                    eventHandlerManager.setEventHandler(TreeTableColumn.<S,T>editCommitEvent(), get());
506                }
507            };
508        }
509        return onEditCommit;
510    }
511
512
513    // --- On Edit Cancel
514    /**
515     * This event handler will be fired when the user cancels editing a cell.
516     */
517    private ObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>> onEditCancel;
518    public final void setOnEditCancel(EventHandler<TreeTableColumn.CellEditEvent<S,T>> value) {
519        onEditCancelProperty().set(value);
520    }
521    public final EventHandler<TreeTableColumn.CellEditEvent<S,T>> getOnEditCancel() {
522        return onEditCancel == null ? null : onEditCancel.get();
523    }
524    public final ObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>> onEditCancelProperty() {
525        if (onEditCancel == null) {
526            onEditCancel = new SimpleObjectProperty<EventHandler<TreeTableColumn.CellEditEvent<S,T>>>(this, "onEditCancel") {
527                @Override protected void invalidated() {
528                    eventHandlerManager.setEventHandler(TreeTableColumn.<S,T>editCancelEvent(), get());
529                }
530            };
531        }
532        return onEditCancel;
533    }
534    
535    
536
537    /***************************************************************************
538     *                                                                         *
539     * Public API                                                              *
540     *                                                                         *
541     **************************************************************************/    
542    
543    /** {@inheritDoc} */
544    @Override public final ObservableList<TreeTableColumn<S,?>> getColumns() {
545        return columns;
546    }
547    
548    /** {@inheritDoc} */
549    @Override public final ObservableValue<T> getCellObservableValue(int index) {
550        if (index < 0) return null;
551        
552        // Get the table
553        final TreeTableView<S> table = getTreeTableView();
554        if (table == null || index >= table.getExpandedItemCount()) return null;
555        
556        // Get the rowData
557        TreeItem<S> item = table.getTreeItem(index);
558        return getCellObservableValue(item);
559    }
560    
561    /** {@inheritDoc} */
562    @Override public final ObservableValue<T> getCellObservableValue(TreeItem<S> item) {
563        // Get the factory
564        final Callback<TreeTableColumn.CellDataFeatures<S,T>, ObservableValue<T>> factory = getCellValueFactory();
565        if (factory == null) return null;
566        
567        // Get the table
568        final TreeTableView<S> table = getTreeTableView();
569        if (table == null) return null;
570        
571        // Call the factory
572        final TreeTableColumn.CellDataFeatures<S,T> cdf = new TreeTableColumn.CellDataFeatures<S,T>(table, this, item);
573        return factory.call(cdf);
574    }
575
576    
577    
578    /***************************************************************************
579     *                                                                         *
580     * Private Implementation                                                  *
581     *                                                                         *
582     **************************************************************************/        
583
584
585    
586    /***************************************************************************
587     *                                                                         *
588     * Stylesheet Handling                                                     *
589     *                                                                         *
590     **************************************************************************/
591
592    private static final String DEFAULT_STYLE_CLASS = "table-column";
593    
594    /**
595     * {@inheritDoc}
596     * @return "TreeTableColumn"
597     */
598    @Override public String getTypeSelector() {
599        return "TreeTableColumn";
600    }
601
602    /**
603     * {@inheritDoc}
604     * @return {@code getTreeTableView()}
605     */
606    @Override public Styleable getStyleableParent() {
607        return getTreeTableView();
608    }
609
610    /**
611     * {@inheritDoc}
612    */
613    @Override public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
614        return getClassCssMetaData();
615    }
616    
617    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
618        return Collections.emptyList();
619    }                
620
621    /**
622     * @treatAsPrivate implementation detail
623     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
624     */
625    @Deprecated    
626    // TODO implement
627    // SB-dependency: RT-21094 has been filed to track this
628    public Node impl_styleableGetNode() {
629//        if (! (getTableView().getSkin() instanceof TableViewSkin)) return null;
630//        TableViewSkin skin = (TableViewSkin) getTableView().getSkin();
631//
632//        TableHeaderRow tableHeader = skin.getTableHeaderRow();
633//        NestedTreeTableColumnHeader rootHeader = tableHeader.getRootHeader();
634//
635//        // we now need to do a search for the header. We'll go depth-first.
636//        return scan(rootHeader);
637            return null;
638        }
639
640//    private TreeTableColumnHeader scan(TreeTableColumnHeader header) {
641//        // firstly test that the parent isn't what we are looking for
642//        if (TreeTableColumn.this.equals(header.getTreeTableColumn())) {
643//            return header;
644//        }
645//
646//        if (header instanceof NestedTreeTableColumnHeader) {
647//            NestedTreeTableColumnHeader parent = (NestedTreeTableColumnHeader) header;
648//            for (int i = 0; i < parent.getColumnHeaders().size(); i++) {
649//                TreeTableColumnHeader result = scan(parent.getColumnHeaders().get(i));
650//                if (result != null) {
651//                    return result;
652//                }
653//            }
654//        }
655//
656//        return null;
657//    }   
658    
659    /***************************************************************************
660     *                                                                         *
661     * Support Interfaces                                                      *
662     *                                                                         *
663     **************************************************************************/
664
665    /**
666     * A support class used in TreeTableColumn as a wrapper class 
667     * to provide all necessary information for a particular {@link Cell}. Once
668     * instantiated, this class is immutable.
669     * 
670     * @param <S> The TableView type
671     * @param <T> The TreeTableColumn type
672     */
673    public static class CellDataFeatures<S,T> {
674        private final TreeTableView<S> treeTableView;
675        private final TreeTableColumn<S,T> tableColumn;
676        private final TreeItem<S> value;
677
678        /**
679         * Instantiates a CellDataFeatures instance with the given properties
680         * set as read-only values of this instance.
681         * 
682         * @param tableView The TableView that this instance refers to.
683         * @param tableColumn The TreeTableColumn that this instance refers to.
684         * @param value The value for a row in the TableView.
685         */
686        public CellDataFeatures(TreeTableView<S> treeTableView,
687                TreeTableColumn<S,T> tableColumn, TreeItem<S> value) {
688            this.treeTableView = treeTableView;
689            this.tableColumn = tableColumn;
690            this.value = value;
691        }
692
693        /**
694         * Returns the value passed in to the constructor.
695         */
696        public TreeItem<S> getValue() {
697            return value;
698        }
699
700        /**
701         * Returns the {@link TreeTableColumn} passed in to the constructor.
702         */
703        public TreeTableColumn<S,T> getTreeTableColumn() {
704            return tableColumn;
705        }
706
707        /**
708         * Returns the {@link TableView} passed in to the constructor.
709         */
710        public TreeTableView<S> getTreeTableView() {
711            return treeTableView;
712        }
713    }
714    
715    
716    
717    /**
718     * An event that is fired when a user performs an edit on a table cell.
719     */
720    public static class CellEditEvent<S,T> extends Event {
721        private static final long serialVersionUID = -609964441682677579L;
722
723        /**
724         * Common supertype for all cell edit event types.
725         */
726        public static final EventType<?> ANY = EDIT_ANY_EVENT;
727
728        // represents the new value input by the end user. This is NOT the value
729        // to go back into the TableView.items list - this new value represents
730        // just the input for a single cell, so it is likely that it needs to go
731        // back into a property within an item in the TableView.items list.
732        private final T newValue;
733
734        // The location of the edit event
735        private transient final TreeTablePosition<S,T> pos;
736
737        /**
738         * Creates a new event that can be subsequently fired to the relevant listeners.
739         *
740         * @param table The TableView on which this event occurred.
741         * @param pos The position upon which this event occurred.
742         * @param eventType The type of event that occurred.
743         * @param newValue The value input by the end user.
744         */
745        public CellEditEvent(TreeTableView<S> table, TreeTablePosition<S,T> pos,
746                EventType<TreeTableColumn.CellEditEvent<S,T>> eventType, T newValue) {
747            super(table, Event.NULL_SOURCE_TARGET, eventType);
748
749            if (table == null) {
750                throw new NullPointerException("TableView can not be null");
751            }
752            if (pos == null) {
753                throw new NullPointerException("TablePosition can not be null");
754            }
755            this.pos = pos;
756            this.newValue = newValue;
757        }
758
759        /**
760         * Returns the TableView upon which this event occurred.
761         * @return The TableView control upon which this event occurred.
762         */
763        public TreeTableView<S> getTreeTableView() {
764            return pos.getTreeTableView();
765        }
766
767        /**
768         * Returns the TreeTableColumn upon which this event occurred.
769         *
770         * @return The TreeTableColumn that the edit occurred in.
771         */
772        public TreeTableColumn<S,T> getTableColumn() {
773            return pos.getTableColumn();
774        }
775
776        /**
777         * Returns the position upon which this event occurred.
778         * @return The position upon which this event occurred.
779         */
780        public TreeTablePosition<S,T> getTreeTablePosition() {
781            return pos;
782        }
783
784        /**
785         * Returns the new value input by the end user. This is <b>not</b> the value
786         * to go back into the TableView.items list - this new value represents
787         * just the input for a single cell, so it is likely that it needs to go
788         * back into a property within an item in the TableView.items list.
789         *
790         * @return An Object representing the new value input by the user.
791         */
792        public T getNewValue() {
793            return newValue;
794        }
795
796        /**
797         * Attempts to return the old value at the position referred to in the
798         * TablePosition returned by {@link #getTablePosition()}. This may return
799         * null for a number of reasons.
800         *
801         * @return Returns the value stored in the position being edited, or null
802         *     if it can not be retrieved.
803         */
804        public T getOldValue() {
805            TreeItem<S> rowData = getRowValue();
806            if (rowData == null || pos.getTableColumn() == null) {
807                return null;
808            }
809
810            // if we are here, we now need to get the data for the specific column
811            return (T) pos.getTableColumn().getCellData(rowData);
812        }
813        
814        /**
815         * Convenience method that returns the value for the row (that is, from
816         * the TableView {@link TableView#itemsProperty() items} list), for the
817         * row contained within the {@link TablePosition} returned in
818         * {@link #getTablePosition()}.
819         */
820        public TreeItem<S> getRowValue() {
821//            List<S> items = getTreeTableView().getItems();
822//            if (items == null) return null;
823
824            TreeTableView treeTable = getTreeTableView();
825            int row = pos.getRow();
826            if (row < 0 || row >= treeTable.getExpandedItemCount()) return null;
827
828            return treeTable.getTreeItem(row);
829        }
830    }
831    
832    /**
833     * Enumeration that specifies the type of sorting being applied to a specific
834     * column.
835     */
836    public static enum SortType {
837        /**
838         * Column will be sorted in an ascending order.
839         */
840        ASCENDING,
841        
842        /**
843         * Column will be sorted in a descending order.
844         */
845        DESCENDING;
846        
847        // UNSORTED
848    }
849}