Commits

Henri Biestro committed 11c35e3

Refactor/renamed implementation classes

Comments (0)

Files changed (9)

src/main/java/impl/org/controlsfx/skin/RowHeader.java

-/**
- * Copyright (c) 2013, ControlsFX
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *     * Neither the name of ControlsFX, any associated website, nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package impl.org.controlsfx.skin;
-
-
-import javafx.application.Platform;
-import javafx.beans.InvalidationListener;
-import javafx.beans.Observable;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableList;
-import javafx.scene.control.CheckMenuItem;
-import javafx.scene.control.ContextMenu;
-import javafx.scene.control.Label;
-import javafx.scene.layout.StackPane;
-import javafx.scene.shape.Rectangle;
-
-import org.controlsfx.control.spreadsheet.SpreadsheetView;
-
-import com.sun.javafx.scene.control.skin.VirtualScrollBar;
-
-
-/**
- * Display a rowHeader, the index of the lines displayed on screen.
- */
-public class RowHeader  extends StackPane {
-
-	/***************************************************************************
-     *                                                                         *
-     * Private Fields                                                          *
-     *                                                                         *
-     **************************************************************************/
-	private final SpreadsheetViewSkin spreadsheetViewSkin;
-	private final SpreadsheetView spreadsheetView;
-	private double prefHeight;
-	private double prefWidth;
-	private Boolean working = true; // Whether or not we are showing the RowHeader
-//	private SpreadsheetViewSelectionModel<?> selectionModel;
-	private Rectangle clip; // Ensure that children do not go out of bounds
-	private ContextMenu blankContextMenu;
-	
-	/***************************************************************************
-     *                                                                         *
-     * Listeners                                                          	   *
-     *                                                                         *
-     **************************************************************************/
-	private final InvalidationListener layout =  new InvalidationListener() {
-		@Override
-		public void invalidated(Observable arg0) {
-			final Runnable r = new Runnable() {
-				@Override
-				public void run() {
-					requestLayout();
-				}
-			};
-			Platform.runLater(r);
-		}
-	};
-
-	
-
-	/******************************************************************
-	 * 								CONSTRUCTOR
-	 * @param skin
-	 * @param spreadsheetView
-	 * @param rowHeaderWidth
-	 ******************************************************************/
-	public RowHeader(final SpreadsheetViewSkin skin, final SpreadsheetView spreadsheetView, final double rowHeaderWidth) {
-		this.spreadsheetViewSkin = skin;
-		this.spreadsheetView = spreadsheetView;
-		prefWidth = rowHeaderWidth;
-	}
-	
-	/***************************************************************************
-     *                                                                         *
-     * Private/Protected Methods                                                          *
-     *                                                                         *
-     **************************************************************************/
-	void init(){
-		prefHeight = spreadsheetViewSkin.getDefaultCellSize();
-//		selectionModel = spreadsheetView.getSelectionModel();
-
-		//Clip property to stay within bounds
-		clip = new Rectangle(prefWidth, snapSize(spreadsheetViewSkin.getSkinnable().getHeight()));
-		clip.relocate(snappedTopInset(), snappedLeftInset());
-		clip.setSmooth(false);
-		clip.heightProperty().bind(spreadsheetViewSkin.getSkinnable().heightProperty());
-		RowHeader.this.setClip(clip);
-
-		// We desactivate and activate the rowheader upon request
-		spreadsheetView.showRowHeaderProperty().addListener(new ChangeListener<Boolean>(){
-			@Override
-			public void changed(ObservableValue<? extends Boolean> arg0,
-					Boolean arg1, Boolean arg2) {
-				working = arg2;
-				requestLayout();
-			}});
-
-		// When the Column header is showing or not, we need to update the position of the rowHeader
-		spreadsheetView.showColumnHeaderProperty().addListener(layout);
-		spreadsheetView.getFixedRows().addListener(layout);
-		//In case we resize the view in any manners
-		spreadsheetView.heightProperty().addListener(layout);
-
-		// For layout properly the rowHeader when there are some selected items
-		spreadsheetViewSkin.getSelectedRows().addListener(layout);
-		
-		blankContextMenu = new ContextMenu();
-		requestLayout();
-			
-	}
-
-	@Override protected void layoutChildren() {
-		if(working && spreadsheetView != null) {
-
-			final double x =snappedLeftInset();
-			final int cellSize = spreadsheetViewSkin.getCellsSize();
-			
-			//We add prefHeight because we need to take the other header into account
-			// And also the fixedRows if any
-			double y = snappedTopInset() ;//+prefHeight*flow.getFixedRows().size();
-			if(spreadsheetView.showColumnHeaderProperty().get()){
-				y+=prefHeight;
-			}
-
-			//The Labels must be aligned with the rows
-			if( cellSize != 0){
-				y += spreadsheetViewSkin.getCell(0).getLocalToParentTransform().getTy();
-			}
-
-			int rowCount = 0;
-			Label label;
-			int i=0;
-			// We don't want to add Label if there are no rows associated with.
-			final int modelRowCount = spreadsheetView.getGrid().getRowCount();
-			SpreadsheetRowImpl row;
-			// We iterate over the visibleRows
-			while(cellSize != 0 && spreadsheetViewSkin.getCell(i) != null && i< modelRowCount){
-				row = spreadsheetViewSkin.getCell(i);
-				label = getLabel(rowCount++);
-				label.setText(String.valueOf(row.getIndexVirtualFlow()+1));
-				label.resize(prefWidth,prefHeight);
-				label.relocate(x, y);
-				label.setContextMenu(getRowContextMenu(row.getIndexVirtualFlow()));
-				
-				//We want to highlight selected rows
-				final ObservableList<String> css = label.getStyleClass();
-				if(spreadsheetViewSkin.getSelectedRows().contains(row.getIndex())){
-					css.addAll("selected");
-				}else{
-					css.removeAll("selected");
-				}
-				if(spreadsheetView.getFixedRows().contains(row.getIndex())){
-					css.addAll("fixed");
-				}else{
-					css.removeAll("fixed");
-				}
-				y+=prefHeight;
-				++i;
-			}
-
-			// Then we iterate over the FixedRows if any
-			if(!spreadsheetView.getFixedRows().isEmpty() && cellSize != 0){
-				for(i = 0;i<spreadsheetView.getFixedRows().size();++i){
-					if(spreadsheetViewSkin.getCell(i).getCurrentlyFixed()){
-						label = getLabel(rowCount++);
-						label.setText(String.valueOf(spreadsheetView.getFixedRows().get(i)+1));
-						label.resize(prefWidth,prefHeight);
-						label.setContextMenu(getRowContextMenu(spreadsheetView.getFixedRows().get(i)));
-						
-						//If the columnHeader is here, we need to translate a bit
-						if(spreadsheetView.showColumnHeaderProperty().get()){
-							label.relocate(x, snappedTopInset()+prefHeight*(i+1));
-						}else{
-							label.relocate(x, snappedTopInset()+prefHeight*i);
-						}
-						final ObservableList<String> css = label.getStyleClass();
-						if(spreadsheetViewSkin.getSelectedRows().contains(spreadsheetViewSkin.getCell(i).getIndex())){
-							css.addAll("selected");
-						}else{
-							css.removeAll("selected");
-						}
-						css.addAll("fixed");
-						y+=prefHeight;
-					}
-				}
-			}
-
-			//First one blank and on top (z-order) of the others
-			if(spreadsheetView.showColumnHeaderProperty().get()){
-				label = getLabel(rowCount++);
-				label.setText("");
-				label.resize(prefWidth,prefHeight);
-				label.relocate(x, 0);
-				label.getStyleClass().clear();
-				label.setContextMenu(blankContextMenu);
-			}
-
-			VirtualScrollBar hbar = spreadsheetView.getSpreadsheetSkin().getHBar();
-			if(hbar.isVisible()){
-				//Last one blank and on top (z-order) of the others
-				label = getLabel(rowCount++);
-				label.setText("");
-				label.resize(prefWidth,hbar.getHeight());
-				label.relocate(snappedLeftInset(), getHeight()-hbar.getHeight());
-				label.getStyleClass().clear();
-				label.setContextMenu(blankContextMenu);
-			}
-			//Flush the rest of the children if any
-			while(getChildren().size() > rowCount){
-				getChildren().remove(rowCount);
-			}
-		}else{
-			getChildren().clear();
-		}
-	}
-
-	/**
-	 * Called when value of vertical scrollbar change
-	 */
-	void updateScrollY() {
-		if(working) {
-			requestLayout();
-		}
-	}
-
-	/**
-	 * Create a new label and put it in the pile or just
-	 * grab one from the pile.
-	 * @param rowNumber
-	 * @return
-	 */
-	private Label getLabel(int rowNumber){
-		if(getChildren().isEmpty() || getChildren().size()<=rowNumber){
-			final Label label = new Label();
-			label.resize(prefWidth,prefHeight);
-			getChildren().add(label);
-			return label;
-		}else{
-			return (Label) getChildren().get(rowNumber);
-		}
-	}
-	
-	/**
-	 * Return a contextMenu for fixing a row if possible.
-	 * @param i
-	 * @return
-	 */
-	private ContextMenu getRowContextMenu(final Integer i){
-		if(spreadsheetView.isRowFixable(i)){
-	    	final ContextMenu contextMenu = new ContextMenu();
-	
-	    	CheckMenuItem fixItem = new CheckMenuItem("Fix");
-	    	fixItem.selectedProperty().addListener(new ChangeListener<Boolean>(){
-				@Override
-				public void changed(ObservableValue<? extends Boolean> arg0,
-						Boolean arg1, Boolean arg2) {
-					
-						if(spreadsheetView.getFixedRows().contains(i)){
-							spreadsheetView.getFixedRows().remove(i);
-						}else{
-							spreadsheetView.getFixedRows().add(i);
-						}
-						//We MUST have the fixed rows sorted!
-						FXCollections.sort(spreadsheetView.getFixedRows());
-				}
-	        });
-	        contextMenu.getItems().addAll(fixItem);
-	        
-	        return contextMenu;
-    	}else{
-    		return blankContextMenu;
-    	}
-	}
-
-}

