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
.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
.model
.MessagingUtils
;
75 import eu
.etaxonomy
.taxeditor
.molecular
.TaxeditorMolecularPlugin
;
76 import eu
.etaxonomy
.taxeditor
.molecular
.handler
.ToggleInsertOverwriteHandler
;
77 import eu
.etaxonomy
.taxeditor
.molecular
.handler
.ToggleLeftRightInsertionHandler
;
78 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
79 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateLabelProvider
;
84 * Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
85 * a consensus sequence.
87 * The contained GUI components used to edit the alignment come from <a href="http://bioinfweb.info/LibrAlign/">LibrAlign</a>.
93 public class AlignmentEditor
extends EditorPart
{
94 public static final String ID
= "eu.etaxonomy.taxeditor.molecular.AlignmentEditor";
96 public static final int READS_AREA_INDEX
= 1;
97 public static final int EDITABLE_CONSENSUS_AREA_INDEX
= READS_AREA_INDEX
+ 1;
98 public static final int CONSENSUS_HINT_AREA_INDEX
= EDITABLE_CONSENSUS_AREA_INDEX
+ 1;
99 public static final int PHEROGRAM_AREA_INDEX
= 0;
100 public static final int CONSENSUS_DATA_AREA_INDEX
= 0;
101 public static final String DEFAULT_READ_NAME_PREFIX
= "Read ";
102 public static final String CONSENSUS_NAME
= "Consensus";
105 private final ConversationHolder conversationHolder
;
107 private final AlignmentModelChangeListener DIRTY_LISTENER
= new AlignmentModelChangeListener() {
109 public <T
> void afterTokenChange(TokenChangeEvent
<T
> e
) {
114 public <T
> void afterSequenceRenamed(SequenceRenamedEvent
<T
> e
) {
119 public <T
> void afterSequenceChange(SequenceChangeEvent
<T
> e
) {
124 public <T
, U
> void afterProviderChanged(AlignmentModel
<T
> oldProvider
,
125 AlignmentModel
<U
> newProvider
) { // Not expected.
131 private MultipleAlignmentsContainer alignmentsContainer
= null;
132 private final Map
<Integer
, SingleReadAlignment
> cdmMap
= new TreeMap
<Integer
, SingleReadAlignment
>(); //TODO Move this to ContigSequenceDataProvider
133 private boolean dirty
= false;
136 public AlignmentEditor() {
138 conversationHolder
= CdmStore
.createConversation();
139 //conversationHolder = null;
143 private void refreshToolbarElement(String id
) {
144 ICommandService commandService
=
145 (ICommandService
)PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService
.class);
146 if (commandService
!= null) {
147 commandService
.refreshElements(id
, Collections
.EMPTY_MAP
);
152 private void registerEditSettingListener(MultipleAlignmentsContainer container
) {
153 container
.getEditSettings().addListener(new EditSettingsListener() {
155 public void workingModeChanged(EditSettingsChangeEvent e
) {} // Currently nothing to do
158 public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e
) {
160 refreshToolbarElement(ToggleLeftRightInsertionHandler
.COMMAND_ID
);
164 public void insertChanged(EditSettingsChangeEvent e
) {
166 refreshToolbarElement(ToggleInsertOverwriteHandler
.COMMAND_ID
);
172 private AlignmentArea
createIndexArea(MultipleAlignmentsContainer container
, AlignmentArea labeledArea
) {
173 AlignmentArea result
= new AlignmentArea(container
);
174 result
.setAllowVerticalScrolling(false);
175 result
.getDataAreas().getTopAreas().add(new SequenceIndexArea(result
.getContentArea(), labeledArea
));
180 private AlignmentArea
createEditableAlignmentArea(MultipleAlignmentsContainer container
, boolean allowVerticalScrolling
) {
181 AlignmentArea result
= new AlignmentArea(container
);
182 result
.setAllowVerticalScrolling(allowVerticalScrolling
);
184 CharacterTokenSet tokenSet
= CharacterTokenSet
.newDNAInstance(); //TODO Should NUCLEOTIDE be used instead?
185 AlignmentModel
<Character
> provider
= new PackedAlignmentModel
<Character
>(tokenSet
);
186 result
.setAlignmentModel(provider
, false);
187 provider
.getChangeListeners().add(DIRTY_LISTENER
);
188 result
.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
194 private AlignmentArea
createConsensusHintArea(MultipleAlignmentsContainer container
,
195 AlignmentArea labeledArea
) {
197 AlignmentArea result
= new AlignmentArea(container
);
198 result
.setAllowVerticalScrolling(false);
199 result
.getDataAreas().getBottomAreas().add(
200 new ConsensusSequenceArea(result
.getContentArea(), labeledArea
));
205 private MultipleAlignmentsContainer
getAlignmentsContainer() {
206 if (alignmentsContainer
== null) {
207 alignmentsContainer
= new MultipleAlignmentsContainer();
209 AlignmentAreaList list
= alignmentsContainer
.getAlignmentAreas();
210 AlignmentArea readsArea
= createEditableAlignmentArea(alignmentsContainer
, true);
211 list
.add(createIndexArea(alignmentsContainer
, readsArea
));
212 list
.add(readsArea
); // Make sure READS_AREA_INDEX is correct.
213 list
.add(createEditableAlignmentArea(alignmentsContainer
, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
214 list
.add(createConsensusHintArea(alignmentsContainer
, readsArea
));
216 registerEditSettingListener(alignmentsContainer
);
218 return alignmentsContainer
;
222 public AlignmentArea
getReadsArea() {
223 return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX
);
227 private AlignmentArea
getEditableConsensusArea() {
228 return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX
);
232 public boolean hasPherogram(int sequenceID
) {
233 return getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).size() > PHEROGRAM_AREA_INDEX
;
237 public PherogramArea
getPherogramArea(int sequenceID
) {
238 if (hasPherogram(sequenceID
)) {
239 return (PherogramArea
)getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).get(PHEROGRAM_AREA_INDEX
);
247 private ConsensusSequenceArea
getConsensusHintDataArea() {
248 return (ConsensusSequenceArea
)getAlignmentsContainer().getAlignmentAreas().
249 get(CONSENSUS_HINT_AREA_INDEX
).getDataAreas().getBottomAreas().
250 get(CONSENSUS_DATA_AREA_INDEX
);
254 @Deprecated //TODO Remove as soon as testing period is over
255 private void createTestContents() {
258 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);
259 //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);
260 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);
262 // Add test consensus sequence:
263 AlignmentModel consensusModel
= getEditableConsensusArea().getAlignmentModel();
264 int id
= consensusModel
.addSequence(CONSENSUS_NAME
);
265 Collection
<Object
> tokens
= new ArrayList
<Object
>(); // First save tokens in a collection to avoid GUI updated for each token.
266 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("A"));
267 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("C"));
268 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("G"));
269 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("T"));
270 consensusModel
.insertTokensAt(id
, 0, tokens
);
272 catch (Exception e
) {
273 throw new RuntimeException(e
);
278 private void readCDMData(Sequence sequenceNode
) {
279 //TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
282 for (SingleReadAlignment singleReadAlignment
: sequenceNode
.getSingleReadAlignments()) {
284 SingleRead pherogramInfo
= singleReadAlignment
.getSingleRead();
286 if (pherogramInfo
.getPherogram() != null) {
287 uri
= MediaUtils
.getFirstMediaRepresentationPart(pherogramInfo
.getPherogram()).getUri();
289 int id
= addRead(DerivateLabelProvider
.getDerivateText(pherogramInfo
, conversationHolder
),
291 singleReadAlignment
.isReverseComplement(),
292 singleReadAlignment
.getEditedSequence(),
293 singleReadAlignment
.getFirstSeqPosition(),
294 singleReadAlignment
.getLeftCutPosition(),
295 singleReadAlignment
.getRightCutPosition(),
296 singleReadAlignment
.getShifts());
297 cdmMap
.put(id
, singleReadAlignment
);
299 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).
300 MessagingUtils
.errorDialog("Error", null, "A single read was skipped because of the following error:\n\n" +
301 e
.getLocalizedMessage(), TaxeditorMolecularPlugin
.PLUGIN_ID
, e
, false);
305 // Set consensus sequence:
306 AlignmentModel consensusProvider
= getEditableConsensusArea().getAlignmentModel();
307 int id
= consensusProvider
.addSequence(CONSENSUS_NAME
);
308 consensusProvider
.insertTokensAt(id
, 0, AlignmentModelUtils
.charSequenceToTokenList(
309 sequenceNode
.getConsensusSequence().getString(), consensusProvider
.getTokenSet()));
310 //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
315 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
318 public void createPartControl(Composite parent
) {
319 SWTComponentFactory
.getInstance().getSWTComponent(getAlignmentsContainer(), parent
, SWT
.NONE
);
322 if (getEditorInput() instanceof AlignmentEditorInput
) {
323 if (((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid() != null) {
324 Sequence sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid());
325 //re-load into the current session if it is already persisted in the DB
326 if(sequenceNode
!=null && sequenceNode
.getId()!=0){
327 sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(sequenceNode
.getUuid());
329 readCDMData(sequenceNode
);
332 createTestContents(); // This case will removed after the test phase and an exception should probably be thrown.
336 throw new IllegalArgumentException("The editor input must have the type " +
337 AlignmentEditorInput
.class.getCanonicalName()); //TODO What should be done here?
342 private void updateStatusBar() {
343 IActionBars bars
= getEditorSite().getActionBars();
344 bars
.getStatusLineManager().setMessage("Edit mode: " +
345 (getReadsArea().getEditSettings().isInsert() ?
"Insert" : "Overwrite") + " " +
346 "Insertion in pherogram: " +
347 (getReadsArea().getEditSettings().isInsertLeftInDataArea() ?
"Left" : "Right"));
351 private SingleReadAlignment
.Shift
[] convertToCDMShifts(PherogramAreaModel model
) {
352 Iterator
<ShiftChange
> iterator
= model
.shiftChangeIterator();
353 List
<Shift
> shifts
= new ArrayList
<SingleReadAlignment
.Shift
>();
354 while (iterator
.hasNext()) {
355 ShiftChange shiftChange
= iterator
.next();
356 shifts
.add(new SingleReadAlignment
.Shift(shiftChange
.getBaseCallIndex(), shiftChange
.getShiftChange()));
358 return shifts
.toArray(new Shift
[]{});
363 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
366 public void doSave(IProgressMonitor monitor
) {
367 if (getEditorInput() instanceof AlignmentEditorInput
) {
368 String taskName
= "Saving alignment";
369 monitor
.beginTask(taskName
, 3);
371 //re-loading sequence to avoid session conflicts
372 Sequence sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(((AlignmentEditorInput
)getEditorInput()).getSequenceNodeUuid());
373 StringAdapter stringProvider
= new StringAdapter(getEditableConsensusArea().getAlignmentModel(), false); // Throws an exception if a token has more than one character.
375 // Write consensus sequence:
376 SequenceString consensusSequenceObj
= sequenceNode
.getConsensusSequence();
377 String newConsensusSequence
= stringProvider
.getSequence(
378 getEditableConsensusArea().getAlignmentModel().sequenceIDByName(CONSENSUS_NAME
));
379 if (consensusSequenceObj
== null) {
380 sequenceNode
.setConsensusSequence(SequenceString
.NewInstance(newConsensusSequence
));
383 consensusSequenceObj
.setString(newConsensusSequence
);
386 // Write single reads:
387 stringProvider
.setUnderlyingProvider(getReadsArea().getAlignmentModel());
388 sequenceNode
.getSingleReadAlignments().retainAll(cdmMap
.values()); // Remove all reads that are not in the alignment anymore.
389 Iterator
<Integer
> iterator
= getReadsArea().getAlignmentModel().sequenceIDIterator();
390 while (iterator
.hasNext()) {
391 int id
= iterator
.next();
392 SingleReadAlignment singleRead
= cdmMap
.get(id
);
393 if (singleRead
== null) {
394 throw new InternalError("Creating new reads from AlignmentEditor not implemented.");
395 //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?
396 //singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
399 singleRead
.setEditedSequence(stringProvider
.getSequence(id
));
401 PherogramAreaModel model
= getPherogramArea(id
).getModel();
402 singleRead
.setReverseComplement(model
.getPherogramProvider() instanceof ReverseComplementPherogramProvider
); // Works only if ReverseComplementPherogramProvider instances are not nested.
403 singleRead
.setShifts(convertToCDMShifts(getPherogramArea(id
).getModel()));
404 singleRead
.setFirstSeqPosition(model
.getFirstSeqPos());
405 singleRead
.setLeftCutPosition(model
.getLeftCutPosition());
406 singleRead
.setRightCutPosition(model
.getRightCutPosition());
409 if (!conversationHolder
.isBound()) {
410 conversationHolder
.bind();
414 // Commit the conversation and start a new transaction immediately:
415 conversationHolder
.commit(true);
421 firePropertyChange(PROP_DIRTY
);
424 //TODO Throw exception as soon as testing period which allows unlinked AlignmentEditor is over.
430 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
433 public void doSaveAs() {}
437 * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
440 public void init(IEditorSite site
, IEditorInput input
) throws PartInitException
{
447 * @see org.eclipse.ui.part.EditorPart#isDirty()
450 public boolean isDirty() {
455 private void setDirty() {
457 firePropertyChange(IEditorPart
.PROP_DIRTY
);
462 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
465 public boolean isSaveAsAllowed() {
466 return false; // "Save as" not allowed.
471 public void setFocus() {
472 if(conversationHolder
!=null){
473 conversationHolder
.bind();
478 public boolean isInsertMode() {
479 return getAlignmentsContainer().getEditSettings().isInsert();
483 public boolean isInsertLeftInPherogram() {
484 return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
488 public void toggleLeftRightInsertionInPherogram() {
489 getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
493 public void toggleInsertOverwrite() {
494 getAlignmentsContainer().getEditSettings().toggleInsert();
498 private String
cutPherogram(boolean left
) {
499 SelectionModel selection
= getReadsArea().getSelection();
500 if (selection
.getCursorHeight() != 1) {
501 return "Cutting pherograms is only possible if exactly one row is selected.";
504 PherogramArea pherogramArea
=
505 getPherogramArea(getReadsArea().getSequenceOrder().idByIndex(selection
.getCursorRow()));
506 if (pherogramArea
== null) {
507 return "There is no pherogram attached to the current sequence.";
511 if (pherogramArea
.setLeftCutPositionBySelection()) {
515 return "The left end of the selection lies outside the pherogram attached to this sequence.";
519 if (pherogramArea
.setRightCutPositionBySelection()) {
523 return "The right end of the selection lies outside the pherogram attached to this sequence.";
531 public String
cutPherogramLeft() {
532 return cutPherogram(true);
536 public String
cutPherogramRight() {
537 return cutPherogram(false);
541 public void reverseComplementSelectedSequences() {
542 SelectionModel selection
= getReadsArea().getSelection();
543 AlignmentModel
<?
> model
= getReadsArea().getAlignmentModel();
544 for (int row
= selection
.getFirstRow(); row
< selection
.getFirstRow() + selection
.getCursorHeight(); row
++) {
545 int sequenceID
= getReadsArea().getSequenceOrder().idByIndex(row
);
546 PherogramArea area
= getPherogramArea(sequenceID
);
547 PherogramAreaModel pherogramAlignmentModel
= area
.getModel();
548 AlignmentModelUtils
.reverseComplement(model
, sequenceID
,
549 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
550 pherogramAlignmentModel
.getLeftCutPosition()).getBeforeValidIndex(),
551 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
552 pherogramAlignmentModel
.getRightCutPosition()).getAfterValidIndex());
553 pherogramAlignmentModel
.reverseComplement();
559 * Recreates the whole consensus sequence from all single read sequences. The previous consensus
560 * sequence is overwritte.
562 @SuppressWarnings("unchecked")
563 public <T
> void createConsensusSequence() {
564 ConsensusSequenceArea area
= getConsensusHintDataArea();
565 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
566 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
567 int length
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
569 Collection
<T
> tokens
= new ArrayList
<T
>(length
);
570 for (int column
= 0; column
< length
; column
++) {
571 tokens
.add(model
.getTokenSet().tokenByRepresentation(area
.getConsensusToken(column
)));
574 model
.removeTokensAt(sequenceID
, 0, model
.getSequenceLength(sequenceID
));
575 model
.insertTokensAt(sequenceID
, 0, tokens
);
580 * Updates the current consensus sequence by replacing gaps by the according consensus tokens
581 * calculated from the single read sequences and extends the consensus sequence if necessary.
583 @SuppressWarnings("unchecked")
584 public <T
> void updateConsensusSequence() {
585 ConsensusSequenceArea area
= getConsensusHintDataArea();
586 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
587 TokenSet
<T
> tokenSet
= model
.getTokenSet();
588 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
589 int currentConsensusLength
= model
.getSequenceLength(sequenceID
);
590 int overallLength
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
592 // Replace gaps by new information:
593 for (int column
= 0; column
< currentConsensusLength
; column
++) {
594 if (tokenSet
.isGapToken(model
.getTokenAt(sequenceID
, column
))) {
595 T newToken
= tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
));
596 if (!tokenSet
.isGapToken(newToken
)) {
597 model
.setTokenAt(sequenceID
, column
, newToken
);
602 // Append additional tokens:
603 if (overallLength
> currentConsensusLength
) {
604 Collection
<T
> tokens
= new ArrayList
<T
>(overallLength
);
605 for (int column
= currentConsensusLength
; column
< overallLength
; column
++) {
606 tokens
.add(tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
)));
608 model
.appendTokens(sequenceID
, tokens
);
613 public static PherogramProvider
readPherogram(URI uri
) throws IOException
, UnsupportedChromatogramFormatException
{
614 PherogramProvider result
;
615 InputStream stream
= uri
.toURL().openStream();
617 result
= new BioJavaPherogramProvider(ChromatogramFactory
.create(stream
));
626 private String
newReadName() {
628 while (getReadsArea().getAlignmentModel().sequenceIDByName(DEFAULT_READ_NAME_PREFIX
+ index
)
629 != AlignmentModel
.NO_SEQUENCE_FOUND
) {
633 return DEFAULT_READ_NAME_PREFIX
+ index
;
637 public void addRead(URI pherogramURI
, boolean reverseComplemented
) throws IOException
, UnsupportedChromatogramFormatException
{
638 addRead(newReadName(), pherogramURI
, reverseComplemented
, null, null, null, null, null);
643 * Adds a new sequence with attached phergram data area to the reads alignment.
645 * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
646 * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
647 * and the base calls sequence are assumed.
649 * @param name the name of the new sequence
650 * @param pherogramURI the URI where the associated pherogram file is located
651 * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
652 * be added, {@code false} otherwise.
653 * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
654 * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
655 * @return the sequence ID of the added read
656 * @throws IOException if an error occurred when trying to read the pherogram file
657 * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
659 public int addRead(String name
, URI pherogramURI
, boolean reverseComplemented
, String editedSequence
,
660 Integer firstSeqPos
, Integer leftCutPos
, Integer rightCutPos
, SingleReadAlignment
.Shift
[] shifts
)
661 throws IOException
, UnsupportedChromatogramFormatException
{
663 AlignmentModel provider
= getReadsArea().getAlignmentModel();
664 PherogramProvider pherogramProvider
= null;
665 if (pherogramURI
!= null) {
666 pherogramProvider
= readPherogram(pherogramURI
); // Must happen before a sequence is added, because it might throw an exception.
667 if (reverseComplemented
) {
668 pherogramProvider
= new ReverseComplementPherogramProvider(pherogramProvider
);
673 provider
.addSequence(name
);
674 int id
= provider
.sequenceIDByName(name
);
676 // Set edited sequence:
677 Collection
<Object
> tokens
= null; // First save tokens in a collection to avoid GUI updated for each token.
678 if (editedSequence
!= null) {
679 tokens
= AlignmentModelUtils
.charSequenceToTokenList(editedSequence
, provider
.getTokenSet());
681 else if (pherogramProvider
!= null) { // Copy base call sequence into alignment:
682 tokens
= new ArrayList
<Object
>();
683 for (int i
= 0; i
< pherogramProvider
.getSequenceLength(); i
++) {
684 tokens
.add(provider
.getTokenSet().tokenByRepresentation(
685 Character
.toString(pherogramProvider
.getBaseCall(i
))));
690 if (tokens
!= null) { // If either an edited sequence or a pherogram URI was provided.
691 provider
.insertTokensAt(id
, 0, tokens
);
692 // Create pherogram area:
693 PherogramArea pherogramArea
= new PherogramArea(getReadsArea().getContentArea(),
694 new PherogramAreaModel(pherogramProvider
));
696 // Set position properties and shifts:
697 PherogramAreaModel model
= pherogramArea
.getModel();
698 if ((firstSeqPos
!= null) && (leftCutPos
!= null)) {
699 model
.setFirstSeqLeftCutPos(firstSeqPos
, leftCutPos
);
701 if (rightCutPos
!= null) {
702 model
.setRightCutPosition(rightCutPos
);
704 if ((shifts
!= null) && (shifts
.length
> 0)) {
705 for (int i
= 0; i
< shifts
.length
; i
++) {
706 model
.addShiftChange(shifts
[i
].position
, shifts
[i
].shift
);
711 // Add pherogram area to GUI:
712 pherogramArea
.addMouseListener(new PherogramMouseListener(pherogramArea
));
713 getReadsArea().getDataAreas().getSequenceAreas(id
).add(pherogramArea
);