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}