gt: 			if (isShowingPreview && wasModelLoaded) {
context: /**
   * Copyright (C) 2001-2017 by RapidMiner and the contributors
   * 
   * Complete list of developers available at our web site:
   * 
   * http://rapidminer.com
   * 
   * This program is free software: you can redistribute it and/or modify it under the terms of the
   * GNU Affero General Public License as published by the Free Software Foundation, either version 3
   * of the License, or (at your option) any later version.
   * 
   * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
   * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Affero General Public License for more details.
   * 
   * You should have received a copy of the GNU Affero General Public License along with this program.
   * If not, see http://www.gnu.org/licenses/.
  */
  package com.rapidminer.studio.io.data.internal.file.excel;
  
  import com.rapidminer.core.io.gui.InvalidConfigurationException;
  import com.rapidminer.gui.look.Colors;
  import com.rapidminer.gui.tools.*;
  import com.rapidminer.gui.tools.bubble.BubbleWindow;
  import com.rapidminer.gui.tools.bubble.BubbleWindow.AlignedSide;
  import com.rapidminer.gui.tools.bubble.BubbleWindow.BubbleStyle;
  import com.rapidminer.gui.tools.bubble.ComponentBubbleWindow;
  import com.rapidminer.operator.nio.model.xlsx.XlsxSheetMetaDataParser;
  import com.rapidminer.operator.nio.model.xlsx.XlsxUtilities;
  import com.rapidminer.operator.nio.model.xlsx.XlsxUtilities.XlsxCellCoordinates;
  import com.rapidminer.studio.io.data.internal.ResultSetAdapter;
  import com.rapidminer.studio.io.gui.internal.DataImportWizardUtils;
  import com.rapidminer.studio.io.gui.internal.DataWizardEventType;
  import com.rapidminer.tools.I18N;
  import com.rapidminer.tools.LogService;
  import com.rapidminer.tools.container.Pair;
  
  import javax.swing.*;
  import javax.swing.event.*;
  import javax.swing.table.DefaultTableCellRenderer;
  import javax.swing.table.TableModel;
  import java.awt.*;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.ItemEvent;
  import java.awt.event.ItemListener;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.logging.Level;
  
  
  /**
   * This is a panel showing the contents of a complete excel workbook. The user is able to select the
   * current sheet via a drop down menu.
   *
   * @author Nils Woehler
   * @since 7.0.0
   */
  final class ExcelSheetSelectionPanel extends JPanel {
  
  	private static final long serialVersionUID = 9179757216097316344L;
  
  	private static final Dimension CELL_TEXTFIELD_MIN_DIMENSION = new Dimension(50, 25);
  	private static final Dimension CELL_TEXTFIELD_PREF_DIMENSION = new Dimension(150, 25);
  
  	private static final Dimension CELL_CHECKBOX_MIN_DIMENSION = new Dimension(100, 25);
  
  	/** re-use same log timer for all data import wizard dialogs */
  	private static final Timer CELL_RANGE_TIMER = new Timer(500, null);
  
  	/**
  	 * Cell renderer for the content table.
  	 */
  	private final ColoredTableCellRenderer tableCellRenderer = new ColoredTableCellRenderer() {
  
  		private final DefaultTableCellRenderer defaultRenderer = new DefaultTableCellRenderer();
  		private final Font normalFont = defaultRenderer.getFont();
  		private final Font boldFont = defaultRenderer.getFont().deriveFont(Font.BOLD);
  
  		@Override
  		public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
  				int row, int column) {
  			Component rendererComponent = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
  					column);
  			try {
  				if (row == getHeaderRowIndex()) {
  					rendererComponent.setFont(boldFont);
  				} else {
  					rendererComponent.setFont(normalFont);
  				}
  			} catch (NumberFormatException e) {
  				rendererComponent.setFont(normalFont);
  			}
  
  			if (sheetSelectionModel.isShowingPreview()) {
  				try {
  					CellRangeSelection selection = getSelection();
  
  					// highlight preview cells as if they were selected if included in the selection
  					if (row >= selection.getRowIndexStart() && row <= selection.getRowIndexEnd()
  							&& column >= selection.getColumnIndexStart() && column <= selection.getColumnIndexEnd()) {
  						rendererComponent.setBackground(contentTable.getSelectionBackground());
  						rendererComponent.setForeground(contentTable.getSelectionForeground());
  					} else {
  						rendererComponent.setBackground(contentTable.getBackground());
  						rendererComponent.setForeground(contentTable.getForeground());
  					}
  				} catch (InvalidConfigurationException e) {
  					rendererComponent.setBackground(contentTable.getBackground());
  					rendererComponent.setForeground(contentTable.getForeground());
  				}
  			}
  			return rendererComponent;
  		}
  	};
  
  	/**
  	 * Selection listener which updates the sheet selection model in case of list selection events.
  	 */
  	private final ListSelectionListener selectionListener = new ListSelectionListener() {
  
  		@Override
  		public void valueChanged(ListSelectionEvent e) {
  			if (!e.getValueIsAdjusting() && !updatingUI) {
  				sheetSelectionModel.updateCellRangeByTableSelection(contentTable);
  			}
  		}
  	};
  
  	/**
  	 * Selection listener which updates the sheet selection model in case of column selection
  	 * events.
  	 */
  	private final TableColumnModelListener columnSelectionListener = new TableColumnModelListener() {
  
  		@Override
  		public void columnAdded(TableColumnModelEvent e) {}
  
  		@Override
  		public void columnRemoved(TableColumnModelEvent e) {}
  
  		@Override
  		public void columnMoved(TableColumnModelEvent e) {}
  
  		@Override
  		public void columnMarginChanged(ChangeEvent e) {}
  
  		@Override
  		public void columnSelectionChanged(ListSelectionEvent e) {
  			if (!e.getValueIsAdjusting() && !updatingUI) {
  				sheetSelectionModel.updateCellRangeByTableSelection(contentTable);
  			}
  		}
  
  	};
  
  	/**
  	 * Action which selects the whole sheet content.
  	 */
  	private final Action selectAllAction = new ResourceActionAdapter(false,
  			"io.dataimport.step.excel.sheet_selection.select_all") {
  
  		private static final long serialVersionUID = 1L;
  
  		@Override
  		public void actionPerformed(ActionEvent e) {
  			killCurrentBubbleWindow(null);
  
  			// create a new selection object
  			CellRangeSelection selection = new CellRangeSelection(0, XlsxCellCoordinates.NO_ROW_NUMBER,
  					contentTable.getModel().getColumnCount() - 1, XlsxSheetMetaDataParser.MAXIMUM_XLSX_ROW_INDEX);
  
  			// update the model (will trigger an UI update)
  			sheetSelectionModel.setCellRangeSelection(selection);
  		}
  	};
  
  	/**
  	 * Action to apply the selection entered into the cell range text field.
  	 */
  	private final Action applySelectionAction = new ResourceActionAdapter(false,
  			"io.dataimport.step.excel.sheet_selection.apply_cell_selection") {
  
  		private static final long serialVersionUID = 1L;
  
  		@Override
  		public synchronized void actionPerformed(ActionEvent e) {
  			applyTextFieldSelection(true);
  		}
  
  	};
  
  	/**
  	 * Item listener that acts in case the sheet has been changed.
  	 */
  	private final ItemListener comboBoxItemListener = new ItemListener() {
  
  		@Override
  		public void itemStateChanged(ItemEvent e) {
  			if (e.getStateChange() == ItemEvent.SELECTED) {
  				if (!updatingUI) {
  					int newSheetIndex = sheetComboBox.getSelectedIndex();
  					sheetSelectionModel.setSheetIndex(newSheetIndex);
  				}
  			}
  		}
  	};
  
  	/**
  	 * Observer that watches the {@link ExcelSheetSelectionPanelModel} and updates the UI on
  	 * changes.
  	 */
  	private final ExcelSheetSelectionModelListener sheetSelectionModelListener = new ExcelSheetSelectionModelListener() {
  
  		@Override
  		public void loadingNewTableModel() {
  			SwingTools.invokeAndWait(new Runnable() {
  
  				@Override
  				public void run() {
  					updatingUI = true;
  					showNotificationLabel("io.dataimport.step.excel.sheet_selection.loading_excel_sheets");
  					fireStateChanged();
  					updatingUI = false;
  				}
  			});
  		}
  
  		@Override
  		public void reportErrorLoadingTableModel(final Exception e) {
  			SwingTools.invokeAndWait(new Runnable() {
  
  				@Override
  				public void run() {
  					showNotificationLabel("io.dataimport.step.excel.sheet_selection.error_loading_excel_sheet",
  							e.getMessage());
  					fireStateChanged();
  				}
  			});
  		}
  
  		@Override
  		public void sheetIndexUpdated(final int newSheetIndex, final String[] sheetNames, final TableModel tableModel,
  				final boolean isShowingPreview, final boolean wasModelLoaded) {
  
  			updatingUI = true;
  
  			SwingTools.invokeAndWait(new Runnable() {
  
  				@Override
  				public void run() {
  					fireStateChanged();
  					updateTableModel(tableModel, isShowingPreview, wasModelLoaded, sheetNames, newSheetIndex);
  				}
  			});
  
  			updatingUI = false;
  
  			fireStateChanged();
  
  		}
  
  		@Override
  		public void headerRowIndexUpdated(final int newHeaderRowIndex) {
  			updatingUI = true;
  
  			SwingTools.invokeAndWait(new Runnable() {
  
  				@Override
  				public void run() {
  					boolean hasHeaderRow = newHeaderRowIndex > ResultSetAdapter.NO_HEADER_ROW;
  					int displayedHeaderRowIndex = hasHeaderRow ? newHeaderRowIndex + 1 : 1;
  					headerRowSpinner.setModel(new SpinnerNumberModel(displayedHeaderRowIndex, 1, Integer.MAX_VALUE, 1));
  					hasHeaderRowCheckBox.setSelected(hasHeaderRow);
  					killCurrentBubbleWindow(headerRowSpinner);
  
  					contentTable.revalidate();
  					contentTable.repaint();
  				}
  			});
  
  			updatingUI = false;
  
  			fireStateChanged();
  		}
  
  		@Override
  		public void cellRangeSelectionUpdate(final CellRangeSelection newSelection) {
  			updatingUI = true;
  
  			SwingTools.invokeAndWait(new Runnable() {
  
  				@Override
  				public void run() {
  					if (newSelection == null) {
  						contentTable.clearSelection();
  						return;
  					}
  
  					// column indices
  					int columnStartIndex = Math.max(newSelection.getColumnIndexStart(), 0);
  					int columnEndIndex = Math.min(newSelection.getColumnIndexEnd(),
  							isSheetEmpty() ? 0 : contentTable.getColumnCount() - 1);
  
  					// row indices
  					int firstSelectedRow = newSelection.getRowIndexStart();
  					int lastSelectedRow = newSelection.getRowIndexEnd();
  
  					if (sheetSelectionModel.isShowingPreview()) {
  						// Only update the text field when showing a preview
  						updateCellRangeTextFields(columnStartIndex, firstSelectedRow, columnEndIndex, lastSelectedRow);
  					} else {
  
  						if (!isSheetEmpty()) {
  							contentTable.clearSelection();
  
  							int tableRowCount = isSheetEmpty() ? 0 : contentTable.getRowCount() - 1;
  							int lastSelectedTableRow = Math.min(newSelection.getRowIndexEnd(), tableRowCount);
  
  							// no row number means we start with first row for table selection
  							int firstSelectedTableRow = firstSelectedRow == XlsxCellCoordinates.NO_ROW_NUMBER ? 0
  									: firstSelectedRow;
  
  							// update the table selection
  							contentTable.setColumnSelectionInterval(columnStartIndex, columnEndIndex);
  							contentTable.setRowSelectionInterval(firstSelectedTableRow, lastSelectedTableRow);
  
  							// update the text field
  							updateCellRangeTextFields(columnStartIndex, firstSelectedRow, columnEndIndex, lastSelectedRow);
  						}
  
  					}
  
  				}
  			});
  
  			updatingUI = false;
  
  			fireStateChanged();
  
  			contentTable.revalidate();
  			contentTable.repaint();
  		}
  
  		private void updateTableModel(TableModel selectedModel, boolean isShowingPreview, boolean wasModelLoaded,
  				String[] sheetNames, int sheetIndex) {
  
  			final GridBagConstraints constraint = new GridBagConstraints();
  			constraint.fill = GridBagConstraints.BOTH;
  			constraint.weightx = 1.0;
  			constraint.weighty = 1.0;
  
  			// create a new table
  			contentTable = new ExtendedJTable(false, false, false) {
  
  				private static final long serialVersionUID = 1L;
  
  				@Override
  				public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
  					/*
  					 * Overwrite selection change event for the sheet table to disable partial
  					 * selection changing with CTRL + click.
  					 */
  					if (toggle && !extend) {
  						return;
  					}
  					super.changeSelection(rowIndex, columnIndex, toggle, extend);
  				};
  			};
  
  			// ensure same background as JPanels in case of only few rows
  			contentTable.setBackground(Colors.PANEL_BACKGROUND);
  
  			contentTable.setGridColor(Colors.TAB_BORDER);
  			contentTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
  			contentTable.setBorder(null);
  			contentTable.getSelectionModel().addListSelectionListener(selectionListener);
  			contentTable.getColumnModel().addColumnModelListener(columnSelectionListener);
  
  			// only allow selection in case no preview is shown
  			contentTable.setRowSelectionAllowed(!isShowingPreview);
  			contentTable.setColumnSelectionAllowed(!isShowingPreview);
  			contentTable.setCellSelectionEnabled(!isShowingPreview);
  
  			contentTable.setShowPopupMenu(false);
  			contentTable.setSortable(false);
  			contentTable.getTableHeader().setReorderingAllowed(false);
  			contentTable.setColoredTableCellRenderer(tableCellRenderer);
  			contentTable.setEnabled(!isShowingPreview);
  
  			// update table model
  			contentTable.setModel(selectedModel);
  
  			// update combo box content
  			sheetComboBox.setModel(new DefaultComboBoxModel<String>(sheetNames));
  			sheetComboBox.setSelectedIndex(sheetIndex);
  
  			// add content table again
  			centerPanel.removeAll();
  
  			/*
  			 * Hack to enlarge table columns in case of few columns. Add table to a full size JPanel
  			 * and add the table header to the scroll pane.
  			 */
  			JPanel tablePanel = new JPanel(new BorderLayout());
  			tablePanel.add(contentTable, BorderLayout.CENTER);
  
  			JScrollPane scrollPane = new ExtendedJScrollPane(tablePanel);
  			scrollPane.setColumnHeaderView(contentTable.getTableHeader());
  
  			// Add scroll panel and table
  			scrollPane.setRowHeaderView(new RowNumberTable(contentTable));
  			scrollPane.setBorder(null);
  
  			if (isShowingPreview) {
  				// Create a layered pane to display both, the data table and a
  				// "preview" overlay
  				JLayeredPane layeredPane = new JLayeredPane();
  				layeredPane.setLayout(new OverlayLayout(layeredPane));
  
  				// add scroll pane
  				layeredPane.add(scrollPane, JLayeredPane.DEFAULT_LAYER);
  
  				// Add "Preview" overlay
  				JPanel previewPanel = new JPanel(new BorderLayout());
  				previewPanel.setOpaque(false);
  				JLabel previewLabel = new JLabel(I18N.getGUILabel("csv_format_specification.preview_background"),
  						SwingConstants.CENTER);
  				previewLabel.setFont(previewLabel.getFont().deriveFont(Font.BOLD, 180));
  				previewLabel.setForeground(DataImportWizardUtils.getPreviewFontColor());
  				previewPanel.add(previewLabel, BorderLayout.CENTER);
  
  				layeredPane.add(previewPanel, JLayeredPane.PALETTE_LAYER);
  
  				centerPanel.add(layeredPane, constraint);
  			} else {
  				// display plain scroll pane
  				centerPanel.add(scrollPane, constraint);
  			}
  
  			/*
  			 * one last check whether the selected sheet is empty
  			 */
  			if (isSheetEmpty()) {
  				showNotificationLabel("io.dataimport.step.excel.sheet_selection.empty_sheet");
  
  				// even though the sheet is empty the user should still be able
  				// to
  				// select another sheet
  				sheetComboBox.setEnabled(true);
  			} else {
  				// enable all header actions
  				enableHeaderActions(true);
  			}
  
  			/*
  			 * Show an information bubble in case the modal was loaded the first time and only a
  			 * preview is shown.
  			 */
  