Project

General

Profile

« Previous | Next » 

Revision 118433fc

Added by Patrick Plitzner almost 6 years ago

ref #6913 Remove alignment editor

View differences:

eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/AlignmentEditor.java
1
/**
2
* Copyright (C) 2014 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.taxeditor.molecular.editor;
10

  
11

  
12
import java.io.File;
13
import java.io.IOException;
14
import java.io.InputStream;
15
import java.net.URI;
16
import java.util.ArrayList;
17
import java.util.Collection;
18
import java.util.Collections;
19
import java.util.Iterator;
20
import java.util.List;
21
import java.util.Map;
22
import java.util.TreeMap;
23

  
24
import org.biojava.bio.chromatogram.ChromatogramFactory;
25
import org.biojava.bio.chromatogram.UnsupportedChromatogramFormatException;
26
import org.eclipse.core.runtime.IProgressMonitor;
27
import org.eclipse.swt.SWT;
28
import org.eclipse.swt.dnd.Clipboard;
29
import org.eclipse.swt.widgets.Composite;
30
import org.eclipse.swt.widgets.Display;
31
import org.eclipse.ui.IActionBars;
32
import org.eclipse.ui.IEditorInput;
33
import org.eclipse.ui.IEditorPart;
34
import org.eclipse.ui.IEditorSite;
35
import org.eclipse.ui.PartInitException;
36
import org.eclipse.ui.PlatformUI;
37
import org.eclipse.ui.commands.ICommandService;
38
import org.eclipse.ui.part.EditorPart;
39

  
40
import eu.etaxonomy.cdm.api.conversation.ConversationHolder;
41
import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
42
import eu.etaxonomy.cdm.model.media.MediaUtils;
43
import eu.etaxonomy.cdm.model.molecular.Sequence;
44
import eu.etaxonomy.cdm.model.molecular.SequenceString;
45
import eu.etaxonomy.cdm.model.molecular.SingleRead;
46
import eu.etaxonomy.cdm.model.molecular.SingleReadAlignment;
47
import eu.etaxonomy.taxeditor.model.MessagingUtils;
48
import eu.etaxonomy.taxeditor.molecular.TaxeditorMolecularPlugin;
49
import eu.etaxonomy.taxeditor.molecular.handler.ToggleInsertOverwriteHandler;
50
import eu.etaxonomy.taxeditor.molecular.handler.ToggleLeftRightInsertionHandler;
51
import eu.etaxonomy.taxeditor.molecular.l10n.Messages;
52
import eu.etaxonomy.taxeditor.store.CdmStore;
53
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
54
import info.bioinfweb.commons.swt.SWTUtils;
55
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
56
import info.bioinfweb.libralign.alignmentarea.selection.SelectionModel;
57
import info.bioinfweb.libralign.alignmentarea.tokenpainter.NucleotideTokenPainter;
58
import info.bioinfweb.libralign.dataarea.implementations.ConsensusSequenceArea;
59
import info.bioinfweb.libralign.dataarea.implementations.pherogram.PherogramArea;
60
import info.bioinfweb.libralign.dataarea.implementations.sequenceindex.SequenceIndexArea;
61
import info.bioinfweb.libralign.editsettings.EditSettingsChangeEvent;
62
import info.bioinfweb.libralign.editsettings.EditSettingsListener;
63
import info.bioinfweb.libralign.model.AlignmentModel;
64
import info.bioinfweb.libralign.model.AlignmentModelChangeListener;
65
import info.bioinfweb.libralign.model.adapters.StringAdapter;
66
import info.bioinfweb.libralign.model.events.SequenceChangeEvent;
67
import info.bioinfweb.libralign.model.events.SequenceRenamedEvent;
68
import info.bioinfweb.libralign.model.events.TokenChangeEvent;
69
import info.bioinfweb.libralign.model.implementations.PackedAlignmentModel;
70
import info.bioinfweb.libralign.model.tokenset.CharacterTokenSet;
71
import info.bioinfweb.libralign.model.tokenset.TokenSet;
72
import info.bioinfweb.libralign.model.utils.AlignmentModelUtils;
73
import info.bioinfweb.libralign.multiplealignments.AlignmentAreaList;
74
import info.bioinfweb.libralign.multiplealignments.MultipleAlignmentsContainer;
75
import info.bioinfweb.libralign.pherogram.model.PherogramAlignmentRelation;
76
import info.bioinfweb.libralign.pherogram.model.PherogramAreaModel;
77
import info.bioinfweb.libralign.pherogram.model.ShiftChange;
78
import info.bioinfweb.libralign.pherogram.provider.BioJavaPherogramProvider;
79
import info.bioinfweb.libralign.pherogram.provider.PherogramProvider;
80
import info.bioinfweb.libralign.pherogram.provider.ReverseComplementPherogramProvider;
81
import info.bioinfweb.tic.SWTComponentFactory;
82

  
83

  
84

  
85
/**
86
 * Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
87
 * a consensus sequence.
88
 * <p>
89
 * The contained GUI components used to edit the alignment come from <a href="http://bioinfweb.info/LibrAlign/">LibrAlign</a>.
90
 *
91
 * @author Ben Stöver
92
 * @author pplitzner
93
 * @date 04.08.2014
94
 */
95
public class AlignmentEditor extends EditorPart {
96
    public static final String ID = "eu.etaxonomy.taxeditor.molecular.AlignmentEditor"; //$NON-NLS-1$
97

  
98
	public static final int READS_AREA_INDEX = 1;
99
    public static final int EDITABLE_CONSENSUS_AREA_INDEX = READS_AREA_INDEX + 1;
100
    public static final int CONSENSUS_HINT_AREA_INDEX = EDITABLE_CONSENSUS_AREA_INDEX + 1;
101
	public static final int PHEROGRAM_AREA_INDEX = 0;
102
	public static final int CONSENSUS_DATA_AREA_INDEX = 0;
103
	public static final String DEFAULT_READ_NAME_PREFIX = "Read "; //$NON-NLS-1$
104
	public static final String CONSENSUS_NAME = "Consensus"; //$NON-NLS-1$
105

  
106

  
107
    private final ConversationHolder conversationHolder;
108
	private final AlignmentModelChangeListener DIRTY_LISTENER = new AlignmentModelChangeListener() {
109
				@Override
110
				public <T> void afterTokenChange(TokenChangeEvent<T> e) {
111
					setDirty();
112
				}
113

  
114
				@Override
115
				public <T> void afterSequenceRenamed(SequenceRenamedEvent<T> e) {
116
					setDirty();
117
				}
118

  
119
				@Override
120
				public <T> void afterSequenceChange(SequenceChangeEvent<T> e) {
121
					setDirty();
122
				}
123

  
124
				@Override
125
				public <T, U> void afterProviderChanged(AlignmentModel<T> oldProvider,
126
						AlignmentModel<U> newProvider) {  // Not expected.
127

  
128
					setDirty();
129
				}
130
			};
131
	private final AlignmentEditorActionUpdater ACTION_UPDATER = new AlignmentEditorActionUpdater();
132
	public final Clipboard CLIPBOARD = new Clipboard(Display.getCurrent());  //TODO Move to global EDITor class.
133

  
134

  
135
    private MultipleAlignmentsContainer alignmentsContainer = null;
136
    private final Map<String, SingleReadAlignment> cdmMap = new TreeMap<String, SingleReadAlignment>();  //TODO Move this to ContigSequenceDataProvider
137
    private boolean dirty = false;
138

  
139

  
140
    public AlignmentEditor() {
141
    	super();
142
    	conversationHolder = CdmStore.createConversation();
143
    	//conversationHolder = null;
144
    }
145

  
146

  
147
    private void refreshToolbarElement(String id) {
148
		ICommandService commandService =
149
				(ICommandService)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService.class);
150
		if (commandService != null) {
151
			commandService.refreshElements(id, Collections.EMPTY_MAP);
152
		}
153
    }
