-// $Id$
-/**
-* Copyright (C) 2014 EDIT
-* European Distributed Institute of Taxonomy
-* http://www.e-taxonomy.eu
-*
-* The contents of this file are subject to the Mozilla Public License Version 1.1
-* See LICENSE.TXT at the top of this package for the full license terms.
-*/
-package eu.etaxonomy.taxeditor.editor.molecular;
-
-
-import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
-import info.bioinfweb.libralign.alignmentarea.selection.SelectionModel;
-import info.bioinfweb.libralign.alignmentarea.tokenpainter.NucleotideTokenPainter;
-import info.bioinfweb.libralign.dataarea.implementations.ConsensusSequenceArea;
-import info.bioinfweb.libralign.dataarea.implementations.SequenceIndexArea;
-import info.bioinfweb.libralign.dataarea.implementations.pherogram.PherogramArea;
-import info.bioinfweb.libralign.editsettings.EditSettingsChangeEvent;
-import info.bioinfweb.libralign.editsettings.EditSettingsListener;
-import info.bioinfweb.libralign.model.AlignmentModel;
-import info.bioinfweb.libralign.model.AlignmentModelChangeListener;
-import info.bioinfweb.libralign.model.AlignmentModelUtils;
-import info.bioinfweb.libralign.model.adapters.StringAdapter;
-import info.bioinfweb.libralign.model.events.SequenceChangeEvent;
-import info.bioinfweb.libralign.model.events.SequenceRenamedEvent;
-import info.bioinfweb.libralign.model.events.TokenChangeEvent;
-import info.bioinfweb.libralign.model.implementations.PackedAlignmentModel;
-import info.bioinfweb.libralign.model.tokenset.CharacterTokenSet;
-import info.bioinfweb.libralign.model.tokenset.TokenSet;
-import info.bioinfweb.libralign.multiplealignments.AlignmentAreaList;
-import info.bioinfweb.libralign.multiplealignments.MultipleAlignmentsContainer;
-import info.bioinfweb.libralign.pherogram.model.PherogramAreaModel;
-import info.bioinfweb.libralign.pherogram.model.ShiftChange;
-import info.bioinfweb.libralign.pherogram.provider.BioJavaPherogramProvider;
-import info.bioinfweb.libralign.pherogram.provider.PherogramProvider;
-import info.bioinfweb.libralign.pherogram.provider.ReverseComplementPherogramProvider;
-import info.bioinfweb.tic.SWTComponentFactory;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.biojava.bio.chromatogram.ChromatogramFactory;
-import org.biojava.bio.chromatogram.UnsupportedChromatogramFormatException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.ui.IActionBars;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.commands.ICommandService;
-import org.eclipse.ui.part.EditorPart;
-
-import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
-import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
-import eu.etaxonomy.cdm.model.media.MediaUtils;
-import eu.etaxonomy.cdm.model.molecular.Sequence;
-import eu.etaxonomy.cdm.model.molecular.SequenceString;
-import eu.etaxonomy.cdm.model.molecular.SingleRead;
-import eu.etaxonomy.cdm.model.molecular.SingleReadAlignment;
-import eu.etaxonomy.cdm.model.molecular.SingleReadAlignment.Shift;
-import eu.etaxonomy.taxeditor.editor.handler.alignmenteditor.ToggleInsertOverwriteHandler;
-import eu.etaxonomy.taxeditor.editor.handler.alignmenteditor.ToggleLeftRightInsertionHandler;
-import eu.etaxonomy.taxeditor.model.MessagingUtils;
-import eu.etaxonomy.taxeditor.store.CdmStore;
-import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
-
-
-
-/**
- * Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
- * a consensus sequence.
- * <p>
- * The contained GUI components used to edit the alignment come from <a href="http://bioinfweb.info/LibrAlign/">LibrAlign</a>.
- *
- * @author Ben Stöver
- * @author pplitzner
- * @date 04.08.2014
- */
-public class AlignmentEditor extends EditorPart {
- public static final String ID = "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor";
-
- public static final int READS_AREA_INDEX = 1;
- public static final int EDITABLE_CONSENSUS_AREA_INDEX = READS_AREA_INDEX + 1;
- public static final int CONSENSUS_HINT_AREA_INDEX = EDITABLE_CONSENSUS_AREA_INDEX + 1;
- public static final int PHEROGRAM_AREA_INDEX = 0;
- public static final int CONSENSUS_DATA_AREA_INDEX = 0;
- public static final String DEFAULT_READ_NAME_PREFIX = "Read ";
- public static final String CONSENSUS_NAME = "Consensus";
-
-
- private final ConversationHolder conversationHolder;
-
- private final AlignmentModelChangeListener DIRTY_LISTENER = new AlignmentModelChangeListener() {
- @Override
- public <T> void afterTokenChange(TokenChangeEvent<T> e) {
- setDirty();
- }
-
- @Override
- public <T> void afterSequenceRenamed(SequenceRenamedEvent<T> e) {
- setDirty();
- }
-
- @Override
- public <T> void afterSequenceChange(SequenceChangeEvent<T> e) {
- setDirty();
- }
-
- @Override
- public <T, U> void afterProviderChanged(AlignmentModel<T> oldProvider,
- AlignmentModel<U> newProvider) { // Not expected.
-
- setDirty();
- }
- };
-
- private MultipleAlignmentsContainer alignmentsContainer = null;
- private final Map<Integer, SingleReadAlignment> cdmMap = new TreeMap<Integer, SingleReadAlignment>(); //TODO Move this to ContigSequenceDataProvider
- private boolean dirty = false;
-
-
- public AlignmentEditor() {
- super();
- conversationHolder = CdmStore.createConversation();
- //conversationHolder = null;
- }
-
-
- private void refreshToolbarElement(String id) {
- ICommandService commandService =
- (ICommandService)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService.class);
- if (commandService != null) {
- commandService.refreshElements(id, Collections.EMPTY_MAP);
- }
- }
-
-
- private void registerEditSettingListener(MultipleAlignmentsContainer container) {
- container.getEditSettings().addListener(new EditSettingsListener() {
- @Override
- public void workingModeChanged(EditSettingsChangeEvent e) {} // Currently nothing to do
-
- @Override
- public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e) {
- updateStatusBar();
- refreshToolbarElement(ToggleLeftRightInsertionHandler.COMMAND_ID);
- }
-
- @Override
- public void insertChanged(EditSettingsChangeEvent e) {
- updateStatusBar();
- refreshToolbarElement(ToggleInsertOverwriteHandler.COMMAND_ID);
- }
- });
- }
-
-
- private AlignmentArea createIndexArea(MultipleAlignmentsContainer container, AlignmentArea labeledArea) {
- AlignmentArea result = new AlignmentArea(container);
- result.setAllowVerticalScrolling(false);
- result.getDataAreas().getTopAreas().add(new SequenceIndexArea(result.getContentArea(), labeledArea));
- return result;
- }
-
-
- private AlignmentArea createEditableAlignmentArea(MultipleAlignmentsContainer container, boolean allowVerticalScrolling) {
- AlignmentArea result = new AlignmentArea(container);
- result.setAllowVerticalScrolling(allowVerticalScrolling);
-
- CharacterTokenSet tokenSet = CharacterTokenSet.newDNAInstance(); //TODO Should NUCLEOTIDE be used instead?
- AlignmentModel<Character> provider = new PackedAlignmentModel<Character>(tokenSet);
- result.setAlignmentModel(provider, false);
- provider.getChangeListeners().add(DIRTY_LISTENER);
- result.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
-
- return result;
- }
-
-
- private AlignmentArea createConsensusHintArea(MultipleAlignmentsContainer container,
- AlignmentArea labeledArea) {
-
- AlignmentArea result = new AlignmentArea(container);
- result.setAllowVerticalScrolling(false);
- result.getDataAreas().getBottomAreas().add(
- new ConsensusSequenceArea(result.getContentArea(), labeledArea));
- return result;
- }
-
-
- private MultipleAlignmentsContainer getAlignmentsContainer() {
- if (alignmentsContainer == null) {
- alignmentsContainer = new MultipleAlignmentsContainer();
-
- AlignmentAreaList list = alignmentsContainer.getAlignmentAreas();
- AlignmentArea readsArea = createEditableAlignmentArea(alignmentsContainer, true);
- list.add(createIndexArea(alignmentsContainer, readsArea));
- list.add(readsArea); // Make sure READS_AREA_INDEX is correct.
- list.add(createEditableAlignmentArea(alignmentsContainer, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
- list.add(createConsensusHintArea(alignmentsContainer, readsArea));
-
- registerEditSettingListener(alignmentsContainer);
- }
- return alignmentsContainer;
- }
-
-
- public AlignmentArea getReadsArea() {
- return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX);
- }
-
-
- private AlignmentArea getEditableConsensusArea() {
- return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX);
- }
-
-
- public boolean hasPherogram(int sequenceID) {
- return getReadsArea().getDataAreas().getSequenceAreas(sequenceID).size() > PHEROGRAM_AREA_INDEX;
- }
-
-
- public PherogramArea getPherogramArea(int sequenceID) {
- if (hasPherogram(sequenceID)) {
- return (PherogramArea)getReadsArea().getDataAreas().getSequenceAreas(sequenceID).get(PHEROGRAM_AREA_INDEX);
- }
- else {
- return null;
- }
- }
-
-
- private ConsensusSequenceArea getConsensusHintDataArea() {
- return (ConsensusSequenceArea)getAlignmentsContainer().getAlignmentAreas().
- get(CONSENSUS_HINT_AREA_INDEX).getDataAreas().getBottomAreas().
- get(CONSENSUS_DATA_AREA_INDEX);
- }
-
-
- @Deprecated //TODO Remove as soon as testing period is over
- private void createTestContents() {
- // Just for testing:
- try {
- 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);
- //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);
- 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);
-
- // Add test consensus sequence:
- AlignmentModel consensusModel = getEditableConsensusArea().getAlignmentModel();
- int id = consensusModel.addSequence(CONSENSUS_NAME);
- Collection<Object> tokens = new ArrayList<Object>(); // First save tokens in a collection to avoid GUI updated for each token.
- tokens.add(consensusModel.getTokenSet().tokenByRepresentation("A"));
- tokens.add(consensusModel.getTokenSet().tokenByRepresentation("C"));
- tokens.add(consensusModel.getTokenSet().tokenByRepresentation("G"));
- tokens.add(consensusModel.getTokenSet().tokenByRepresentation("T"));
- consensusModel.insertTokensAt(id, 0, tokens);
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
-
- private void readCDMData(Sequence sequenceNode) {
- //TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
-
- // Add reads:
- for (SingleReadAlignment singleReadAlignment : sequenceNode.getSingleReadAlignments()) {
- try {
- SingleRead pherogramInfo = singleReadAlignment.getSingleRead();
- URI uri = null;
- if (pherogramInfo.getPherogram() != null) {
- uri = MediaUtils.getFirstMediaRepresentationPart(pherogramInfo.getPherogram()).getUri();
- }
- int id = addRead(DerivateLabelProvider.getDerivateText(pherogramInfo, conversationHolder),
- uri,
- singleReadAlignment.isReverseComplement(),
- singleReadAlignment.getEditedSequence(),
- singleReadAlignment.getFirstSeqPosition(),
- singleReadAlignment.getLeftCutPosition(),
- singleReadAlignment.getRightCutPosition(),
- singleReadAlignment.getShifts());
- cdmMap.put(id, singleReadAlignment);
- }
- 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).
- MessagingUtils.errorDialog("Error", null, "A single read was skipped because of the following error:\n\n" +
- e.getLocalizedMessage(), "eu.etaxonomy.taxeditor.editor", e, false);
- }
- }
-
- // Set consensus sequence:
- AlignmentModel consensusProvider = getEditableConsensusArea().getAlignmentModel();
- int id = consensusProvider.addSequence(CONSENSUS_NAME);
- consensusProvider.insertTokensAt(id, 0, AlignmentModelUtils.charSequenceToTokenList(
- sequenceNode.getConsensusSequence().getString(), consensusProvider.getTokenSet()));
- //TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
- */
- @Override
- public void createPartControl(Composite parent) {
- SWTComponentFactory.getInstance().getSWTComponent(getAlignmentsContainer(), parent, SWT.NONE);
- updateStatusBar();
-
- if (getEditorInput() instanceof AlignmentEditorInput) {
- if (((AlignmentEditorInput)getEditorInput()).getSequenceNodeUuid() != null) {
- Sequence sequenceNode = CdmStore.getService(ISequenceService.class).load(((AlignmentEditorInput)getEditorInput()).getSequenceNodeUuid());
- //re-load into the current session if it is already persisted in the DB
- if(sequenceNode!=null && sequenceNode.getId()!=0){
- sequenceNode = CdmStore.getService(ISequenceService.class).load(sequenceNode.getUuid());
- }
- readCDMData(sequenceNode);
- }
- else {
- createTestContents(); // This case will removed after the test phase and an exception should probably be thrown.
- }
- }
- else {
- throw new IllegalArgumentException("The editor input must have the type " +
- AlignmentEditorInput.class.getCanonicalName()); //TODO What should be done here?
- }
- }
-
-
- private void updateStatusBar() {
- IActionBars bars = getEditorSite().getActionBars();
- bars.getStatusLineManager().setMessage("Edit mode: " +
- (getReadsArea().getEditSettings().isInsert() ? "Insert" : "Overwrite") + " " +
- "Insertion in pherogram: " +
- (getReadsArea().getEditSettings().isInsertLeftInDataArea() ? "Left" : "Right"));
- }
-
-
- private SingleReadAlignment.Shift[] convertToCDMShifts(PherogramAreaModel model) {
- Iterator<ShiftChange> iterator = model.shiftChangeIterator();
- List<Shift> shifts = new ArrayList<SingleReadAlignment.Shift>();
- while (iterator.hasNext()) {
- ShiftChange shiftChange = iterator.next();
- shifts.add(new SingleReadAlignment.Shift(shiftChange.getBaseCallIndex(), shiftChange.getShiftChange()));
- }
- return shifts.toArray(new Shift[]{});
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
- */
- @Override
- public void doSave(IProgressMonitor monitor) {
- if (getEditorInput() instanceof AlignmentEditorInput) {
- String taskName = "Saving alignment";
- monitor.beginTask(taskName, 3);
-
- //re-loading sequence to avoid session conflicts
- Sequence sequenceNode = CdmStore.getService(ISequenceService.class).load(((AlignmentEditorInput)getEditorInput()).getSequenceNodeUuid());
- StringAdapter stringProvider = new StringAdapter(getEditableConsensusArea().getAlignmentModel(), false); // Throws an exception if a token has more than one character.
-
- // Write consensus sequence:
- SequenceString consensusSequenceObj = sequenceNode.getConsensusSequence();
- String newConsensusSequence = stringProvider.getSequence(
- getEditableConsensusArea().getAlignmentModel().sequenceIDByName(CONSENSUS_NAME));
- if (consensusSequenceObj == null) {
- sequenceNode.setConsensusSequence(SequenceString.NewInstance(newConsensusSequence));
- }
- else {
- consensusSequenceObj.setString(newConsensusSequence);
- }
-
- // Write single reads:
- stringProvider.setUnderlyingProvider(getReadsArea().getAlignmentModel());
- sequenceNode.getSingleReadAlignments().retainAll(cdmMap.values()); // Remove all reads that are not in the alignment anymore.
- Iterator<Integer> iterator = getReadsArea().getAlignmentModel().sequenceIDIterator();
- while (iterator.hasNext()) {
- int id = iterator.next();
- SingleReadAlignment singleRead = cdmMap.get(id);
- if (singleRead == null) {
- throw new InternalError("Creating new reads from AlignmentEditor not implemented.");
- //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?
- //singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
- }
-
- singleRead.setEditedSequence(stringProvider.getSequence(id));
-
- PherogramAreaModel model = getPherogramArea(id).getModel();
- singleRead.setReverseComplement(model.getPherogramProvider() instanceof ReverseComplementPherogramProvider); // Works only if ReverseComplementPherogramProvider instances are not nested.
- singleRead.setShifts(convertToCDMShifts(getPherogramArea(id).getModel()));
- singleRead.setFirstSeqPosition(model.getFirstSeqPos());
- singleRead.setLeftCutPosition(model.getLeftCutPosition());
- singleRead.setRightCutPosition(model.getRightCutPosition());
- }
-
- if (!conversationHolder.isBound()) {
- conversationHolder.bind();
- }
- monitor.worked(1);
-
- // Commit the conversation and start a new transaction immediately:
- conversationHolder.commit(true);
- monitor.worked(1);
-
- dirty = false;
- monitor.worked(1);
- monitor.done();
- firePropertyChange(PROP_DIRTY);
- }
- else {
- //TODO Throw exception as soon as testing period which allows unlinked AlignmentEditor is over.
- }
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.EditorPart#doSaveAs()
- */
- @Override
- public void doSaveAs() {}
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
- */
- @Override
- public void init(IEditorSite site, IEditorInput input) throws PartInitException {
- setSite(site);
- setInput(input);
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.EditorPart#isDirty()
- */
- @Override
- public boolean isDirty() {
- return dirty;
- }
-
-
- private void setDirty() {
- dirty = true;
- firePropertyChange(IEditorPart.PROP_DIRTY);
- }
-
-
- /* (non-Javadoc)
- * @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
- */
- @Override
- public boolean isSaveAsAllowed() {
- return false; // "Save as" not allowed.
- }
-
-
- @Override
- public void setFocus() {
- if(conversationHolder!=null){
- conversationHolder.bind();
- }
- }
-
-
- public boolean isInsertMode() {
- return getAlignmentsContainer().getEditSettings().isInsert();
- }
-
-
- public boolean isInsertLeftInPherogram() {
- return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
- }
-
-
- public void toggleLeftRightInsertionInPherogram() {
- getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
- }
-
-
- public void toggleInsertOverwrite() {
- getAlignmentsContainer().getEditSettings().toggleInsert();
- }
-
-
- private String cutPherogram(boolean left) {
- SelectionModel selection = getReadsArea().getSelection();
- if (selection.getCursorHeight() != 1) {
- return "Cutting pherograms is only possible if exactly one row is selected.";
- }
- else {
- PherogramArea pherogramArea =
- getPherogramArea(getReadsArea().getSequenceOrder().idByIndex(selection.getCursorRow()));
- if (pherogramArea == null) {
- return "There is no pherogram attached to the current sequence.";
- }
- else {
- if (left) {
- if (pherogramArea.setLeftCutPositionBySelection()) {
- return null;
- }
- else {
- return "The left end of the selection lies outside the pherogram attached to this sequence.";
- }
- }
- else {
- if (pherogramArea.setRightCutPositionBySelection()) {
- return null;
- }
- else {
- return "The right end of the selection lies outside the pherogram attached to this sequence.";
- }
- }
- }
- }
- }
-
-
- public String cutPherogramLeft() {
- return cutPherogram(true);
- }
-
-
- public String cutPherogramRight() {
- return cutPherogram(false);
- }
-
-
- public void reverseComplementSelectedSequences() {
- SelectionModel selection = getReadsArea().getSelection();
- AlignmentModel<?> model = getReadsArea().getAlignmentModel();
- for (int row = selection.getFirstRow(); row < selection.getFirstRow() + selection.getCursorHeight(); row++) {
- int sequenceID = getReadsArea().getSequenceOrder().idByIndex(row);
- PherogramArea area = getPherogramArea(sequenceID);
- PherogramAreaModel pherogramAlignmentModel = area.getModel();
- AlignmentModelUtils.reverseComplement(model, sequenceID,
- pherogramAlignmentModel.editableIndexByBaseCallIndex(
- pherogramAlignmentModel.getLeftCutPosition()).getBeforeValidIndex(),
- pherogramAlignmentModel.editableIndexByBaseCallIndex(
- pherogramAlignmentModel.getRightCutPosition()).getAfterValidIndex());
- pherogramAlignmentModel.reverseComplement();
- }
- }
-
-
- /**
- * Recreates the whole consensus sequence from all single read sequences. The previous consensus
- * sequence is overwritte.
- */
- @SuppressWarnings("unchecked")
- public <T> void createConsensusSequence() {
- ConsensusSequenceArea area = getConsensusHintDataArea();
- AlignmentModel<T> model = (AlignmentModel<T>)getEditableConsensusArea().getAlignmentModel();
- int sequenceID = model.sequenceIDIterator().next(); // There is always one sequence contained.
- int length = getReadsArea().getAlignmentModel().getMaxSequenceLength();
-
- Collection<T> tokens = new ArrayList<T>(length);
- for (int column = 0; column < length; column++) {
- tokens.add(model.getTokenSet().tokenByRepresentation(area.getConsensusToken(column)));
- }
-
- model.removeTokensAt(sequenceID, 0, model.getSequenceLength(sequenceID));
- model.insertTokensAt(sequenceID, 0, tokens);
- }
-
-
- /**
- * Updates the current consensus sequence by replacing gaps by the according consensus tokens
- * calculated from the single read sequences and extends the consensus sequence if necessary.
- */
- @SuppressWarnings("unchecked")
- public <T> void updateConsensusSequence() {
- ConsensusSequenceArea area = getConsensusHintDataArea();
- AlignmentModel<T> model = (AlignmentModel<T>)getEditableConsensusArea().getAlignmentModel();
- TokenSet<T> tokenSet = model.getTokenSet();
- int sequenceID = model.sequenceIDIterator().next(); // There is always one sequence contained.
- int currentConsensusLength = model.getSequenceLength(sequenceID);
- int overallLength = getReadsArea().getAlignmentModel().getMaxSequenceLength();
-
- // Replace gaps by new information:
- for (int column = 0; column < currentConsensusLength; column++) {
- if (tokenSet.isGapToken(model.getTokenAt(sequenceID, column))) {
- T newToken = tokenSet.tokenByRepresentation(area.getConsensusToken(column));
- if (!tokenSet.isGapToken(newToken)) {
- model.setTokenAt(sequenceID, column, newToken);
- }
- }
- }
-
- // Append additional tokens:
- if (overallLength > currentConsensusLength) {
- Collection<T> tokens = new ArrayList<T>(overallLength);
- for (int column = currentConsensusLength; column < overallLength; column++) {
- tokens.add(tokenSet.tokenByRepresentation(area.getConsensusToken(column)));
- }
- model.appendTokens(sequenceID, tokens);
- }
- }
-
-
- public static PherogramProvider readPherogram(URI uri) throws IOException, UnsupportedChromatogramFormatException {
- PherogramProvider result;
- InputStream stream = uri.toURL().openStream();
- try {
- result = new BioJavaPherogramProvider(ChromatogramFactory.create(stream));
- }
- finally {
- stream.close();
- }
- return result;
- }
-
-
- private String newReadName() {
- int index = 1;
- while (getReadsArea().getAlignmentModel().sequenceIDByName(DEFAULT_READ_NAME_PREFIX + index)
- != AlignmentModel.NO_SEQUENCE_FOUND) {
-
- index++;
- }
- return DEFAULT_READ_NAME_PREFIX + index;
- }
-
-
- public void addRead(URI pherogramURI, boolean reverseComplemented) throws IOException, UnsupportedChromatogramFormatException {
- addRead(newReadName(), pherogramURI, reverseComplemented, null, null, null, null, null);
- }
-
-
- /**
- * Adds a new sequence with attached phergram data area to the reads alignment.
- * <p>
- * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
- * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
- * and the base calls sequence are assumed.
- *
- * @param name the name of the new sequence
- * @param pherogramURI the URI where the associated pherogram file is located
- * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
- * be added, {@code false} otherwise.
- * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
- * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
- * @return the sequence ID of the added read
- * @throws IOException if an error occurred when trying to read the pherogram file
- * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
- */
- public int addRead(String name, URI pherogramURI, boolean reverseComplemented, String editedSequence,
- Integer firstSeqPos, Integer leftCutPos, Integer rightCutPos, SingleReadAlignment.Shift[] shifts)
- throws IOException, UnsupportedChromatogramFormatException {
-
- AlignmentModel provider = getReadsArea().getAlignmentModel();
- PherogramProvider pherogramProvider = null;
- if (pherogramURI != null) {
- pherogramProvider = readPherogram(pherogramURI); // Must happen before a sequence is added, because it might throw an exception.
- if (reverseComplemented) {
- pherogramProvider = new ReverseComplementPherogramProvider(pherogramProvider);
- }
- }
-
- // Create sequence:
- provider.addSequence(name);
- int id = provider.sequenceIDByName(name);
-
- // Set edited sequence:
- Collection<Object> tokens = null; // First save tokens in a collection to avoid GUI updated for each token.
- if (editedSequence != null) {
- tokens = AlignmentModelUtils.charSequenceToTokenList(editedSequence, provider.getTokenSet());
- }
- else if (pherogramProvider != null) { // Copy base call sequence into alignment:
- tokens = new ArrayList<Object>();
- for (int i = 0; i < pherogramProvider.getSequenceLength(); i++) {
- tokens.add(provider.getTokenSet().tokenByRepresentation(
- Character.toString(pherogramProvider.getBaseCall(i))));
- }
- setDirty();
- }
-
- if (tokens != null) { // If either an edited sequence or a pherogram URI was provided.
- provider.insertTokensAt(id, 0, tokens);
- // Create pherogram area:
- PherogramArea pherogramArea = new PherogramArea(getReadsArea().getContentArea(),
- new PherogramAreaModel(pherogramProvider));
-
- // Set position properties and shifts:
- PherogramAreaModel model = pherogramArea.getModel();
- if ((firstSeqPos != null) && (leftCutPos != null)) {
- model.setFirstSeqLeftCutPos(firstSeqPos, leftCutPos);
- }
- if (rightCutPos != null) {
- model.setRightCutPosition(rightCutPos);
- }
- if ((shifts != null) && (shifts.length > 0)) {
- for (int i = 0; i < shifts.length; i++) {
- model.addShiftChange(shifts[i].position, shifts[i].shift);
- }
- setDirty();
- }
-
- // Add pherogram area to GUI:
- pherogramArea.addMouseListener(new PherogramMouseListener(pherogramArea));
- getReadsArea().getDataAreas().getSequenceAreas(id).add(pherogramArea);
- }
-
- return id;
- }
-}
\ No newline at end of file