import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
-import info.bioinfweb.libralign.alignmentarea.content.AlignmentContentArea;
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.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.part.EditorPart;
+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;
public static final String ID = "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor";
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 <T> void afterTokenChange(TokenChangeEvent<T> e) {
+ setDirty();
+ }
+
+ @Override
+ public <T> void afterSequenceRenamed(SequenceRenamedEvent<T> e) {
+ setDirty();
+ }
+
+ @Override
+ public <T> void afterSequenceChange(SequenceChangeEvent<T> e) {
+ setDirty();
+ }
+
+ @Override
+ public <T, U> void afterProviderChanged(SequenceDataProvider<T> oldProvider,
+ SequenceDataProvider<U> newProvider) { // Not expected.
+
+ setDirty();
+ }
+ };
+
private MultipleAlignmentsContainer alignmentsContainer = null;
- private Map<Integer, URI> uriMap = new TreeMap<Integer, URI>(); //TODO Move this to ContigSequenceDataProvider
+ private Map<Integer, SingleReadAlignment> cdmMap = new TreeMap<Integer, SingleReadAlignment>(); //TODO Move this to ContigSequenceDataProvider
+ private boolean dirty = false;
private void refreshToolbarElement(String id) {
TokenSet<NucleotideCompound> tokenSet = new BioJavaTokenSet<NucleotideCompound>(new DNACompoundSet(), true);
SequenceDataProvider<NucleotideCompound> provider = new PackedSequenceDataProvider<NucleotideCompound>(tokenSet);
result.setSequenceProvider(provider, false);
+ provider.getChangeListeners().add(DIRTY_LISTENER);
return result;
}
private AlignmentArea getConsensusArea() {
return getAlignmentsContainer().getAlignmentAreas().get(CONSENSUS_AREA_INDEX);
}
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
- */
- @Override
- public void createPartControl(Composite parent) {
- getAlignmentsContainer().createSWTWidget(parent, SWT.NONE);
- updateStatusBar();
-
+
+
+ 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());
- 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());
+ 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");
+ int id = consensusProvider.addSequence(CONSENSUS_NAME);
Collection<Object> tokens = new ArrayList<Object>(); // First save tokens in a collection to avoid GUI updated for each token.
tokens.add(consensusProvider.getTokenSet().tokenByKeyChar('A'));
tokens.add(consensusProvider.getTokenSet().tokenByKeyChar('C'));
throw new RuntimeException(e);
}
}
+
+
+ private void readCDMData() {
+ //TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
+ Sequence sequenceNode = ((AlignmentEditorInput)getEditorInput()).getSequenceNode();
+
+ // Add reads:
+ for (SingleReadAlignment singleReadAlignment : sequenceNode.getSingleReadAlignments()) {
+ try {
+ SingleRead pherogramInfo = singleReadAlignment.getSingleRead();
+ int id = addRead(pherogramInfo.getPrimer().getLabel(), //TODO Should the sequence name contain other/additional/alternative data? Can the same string as in the derivative tree be used here?
+ MediaUtils.getFirstMediaRepresentationPart(pherogramInfo.getPherogram()).getUri(),
+ singleReadAlignment.isReverseComplement(),
+ singleReadAlignment.getEditedSequence(),
+ singleReadAlignment.getShifts());
+ cdmMap.put(id, singleReadAlignment);
+ }
+ catch (IOException e) {
+ e.printStackTrace(); //TODO Output to user (Possibly collect for all pherograms and display in the end.)
+ }
+ catch (UnsupportedChromatogramFormatException e) {
+ e.printStackTrace(); //TODO Output to user (Possibly collect for all pherograms and display in the end.)
+ }
+ }
+
+ // Set consensus sequence:
+ SequenceDataProvider consensusProvider = getConsensusArea().getSequenceProvider();
+ int id = consensusProvider.addSequence(CONSENSUS_NAME);
+ consensusProvider.insertTokensAt(id, 0, SequenceUtils.stringToTokenList(
+ sequenceNode.getConsensusSequence().getString(), consensusProvider.getTokenSet()));
+ //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPartControl(Composite parent) {
+ getAlignmentsContainer().createSWTWidget(parent, SWT.NONE);
+ updateStatusBar();
+
+ if (getEditorInput() instanceof AlignmentEditorInput) {
+ if (((AlignmentEditorInput)getEditorInput()).getSequenceNode() != null) {
+ readCDMData();
+ }
+ else {
+ createTestContents(); //TODO What to do here instead in the final version?
+ }
+ }
+ else {
+ throw new IllegalArgumentException("The editor input must have the type " +
+ AlignmentEditorInput.class.getCanonicalName()); //TODO What should be done here?
+ }
+ }
private void updateStatusBar() {
}
+ private SingleReadAlignment.Shift[] convertToCDMShifts(PherogramAlignmentModel alignmentModel) {
+ SingleReadAlignment.Shift[] result = new SingleReadAlignment.Shift[alignmentModel.getShiftChangeCount()];
+ Iterator<ShiftChange> iterator = alignmentModel.shiftChangeIterator();
+ int pos = 0;
+ while (iterator.hasNext()) {
+ ShiftChange shiftChange = iterator.next();
+ result[pos] = new SingleReadAlignment.Shift(shiftChange.getBaseCallIndex(), shiftChange.getShiftChange());
+ }
+ return result;
+ }
+
+
/* (non-Javadoc)
* @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
*/
@Override
public void doSave(IProgressMonitor monitor) {
- // TODO Auto-generated method stub
-
+ System.out.println("save 1");
+ if (getEditorInput() instanceof AlignmentEditorInput) {
+ System.out.println("save 2");
+ Sequence sequenceNode = ((AlignmentEditorInput)getEditorInput()).getSequenceNode();
+ StringAdapter stringProvider = new StringAdapter(getConsensusArea().getSequenceProvider(), false); // Throws an exception if a token has more than one character.
+
+ // Write consensus sequence:
+ SequenceString consensusSequenceObj = sequenceNode.getConsensusSequence();
+ String newConsensusSequence = stringProvider.getSequence(
+ getConsensusArea().getSequenceProvider().sequenceIDByName(CONSENSUS_NAME));
+ if (consensusSequenceObj == null) {
+ sequenceNode.setConsensusSequence(SequenceString.NewInstance(newConsensusSequence));
+ }
+ else {
+ consensusSequenceObj.setString(newConsensusSequence);
+ }
+
+ // Write single reads:
+ stringProvider.setUnderlyingProvider(getReadsArea().getSequenceProvider());
+ sequenceNode.getSingleReadAlignments().retainAll(cdmMap.values()); // Remove all reads that are not in the alignment anymore.
+ Iterator<Integer> iterator = getReadsArea().getSequenceProvider().sequenceIDIterator();
+ while (iterator.hasNext()) {
+ int id = iterator.next();
+ System.out.println("Saving sequence " + id);
+ SingleReadAlignment singleRead = cdmMap.get(id);
+ if (singleRead == null) {
+ //TODO Create new read object. => Shall it be allowed to add reads in the alignment editor which are not represented in the CDM tree before the alignment editor is saved?
+ //singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
+ }
+
+ singleRead.setEditedSequence(stringProvider.getSequence(id));
+ singleRead.setReverseComplement(getPherogramArea(id).getProvider() instanceof ReverseComplementPherogramProvider); // Works only if ReverseComplementPherogramProvider instances are not nested.
+ singleRead.setShifts(convertToCDMShifts(getPherogramArea(id).getAlignmentModel()));
+ System.out.println(singleRead.getShifts());
+ }
+ }
+ dirty = false; //TODO "*" is not removed from editor title. Why not? (Should be save action in the tool bar be disabled when isDirty() returns false? This is also not the case.)
}
* @see org.eclipse.ui.part.EditorPart#doSaveAs()
*/
@Override
- public void doSaveAs() {
- // TODO Auto-generated method stub
-
- }
+ public void doSaveAs() {}
/* (non-Javadoc)
*/
@Override
public boolean isDirty() {
- // TODO Auto-generated method stub
- return false;
+ return dirty;
+ }
+
+
+ private void setDirty() {
+ dirty = true;
}
*/
@Override
public boolean isSaveAsAllowed() {
- // TODO Auto-generated method stub
- return false;
+ return false; // "Save as" not allowed.
}
}
- public void addRead(URI pherogramURI) throws IOException, UnsupportedChromatogramFormatException {
- addRead(newReadName(), pherogramURI);
+ public void addRead(URI pherogramURI, boolean reverseComplemented) throws IOException, UnsupportedChromatogramFormatException {
+ addRead(newReadName(), pherogramURI, reverseComplemented, null, null);
}
- public void addRead(String name, URI pherogramURI) throws IOException, UnsupportedChromatogramFormatException {
+ /**
+ * Adds a new sequence with attached phergram data area to the reads alignment.
+ * <p>
+ * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
+ * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
+ * and the base calls sequence are assumed.
+ *
+ * @param name the name of the new sequence
+ * @param pherogramURI the URI where the associated pherogram file is located
+ * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
+ * be added, {@code false} otherwise.
+ * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
+ * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
+ * @return the sequence ID of the added read
+ * @throws IOException if an error occurred when trying to read the pherogram file
+ * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
+ */
+ public int addRead(String name, URI pherogramURI, boolean reverseComplemented, String editedSequence,
+ SingleReadAlignment.Shift[] shifts) throws IOException, UnsupportedChromatogramFormatException {
+
SequenceDataProvider provider = getReadsArea().getSequenceProvider();
PherogramProvider pherogramProvider = readPherogram(pherogramURI); // Must happen before a sequence is added, because it might throw an exception.
+ if (reverseComplemented) {
+ pherogramProvider = new ReverseComplementPherogramProvider(pherogramProvider);
+ }
// Create sequence:
provider.addSequence(name);
int id = provider.sequenceIDByName(name);
- // Copy base call sequence into alignment:
- Collection<Object> tokens = new ArrayList<Object>(); // First save tokens in a collection to avoid GUI updated for each token.
- for (int i = 0; i < pherogramProvider.getSequenceLength(); i++) {
- tokens.add(provider.getTokenSet().tokenByKeyChar(
- pherogramProvider.getBaseCall(i).getUpperedBase().charAt(0)));
+ // Set edited sequence:
+ Collection<Object> tokens; // First save tokens in a collection to avoid GUI updated for each token.
+ if (editedSequence != null) {
+ tokens = SequenceUtils.stringToTokenList(editedSequence, provider.getTokenSet());
+ }
+ else { // Copy base call sequence into alignment:
+ tokens = new ArrayList<Object>();
+ for (int i = 0; i < pherogramProvider.getSequenceLength(); i++) {
+ tokens.add(provider.getTokenSet().tokenByKeyChar(
+ pherogramProvider.getBaseCall(i).getUpperedBase().charAt(0)));
+ }
+ setDirty();
}
provider.insertTokensAt(id, 0, tokens);
- // Add data area:
+ // Create pherogram area:
PherogramArea pherogramArea = new PherogramArea(getReadsArea().getContentArea(), pherogramProvider);
+
+ // Set shifts:
+ if (shifts != null) {
+ PherogramAlignmentModel alignmentModel = pherogramArea.getAlignmentModel();
+ for (int i = 0; i < shifts.length; i++) {
+ alignmentModel.addShiftChange(shifts[i].position, shifts[i].shift);
+ }
+ setDirty();
+ }
+
+ // Add pherogram area to GUI:
pherogramArea.addMouseListener(new PherogramMouseListener(pherogramURI));
getReadsArea().getDataAreas().getSequenceAreas(id).add(pherogramArea);
// Save source URI:
- uriMap.put(id, pherogramURI);
+ return id;
}
}
\ No newline at end of file