+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eu.etaxonomy.taxeditor.molecular/pom.xml b/eu.etaxonomy.taxeditor.molecular/pom.xml
new file mode 100644
index 000000000..06d847999
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.molecular/pom.xml
@@ -0,0 +1,106 @@
+
+
+
+ eu.etaxonomy
+ taxeditor-parent
+ 3.6.1-SNAPSHOT
+
+
+ 4.0.0
+ eu.etaxonomy.taxeditor.molecular
+ eclipse-plugin
+
+ Molecular Bundle
+ Provides editors, views and operations for handling molecular data and alignments
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ info.bioinfweb.libralign
+ libralign-core
+ 0-SNAPSHOT
+
+
+ info.bioinfweb.libralign
+ libralign-swt
+ 0-SNAPSHOT
+
+
+ info.bioinfweb.commons.java
+ bioinfweb-commons-swt
+ 2-SNAPSHOT
+
+
+ info.bioinfweb.commons.java
+ bioinfweb-commons-core
+ 2-SNAPSHOT
+
+
+ info.bioinfweb.commons.java
+ bioinfweb-commons-bio
+ 2-SNAPSHOT
+
+
+ info.bioinfweb.commons.java
+ bioinfweb-commons-swing
+ 2-SNAPSHOT
+
+
+ info.bioinfweb.tic
+ tic-core
+ 2-SNAPSHOT
+
+
+
+
+
+ bioinfweb-maven-repo
+ bioinfweb repository
+ http://bioinfweb.info/MavenRepository/
+
+
+
+
diff --git a/eu.etaxonomy.taxeditor.molecular/src/eu/etaxonomy/taxeditor/molecular/TaxeditorMolecularPlugin.java b/eu.etaxonomy.taxeditor.molecular/src/eu/etaxonomy/taxeditor/molecular/TaxeditorMolecularPlugin.java
new file mode 100644
index 000000000..77818edfd
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.molecular/src/eu/etaxonomy/taxeditor/molecular/TaxeditorMolecularPlugin.java
@@ -0,0 +1,44 @@
+package eu.etaxonomy.taxeditor.molecular;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class TaxeditorMolecularPlugin extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "eu.etaxonomy.taxeditor.molecular"; //$NON-NLS-1$
+
+ // The shared instance
+ private static TaxeditorMolecularPlugin plugin;
+
+ /**
+ * The constructor
+ */
+ public TaxeditorMolecularPlugin() {
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static TaxeditorMolecularPlugin getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/eu.etaxonomy.taxeditor.molecular/src/eu/etaxonomy/taxeditor/molecular/editor/AlignmentEditor.java b/eu.etaxonomy.taxeditor.molecular/src/eu/etaxonomy/taxeditor/molecular/editor/AlignmentEditor.java
new file mode 100644
index 000000000..3ec547504
--- /dev/null
+++ b/eu.etaxonomy.taxeditor.molecular/src/eu/etaxonomy/taxeditor/molecular/editor/AlignmentEditor.java
@@ -0,0 +1,718 @@
+// $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.molecular.editor;
+
+
+import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
+import info.bioinfweb.libralign.alignmentarea.selection.SelectionModel;
+import info.bioinfweb.libralign.alignmentarea.tokenpainter.NucleotideTokenPainter;
+import info.bioinfweb.libralign.dataarea.implementations.ConsensusSequenceArea;
+import info.bioinfweb.libralign.dataarea.implementations.SequenceIndexArea;
+import info.bioinfweb.libralign.dataarea.implementations.pherogram.PherogramArea;
+import info.bioinfweb.libralign.editsettings.EditSettingsChangeEvent;
+import info.bioinfweb.libralign.editsettings.EditSettingsListener;
+import info.bioinfweb.libralign.model.AlignmentModel;
+import info.bioinfweb.libralign.model.AlignmentModelChangeListener;
+import info.bioinfweb.libralign.model.AlignmentModelUtils;
+import info.bioinfweb.libralign.model.adapters.StringAdapter;
+import info.bioinfweb.libralign.model.events.SequenceChangeEvent;
+import info.bioinfweb.libralign.model.events.SequenceRenamedEvent;
+import info.bioinfweb.libralign.model.events.TokenChangeEvent;
+import info.bioinfweb.libralign.model.implementations.PackedAlignmentModel;
+import info.bioinfweb.libralign.model.tokenset.CharacterTokenSet;
+import info.bioinfweb.libralign.model.tokenset.TokenSet;
+import info.bioinfweb.libralign.multiplealignments.AlignmentAreaList;
+import info.bioinfweb.libralign.multiplealignments.MultipleAlignmentsContainer;
+import info.bioinfweb.libralign.pherogram.model.PherogramAreaModel;
+import info.bioinfweb.libralign.pherogram.model.ShiftChange;
+import info.bioinfweb.libralign.pherogram.provider.BioJavaPherogramProvider;
+import info.bioinfweb.libralign.pherogram.provider.PherogramProvider;
+import info.bioinfweb.libralign.pherogram.provider.ReverseComplementPherogramProvider;
+import info.bioinfweb.tic.SWTComponentFactory;
+
+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.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.biojava.bio.chromatogram.ChromatogramFactory;
+import org.biojava.bio.chromatogram.UnsupportedChromatogramFormatException;
+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.IEditorPart;
+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.cdm.model.molecular.SingleReadAlignment.Shift;
+import eu.etaxonomy.taxeditor.model.MessagingUtils;
+import eu.etaxonomy.taxeditor.molecular.TaxeditorMolecularPlugin;
+import eu.etaxonomy.taxeditor.molecular.handler.ToggleInsertOverwriteHandler;
+import eu.etaxonomy.taxeditor.molecular.handler.ToggleLeftRightInsertionHandler;
+import eu.etaxonomy.taxeditor.store.CdmStore;
+import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
+
+
+
+/**
+ * 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.molecular.AlignmentEditor";
+
+ public static final int READS_AREA_INDEX = 1;
+ public static final int EDITABLE_CONSENSUS_AREA_INDEX = READS_AREA_INDEX + 1;
+ public static final int CONSENSUS_HINT_AREA_INDEX = EDITABLE_CONSENSUS_AREA_INDEX + 1;
+ public static final int PHEROGRAM_AREA_INDEX = 0;
+ public static final int CONSENSUS_DATA_AREA_INDEX = 0;
+ public static final String DEFAULT_READ_NAME_PREFIX = "Read ";
+ public static final String CONSENSUS_NAME = "Consensus";
+
+
+ private final ConversationHolder conversationHolder;
+
+ private final AlignmentModelChangeListener DIRTY_LISTENER = new AlignmentModelChangeListener() {
+ @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(AlignmentModel oldProvider,
+ AlignmentModel 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() {
+ super();
+ conversationHolder = CdmStore.createConversation();
+ //conversationHolder = null;
+ }
+
+
+ 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 labeledArea) {
+ AlignmentArea result = new AlignmentArea(container);
+ result.setAllowVerticalScrolling(false);
+ result.getDataAreas().getTopAreas().add(new SequenceIndexArea(result.getContentArea(), labeledArea));
+ return result;
+ }
+
+
+ private AlignmentArea createEditableAlignmentArea(MultipleAlignmentsContainer container, boolean allowVerticalScrolling) {
+ AlignmentArea result = new AlignmentArea(container);
+ result.setAllowVerticalScrolling(allowVerticalScrolling);
+
+ CharacterTokenSet tokenSet = CharacterTokenSet.newDNAInstance(); //TODO Should NUCLEOTIDE be used instead?
+ AlignmentModel provider = new PackedAlignmentModel(tokenSet);
+ result.setAlignmentModel(provider, false);
+ provider.getChangeListeners().add(DIRTY_LISTENER);
+ result.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
+
+ return result;
+ }
+
+
+ private AlignmentArea createConsensusHintArea(MultipleAlignmentsContainer container,
+ AlignmentArea labeledArea) {
+
+ AlignmentArea result = new AlignmentArea(container);
+ result.setAllowVerticalScrolling(false);
+ result.getDataAreas().getBottomAreas().add(
+ new ConsensusSequenceArea(result.getContentArea(), labeledArea));
+ return result;
+ }
+
+
+ private MultipleAlignmentsContainer getAlignmentsContainer() {
+ if (alignmentsContainer == null) {
+ alignmentsContainer = new MultipleAlignmentsContainer();
+
+ AlignmentAreaList list = alignmentsContainer.getAlignmentAreas();
+ AlignmentArea readsArea = createEditableAlignmentArea(alignmentsContainer, true);
+ list.add(createIndexArea(alignmentsContainer, readsArea));
+ 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));
+
+ registerEditSettingListener(alignmentsContainer);
+ }
+ return alignmentsContainer;
+ }
+
+
+ public AlignmentArea getReadsArea() {
+ return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX);
+ }
+
+
+ private AlignmentArea getEditableConsensusArea() {
+ return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX);
+ }
+
+
+ public boolean hasPherogram(int sequenceID) {
+ return getReadsArea().getDataAreas().getSequenceAreas(sequenceID).size() > PHEROGRAM_AREA_INDEX;
+ }
+
+
+ public PherogramArea getPherogramArea(int sequenceID) {
+ if (hasPherogram(sequenceID)) {
+ return (PherogramArea)getReadsArea().getDataAreas().getSequenceAreas(sequenceID).get(PHEROGRAM_AREA_INDEX);
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ private ConsensusSequenceArea getConsensusHintDataArea() {
+ return (ConsensusSequenceArea)getAlignmentsContainer().getAlignmentAreas().
+ get(CONSENSUS_HINT_AREA_INDEX).getDataAreas().getBottomAreas().
+ get(CONSENSUS_DATA_AREA_INDEX);
+ }
+
+
+ @Deprecated //TODO Remove as soon as testing period is over
+ private void createTestContents() {
+ // Just for testing:
+ try {
+ addRead(new File("D:/Users/BenStoever/ownCloud/Dokumente/Projekte/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/ownCloud/Dokumente/Projekte/EDITor/Quelltexte/LibrAlign branch/Repository/eu.etaxonomy.taxeditor.editor/src/main/resources/AlignmentTestData/JR444_JR-P05.ab1").toURI(), false);
+ addRead(new File("D:/Users/BenStoever/ownCloud/Dokumente/Projekte/EDITor/Quelltexte/LibrAlign branch/Repository/eu.etaxonomy.taxeditor.editor/src/main/resources/AlignmentTestData/Test_qualityScore.scf").toURI(), false);
+
+ // Add test consensus sequence:
+ AlignmentModel consensusModel = getEditableConsensusArea().getAlignmentModel();
+ int id = consensusModel.addSequence(CONSENSUS_NAME);
+ Collection