/**
* 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 java.util.Map;
import javax.swing.JComponent;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.rapidminer.core.io.data.DataSetException;
import com.rapidminer.core.io.gui.ImportWizard;
import com.rapidminer.core.io.gui.InvalidConfigurationException;
import com.rapidminer.core.io.gui.WizardDirection;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.operator.nio.model.ExcelResultSetConfiguration;
import com.rapidminer.operator.nio.model.xlsx.XlsxUtilities.XlsxCellCoordinates;
import com.rapidminer.studio.io.data.HeaderRowNotFoundException;
import com.rapidminer.studio.io.gui.internal.steps.AbstractWizardStep;
/**
* An {@link ImportWizardStep} which allows to select the Excel sheet and cell range to import.
*
* @author Nils Woehler
* @since 7.0.0
*/
final class ExcelSheetSelectionWizardStep extends AbstractWizardStep {
static final String EXCEL_SHEET_SELECTION_STEP_ID = "excel.sheet_selection";
private final ExcelSheetSelectionPanel workbookSelectionPanel;
private final ExcelDataSource excelDataSource;
private Map<String, String> enteringConfiguration;
private String enteringPath;
private boolean calculateMetaData = true;
private final ImportWizard wizard;
ExcelSheetSelectionWizardStep(ExcelDataSource excelDataSource, ImportWizard wizard) {
this.excelDataSource = excelDataSource;
this.wizard = wizard;
this.workbookSelectionPanel = new ExcelSheetSelectionPanel(excelDataSource);
this.workbookSelectionPanel.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
fireStateChanged();
}
});
}
@Override
public String getI18NKey() {
return EXCEL_SHEET_SELECTION_STEP_ID;
}
@Override
public JComponent getView() {
return workbookSelectionPanel;
}
@Override
public void validate() throws InvalidConfigurationException {
if (workbookSelectionPanel.isSheetEmpty() || workbookSelectionPanel.isSelectionEmpty()
|| workbookSelectionPanel.isUpdatingUI()) {
throw new InvalidConfigurationException();
}
// check whether header row is included in the data
int headerRowIndex = workbookSelectionPanel.getHeaderRowIndex();
if (headerRowIndex > workbookSelectionPanel.getSelection().getRowIndexEnd()) {
workbookSelectionPanel.notifyHeaderRowBehindStartRow();
throw new InvalidConfigurationException();
}
// in case only a column is specified we use the first row as start row
int rowIndexStart = workbookSelectionPanel.getSelection().getRowIndexStart();
if (rowIndexStart == XlsxCellCoordinates.NO_ROW_NUMBER) {
rowIndexStart = 0;
}
// check whether the header is behind or equal to the first data row
if (headerRowIndex > rowIndexStart) {
workbookSelectionPanel.notifyHeaderRowBehindStartRow();
throw new InvalidConfigurationException();
}
}
@Override
public void viewWillBecomeVisible(WizardDirection direction) throws InvalidConfigurationException {
wizard.setProgress(40);
/*
* If the users proceeds to this step from the file selection and changed the file we need
* to clear the cache. If he returns from the column configuration we can still use the old
* cache.
*/
if (direction == WizardDirection.NEXT && enteringPath != null
&& !enteringPath.equals(excelDataSource.getLocation().toString())) {
workbookSelectionPanel.clearCache();
}
// we need to update the model (and thus the UI) in any case though
workbookSelectionPanel.configureSheetSelectionModel(excelDataSource);
// remember configuration of the data source
enteringConfiguration = excelDataSource.getConfiguration().getParameters();
enteringPath = excelDataSource.getLocation().toString();
}
@Override
public void viewWillBecomeInvisible(WizardDirection direction) throws InvalidConfigurationException {
// ensure error bubble has been killed when leaving the step
workbookSelectionPanel.killCurrentBubbleWindow(null);
// only configure meta data in case the user proceeds to the next step
if (direction == WizardDirection.NEXT) {
// update configuration with content selection
CellRangeSelection selection = workbookSelectionPanel.getSelection();
ExcelResultSetConfiguration configuration = excelDataSource.getResultSetConfiguration();
// update the selected sheet
configuration.setSheet(workbookSelectionPanel.getSheetIndex());
// update the cell range selection
configuration.setColumnOffset(selection.getColumnIndexStart());
configuration.setColumnLast(selection.getColumnIndexEnd());
configuration.setRowOffset(selection.getRowIndexStart());
configuration.setRowLast(selection.getRowIndexEnd());
// update header row
excelDataSource.setHeaderRowIndex(workbookSelectionPanel.getHeaderRowIndex());
Map<String, String> currentConfiguration = excelDataSource.getConfiguration().getParameters();
if (calculateMetaData || !enteringConfiguration.equals(currentConfiguration)) {
// only calculate meta data if the configuration has changed, it has not been
// calculated before or the last calculation resulted in an error
try {
excelDataSource.createMetaData();
calculateMetaData = false;
} catch (HeaderRowNotFoundException e) {
calculateMetaData = true;
workbookSelectionPanel.notifyHeaderRowBehindStartRow();
throw new InvalidConfigurationException();
} catch (DataSetException e) {
calculateMetaData = true;
SwingTools.showSimpleErrorMessage(wizard.getDialog(),
"io.dataimport.step.excel.sheet_selection.read_failure", e, e.getMessage());
throw new InvalidConfigurationException();
}
}
}
}
@Override
public String getNextStepID() {
return ImportWizard.CONFIGURE_DATA_STEP_ID;
}
}