src/main/java/impl/org/controlsfx/skin/SpreadsheetCellEditorImpl.java

-package impl.org.controlsfx.skin;
-
-import javafx.beans.InvalidationListener;
-import javafx.beans.Observable;
-
-import org.controlsfx.control.spreadsheet.SpreadsheetCell;
-import org.controlsfx.control.spreadsheet.SpreadsheetCellEditor;
-import org.controlsfx.control.spreadsheet.SpreadsheetView;
-
-public class SpreadsheetCellEditorImpl<T>{
-
-	/***************************************************************************
-	 * * Protected/Private Fields * *
-	 **************************************************************************/
-
-	// transient properties - these fields will change based on the current
-	// cell being edited.
-	private SpreadsheetCell<T> modelCell;
-	private SpreadsheetCellImpl<T> viewCell;
-
-	// private internal fields
-	private SpreadsheetEditor spreadsheetEditor;
-	private InvalidationListener editorListener;
-	private InvalidationListener il;
-	private boolean editing = false;
-	private SpreadsheetView spreadsheetView;
-	private SpreadsheetCellEditor<T> spreadsheetCellEditor;
-    private SpreadsheetCellImpl<?> lastHover = null;
-
-	/***************************************************************************
-	 * * Constructor * *
-	 **************************************************************************/
-
-	/**
-	 * Construct the SpreadsheetCellEditor.
-	 */
-	public SpreadsheetCellEditorImpl() {
-		this.spreadsheetEditor = new SpreadsheetEditor();
-	}
-
-	/***************************************************************************
-	 * * Public Methods * *
-	 **************************************************************************/
-	/**
-	 * Update the internal {@link SpreadsheetCell}.
-	 * @param cell
-	 */
-	public void updateDataCell(SpreadsheetCell<T> cell) {
-		this.modelCell = cell;
-	}
-
-	/**
-	 * Update the internal {@link SpreadsheetCellImpl}
-	 * @param cell
-	 */
-	public void updateSpreadsheetCell(SpreadsheetCellImpl<T> cell) {
-		this.viewCell = cell;
-	}
-
-	/**
-	 * Update the SpreadsheetView
-	 * @param spreadsheet
-	 */
-	public void updateSpreadsheetView(SpreadsheetView spreadsheet) {
-		this.spreadsheetView = spreadsheet;
-	}
-	/**
-	 * Update the SpreadsheetCellEditor
-	 * @param spreadsheetCellEditor
-	 */
-	public void updateSpreadsheetCellEditor(final SpreadsheetCellEditor<T> spreadsheetCellEditor) {
-		this.spreadsheetCellEditor = spreadsheetCellEditor;
-	}
-    
-    public SpreadsheetCellImpl<?> getLastHover() {
-    	return lastHover;
-    }
-    
-    public void setLastHover(SpreadsheetCellImpl<?> lastHover) {
-    	this.lastHover = lastHover;
-    }
-    
-	/**
-	 * Whenever you want to stop the edition, you call that method.<br/>
-	 * True means you're trying to commit the value, then {@link #validateEdit()}
-	 * will be called in order to verify that the value is correct.<br/>
-	 * False means you're trying to cancel the value and it will be follow by {@link #end()}.<br/>
-	 * See SpreadsheetCellEditor description
-	 * @param b true means commit, false means cancel
-	 */
-	public void endEdit(boolean b){
-		if(b){
-			T value = spreadsheetCellEditor.validateEdit();
-			if(value != null && viewCell != null){
-				modelCell.setItem(value);
-				viewCell.commitEdit(modelCell);
-				end();
-				spreadsheetCellEditor.end();
-			}
-		}else{
-			viewCell.cancelEdit();
-			end();
-			spreadsheetCellEditor.end();
-		}
-	}
-
-
-	/**
-	 * Return if this editor is currently being used.
-	 * @return if this editor is being used.
-	 */
-	public boolean isEditing() {
-		return editing;
-	}
-
-	public SpreadsheetCell<T> getModelCell() {
-		return modelCell;
-	}
-
-	/***************************************************************************
-	 * * Protected/Private Methods * *
-	 **************************************************************************/
-	void startEdit() {
-		editing = true;
-		spreadsheetEditor.startEdit();
-
-		// If the SpreadsheetCell is deselected, we commit.
-		// Sometimes, when you you touch the scrollBar when editing,
-		// this is called way
-		// too late and the SpreadsheetCell is null, so we need to be
-		// careful.
-		il = new InvalidationListener() {
-			@Override
-			public void invalidated(Observable observable) {
-				endEdit(false);
-			}
-		};
-
-		viewCell.selectedProperty().addListener(il);
-
-		// In ANY case, we stop when something move in scrollBar Vertical
-		editorListener = new InvalidationListener() {
-			@Override
-			public void invalidated(Observable arg0) {
-				endEdit(false);
-			}
-		};
-		spreadsheetView.getSpreadsheetSkin().getVBar().valueProperty().addListener(editorListener);
-		//FIXME We need to REALLY find a way to stop edition when anything happen
-		// This is one way but it will need further investigation
-		spreadsheetView.disabledProperty().addListener(editorListener);
-
-		//Then we call the user editor in order for it to be ready
-		spreadsheetCellEditor.startEdit();
-
-		viewCell.setGraphic(spreadsheetCellEditor.getEditor());
-	}
-
-
-	private void end() {
-		editing = false;
-		spreadsheetEditor.end();
-		if (viewCell != null) {
-			viewCell.selectedProperty().removeListener(il);
-		}
-		il = null;
-
-		spreadsheetView.getSpreadsheetSkin().getVBar().valueProperty().removeListener(editorListener);
-		spreadsheetView.disabledProperty().removeListener(editorListener);
-		editorListener = null;
-		this.modelCell = null;
-		this.viewCell = null;
-	}
-
-
-	private class SpreadsheetEditor {
-
-		/***********************************************************************
-		 * * Private Fields * *
-		 **********************************************************************/
-		private SpreadsheetRowImpl original;
-		private boolean isMoved;
-
-		private int getCellCount() {
-			return spreadsheetView.getSpreadsheetSkin().getCellsSize();
-		}
-
-		private boolean addCell(SpreadsheetCellImpl<?> cell){
-			SpreadsheetRowImpl temp = spreadsheetView.getSpreadsheetSkin().getRow(getCellCount()-1-spreadsheetView.getFixedRows().size());
-			if(temp != null){
-				temp.addCell(cell);
-				return true;
-			}
-			return false;
-		}
-		/***********************************************************************
-		 * * Public Methods * *
-		 **********************************************************************/
-
-		/**
-		 * In case the cell is spanning in rows. We want the cell to be fully
-		 * accessible so we need to remove it from its tableRow and add it to the
-		 * last row possible. Then we translate the cell so that it's invisible for
-		 * the user.
-		 */
-		public void startEdit() {
-			// Case when RowSpan if larger and we're not on the last row
-			if (modelCell != null && modelCell.getRowSpan() > 1
-					&& modelCell.getRow() != getCellCount() - 1) {
-				original = (SpreadsheetRowImpl) viewCell.getTableRow();
-
-				final double temp = viewCell.getLocalToSceneTransform().getTy();
-				isMoved = addCell(viewCell);
-				if (isMoved) {
-					viewCell.setTranslateY(temp
-							- viewCell.getLocalToSceneTransform().getTy());
-					original.putFixedColumnToBack();
-				}
-			}
-		}
-
-		/**
-		 * When we have finish editing. We put the cell back to its right TableRow.
-		 */
-		public void end() {
-			if (modelCell != null && modelCell.getRowSpan() > 1) {
-				viewCell.setTranslateY(0);
-				if (isMoved) {
-					original.addCell(viewCell);
-					original.putFixedColumnToBack();
-				}
-			}
-		}
-	}
-}