154

  
155

  
156
    private void registerEditSettingListener(MultipleAlignmentsContainer container) {
157
        container.getEditSettings().addListener(new EditSettingsListener() {
158
            @Override
159
            public void workingModeChanged(EditSettingsChangeEvent e) {}  // Currently nothing to do
160

  
161
            @Override
162
            public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e) {
163
                updateStatusBar();
164
                refreshToolbarElement(ToggleLeftRightInsertionHandler.COMMAND_ID);
165
            }
166

  
167
            @Override
168
            public void insertChanged(EditSettingsChangeEvent e) {
169
                updateStatusBar();
170
                refreshToolbarElement(ToggleInsertOverwriteHandler.COMMAND_ID);
171
            }
172
        });
173
    }
174

  
175

  
176
    private AlignmentArea createIndexArea(MultipleAlignmentsContainer container, AlignmentArea labeledArea) {
177
		AlignmentArea result = new AlignmentArea(container);
178
		result.setAllowVerticalScrolling(false);
179
		result.getDataAreas().getTopAreas().add(new SequenceIndexArea(result.getContentArea(), labeledArea));
180
		return result;
181
    }
182

  
183

  
184
    private AlignmentArea createEditableAlignmentArea(MultipleAlignmentsContainer container, boolean allowVerticalScrolling) {
185
		AlignmentArea result = new AlignmentArea(container);
186
		result.setAllowVerticalScrolling(allowVerticalScrolling);
187

  
188
		CharacterTokenSet tokenSet = CharacterTokenSet.newDNAInstance();  //TODO Should NUCLEOTIDE be used instead?
189
		AlignmentModel<Character> model = new PackedAlignmentModel<Character>(tokenSet);
190
		result.setAlignmentModel(model, false);
191
		model.getChangeListeners().add(DIRTY_LISTENER);
192
		result.getPaintSettings().getTokenPainterList().set(0, new NucleotideTokenPainter());
193

  
194
		return result;
195
	}
196

  
197

  
198
    private AlignmentArea createConsensusHintArea(MultipleAlignmentsContainer container,
199
    		AlignmentArea labeledArea) {
200

  
201
		AlignmentArea result = new AlignmentArea(container);
202
		result.setAllowVerticalScrolling(false);
203
		result.getDataAreas().getBottomAreas().add(
204
				new ConsensusSequenceArea(result.getContentArea(), labeledArea));
205
		return result;
206
    }
207

  
208

  
209
    private MultipleAlignmentsContainer getAlignmentsContainer() {
210
    	if (alignmentsContainer == null) {
211
    		alignmentsContainer = new MultipleAlignmentsContainer();
212

  
213
    		AlignmentAreaList list = alignmentsContainer.getAlignmentAreas();
214
    		AlignmentArea readsArea = createEditableAlignmentArea(alignmentsContainer, true);
215
    		readsArea.getSelection().addSelectionListener(ACTION_UPDATER);
216
    	    list.add(createIndexArea(alignmentsContainer, readsArea));
217
    		list.add(readsArea);  // Make sure READS_AREA_INDEX is correct.
218
    		AlignmentArea editableConsensusArea = createEditableAlignmentArea(alignmentsContainer, false);
219
    		editableConsensusArea.getSelection().addSelectionListener(ACTION_UPDATER);
220
    		list.add(editableConsensusArea);  // Make sure COMSENSUS_AREA_INDEX is correct.
221
    		list.add(createConsensusHintArea(alignmentsContainer, readsArea));
222

  
223
    		registerEditSettingListener(alignmentsContainer);
224
       	}
225
		return alignmentsContainer;
226
	}
227

  
228

  
229
    public AlignmentArea getReadsArea() {
230
    	return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX);
231
    }
232

  
233

  
234
    public AlignmentArea getEditableConsensusArea() {
235
    	return getAlignmentsContainer().getAlignmentAreas().get(EDITABLE_CONSENSUS_AREA_INDEX);
236
    }
237

  
238

  
239
    /**
240
     * Checks whether {@link #getReadsArea()} or {@link #getEditableConsensusArea()} currently
241
     * have the user focus and returns the according component.
242
     *
243
     * @return either the reads or the consensus alignment area or {@code null} if none of these
244
     *         components is currently focused
245
     */
246
    public AlignmentArea getFocusedArea() {
247
    	AlignmentArea result = getReadsArea();
248
    	if (hasFocus(result)) {
249
    		return result;
250
    	}
251
    	else {
252
    		result = getEditableConsensusArea();
253
        	if (hasFocus(result)) {
254
        		return result;
255
        	}
256
        	else {
257
        		return null;
258
        	}
259
    	}
260
    }
261

  
262

  
263
    /**
264
     * Checks whether the specified alignment area or one of its subcomponents currently has the
265
     * focus.
266
     *
267
     * @param area the alignment area to be checked (Can only be {@link #getReadsArea()} or
268
     *        {@link #getEditableConsensusArea()}.)
269
     * @return {@code true} if the specified component is focused and is either equal to
270
     *         {@link #getReadsArea()} or {@link #getEditableConsensusArea()}or {@code false} otherwise
271
     */
272
    private boolean hasFocus(AlignmentArea area) {
273
    	return SWTUtils.childHasFocus((Composite)area.getToolkitComponent());
274
    }
275

  
276

  
277
    public boolean hasPherogram(String sequenceID) {
278
        return getReadsArea().getDataAreas().getSequenceAreas(sequenceID).size() > PHEROGRAM_AREA_INDEX;
279
    }
280

  
281

  
282
    public PherogramArea getPherogramArea(String sequenceID) {
283
        if (hasPherogram(sequenceID)) {
284
            return (PherogramArea)getReadsArea().getDataAreas().getSequenceAreas(sequenceID).get(PHEROGRAM_AREA_INDEX);
285
        }
286
        else {
287
            return null;
288
        }
289
    }
290

  
291

  
292
    private ConsensusSequenceArea getConsensusHintDataArea() {
293
        return (ConsensusSequenceArea)getAlignmentsContainer().getAlignmentAreas().
294
                get(CONSENSUS_HINT_AREA_INDEX).getDataAreas().getBottomAreas().
295
                get(CONSENSUS_DATA_AREA_INDEX);
296
    }
297

  
298

  
299
    @Deprecated  //TODO Remove as soon as testing period is over
300
    private void createTestContents() {
301
		// Just for testing:
302
		try {
303
			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); //$NON-NLS-1$
304
            //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);
305
            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); //$NON-NLS-1$
306

  
307
			// Add test consensus sequence:
308
			AlignmentModel consensusModel = getEditableConsensusArea().getAlignmentModel();
309
			String id = consensusModel.addSequence(CONSENSUS_NAME);
310
			Collection<Object> tokens = new ArrayList<Object>();  // First save tokens in a collection to avoid GUI updated for each token.
311
			tokens.add(consensusModel.getTokenSet().tokenByRepresentation("A")); //$NON-NLS-1$
312
			tokens.add(consensusModel.getTokenSet().tokenByRepresentation("C")); //$NON-NLS-1$
313
			tokens.add(consensusModel.getTokenSet().tokenByRepresentation("G")); //$NON-NLS-1$
314
			tokens.add(consensusModel.getTokenSet().tokenByRepresentation("T")); //$NON-NLS-1$
315
			consensusModel.insertTokensAt(id, 0, tokens);
316
		}
317
		catch (Exception e) {
318
			throw new RuntimeException(e);
319
		}
320
    }
321

  
322

  
323
    private void readCDMData(Sequence sequenceNode) {
324
    	//TODO If called from somewhere else than createPartControl() the editorInput needs to be checked and previous contents need to be cleared (or updated).
325

  
326
		// Add reads:
327
		for (SingleReadAlignment singleReadAlignment : sequenceNode.getSingleReadAlignments()) {
328
			try {
329
				SingleRead pherogramInfo = singleReadAlignment.getSingleRead();
330
				String id = addRead(DerivateLabelProvider.getDerivateText(pherogramInfo, conversationHolder),
331
						getPherogramURI(pherogramInfo),
332
						singleReadAlignment.isReverseComplement(),
333
						singleReadAlignment.getEditedSequence(),
334
						singleReadAlignment.getFirstSeqPosition(),
335
						singleReadAlignment.getLeftCutPosition(),
336
						singleReadAlignment.getRightCutPosition(),
337
						singleReadAlignment.getShifts());
338
				cdmMap.put(id, singleReadAlignment);
339
			}
340
			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).
341
                MessagingUtils.errorDialog(Messages.AlignmentEditor_ERROR_SINGLE_READ, null, Messages.AlignmentEditor_ERROR_SINGLE_READ_MESSAGE +
342
                        e.getLocalizedMessage(), TaxeditorMolecularPlugin.PLUGIN_ID, e, false);
343
			}
