Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2011, 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.beans.InvalidationListener;
029import javafx.beans.Observable;
030import javafx.beans.WeakInvalidationListener;
031import javafx.collections.ListChangeListener;
032import javafx.scene.control.TableView.TableViewFocusModel;
033
034import javafx.collections.WeakListChangeListener;
035import java.lang.ref.WeakReference;
036import java.util.List;
037import javafx.beans.property.ReadOnlyObjectProperty;
038import javafx.beans.property.ReadOnlyObjectWrapper;
039import com.sun.javafx.scene.control.skin.TableRowSkin;
040
041/**
042 * <p>TableRow is an {@link javafx.scene.control.IndexedCell IndexedCell}, but
043 * rarely needs to be used by developers creating TableView instances. The only
044 * time TableRow is likely to be encountered at all by a developer is if they
045 * wish to create a custom {@link TableView#rowFactoryProperty() rowFactory} 
046 * that replaces an entire row of a TableView.</p>
047 *
048 * <p>More often than not, it is actually easier for a developer to customize
049 * individual cells in a row, rather than the whole row itself. To do this,
050 * you can specify a custom {@link TableColumn#cellFactoryProperty() cellFactory} 
051 * on each TableColumn instance.</p>
052 *
053 * @see TableView
054 * @see TableColumn
055 * @see TableCell
056 * @see IndexedCell
057 * @see Cell
058 * @param <T> The type of the item contained within the Cell.
059 */
060public class TableRow<T> extends IndexedCell<T> {
061
062    /***************************************************************************
063     *                                                                         *
064     * Constructors                                                            *
065     *                                                                         *
066     **************************************************************************/
067
068    /**
069     * Constructs a default TableRow instance with a style class of 'table-row-cell'
070     */
071    public TableRow() {
072        getStyleClass().addAll(DEFAULT_STYLE_CLASS);
073    }
074
075
076
077    /***************************************************************************
078     *                                                                         *
079     * Instance Variables                                                      *
080     *                                                                         *
081     **************************************************************************/
082
083    
084
085    /***************************************************************************
086     *                                                                         *
087     * Callbacks and Events                                                    *
088     *                                                                         *
089     **************************************************************************/
090
091    /*
092     * This is the list observer we use to keep an eye on the SelectedCells
093     * list in the table view. Because it is possible that the table can
094     * be mutated, we create this observer here, and add/remove it from the
095     * storeTableView method.
096     */
097    private ListChangeListener<TablePosition> selectedListener = new ListChangeListener<TablePosition>() {
098        @Override
099        public void onChanged(Change<? extends TablePosition> c) {
100            updateSelection();
101        }
102    };
103
104    // Same as selectedListener, but this time for focus events
105    private final InvalidationListener focusedListener = new InvalidationListener() {
106        @Override public void invalidated(Observable valueModel) {
107            updateFocus();
108        }
109    };
110
111    // same as above, but for editing events
112    private final InvalidationListener editingListener = new InvalidationListener() {
113        @Override public void invalidated(Observable valueModel) {
114            updateEditing();
115        }
116    };
117
118    private final WeakListChangeListener weakSelectedListener = new WeakListChangeListener(selectedListener);
119    private final WeakInvalidationListener weakFocusedListener = new WeakInvalidationListener(focusedListener);
120    private final WeakInvalidationListener weakEditingListener = new WeakInvalidationListener(editingListener);
121
122    
123    
124    /***************************************************************************
125     *                                                                         *
126     * Properties                                                              *
127     *                                                                         *
128     **************************************************************************/
129    
130    // --- TableView
131    private ReadOnlyObjectWrapper<TableView<T>> tableView;
132    private void setTableView(TableView<T> value) {
133        tableViewPropertyImpl().set(value);
134    }
135
136    public final TableView<T> getTableView() {
137        return tableView == null ? null : tableView.get();
138    }
139
140    /**
141     * The TableView associated with this Cell.
142     */
143    public final ReadOnlyObjectProperty<TableView<T>> tableViewProperty() {
144        return tableViewPropertyImpl().getReadOnlyProperty();
145    }
146
147    private ReadOnlyObjectWrapper<TableView<T>> tableViewPropertyImpl() {
148        if (tableView == null) {
149            tableView = new ReadOnlyObjectWrapper<TableView<T>>() {
150                private WeakReference<TableView<T>> weakTableViewRef;
151                @Override protected void invalidated() {
152                    TableView.TableViewSelectionModel sm;
153                    TableViewFocusModel fm;
154
155                    if (weakTableViewRef != null) {
156                        TableView oldTableView = weakTableViewRef.get();
157                        if (oldTableView != null) {
158                            sm = oldTableView.getSelectionModel();
159                            if (sm != null) {
160                                sm.getSelectedCells().removeListener(weakSelectedListener);
161                            }
162
163                            fm = oldTableView.getFocusModel();
164                            if (fm != null) {
165                                fm.focusedCellProperty().removeListener(weakFocusedListener);
166                            }
167
168                            oldTableView.editingCellProperty().removeListener(weakEditingListener);
169                        }
170                        
171                        weakTableViewRef = null;
172                    }
173
174                    TableView tableView = getTableView();
175                    if (tableView != null) {
176                        sm = tableView.getSelectionModel();
177                        if (sm != null) {
178                            sm.getSelectedCells().addListener(weakSelectedListener);
179                        }
180
181                        fm = tableView.getFocusModel();
182                        if (fm != null) {
183                            fm.focusedCellProperty().addListener(weakFocusedListener);
184                        }
185
186                        tableView.editingCellProperty().addListener(weakEditingListener);
187                        
188                        weakTableViewRef = new WeakReference<TableView<T>>(get());
189                    }
190                }
191
192                @Override
193                public Object getBean() {
194                    return TableRow.this;
195                }
196
197                @Override
198                public String getName() {
199                    return "tableView";
200                }
201            };
202        }
203        return tableView;
204    }
205
206
207
208    /***************************************************************************
209     *                                                                         *
210     * Public API                                                              *
211     *                                                                         *
212     **************************************************************************/
213
214    /** {@inheritDoc} */
215    @Override protected Skin<?> createDefaultSkin() {
216        return new TableRowSkin(this);
217    }
218
219    /***************************************************************************
220     *                                                                         *
221     * Private implementation                                                  *
222     *                                                                         *
223     **************************************************************************/
224
225    private int oldIndex = -1;
226    
227    /** {@inheritDoc} */
228    @Override void indexChanged() {
229        int newIndex = getIndex();
230        
231        super.indexChanged();
232        
233        // Below we check if the index has changed, but we always call updateItem,
234        // as the value in the given index may have changed.
235        updateItem(newIndex);
236        
237        if (oldIndex == newIndex) return;
238        oldIndex = newIndex;
239        
240        updateSelection();
241        updateFocus();
242    }
243    
244    private void updateItem(int newIndex) {
245        TableView<T> tv = getTableView();
246        if (tv == null || tv.getItems() == null) return;
247        
248        List<T> items = tv.getItems();
249
250        // Compute whether the index for this cell is for a real item
251        boolean valid = newIndex >= 0 && newIndex < items.size();
252
253        // Cause the cell to update itself
254        if (valid) {
255            T newItem = items.get(newIndex);
256            if (newItem == null || ! newItem.equals(getItem())) {
257                updateItem(newItem, false);
258            }
259        } else {
260            updateItem(null, true);
261        }
262    }
263    
264    private void updateSelection() {
265        /*
266         * This cell should be selected if the selection mode of the table
267         * is row-based, and if the row that this cell represents is selected.
268         *
269         * If the selection mode is not row-based, then the listener in the
270         * TableCell class might pick up the need to set a single cell to be
271         * selected.
272         */
273        if (getIndex() == -1) return;
274        
275        TableView<T> table = getTableView();
276        boolean isSelected = table != null &&
277                table.getSelectionModel() != null &&
278                ! table.getSelectionModel().isCellSelectionEnabled() &&
279                table.getSelectionModel().isSelected(getIndex());
280
281        updateSelected(isSelected);
282    }
283
284    private void updateFocus() {
285        if (getIndex() == -1) return;
286        
287        TableView<T> table = getTableView();
288        if (table == null) return;
289        
290        TableView.TableViewSelectionModel sm = table.getSelectionModel();
291        TableView.TableViewFocusModel fm = table.getFocusModel();
292        if (sm == null || fm == null) return;
293        
294        boolean isFocused = ! sm.isCellSelectionEnabled() && fm.isFocused(getIndex());
295        setFocused(isFocused);
296    }
297
298    private void updateEditing() {
299        if (getIndex() == -1) return;
300        
301        TableView<T> table = getTableView();
302        if (table == null) return;
303
304        TableView.TableViewSelectionModel sm = table.getSelectionModel();
305        if (sm == null || sm.isCellSelectionEnabled()) return;
306
307        TablePosition editCell = table.getEditingCell();
308        boolean rowMatch = editCell.getRow() == getIndex();
309
310        if (! isEditing() && rowMatch) {
311            startEdit();
312        } else if (isEditing() && ! rowMatch) {
313            cancelEdit();
314        }
315    }
316
317
318
319    /***************************************************************************
320     *                                                                         *
321     * Expert API                                                              *
322     *                                                                         *
323     **************************************************************************/
324
325    /**
326     * Updates the TableView associated with this TableCell. This is typically
327     * only done once when the TableCell is first added to the TableView.
328     *
329     * @expert This function is intended to be used by experts, primarily
330     *         by those implementing new Skins. It is not common
331     *         for developers or designers to access this function directly.
332     */
333    public final void updateTableView(TableView<T> tv) {
334        setTableView(tv);
335    }
336
337
338    /***************************************************************************
339     *                                                                         *
340     * Stylesheet Handling                                                     *
341     *                                                                         *
342     **************************************************************************/
343
344    private static final String DEFAULT_STYLE_CLASS = "table-row-cell";
345}