src/main/java/impl/org/controlsfx/skin/SpreadsheetCellImpl.java

-/**
- * Copyright (c) 2013, ControlsFX
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *     * Neither the name of ControlsFX, any associated website, nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package impl.org.controlsfx.skin;
-
-import javafx.application.Platform;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.ObservableList;
-import javafx.event.EventHandler;
-import javafx.scene.control.ContentDisplay;
-import javafx.scene.control.Control;
-import javafx.scene.control.Skin;
-import javafx.scene.control.TableCell;
-import javafx.scene.control.TablePositionBase;
-import javafx.scene.control.TableSelectionModel;
-import javafx.scene.control.TableView;
-import javafx.scene.control.TableView.TableViewFocusModel;
-import javafx.scene.input.MouseButton;
-import javafx.scene.input.MouseEvent;
-
-import org.controlsfx.control.spreadsheet.Grid;
-import org.controlsfx.control.spreadsheet.SpreadsheetCell;
-import org.controlsfx.control.spreadsheet.SpreadsheetView;
-import org.controlsfx.control.spreadsheet.SpreadsheetCellType;
-
-import com.sun.javafx.scene.control.skin.TableCellSkin;
-
-
-/**
- *
- * The View cell that will be visible on screen.
- * It holds the {@link SpreadsheetCell}.
- */
-public class SpreadsheetCellImpl<T> extends TableCell<ObservableList<SpreadsheetCell<?>>, SpreadsheetCell<T>> {
-
-    /***************************************************************************
-     *                                                                         *
-     * Static Fields                                                           *
-     *                                                                         *
-     **************************************************************************/
-    private static final String ANCHOR_PROPERTY_KEY = "table.anchor";
-
-    static TablePositionBase<?> getAnchor(Control table, TablePositionBase<?> focusedCell) {
-        return hasAnchor(table) ?
-                (TablePositionBase<?>) table.getProperties().get(ANCHOR_PROPERTY_KEY) :
-                    focusedCell;
-    }
-    static boolean hasAnchor(Control table) {
-        return table.getProperties().get(ANCHOR_PROPERTY_KEY) != null;
-    }
-    
-   // private static SpreadsheetCellImpl<?> lastHover = null;
-    
-    
-    /***************************************************************************
-     *                                                                         *
-     * Constructor                                                             *
-     *                                                                         *
-     **************************************************************************/
-    public SpreadsheetCellImpl() {
-    	hoverProperty().addListener(new ChangeListener<Boolean>() {
-            @Override
-            public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
-                final int row = getIndex();
-//                final SpreadsheetView spv = ((SpreadsheetRow)getTableRow()).getSpreadsheetView();
-
-                if (getItem() == null) {
-                    getTableRow().requestLayout();
-                // We only need to re-route if the rowSpan is large because
-                // it's the only case where it's not handled correctly.
-                }else if(getItem().getRowSpan() >1){
-                	 // If we are not at the top of the Spanned Cell
-                	if (t1 && row != getItem().getRow()) {
-                        hoverGridCell(getItem());
-                    } else if (!t1 && row != getItem().getRow()) {
-                        unHoverGridCell();
-                    }
-                }
-            }
-        });
-        //When we detect a drag, we start the Full Drag so that other event will be fired
-        this.addEventHandler(MouseEvent.DRAG_DETECTED,new EventHandler<MouseEvent>() {
-            @Override
-            public void handle(MouseEvent arg0) {
-                startFullDrag();
-            }});
-
-
-        setOnMouseDragEntered(new EventHandler<MouseEvent>(){
-            @Override
-            public void handle(MouseEvent arg0) {
-                dragSelect(arg0);
-            }});
-
-    }
-
-    /***************************************************************************
-     *                                                                         *
-     * Public Methods                                                          *
-     *                                                                         *
-     **************************************************************************/
-    @Override
-    public void startEdit() {
-        if(!isEditable()) {
-            return;
-        }
-
-        final int column = this.getTableView().getColumns().indexOf(this.getTableColumn());
-        final int row = getIndex();
-        //We start to edit only if the Cell is a normal Cell (aka visible).
-        final SpreadsheetView spv = getSpreadsheetView();
-        final SpreadsheetViewSkin sps = spv.getSpreadsheetSkin();
-        Grid grid = spv.getGrid();
-        final SpreadsheetView.SpanType type = grid.getSpanType(spv, row, column);
-        if ( type == SpreadsheetView.SpanType.NORMAL_CELL || type == SpreadsheetView.SpanType.ROW_VISIBLE) {
-        	
-        	/* FIXME Currently we're adding a row two times if it's located in the fixedRows.
-        	 * So we have a problem because some events, especially when editing
-        	 * are received in double.
-        	 * I don't know right now why this is happening but I have found a work-around.
-        	 * I check if the current SpreadsheetRow is referenced in the SpreadsheetView,
-        	 * if not, then I know I can throw it away (setManaged(false) ?)
-        	 */
-        	if(spv.getFixedRows().contains(row)){//row <= spv.getFixedRows().size()){
-	        	boolean flag = false;
-	        	for (int j = 0; j< sps.getCellsSize();j++ ) {
-	                    if(sps.getRow(j) == getTableRow()){
-	                    	flag = true;
-	                    }
-	            }
-	        	if(!flag){
-	        		getTableRow().setManaged(false);
-	        		return;
-	        	}
-        	}
-        	
-        	SpreadsheetCellEditorImpl<T> editor = getEditor(getItem(), spv);
-            if(editor != null){
-                super.startEdit();
-                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
-                editor.startEdit();
-            }
-        }
-    }
-    
-    /**
-     * Return an instance of Editor specific to the Cell type
-     * We are not using the build-in editor-Cell because we cannot know in advance
-     * which editor we will need. Furthermore, we want to control the behavior very closely
-     * in regards of the spanned cell (invisible etc).
-     * @param cell The SpreadsheetCell
-     * @param bc The SpreadsheetCell
-     * @return
-     */
-    @SuppressWarnings("unchecked")
-    private SpreadsheetCellEditorImpl<T> getEditor(final SpreadsheetCell<T> cell, final SpreadsheetView spv) {
-    	SpreadsheetCellType cellType = cell.getCellType();
-    	SpreadsheetCellEditorImpl<T> editor2 = (SpreadsheetCellEditorImpl<T>) spv.getSpreadsheetSkin().getSpreadsheetCellEditorImpl();
-        if (editor2.isEditing()){
-            return null;
-        } else {
-        	editor2.updateSpreadsheetView(spv);
-        	editor2.updateSpreadsheetCell(this);
-        	editor2.updateDataCell(cell);
-        	editor2.updateSpreadsheetCellEditor(cellType.getEditor(spv));
-            return editor2;
-        }
-    }
-    
-    
-
-    @Override
-    public void commitEdit(SpreadsheetCell<T> newValue) {
-        if (! isEditing()) {
-            return;
-        }
-        super.commitEdit(newValue);
-
-        setContentDisplay(ContentDisplay.TEXT_ONLY);
-
-        updateItem(newValue, false);
-
-    }
-
-    @Override
-    public void cancelEdit() {
-        if (! isEditing()) {
-            return;
-        }
-
-        super.cancelEdit();
-
-        setContentDisplay(ContentDisplay.TEXT_ONLY);
-        final Runnable r = new Runnable() {
-            @Override
-            public void run() {
-                getTableView().requestFocus();
-            }
-        };
-        Platform.runLater(r);
-    }
-
-    @Override
-    public void updateItem(final SpreadsheetCell<T> item, boolean empty) {
-        final boolean emptyRow = getTableView().getItems().size() < getIndex() + 1;
-
-        /**
-         * don't call super.updateItem() because it will trigger cancelEdit() if
-         * the cell is being edited. It causes calling commitEdit() ALWAYS call
-         * cancelEdit as well which is undesired.
-         *
-         */
-        if (!isEditing()) {
-            super.updateItem(item, empty && emptyRow);
-        }
-        if (empty && isSelected()) {
-            updateSelected(false);
-        }
-        if (empty && emptyRow) {
-            setText(null);
-            //do not nullify graphic here. Let the TableRow to control cell dislay
-            //setGraphic(null);
-            setContentDisplay(null);
-        } else if (!isEditing() && item != null) {
-            show(item);
-            //Sometimes the hoverProperty is not called on exit. So the cell is affected to a new Item but
-            // the hover is still activated. So we fix it now.
-            if(isHover()){
-            	setHoverPublic(false);
-            }
-
-        }
-    }
-    
-    /**
-     * Set this SpreadsheetCell hoverProperty
-     *
-     * @param hover
-     */
-    void setHoverPublic(boolean hover) {
-        this.setHover(hover);
-        // We need to tell the SpreadsheetRow where this SpreadsheetCell is in to be in Hover
-        //Otherwise it's will not be visible
-        ((SpreadsheetRowImpl) this.getTableRow()).setHoverPublic(hover);
-    }
-
-    @Override
-    public String toString(){
-        return getItem().getRow()+"/"+getItem().getColumn();
-
-    }
-    /**
-     * Called in the gridRowSkinBase when doing layout
-     * This allow not to override opacity in the row and let the
-     * cell handle itself
-     */
-    public void show(final SpreadsheetCell<?> item){
-        //We reset the settings
-        setText(item.getText());
-        this.setEditable(item.isEditable());
-        
-        getStyleClass().clear();
-        getStyleClass().add("spreadsheet-cell");
-        
-        // TODO bind
-        getStyleClass().addAll(item.getStyleClass());
-        
-        // Style
-//        final ObservableList<String> css = getStyleClass();
-//        if (css.size() == 1) {
-//            css.set(0, item.getStyleCss());
-//        }else{
-//            css.clear();
-//            css.add(item.getStyleCss());
-//        }
-    }
-
-    public void show(){
-        if (getItem() != null){
-            show(getItem());
-        }
-    }
-
-    /***************************************************************************
-     *                                                                         *
-     * Protected Methods                                                          *
-     *                                                                         *
-     **************************************************************************/
-    @Override
-    protected Skin<?> createDefaultSkin() {
-        return new TableCellSkin<>(this);
-    }
-
-    /***************************************************************************
-     *                                                                         *
-     * Private Methods                                                          *
-     *                                                                         *
-     **************************************************************************/
-    
-    private SpreadsheetView getSpreadsheetView() {
-        return ((SpreadsheetRowImpl)getTableRow()).getSpreadsheetView();
-    }
-    
-    /**
-     * A SpreadsheetCell is being hovered and we need to re-route the signal.
-     *
-     * @param cell The DataCell needed to be hovered.
-     * @param hover
-     */
-    private void hoverGridCell(SpreadsheetCell<?> cell) {
-        SpreadsheetCellImpl<?> gridCell;
-        
-        final SpreadsheetView spv = getSpreadsheetView();
-        final SpreadsheetViewSkin sps = spv.getSpreadsheetSkin();
-        final SpreadsheetRowImpl row = sps.getRow(spv.getFixedRows().size());
-        
-        if (sps.getCellsSize() !=0  && row.getIndex() <= cell.getRow()) {
-        	final SpreadsheetRowImpl rightRow = sps.getRow(spv.getFixedRows().size()+cell.getRow() - row.getIndex());
-            // We want to get the top of the spanned cell, so we need
-            // to access the fixedRows.size plus the difference between where we want to go and the first visibleRow (header excluded)
-            if( rightRow != null) {// Sometime when scrolling fast it's null so..
-                gridCell = rightRow.getGridCell(cell.getColumn());
-            } else {
-                gridCell = row.getGridCell(cell.getColumn());
-            }
-        } else { // If it's not, then it's the firstkey
-            gridCell = row.getGridCell(cell.getColumn());
-        }
-        
-        if(gridCell != null){
-	        gridCell.setHoverPublic(true);
-	        SpreadsheetCellEditorImpl<?> editor = sps.getSpreadsheetCellEditorImpl();
-	        editor.setLastHover(gridCell);
-        }
-    }
-
-    /**
-     * Set Hover to false to the previous Cell we force to be hovered
-     */
-    private void unHoverGridCell() {
-        //If the top of the spanned cell is visible, then no problem
-        final SpreadsheetView spv = getSpreadsheetView();
-        final SpreadsheetViewSkin sps = spv.getSpreadsheetSkin();
-        SpreadsheetCellEditorImpl<?> editor = sps.getSpreadsheetCellEditorImpl();
-        SpreadsheetCellImpl<?> lastHover = editor.getLastHover();
-        if(editor.getLastHover() != null){
-        	lastHover.setHoverPublic(false);
-        }
-    }
-    
-    
-    /**
-     * Method that will select all the cells between the drag place and that cell.
-     * @param e
-     */
-    private void dragSelect(MouseEvent e) {
-
-        // If the mouse event is not contained within this tableCell, then
-        // we don't want to react to it.
-        if (! this.contains(e.getX(), e.getY())) {
-            return;
-        }
-
-        final TableView<ObservableList<SpreadsheetCell<?>>> tableView = getTableView();
-        if (tableView == null) {
-            return;
-        }
-
-        final int count = tableView.getItems().size();
-        if (getIndex() >= count) {
-            return;
-        }
-
-        final TableSelectionModel<ObservableList<SpreadsheetCell<?>>> sm = tableView.getSelectionModel();
-        if (sm == null) {
-            return;
-        }
-
-        final int row = getIndex();
-        final int column = tableView.getVisibleLeafIndex(getTableColumn());
-        // For spanned Cells
-        final SpreadsheetCell<?> cell = (SpreadsheetCell<?>) getItem();
-        final int rowCell = cell.getRow()+cell.getRowSpan()-1;
-        final int columnCell = cell.getColumn()+cell.getColumnSpan()-1;
-
-        final TableViewFocusModel<?> fm = tableView.getFocusModel();
-        if (fm == null) {
-            return;
-        }
-
-        final TablePositionBase<?> focusedCell = fm.getFocusedCell();
-        final MouseButton button = e.getButton();
-        if (button == MouseButton.PRIMARY) {
-            // we add all cells/rows between the current selection focus and
-            // this cell/row (inclusive) to the current selection.
-            final TablePositionBase<?> anchor = getAnchor(tableView, focusedCell);
-
-            // and then determine all row and columns which must be selected
-            int minRow = Math.min(anchor.getRow(), row);
-            minRow = Math.min(minRow, rowCell);
-            int maxRow = Math.max(anchor.getRow(), row);
-            maxRow = Math.max(maxRow, rowCell);
-            int minColumn = Math.min(anchor.getColumn(), column);
-            minColumn = Math.min(minColumn, columnCell);
-            int maxColumn = Math.max(anchor.getColumn(), column);
-            maxColumn = Math.max(maxColumn, columnCell);
-
-            // clear selection, but maintain the anchor
-            sm.clearSelection();
-
-            // and then perform the selection
-            for (int _row = minRow; _row <= maxRow; _row++) {
-                for (int _col = minColumn; _col <= maxColumn; _col++) {
-                    sm.select(_row, tableView.getVisibleLeafColumn(_col));
-                }
-            }
-        }
-
-    }
-}