344
		}
345

  
346
		// Set consensus sequence:
347
		AlignmentModel consensusModel = getEditableConsensusArea().getAlignmentModel();
348
		String id = consensusModel.addSequence(CONSENSUS_NAME);
349
		consensusModel.insertTokensAt(id, 0, AlignmentModelUtils.charSequenceToTokenList(
350
				sequenceNode.getConsensusSequence().getString(), consensusModel.getTokenSet()));
351
		//TODO Can the consensus sequence also be null? / Should it be created here, if nothing is in the DB?
352
    }
353

  
354

  
355
    @Override
356
    public void createPartControl(Composite parent) {
357
		SWTComponentFactory.getInstance().getSWTComponent(getAlignmentsContainer(), parent, SWT.NONE);
358
		Display.getCurrent().addFilter(SWT.FocusIn, ACTION_UPDATER);
359
		Display.getCurrent().addFilter(SWT.FocusOut, ACTION_UPDATER);
360
		updateStatusBar();
361

  
362
		if (getEditorInput() instanceof AlignmentEditorInput) {
363
			if (((AlignmentEditorInput)getEditorInput()).getSequenceNodeUuid() != null) {
364
			    Sequence sequenceNode = CdmStore.getService(ISequenceService.class).load(((AlignmentEditorInput)getEditorInput()).getSequenceNodeUuid());
365
		        //re-load into the current session if it is already persisted in the DB
366
		        if(sequenceNode!=null && sequenceNode.getId()!=0){
367
		            sequenceNode = CdmStore.getService(ISequenceService.class).load(sequenceNode.getUuid());
368
		        }
369
				readCDMData(sequenceNode);
370
			}
371
			else {
372
				createTestContents();  // This case will removed after the test phase and an exception should probably be thrown.
373
			}
374
		}
375
		else {
376
			throw new IllegalArgumentException(String.format(Messages.AlignmentEditor_MUST_HAVE_TYPE,
377
					AlignmentEditorInput.class.getCanonicalName()));  //TODO What should be done here?
378
		}
379
	}
380

  
381

  
382
    @Override
383
	public void dispose() {
384
		Display.getCurrent().removeFilter(SWT.FocusIn, ACTION_UPDATER);
385
		Display.getCurrent().removeFilter(SWT.FocusOut, ACTION_UPDATER);
386
		CLIPBOARD.dispose();
387
        ((AlignmentEditorInput)getEditorInput()).dispose();
388
		super.dispose();
389
	}
390

  
391

  
392
	private void updateStatusBar() {
393
        IActionBars bars = getEditorSite().getActionBars();
394
        bars.getStatusLineManager().setMessage(
395
                Messages.AlignmentEditor_EDIT_MODE + (getReadsArea().getEditSettings().isInsert() ? Messages.AlignmentEditor_INSERT : Messages.AlignmentEditor_OVERWRITE) + "  " + //$NON-NLS-1$
396
        		Messages.AlignmentEditor_INSERTION_PHEROGRAM +
397
	       		(getReadsArea().getEditSettings().isInsertLeftInDataArea() ? Messages.AlignmentEditor_LEFT : Messages.AlignmentEditor_RIGHT));  //TODO multi language
398
    }
399

  
400

  
401
    private SingleReadAlignment.Shift[] convertToCDMShifts(PherogramAreaModel model) {
402
    	Iterator<ShiftChange> iterator = model.shiftChangeIterator();
403
    	List<SingleReadAlignment.Shift> shifts = new ArrayList<SingleReadAlignment.Shift>();
404
    	while (iterator.hasNext()) {
405
    		ShiftChange shiftChange = iterator.next();
406
    		shifts.add(new SingleReadAlignment.Shift(shiftChange.getBaseCallIndex(), shiftChange.getShiftChange()));
407
    	}
408
    	return shifts.toArray(new SingleReadAlignment.Shift[shifts.size()]);
409
    }
410

  
411

  
412
    @Override
413
    public void doSave(IProgressMonitor monitor) {
414
    	if (getEditorInput() instanceof AlignmentEditorInput) {
415
        	String taskName = Messages.AlignmentEditor_SAVING_ALIGNMENT;  //TODO multi language
416
            monitor.beginTask(taskName, 3);
417

  
418
            //re-loading sequence to avoid session conflicts
419
    		Sequence sequenceNode = CdmStore.getService(ISequenceService.class).load(((AlignmentEditorInput)getEditorInput()).getSequenceNodeUuid());
420
    		((AlignmentEditorInput)getEditorInput()).setSequenceNode(sequenceNode);
421
    		StringAdapter stringProvider = new StringAdapter(getEditableConsensusArea().getAlignmentModel(), false);  // Throws an exception if a token has more than one character.
422

  
423
    		// Write consensus sequence:
424
    		SequenceString consensusSequenceObj = sequenceNode.getConsensusSequence();
425
    		String newConsensusSequence = stringProvider.getSequence(
426
    				getEditableConsensusArea().getAlignmentModel().sequenceIDByName(CONSENSUS_NAME));
427
    		if (consensusSequenceObj == null) {
428
    			sequenceNode.setConsensusSequence(SequenceString.NewInstance(newConsensusSequence));
429
    		}
430
    		else {
431
    			consensusSequenceObj.setString(newConsensusSequence);
432
    		}
433

  
434
    		// Write single reads:
435
    		stringProvider.setUnderlyingModel(getReadsArea().getAlignmentModel());
436
    		sequenceNode.getSingleReadAlignments().retainAll(cdmMap.values());  // Remove all reads that are not in the alignment anymore.
437
    		Iterator<String> iterator = getReadsArea().getAlignmentModel().sequenceIDIterator();
438
    		while (iterator.hasNext()) {
439
    			String id = iterator.next();
440
    			SingleReadAlignment singleRead = cdmMap.get(id);
441
    			if (singleRead == null) {
442
    			    throw new InternalError(Messages.AlignmentEditor_NEW_READ_FAILURE);  //TODO multi language
443
    				//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?
444
    				//singleRead = SingleReadAlignment.NewInstance(consensusSequence, singleRead, shifts, editedSequence);
445
    			}
446

  
447
    			singleRead.setEditedSequence(stringProvider.getSequence(id));
448

  
449
    			PherogramArea pherogramArea = getPherogramArea(id);
450
    			if (pherogramArea != null) {
451
        			PherogramAreaModel model = pherogramArea.getModel();
452
        			singleRead.setReverseComplement(model.getPherogramProvider() instanceof ReverseComplementPherogramProvider);  // Works only if ReverseComplementPherogramProvider instances are not nested.
453
        			singleRead.setShifts(convertToCDMShifts(getPherogramArea(id).getModel()));
454
        			singleRead.setFirstSeqPosition(model.getFirstSeqPos());
455
        			singleRead.setLeftCutPosition(model.getLeftCutPosition());
456
        			singleRead.setRightCutPosition(model.getRightCutPosition());
457
    			}
458
    		}
459

  
460
    		if (!conversationHolder.isBound()) {
461
                conversationHolder.bind();
462
            }
463
            monitor.worked(1);
464

  
465
            ((AlignmentEditorInput)getEditorInput()).merge();
466
            // Commit the conversation and start a new transaction immediately:
467
            conversationHolder.commit(true);
468
            monitor.worked(1);
469

  
470
            dirty = false;
471
            monitor.worked(1);
472
            monitor.done();
473
            firePropertyChange(PROP_DIRTY);
474
    	}
475
    	else {
476
    		//TODO Throw exception as soon as testing period which allows unlinked AlignmentEditor is over.
477
    	}
478
    }
479

  
480

  
481
    @Override
482
    public void doSaveAs() {}
483

  
484

  
485
    @Override
