diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/EditorUtil.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/EditorUtil.java
index c93501452..d923dd9b8 100644
--- a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/EditorUtil.java
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/EditorUtil.java
@@ -37,6 +37,8 @@ import eu.etaxonomy.taxeditor.editor.group.authority.CdmAuthorityEditorInput;
import eu.etaxonomy.taxeditor.editor.internal.TaxeditorEditorPlugin;
import eu.etaxonomy.taxeditor.editor.key.KeyEditor;
import eu.etaxonomy.taxeditor.editor.key.polytomous.PolytomousKeyEditorInput;
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor;
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditorInput;
import eu.etaxonomy.taxeditor.editor.view.checklist.ChecklistEditor;
import eu.etaxonomy.taxeditor.editor.view.checklist.ChecklistEditorInput;
import eu.etaxonomy.taxeditor.editor.view.dataimport.BioCaseEditorInput;
@@ -120,6 +122,16 @@ public class EditorUtil extends AbstractUtility {
open(input, ChecklistEditor.ID);
}
+ /**
+ * Opens a new AlignmentEditor for the given input
+ * @param input
+ * @throws PartInitException
+ */
+ public static void open(AlignmentEditorInput input)
+ throws PartInitException {
+ open(input, AlignmentEditor.ID);
+ }
+
/**
* Opens a new {@link DataImportEditor} for the given input
* @param input a {@link DataImportEditorInput}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/EditSequenceHandler.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/EditSequenceHandler.java
new file mode 100644
index 000000000..dc41cf1ff
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/EditSequenceHandler.java
@@ -0,0 +1,42 @@
+package eu.etaxonomy.taxeditor.editor.handler;
+
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.TreeNode;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+import eu.etaxonomy.cdm.model.molecular.Sequence;
+import eu.etaxonomy.taxeditor.editor.EditorUtil;
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditorInput;
+
+
+
+/**
+ * Opens the alignment editor from the CDM tree.
+ *
+ * @author Ben Stöver
+ * @author pplitzner
+ */
+public class EditSequenceHandler extends AbstractHandler {
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ ISelection currentSelection = HandlerUtil.getCurrentSelection(event);
+ TreeNode treeNodeOfSelection = EditorUtil.getTreeNodeOfSelection(currentSelection);
+ if(treeNodeOfSelection != null && treeNodeOfSelection.getValue() instanceof Sequence){
+ AlignmentEditorInput input = new AlignmentEditorInput((Sequence)treeNodeOfSelection.getValue()); //TODO Should there always be a new instance created here? What if the specified CDM node is already opened in an AlignmentEditor? => Possible create Singleton that keeps instances by sequence objects in a map.
+ try {
+ EditorUtil.open(input);
+ }
+ catch (PartInitException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/LoadPherogramHandler.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/LoadPherogramHandler.java
new file mode 100644
index 000000000..a803a64d6
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/LoadPherogramHandler.java
@@ -0,0 +1,69 @@
+/**
+* Copyright (C) 2007 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.editor.handler;
+
+
+import java.io.File;
+import java.io.IOException;
+
+import org.biojava.bio.chromatogram.UnsupportedChromatogramFormatException;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.ui.IEditorPart;
+
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+
+
+
+/**
+ * Handler that loads an additional read into the contig alignment displayed by an instance of {@link AlignmentEditor}.
+ *
+ * @author Ben Stöver
+ * @author pplitzner
+ */
+public class LoadPherogramHandler extends AbstractHandler {
+ //TODO Change so that also URIs which do not point to files can be specified.
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IEditorPart activeEditor = AbstractUtility.getActiveEditor();
+ if (activeEditor instanceof AlignmentEditor) {
+ AlignmentEditor alignmentEditor = (AlignmentEditor)activeEditor;
+
+ FileDialog fileDialog = new FileDialog(alignmentEditor.getSite().getShell());
+ fileDialog.setText("Import pherogram into contig alignment");
+ fileDialog.setFilterNames(new String[]{"All supported formats", "AB1 pherogram files", "SCF pherogram files", "All files"});
+ fileDialog.setFilterExtensions(new String[]{"*.ab1;*.scf", "*.ab1", "*.scf", "*.*"});
+
+ String path = fileDialog.open();
+ if (path != null) {
+ try {
+ alignmentEditor.addRead(new File(path).toURI(), false);
+ }
+ catch (UnsupportedChromatogramFormatException e) {
+ MessagingUtils.errorDialog("Unsupported format", this, "The format of the pherogram file \"" + path +
+ "\" is not supported. (Only AB1 and SCF are supported.)", "eu.etaxonomy.taxeditor.editor", e, false); //TODO set pluginID
+ }
+ catch (IOException e) {
+ MessagingUtils.errorDialog("Unsupported format", this,
+ "An IO error occurred while trying to read the file \"" + path + "\".",
+ "/eu.etaxonomy.taxeditor.editor", e, false); //TODO set pluginID
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/OpenAlignmentEditorHandler.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/OpenAlignmentEditorHandler.java
new file mode 100644
index 000000000..4350fa29c
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/OpenAlignmentEditorHandler.java
@@ -0,0 +1,47 @@
+// $Id$
+/**
+* Copyright (C) 2014 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.editor.handler;
+
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.PartInitException;
+
+import eu.etaxonomy.taxeditor.editor.EditorUtil;
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor;
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditorInput;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+
+
+
+/**
+ * Opens the {@link AlignmentEditor}.
+ *
+ * @author pplitzner
+ * @date 04.08.2014
+ */
+@Deprecated
+public class OpenAlignmentEditorHandler extends AbstractHandler {
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ AlignmentEditorInput input = new AlignmentEditorInput(null); //TODO Does it make sense to start an empty editor?
+ try {
+ EditorUtil.open(input);
+ }
+ catch (PartInitException e) {
+ MessagingUtils.error(OpenAlignmentEditorHandler.class, "Could not open AlignmentEditor", e);
+ }
+ return null;
+ }
+}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ShowPherogramHandler.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ShowPherogramHandler.java
new file mode 100644
index 000000000..149e5ceb8
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ShowPherogramHandler.java
@@ -0,0 +1,49 @@
+package eu.etaxonomy.taxeditor.editor.handler;
+
+
+import java.net.URI;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.TreeNode;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+import eu.etaxonomy.cdm.model.media.MediaUtils;
+import eu.etaxonomy.cdm.model.molecular.SingleRead;
+import eu.etaxonomy.taxeditor.editor.EditorUtil;
+import eu.etaxonomy.taxeditor.editor.molecular.PherogramViewPart;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+
+
+
+/**
+ * Displays an undistorted pherogram with {@link PherogramViewPart}.
+ *
+ * @author Ben Stöver
+ *
+ */
+public class ShowPherogramHandler extends AbstractHandler {
+ public static void showPherogram(URI uri) {
+ try {
+ PherogramViewPart.createView(uri);
+ }
+ catch (Exception e) {
+ MessagingUtils.errorDialog("Error", null, e.getLocalizedMessage(), "eu.etaxonomy.taxeditor.editor", //TODO Is null a valid value here?
+ e, false); //TODO set pluginID
+ }
+ }
+
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ ISelection currentSelection = HandlerUtil.getCurrentSelection(event);
+ TreeNode treeNodeOfSelection = EditorUtil.getTreeNodeOfSelection(currentSelection);
+ if (treeNodeOfSelection != null && treeNodeOfSelection.getValue() instanceof SingleRead) {
+ showPherogram(MediaUtils.getFirstMediaRepresentationPart(
+ ((SingleRead)treeNodeOfSelection.getValue()).getPherogram()).getUri());
+ }
+ return null;
+ }
+}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/SpecimenPropertyTester.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/SpecimenPropertyTester.java
new file mode 100644
index 000000000..17c821365
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/SpecimenPropertyTester.java
@@ -0,0 +1,58 @@
+package eu.etaxonomy.taxeditor.editor.handler;
+
+
+import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeNode;
+
+import eu.etaxonomy.cdm.model.molecular.Sequence;
+import eu.etaxonomy.cdm.model.molecular.SingleRead;
+import eu.etaxonomy.taxeditor.editor.EditorUtil;
+
+
+
+/**
+ * Tests types of specimens to add items to the context menu.
+ *
+ * @author pplitzner
+ * @author BenStoever
+ */
+public class SpecimenPropertyTester extends PropertyTester {
+ private static final String SEQUENCE = "isSequence";
+ private static final String SINGLE_READ = "isSingleRead";
+
+
+ public SpecimenPropertyTester() {}
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.expressions.IPropertyTester#test(java.lang.Object, java.lang.String, java.lang.Object[], java.lang.Object)
+ */
+ /** {@inheritDoc} */
+ @Override
+ public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
+ if (receiver instanceof IStructuredSelection) {
+ IStructuredSelection selection = (IStructuredSelection) receiver;
+ TreeNode treeNodeOfSelection = EditorUtil.getTreeNodeOfSelection(selection);
+ if (treeNodeOfSelection!=null) {
+ if (SEQUENCE.equals(property)) {
+ return isSequence(treeNodeOfSelection.getValue());
+ }
+ else if (SINGLE_READ.equals(property)) {
+ return isSingleReadAlignment(treeNodeOfSelection.getValue());
+ }
+ }
+ }
+ return false;
+ }
+
+
+ private boolean isSequence(Object object) {
+ return (object instanceof Sequence);
+ }
+
+
+ private boolean isSingleReadAlignment(Object object) {
+ return (object instanceof SingleRead);
+ }
+}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ToggleInsertOverwriteHandler.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ToggleInsertOverwriteHandler.java
new file mode 100644
index 000000000..28533af13
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ToggleInsertOverwriteHandler.java
@@ -0,0 +1,62 @@
+/**
+* Copyright (C) 2007 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.editor.handler;
+
+
+import java.util.Map;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.menus.UIElement;
+
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
+
+
+
+/**
+ * Switches an {@link AlignmentEditor} between insertion and overwrite mode.
+ *
+ * @author Ben Stöver
+ * @date 04.12.2014
+ */
+public class ToggleInsertOverwriteHandler extends AbstractHandler implements IElementUpdater {
+ public static final String COMMAND_ID =
+ "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor.toggleInsertOverwrite";
+
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IEditorPart activeEditor = AbstractUtility.getActiveEditor();
+ if (activeEditor instanceof AlignmentEditor) {
+ ((AlignmentEditor)activeEditor).toggleInsertOverwrite();
+ }
+ return null;
+ }
+
+
+ @Override
+ public void updateElement(UIElement element, @SuppressWarnings("rawtypes") Map parameters) {
+ IEditorPart activeEditor = AbstractUtility.getActiveEditor();
+ if (activeEditor instanceof AlignmentEditor) {
+ if (((AlignmentEditor)activeEditor).isInsertMode()) {
+ element.setText(" INS ");
+ element.setTooltip("Click to switch to overwrite mode");
+ }
+ else {
+ element.setText("OVR");
+ element.setTooltip("Click to switch to insertion mode");
+ }
+ }
+ }
+}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ToggleLeftRightInsertionHandler.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ToggleLeftRightInsertionHandler.java
new file mode 100644
index 000000000..2173f63d9
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/handler/ToggleLeftRightInsertionHandler.java
@@ -0,0 +1,63 @@
+/**
+* Copyright (C) 2007 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.editor.handler;
+
+
+import java.util.Map;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.commands.IElementUpdater;
+import org.eclipse.ui.menus.UIElement;
+
+import eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor;
+import eu.etaxonomy.taxeditor.model.AbstractUtility;
+
+
+
+/**
+ * Switches an {@link AlignmentEditor} between insertion in the base sequence to the left or to the right.
+ *
+ * @author Ben Stöver
+ * @date 04.12.2014
+ */
+public class ToggleLeftRightInsertionHandler extends AbstractHandler implements IElementUpdater {
+ public static final String COMMAND_ID =
+ "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor.toggleLeftRightInsertion";
+
+
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IEditorPart activeEditor = AbstractUtility.getActiveEditor();
+ if (activeEditor instanceof AlignmentEditor) {
+ ((AlignmentEditor)activeEditor).toggleLeftRightInsertionInPherogram();
+ }
+ return null;
+ }
+
+
+ @Override
+ public void updateElement(UIElement element, @SuppressWarnings("rawtypes") Map parameters) {
+ IEditorPart activeEditor = AbstractUtility.getActiveEditor();
+ if (activeEditor instanceof AlignmentEditor) {
+ //TODO Use icons instead.
+ if (((AlignmentEditor)activeEditor).isInsertLeftInPherogram()) {
+ element.setText(" Left ");
+ element.setTooltip("Click to switch to insert new distorsions of the base call sequence right of future edits.");
+ }
+ else {
+ element.setText("Right");
+ element.setTooltip("Click to switch to insert new distorsions of the base call sequence left of future edits.");
+ }
+ }
+ }
+}
diff --git a/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/molecular/AlignmentEditor.java b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/molecular/AlignmentEditor.java
new file mode 100644
index 000000000..75eb41ce6
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.editor/src/main/java/eu/etaxonomy/taxeditor/editor/molecular/AlignmentEditor.java
@@ -0,0 +1,548 @@
+// $Id$
+/**
+* Copyright (C) 2014 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.editor.molecular;
+
+
+import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
+import info.bioinfweb.libralign.dataarea.implementations.ConsensusSequenceArea;
+import info.bioinfweb.libralign.dataarea.implementations.SequenceIndexArea;
+import info.bioinfweb.libralign.dataarea.implementations.pherogram.PherogramAlignmentModel;
+import info.bioinfweb.libralign.dataarea.implementations.pherogram.PherogramArea;
+import info.bioinfweb.libralign.dataarea.implementations.pherogram.ShiftChange;
+import info.bioinfweb.libralign.editsettings.EditSettingsChangeEvent;
+import info.bioinfweb.libralign.editsettings.EditSettingsListener;
+import info.bioinfweb.libralign.multiplealignments.AlignmentAreaList;
+import info.bioinfweb.libralign.multiplealignments.MultipleAlignmentsContainer;
+import info.bioinfweb.libralign.pherogram.provider.BioJavaPherogramProvider;
+import info.bioinfweb.libralign.pherogram.provider.PherogramProvider;
+import info.bioinfweb.libralign.pherogram.provider.ReverseComplementPherogramProvider;
+import info.bioinfweb.libralign.sequenceprovider.SequenceDataChangeListener;
+import info.bioinfweb.libralign.sequenceprovider.SequenceDataProvider;
+import info.bioinfweb.libralign.sequenceprovider.SequenceUtils;
+import info.bioinfweb.libralign.sequenceprovider.adapters.StringAdapter;
+import info.bioinfweb.libralign.sequenceprovider.events.SequenceChangeEvent;
+import info.bioinfweb.libralign.sequenceprovider.events.SequenceRenamedEvent;
+import info.bioinfweb.libralign.sequenceprovider.events.TokenChangeEvent;
+import info.bioinfweb.libralign.sequenceprovider.implementations.PackedSequenceDataProvider;
+import info.bioinfweb.libralign.sequenceprovider.tokenset.BioJavaTokenSet;
+import info.bioinfweb.libralign.sequenceprovider.tokenset.TokenSet;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.biojava.bio.chromatogram.ChromatogramFactory;
+import org.biojava.bio.chromatogram.UnsupportedChromatogramFormatException;
+import org.biojava3.core.sequence.compound.DNACompoundSet;
+import org.biojava3.core.sequence.compound.NucleotideCompound;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.part.EditorPart;
+
+import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
+import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
+import eu.etaxonomy.cdm.model.media.MediaUtils;
+import eu.etaxonomy.cdm.model.molecular.Sequence;
+import eu.etaxonomy.cdm.model.molecular.SequenceString;
+import eu.etaxonomy.cdm.model.molecular.SingleRead;
+import eu.etaxonomy.cdm.model.molecular.SingleReadAlignment;
+import eu.etaxonomy.taxeditor.editor.handler.ToggleInsertOverwriteHandler;
+import eu.etaxonomy.taxeditor.editor.handler.ToggleLeftRightInsertionHandler;
+import eu.etaxonomy.taxeditor.store.CdmStore;
+
+
+
+/**
+ * Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
+ * a consensus sequence.
+ *
+ * The contained GUI components used to edit the alignment come from LibrAlign.
+ *
+ * @author Ben Stöver
+ * @author pplitzner
+ * @date 04.08.2014
+ */
+public class AlignmentEditor extends EditorPart {
+ public static final String ID = "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor";
+
+ private final ConversationHolder conversationHolder;
+
+ public static final int READS_AREA_INDEX = 1;
+ public static final int CONSENSUS_AREA_INDEX = READS_AREA_INDEX + 1;
+ public static final int PHEROGRAM_AREA_INDEX = 0;
+ public static final String DEFAULT_READ_NAME_PREFIX = "Read ";
+ public static final String CONSENSUS_NAME = "Consensus";
+
+
+ private final SequenceDataChangeListener DIRTY_LISTENER = new SequenceDataChangeListener() {
+ @Override
+ public void afterTokenChange(TokenChangeEvent e) {
+ setDirty();
+ }
+
+ @Override
+ public void afterSequenceRenamed(SequenceRenamedEvent e) {
+ setDirty();
+ }
+
+ @Override
+ public void afterSequenceChange(SequenceChangeEvent e) {
+ setDirty();
+ }
+
+ @Override
+ public void afterProviderChanged(SequenceDataProvider oldProvider,
+ SequenceDataProvider newProvider) { // Not expected.
+
+ setDirty();
+ }
+ };
+
+ private MultipleAlignmentsContainer alignmentsContainer = null;
+ private final Map cdmMap = new TreeMap(); //TODO Move this to ContigSequenceDataProvider
+ private boolean dirty = false;
+
+ public AlignmentEditor() {
+ conversationHolder = CdmStore.createConversation();
+ }
+
+
+ private void refreshToolbarElement(String id) {
+ ICommandService commandService =
+ (ICommandService)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService.class);
+ if (commandService != null) {
+ commandService.refreshElements(id, Collections.EMPTY_MAP);
+ }
+ }
+
+
+ private void registerEditSettingListener(MultipleAlignmentsContainer container) {
+ container.getEditSettings().addListener(new EditSettingsListener() {
+ @Override
+ public void workingModeChanged(EditSettingsChangeEvent e) {} // Currently nothing to do
+
+ @Override
+ public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e) {
+ updateStatusBar();
+ refreshToolbarElement(ToggleLeftRightInsertionHandler.COMMAND_ID);
+ }
+
+ @Override
+ public void insertChanged(EditSettingsChangeEvent e) {
+ updateStatusBar();
+ refreshToolbarElement(ToggleInsertOverwriteHandler.COMMAND_ID);
+ }
+ });
+ }
+
+
+ private AlignmentArea createIndexArea(MultipleAlignmentsContainer container) {
+ AlignmentArea result = new AlignmentArea(container);
+ result.setAllowVerticalScrolling(false);
+ result.getDataAreas().getTopAreas().add(new SequenceIndexArea(result.getContentArea()));
+ return result;
+ }
+
+
+ private AlignmentArea createEditableAlignmentArea(MultipleAlignmentsContainer container, boolean allowVerticalScrolling) {
+ AlignmentArea result = new AlignmentArea(container);
+ result.setAllowVerticalScrolling(allowVerticalScrolling);
+
+ TokenSet tokenSet = new BioJavaTokenSet(new DNACompoundSet(), true);
+ SequenceDataProvider provider = new PackedSequenceDataProvider(tokenSet);
+ result.setSequenceProvider(provider, false);
+ provider.getChangeListeners().add(DIRTY_LISTENER);
+
+ return result;
+ }
+
+
+ private AlignmentArea createConsensusHintArea(MultipleAlignmentsContainer container,
+ SequenceDataProvider> sequenceProvider) {
+
+ AlignmentArea result = new AlignmentArea(container);
+ result.setAllowVerticalScrolling(false);
+ result.getDataAreas().getBottomAreas().add(
+ new ConsensusSequenceArea(result.getContentArea(), sequenceProvider));
+ return result;
+ }
+
+
+ private MultipleAlignmentsContainer getAlignmentsContainer() {
+ if (alignmentsContainer == null) {
+ alignmentsContainer = new MultipleAlignmentsContainer();
+
+ AlignmentAreaList list = alignmentsContainer.getAlignmentAreas();
+ list.add(createIndexArea(alignmentsContainer));
+ AlignmentArea readsArea = createEditableAlignmentArea(alignmentsContainer, true);
+ list.add(readsArea); // Make sure READS_AREA_INDEX is correct.
+ list.add(createEditableAlignmentArea(alignmentsContainer, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
+ list.add(createConsensusHintArea(alignmentsContainer,
+ readsArea.getSequenceProvider()));
+
+ registerEditSettingListener(alignmentsContainer);
+ }
+ return alignmentsContainer;
+ }
+
+
+ private AlignmentArea getReadsArea() {
+ return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX);
+ }
+
+
+ private AlignmentArea getConsensusArea() {
+ return getAlignmentsContainer().getAlignmentAreas().get(CONSENSUS_AREA_INDEX);
+ }
+
+
+ private PherogramArea getPherogramArea(int sequenceID) {
+ return (PherogramArea)getReadsArea().getDataAreas().getSequenceAreas(sequenceID).get(PHEROGRAM_AREA_INDEX);
+ }
+
+
+ private void createTestContents() {
+ // Just for testing:
+ try {
+ addRead(new File("D:/Users/BenStoever/Documents/Studium/Projekte/Promotion/EDITor/Quelltexte/LibrAlign branch/Repository/eu.etaxonomy.taxeditor.editor/src/main/resources/AlignmentTestData/JR430_JR-P01.ab1").toURI(), false);
+ addRead(new File("D:/Users/BenStoever/Documents/Studium/Projekte/Promotion/EDITor/Quelltexte/LibrAlign branch/Repository/eu.etaxonomy.taxeditor.editor/src/main/resources/AlignmentTestData/JR444_JR-P05.ab1").toURI(), false);
+
+ // Add test consensus sequence:
+ SequenceDataProvider consensusProvider = getConsensusArea().getSequenceProvider();
+ int id = consensusProvider.addSequence(CONSENSUS_NAME);
+ Collection