src/main/java/impl/org/controlsfx/skin/SpreadsheetHeaderRow.java

-/**
- * Copyright (c) 2013, ControlsFX
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *     * Neither the name of ControlsFX, any associated website, nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package impl.org.controlsfx.skin;
-
-import java.util.List;
-
-import javafx.application.Platform;
-import javafx.beans.InvalidationListener;
-import javafx.beans.Observable;
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.collections.ListChangeListener;
-import javafx.scene.shape.Rectangle;
-
-import org.controlsfx.control.spreadsheet.SpreadsheetColumn;
-
-import com.sun.javafx.scene.control.skin.NestedTableColumnHeader;
-import com.sun.javafx.scene.control.skin.TableColumnHeader;
-import com.sun.javafx.scene.control.skin.TableHeaderRow;
-
-public class SpreadsheetHeaderRow extends TableHeaderRow {
-
-    SpreadsheetViewSkin spreadsheetViewSkin;
-    public SpreadsheetHeaderRow(final SpreadsheetViewSkin skin) {
-        super(skin);
-        spreadsheetViewSkin = skin;
-    }
-    public void init() {
-        final Runnable r = new Runnable() {
-            @Override
-            public void run() {
-
-                spreadsheetViewSkin.spreadsheetView.showRowHeaderProperty().addListener(rowHeaderListener);
-//                selectionModel = spreadsheetViewSkin.spreadsheetView.getSelectionModel();
-                spreadsheetViewSkin.getSelectedColumns().addListener(selectionListener);
-                spreadsheetViewSkin.spreadsheetView.getFixedColumns().addListener(fixedColumnsListener);
-
-                spreadsheetViewSkin.getTableMenuButtonVisibleProperty()
-                        .addListener(new InvalidationListener() {
-                            @Override
-                            public void invalidated(Observable valueModel) {
-                                if (working) {
-                                    requestLayout();
-                                }
-                            }
-                        });
-
-                /*****************************************************************
-                 * MODIFIED BY NELLARMONIA
-                 *****************************************************************/
-                // We listen to the BooleanProperty linked with the CheckBox of
-                // the columnHeader
-                spreadsheetViewSkin.spreadsheetView.showColumnHeaderProperty()
-                        .addListener(new ChangeListener<Boolean>() {
-                            @Override
-                            public void changed(
-                                    ObservableValue<? extends Boolean> arg0,
-                                    Boolean arg1, Boolean arg2) {
-                                working = arg2;
-                                requestLayout();
-                                getRootHeader().layoutFixedColumns();
-                                updateHighlighSelection();
-                            }
-                        });
-                /*****************************************************************
-                 * END OF MODIFIED BY NELLARMONIA
-                 *****************************************************************/
-            }
-        };
-        Platform.runLater(r);
-    }
-
-    protected void updateTableWidth() {
-        super.updateTableWidth();
-        // snapping added for RT-19428
-        double padding = 0;
-        /*****************************************************************
-         * MODIFIED BY NELLARMONIA
-         *****************************************************************/
-        if (spreadsheetViewSkin != null
-                && spreadsheetViewSkin.spreadsheetView != null
-                && spreadsheetViewSkin.spreadsheetView.showRowHeaderProperty().get()) {
-            padding += spreadsheetViewSkin.getRowHeaderWidth();
-        }
-
-        /*****************************************************************
-         * END OF MODIFIED BY NELLARMONIA
-         *****************************************************************/
-        Rectangle clip = ((Rectangle) getClip());
-        clip.setWidth(clip.getWidth() == 0 ? 0 : clip.getWidth() - padding);
-    }
-
-    protected void updateScrollX() {
-        super.updateScrollX();
-        /*****************************************************************
-         * MODIFIED BY NELLARMONIA
-         *****************************************************************/
-        if (working) {
-            requestLayout();
-            getRootHeader().layoutFixedColumns();
-        }
-        /*****************************************************************
-         * END OF MODIFIED BY NELLARMONIA
-         *****************************************************************/
-    }
-
-    // Indicate wether the this TableHeaderRow is activated or not
-    private Boolean working = true;
-
-    /**
-     * When the Rowheader is showing (or not anymore) we need to react
-     * accordingly
-     */
-    private final ChangeListener<Boolean> rowHeaderListener = new ChangeListener<Boolean>() {
-		@Override
-		public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
-			 updateTableWidth();
-		}
-    };
-    
-    /**
-     * When we fix/unfix some columns, we change the style of the Label header text
-     */
-    private final ListChangeListener<SpreadsheetColumn<?>> fixedColumnsListener = new ListChangeListener<SpreadsheetColumn<?>>() {
-
-		@Override
-		public void onChanged(
-				javafx.collections.ListChangeListener.Change<? extends SpreadsheetColumn<?>> arg0) {
-			while(arg0.next()){
-				//If we unfix a column
-				for (SpreadsheetColumn<?> remitem : arg0.getRemoved()) {
-                   removeStyleHeader(spreadsheetViewSkin.spreadsheetView.getColumns().indexOf(remitem));
-                }
-				//If we fix one
-                for (SpreadsheetColumn<?> additem : arg0.getAddedSubList()) {
-                	addStyleHeader(spreadsheetViewSkin.spreadsheetView.getColumns().indexOf(additem));
-                }
-			}
-			 updateHighlighSelection();
-		}
-	}; 
-
-	/**
-	 * Add the fix style of the header Label of the specified column
-	 * @param i
-	 */
-	private void removeStyleHeader(Integer i) {
-        	getRootHeader().getColumnHeaders().get(i).getChildrenUnmodifiable().get(0).getStyleClass().removeAll("fixed");
-    }
-	/**
-	 * Remove the fix style of the header Label of the specified column
-	 * @param i
-	 */
-	private void addStyleHeader(Integer i) {
-            getRootHeader().getColumnHeaders().get((Integer) i)
-                    .getChildrenUnmodifiable().get(0).getStyleClass()
-                    .addAll("fixed");
-    }
-//    private TableViewSelectionModel<ObservableList<SpreadsheetCell<?>>> selectionModel;
-    
-    
-    /**
-     * When we select some cells, we want the header to be highlighted
-     */
-    private final InvalidationListener selectionListener = new InvalidationListener() {
-        @Override
-        public void invalidated(Observable valueModel) {
-            updateHighlighSelection();
-        }
-    };
-    
-    /**
-     * Highlight the header Label when selection change.
-     */
-    private void updateHighlighSelection() {
-    	for (final TableColumnHeader i : getRootHeader().getColumnHeaders()) {
-            i.getChildrenUnmodifiable().get(0).getStyleClass().removeAll("selected");
-
-        }
-        final List<Integer> selectedColumns = spreadsheetViewSkin.getSelectedColumns();
-        // TODO Ugly hack to get access to the Label
-        for (final Object i : selectedColumns) {
-            getRootHeader().getColumnHeaders().get((Integer) i)
-                    .getChildrenUnmodifiable().get(0).getStyleClass()
-                    .addAll("selected");
-        }
-
-    }
-
-    protected NestedTableColumnHeader createRootHeader() {
-        return new SpreadsheetNestedTableColumnHeader(getTableSkin(), null);
-    }
-
-    public SpreadsheetNestedTableColumnHeader getRootHeader() {
-        return (SpreadsheetNestedTableColumnHeader) super.getRootHeader();
-    }
-
-}