486
    public void init(IEditorSite site, IEditorInput input) throws PartInitException {
487
        setSite(site);
488
        setInput(input);
489
    }
490

  
491

  
492
    @Override
493
    public boolean isDirty() {
494
        return dirty;
495
    }
496

  
497

  
498
    private void setDirty() {
499
    	dirty = true;
500
    	firePropertyChange(IEditorPart.PROP_DIRTY);
501
    }
502

  
503

  
504
    @Override
505
    public boolean isSaveAsAllowed() {
506
        return false;  // "Save as" not allowed.
507
    }
508

  
509

  
510
    @Override
511
    public void setFocus() {
512
        if(conversationHolder != null){
513
            conversationHolder.bind();
514
        }
515
        ((AlignmentEditorInput)getEditorInput()).bind();
516
    }
517

  
518
    public boolean isInsertMode() {
519
        return getAlignmentsContainer().getEditSettings().isInsert();
520
    }
521

  
522

  
523
    public boolean isInsertLeftInPherogram() {
524
        return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
525
    }
526

  
527

  
528
    public void toggleLeftRightInsertionInPherogram() {
529
    	getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
530
    }
531

  
532

  
533
    public void toggleInsertOverwrite() {
534
    	getAlignmentsContainer().getEditSettings().toggleInsert();
535
    }
536

  
537

  
538
    private String cutPherogram(boolean left) {
539
        SelectionModel selection = getReadsArea().getSelection();
540
        if (selection.getCursorHeight() != 1) {
541
            return Messages.AlignmentEditor_CUTTING_FAILURE;  //TODO multi language
542
        }
543
        else {
544
            PherogramArea pherogramArea =
545
                    getPherogramArea(getReadsArea().getSequenceOrder().idByIndex(selection.getCursorRow()));
546
            if (pherogramArea == null) {
547
                return Messages.AlignmentEditor_NO_ATTACHED_PHEROGRAM;  //TODO multi language
548
            }
549
            else {
550
                if (left) {
551
                    if (pherogramArea.setLeftCutPositionBySelection()) {
552
                        return null;
553
                    }
554
                    else {
555
                        return Messages.AlignmentEditor_LEFT_END_OUTSIDE;  //TODO multi language
556
                    }
557
                }
558
                else {
559
                    if (pherogramArea.setRightCutPositionBySelection()) {
560
                        return null;
561
                    }
562
                    else {
563
                        return Messages.AlignmentEditor_RIGHT_END_OUTSIDE;  //TODO multi language
564
                    }
565
                }
566
            }
567
        }
568
    }
569

  
570

  
571
    public String cutPherogramLeft() {
572
        return cutPherogram(true);
573
    }
574

  
575

  
576
    public String cutPherogramRight() {
577
        return cutPherogram(false);
578
    }
579

  
580

  
581
    public void reverseComplementSelectedSequences() {
582
    	SelectionModel selection = getReadsArea().getSelection();
583
    	AlignmentModel<?> model = getReadsArea().getAlignmentModel();
584
    	for (int row = selection.getFirstRow(); row < selection.getFirstRow() + selection.getCursorHeight(); row++) {
585
    		String sequenceID = getReadsArea().getSequenceOrder().idByIndex(row);
586
			PherogramArea area = getPherogramArea(sequenceID);
587
			PherogramAreaModel pherogramAlignmentModel = area.getModel();
588

  
589
            PherogramAlignmentRelation rightRelation = pherogramAlignmentModel.editableIndexByBaseCallIndex(
590
                    pherogramAlignmentModel.getRightCutPosition());
591
            int rightBorder;
592
            if (rightRelation.getCorresponding() == PherogramAlignmentRelation.OUT_OF_RANGE) {
593
                rightBorder = rightRelation.getBeforeValidIndex() + 1;
594
            }
595
            else {
596
                rightBorder = rightRelation.getAfterValidIndex();
597
            }
598

  
599
			AlignmentModelUtils.reverseComplement(model, sequenceID,
600
			        pherogramAlignmentModel.editableIndexByBaseCallIndex(
601
			                pherogramAlignmentModel.getLeftCutPosition()).getBeforeValidIndex(),
602
			        rightBorder);
603
			pherogramAlignmentModel.reverseComplement();
604
		}
605
    }
606

  
607

  
608
    /**
609
     * Recreates the whole consensus sequence from all single read sequences. The previous consensus
610
     * sequence is overwritten.
611
     */
612
    @SuppressWarnings("unchecked")
613
    public <T> void createConsensusSequence() {
614
        ConsensusSequenceArea area = getConsensusHintDataArea();
615
        AlignmentModel<T> model = (AlignmentModel<T>)getEditableConsensusArea().getAlignmentModel();
616
        String sequenceID = model.sequenceIDIterator().next();  // There is always one sequence contained.
617
        int length = getReadsArea().getAlignmentModel().getMaxSequenceLength();
618

  
619
        Collection<T> tokens = new ArrayList<T>(length);
620
        for (int column = 0; column < length; column++) {
621
            tokens.add(model.getTokenSet().tokenByRepresentation(area.getConsensusToken(column)));
622
        }
623

  
624
        model.removeTokensAt(sequenceID, 0, model.getSequenceLength(sequenceID));
625
        model.insertTokensAt(sequenceID, 0, tokens);
626
    }
627

  
628

  
629
    /**
630
     * Updates the current consensus sequence by replacing gaps by the according consensus tokens
631
     * calculated from the single read sequences and extends the consensus sequence if necessary.
632
     */
633
    @SuppressWarnings("unchecked")
634
    public <T> void updateConsensusSequence() {
635
        ConsensusSequenceArea area = getConsensusHintDataArea();
636
        AlignmentModel<T> model = (AlignmentModel<T>)getEditableConsensusArea().getAlignmentModel();
637
        TokenSet<T> tokenSet = model.getTokenSet();
638
        String sequenceID = model.sequenceIDIterator().next();  // There is always one sequence contained.
639
        int currentConsensusLength = model.getSequenceLength(sequenceID);
640
        int overallLength = getReadsArea().getAlignmentModel().getMaxSequenceLength();
641

  
642
        // Replace gaps by new information:
643
        for (int column = 0; column < currentConsensusLength; column++) {
644
            if (tokenSet.isGapToken(model.getTokenAt(sequenceID, column))) {
645
                T newToken = tokenSet.tokenByRepresentation(area.getConsensusToken(column));
646
                if (!tokenSet.isGapToken(newToken)) {
647
                    model.setTokenAt(sequenceID, column, newToken);
648
                }
649
            }
650
        }
651

  
652
        // Append additional tokens:
653
        if (overallLength > currentConsensusLength) {
654
            Collection<T> tokens = new ArrayList<T>(overallLength);
655
            for (int column = currentConsensusLength; column < overallLength; column++) {
656
                tokens.add(tokenSet.tokenByRepresentation(area.getConsensusToken(column)));
657
            }
658
            model.appendTokens(sequenceID, tokens);
659
        }
660
    }
661

  
662

  
663
	public static PherogramProvider readPherogram(URI uri) throws IOException, UnsupportedChromatogramFormatException {
664
	    PherogramProvider result;
665
		InputStream stream = uri.toURL().openStream();
666
		try {
667
			result = new BioJavaPherogramProvider(ChromatogramFactory.create(stream));
668
		}
669
		finally {
670
			stream.close();
671
		}
672
		return result;
673
	}
674

  
675

  
676
	private String newReadName() {
677
		int index = 1;
678
		while (getReadsArea().getAlignmentModel().sequenceIDByName(DEFAULT_READ_NAME_PREFIX + index) != null) {
679
			index++;
680
		}
681
		return DEFAULT_READ_NAME_PREFIX + index;
682
	}
683

  
684

  
685
    public void addRead(URI pherogramURI, boolean reverseComplemented) throws IOException, UnsupportedChromatogramFormatException {
686
    	addRead(newReadName(), pherogramURI, reverseComplemented, null, null, null, null, null);
687
    }
