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
.editor
.molecular
;
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
.swt
.SWT
;
56 import org
.eclipse
.swt
.widgets
.Composite
;
57 import org
.eclipse
.ui
.IActionBars
;
58 import org
.eclipse
.ui
.IEditorInput
;
59 import org
.eclipse
.ui
.IEditorPart
;
60 import org
.eclipse
.ui
.IEditorSite
;
61 import org
.eclipse
.ui
.PartInitException
;
62 import org
.eclipse
.ui
.PlatformUI
;
63 import org
.eclipse
.ui
.commands
.ICommandService
;
64 import org
.eclipse
.ui
.part
.EditorPart
;
66 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
67 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
68 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
69 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
70 import eu
.etaxonomy
.cdm
.model
.molecular
.SequenceString
;
71 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
72 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleReadAlignment
;
73 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleReadAlignment
.Shift
;
74 import eu
.etaxonomy
.taxeditor
.editor
.handler
.alignmenteditor
.ToggleInsertOverwriteHandler
;
75 import eu
.etaxonomy
.taxeditor
.editor
.handler
.alignmenteditor
.ToggleLeftRightInsertionHandler
;
76 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
77 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
78 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateLabelProvider
;
83 * Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
84 * a consensus sequence.
86 * The contained GUI components used to edit the alignment come from <a href="http://bioinfweb.info/LibrAlign/">LibrAlign</a>.
92 public class AlignmentEditor
extends EditorPart
{
93 public static final String ID
= "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor";
95 public static final int READS_AREA_INDEX
= 1;
96 public static final int EDITABLE_CONSENSUS_AREA_INDEX
= READS_AREA_INDEX
+ 1;
97 public static final int CONSENSUS_HINT_AREA_INDEX
= EDITABLE_CONSENSUS_AREA_INDEX
+ 1;
98 public static final int PHEROGRAM_AREA_INDEX
= 0;
99 public static final int CONSENSUS_DATA_AREA_INDEX
= 0;
100 public static final String DEFAULT_READ_NAME_PREFIX
= "Read ";
101 public static final String CONSENSUS_NAME
= "Consensus";
104 private final ConversationHolder conversationHolder
;
106 private final AlignmentModelChangeListener DIRTY_LISTENER
= new AlignmentModelChangeListener() {
108 public <T
> void afterTokenChange(TokenChangeEvent
<T
> e
) {
113 public <T
> void afterSequenceRenamed(SequenceRenamedEvent
<T
> e
) {
118 public <T
> void afterSequenceChange(SequenceChangeEvent
<T
> e
) {
123 public <T
, U
> void afterProviderChanged(AlignmentModel
<T
> oldProvider
,
124 AlignmentModel
<U
> newProvider
) { // Not expected.
130 private MultipleAlignmentsContainer alignmentsContainer
= null;
131 private final Map
<Integer
, SingleReadAlignment
> cdmMap
= new TreeMap
<Integer
, SingleReadAlignment
>(); //TODO Move this to ContigSequenceDataProvider
132 private boolean dirty
= false;
135 public AlignmentEditor() {
137 conversationHolder
= CdmStore
.createConversation();
138 //conversationHolder = null;
142 private void refreshToolbarElement(String id
) {
143 ICommandService commandService
=
144 (ICommandService
)PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService
.class);
145 if (commandService
!= null) {
146 commandService
.refreshElements(id
, Collections
.EMPTY_MAP
);
151 private void registerEditSettingListener(MultipleAlignmentsContainer container
) {
152 container
.getEditSettings().addListener(new EditSettingsListener() {
154 public void workingModeChanged(EditSettingsChangeEvent e
) {} // Currently nothing to do
157 public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e
) {
159 refreshToolbarElement(ToggleLeftRightInsertionHandler
.COMMAND_ID
);
163 public void insertChanged(EditSettingsChangeEvent e
) {
165 refreshToolbarElement(ToggleInsertOverwriteHandler
.COMMAND_ID
);
171 private AlignmentArea
createIndexArea(MultipleAlignmentsContainer container
, AlignmentArea labeledArea
) {
172 AlignmentArea result
= new AlignmentArea(container
);
173 result
.setAllowVerticalScrolling(false);
174 result
.getDataAreas().getTopAreas().add(new SequenceIndexArea(result
.getContentArea(), labeledArea
));
179 private AlignmentArea
createEditableAlignmentArea(MultipleAlignmentsContainer container
, boolean allowVerticalScrolling
) {
180 AlignmentArea result
= new AlignmentArea(container
);
181 result
.setAllowVerticalScrolling(allowVerticalScrolling
);
183 CharacterTokenSet tokenSet
= CharacterTokenSet
.newDNAInstance(); //TODO Should NUCLEOTIDE be used instead?
184 AlignmentModel
<Character
> provider
= new PackedAlignmentModel
<Character
>(tokenSet
);
185 result
.setAlignmentModel(provider
, false);
186 provider
.getChangeListeners().add(DIRTY_LISTENER
);
187 result
.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
193 private AlignmentArea
createConsensusHintArea(MultipleAlignmentsContainer container
,
194 AlignmentArea labeledArea
) {
196 AlignmentArea result
= new AlignmentArea(container
);
197 result
.setAllowVerticalScrolling(false);
198 result
.getDataAreas().getBottomAreas().add(
199 new ConsensusSequenceArea(result
.getContentArea(), labeledArea
));
204 private MultipleAlignmentsContainer
getAlignmentsContainer() {
205 if (alignmentsContainer
== null) {
206 alignmentsContainer
= new MultipleAlignmentsContainer();
208 AlignmentAreaList list
= alignmentsContainer
.getAlignmentAreas();
209 AlignmentArea readsArea
= createEditableAlignmentArea(alignmentsContainer
, true);
210 list
.add(createIndexArea(alignmentsContainer
, readsArea
));
211 list
.add(readsArea
); // Make sure READS_AREA_INDEX is correct.
212 list
.add(createEditableAlignmentArea(alignmentsContainer
, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
213 list
.add(createConsensusHintArea(alignmentsContainer
, readsArea
));
215 registerEditSettingListener(alignmentsContainer
);
217 return alignmentsContainer
;
221 public AlignmentArea
getReadsArea() {
222 return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX
);
226 private AlignmentArea
getEditableConsensusArea() {
227 return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX
);
231 public boolean hasPherogram(int sequenceID
) {
232 return getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).size() > PHEROGRAM_AREA_INDEX
;
236 public PherogramArea
getPherogramArea(int sequenceID
) {
237 if (hasPherogram(sequenceID
)) {
238 return (PherogramArea
)getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).get(PHEROGRAM_AREA_INDEX
);
246 private ConsensusSequenceArea
getConsensusHintDataArea() {
247 return (ConsensusSequenceArea
)getAlignmentsContainer().getAlignmentAreas().
248 get(CONSENSUS_HINT_AREA_INDEX
).getDataAreas().getBottomAreas().
249 get(CONSENSUS_DATA_AREA_INDEX
);
253 @Deprecated //TODO Remove as soon as testing period is over
254 private void createTestContents() {
257 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);
258 //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);
259 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);
261 // Add test consensus sequence:
262 AlignmentModel consensusModel
= getEditableConsensusArea().getAlignmentModel();
263 int id
= consensusModel
.addSequence(CONSENSUS_NAME
);
264 Collection
<Object
> tokens
= new ArrayList
<Object
>(); // First save tokens in a collection to avoid GUI updated for each token.
265 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("A"));
266 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("C"));
267 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("G"));
268 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("T"));
269 consensusModel
.insertTokensAt(id
, 0, tokens
);
271 catch (Exception e
) {
272 throw new RuntimeException(e
);
277 private void readCDMData(Sequence sequenceNode
) {
278 //TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
281 for (SingleReadAlignment singleReadAlignment
: sequenceNode
.getSingleReadAlignments()) {
283 SingleRead pherogramInfo
= singleReadAlignment
.getSingleRead();
285 if (pherogramInfo
.getPherogram() != null) {
286 uri
= MediaUtils
.getFirstMediaRepresentationPart(pherogramInfo
.getPherogram()).getUri();
288 int id
= addRead(DerivateLabelProvider
.getDerivateText(pherogramInfo
, conversationHolder
),
290 singleReadAlignment
.isReverseComplement(),
291 singleReadAlignment
.getEditedSequence(),
292 singleReadAlignment
.getFirstSeqPosition(),
293 singleReadAlignment
.getLeftCutPosition(),
294 singleReadAlignment
.getRightCutPosition(),
295 singleReadAlignment
.getShifts());
296 cdmMap
.put(id
, singleReadAlignment
);
298 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).
299 MessagingUtils
.errorDialog("Error", null, "A single read was skipped because of the following error:\n\n" +
300 e
.getLocalizedMessage(), "eu.etaxonomy.taxeditor.editor", e
, false);
304 // Set consensus sequence:
305 AlignmentModel consensusProvider
= getEditableConsensusArea().getAlignmentModel();
306 int id
= consensusProvider
.addSequence(CONSENSUS_NAME
);
307 consensusProvider
.insertTokensAt(id
, 0, AlignmentModelUtils
.charSequenceToTokenList(
308 sequenceNode
.getConsensusSequence().getString(), consensusProvider
.getTokenSet()));
309 //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
314 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
317 public void createPartControl(Composite parent
) {
318 SWTComponentFactory
.getInstance().getSWTComponent(getAlignmentsContainer(), parent
, SWT
.NONE
);
321 if (getEditorInput() instanceof AlignmentEditorInput
) {
322 if (((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid() != null) {
323 Sequence sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid());
324 //re-load into the current session if it is already persisted in the DB
325 if(sequenceNode
!=null && sequenceNode
.getId()!=0){
326 sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(sequenceNode
.getUuid());
328 readCDMData(sequenceNode
);
331 createTestContents(); // This case will removed after the test phase and an exception should probably be thrown.
335 throw new IllegalArgumentException("The editor input must have the type " +
336 AlignmentEditorInput
.class.getCanonicalName()); //TODO What should be done here?
341 private void updateStatusBar() {
342 IActionBars bars
= getEditorSite().getActionBars();
343 bars
.getStatusLineManager().setMessage("Edit mode: " +
344 (getReadsArea().getEditSettings().isInsert() ?
"Insert" : "Overwrite") + " " +
345 "Insertion in pherogram: " +
346 (getReadsArea().getEditSettings().isInsertLeftInDataArea() ?
"Left" : "Right"));
350 private SingleReadAlignment
.Shift
[] convertToCDMShifts(PherogramAreaModel model
) {
351 Iterator
<ShiftChange
> iterator
= model
.shiftChangeIterator();
352 List
<Shift
> shifts
= new ArrayList
<SingleReadAlignment
.Shift
>();
353 while (iterator
.hasNext()) {
354 ShiftChange shiftChange
= iterator
.next();
355 shifts
.add(new SingleReadAlignment
.Shift(shiftChange
.getBaseCallIndex(), shiftChange
.getShiftChange()));
357 return shifts
.toArray(new Shift
[]{});
362 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
365 public void doSave(IProgressMonitor monitor
) {
366 if (getEditorInput() instanceof AlignmentEditorInput
) {
367 String taskName
= "Saving alignment";
368 monitor
.beginTask(taskName
, 3);
370 //re-loading sequence to avoid session conflicts
371 Sequence sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid());
372 StringAdapter stringProvider
= new StringAdapter(getEditableConsensusArea().getAlignmentModel(), false); // Throws an exception if a token has more than one character.
374 // Write consensus sequence:
375 SequenceString consensusSequenceObj
= sequenceNode
.getConsensusSequence();
376 String newConsensusSequence
= stringProvider
.getSequence(
377 getEditableConsensusArea().getAlignmentModel().sequenceIDByName(CONSENSUS_NAME
));
378 if (consensusSequenceObj
== null) {
379 sequenceNode
.setConsensusSequence(SequenceString
.NewInstance(newConsensusSequence
));
382 consensusSequenceObj
.setString(newConsensusSequence
);
385 // Write single reads:
386 stringProvider
.setUnderlyingProvider(getReadsArea().getAlignmentModel());
387 sequenceNode
.getSingleReadAlignments().retainAll(cdmMap
.values()); // Remove all reads that are not in the alignment anymore.
388 Iterator
<Integer
> iterator
= getReadsArea().getAlignmentModel().sequenceIDIterator();
389 while (iterator
.hasNext()) {
390 int id
= iterator
.next();
391 SingleReadAlignment singleRead
= cdmMap
.get(id
);
392 if (singleRead
== null) {
393 throw new InternalError("Creating new reads from AlignmentEditor not implemented.");
394 //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?
395 //singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
398 singleRead
.setEditedSequence(stringProvider
.getSequence(id
));
400 PherogramAreaModel model
= getPherogramArea(id
).getModel();
401 singleRead
.setReverseComplement(model
.getPherogramProvider() instanceof ReverseComplementPherogramProvider
); // Works only if ReverseComplementPherogramProvider instances are not nested.
402 singleRead
.setShifts(convertToCDMShifts(getPherogramArea(id
).getModel()));
403 singleRead
.setFirstSeqPosition(model
.getFirstSeqPos());
404 singleRead
.setLeftCutPosition(model
.getLeftCutPosition());
405 singleRead
.setRightCutPosition(model
.getRightCutPosition());
408 if (!conversationHolder
.isBound()) {
409 conversationHolder
.bind();
413 // Commit the conversation and start a new transaction immediately:
414 conversationHolder
.commit(true);
420 firePropertyChange(PROP_DIRTY
);
423 //TODO Throw exception as soon as testing period which allows unlinked AlignmentEditor is over.
429 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
432 public void doSaveAs() {}
436 * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
439 public void init(IEditorSite site
, IEditorInput input
) throws PartInitException
{
446 * @see org.eclipse.ui.part.EditorPart#isDirty()
449 public boolean isDirty() {
454 private void setDirty() {
456 firePropertyChange(IEditorPart
.PROP_DIRTY
);
461 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
464 public boolean isSaveAsAllowed() {
465 return false; // "Save as" not allowed.
470 public void setFocus() {
471 if(conversationHolder
!=null){
472 conversationHolder
.bind();
477 public boolean isInsertMode() {
478 return getAlignmentsContainer().getEditSettings().isInsert();
482 public boolean isInsertLeftInPherogram() {
483 return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
487 public void toggleLeftRightInsertionInPherogram() {
488 getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
492 public void toggleInsertOverwrite() {
493 getAlignmentsContainer().getEditSettings().toggleInsert();
497 private String
cutPherogram(boolean left
) {
498 SelectionModel selection
= getReadsArea().getSelection();
499 if (selection
.getCursorHeight() != 1) {
500 return "Cutting pherograms is only possible if exactly one row is selected.";
503 PherogramArea pherogramArea
=
504 getPherogramArea(getReadsArea().getSequenceOrder().idByIndex(selection
.getCursorRow()));
505 if (pherogramArea
== null) {
506 return "There is no pherogram attached to the current sequence.";
510 if (pherogramArea
.setLeftCutPositionBySelection()) {
514 return "The left end of the selection lies outside the pherogram attached to this sequence.";
518 if (pherogramArea
.setRightCutPositionBySelection()) {
522 return "The right end of the selection lies outside the pherogram attached to this sequence.";
530 public String
cutPherogramLeft() {
531 return cutPherogram(true);
535 public String
cutPherogramRight() {
536 return cutPherogram(false);
540 public void reverseComplementSelectedSequences() {
541 SelectionModel selection
= getReadsArea().getSelection();
542 AlignmentModel
<?
> model
= getReadsArea().getAlignmentModel();
543 for (int row
= selection
.getFirstRow(); row
< selection
.getFirstRow() + selection
.getCursorHeight(); row
++) {
544 int sequenceID
= getReadsArea().getSequenceOrder().idByIndex(row
);
545 PherogramArea area
= getPherogramArea(sequenceID
);
546 PherogramAreaModel pherogramAlignmentModel
= area
.getModel();
547 AlignmentModelUtils
.reverseComplement(model
, sequenceID
,
548 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
549 pherogramAlignmentModel
.getLeftCutPosition()).getBeforeValidIndex(),
550 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
551 pherogramAlignmentModel
.getRightCutPosition()).getAfterValidIndex());
552 pherogramAlignmentModel
.reverseComplement();
558 * Recreates the whole consensus sequence from all single read sequences. The previous consensus
559 * sequence is overwritte.
561 @SuppressWarnings("unchecked")
562 public <T
> void createConsensusSequence() {
563 ConsensusSequenceArea area
= getConsensusHintDataArea();
564 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
565 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
566 int length
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
568 Collection
<T
> tokens
= new ArrayList
<T
>(length
);
569 for (int column
= 0; column
< length
; column
++) {
570 tokens
.add(model
.getTokenSet().tokenByRepresentation(area
.getConsensusToken(column
)));
573 model
.removeTokensAt(sequenceID
, 0, model
.getSequenceLength(sequenceID
));
574 model
.insertTokensAt(sequenceID
, 0, tokens
);
579 * Updates the current consensus sequence by replacing gaps by the according consensus tokens
580 * calculated from the single read sequences and extends the consensus sequence if necessary.
582 @SuppressWarnings("unchecked")
583 public <T
> void updateConsensusSequence() {
584 ConsensusSequenceArea area
= getConsensusHintDataArea();
585 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
586 TokenSet
<T
> tokenSet
= model
.getTokenSet();
587 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
588 int currentConsensusLength
= model
.getSequenceLength(sequenceID
);
589 int overallLength
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
591 // Replace gaps by new information:
592 for (int column
= 0; column
< currentConsensusLength
; column
++) {
593 if (tokenSet
.isGapToken(model
.getTokenAt(sequenceID
, column
))) {
594 T newToken
= tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
));
595 if (!tokenSet
.isGapToken(newToken
)) {
596 model
.setTokenAt(sequenceID
, column
, newToken
);
601 // Append additional tokens:
602 if (overallLength
> currentConsensusLength
) {
603 Collection
<T
> tokens
= new ArrayList
<T
>(overallLength
);
604 for (int column
= currentConsensusLength
; column
< overallLength
; column
++) {
605 tokens
.add(tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
)));
607 model
.appendTokens(sequenceID
, tokens
);
612 public static PherogramProvider
readPherogram(URI uri
) throws IOException
, UnsupportedChromatogramFormatException
{
613 PherogramProvider result
;
614 InputStream stream
= uri
.toURL().openStream();
616 result
= new BioJavaPherogramProvider(ChromatogramFactory
.create(stream
));
625 private String
newReadName() {
627 while (getReadsArea().getAlignmentModel().sequenceIDByName(DEFAULT_READ_NAME_PREFIX
+ index
)
628 != AlignmentModel
.NO_SEQUENCE_FOUND
) {
632 return DEFAULT_READ_NAME_PREFIX
+ index
;
636 public void addRead(URI pherogramURI
, boolean reverseComplemented
) throws IOException
, UnsupportedChromatogramFormatException
{
637 addRead(newReadName(), pherogramURI
, reverseComplemented
, null, null, null, null, null);
642 * Adds a new sequence with attached phergram data area to the reads alignment.
644 * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
645 * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
646 * and the base calls sequence are assumed.
648 * @param name the name of the new sequence
649 * @param pherogramURI the URI where the associated pherogram file is located
650 * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
651 * be added, {@code false} otherwise.
652 * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
653 * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
654 * @return the sequence ID of the added read
655 * @throws IOException if an error occurred when trying to read the pherogram file
656 * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
658 public int addRead(String name
, URI pherogramURI
, boolean reverseComplemented
, String editedSequence
,
659 Integer firstSeqPos
, Integer leftCutPos
, Integer rightCutPos
, SingleReadAlignment
.Shift
[] shifts
)
660 throws IOException
, UnsupportedChromatogramFormatException
{
662 AlignmentModel provider
= getReadsArea().getAlignmentModel();
663 PherogramProvider pherogramProvider
= null;
664 if (pherogramURI
!= null) {
665 pherogramProvider
= readPherogram(pherogramURI
); // Must happen before a sequence is added, because it might throw an exception.
666 if (reverseComplemented
) {
667 pherogramProvider
= new ReverseComplementPherogramProvider(pherogramProvider
);
672 provider
.addSequence(name
);
673 int id
= provider
.sequenceIDByName(name
);
675 // Set edited sequence:
676 Collection
<Object
> tokens
= null; // First save tokens in a collection to avoid GUI updated for each token.
677 if (editedSequence
!= null) {
678 tokens
= AlignmentModelUtils
.charSequenceToTokenList(editedSequence
, provider
.getTokenSet());
680 else if (pherogramProvider
!= null) { // Copy base call sequence into alignment:
681 tokens
= new ArrayList
<Object
>();
682 for (int i
= 0; i
< pherogramProvider
.getSequenceLength(); i
++) {
683 tokens
.add(provider
.getTokenSet().tokenByRepresentation(
684 Character
.toString(pherogramProvider
.getBaseCall(i
))));
689 if (tokens
!= null) { // If either an edited sequence or a pherogram URI was provided.
690 provider
.insertTokensAt(id
, 0, tokens
);
691 // Create pherogram area:
692 PherogramArea pherogramArea
= new PherogramArea(getReadsArea().getContentArea(),
693 new PherogramAreaModel(pherogramProvider
));
695 // Set position properties and shifts:
696 PherogramAreaModel model
= pherogramArea
.getModel();
697 if ((firstSeqPos
!= null) && (leftCutPos
!= null)) {
698 model
.setFirstSeqLeftCutPos(firstSeqPos
, leftCutPos
);
700 if (rightCutPos
!= null) {
701 model
.setRightCutPosition(rightCutPos
);
703 if ((shifts
!= null) && (shifts
.length
> 0)) {
704 for (int i
= 0; i
< shifts
.length
; i
++) {
705 model
.addShiftChange(shifts
[i
].position
, shifts
[i
].shift
);
710 // Add pherogram area to GUI:
711 pherogramArea
.addMouseListener(new PherogramMouseListener(pherogramArea
));
712 getReadsArea().getDataAreas().getSequenceAreas(id
).add(pherogramArea
);