src/main/java/impl/org/controlsfx/skin/SpreadsheetNestedTableColumnHeader.java

-/**
- * Copyright (c) 2013, ControlsFX
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *     * Neither the name of ControlsFX, any associated website, nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package impl.org.controlsfx.skin;
-
-import org.controlsfx.control.spreadsheet.SpreadsheetView;
-
-import javafx.scene.control.TableColumnBase;
-
-import com.sun.javafx.scene.control.skin.NestedTableColumnHeader;
-import com.sun.javafx.scene.control.skin.TableColumnHeader;
-import com.sun.javafx.scene.control.skin.TableViewSkinBase;
-
-public class SpreadsheetNestedTableColumnHeader extends NestedTableColumnHeader {
-
-    public SpreadsheetNestedTableColumnHeader(
-            TableViewSkinBase<?, ?, ?, ?, ?, ?> skin, TableColumnBase<?, ?> tc) {
-        super(skin, tc);
-    }
-
-    @Override
-    protected TableColumnHeader createTableColumnHeader(TableColumnBase col) {
-        return col.getColumns().isEmpty()
-                ? new TableColumnHeader(getTableViewSkin(), col)
-                : new SpreadsheetNestedTableColumnHeader(getTableViewSkin(),
-                        col);
-    }
-
-    @Override
-    protected void layoutChildren() {
-        super.layoutChildren();
-        /*****************************************************************
-         * MODIFIED BY NELLARMONIA
-         *****************************************************************/
-        layoutFixedColumns();
-        /*****************************************************************
-         * END OF MODIFIED BY NELLARMONIA
-         *****************************************************************/
-    }
-
-    /**
-     * We want ColumnHeader to be fixed when we freeze some columns
-     * 
-     * @param scrollX
-     */
-    public void layoutFixedColumns() {
-    	final SpreadsheetView spreadsheetView = ((SpreadsheetViewSkin) getTableViewSkin()).spreadsheetView;
-        double hbarValue = spreadsheetView.getSpreadsheetSkin().getHBar().getValue();
-        
-        final int labelHeight = (int) getChildren().get(0).prefHeight(-1);
-        double fixedColumnWidth = 0;
-        double x = snappedLeftInset();
-        
-        for (int j = 0, max = getColumnHeaders().size(); j < max; j++) {
-        	final TableColumnHeader n = getColumnHeaders().get(j);
-        	final double prefWidth = snapSize(n.prefWidth(-1));
-        	 
-        	//If the column is fixed
-        	if(spreadsheetView.getFixedColumns().indexOf(spreadsheetView.getColumns().get(j)) != -1){
-                 double tableCellX = 0;
-                 //If the column is hidden we have to translate it
-                 if(hbarValue + fixedColumnWidth > x){
-
-                 	tableCellX = Math.abs(hbarValue - x + fixedColumnWidth);
-
-                 	n.toFront();
-                 	fixedColumnWidth += prefWidth;
-                 }
-                 n.relocate(x+tableCellX , labelHeight + snappedTopInset());
-        	}
-        	
-           x+= prefWidth;
-        }
-
-    }
-
-    public void updateHeader() {
-        setHeadersNeedUpdate();
-    }
-
-}