688

  
689

  
690
    /**
691
     * Adds a new sequence with attached phergram data area to the reads alignment.
692
     * <p>
693
     * If {@code null} is specified as {@code editedSequence} the base call sequence from the pherogram will
694
     * be set as the edited sequence. If {@code null} is specified as {@code shifts} no shifts between the edited
695
     * and the base calls sequence are assumed.
696
     *
697
     * @param name the name of the new sequence
698
     * @param pherogramURI the URI where the associated pherogram file is located
699
     * @param reverseComplemented Specify {@code true} here, if the reverse complement of the pherogram data should
700
     *        be added, {@code false} otherwise.
701
     * @param editedSequence the edited version of the base call sequence (May be {@code null}.)
702
     * @param shifts the alignment information that links the edited and the base call sequence (May be {@code null}.)
703
     * @return the sequence ID of the added read
704
     * @throws IOException if an error occurred when trying to read the pherogram file
705
     * @throws UnsupportedChromatogramFormatException if the format of the pherogram file is not supported
706
     */
707
    public String addRead(String name, URI pherogramURI, boolean reverseComplemented, String editedSequence,
708
            Integer firstSeqPos, Integer leftCutPos, Integer rightCutPos, SingleReadAlignment.Shift[] shifts)
709
            throws IOException, UnsupportedChromatogramFormatException {
710

  
711
		AlignmentModel model = getReadsArea().getAlignmentModel();
712
		PherogramProvider pherogramProvider = null;
713
		if (pherogramURI != null) {
714
		    pherogramProvider = readPherogram(pherogramURI);  // Must happen before a sequence is added, because it might throw an exception.
715
            if (reverseComplemented) {
716
                pherogramProvider = new ReverseComplementPherogramProvider(pherogramProvider);
717
            }
718
		}
719

  
720
        // Create sequence:
721
		model.addSequence(name);
722
		String id = model.sequenceIDByName(name);
723

  
724
		// Set edited sequence:
725
		Collection<Object> tokens = null;  // First save tokens in a collection to avoid GUI updated for each token.
726
		if (editedSequence != null) {
727
			tokens = AlignmentModelUtils.charSequenceToTokenList(editedSequence, model.getTokenSet());
728
		}
729
		else if (pherogramProvider != null) {  // Copy base call sequence into alignment:
730
			tokens = new ArrayList<Object>();
731
			for (int i = 0; i < pherogramProvider.getSequenceLength(); i++) {
732
				tokens.add(model.getTokenSet().tokenByRepresentation(
733
					Character.toString(pherogramProvider.getBaseCall(i))));
734
			}
735
			setDirty();
736
		}
737

  
738
		if (tokens != null) {  // If either an edited sequence or a pherogram URI was provided.
739
		    model.insertTokensAt(id, 0, tokens);
740

  
741
		    if (pherogramProvider != null) {
742
		        // Create pherogram area:
743
		        PherogramArea pherogramArea = new PherogramArea(getReadsArea().getContentArea(),
744
		                new PherogramAreaModel(pherogramProvider));
745

  
746
		        // Set position properties and shifts:
747
		        PherogramAreaModel phergramModel = pherogramArea.getModel();
748
		        if ((firstSeqPos != null) && (leftCutPos != null)) {
749
		            phergramModel.setFirstSeqLeftCutPos(firstSeqPos, leftCutPos);
750
		        }
751
		        if (rightCutPos != null) {
752
		            phergramModel.setRightCutPosition(rightCutPos);
753
		        }
754
		        if ((shifts != null) && (shifts.length > 0)) {
755
		            for (int i = 0; i < shifts.length; i++) {
756
		                phergramModel.addShiftChange(shifts[i].position, shifts[i].shift);
757
		            }
758
		            setDirty();
759
		        }
760

  
761
		        // Add pherogram area to GUI:
762
		        pherogramArea.addMouseListener(new PherogramMouseListener(pherogramArea));
763
		        getReadsArea().getDataAreas().getSequenceAreas(id).add(pherogramArea);
764
		    }
765
		}
766
		return id;
767
	}
768

  
769

  
770
    public static URI getPherogramURI(SingleRead pherogramInfo) {
771
        if (pherogramInfo.getPherogram() != null) {
772
            return MediaUtils.getFirstMediaRepresentationPart(pherogramInfo.getPherogram()).getUri();
773
        }
774
        else {
775
            return null;
776
        }
777
    }
778
}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/AlignmentEditorActionUpdater.java
7 7
import org.eclipse.ui.actions.ActionFactory;
8 8
import org.eclipse.ui.commands.ICommandService;
9 9

  
10
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
10 11
import eu.etaxonomy.taxeditor.molecular.handler.AbstractAlignmentEditorHandler;
11 12
import info.bioinfweb.libralign.alignmentarea.selection.SelectionChangeEvent;
12 13
import info.bioinfweb.libralign.alignmentarea.selection.SelectionListener;
......
15 16

  
16 17
/**
17 18
 * Listener used to update copy/paste events associated with {@link AlignmentEditor}.
18
 * 
19
 *
19 20
 * @author Ben Stöver
20 21
 * @date 25.08.2015
21 22
 */
