/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.commons.cismap.io; import org.apache.log4j.Logger; import org.openide.WizardDescriptor; import org.openide.WizardDescriptor.FinishablePanel; import org.openide.util.NbBundle; import java.awt.Component; import java.awt.EventQueue; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import javax.swing.SwingWorker; import de.cismet.cismap.commons.Crs; import de.cismet.commons.concurrency.CismetConcurrency; import de.cismet.commons.concurrency.CismetExecutors; import de.cismet.commons.converter.Converter; import de.cismet.commons.converter.Converter.MatchRating; import de.cismet.commons.gui.wizard.AbstractWizardPanel; import de.cismet.commons.gui.wizard.converter.ConverterPreselectionMode; /** * DOCUMENT ME! * * @author martin.scholl@cismet.de * @version 1.0 */ public final class AddGeometriesToMapEnterDataWizardPanel extends AbstractWizardPanel implements FinishablePanel { //~ Static fields/initializers --------------------------------------------- /** LOGGER. */ private static final transient Logger LOG = Logger.getLogger(AddGeometriesToMapEnterDataWizardPanel.class); public static final String PROP_COORDINATE_DATA = "__prop_coordinate_data__"; // NOI18N //~ Instance fields -------------------------------------------------------- private final transient ExecutorService dispatcher; private final transient ThreadFactory threadFactory; private final transient PropertyChangeSupport propCSupport; // -- properties private transient File inputFile; private transient String coordinateData; private transient String crsName; private transient Converter selectedConverter; private transient ConverterPreselectionMode converterPreselectionMode; // -- properties private transient List<Converter> availableConverters; private transient ScheduledExecutorService detectorExecutor; private transient ScheduledFuture<?> currentDetectorTask; //~ Constructors ----------------------------------------------------------- /** * Creates a new AddGeometriesToMapEnterDataWizardPanel object. */ public AddGeometriesToMapEnterDataWizardPanel() { threadFactory = CismetConcurrency.getInstance("cismap-commons") // NOI18N .createThreadFactory("AddGeometriesToMapEnterDataWizardPanel-threadfactory"); // NOI18N dispatcher = CismetExecutors.newSingleThreadExecutor(threadFactory); propCSupport = new PropertyChangeSupport(this); } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public File getInputFile() { return inputFile; } /** * Sets the inputfile and reads it. if it is a valid file it sets the coordinate data accordingly. * * @param inputFile the input file to read from */ public void setInputFile(final File inputFile) { final File oldData = this.inputFile; this.inputFile = inputFile; changeSupport.fireChange(); propCSupport.firePropertyChange("inputFile", oldData, this.inputFile); // NOI18N processInputFile(inputFile); } /** * DOCUMENT ME! * * @param inputFile DOCUMENT ME! * * @throws IllegalStateException DOCUMENT ME! */ private void processInputFile(final File inputFile) { dispatcher.execute(new SwingWorker<String, Void>() { @Override protected String doInBackground() throws Exception { Thread.currentThread().setName("AddGeometriesToMapEnterDataWizardPanel processInputFile()"); if (inputFile != null) { if (inputFile.isFile() && inputFile.canRead()) { BufferedReader fileReader = null; try { // possible encoding issues fileReader = new BufferedReader(new FileReader(inputFile)); final StringBuilder sb = new StringBuilder(); String line; while ((line = fileReader.readLine()) != null) { sb.append(line).append('\n'); } if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } catch (final FileNotFoundException ex) { throw new IllegalStateException( "file was present and readable, but now is not anymore: " + inputFile, ex); // NOI18N } catch (final IOException ex) { LOG.warn("cannot read input file", ex); // NOI18N } finally { if (fileReader != null) { try { fileReader.close(); } catch (final IOException ex) { LOG.warn("cannot close input file: " + inputFile, ex); // NOI18N } } } } } return null; } @Override protected void done() { try { final String fileData = get(300, TimeUnit.MILLISECONDS); if (fileData != null) { setCoordinateData(fileData); } } catch (final Exception ex) { LOG.warn("cannot fetch result data from worker", ex); // NOI18N } } }); } /** * DOCUMENT ME! * * @param pcl DOCUMENT ME! */ public void addPropertyChangeListener(final PropertyChangeListener pcl) { propCSupport.addPropertyChangeListener(pcl); } /** * DOCUMENT ME! * * @param property DOCUMENT ME! * @param pcl DOCUMENT ME! */ public void addPropertyChangeListener(final String property, final PropertyChangeListener pcl) { propCSupport.addPropertyChangeListener(property, pcl); } /** * DOCUMENT ME! * * @param pcl DOCUMENT ME! */ public void removePropertyChangeListener(final PropertyChangeListener pcl) { propCSupport.removePropertyChangeListener(pcl); } /** * DOCUMENT ME! * * @param property DOCUMENT ME! * @param pcl DOCUMENT ME! */ public void removePropertyChangeListener(final String property, final PropertyChangeListener pcl) { propCSupport.removePropertyChangeListener(property, pcl); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public String getCoordinateData() { return coordinateData; } /** * DOCUMENT ME! * * @param coordinateData DOCUMENT ME! */ public void setCoordinateData(final String coordinateData) { final String oldData = this.coordinateData; this.coordinateData = coordinateData; changeSupport.fireChange(); propCSupport.firePropertyChange("coordinateData", oldData, this.coordinateData); // NOI18N if (ConverterPreselectionMode.AUTO_DETECT == converterPreselectionMode) { detectFormat(); } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public String getCrsName() { return crsName; } /** * DOCUMENT ME! * * @param crsName DOCUMENT ME! */ public void setCrsName(final String crsName) { final String oldData = this.crsName; this.crsName = crsName; changeSupport.fireChange(); propCSupport.firePropertyChange("crsName", oldData, this.crsName); // NOI18N } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public Converter getSelectedConverter() { return selectedConverter; } /** * DOCUMENT ME! * * @param selectedConverter DOCUMENT ME! */ public void setSelectedConverter(final Converter selectedConverter) { final Converter oldData = this.selectedConverter; this.selectedConverter = selectedConverter; changeSupport.fireChange(); propCSupport.firePropertyChange("selectedConverter", oldData, this.selectedConverter); // NOI18N } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public ConverterPreselectionMode getConverterPreselectionMode() { return converterPreselectionMode; } /** * DOCUMENT ME! * * @param converterPreselectionMode DOCUMENT ME! */ public void setConverterPreselectionMode(final ConverterPreselectionMode converterPreselectionMode) { final ConverterPreselectionMode oldData = this.converterPreselectionMode; this.converterPreselectionMode = converterPreselectionMode; changeSupport.fireChange(); propCSupport.firePropertyChange("converterPreselectionMode", oldData, this.converterPreselectionMode); // NOI18N } @Override public boolean isValid() { if ((coordinateData == null) || coordinateData.isEmpty()) { wizard.putProperty( WizardDescriptor.PROP_INFO_MESSAGE, NbBundle.getMessage( AddGeometriesToMapEnterDataWizardPanel.class, "AddGeometriesToMapEnterDataWizardPanel.isValid().infoMessage.enterCoordinateData")); // NOI18N return false; } else { wizard.putProperty( WizardDescriptor.PROP_INFO_MESSAGE, NbBundle.getMessage( AddGeometriesToMapEnterDataWizardPanel.class, "AddGeometriesToMapEnterDataWizardPanel.isValid().infoMessage.proceed")); // NOI18N return true; } } /** * DOCUMENT ME! */ private void detectFormat() { // EDT only if (currentDetectorTask != null) { currentDetectorTask.cancel(true); } final Runnable task = new DetectConverterTask(); currentDetectorTask = detectorExecutor.schedule(task, 300, TimeUnit.MILLISECONDS); } @Override protected Component createComponent() { return new AddGeometriesToMapEnterDataVisualPanel(this); } @Override @SuppressWarnings("unchecked") protected void read(final WizardDescriptor wizard) { // initialise first so that setters work correctly when using auto detect mode setConverterPreselectionMode((ConverterPreselectionMode)wizard.getProperty( AddGeometriesToMapWizardAction.PROP_CONVERTER_PRESELECT_MODE)); if (ConverterPreselectionMode.AUTO_DETECT == converterPreselectionMode) { availableConverters = (List<Converter>)wizard.getProperty( AddGeometriesToMapWizardAction.PROP_AVAILABLE_CONVERTERS); detectorExecutor = Executors.newSingleThreadScheduledExecutor(threadFactory); } setCoordinateData((String)wizard.getProperty(PROP_COORDINATE_DATA)); setInputFile((File)wizard.getProperty(AddGeometriesToMapWizardAction.PROP_INPUT_FILE)); setCrsName(((Crs)wizard.getProperty(AddGeometriesToMapWizardAction.PROP_CURRENT_CRS)).getShortname()); setSelectedConverter((Converter)wizard.getProperty( AddGeometriesToMapChooseConverterWizardPanel.PROP_CONVERTER)); } @Override protected void store(final WizardDescriptor wizard) { wizard.putProperty(PROP_COORDINATE_DATA, coordinateData); wizard.putProperty(AddGeometriesToMapChooseConverterWizardPanel.PROP_CONVERTER, selectedConverter); // we do not save the input file that has probably been choosen so that any manual alteration of the file // content is preserved and not overridden again through the input file wizard.putProperty(AddGeometriesToMapWizardAction.PROP_INPUT_FILE, null); availableConverters = null; if (detectorExecutor != null) { detectorExecutor.shutdownNow(); detectorExecutor = null; } } @Override public boolean isFinishPanel() { return selectedConverter != null; } //~ Inner Classes ---------------------------------------------------------- /** * DOCUMENT ME! * * @version $Revision$, $Date$ */ private final class DetectConverterTask implements Runnable { //~ Methods ------------------------------------------------------------ @Override public void run() { Converter highScoreConverter = null; int highScoreConverterRating = 0; for (final Converter converter : availableConverters) { if (Thread.currentThread().isInterrupted()) { return; } if (converter instanceof Converter.MatchRating) { final MatchRating matchRating = (MatchRating)converter; @SuppressWarnings("unchecked") final int converterRating = matchRating.rate( getCoordinateData(), ((Crs)wizard.getProperty(AddGeometriesToMapWizardAction.PROP_CURRENT_CRS)).getCode()); if (converterRating > highScoreConverterRating) { highScoreConverterRating = converterRating; highScoreConverter = converter; } } } final Converter detectedConverter = highScoreConverter; if (Thread.currentThread().isInterrupted()) { return; } EventQueue.invokeLater(new Runnable() { @Override public void run() { setSelectedConverter(detectedConverter); } }); } } }