src/main/java/impl/org/controlsfx/skin/SpreadsheetRowImpl.java

-/**
- * Copyright (c) 2013, ControlsFX
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *     * Neither the name of ControlsFX, any associated website, nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package impl.org.controlsfx.skin;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-
-import javafx.collections.ObservableList;
-import javafx.scene.Node;
-import javafx.scene.control.Skin;
-import javafx.scene.control.TableRow;
-
-import org.controlsfx.control.spreadsheet.SpreadsheetCell;
-import org.controlsfx.control.spreadsheet.SpreadsheetView;
-
-
-/**
- *
- * The tableRow which will holds the SpreadsheetCell.
- */
-public class SpreadsheetRowImpl extends TableRow<ObservableList<SpreadsheetCell<?>>>{
-
-    /***************************************************************************
-     *                                                                         *
-     * Private Fields                                                          *
-     *                                                                         *
-     **************************************************************************/
-    private final SpreadsheetView spreadsheetView;
-    /**
-     * This is the index used by the VirtualFlow
-     * So the row can be with indexVirtualFlow at 32
-     * But if it is situated in the header, his index will be 0 (or the row in the header)
-     */
-    private Integer indexVirtualFlow = null;
-    private boolean layoutFixedColumns = false;
-    private Boolean currentlyFixed = false;
-
-    /***************************************************************************
-     *                                                                         *
-     * Constructor                                                             *
-     *                                                                         *
-     **************************************************************************/
-    public SpreadsheetRowImpl(SpreadsheetView spreadsheetView) {
-        super();
-        this.spreadsheetView = spreadsheetView;
-    }
-
-    /***************************************************************************
-     *                                                                         *
-     * Public Methods                                                          *
-     *                                                                         *
-     **************************************************************************/
-
-    public int getIndexVirtualFlow(){
-        return indexVirtualFlow == null?getIndex():indexVirtualFlow;
-    }
-    
-    public void setIndexVirtualFlow(int i){
-        indexVirtualFlow = i;
-    }
-
-    public Boolean getCurrentlyFixed() {
-		return currentlyFixed;
-	}
-
-	/**
-	 * Indicate that this row is bonded on the top.
-	 * @param currentlyFixed
-	 */
-	public void setCurrentlyFixed(Boolean currentlyFixed) {
-		this.currentlyFixed = currentlyFixed;
-	}
-	
-    /**
-     * For the fixed columns in order to just re-layout the fixed columns
-     * @param b
-     */
-    public void setLayoutFixedColumns(boolean b){
-        layoutFixedColumns = b;
-    }
-
-    public boolean getLayoutFixedColumns(){
-        return layoutFixedColumns;
-    }
-
-    /**
-     * When unfixing some Columns, we need to put the previously FixedColumns back
-     * if we want the hover to be dealt correctly
-     * @param size
-     */
-    public void putFixedColumnToBack() {
-        final List<Node> tset = new ArrayList<>(getChildren());
-        tset.sort( new Comparator<Node>() {
-            @Override
-            public int compare(Node o1, Node o2) {
-                // In case it's null (some rows are initiated after rowCount)
-                if(((SpreadsheetCellImpl<?>)o1).getItem() == null || ((SpreadsheetCellImpl<?>)o2).getItem() == null){
-                    return -1;
-                }
-                final int lhs = getTableView().getColumns().indexOf(((SpreadsheetCellImpl<?>) o1).getTableColumn());
-                final int rhs = getTableView().getColumns().indexOf(((SpreadsheetCellImpl<?>) o2).getTableColumn());
-                if (lhs < rhs) {
-                    return -1;
-                }
-                if (lhs > rhs) {
-                    return +1;
-                }
-                return 0;
-
-            }
-        });
-        getChildren().setAll(tset);
-    }
-
-
-    public void addCell(SpreadsheetCellImpl<?> cell){
-        getChildren().add(cell);
-    }
-
-    public void removeCell(SpreadsheetCellImpl<?> gc) {
-        getChildren().remove(gc);
-    }
-
-    /***************************************************************************
-     *                                                                         *
-     * Protected Methods                                                       *
-     *                                                                         *
-     **************************************************************************/
-
-    SpreadsheetView getSpreadsheetView() {
-        return spreadsheetView;
-    }
-
-    /**
-     * Set this SpreadsheetRow hoverProperty
-     * @param hover
-     */
-    void setHoverPublic(boolean hover) {
-        this.setHover(hover);
-    }
-
-    /**
-     * Return the SpreadsheetCell at the specified column.
-     * We have to be careful because if we have fixedColumns
-     * then the fixedColumns cells will be at the end of the Children's List
-     * @param col
-     * @return the corresponding SpreadsheetCell
-     */
-    SpreadsheetCellImpl<?> getGridCell(int col){
-    	
-    	// Too much complication for a minor effect, simple is better.
- 	/*	final int max = getChildrenUnmodifiable().size()-1;
- 		int j = max;
- 		while(j>= 0 && ((SpreadsheetCellImpl<?>)getChildrenUnmodifiable().get(j)).getItem().getColumn() != max){
- 			--j;
- 		}
- 		
-    	int fixedColSize = j == -1? 0:max -j;
-    	
-    	//If any cells was moved to the end
-        if(fixedColSize != 0){
-        	//if the requested column is fixed
-            if(spreadsheetView.getColumns().get(col).getCurrentlyFixed()){
-            	final int indexCol = spreadsheetView.getFixedColumns().indexOf(col);
-                return (SpreadsheetCellImpl<?>) getChildrenUnmodifiable().get(getChildrenUnmodifiable().size() + indexCol - fixedColSize);
-            } else {
-                return (SpreadsheetCellImpl<?>) getChildrenUnmodifiable().get( col- fixedColSize );
-            }
-        }else{
-            return (SpreadsheetCellImpl<?>) getChildrenUnmodifiable().get(col);
-        }*/
-    	
-        for(Node cell:getChildrenUnmodifiable()){
-        	if(((SpreadsheetCellImpl<?>)cell).getItem().getColumn() == col){
-        		return ((SpreadsheetCellImpl<?>)cell);
-        	}
-        }
-        return null;
-    }
-
-    @Override
-    protected Skin<?> createDefaultSkin() {
-        return new SpreadsheetRowSkin<>(this,spreadsheetView);
-    }
-
-}