22 23
public class AlignmentEditorActionUpdater implements SelectionListener, Listener {
23
	private static final String[] IDS = {ActionFactory.COPY.getCommandId(), ActionFactory.CUT.getCommandId(), 
24
	private static final String[] IDS = {ActionFactory.COPY.getCommandId(), ActionFactory.CUT.getCommandId(),
24 25
		ActionFactory.PASTE.getCommandId()};
25
	
26
	
26

  
27

  
27 28
	private void updateEvents() {
28
		ICommandService service = (ICommandService)PlatformUI.getWorkbench().getService(ICommandService.class);
29
		ICommandService service = PlatformUI.getWorkbench().getService(ICommandService.class);
29 30
		for (int i = 0; i < IDS.length; i++) {
30 31
	        service.refreshElements(IDS[i], null);
31 32
		}
32 33
	}
33
	
34
	
34

  
35

  
35 36
	@Override
36 37
	public void handleEvent(Event event) {
37
		AlignmentEditor editor = AbstractAlignmentEditorHandler.getActiveAlignmentEditor();
38
		AlignmentEditorE4 editor = AbstractAlignmentEditorHandler.getActiveAlignmentEditor();
38 39
		if (editor != null) {
39 40
            updateEvents();
40 41
		}
41 42
	}
42 43

  
43
	
44

  
44 45
	@Override
45 46
	public void selectionChanged(SelectionChangeEvent e) {
46
		AlignmentEditor editor = AbstractAlignmentEditorHandler.getActiveAlignmentEditor();
47
		AlignmentEditorE4 editor = AbstractAlignmentEditorHandler.getActiveAlignmentEditor();
47 48
		if (editor != null) {
48
			if ((e.getSource() == editor.getReadsArea().getSelection()) || 
49
			if ((e.getSource() == editor.getReadsArea().getSelection()) ||
49 50
					(e.getSource() == editor.getEditableConsensusArea().getSelection())) {
50
				
51

  
51 52
				updateEvents();
52 53
			}
53 54
		}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/PherogramMouseListener.java
13 13
import info.bioinfweb.tic.input.TICMouseAdapter;
14 14
import info.bioinfweb.tic.input.TICMouseEvent;
15 15

  
16
import org.eclipse.ui.PartInitException;
17

  
18
import eu.etaxonomy.taxeditor.model.MessagingUtils;
19
import eu.etaxonomy.taxeditor.molecular.TaxeditorMolecularPlugin;
20
import eu.etaxonomy.taxeditor.molecular.handler.ShowPherogramHandler;
21
import eu.etaxonomy.taxeditor.molecular.l10n.Messages;
22

  
23 16

  
24 17

  
25 18
/**
......
40 33

  
41 34
	@Override
42 35
	public boolean mousePressed(TICMouseEvent event) {
43
		if (event.getClickCount() == 2) {  // Double click
44
			try {
45
			    ShowPherogramHandler.showPherogram(area.getModel());
46
			}
47
			catch (PartInitException e) {
48
                MessagingUtils.errorDialog(Messages.PherogramMouseListener_UNABLE_TO_CREATE_VIEW, null, e.getLocalizedMessage(),
49
                        TaxeditorMolecularPlugin.PLUGIN_ID,  e, false);  //TODO set pluginID
50
			}
51
            return true;
52
		}
53
		else {
36
//		if (event.getClickCount() == 2) {  // Double click
37
//			try {
38
			    //FIXME E4 implement double click functionality
39
//			    ShowPherogramHandler.showPherogram(area.getModel());
40
//			}
41
//			catch (PartInitException e) {
42
//                MessagingUtils.errorDialog(Messages.PherogramMouseListener_UNABLE_TO_CREATE_VIEW, null, e.getLocalizedMessage(),
43
//                        TaxeditorMolecularPlugin.PLUGIN_ID,  e, false);  //TODO set pluginID
44
//			}
45
//            return true;
46
//		}
47
//		else {
54 48
		    return false;
55
		}
49
//		}
56 50
	}
57 51
}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/AlignmentEditorE4.java
51 51
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditorActionUpdater;
52 52
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditorInput;
53 53
import eu.etaxonomy.taxeditor.molecular.editor.PherogramMouseListener;
54
import eu.etaxonomy.taxeditor.molecular.handler.ToggleInsertOverwriteHandler;
55
import eu.etaxonomy.taxeditor.molecular.handler.ToggleLeftRightInsertionHandler;
54
import eu.etaxonomy.taxeditor.molecular.editor.e4.handler.ToggleInsertOverwriteHandlerE4;
55
import eu.etaxonomy.taxeditor.molecular.editor.e4.handler.ToggleLeftRightInsertionHandlerE4;
56 56
import eu.etaxonomy.taxeditor.molecular.l10n.Messages;
57 57
import eu.etaxonomy.taxeditor.store.CdmStore;
58 58
import eu.etaxonomy.taxeditor.view.derivateSearch.DerivateLabelProvider;
......
168 168
            @Override
169 169
            public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e) {
170 170
                updateStatusBar();
171
                refreshToolbarElement(ToggleLeftRightInsertionHandler.COMMAND_ID);
171
                refreshToolbarElement(ToggleLeftRightInsertionHandlerE4.COMMAND_ID);
172 172
            }
173 173

  
174 174
            @Override
175 175
            public void insertChanged(EditSettingsChangeEvent e) {
176 176
                updateStatusBar();
177
                refreshToolbarElement(ToggleInsertOverwriteHandler.COMMAND_ID);
177
                refreshToolbarElement(ToggleInsertOverwriteHandlerE4.COMMAND_ID);
178 178
            }
179 179
        });
180 180
    }
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/PherogramPartE4.java
14 14
import org.eclipse.swt.SWT;
15 15
import org.eclipse.swt.widgets.Composite;
16 16

  
17
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
18 17
import info.bioinfweb.libralign.pherogram.PherogramFormats.QualityOutputType;
19 18
import info.bioinfweb.libralign.pherogram.model.PherogramComponentModel;
20 19
import info.bioinfweb.libralign.pherogram.view.PherogramView;
......
24 23

  
25 24
/**
26 25
 * Component that allows to view a pherogram without the distortion due to aligning it to a sequence as in
27
 * {@link AlignmentEditor}.
26
 * {@link AlignmentEditorE4}.
28 27
 *
29 28
 * @author Ben Stöver
30 29
 * @date Nov 20, 2014
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/AlignmentEditorPasteHandlerE4.java
15 15
import org.eclipse.swt.dnd.TextTransfer;
16 16
import org.eclipse.swt.widgets.Shell;
17 17

  
18
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
19 18
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
20 19
import eu.etaxonomy.taxeditor.molecular.l10n.Messages;
21 20
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
......
27 26

  
28 27

  
29 28
/**
30
 * Handler that pastes the current contents of the clipboard into an active instance of {@link AlignmentEditor}.
29
 * Handler that pastes the current contents of the clipboard into an active instance of {@link AlignmentEditorE4}.
31 30
 *
32 31
 * @author Ben Stöver
33 32
 * @date 26.08.2015
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/CreateConsensusSequenceHandlerE4.java
15 15
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
16 16
import org.eclipse.e4.ui.services.IServiceConstants;
17 17

  
18
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
19 18
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
20 19

  
21 20

  
......
23 22

  
24 23
/**
25 24
 * Handler that creates the consensus sequence from all single read sequences in the active instance
26
 * of {@link AlignmentEditor}. A previously present consensus sequence will be overwritten.
25
 * of {@link AlignmentEditorE4}. A previously present consensus sequence will be overwritten.
27 26
 *
28 27
 * @author Ben Stöver
29 28
 * @date 19.06.2015
30 29
 * @see UpdateConsensusSequenceHandlerE4
31
 * @see AlignmentEditor#createConsensusSequence()
30
 * @see AlignmentEditorE4#createConsensusSequence()
32 31
 */
33 32
public class CreateConsensusSequenceHandlerE4 {
34 33

  
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/LoadPherogramHandlerE4.java
23 23

  
24 24
import eu.etaxonomy.taxeditor.model.MessagingUtils;
25 25
import eu.etaxonomy.taxeditor.molecular.TaxeditorMolecularPlugin;
26
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
27 26
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
28 27
import eu.etaxonomy.taxeditor.molecular.l10n.Messages;
29 28

  
30 29

  
31 30

  
32 31
/**
33
 * Handler that loads an additional read into the contig alignment displayed by an instance of {@link AlignmentEditor}.
32
 * Handler that loads an additional read into the contig alignment displayed by an instance of {@link AlignmentEditorE4}.
34 33
 *
35 34
 * @author Ben Stöver
36 35
 * @author pplitzner
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/ReverseComplementHandlerE4.java
15 15
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
16 16
import org.eclipse.e4.ui.services.IServiceConstants;
17 17

  
18
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
19 18
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
20 19

  
21 20

  
22 21

  
23 22

  
24 23
/**
25
 * Reverse complements the single read sequence in an active {@link AlignmentEditor}, where the alignment cursor
24
 * Reverse complements the single read sequence in an active {@link AlignmentEditorE4}, where the alignment cursor
26 25
 * is currently located.
27 26
 *
28 27
 * @author Ben Stöver
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/ShowPherogramHandlerE4.java
19 19
import eu.etaxonomy.cdm.model.molecular.SingleRead;
20 20
import eu.etaxonomy.taxeditor.model.MessagingUtils;
21 21
import eu.etaxonomy.taxeditor.molecular.TaxeditorMolecularPlugin;
22
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
23
import eu.etaxonomy.taxeditor.molecular.editor.PherogramViewPart;
22
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
24 23
import eu.etaxonomy.taxeditor.molecular.editor.e4.PherogramPartE4;
25 24
import eu.etaxonomy.taxeditor.molecular.l10n.Messages;
26 25
import info.bioinfweb.libralign.pherogram.model.PherogramComponentModel;
......
28 27

  
29 28

  
30 29
/**
31
 * Displays an undistorted pherogram with {@link PherogramViewPart}.
30
 * Displays an undistorted pherogram with {@link PherogramPartE4}.
32 31
 *
33 32
 * @author Ben Stöver
34 33
 */
......
54 53
			        MPart part = partService.createPart(eu.etaxonomy.taxeditor.molecular.AppModelId.PARTDESCRIPTOR_EU_ETAXONOMY_TAXEDITOR_MOLECULAR_EDITOR_E4_PHEROGRAMPARTE4);
55 54
			        part = partService.showPart(part, PartState.ACTIVATE);
56 55
			        PherogramPartE4 pherogramPart = (PherogramPartE4) part.getObject();
57
			        pherogramPart.init(new PherogramComponentModel(AlignmentEditor.readPherogram(uri)));
56
			        pherogramPart.init(new PherogramComponentModel(AlignmentEditorE4.readPherogram(uri)));
58 57
			    }
59 58
			}
60 59
	        catch (Exception e) {
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/ToggleInsertOverwriteHandlerE4.java
17 17
import org.eclipse.e4.ui.services.IServiceConstants;
18 18
import org.eclipse.jface.resource.ImageDescriptor;
19 19

  
20
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
21 20
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
22 21
import eu.etaxonomy.taxeditor.molecular.handler.HandlerTools;
23 22

  
24 23

  
25 24

  
26 25
/**
27
 * Switches an {@link AlignmentEditor} between insertion and overwrite mode.
26
 * Switches an {@link AlignmentEditorE4} between insertion and overwrite mode.
28 27
 *
29 28
 * @author Ben Stöver
30 29
 * @date 04.12.2014
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/ToggleLeftRightInsertionHandlerE4.java
16 16
import org.eclipse.e4.ui.services.IServiceConstants;
17 17
import org.eclipse.jface.resource.ImageDescriptor;
18 18

  
19
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
20 19
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
21 20
import eu.etaxonomy.taxeditor.molecular.handler.HandlerTools;
22 21

  
23 22

  
24 23

  
25 24
/**
26
 * Switches an {@link AlignmentEditor} between insertion in the base sequence to
25
 * Switches an {@link AlignmentEditorE4} between insertion in the base sequence to
27 26
 * the left or to the right.
28 27
 *
29 28
 * @author Ben Stöver
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/editor/e4/handler/ToggleShowPherogramProbabilitiesHandlerE4.java
15 15
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
16 16
import org.eclipse.e4.ui.services.IServiceConstants;
17 17

  
18
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
19
import eu.etaxonomy.taxeditor.molecular.editor.PherogramViewPart;
18
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
20 19
import eu.etaxonomy.taxeditor.molecular.editor.e4.PherogramPartE4;
21 20

  
22 21

  
......
24 23

  
25 24
/**
26 25
 * Toggles whether probability values (substitution, overcall and undercall) should be displayed
27
 * in pherogram areas of {@link AlignmentEditor} or {@link PherogramViewPart}.
26
 * in pherogram areas of {@link AlignmentEditorE4} or {@link PherogramPartE4}.
28 27
 *
29 28
 * @author Ben Stöver
30 29
 * @date 23.06.2015
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/AbstractAlignmentEditorHandler.java
14 14
import org.eclipse.core.commands.ExecutionException;
15 15

  
16 16
import eu.etaxonomy.taxeditor.model.AbstractUtility;
17
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
17
import eu.etaxonomy.taxeditor.molecular.editor.e4.AlignmentEditorE4;
18 18

  
19 19

  
20 20

  
21 21

  
22 22
/**
23 23
 * Abstract implementation for all handlers triggering actions in an active instance of
24
 * {@link AlignmentEditor}.
24
 * {@link AlignmentEditorE4}.
25 25
 *
26 26
 * @author Ben Stöver
27 27
 * @date 19.06.2015
28 28
 */
29 29
public abstract class AbstractAlignmentEditorHandler extends AbstractHandler {
30
	public static AlignmentEditor getActiveAlignmentEditor() {
30
	public static AlignmentEditorE4 getActiveAlignmentEditor() {
31 31
	    Object activeEditor = AbstractUtility.getActiveEditor();
32
        if (activeEditor instanceof AlignmentEditor) {
33
            return (AlignmentEditor)activeEditor;
32
        if (activeEditor instanceof AlignmentEditorE4) {
33
            return (AlignmentEditorE4)activeEditor;
34 34
        }
35 35
        else {
36 36
        	return null;
......
40 40

  
41 41
    @Override
42 42
    public Object execute(ExecutionEvent event) throws ExecutionException {
43
    	AlignmentEditor editor = getActiveAlignmentEditor();
43
    	AlignmentEditorE4 editor = getActiveAlignmentEditor();
44 44
        if (editor != null) {
45 45
            doExecute(event, editor);
46 46
        }
......
48 48
    }
49 49

  
50 50

  
51
    protected abstract void doExecute(ExecutionEvent event, AlignmentEditor editor) throws ExecutionException;
51
    protected abstract void doExecute(ExecutionEvent event, AlignmentEditorE4 editor) throws ExecutionException;
52 52
}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/AbstractFocusedAlignmentAreaHandler.java
1
package eu.etaxonomy.taxeditor.molecular.handler;
2

  
3

  
4
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
5

  
6
import org.eclipse.core.commands.ExecutionEvent;
7
import org.eclipse.core.commands.ExecutionException;
8

  
9
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
10

  
11

  
12

  
13
public abstract class AbstractFocusedAlignmentAreaHandler extends AbstractAlignmentEditorHandler {
14
	@Override
15
	protected void doExecute(ExecutionEvent event, AlignmentEditor editor) throws ExecutionException {
16
    	AlignmentArea focusedArea = editor.getFocusedArea();
17
    	if (focusedArea != null) {
18
    		doExecute2(event, editor, focusedArea);
19
    	}
20
	}
21
	
22
	
23
	protected abstract void doExecute2(ExecutionEvent event, AlignmentEditor editor, AlignmentArea focusedArea);
24
}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/AbstractPherogramComponentHandler.java
1
/**
2
* Copyright (C) 2015 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.taxeditor.molecular.handler;
10

  
11

  
12
import java.util.Iterator;
13

  
14
import org.eclipse.core.commands.AbstractHandler;
15
import org.eclipse.core.commands.ExecutionEvent;
16
import org.eclipse.core.commands.ExecutionException;
17

  
18
import eu.etaxonomy.taxeditor.model.AbstractUtility;
19
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
20
import eu.etaxonomy.taxeditor.molecular.editor.PherogramViewPart;
21
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
22
import info.bioinfweb.libralign.dataarea.implementations.pherogram.PherogramArea;
23
import info.bioinfweb.libralign.pherogram.PherogramComponent;
24

  
25

  
26

  
27
/**
28
 * Abstract handler implementation allows to performs the concrete operation either on an instance of
29
 * {@link PherogramViewPart} or all {@link AlignmentArea}s inside an instance of {@link AlignmentEditor}.
30
 *
31
 * @author Ben Stöver
32
 * @date 23.06.2015
33
 */
34
public abstract class AbstractPherogramComponentHandler extends AbstractHandler {
35
    @Override
36
    public Object execute(ExecutionEvent event) throws ExecutionException {
37
        Object activePart = AbstractUtility.getActivePart();
38

  
39
        if (activePart instanceof AlignmentEditor) {
40
            AlignmentEditor editor = (AlignmentEditor)activePart;
41
            Iterator<String> idIterator = editor.getReadsArea().getAlignmentModel().sequenceIDIterator();
42
            while (idIterator.hasNext()) {
43
                PherogramArea area = editor.getPherogramArea(idIterator.next());
44
                if (area != null) {
45
                    doExecute(event, area);
46
                }
47
            }
48
        }
49
        else if (activePart instanceof PherogramViewPart) {
50
            doExecute(event, ((PherogramViewPart)activePart).getPherogramView().getTraceCurveView());
51
        }
52
        return null;
53
    }
54

  
55

  
56
    public abstract void doExecute(ExecutionEvent event, PherogramComponent component) throws ExecutionException;
57
}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/AlignmentEditorCopyHandler.java
1
package eu.etaxonomy.taxeditor.molecular.handler;
2

  
3

  
4
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
5
import info.bioinfweb.libralign.alignmentarea.selection.SelectionModel;
6
import info.bioinfweb.libralign.model.utils.AlignmentModelUtils;
7

  
8
import java.util.Map;
9

  
10
import org.eclipse.core.commands.ExecutionEvent;
11
import org.eclipse.swt.dnd.TextTransfer;
12
import org.eclipse.swt.dnd.Transfer;
13
import org.eclipse.ui.commands.IElementUpdater;
14
import org.eclipse.ui.menus.UIElement;
15

  
16
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
17

  
18

  
19

  
20
/**
21
 * Handler that copies the currently selected nucleotides from an alignment editor to the clipboard.
22
 * <p>
23
 * The copied contents either come from the single reads or the consensus sequence alignment area,
24
 * depending on which component currently has the focus. If none of these components has the focus,
25
 * nothing will be copied, even if nucleotides are currently selected.
26
 * <p>
27
 * If the selection contains parts of multiple sequence, these are separated by the line separator
28
 * of the current operating system.
29
 *
30
 * @author Ben Stöver
31
 * @date 25.08.2015
32
 */
33
public class AlignmentEditorCopyHandler extends AbstractFocusedAlignmentAreaHandler implements IElementUpdater {
34
    @Override
35
	@SuppressWarnings("unchecked")
36
	protected void doExecute2(ExecutionEvent event, AlignmentEditor editor, AlignmentArea focusedArea) {
37
    	SelectionModel selection = focusedArea.getSelection();
38
    	if (!selection.isEmpty()) {
39
    		editor.CLIPBOARD.setContents(new Object[]{AlignmentModelUtils.selectionAsString(focusedArea, false)},
40
            		new Transfer[]{TextTransfer.getInstance()});
41
    	}
42
	}
43

  
44

  
45
	@Override
46
	public boolean isEnabled() {
47
		AlignmentEditor editor = getActiveAlignmentEditor();
48
		if (editor != null) {
49
			AlignmentArea focusedArea = editor.getFocusedArea();
50
			if (focusedArea != null) {
51
				return !focusedArea.getSelection().isEmpty();
52
			}
53
		}
54
		return false;
55
	}
56

  
57

  
58
	@Override
59
	public void updateElement(UIElement element, @SuppressWarnings("rawtypes") Map parameters) {
60
		setBaseEnabled(isEnabled());
61
    }
62
}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/AlignmentEditorCutHandler.java
1
package eu.etaxonomy.taxeditor.molecular.handler;
2

  
3

  
4
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
5

  
6
import org.eclipse.core.commands.ExecutionEvent;
7

  
8
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
9

  
10

  
11

  
12
/**
13
 * Handler that cuts the currently selected nucleotides from an alignment editor to the clipboard.
14
 * <p>
15
 * The cut contents either come from the single reads or the consensus sequence alignment area,
16
 * depending on which component currently has the focus. If none of these components has the focus,
17
 * nothing will be cut, even if nucleotides are currently selected.
18
 * <p>
19
 * If the selection contains parts of multiple sequence, these are separated by the line separator
20
 * of the current operating system.  
21
 * 
22
 * @author Ben Stöver
23
 * @date 25.08.2015
24
 */
25
public class AlignmentEditorCutHandler extends AlignmentEditorCopyHandler {
26
	@Override
27
	protected void doExecute2(ExecutionEvent event, AlignmentEditor editor,	AlignmentArea focusedArea) {
28
		super.doExecute2(event, editor, focusedArea);  // Copy selected contents.
29
		focusedArea.getActionProvider().deleteSelection();
30
	}
31
}
eu.etaxonomy.taxeditor.molecular/src/main/java/eu/etaxonomy/taxeditor/molecular/handler/AlignmentEditorPasteHandler.java
1
package eu.etaxonomy.taxeditor.molecular.handler;
2

  
3

  
4
import java.util.ArrayList;
5
import java.util.List;
6
import java.util.Map;
7
import java.util.Scanner;
8

  
9
import org.eclipse.core.commands.ExecutionEvent;
10
import org.eclipse.jface.dialogs.MessageDialog;
11
import org.eclipse.swt.dnd.TextTransfer;
12
import org.eclipse.ui.commands.IElementUpdater;
13
import org.eclipse.ui.handlers.HandlerUtil;
14
import org.eclipse.ui.menus.UIElement;
15

  
16
import eu.etaxonomy.taxeditor.molecular.editor.AlignmentEditor;
17
import eu.etaxonomy.taxeditor.molecular.l10n.Messages;
18
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
19
import info.bioinfweb.libralign.alignmentarea.order.SequenceOrder;
20
import info.bioinfweb.libralign.alignmentarea.selection.SelectionModel;
21
import info.bioinfweb.libralign.model.AlignmentModel;
22
import info.bioinfweb.libralign.model.utils.AlignmentModelUtils;
23

  
24

  
25

  
26
/**
27
 * Handler that pastes the current contents of the clipboard into an active instance of {@link AlignmentEditor}.
28
 *
29
 * @author Ben Stöver
30
 * @date 26.08.2015
31
 */
32
public class AlignmentEditorPasteHandler extends AbstractFocusedAlignmentAreaHandler implements IElementUpdater {
33
	private void pasteString(AlignmentArea area, String sequenceID, String content) {
34
		area.getActionProvider().deleteSelection();  // Overwrite selected tokens.
35
		area.getActionProvider().elongateSequence(sequenceID, area.getSelection().getCursorColumn());
36

  
37
		@SuppressWarnings("unchecked")
38
		AlignmentModel<Object> alignmentModel = (AlignmentModel<Object>)area.getAlignmentModel();
39
		alignmentModel.insertTokensAt(sequenceID, area.getSelection().getCursorColumn(),
40
				AlignmentModelUtils.charSequenceToTokenList(content, alignmentModel.getTokenSet(),
41
						true, alignmentModel.getTokenSet().getGapToken()));
42
	}
43

  
44

  
45
	@Override
46
	protected void doExecute2(ExecutionEvent event, AlignmentEditor editor, AlignmentArea focusedArea) {
47
		SelectionModel selection = focusedArea.getSelection();
48
		String clipboardText = (String)editor.CLIPBOARD.getContents(TextTransfer.getInstance());
49
		if (clipboardText != null) {
50
			List<String> lines = new ArrayList<String>();
51
			Scanner scanner = new Scanner(clipboardText);
52
			try {
53
				while (scanner.hasNext()) {
54
					lines.add(scanner.nextLine());
55
				}
56
				if (lines.get(lines.size() - 1).equals("")) { //$NON-NLS-1$
57
					lines.remove(lines.size() - 1);
58
				}
59
			}
60
			finally {
61
				scanner.close();
62
			}
63

  
64
			if (!lines.isEmpty()) { //TODO Can lines be empty? (Can an empty string "" be copied to the clipboard?)
65
				if (selection.getCursorHeight() == 1) {  // If the consensus sequence is focused, this is the only possible case.
66
					String sequenceID = focusedArea.getSequenceOrder().idByIndex(selection.getCursorRow());
67
					if (lines.size() == 1) {
68
						pasteString(focusedArea, sequenceID, lines.get(0));
69
					}
70
					else {
71
						MessageDialog dialog = new MessageDialog(HandlerUtil.getActiveWorkbenchWindow(event).getShell(),  //TODO Can the window be null?
72
								Messages.AlignmentEditorPasteHandler_PASTING_LINES, null,
73
								String.format(Messages.AlignmentEditorPasteHandler_PASTING_LINES_QUESTION, lines.size()),
74
								MessageDialog.QUESTION,
75
								new String[]{Messages.AlignmentEditorPasteHandler_PASTING_LINES_IGNORE,
76
										Messages.AlignmentEditorPasteHandler_PASTING_LINES_FIRST_LINE, Messages.AlignmentEditorPasteHandler_CANCEL},
77
								0);
78
						//TODO Does the dialog have to be disposed in some way?
79

  
80
						switch (dialog.open()) {
81
							case 0:  // Paste all lines in one sequence.
82
								pasteString(focusedArea, sequenceID, clipboardText);
83
								break;
84
							case 1:  // Paste only first line.
85
								pasteString(focusedArea, sequenceID, lines.get(0));
86
								break;
87
						}
88
					}
89
				}
90
				else {
91
					if (selection.getCursorHeight() == lines.size()) {
92
						SequenceOrder order = focusedArea.getSequenceOrder();
93
						for (int i = 0; i < selection.getCursorHeight(); i++) {
94
							pasteString(focusedArea, order.idByIndex(selection.getCursorRow() + i), lines.get(i));  // Multiple calls of deleteSelection() in here are unnecessary, but should have no effect.
95
						}
96
					}
97
					else {
98
						MessageDialog.openError(HandlerUtil.getActiveWorkbenchWindow(event).getShell(),  //TODO Can the window be null?
99
								Messages.AlignmentEditorPasteHandler_PASTE_FAILURE,
100
								String.format(Messages.AlignmentEditorPasteHandler_PASTE_FAILURE_MESSAGE, selection.getCursorHeight(), lines.size(), System.getProperty("line.separator"))); //$NON-NLS-1$
101
					}
102
				}
103
			}
104
		}
105
	}
106

  
107

  
108
	@Override
109
	public boolean isEnabled() {
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff