3 * Copyright (C) 2014 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.taxeditor
.molecular
.editor
;
13 import info
.bioinfweb
.libralign
.alignmentarea
.AlignmentArea
;
14 import info
.bioinfweb
.libralign
.alignmentarea
.selection
.SelectionModel
;
15 import info
.bioinfweb
.libralign
.alignmentarea
.tokenpainter
.NucleotideTokenPainter
;
16 import info
.bioinfweb
.libralign
.dataarea
.implementations
.ConsensusSequenceArea
;
17 import info
.bioinfweb
.libralign
.dataarea
.implementations
.SequenceIndexArea
;
18 import info
.bioinfweb
.libralign
.dataarea
.implementations
.pherogram
.PherogramArea
;
19 import info
.bioinfweb
.libralign
.editsettings
.EditSettingsChangeEvent
;
20 import info
.bioinfweb
.libralign
.editsettings
.EditSettingsListener
;
21 import info
.bioinfweb
.libralign
.model
.AlignmentModel
;
22 import info
.bioinfweb
.libralign
.model
.AlignmentModelChangeListener
;
23 import info
.bioinfweb
.libralign
.model
.AlignmentModelUtils
;
24 import info
.bioinfweb
.libralign
.model
.adapters
.StringAdapter
;
25 import info
.bioinfweb
.libralign
.model
.events
.SequenceChangeEvent
;
26 import info
.bioinfweb
.libralign
.model
.events
.SequenceRenamedEvent
;
27 import info
.bioinfweb
.libralign
.model
.events
.TokenChangeEvent
;
28 import info
.bioinfweb
.libralign
.model
.implementations
.PackedAlignmentModel
;
29 import info
.bioinfweb
.libralign
.model
.tokenset
.CharacterTokenSet
;
30 import info
.bioinfweb
.libralign
.model
.tokenset
.TokenSet
;
31 import info
.bioinfweb
.libralign
.multiplealignments
.AlignmentAreaList
;
32 import info
.bioinfweb
.libralign
.multiplealignments
.MultipleAlignmentsContainer
;
33 import info
.bioinfweb
.libralign
.pherogram
.model
.PherogramAreaModel
;
34 import info
.bioinfweb
.libralign
.pherogram
.model
.ShiftChange
;
35 import info
.bioinfweb
.libralign
.pherogram
.provider
.BioJavaPherogramProvider
;
36 import info
.bioinfweb
.libralign
.pherogram
.provider
.PherogramProvider
;
37 import info
.bioinfweb
.libralign
.pherogram
.provider
.ReverseComplementPherogramProvider
;
38 import info
.bioinfweb
.tic
.SWTComponentFactory
;
41 import java
.io
.IOException
;
42 import java
.io
.InputStream
;
44 import java
.util
.ArrayList
;
45 import java
.util
.Collection
;
46 import java
.util
.Collections
;
47 import java
.util
.Iterator
;
48 import java
.util
.List
;
50 import java
.util
.TreeMap
;
52 import org
.biojava
.bio
.chromatogram
.ChromatogramFactory
;
53 import org
.biojava
.bio
.chromatogram
.UnsupportedChromatogramFormatException
;
54 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
55 import org
.eclipse
.jface
.action
.Action
;
56 import org
.eclipse
.swt
.SWT
;
57 import org
.eclipse
.swt
.widgets
.Composite
;
58 import org
.eclipse
.ui
.IActionBars
;
59 import org
.eclipse
.ui
.IEditorInput
;
60 import org
.eclipse
.ui
.IEditorPart
;
61 import org
.eclipse
.ui
.IEditorSite
;
62 import org
.eclipse
.ui
.PartInitException
;
63 import org
.eclipse
.ui
.PlatformUI
;
64 import org
.eclipse
.ui
.actions
.ActionFactory
;
65 import org
.eclipse
.ui
.commands
.ICommandService
;
66 import org
.eclipse
.ui
.part
.EditorPart
;
68 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
69 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
70 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
71 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
72 import eu
.etaxonomy
.cdm
.model
.molecular
.SequenceString
;
73 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
74 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleReadAlignment
;
75 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleReadAlignment
.Shift
;
76 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
77 import eu
.etaxonomy
.taxeditor
.molecular
.TaxeditorMolecularPlugin
;
78 import eu
.etaxonomy
.taxeditor
.molecular
.handler
.ToggleInsertOverwriteHandler
;
79 import eu
.etaxonomy
.taxeditor
.molecular
.handler
.ToggleLeftRightInsertionHandler
;
80 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
81 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateLabelProvider
;
86 * Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
87 * a consensus sequence.
89 * The contained GUI components used to edit the alignment come from <a href="http://bioinfweb.info/LibrAlign/">LibrAlign</a>.
95 public class AlignmentEditor
extends EditorPart
{
96 public static final String ID
= "eu.etaxonomy.taxeditor.molecular.AlignmentEditor";
98 public static final int READS_AREA_INDEX
= 1;
99 public static final int EDITABLE_CONSENSUS_AREA_INDEX
= READS_AREA_INDEX
+ 1;
100 public static final int CONSENSUS_HINT_AREA_INDEX
= EDITABLE_CONSENSUS_AREA_INDEX
+ 1;
101 public static final int PHEROGRAM_AREA_INDEX
= 0;
102 public static final int CONSENSUS_DATA_AREA_INDEX
= 0;
103 public static final String DEFAULT_READ_NAME_PREFIX
= "Read ";
104 public static final String CONSENSUS_NAME
= "Consensus";
107 private final ConversationHolder conversationHolder
;
108 private final AlignmentModelChangeListener DIRTY_LISTENER
= new AlignmentModelChangeListener() {
110 public <T
> void afterTokenChange(TokenChangeEvent
<T
> e
) {
115 public <T
> void afterSequenceRenamed(SequenceRenamedEvent
<T
> e
) {
120 public <T
> void afterSequenceChange(SequenceChangeEvent
<T
> e
) {
125 public <T
, U
> void afterProviderChanged(AlignmentModel
<T
> oldProvider
,
126 AlignmentModel
<U
> newProvider
) { // Not expected.
132 private MultipleAlignmentsContainer alignmentsContainer
= null;
133 private final Map
<Integer
, SingleReadAlignment
> cdmMap
= new TreeMap
<Integer
, SingleReadAlignment
>(); //TODO Move this to ContigSequenceDataProvider
134 private boolean dirty
= false;
137 public AlignmentEditor() {
139 conversationHolder
= CdmStore
.createConversation();
140 //conversationHolder = null;
144 private void refreshToolbarElement(String id
) {
145 ICommandService commandService
=
146 (ICommandService
)PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService
.class);
147 if (commandService
!= null) {
148 commandService
.refreshElements(id
, Collections
.EMPTY_MAP
);
153 private void registerEditSettingListener(MultipleAlignmentsContainer container
) {
154 container
.getEditSettings().addListener(new EditSettingsListener() {
156 public void workingModeChanged(EditSettingsChangeEvent e
) {} // Currently nothing to do
159 public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e
) {
161 refreshToolbarElement(ToggleLeftRightInsertionHandler
.COMMAND_ID
);
165 public void insertChanged(EditSettingsChangeEvent e
) {
167 refreshToolbarElement(ToggleInsertOverwriteHandler
.COMMAND_ID
);
173 private AlignmentArea
createIndexArea(MultipleAlignmentsContainer container
, AlignmentArea labeledArea
) {
174 AlignmentArea result
= new AlignmentArea(container
);
175 result
.setAllowVerticalScrolling(false);
176 result
.getDataAreas().getTopAreas().add(new SequenceIndexArea(result
.getContentArea(), labeledArea
));
181 private AlignmentArea
createEditableAlignmentArea(MultipleAlignmentsContainer container
, boolean allowVerticalScrolling
) {
182 AlignmentArea result
= new AlignmentArea(container
);
183 result
.setAllowVerticalScrolling(allowVerticalScrolling
);
185 CharacterTokenSet tokenSet
= CharacterTokenSet
.newDNAInstance(); //TODO Should NUCLEOTIDE be used instead?
186 AlignmentModel
<Character
> provider
= new PackedAlignmentModel
<Character
>(tokenSet
);
187 result
.setAlignmentModel(provider
, false);
188 provider
.getChangeListeners().add(DIRTY_LISTENER
);
189 result
.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
195 private AlignmentArea
createConsensusHintArea(MultipleAlignmentsContainer container
,
196 AlignmentArea labeledArea
) {
198 AlignmentArea result
= new AlignmentArea(container
);
199 result
.setAllowVerticalScrolling(false);
200 result
.getDataAreas().getBottomAreas().add(
201 new ConsensusSequenceArea(result
.getContentArea(), labeledArea
));
206 private MultipleAlignmentsContainer
getAlignmentsContainer() {
207 if (alignmentsContainer
== null) {
208 alignmentsContainer
= new MultipleAlignmentsContainer();
210 AlignmentAreaList list
= alignmentsContainer
.getAlignmentAreas();
211 AlignmentArea readsArea
= createEditableAlignmentArea(alignmentsContainer
, true);
212 list
.add(createIndexArea(alignmentsContainer
, readsArea
));
213 list
.add(readsArea
); // Make sure READS_AREA_INDEX is correct.
214 list
.add(createEditableAlignmentArea(alignmentsContainer
, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
215 list
.add(createConsensusHintArea(alignmentsContainer
, readsArea
));
217 registerEditSettingListener(alignmentsContainer
);
219 return alignmentsContainer
;
223 public AlignmentArea
getReadsArea() {
224 return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX
);
228 private AlignmentArea
getEditableConsensusArea() {
229 return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX
);
233 public boolean hasPherogram(int sequenceID
) {
234 return getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).size() > PHEROGRAM_AREA_INDEX
;
238 public PherogramArea
getPherogramArea(int sequenceID
) {
239 if (hasPherogram(sequenceID
)) {
240 return (PherogramArea
)getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).get(PHEROGRAM_AREA_INDEX
);
248 private ConsensusSequenceArea
getConsensusHintDataArea() {
249 return (ConsensusSequenceArea
)getAlignmentsContainer().getAlignmentAreas().
250 get(CONSENSUS_HINT_AREA_INDEX
).getDataAreas().getBottomAreas().
251 get(CONSENSUS_DATA_AREA_INDEX
);
255 @Deprecated //TODO Remove as soon as testing period is over
256 private void createTestContents() {
259 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);
260 //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);
261 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);
263 // Add test consensus sequence:
264 AlignmentModel consensusModel
= getEditableConsensusArea().getAlignmentModel();
265 int id
= consensusModel
.addSequence(CONSENSUS_NAME
);
266 Collection
<Object
> tokens
= new ArrayList
<Object
>(); // First save tokens in a collection to avoid GUI updated for each token.
267 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("A"));
268 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("C"));
269 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("G"));
270 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("T"));
271 consensusModel
.insertTokensAt(id
, 0, tokens
);
273 catch (Exception e
) {
274 throw new RuntimeException(e
);
279 private void readCDMData(Sequence sequenceNode
) {
280 //TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
283 for (SingleReadAlignment singleReadAlignment
: sequenceNode
.getSingleReadAlignments()) {
285 SingleRead pherogramInfo
= singleReadAlignment
.getSingleRead();
287 if (pherogramInfo
.getPherogram() != null) {
288 uri
= MediaUtils
.getFirstMediaRepresentationPart(pherogramInfo
.getPherogram()).getUri();
290 int id
= addRead(DerivateLabelProvider
.getDerivateText(pherogramInfo
, conversationHolder
),
292 singleReadAlignment
.isReverseComplement(),
293 singleReadAlignment
.getEditedSequence(),
294 singleReadAlignment
.getFirstSeqPosition(),
295 singleReadAlignment
.getLeftCutPosition(),
296 singleReadAlignment
.getRightCutPosition(),
297 singleReadAlignment
.getShifts());
298 cdmMap
.put(id
, singleReadAlignment
);
300 catch (Exception e
) { // Usually due to an error while trying to read the pherogram (e.g. due to an unsupported format or an invalid URI).
301 MessagingUtils
.errorDialog("Error", null, "A single read was skipped because of the following error:\n\n" +
302 e
.getLocalizedMessage(), TaxeditorMolecularPlugin
.PLUGIN_ID
, e
, false);
306 // Set consensus sequence:
307 AlignmentModel consensusProvider
= getEditableConsensusArea().getAlignmentModel();
308 int id
= consensusProvider
.addSequence(CONSENSUS_NAME
);
309 consensusProvider
.insertTokensAt(id
, 0, AlignmentModelUtils
.charSequenceToTokenList(
310 sequenceNode
.getConsensusSequence().getString(), consensusProvider
.getTokenSet()));
311 //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
316 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
319 public void createPartControl(Composite parent
) {
320 SWTComponentFactory
.getInstance().getSWTComponent(getAlignmentsContainer(), parent
, SWT
.NONE
);
323 if (getEditorInput() instanceof AlignmentEditorInput
) {
324 if (((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid() != null) {
325 Sequence sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid());
326 //re-load into the current session if it is already persisted in the DB
327 if(sequenceNode
!=null && sequenceNode
.getId()!=0){
328 sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(sequenceNode
.getUuid());
330 readCDMData(sequenceNode
);
333 createTestContents(); // This case will removed after the test phase and an exception should probably be thrown.
337 throw new IllegalArgumentException("The editor input must have the type " +
338 AlignmentEditorInput
.class.getCanonicalName()); //TODO What should be done here?
343 private void updateStatusBar() {
344 IActionBars bars
= getEditorSite().getActionBars();
345 bars
.getStatusLineManager().setMessage("Edit mode: " +
346 (getReadsArea().getEditSettings().isInsert() ?
"Insert" : "Overwrite") + " " +
347 "Insertion in pherogram: " +
348 (getReadsArea().getEditSettings().isInsertLeftInDataArea() ?
"Left" : "Right"));
352 private SingleReadAlignment
.Shift
[] convertToCDMShifts(PherogramAreaModel model
) {
353 Iterator
<ShiftChange
> iterator
= model
.shiftChangeIterator();
354 List
<Shift
> shifts
= new ArrayList
<SingleReadAlignment
.Shift
>();
355 while (iterator
.hasNext()) {
356 ShiftChange shiftChange
= iterator
.next();
357 shifts
.add(new SingleReadAlignment
.Shift(shiftChange
.getBaseCallIndex(), shiftChange
.getShiftChange()));
359 return shifts
.toArray(new Shift
[]{});
364 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
367 public void doSave(IProgressMonitor monitor
) {
368 if (getEditorInput() instanceof AlignmentEditorInput
) {
369 String taskName
= "Saving alignment";
370 monitor
.beginTask(taskName
, 3);
372 //re-loading sequence to avoid session conflicts
373 Sequence sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid());
374 StringAdapter stringProvider
= new StringAdapter(getEditableConsensusArea().getAlignmentModel(), false); // Throws an exception if a token has more than one character.
376 // Write consensus sequence:
377 SequenceString consensusSequenceObj
= sequenceNode
.getConsensusSequence();
378 String newConsensusSequence
= stringProvider
.getSequence(
379 getEditableConsensusArea().getAlignmentModel().sequenceIDByName(CONSENSUS_NAME
));
380 if (consensusSequenceObj
== null) {
381 sequenceNode
.setConsensusSequence(SequenceString
.NewInstance(newConsensusSequence
));
384 consensusSequenceObj
.setString(newConsensusSequence
);
387 // Write single reads:
388 stringProvider
.setUnderlyingProvider(getReadsArea().getAlignmentModel());
389 sequenceNode
.getSingleReadAlignments().retainAll(cdmMap
.values()); // Remove all reads that are not in the alignment anymore.
390 Iterator
<Integer
> iterator
= getReadsArea().getAlignmentModel().sequenceIDIterator();
391 while (iterator
.hasNext()) {
392 int id
= iterator
.next();
393 SingleReadAlignment singleRead
= cdmMap
.get(id
);
394 if (singleRead
== null) {
395 throw new InternalError("Creating new reads from AlignmentEditor not implemented.");
396 //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?
397 //singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
400 singleRead
.setEditedSequence(stringProvider
.getSequence(id
));
402 PherogramArea pherogramArea
= getPherogramArea(id
);
403 if (pherogramArea
!= null) {
404 PherogramAreaModel model
= pherogramArea
.getModel();
405 singleRead
.setReverseComplement(model
.getPherogramProvider() instanceof ReverseComplementPherogramProvider
); // Works only if ReverseComplementPherogramProvider instances are not nested.
406 singleRead
.setShifts(convertToCDMShifts(getPherogramArea(id
).getModel()));
407 singleRead
.setFirstSeqPosition(model
.getFirstSeqPos());
408 singleRead
.setLeftCutPosition(model
.getLeftCutPosition());
409 singleRead
.setRightCutPosition(model
.getRightCutPosition());
413 if (!conversationHolder
.isBound()) {
414 conversationHolder
.bind();
418 // Commit the conversation and start a new transaction immediately:
419 conversationHolder
.commit(true);
425 firePropertyChange(PROP_DIRTY
);
428 //TODO Throw exception as soon as testing period which allows unlinked AlignmentEditor is over.
434 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
437 public void doSaveAs() {}
441 * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
444 public void init(IEditorSite site
, IEditorInput input
) throws PartInitException
{
447 System
.out
.println("AlignmentEditor.init(): " + ActionFactory
.COPY
.getId());
448 site
.getActionBars().setGlobalActionHandler(ActionFactory
.COPY
.getId(), new Action(ActionFactory
.COPY
.getId()) {
450 public boolean isEnabled() {
451 System
.out
.println("isEnabled()");
457 System
.out
.println("run");
465 * @see org.eclipse.ui.part.EditorPart#isDirty()
468 public boolean isDirty() {
473 private void setDirty() {
475 firePropertyChange(IEditorPart
.PROP_DIRTY
);
480 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
483 public boolean isSaveAsAllowed() {
484 return false; // "Save as" not allowed.
489 public void setFocus() {
490 if(conversationHolder
!=null){
491 conversationHolder
.bind();
496 public boolean isInsertMode() {
497 return getAlignmentsContainer().getEditSettings().isInsert();
501 public boolean isInsertLeftInPherogram() {
502 return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
506 public void toggleLeftRightInsertionInPherogram() {
507 getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
511 public void toggleInsertOverwrite() {
512 getAlignmentsContainer().getEditSettings().toggleInsert();
516 private String
cutPherogram(boolean left
) {
517 SelectionModel selection
= getReadsArea().getSelection();
518 if (selection
.getCursorHeight() != 1) {
519 return "Cutting pherograms is only possible if exactly one row is selected.";
522 PherogramArea pherogramArea
=
523 getPherogramArea(getReadsArea().getSequenceOrder().idByIndex(selection
.getCursorRow()));
524 if (pherogramArea
== null) {
525 return "There is no pherogram attached to the current sequence.";
529 if (pherogramArea
.setLeftCutPositionBySelection()) {
533 return "The left end of the selection lies outside the pherogram attached to this sequence.";
537 if (pherogramArea
.setRightCutPositionBySelection()) {
541 return "The right end of the selection lies outside the pherogram attached to this sequence.";
549 public String
cutPherogramLeft() {
550 return cutPherogram(true);
554 public String
cutPherogramRight() {
555 return cutPherogram(false);
559 public void reverseComplementSelectedSequences() {
560 SelectionModel selection
= getReadsArea().getSelection();
561 AlignmentModel
<?
> model
= getReadsArea().getAlignmentModel();
562 for (int row
= selection
.getFirstRow(); row
< selection
.getFirstRow() + selection
.getCursorHeight(); row
++) {
563 int sequenceID
= getReadsArea().getSequenceOrder().idByIndex(row
);
564 PherogramArea area
= getPherogramArea(sequenceID
);
565 PherogramAreaModel pherogramAlignmentModel
= area
.getModel();
566 AlignmentModelUtils
.reverseComplement(model
, sequenceID
,
567 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
568 pherogramAlignmentModel
.getLeftCutPosition()).getBeforeValidIndex(),
569 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
570 pherogramAlignmentModel
.getRightCutPosition()).getAfterValidIndex());
571 pherogramAlignmentModel
.reverseComplement();
577 * Recreates the whole consensus sequence from all single read sequences. The previous consensus
578 * sequence is overwritte.
580 @SuppressWarnings("unchecked")
581 public <T
> void createConsensusSequence() {
582 ConsensusSequenceArea area
= getConsensusHintDataArea();
583 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
584 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
585 int length
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
587 Collection
<T
> tokens
= new ArrayList
<T
>(length
);
588 for (int column
= 0; column
< length
; column
++) {
589 tokens
.add(model
.getTokenSet().tokenByRepresentation(area
.getConsensusToken(column
)));
592 model
.removeTokensAt(sequenceID
, 0, model
.getSequenceLength(sequenceID
));
593 model
.insertTokensAt(sequenceID
, 0, tokens
);
598 * Updates the current consensus sequence by replacing gaps by the according consensus tokens
599 * calculated from the single read sequences and extends the consensus sequence if necessary.
601 @SuppressWarnings("unchecked")
602 public <T
> void updateConsensusSequence() {
603 ConsensusSequenceArea area
= getConsensusHintDataArea();
604 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
605 TokenSet
<T
> tokenSet
= model
.getTokenSet();
606 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
607 int currentConsensusLength
= model
.getSequenceLength(sequenceID
);
608 int overallLength
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
610 // Replace gaps by new information:
611 for (int column
= 0; column
< currentConsensusLength
; column
++) {
612 if (tokenSet
.isGapToken(model
.getTokenAt(sequenceID
, column
))) {
613 T newToken
= tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
));
614 if (!tokenSet
.isGapToken(newToken
)) {
615 model
.setTokenAt(sequenceID
, column
, newToken
);
620 // Append additional tokens:
621 if (overallLength
> currentConsensusLength
) {
622 Collection
<T
> tokens
= new ArrayList
<T
>(overallLength
);
623 for (int column
= currentConsensusLength
; column
< overallLength
; column
++) {
624 tokens
.add(tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
)));
626 model
.appendTokens(sequenceID
, tokens
);
631 public static PherogramProvider
readPherogram(URI uri
) throws IOException
, UnsupportedChromatogramFormatException
{
632 PherogramProvider result
;
633 InputStream stream
= uri
.toURL().openStream();
635 result
= new BioJavaPherogramProvider(ChromatogramFactory
.create(stream
));
644 private String
newReadName() {
646 while (getReadsArea().getAlignmentModel().sequenceIDByName(DEFAULT_READ_NAME_PREFIX
+ index
)
647 != AlignmentModel
.NO_SEQUENCE_FOUND
) {
651 return DEFAULT_READ_NAME_PREFIX
+ index
;
655 public void addRead(URI pherogramURI
, boolean reverseComplemented
) throws IOException
, UnsupportedChromatogramFormatException
{
656 addRead(newReadName(), pherogramURI
, reverseComplemented
, null, null, null, null, null);
661 * Adds a new sequence with attached phergram data area to the reads alignment.
663 * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
664 * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
665 * and the base calls sequence are assumed.
667 * @param name the name of the new sequence
668 * @param pherogramURI the URI where the associated pherogram file is located
669 * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
670 * be added, {@code false} otherwise.
671 * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
672 * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
673 * @return the sequence ID of the added read
674 * @throws IOException if an error occurred when trying to read the pherogram file
675 * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
677 public int addRead(String name
, URI pherogramURI
, boolean reverseComplemented
, String editedSequence
,
678 Integer firstSeqPos
, Integer leftCutPos
, Integer rightCutPos
, SingleReadAlignment
.Shift
[] shifts
)
679 throws IOException
, UnsupportedChromatogramFormatException
{
681 AlignmentModel provider
= getReadsArea().getAlignmentModel();
682 PherogramProvider pherogramProvider
= null;
683 if (pherogramURI
!= null) {
684 pherogramProvider
= readPherogram(pherogramURI
); // Must happen before a sequence is added, because it might throw an exception.
685 if (reverseComplemented
) {
686 pherogramProvider
= new ReverseComplementPherogramProvider(pherogramProvider
);
691 provider
.addSequence(name
);
692 int id
= provider
.sequenceIDByName(name
);
694 // Set edited sequence:
695 Collection
<Object
> tokens
= null; // First save tokens in a collection to avoid GUI updated for each token.
696 if (editedSequence
!= null) {
697 tokens
= AlignmentModelUtils
.charSequenceToTokenList(editedSequence
, provider
.getTokenSet());
699 else if (pherogramProvider
!= null) { // Copy base call sequence into alignment:
700 tokens
= new ArrayList
<Object
>();
701 for (int i
= 0; i
< pherogramProvider
.getSequenceLength(); i
++) {
702 tokens
.add(provider
.getTokenSet().tokenByRepresentation(
703 Character
.toString(pherogramProvider
.getBaseCall(i
))));
708 if (tokens
!= null) { // If either an edited sequence or a pherogram URI was provided.
709 provider
.insertTokensAt(id
, 0, tokens
);
711 if (pherogramProvider
!= null) {
712 // Create pherogram area:
713 PherogramArea pherogramArea
= new PherogramArea(getReadsArea().getContentArea(),
714 new PherogramAreaModel(pherogramProvider
));
716 // Set position properties and shifts:
717 PherogramAreaModel model
= pherogramArea
.getModel();
718 if ((firstSeqPos
!= null) && (leftCutPos
!= null)) {
719 model
.setFirstSeqLeftCutPos(firstSeqPos
, leftCutPos
);
721 if (rightCutPos
!= null) {
722 model
.setRightCutPosition(rightCutPos
);
724 if ((shifts
!= null) && (shifts
.length
> 0)) {
725 for (int i
= 0; i
< shifts
.length
; i
++) {
726 model
.addShiftChange(shifts
[i
].position
, shifts
[i
].shift
);
731 // Add pherogram area to GUI:
732 pherogramArea
.addMouseListener(new PherogramMouseListener(pherogramArea
));
733 getReadsArea().getDataAreas().getSequenceAreas(id
).add(pherogramArea
);