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
;
49 import java
.util
.TreeMap
;
51 import org
.biojava
.bio
.chromatogram
.ChromatogramFactory
;
52 import org
.biojava
.bio
.chromatogram
.UnsupportedChromatogramFormatException
;
53 import org
.eclipse
.core
.runtime
.IProgressMonitor
;
54 import org
.eclipse
.swt
.SWT
;
55 import org
.eclipse
.swt
.widgets
.Composite
;
56 import org
.eclipse
.ui
.IActionBars
;
57 import org
.eclipse
.ui
.IEditorInput
;
58 import org
.eclipse
.ui
.IEditorPart
;
59 import org
.eclipse
.ui
.IEditorSite
;
60 import org
.eclipse
.ui
.PartInitException
;
61 import org
.eclipse
.ui
.PlatformUI
;
62 import org
.eclipse
.ui
.commands
.ICommandService
;
63 import org
.eclipse
.ui
.part
.EditorPart
;
65 import eu
.etaxonomy
.cdm
.api
.conversation
.ConversationHolder
;
66 import eu
.etaxonomy
.cdm
.api
.service
.molecular
.ISequenceService
;
67 import eu
.etaxonomy
.cdm
.model
.media
.MediaUtils
;
68 import eu
.etaxonomy
.cdm
.model
.molecular
.Sequence
;
69 import eu
.etaxonomy
.cdm
.model
.molecular
.SequenceString
;
70 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleRead
;
71 import eu
.etaxonomy
.cdm
.model
.molecular
.SingleReadAlignment
;
72 import eu
.etaxonomy
.taxeditor
.editor
.handler
.alignmenteditor
.ToggleInsertOverwriteHandler
;
73 import eu
.etaxonomy
.taxeditor
.editor
.handler
.alignmenteditor
.ToggleLeftRightInsertionHandler
;
74 import eu
.etaxonomy
.taxeditor
.model
.MessagingUtils
;
75 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
76 import eu
.etaxonomy
.taxeditor
.view
.derivateSearch
.DerivateLabelProvider
;
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 CharacterTokenSet tokenSet
= CharacterTokenSet
.newDNAInstance(); //TODO Should NUCLEOTIDE be used instead?
182 AlignmentModel
<Character
> provider
= new PackedAlignmentModel
<Character
>(tokenSet
);
183 result
.setAlignmentModel(provider
, false);
184 provider
.getChangeListeners().add(DIRTY_LISTENER
);
185 result
.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
191 private AlignmentArea
createConsensusHintArea(MultipleAlignmentsContainer container
,
192 AlignmentArea labeledArea
) {
194 AlignmentArea result
= new AlignmentArea(container
);
195 result
.setAllowVerticalScrolling(false);
196 result
.getDataAreas().getBottomAreas().add(
197 new ConsensusSequenceArea(result
.getContentArea(), labeledArea
));
202 private MultipleAlignmentsContainer
getAlignmentsContainer() {
203 if (alignmentsContainer
== null) {
204 alignmentsContainer
= new MultipleAlignmentsContainer();
206 AlignmentAreaList list
= alignmentsContainer
.getAlignmentAreas();
207 AlignmentArea readsArea
= createEditableAlignmentArea(alignmentsContainer
, true);
208 list
.add(createIndexArea(alignmentsContainer
, readsArea
));
209 list
.add(readsArea
); // Make sure READS_AREA_INDEX is correct.
210 list
.add(createEditableAlignmentArea(alignmentsContainer
, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
211 list
.add(createConsensusHintArea(alignmentsContainer
, readsArea
));
213 registerEditSettingListener(alignmentsContainer
);
215 return alignmentsContainer
;
219 public AlignmentArea
getReadsArea() {
220 return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX
);
224 private AlignmentArea
getEditableConsensusArea() {
225 return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX
);
229 public boolean hasPherogram(int sequenceID
) {
230 return getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).size() > PHEROGRAM_AREA_INDEX
;
234 public PherogramArea
getPherogramArea(int sequenceID
) {
235 if (hasPherogram(sequenceID
)) {
236 return (PherogramArea
)getReadsArea().getDataAreas().getSequenceAreas(sequenceID
).get(PHEROGRAM_AREA_INDEX
);
244 private ConsensusSequenceArea
getConsensusHintDataArea() {
245 return (ConsensusSequenceArea
)getAlignmentsContainer().getAlignmentAreas().
246 get(CONSENSUS_HINT_AREA_INDEX
).getDataAreas().getBottomAreas().
247 get(CONSENSUS_DATA_AREA_INDEX
);
251 private void createTestContents() {
254 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);
255 //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);
256 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);
258 // Add test consensus sequence:
259 AlignmentModel consensusModel
= getEditableConsensusArea().getAlignmentModel();
260 int id
= consensusModel
.addSequence(CONSENSUS_NAME
);
261 Collection
<Object
> tokens
= new ArrayList
<Object
>(); // First save tokens in a collection to avoid GUI updated for each token.
262 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("A"));
263 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("C"));
264 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("G"));
265 tokens
.add(consensusModel
.getTokenSet().tokenByRepresentation("T"));
266 consensusModel
.insertTokensAt(id
, 0, tokens
);
268 catch (Exception e
) {
269 throw new RuntimeException(e
);
274 private void readCDMData(Sequence sequenceNode
) {
275 //TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
278 for (SingleReadAlignment singleReadAlignment
: sequenceNode
.getSingleReadAlignments()) {
280 SingleRead pherogramInfo
= singleReadAlignment
.getSingleRead();
282 if (pherogramInfo
.getPherogram() != null) {
283 uri
= MediaUtils
.getFirstMediaRepresentationPart(pherogramInfo
.getPherogram()).getUri();
285 int id
= addRead(DerivateLabelProvider
.getDerivateText(pherogramInfo
, conversationHolder
),
287 singleReadAlignment
.isReverseComplement(),
288 singleReadAlignment
.getEditedSequence(),
289 singleReadAlignment
.getFirstSeqPosition(),
290 singleReadAlignment
.getLeftCutPosition(),
291 singleReadAlignment
.getRightCutPosition(),
292 singleReadAlignment
.getShifts());
293 cdmMap
.put(id
, singleReadAlignment
);
295 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).
296 MessagingUtils
.errorDialog("Error", null, "A single read was skipped because of the following error:\n\n" +
297 e
.getLocalizedMessage(), "eu.etaxonomy.taxeditor.editor", e
, false);
301 // Set consensus sequence:
302 AlignmentModel consensusProvider
= getEditableConsensusArea().getAlignmentModel();
303 int id
= consensusProvider
.addSequence(CONSENSUS_NAME
);
304 consensusProvider
.insertTokensAt(id
, 0, AlignmentModelUtils
.charSequenceToTokenList(
305 sequenceNode
.getConsensusSequence().getString(), consensusProvider
.getTokenSet()));
306 //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
311 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
314 public void createPartControl(Composite parent
) {
315 SWTComponentFactory
.getInstance().getSWTComponent(getAlignmentsContainer(), parent
, SWT
.NONE
);
318 if (getEditorInput() instanceof AlignmentEditorInput
) {
319 if (((AlignmentEditorInput
)getEditorInput()).getSequenceNode() != null) {
320 Sequence sequenceNode
= ((AlignmentEditorInput
)getEditorInput()).getSequenceNode();
321 //re-load into the current session if it is already persisted in the DB
322 if(sequenceNode
!=null && sequenceNode
.getId()!=0){
323 sequenceNode
= CdmStore
.getService(ISequenceService
.class).load(sequenceNode
.getUuid());
325 readCDMData(sequenceNode
);
328 createTestContents(); // This case will removed after the test phase and an exception should probably be thrown.
332 throw new IllegalArgumentException("The editor input must have the type " +
333 AlignmentEditorInput
.class.getCanonicalName()); //TODO What should be done here?
338 private void updateStatusBar() {
339 IActionBars bars
= getEditorSite().getActionBars();
340 bars
.getStatusLineManager().setMessage("Edit mode: " +
341 (getReadsArea().getEditSettings().isInsert() ?
"Insert" : "Overwrite") + " " +
342 "Insertion in pherogram: " +
343 (getReadsArea().getEditSettings().isInsertLeftInDataArea() ?
"Left" : "Right"));
347 private SingleReadAlignment
.Shift
[] convertToCDMShifts(PherogramAreaModel model
) {
348 SingleReadAlignment
.Shift
[] result
= new SingleReadAlignment
.Shift
[model
.getShiftChangeCount()];
349 Iterator
<ShiftChange
> iterator
= model
.shiftChangeIterator();
351 while (iterator
.hasNext()) {
352 ShiftChange shiftChange
= iterator
.next();
353 result
[pos
] = new SingleReadAlignment
.Shift(shiftChange
.getBaseCallIndex(), shiftChange
.getShiftChange());
360 * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
363 public void doSave(IProgressMonitor monitor
) {
364 if (getEditorInput() instanceof AlignmentEditorInput
) {
365 String taskName
= "Saving alignment";
366 monitor
.beginTask(taskName
, 3);
368 Sequence sequenceNode
= ((AlignmentEditorInput
)getEditorInput()).getSequenceNode();
369 StringAdapter stringProvider
= new StringAdapter(getEditableConsensusArea().getAlignmentModel(), false); // Throws an exception if a token has more than one character.
371 // Write consensus sequence:
372 SequenceString consensusSequenceObj
= sequenceNode
.getConsensusSequence();
373 String newConsensusSequence
= stringProvider
.getSequence(
374 getEditableConsensusArea().getAlignmentModel().sequenceIDByName(CONSENSUS_NAME
));
375 if (consensusSequenceObj
== null) {
376 sequenceNode
.setConsensusSequence(SequenceString
.NewInstance(newConsensusSequence
));
379 consensusSequenceObj
.setString(newConsensusSequence
);
382 // Write single reads:
383 stringProvider
.setUnderlyingProvider(getReadsArea().getAlignmentModel());
384 sequenceNode
.getSingleReadAlignments().retainAll(cdmMap
.values()); // Remove all reads that are not in the alignment anymore.
385 Iterator
<Integer
> iterator
= getReadsArea().getAlignmentModel().sequenceIDIterator();
386 while (iterator
.hasNext()) {
387 int id
= iterator
.next();
388 SingleReadAlignment singleRead
= cdmMap
.get(id
);
389 if (singleRead
== null) {
390 throw new InternalError("Creating new reads from AlignmentEditor not implemented.");
391 //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?
392 //singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
395 singleRead
.setEditedSequence(stringProvider
.getSequence(id
));
397 PherogramAreaModel model
= getPherogramArea(id
).getModel();
398 singleRead
.setReverseComplement(model
.getPherogramProvider() instanceof ReverseComplementPherogramProvider
); // Works only if ReverseComplementPherogramProvider instances are not nested.
399 singleRead
.setShifts(convertToCDMShifts(getPherogramArea(id
).getModel()));
400 singleRead
.setFirstSeqPosition(model
.getFirstSeqPos());
401 singleRead
.setLeftCutPosition(model
.getLeftCutPosition());
402 singleRead
.setRightCutPosition(model
.getRightCutPosition());
405 if (!conversationHolder
.isBound()) {
406 conversationHolder
.bind();
410 // Commit the conversation and start a new transaction immediately:
411 conversationHolder
.commit(true);
417 firePropertyChange(PROP_DIRTY
);
420 //TODO Throw exception as soon as testing period which allows unlinked AlignmentEditor is over.
426 * @see org.eclipse.ui.part.EditorPart#doSaveAs()
429 public void doSaveAs() {}
433 * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
436 public void init(IEditorSite site
, IEditorInput input
) throws PartInitException
{
443 * @see org.eclipse.ui.part.EditorPart#isDirty()
446 public boolean isDirty() {
451 private void setDirty() {
453 firePropertyChange(IEditorPart
.PROP_DIRTY
);
458 * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
461 public boolean isSaveAsAllowed() {
462 return false; // "Save as" not allowed.
467 public void setFocus() {
468 if(conversationHolder
!=null){
469 conversationHolder
.bind();
474 public boolean isInsertMode() {
475 return getAlignmentsContainer().getEditSettings().isInsert();
479 public boolean isInsertLeftInPherogram() {
480 return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
484 public void toggleLeftRightInsertionInPherogram() {
485 getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
489 public void toggleInsertOverwrite() {
490 getAlignmentsContainer().getEditSettings().toggleInsert();
494 private String
cutPherogram(boolean left
) {
495 SelectionModel selection
= getReadsArea().getSelection();
496 if (selection
.getCursorHeight() != 1) {
497 return "Cutting pherograms is only possible if exactly one row is selected.";
500 PherogramArea pherogramArea
=
501 getPherogramArea(getReadsArea().getSequenceOrder().idByIndex(selection
.getCursorRow()));
502 if (pherogramArea
== null) {
503 return "There is no pherogram attached to the current sequence.";
507 if (pherogramArea
.setLeftCutPositionBySelection()) {
511 return "The left end of the selection lies outside the pherogram attached to this sequence.";
515 if (pherogramArea
.setRightCutPositionBySelection()) {
519 return "The right end of the selection lies outside the pherogram attached to this sequence.";
527 public String
cutPherogramLeft() {
528 return cutPherogram(true);
532 public String
cutPherogramRight() {
533 return cutPherogram(false);
537 public void reverseComplementSelectedSequences() {
538 SelectionModel selection
= getReadsArea().getSelection();
539 AlignmentModel
<?
> model
= getReadsArea().getAlignmentModel();
540 for (int row
= selection
.getFirstRow(); row
< selection
.getFirstRow() + selection
.getCursorHeight(); row
++) {
541 int sequenceID
= getReadsArea().getSequenceOrder().idByIndex(row
);
542 PherogramArea area
= getPherogramArea(sequenceID
);
543 PherogramAreaModel pherogramAlignmentModel
= area
.getModel();
544 AlignmentModelUtils
.reverseComplement(model
, sequenceID
,
545 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
546 pherogramAlignmentModel
.getLeftCutPosition()).getBeforeValidIndex(),
547 pherogramAlignmentModel
.editableIndexByBaseCallIndex(
548 pherogramAlignmentModel
.getRightCutPosition()).getAfterValidIndex());
549 pherogramAlignmentModel
.reverseComplement();
555 * Recreates the whole consensus sequence from all single read sequences. The previous consensus
556 * sequence is overwritte.
558 @SuppressWarnings("unchecked")
559 public <T
> void createConsensusSequence() {
560 ConsensusSequenceArea area
= getConsensusHintDataArea();
561 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
562 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
563 int length
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
565 Collection
<T
> tokens
= new ArrayList
<T
>(length
);
566 for (int column
= 0; column
< length
; column
++) {
567 tokens
.add(model
.getTokenSet().tokenByRepresentation(area
.getConsensusToken(column
)));
570 model
.removeTokensAt(sequenceID
, 0, model
.getSequenceLength(sequenceID
));
571 model
.insertTokensAt(sequenceID
, 0, tokens
);
576 * Updates the current consensus sequence by replacing gaps by the according consensus tokens
577 * calculated from the single read sequences and extends the consensus sequence if necessary.
579 @SuppressWarnings("unchecked")
580 public <T
> void updateConsensusSequence() {
581 ConsensusSequenceArea area
= getConsensusHintDataArea();
582 AlignmentModel
<T
> model
= (AlignmentModel
<T
>)getEditableConsensusArea().getAlignmentModel();
583 TokenSet
<T
> tokenSet
= model
.getTokenSet();
584 int sequenceID
= model
.sequenceIDIterator().next(); // There is always one sequence contained.
585 int currentConsensusLength
= model
.getSequenceLength(sequenceID
);
586 int overallLength
= getReadsArea().getAlignmentModel().getMaxSequenceLength();
588 // Replace gaps by new information:
589 for (int column
= 0; column
< currentConsensusLength
; column
++) {
590 if (tokenSet
.isGapToken(model
.getTokenAt(sequenceID
, column
))) {
591 T newToken
= tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
));
592 if (!tokenSet
.isGapToken(newToken
)) {
593 model
.setTokenAt(sequenceID
, column
, newToken
);
598 // Append additional tokens:
599 if (overallLength
> currentConsensusLength
) {
600 Collection
<T
> tokens
= new ArrayList
<T
>(overallLength
);
601 for (int column
= currentConsensusLength
; column
< overallLength
; column
++) {
602 tokens
.add(tokenSet
.tokenByRepresentation(area
.getConsensusToken(column
)));
604 model
.appendTokens(sequenceID
, tokens
);
609 public static PherogramProvider
readPherogram(URI uri
) throws IOException
, UnsupportedChromatogramFormatException
{
610 PherogramProvider result
;
611 InputStream stream
= uri
.toURL().openStream();
613 result
= new BioJavaPherogramProvider(ChromatogramFactory
.create(stream
));
622 private String
newReadName() {
624 while (getReadsArea().getAlignmentModel().sequenceIDByName(DEFAULT_READ_NAME_PREFIX
+ index
)
625 != AlignmentModel
.NO_SEQUENCE_FOUND
) {
629 return DEFAULT_READ_NAME_PREFIX
+ index
;
633 public void addRead(URI pherogramURI
, boolean reverseComplemented
) throws IOException
, UnsupportedChromatogramFormatException
{
634 addRead(newReadName(), pherogramURI
, reverseComplemented
, null, null, null, null, null);
639 * Adds a new sequence with attached phergram data area to the reads alignment.
641 * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
642 * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
643 * and the base calls sequence are assumed.
645 * @param name the name of the new sequence
646 * @param pherogramURI the URI where the associated pherogram file is located
647 * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
648 * be added, {@code false} otherwise.
649 * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
650 * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
651 * @return the sequence ID of the added read
652 * @throws IOException if an error occurred when trying to read the pherogram file
653 * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
655 public int addRead(String name
, URI pherogramURI
, boolean reverseComplemented
, String editedSequence
,
656 Integer firstSeqPos
, Integer leftCutPos
, Integer rightCutPos
, SingleReadAlignment
.Shift
[] shifts
)
657 throws IOException
, UnsupportedChromatogramFormatException
{
659 AlignmentModel provider
= getReadsArea().getAlignmentModel();
660 PherogramProvider pherogramProvider
= null;
661 if (pherogramURI
!= null) {
662 pherogramProvider
= readPherogram(pherogramURI
); // Must happen before a sequence is added, because it might throw an exception.
663 if (reverseComplemented
) {
664 pherogramProvider
= new ReverseComplementPherogramProvider(pherogramProvider
);
669 provider
.addSequence(name
);
670 int id
= provider
.sequenceIDByName(name
);
672 // Set edited sequence:
673 Collection
<Object
> tokens
= null; // First save tokens in a collection to avoid GUI updated for each token.
674 if (editedSequence
!= null) {
675 tokens
= AlignmentModelUtils
.charSequenceToTokenList(editedSequence
, provider
.getTokenSet());
677 else if (pherogramProvider
!= null) { // Copy base call sequence into alignment:
678 tokens
= new ArrayList
<Object
>();
679 for (int i
= 0; i
< pherogramProvider
.getSequenceLength(); i
++) {
680 tokens
.add(provider
.getTokenSet().tokenByRepresentation(
681 Character
.toString(pherogramProvider
.getBaseCall(i
))));
686 if (tokens
!= null) { // If either an edited sequence or a pherogram URI was provided.
687 provider
.insertTokensAt(id
, 0, tokens
);
688 // Create pherogram area:
689 PherogramArea pherogramArea
= new PherogramArea(getReadsArea().getContentArea(),
690 new PherogramAreaModel(pherogramProvider
));
692 // Set position properties and shifts:
693 PherogramAreaModel model
= pherogramArea
.getModel();
694 if ((firstSeqPos
!= null) && (leftCutPos
!= null)) {
695 model
.setFirstSeqLeftCutPos(firstSeqPos
, leftCutPos
);
697 if (rightCutPos
!= null) {
698 model
.setRightCutPosition(rightCutPos
);
700 if ((shifts
!= null) && (shifts
.length
> 0)) {
701 for (int i
= 0; i
< shifts
.length
; i
++) {
702 model
.addShiftChange(shifts
[i
].position
, shifts
[i
].shift
);
707 // Add pherogram area to GUI:
708 pherogramArea
.addMouseListener(new PherogramMouseListener(pherogramArea
));
709 getReadsArea().getDataAreas().getSequenceAreas(id
).add(pherogramArea
);