commit 661914bed4382c67f7aaf93967dad6a5f69dd802
Author: b.stoever <stoever@bioinfweb.info>
Date:   Wed Nov 16 21:25:30 2016 +0100

    Intermediate commit in implementing wizard validation (before moving to MultiValidator).
    Plug-in dependencies added to molecular.

diff --git a/eu.etaxonomy.taxeditor.molecular/META-INF/MANIFEST.MF b/eu.etaxonomy.taxeditor.molecular/META-INF/MANIFEST.MF
index 2ad5bf685..ec1008f47 100644
--- a/eu.etaxonomy.taxeditor.molecular/META-INF/MANIFEST.MF
+++ b/eu.etaxonomy.taxeditor.molecular/META-INF/MANIFEST.MF
@@ -12,7 +12,11 @@ Require-Bundle: org.eclipse.ui,
  eu.etaxonomy.taxeditor.cdmlib,
  eu.etaxonomy.taxeditor.editor,
  eu.etaxonomy.taxeditor.store,
- eu.etaxonomy.taxeditor.molecular.lib
+ eu.etaxonomy.taxeditor.molecular.lib,
+ org.eclipse.core.databinding.observable;bundle-version="1.4.0",
+ org.eclipse.core.databinding;bundle-version="1.4.0",
+ org.eclipse.jface.databinding;bundle-version="1.5.0",
+ org.eclipse.core.databinding.property;bundle-version="1.4.0"
 Bundle-RequiredExecutionEnvironment: JavaSE-1.7
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: EDIT
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/ExportSequenceToFileHandler.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/ExportSequenceToFileHandler.java
index 719a8cba3..6a07ae8b6 100644
--- a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/ExportSequenceToFileHandler.java
+++ b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/ExportSequenceToFileHandler.java
@@ -17,6 +17,7 @@ import info.bioinfweb.jphyloio.dataadapters.implementations.ListBasedDocumentDat
 import info.bioinfweb.jphyloio.factory.JPhyloIOReaderWriterFactory;
 import info.bioinfweb.jphyloio.objecttranslation.ObjectTranslatorFactory;
 
+import java.io.File;
 import java.io.IOException;
 
 import org.eclipse.core.commands.AbstractHandler;
