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
.jphyloio
.events
.TokenSetType
;
14 import info
.bioinfweb
.libralign
.alignmentarea
.AlignmentArea
;
15 import info
.bioinfweb
.libralign
.alignmentarea
.selection
.SelectionModel
;
16 import info
.bioinfweb
.libralign
.alignmentarea
.tokenpainter
.NucleotideTokenPainter
;
17 import info
.bioinfweb
.libralign
.dataarea
.implementations
.ConsensusSequenceArea
;
18 import info
.bioinfweb
.libralign
.dataarea
.implementations
.SequenceIndexArea
;
19 import info
.bioinfweb
.libralign
.dataarea
.implementations
.pherogram
.PherogramArea
;
20 import info
.bioinfweb
.libralign
.editsettings
.EditSettingsChangeEvent
;
21 import info
.bioinfweb
.libralign
.editsettings
.EditSettingsListener
;
22 import info
.bioinfweb
.libralign
.model
.AlignmentModel
;
23 import info
.bioinfweb
.libralign
.model
.AlignmentModelChangeListener
;
24 import info
.bioinfweb
.libralign
.model
.AlignmentModelUtils
;
25 import info
.bioinfweb
.libralign
.model
.adapters
.StringAdapter
;
26 import info
.bioinfweb
.libralign
.model
.events
.SequenceChangeEvent
;
27 import info
.bioinfweb
.libralign
.model
.events
.SequenceRenamedEvent
;
28 import info
.bioinfweb
.libralign
.model
.events
.TokenChangeEvent
;
29 import info
.bioinfweb
.libralign
.model
.implementations
.PackedAlignmentModel
;
30 import info
.bioinfweb
.libralign
.model
.tokenset
.BioJavaTokenSet
;
31 import info
.bioinfweb
.libralign
.model
.tokenset
.TokenSet
;
32 import info
.bioinfweb
.libralign
.multiplealignments
.AlignmentAreaList
;
33 import info
.bioinfweb
.libralign
.multiplealignments
.MultipleAlignmentsContainer
;
34 import info
.bioinfweb
.libralign
.pherogram
.model
.PherogramAreaModel
;
35 import info
.bioinfweb
.libralign
.pherogram
.model
.ShiftChange
;
36 import info
.bioinfweb
.libralign
.pherogram
.provider
.BioJavaPherogramProvider
;
37 import info
.bioinfweb
.libralign
.pherogram
.provider
.PherogramProvider
;
38 import info
.bioinfweb
.libralign
.pherogram
.provider
.ReverseComplementPherogramProvider
;
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
;
49 import java
.util
.TreeMap
;
51 import org
.biojava
.bio
.chromatogram
.ChromatogramFactory
;
52 import org
.biojava
.bio
.chromatogram
.UnsupportedChromatogramFormatException
;
53 import org
.biojava3
.core
.sequence
.compound
.DNACompoundSet
;
54 import org
.biojava3
.core
.sequence
.compound
.NucleotideCompound
;
55 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
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
.commands
.ICommandService
;
65 import org
.eclipse
.ui
.part
.EditorPart
;
67 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
68 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
69 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
70 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
71 import eu
.etaxonomy
.cdm
.model
.molecular
.SequenceString
;
72 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
73 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleReadAlignment
;
74 import eu
.etaxonomy
.taxeditor
.editor
.handler
.alignmenteditor
.ToggleInsertOverwriteHandler
;
75 import eu
.etaxonomy
.taxeditor
.editor
.handler
.alignmenteditor
.ToggleLeftRightInsertionHandler
;
76 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
81 * Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
82 * a consensus sequence.
84 * The contained GUI components used to edit the alignment come from <a href="http://bioinfweb.info/LibrAlign/">LibrAlign</a>.
90 public class AlignmentEditor
extends EditorPart
{
91 public static final String ID
= "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor";
93 public static final int READS_AREA_INDEX
= 1;
94 public static final int EDITABLE_CONSENSUS_AREA_INDEX
= READS_AREA_INDEX
+ 1;
95 public static final int CONSENSUS_HINT_AREA_INDEX
= EDITABLE_CONSENSUS_AREA_INDEX
+ 1;
96 public static final int PHEROGRAM_AREA_INDEX
= 0;
97 public static final int CONSENSUS_DATA_AREA_INDEX
= 0;
98 public static final String DEFAULT_READ_NAME_PREFIX
= "Read ";
99 public static final String CONSENSUS_NAME
= "Consensus";
102 private final ConversationHolder conversationHolder
;
104 private final AlignmentModelChangeListener DIRTY_LISTENER
= new AlignmentModelChangeListener() {
106 public <T
> void afterTokenChange(TokenChangeEvent
<T
> e
) {
111 public <T
> void afterSequenceRenamed(SequenceRenamedEvent
<T
> e
) {
116 public <T
> void afterSequenceChange(SequenceChangeEvent
<T
> e
) {
121 public <T
, U
> void afterProviderChanged(AlignmentModel
<T
> oldProvider
,
122 AlignmentModel
<U
> newProvider
) { // Not expected.
128 private MultipleAlignmentsContainer alignmentsContainer
= null;
129 private final Map
<Integer
, SingleReadAlignment
> cdmMap
= new TreeMap
<Integer
, SingleReadAlignment
>(); //TODO Move this to ContigSequenceDataProvider
130 private boolean dirty
= false;
133 public AlignmentEditor() {
135 //conversationHolder = CdmStore.createConversation();
136 conversationHolder
= null;
140 private void refreshToolbarElement(String id
) {
141 ICommandService commandService
=
142 (ICommandService
)PlatformUI
.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService
.class);
143 if (commandService
!= null) {
144 commandService
.refreshElements(id
, Collections
.EMPTY_MAP
);
149 private void registerEditSettingListener(MultipleAlignmentsContainer container
) {
150 container
.getEditSettings().addListener(new EditSettingsListener() {
152 public void workingModeChanged(EditSettingsChangeEvent e
) {} // Currently nothing to do
155 public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e
) {
157 refreshToolbarElement(ToggleLeftRightInsertionHandler
.COMMAND_ID
);
161 public void insertChanged(EditSettingsChangeEvent e
) {
163 refreshToolbarElement(ToggleInsertOverwriteHandler
.COMMAND_ID
);
169 private AlignmentArea
createIndexArea(MultipleAlignmentsContainer container
, AlignmentArea labeledArea
) {
170 AlignmentArea result
= new AlignmentArea(container
);
171 result
.setAllowVerticalScrolling(false);
172 result
.getDataAreas().getTopAreas().add(new SequenceIndexArea(result
.getContentArea(), labeledArea
));
177 private AlignmentArea
createEditableAlignmentArea(MultipleAlignmentsContainer container
, boolean allowVerticalScrolling
) {
178 AlignmentArea result
= new AlignmentArea(container
);
179 result
.setAllowVerticalScrolling(allowVerticalScrolling
);
181 TokenSet
<NucleotideCompound
> tokenSet
= new BioJavaTokenSet
<NucleotideCompound
>(
182 TokenSetType
.DNA
, new DNACompoundSet(), true); //TODO Should NUCLEOTIDE be used instead?
183 AlignmentModel
<NucleotideCompound
> provider
= new PackedAlignmentModel
<NucleotideCompound
>(tokenSet
);
184 result
.setAlignmentModel(provider
, false);
185 provider
.getChangeListeners().add(DIRTY_LISTENER
);
186 result
.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
192 private AlignmentArea
createConsensusHintArea(MultipleAlignmentsContainer container
,
193 AlignmentArea labeledArea
) {
195 AlignmentArea result
= new AlignmentArea(container
);
196 result
.setAllowVerticalScrolling(false);
197 result
.getDataAreas().getBottomAreas().add(
198 new ConsensusSequenceArea(result
.getContentArea(), labeledArea
));
203 private MultipleAlignmentsContainer
getAlignmentsContainer() {
204 if (alignmentsContainer
== null) {
205 alignmentsContainer
= new MultipleAlignmentsContainer();
207 AlignmentAreaList list
= alignmentsContainer
.getAlignmentAreas();
208 AlignmentArea readsArea
= createEditableAlignmentArea(alignmentsContainer
, true);
209 list
.add(createIndexArea(alignmentsContainer
, readsArea
));
210 list
.add(readsArea
); // Make sure READS_AREA_INDEX is correct.
211 list
.add(createEditableAlignmentArea(alignmentsContainer
, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
212 list
.add(createConsensusHintArea(alignmentsContainer
, readsArea
));
214 registerEditSettingListener(alignmentsContainer
);
216 return alignmentsContainer
;
220 public AlignmentArea
getReadsArea() {
221 return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX
);
225 private AlignmentArea
getEditableConsensusArea() {
226 return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX
);
230 public PherogramArea
getPherogramArea(int sequenceID
) {
231 return (PherogramArea
)getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).get(
232 PHEROGRAM_AREA_INDEX
);
236 private ConsensusSequenceArea
getConsensusHintDataArea() {
237 return (ConsensusSequenceArea
)getAlignmentsContainer().getAlignmentAreas().
238 get(CONSENSUS_HINT_AREA_INDEX
).getDataAreas().getBottomAreas().
239 get(CONSENSUS_DATA_AREA_INDEX
);
243 private void createTestContents() {
246 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);
247 //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);
248 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);
250 // Add test consensus sequence:
251 AlignmentModel consensusModel
= getEditableConsensusArea().getAlignmentModel();
252 int id
= consensusModel
.addSequence(CONSENSUS_NAME
);
253 Collection
<Object
> tokens
= new ArrayList
<Object
>(); // First save tokens in a collection to avoid GUI updated for each token.
254 tokens
.add(consensusModel
.getTokenSet().tokenByKeyChar('A'));
255 tokens
.add(consensusModel
.getTokenSet().tokenByKeyChar('C'));
256 tokens
.add(consensusModel
.getTokenSet().tokenByKeyChar('G'));
257 tokens
.add(consensusModel
.getTokenSet().tokenByKeyChar('T'));
258 consensusModel
.insertTokensAt(id
, 0, tokens
);
260 catch (Exception e
) {
261 throw new RuntimeException(e
);
266 private void readCDMData(Sequence sequenceNode
) {
267 //TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
270 for (SingleReadAlignment singleReadAlignment
: sequenceNode
.getSingleReadAlignments()) {
272 SingleRead pherogramInfo
= singleReadAlignment
.getSingleRead();
273 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?
274 MediaUtils
.getFirstMediaRepresentationPart(pherogramInfo
.getPherogram()).getUri(),
275 singleReadAlignment
.isReverseComplement(),
276 singleReadAlignment
.getEditedSequence(),
277 singleReadAlignment
.getFirstSeqPosition(),
278 singleReadAlignment
.getLeftCutPosition(),
279 singleReadAlignment
.getRightCutPosition(),
280 singleReadAlignment
.getShifts());
281 cdmMap
.put(id
, singleReadAlignment
);
283 catch (IOException e
) {
284 e
.printStackTrace(); //TODO Output to user (Possibly collect for all pherograms and display in the end.)
286 catch (UnsupportedChromatogramFormatException e
) {
287 e
.printStackTrace(); //TODO Output to user (Possibly collect for all pherograms and display in the end.)
291 // Set consensus sequence:
292 AlignmentModel consensusProvider
= getEditableConsensusArea().getAlignmentModel();
293 int id
= consensusProvider
.addSequence(CONSENSUS_NAME
);
294 consensusProvider
.insertTokensAt(id
, 0, AlignmentModelUtils
.charSequenceToTokenList(
295 sequenceNode
.getConsensusSequence().getString(), consensusProvider
.getTokenSet()));
296 //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
301 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
304 public void createPartControl(Composite parent
) {
305 getAlignmentsContainer().createSWTWidget(parent
, SWT
.NONE
);
308 if (getEditorInput() instanceof AlignmentEditorInput
) {
309 if (((AlignmentEditorInput
)getEditorInput()).getSequenceNode() != null) {
310 Sequence sequenceNode
= ((AlignmentEditorInput
)getEditorInput()).getSequenceNode();
311 //re-load into the current session if it is already persisted in the DB
312 if(sequenceNode
!=null && sequenceNode
.getId()!=0){
313 sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(sequenceNode
.getUuid());
315 readCDMData(sequenceNode
);
318 createTestContents(); // This case will removed after the test phase and an exception should probably be thrown.
322 throw new IllegalArgumentException("The editor input must have the type " +
323 AlignmentEditorInput
.class.getCanonicalName()); //TODO What should be done here?
328 private void updateStatusBar() {
329 IActionBars bars
= getEditorSite().getActionBars();
330 bars
.getStatusLineManager().setMessage("Edit mode: " +
331 (getReadsArea().getEditSettings().isInsert() ?
"Insert" : "Overwrite") + " " +
332 "Insertion in pherogram: " +
333 (getReadsArea().getEditSettings().isInsertLeftInDataArea() ?
"Left" : "Right"));
337 private SingleReadAlignment
.Shift
[] convertToCDMShifts(PherogramAreaModel model
) {
338 SingleReadAlignment
.Shift
[] result
= new SingleReadAlignment
.Shift
[model
.getShiftChangeCount()];
339 Iterator
<ShiftChange
> iterator
= model
.shiftChangeIterator();
341 while (iterator
.hasNext()) {
342 ShiftChange shiftChange
= iterator
.next();
343 result
[pos
] = new SingleReadAlignment
.Shift(shiftChange
.getBaseCallIndex(), shiftChange
.getShiftChange());
350 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
353 public void doSave(IProgressMonitor monitor
) {
354 if (getEditorInput() instanceof AlignmentEditorInput
) {
355 String taskName
= "Saving alignment";
356 monitor
.beginTask(taskName
, 3);
358 Sequence sequenceNode
= ((AlignmentEditorInput
)getEditorInput()).getSequenceNode();
359 StringAdapter stringProvider
= new StringAdapter(getEditableConsensusArea().getAlignmentModel(), false); // Throws an exception if a token has more than one character.
361 // Write consensus sequence:
362 SequenceString consensusSequenceObj
= sequenceNode
.getConsensusSequence();
363 String newConsensusSequence
= stringProvider
.getSequence(
364 getEditableConsensusArea().getAlignmentModel().sequenceIDByName(CONSENSUS_NAME
));
365 if (consensusSequenceObj
== null) {
366 sequenceNode
.setConsensusSequence(SequenceString
.NewInstance(newConsensusSequence
));
369 consensusSequenceObj
.setString(newConsensusSequence
);
372 // Write single reads:
373 stringProvider
.setUnderlyingProvider(getReadsArea().getAlignmentModel());
374 sequenceNode
.getSingleReadAlignments().retainAll(cdmMap
.values()); // Remove all reads that are not in the alignment anymore.
375 Iterator
<Integer
> iterator
= getReadsArea().getAlignmentModel().sequenceIDIterator();
376 while (iterator
.hasNext()) {
377 int id
= iterator
.next();
378 SingleReadAlignment singleRead
= cdmMap
.get(id
);
379 if (singleRead
== null) {
380 //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?
381 //singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
384 singleRead
.setEditedSequence(stringProvider
.getSequence(id
));
386 PherogramAreaModel model
= getPherogramArea(id
).getModel();
387 singleRead
.setReverseComplement(model
.getPherogramProvider() instanceof ReverseComplementPherogramProvider
); // Works only if ReverseComplementPherogramProvider instances are not nested.
388 singleRead
.setShifts(convertToCDMShifts(getPherogramArea(id
).getModel()));
389 singleRead
.setFirstSeqPosition(model
.getFirstSeqPos());
390 singleRead
.setLeftCutPosition(model
.getLeftCutPosition());
391 singleRead
.setRightCutPosition(model
.getRightCutPosition());
394 if (!conversationHolder
.isBound()) {
395 conversationHolder
.bind();
399 // Commit the conversation and start a new transaction immediately:
400 conversationHolder
.commit(true);
406 firePropertyChange(PROP_DIRTY
);
409 //TODO Throw exception as soon as testing period which allows unlinked AlignmentEditor is over.
415 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
418 public void doSaveAs() {}
422 * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
425 public void init(IEditorSite site
, IEditorInput input
) throws PartInitException
{
432 * @see org.eclipse.ui.part.EditorPart#isDirty()
435 public boolean isDirty() {
440 private void setDirty() {
442 firePropertyChange(IEditorPart
.PROP_DIRTY
);
447 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
450 public boolean isSaveAsAllowed() {
451 return false; // "Save as" not allowed.
456 public void setFocus() {
457 if(conversationHolder
!=null){
458 conversationHolder
.bind();
463 public boolean isInsertMode() {
464 return getAlignmentsContainer().getEditSettings().isInsert();
468 public boolean isInsertLeftInPherogram() {
469 return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
473 public void toggleLeftRightInsertionInPherogram() {
474 getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
478 public void toggleInsertOverwrite() {
479 getAlignmentsContainer().getEditSettings().toggleInsert();
483 private String
cutPherogram(boolean left
) {
484 SelectionModel selection
= getReadsArea().getSelection();
485 if (selection
.getCursorHeight() != 1) {
486 return "Cutting pherograms is only possible if exactly one row is selected.";
489 PherogramArea pherogramArea
=
490 getPherogramArea(getReadsArea().getSequenceOrder().idByIndex(selection
.getCursorRow()));
491 if (pherogramArea
== null) {
492 return "There is no pherogram attached to the current sequence.";
496 if (pherogramArea
.setLeftCutPositionBySelection()) {
500 return "The left end of the selection lies outside the pherogram attached to this sequence.";
504 if (pherogramArea
.setRightCutPositionBySelection()) {
508 return "The right end of the selection lies outside the pherogram attached to this sequence.";
516 public String
cutPherogramLeft() {
517 return cutPherogram(true);
521 public String
cutPherogramRight() {
522 return cutPherogram(false);
526 public void reverseComplementSelectedSequences() {
527 SelectionModel selection
= getReadsArea().getSelection();
528 AlignmentModel
<?
> model
= getReadsArea().getAlignmentModel();
529 for (int row
= selection
.getFirstRow(); row
< selection
.getFirstRow() + selection
.getCursorHeight(); row
++) {
530 int sequenceID
= getReadsArea().getSequenceOrder().idByIndex(row
);
531 PherogramArea area
= getPherogramArea(sequenceID
);
532 PherogramAreaModel pherogramAlignmentModel
= area
.getModel();
533 AlignmentModelUtils
.reverseComplement(model
, sequenceID
,
534 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
535 pherogramAlignmentModel
.getLeftCutPosition()).getBeforeValidIndex(),
536 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
537 pherogramAlignmentModel
.getRightCutPosition()).getAfterValidIndex());
538 pherogramAlignmentModel
.reverseComplement();
544 * Recreates the whole consensus sequence from all single read sequences. The previous consensus
545 * sequence is overwritte.
547 @SuppressWarnings("unchecked")
548 public <T
> void createConsensusSequence() {
549 ConsensusSequenceArea area
= getConsensusHintDataArea();
550 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
551 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
552 int length
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
554 Collection
<T
> tokens
= new ArrayList
<T
>(length
);
555 for (int column
= 0; column
< length
; column
++) {
556 tokens
.add(model
.getTokenSet().tokenByRepresentation(area
.getConsensusToken(column
)));
559 model
.removeTokensAt(sequenceID
, 0, model
.getSequenceLength(sequenceID
));
560 model
.insertTokensAt(sequenceID
, 0, tokens
);
565 * Updates the current consensus sequence by replacing gaps by the according consensus tokens
566 * calculated from the single read sequences and extends the consensus sequence if necessary.
568 @SuppressWarnings("unchecked")
569 public <T
> void updateConsensusSequence() {
570 ConsensusSequenceArea area
= getConsensusHintDataArea();
571 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
572 TokenSet
<T
> tokenSet
= model
.getTokenSet();
573 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
574 int currentConsensusLength
= model
.getSequenceLength(sequenceID
);
575 int overallLength
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
577 // Replace gaps by new information:
578 for (int column
= 0; column
< currentConsensusLength
; column
++) {
579 if (tokenSet
.isGapToken(model
.getTokenAt(sequenceID
, column
))) {
580 T newToken
= tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
));
581 if (!tokenSet
.isGapToken(newToken
)) {
582 model
.setTokenAt(sequenceID
, column
, newToken
);
587 // Append additional tokens:
588 if (overallLength
> currentConsensusLength
) {
589 Collection
<T
> tokens
= new ArrayList
<T
>(overallLength
);
590 for (int column
= currentConsensusLength
; column
< overallLength
; column
++) {
591 tokens
.add(tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
)));
593 model
.appendTokens(sequenceID
, tokens
);
598 public static PherogramProvider
readPherogram(URI uri
) throws IOException
, UnsupportedChromatogramFormatException
{
599 PherogramProvider result
;
600 InputStream stream
= uri
.toURL().openStream();
602 result
= new BioJavaPherogramProvider(ChromatogramFactory
.create(stream
));
611 private String
newReadName() {
613 while (getReadsArea().getAlignmentModel().sequenceIDByName(DEFAULT_READ_NAME_PREFIX
+ index
)
614 != AlignmentModel
.NO_SEQUENCE_FOUND
) {
618 return DEFAULT_READ_NAME_PREFIX
+ index
;
622 public void addRead(URI pherogramURI
, boolean reverseComplemented
) throws IOException
, UnsupportedChromatogramFormatException
{
623 addRead(newReadName(), pherogramURI
, reverseComplemented
, null, 0, 0, 0, null); // Position values will be ignored, if shifts == null.
628 * Adds a new sequence with attached phergram data area to the reads alignment.
630 * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
631 * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
632 * and the base calls sequence are assumed.
634 * @param name the name of the new sequence
635 * @param pherogramURI the URI where the associated pherogram file is located
636 * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
637 * be added, {@code false} otherwise.
638 * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
639 * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
640 * @return the sequence ID of the added read
641 * @throws IOException if an error occurred when trying to read the pherogram file
642 * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
644 public int addRead(String name
, URI pherogramURI
, boolean reverseComplemented
, String editedSequence
,
645 int firstSeqPos
, int leftCutPos
, int rightCutPos
, SingleReadAlignment
.Shift
[] shifts
)
646 throws IOException
, UnsupportedChromatogramFormatException
{
648 AlignmentModel provider
= getReadsArea().getAlignmentModel();
649 PherogramProvider pherogramProvider
= readPherogram(pherogramURI
); // Must happen before a sequence is added, because it might throw an exception.
650 if (reverseComplemented
) {
651 pherogramProvider
= new ReverseComplementPherogramProvider(pherogramProvider
);
655 provider
.addSequence(name
);
656 int id
= provider
.sequenceIDByName(name
);
658 // Set edited sequence:
659 Collection
<Object
> tokens
; // First save tokens in a collection to avoid GUI updated for each token.
660 if (editedSequence
!= null) {
661 tokens
= AlignmentModelUtils
.charSequenceToTokenList(editedSequence
, provider
.getTokenSet());
663 else { // Copy base call sequence into alignment:
664 tokens
= new ArrayList
<Object
>();
665 for (int i
= 0; i
< pherogramProvider
.getSequenceLength(); i
++) {
666 tokens
.add(provider
.getTokenSet().tokenByKeyChar(
667 pherogramProvider
.getBaseCall(i
).getUpperedBase().charAt(0)));
671 provider
.insertTokensAt(id
, 0, tokens
);
673 // Create pherogram area:
674 PherogramArea pherogramArea
= new PherogramArea(getReadsArea().getContentArea(),
675 new PherogramAreaModel(pherogramProvider
));
677 // Set position properties and shifts:
678 if ((shifts
!= null) && (shifts
.length
> 0)) {
679 PherogramAreaModel model
= pherogramArea
.getModel();
680 model
.setFirstSeqLeftCutPos(firstSeqPos
, leftCutPos
);
681 model
.setRightCutPosition(rightCutPos
);
683 for (int i
= 0; i
< shifts
.length
; i
++) {
684 model
.addShiftChange(shifts
[i
].position
, shifts
[i
].shift
);
689 // Add pherogram area to GUI:
690 pherogramArea
.addMouseListener(new PherogramMouseListener(pherogramArea
));
691 getReadsArea().getDataAreas().getSequenceAreas(id
).add(pherogramArea
);