src/main/java/impl/org/controlsfx/skin/SpreadsheetRowSkin.java

-/**
- * Copyright (c) 2013, ControlsFX
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *     * Neither the name of ControlsFX, any associated website, nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL CONTROLSFX BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package impl.org.controlsfx.skin;
-
-import java.lang.reflect.Field;
-
-import javafx.collections.ObservableList;
-import javafx.scene.control.TableColumn;
-import javafx.scene.control.TableColumnBase;
-import javafx.scene.control.TablePosition;
-import javafx.scene.control.TableRow;
-import javafx.scene.control.TableView;
-import javafx.scene.control.TableView.TableViewSelectionModel;
-
-import org.controlsfx.control.spreadsheet.Grid;
-import org.controlsfx.control.spreadsheet.SpreadsheetCell;
-import org.controlsfx.control.spreadsheet.SpreadsheetView;
-
-import com.sun.javafx.scene.control.skin.TableRowSkin;
-
-public class SpreadsheetRowSkin<T extends ObservableList<SpreadsheetCell<?>>> extends TableRowSkin<ObservableList<SpreadsheetCell<?>>> {
-    
-    static final double DEFAULT_CELL_SIZE;
-    static {
-        double cell_size = 24.0;
-        try {
-            Class<?> clazz = com.sun.javafx.scene.control.skin.CellSkinBase.class;
-            Field f = clazz.getDeclaredField("DEFAULT_CELL_SIZE");
-            f.setAccessible(true);
-            cell_size = f.getDouble(null);
-        } catch (NoSuchFieldException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (SecurityException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (IllegalArgumentException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        } catch (IllegalAccessException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-        DEFAULT_CELL_SIZE = cell_size;
-    }
-    
-    SpreadsheetView spreadsheetView;
-    private TableView<ObservableList<SpreadsheetCell<?>>> tableView;
-    
-    public SpreadsheetRowSkin(TableRow<ObservableList<SpreadsheetCell<?>>> tableRow,
-            SpreadsheetView spreadsheetView) {
-        super(tableRow);
-        this.spreadsheetView = spreadsheetView;
-        this.tableView = (TableView<ObservableList<SpreadsheetCell<?>>>) spreadsheetView.getSpreadsheetSkin().getNode();
-    }
-
-    /**
-     * We need to override this since B105 because it's messing up our
-     * fixedRows and also our rows CSS.. (kind of flicker)
-     */
-    @Override protected void handleControlPropertyChanged(String p) {
-        if ("ITEM".equals(p)) {
-            updateCells = true;
-            getSkinnable().requestLayout();
-        } else if ("INDEX".equals(p)){
-           /* // update the index of all children cells (RT-29849)
-            final int newIndex = getSkinnable().getIndex();
-            for (int i = 0, max = cells.size(); i < max; i++) {
-                cells.get(i).updateIndex(newIndex);
-            }*/
-        } else  {
-            super.handleControlPropertyChanged(p);
-        }
-    }
-    
-    @Override
-    protected void layoutChildren(double x, final double y, final double w,
-            final double h) {
-
-        /**
-         * RT-26743:TreeTableView: Vertical Line looks unfinished. We used to
-         * not do layout on cells whose row exceeded the number of items, but
-         * now we do so as to ensure we get vertical lines where expected in
-         * cases where the vertical height exceeds the number of items.
-         */
-        // I put that at the very beginning in the hope that I will not have
-        // that extra row at the bottom layouting.
-        final TableRow<ObservableList<SpreadsheetCell<?>>> control = (TableRow<ObservableList<SpreadsheetCell<?>>>) getSkinnable();
-        final int index = control.getIndex();
-        if (index < 0 || index >= tableView.getItems().size()) {
-            control.setOpacity(0);
-            return;
-        }
-        control.setOpacity(1);
-        checkState(true);
-        if (cellsMap.isEmpty()) { return; }
-
-        final ObservableList<? extends TableColumnBase<?, ?>> visibleLeafColumns = getVisibleLeafColumns();
-        if (visibleLeafColumns.isEmpty()) {
-            super.layoutChildren(x, y, w, h);
-            return;
-        }
-
-     
-        // determine the width of the visible portion of the table
-        double headerWidth =  tableView.getWidth();
-        
-        Grid grid = spreadsheetView.getGrid();
-        
-        // layout the individual column cells
-        double width;
-        double height;
-
-        final double verticalPadding = snappedTopInset() + snappedBottomInset();
-        final double horizontalPadding = snappedLeftInset()
-                + snappedRightInset();
-        final double controlHeight = control.getHeight();
-
-        
-        /**
-         * FOR FIXED ROWS
-         */
-        double tableCellY = 0;
-        int positionY = spreadsheetView.getFixedRows().indexOf(index);
-        //If true, this row is fixed
-        if (positionY != -1 && getSkinnable().getLocalToParentTransform().getTy() <= positionY * DEFAULT_CELL_SIZE) {
-        	//This row is a bit hidden on top so we translate then for it to be fully visible
-            tableCellY = positionY * DEFAULT_CELL_SIZE
-                    - getSkinnable().getLocalToParentTransform().getTy();
-            ((SpreadsheetRowImpl)getSkinnable()).setCurrentlyFixed(true);
-        }else{
-        	((SpreadsheetRowImpl)getSkinnable()).setCurrentlyFixed(false);
-        }
-
-        double fixedColumnWidth = 0;
-        for (int column = 0; column < cells.size(); column++) {
-
-            final SpreadsheetCellImpl<?> tableCell = (SpreadsheetCellImpl<?>) cells.get(column);
-
-            // In case the node was treated previously
-            tableCell.setOpacity(1);
-
-            width = snapSize(tableCell.prefWidth(-1))
-                    - snapSize(horizontalPadding);
-            height = Math.max(controlHeight, tableCell.prefHeight(-1));
-            height = snapSize(height) - snapSize(verticalPadding);
-
-            /**
-             * FOR FIXED COLUMNS
-             */
-            double tableCellX = 0;
-            final double hbarValue = spreadsheetView.getSpreadsheetSkin().getHBar().getValue();
-            
-            //Virtualization of column
-            final SpreadsheetCell<?> cellSpan = grid.getRows().get(index).get(column);
-            boolean isVisible = !isInvisible(x,width,hbarValue,headerWidth,cellSpan.getColumnSpan());
-            
-            // We translate that column by the Hbar Value if it's fixed
-            if (spreadsheetView.getColumns().get(column).isFixed()) {
-                
-                 if(hbarValue + fixedColumnWidth >x){
-                	 tableCellX = Math.abs(hbarValue - x + fixedColumnWidth); 
-                	 tableCell.toFront();
-                	 fixedColumnWidth += tableCell.getWidth();
-                	 isVisible = true; // If in fixedColumn, it's obviously visible
-                 }
-            }
-
-            
-//            if (fixedCellSizeProperty().get() > 0) {
-                // we determine if the cell is visible, and if not we have the
-                // ability to take it out of the scenegraph to help improve
-                // performance. However, we only do this when there is a
-                // fixed cell length specified in the TableView. This is because
-                // when we have a fixed cell length it is possible to know with
-                // certainty the height of each TableCell - it is the fixed
-                // value
-                // provided by the developer, and this means that we do not have
-                // to concern ourselves with the possibility that the height
-                // may be variable and / or dynamic.
-//                isVisible = isColumnPartiallyOrFullyVisible(tableColumn);
-//            }
-
-            if (isVisible) {
-                if (/*fixedCellSizeProperty().get() > 0
-                        &&*/ tableCell.getParent() == null) {
-                    getChildren().add(0,tableCell);
-                }
-
-                final SpreadsheetView.SpanType spanType = grid.getSpanType(spreadsheetView, index, column);
-
-                switch (spanType) {
-                    case ROW_SPAN_INVISIBLE :
-                    case BOTH_INVISIBLE :
-                        tableCell.setOpacity(0);
-                        tableCell.resize(width, height);
-                        tableCell.relocate(x + tableCellX, snappedTopInset()
-                                + tableCellY);
-
-                        x += width;
-                        continue; // we don't want to fall through
-                    case COLUMN_SPAN_INVISIBLE :
-                        tableCell.setOpacity(0);
-                        tableCell.resize(width, height);
-                        tableCell.relocate(x + tableCellX, snappedTopInset()
-                                + tableCellY);
-                        continue; // we don't want to fall through
-                        // infact, we return to the loop here
-                    case ROW_VISIBLE :
-                        // To be sure that the text is the same
-                        // in case we modified the DataCell after that
-                        // SpreadsheetCell was created
-                        final TableViewSelectionModel<ObservableList<SpreadsheetCell<?>>> sm = spreadsheetView.getSelectionModel();
-                        final TableColumn<ObservableList<SpreadsheetCell<?>>, ?> col = tableView.getColumns().get(column);
-
-                        // In case this cell was selected before but we scroll
-                        // up/down and it's invisible now.
-                        // It has to pass his "selected property" to the new
-                        // Cell in charge of spanning
-                        final TablePosition<ObservableList<SpreadsheetCell<?>>, ?> selectedPosition = isSelectedRange(index, col, column);
-                        // If the selected cell is in the same row, no need to re-select it
-                        if (selectedPosition != null
-                                && selectedPosition.getRow() != index) {
-                            sm.clearSelection(selectedPosition.getRow(),
-                                    selectedPosition.getTableColumn());
-                            sm.select(index, col);
-                        }
-                    case NORMAL_CELL : // fall through and carry on
-                        tableCell.show();
-                }
-
-                if (cellSpan != null) {
-                    if (cellSpan.getColumnSpan() > 1) {
-                        // we need to span multiple columns, so we sum up
-                        // the width of the additional columns, adding it
-                        // to the width variable
-                        for (int i = 1, colSpan = cellSpan.getColumnSpan(), max1 = cells
-                                .size() - column; i < colSpan && i < max1; i++) {
-                            // calculate the width
-//                            final Node adjacentNode = (Node) getChildren().get(
-//                                    column + i);
-                            width += snapSize(spreadsheetView.getColumns().get(column+i).getWidth());//adjacentNode.maxWidth(-1));
-                        }
-                    }
-
-                    if (cellSpan.getRowSpan() > 1) {
-                        // we need to span multiple rows, so we sum up
-                        // the height of the additional rows, adding it
-                        // to the height variable