@@ -68,19 +69,20 @@ public class ExportSequenceToFileHandler extends AbstractHandler {
                 parameters.put(ReadWriteParameterNames.KEY_OBJECT_TRANSLATOR_FACTORY, translatorFactory);
 
                 // Create writer and document adapters:
-                JPhyloIOEventWriter writer = factory.getWriter(wizard.getSelectedFormat().getFormatID());
+                JPhyloIOEventWriter writer = factory.getWriter(wizard.getModel().getFormatInfo().getFormatID());
                 ListBasedDocumentDataAdapter document = new ListBasedDocumentDataAdapter();
-                document.getMatrices().add(new CDMSequenceMatrixAdapter(sequence, wizard.getConsensusSequenceLabel()));
+                document.getMatrices().add(new CDMSequenceMatrixAdapter(sequence, wizard.getModel().getConsensusSequenceLabel()));
 
                 // Write document:
+                File file = new File(wizard.getModel().getFileName());
                 try {
-                    writer.writeDocument(document, wizard.getSelectedFile(), parameters);
+                    writer.writeDocument(document, file, parameters);
                 }
                 catch (IOException e) {
                     e.printStackTrace();
                     MessagingUtils.errorDialog("IO error", this,
                             "An error occured when trying to export a consensus sequence alignment to the file \"" +
-                            wizard.getSelectedFile().getAbsolutePath() + "\".", TaxeditorMolecularPlugin.PLUGIN_ID, e, false);  //TODO set pluginID
+                            file.getAbsolutePath() + "\".", TaxeditorMolecularPlugin.PLUGIN_ID, e, false);  //TODO set pluginID
                             //TODO Use multi language error message.
                 }
             }
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ConsensusSequenceLabelValidator.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ConsensusSequenceLabelValidator.java
new file mode 100644
index 000000000..2c41a2860
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ConsensusSequenceLabelValidator.java
@@ -0,0 +1,66 @@
+/**
+* Copyright (C) 2016 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.molecular.io.wizard;
+
+
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.widgets.Button;
+
+
+
+/**
+ * Validator to make sure a non-empty consensus sequence name is provided. It must be registered as a selection listener
+ * of the export consensus sequence check box of the wizard page in order to work properly.
+ *
+ * @author Ben Stöver
+ * @date 16.11.2016
+ */
+public class ConsensusSequenceLabelValidator extends SelectionAdapter implements IValidator {
+    private boolean exportConsensusSequence = true;
+    private ISWTObservableValue checkBoxObersable;
+
+
+    public ConsensusSequenceLabelValidator(ISWTObservableValue checkBoxObersable) {
+        super();
+        this.checkBoxObersable = checkBoxObersable;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IStatus validate(Object value) {
+        if (exportConsensusSequence && ((value == null) || ((String)value).isEmpty())) {
+            return ValidationStatus.error("The consensus sequence label must not be empty.");  //TODO multi language
+        }
+        else {
+            return ValidationStatus.ok();
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void widgetSelected(SelectionEvent event) {
+        exportConsensusSequence = ((Button)event.getSource()).getSelection();
+
+        // Trigger validation of label:
+        Object value = checkBoxObersable.getValue();
+        checkBoxObersable.setValue("");
+        checkBoxObersable.setValue(value);
+    }
+}
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentValidator.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentValidator.java
new file mode 100644
index 000000000..b382879a9
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentValidator.java
@@ -0,0 +1,30 @@
+/**
+* Copyright (C) 2016 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.molecular.io.wizard;
+
+import org.eclipse.core.databinding.validation.MultiValidator;
+import org.eclipse.core.runtime.IStatus;
+
+
+
+/**
+ * @author bstoe_01
+ * @date 16.11.2016
+ *
+ */
+public class ExportSingleReadAlignmentValidator extends MultiValidator {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected IStatus validate() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+}
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizard.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizard.java
index 93532881f..5175fe4ee 100644
--- a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizard.java
+++ b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizard.java
@@ -10,10 +10,6 @@
 package eu.etaxonomy.taxeditor.molecular.io.wizard;
 
 
-import info.bioinfweb.jphyloio.formatinfo.JPhyloIOFormatInfo;
-
-import java.io.File;
-
 import org.eclipse.jface.wizard.Wizard;
 
 
@@ -25,15 +21,18 @@ import org.eclipse.jface.wizard.Wizard;
  * @date 23.06.2016
  */
 public class ExportSingleReadAlignmentWizard extends Wizard {
-    private ExportSingleReadAlignmentWizardPage page;
+    private ExportSingleReadAlignmentWizardModel model = new ExportSingleReadAlignmentWizardModel();
 
-    private JPhyloIOFormatInfo selectedFormat = null;
-    private File selectedFile = null;
-    private String consensusSequenceLabel = null;
+    private ExportSingleReadAlignmentWizardPage page;
 
 
     public ExportSingleReadAlignmentWizard() {
-        setWindowTitle("Export single read alignment");  //TODO Use multi languange message
+        setWindowTitle("Export single read alignment");  //TODO Use multi language message
+    }
+
+
+    public ExportSingleReadAlignmentWizardModel getModel() {
+        return model;
     }
 
 
@@ -46,29 +45,7 @@ public class ExportSingleReadAlignmentWizard extends Wizard {
 
     @Override
     public boolean performFinish() {
-        if (!page.getConsensusSequenceLabel().isEmpty()) {
-            selectedFormat = page.getSelectedFormat();
-            selectedFile = page.getSelectedFile();
-            consensusSequenceLabel = page.getConsensusSequenceLabel();
-            return true;
-        }
-        else {
-            return false;  //TODO Display according error message in wizard heading, as long as valid inputs are not completed.
-        }
-    }
-
-
-    public JPhyloIOFormatInfo getSelectedFormat() {
-        return selectedFormat;
-    }
-
-
-    public File getSelectedFile() {
-        return selectedFile;
-    }
-
-
-    public String getConsensusSequenceLabel() {
-        return consensusSequenceLabel;
+        return true;
+        //TODO Add default extension to file, if necessary?
     }
 }
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizardModel.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizardModel.java
new file mode 100644
index 000000000..7fa09c99c
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizardModel.java
@@ -0,0 +1,81 @@
+/**
+* Copyright (C) 2016 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.molecular.io.wizard;
+
+
+import info.bioinfweb.jphyloio.formatinfo.JPhyloIOFormatInfo;
+
+import org.eclipse.core.databinding.observable.value.IObservableValue;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+
+
+
+/**
+ * The data model for a wizard to export single read alignments to different file formats using <i>JPhyloIO</i>.
+ *
+ * @author Ben Stöver
+ * @date 16.11.2016
+ */
+public class ExportSingleReadAlignmentWizardModel {
+    private IObservableValue exportSingleReads = new WritableValue(null, Boolean.class);
+    private IObservableValue exportConsensusSequence = new WritableValue(null, Boolean.class);
+    private IObservableValue consensusSequenceLabel = new WritableValue(null, String.class);
+    private IObservableValue formatInfo = new WritableValue(null, JPhyloIOFormatInfo.class);
+    private IObservableValue fileName = new WritableValue(null, String.class);
+
+
+    public boolean isExportSingleReads() {
+        return (Boolean)exportSingleReads.getValue();
+    }
+
+
+    protected IObservableValue getExportSingleReadsObservable() {
+        return exportSingleReads;
+    }
+
+
+    public boolean isExportConsensusSequence() {
+        return (Boolean)exportConsensusSequence.getValue();
+    }
+
+
+    protected IObservableValue getExportConsensusSequenceObservable() {
+        return exportConsensusSequence;
+    }
+
+
+    public String getConsensusSequenceLabel() {
+        return (String)consensusSequenceLabel.getValue();
+    }
+
+
+    protected IObservableValue getConsensusSequenceLabelObservable() {
+        return consensusSequenceLabel;
+    }
+
+
+    public JPhyloIOFormatInfo getFormatInfo() {
+        return (JPhyloIOFormatInfo)formatInfo.getValue();
+    }
+
+
+    protected IObservableValue getFormatInfoObservable() {
+        return formatInfo;
+    }
+
+
+    public String getFileName() {
+        return (String)fileName.getValue();
+    }
+
+
+    protected IObservableValue getFileNameObservable() {
+        return fileName;
+    }
+}
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizardPage.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizardPage.java
index 9cae26f52..0c9648f50 100644
--- a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizardPage.java
+++ b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/ExportSingleReadAlignmentWizardPage.java
@@ -15,11 +15,15 @@ import info.bioinfweb.jphyloio.events.type.EventContentType;
 import info.bioinfweb.jphyloio.factory.JPhyloIOReaderWriterFactory;
 import info.bioinfweb.jphyloio.formatinfo.JPhyloIOFormatInfo;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.jface.databinding.swt.ISWTObservableValue;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.databinding.wizard.WizardPageSupport;
 import org.eclipse.jface.wizard.WizardPage;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.SelectionAdapter;
@@ -82,6 +86,9 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
      */
     @Override
     public void createControl(Composite parent) {
+        DataBindingContext dbc = new DataBindingContext();
+        WizardPageSupport.create(this, dbc);
+
         Composite container = new Composite(parent, SWT.NULL);
 
         setControl(container);
@@ -93,6 +100,8 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
         fd_exportSingleReadsCB.left = new FormAttachment(0, 10);
         exportSingleReadsCB.setLayoutData(fd_exportSingleReadsCB);
         exportSingleReadsCB.setText("Export single reads");
+        dbc.bindValue(SWTObservables.observeSelection(exportSingleReadsCB),
+                ((ExportSingleReadAlignmentWizard)getWizard()).getModel().getExportSingleReadsObservable());
 
         exportConsensusSequenceCB = new Button(container, SWT.CHECK);
         exportConsensusSequenceCB.setSelection(true);
@@ -107,6 +116,14 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
         fd_exportConsensusSequenceCB.left = new FormAttachment(0, 10);
         exportConsensusSequenceCB.setLayoutData(fd_exportConsensusSequenceCB);
         exportConsensusSequenceCB.setText("Export consensus sequence");
+        ISWTObservableValue exportConsensusSequenceObservable = SWTObservables.observeSelection(exportConsensusSequenceCB);
+        dbc.bindValue(exportConsensusSequenceObservable,
+                ((ExportSingleReadAlignmentWizard)getWizard()).getModel().getExportConsensusSequenceObservable());
+
+        // Connect validation of check box and text field for consensus sequence label:
+        ConsensusSequenceLabelValidator consensusSequenceLabelValidator =
+                new ConsensusSequenceLabelValidator(exportConsensusSequenceObservable);
+        exportConsensusSequenceCB.addSelectionListener(consensusSequenceLabelValidator);
 
         consensusSequenceNameTextField = new Text(container, SWT.BORDER);
         consensusSequenceNameTextField.setText("ConsensusSequence");
@@ -116,6 +133,9 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
         fd_consensusSequenceNameTextField.top = new FormAttachment(exportConsensusSequenceCB, 6);
         fd_consensusSequenceNameTextField.bottom = new FormAttachment(30, 26);
         consensusSequenceNameTextField.setLayoutData(fd_consensusSequenceNameTextField);
+        dbc.bindValue(SWTObservables.observeText(consensusSequenceNameTextField, SWT.Modify),  // WidgetProperties.text().observe(consensusSequenceNameTextField) does not perform a refresh, although SWTObservables seems to be deprecated.
+                ((ExportSingleReadAlignmentWizard)getWizard()).getModel().getConsensusSequenceLabelObservable(),
+                new UpdateValueStrategy().setAfterConvertValidator(consensusSequenceLabelValidator), null);
 
         Label lblFormat = new Label(container, SWT.NONE);
         FormData fd_lblFormat = new FormData();
@@ -151,6 +171,9 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
         fd_text.left = new FormAttachment(lblAlignmentFile, 6);
         fd_text.top = new FormAttachment(lblSelectTheExport, 6);
         fileTextField.setLayoutData(fd_text);
+        dbc.bindValue(SWTObservables.observeText(fileTextField, SWT.Modify),
+                ((ExportSingleReadAlignmentWizard)getWizard()).getModel().getFileNameObservable(),
+                new UpdateValueStrategy().setAfterConvertValidator(new FileNameValidator()), null);
 
         Button btnBrowse = new Button(container, SWT.NONE);
         btnBrowse.addSelectionListener(new SelectionAdapter() {
@@ -158,7 +181,6 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
             public void widgetSelected(SelectionEvent e) {
                 FileDialog dialog = new FileDialog(getShell(), SWT.OPEN);
                 dialog.setText("Export to");  //TODO Make multi language
-                //fd.setFilterPath("C:/");
                 ContentExtensionFileFilter filter = getSelectedFormat().createFileFilter();
                 dialog.setFilterExtensions(new String[]{filter.getExtensionsAsString()});
                 dialog.setFilterNames(new String[]{filter.getDescription()});
@@ -166,7 +188,6 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
                 if (selectedFile != null) {  // Otherwise selecting was canceled.
                     fileTextField.setText(selectedFile);
                 }
-                //TODO Add default extension, if necessary.
             }
         });
         fd_text.right = new FormAttachment(100, -134);
@@ -181,6 +202,7 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
         for (JPhyloIOFormatInfo formatInfo : FORMATS) {
             formatComboBox.add(formatInfo.getFormatName());
         }
+        //TODO Bind property and somehow handle translation. (Or use model view combo box from JFace.)
 
         FormData fd_formatComboBox = new FormData();
         fd_formatComboBox.right = new FormAttachment(consensusSequenceNameTextField, 0, SWT.RIGHT);
@@ -196,7 +218,7 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
      *
      * @return the format info or {@code null}, if none was yet selected
      */
-    public JPhyloIOFormatInfo getSelectedFormat() {
+    private JPhyloIOFormatInfo getSelectedFormat() {
         if (formatComboBox != null) {
             int index = formatComboBox.getSelectionIndex();
             if (index > -1) {
@@ -205,24 +227,4 @@ public class ExportSingleReadAlignmentWizardPage extends WizardPage {
         }
         return null;
     }
-
-
-    public File getSelectedFile() {
-        if (fileTextField !=  null) {
-            return new File(fileTextField.getText());
-        }
-        else {
-            return null;
-        }
-    }
-
-
-    public String getConsensusSequenceLabel() {
-        if (consensusSequenceNameTextField != null) {
-            return consensusSequenceNameTextField.getText();
-        }
-        else {
-            return null;
-        }
-    }
 }
diff --git a/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/FileNameValidator.java b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/FileNameValidator.java
new file mode 100644
index 000000000..a9475c309
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/io/wizard/FileNameValidator.java
@@ -0,0 +1,38 @@
+/**
+* Copyright (C) 2016 EDIT
+* European Distributed Institute of Taxonomy
+* http://www.e-taxonomy.eu
+*
+* The contents of this file are subject to the Mozilla Public License Version 1.1
+* See LICENSE.TXT at the top of this package for the full license terms.
+*/
+package eu.etaxonomy.taxeditor.molecular.io.wizard;
+
+
+import org.eclipse.core.databinding.validation.IValidator;
+import org.eclipse.core.databinding.validation.ValidationStatus;
+import org.eclipse.core.runtime.IStatus;
+
+
+
+/**
+ * Validator to make sure a non-empty file name is provided.
+ *
+ * @author Ben Stöver
+ * @date 16.11.2016
+ */
+public class FileNameValidator implements IValidator {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IStatus validate(Object value) {
+        if ((value == null) || ((String)value).isEmpty()) {
+            return ValidationStatus.error("The file name must not be empty.");
+        }
+        else {
+            return ValidationStatus.ok();
+        }
+        //TODO Display warning, if the file extension does not match the selected format? (An according listener would have to be registered.)
+    }
+}
