1
|
// $Id$
|
2
|
/**
|
3
|
* Copyright (C) 2014 EDIT
|
4
|
* European Distributed Institute of Taxonomy
|
5
|
* http://www.e-taxonomy.eu
|
6
|
*
|
7
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
8
|
* See LICENSE.TXT at the top of this package for the full license terms.
|
9
|
*/
|
10
|
package eu.etaxonomy.taxeditor.editor.molecular;
|
11
|
|
12
|
|
13
|
import info.bioinfweb.libralign.alignmentarea.AlignmentArea;
|
14
|
import info.bioinfweb.libralign.alignmentarea.content.AlignmentContentArea;
|
15
|
import info.bioinfweb.libralign.dataarea.implementations.ConsensusSequenceArea;
|
16
|
import info.bioinfweb.libralign.dataarea.implementations.SequenceIndexArea;
|
17
|
import info.bioinfweb.libralign.dataarea.implementations.pherogram.PherogramArea;
|
18
|
import info.bioinfweb.libralign.editsettings.EditSettingsChangeEvent;
|
19
|
import info.bioinfweb.libralign.editsettings.EditSettingsListener;
|
20
|
import info.bioinfweb.libralign.multiplealignments.AlignmentAreaList;
|
21
|
import info.bioinfweb.libralign.multiplealignments.MultipleAlignmentsContainer;
|
22
|
import info.bioinfweb.libralign.pherogram.provider.BioJavaPherogramProvider;
|
23
|
import info.bioinfweb.libralign.pherogram.provider.PherogramProvider;
|
24
|
import info.bioinfweb.libralign.sequenceprovider.SequenceDataProvider;
|
25
|
import info.bioinfweb.libralign.sequenceprovider.implementations.PackedSequenceDataProvider;
|
26
|
import info.bioinfweb.libralign.sequenceprovider.tokenset.BioJavaTokenSet;
|
27
|
import info.bioinfweb.libralign.sequenceprovider.tokenset.TokenSet;
|
28
|
|
29
|
import java.io.File;
|
30
|
import java.io.IOException;
|
31
|
import java.io.InputStream;
|
32
|
import java.net.URI;
|
33
|
import java.util.ArrayList;
|
34
|
import java.util.Collection;
|
35
|
import java.util.Collections;
|
36
|
import java.util.Map;
|
37
|
import java.util.TreeMap;
|
38
|
|
39
|
import org.biojava.bio.chromatogram.ChromatogramFactory;
|
40
|
import org.biojava.bio.chromatogram.UnsupportedChromatogramFormatException;
|
41
|
import org.biojava3.core.sequence.compound.DNACompoundSet;
|
42
|
import org.biojava3.core.sequence.compound.NucleotideCompound;
|
43
|
import org.eclipse.core.runtime.IProgressMonitor;
|
44
|
import org.eclipse.swt.SWT;
|
45
|
import org.eclipse.swt.widgets.Composite;
|
46
|
import org.eclipse.ui.IActionBars;
|
47
|
import org.eclipse.ui.IEditorInput;
|
48
|
import org.eclipse.ui.IEditorSite;
|
49
|
import org.eclipse.ui.PartInitException;
|
50
|
import org.eclipse.ui.PlatformUI;
|
51
|
import org.eclipse.ui.commands.ICommandService;
|
52
|
import org.eclipse.ui.part.EditorPart;
|
53
|
|
54
|
import eu.etaxonomy.taxeditor.editor.handler.ToggleInsertOverwriteHandler;
|
55
|
import eu.etaxonomy.taxeditor.editor.handler.ToggleLeftRightInsertionHandler;
|
56
|
|
57
|
|
58
|
|
59
|
/**
|
60
|
* Editor component to edit a contig alignment used to combine different overlapping pherograms from Sanger sequencing to
|
61
|
* a consensus sequence.
|
62
|
* <p>
|
63
|
* The contained GUI components used to edit the alignment come from <a href="http://bioinfweb.info/LibrAlign/">LibrAlign</a>.
|
64
|
*
|
65
|
* @author Ben Stöver
|
66
|
* @author pplitzner
|
67
|
* @date 04.08.2014
|
68
|
*/
|
69
|
public class AlignmentEditor extends EditorPart {
|
70
|
public static final String ID = "eu.etaxonomy.taxeditor.editor.molecular.AlignmentEditor";
|
71
|
public static final int READS_AREA_INDEX = 1;
|
72
|
public static final int CONSENSUS_AREA_INDEX = READS_AREA_INDEX + 1;
|
73
|
public static final String DEFAULT_READ_NAME_PREFIX = "Read ";
|
74
|
|
75
|
|
76
|
private MultipleAlignmentsContainer alignmentsContainer = null;
|
77
|
private Map<Integer, URI> uriMap = new TreeMap<Integer, URI>(); //TODO Move this to ContigSequenceDataProvider
|
78
|
|
79
|
|
80
|
private void refreshToolbarElement(String id) {
|
81
|
ICommandService commandService =
|
82
|
(ICommandService)PlatformUI.getWorkbench().getActiveWorkbenchWindow().getService(ICommandService.class);
|
83
|
if (commandService != null) {
|
84
|
commandService.refreshElements(id, Collections.EMPTY_MAP);
|
85
|
}
|
86
|
}
|
87
|
|
88
|
|
89
|
private void registerEditSettingListener(MultipleAlignmentsContainer container) {
|
90
|
container.getEditSettings().addListener(new EditSettingsListener() {
|
91
|
@Override
|
92
|
public void workingModeChanged(EditSettingsChangeEvent e) {} // Currently nothing to do
|
93
|
|
94
|
@Override
|
95
|
public void insertLeftInDataAreaChanged(EditSettingsChangeEvent e) {
|
96
|
updateStatusBar();
|
97
|
refreshToolbarElement(ToggleLeftRightInsertionHandler.COMMAND_ID);
|
98
|
}
|
99
|
|
100
|
@Override
|
101
|
public void insertChanged(EditSettingsChangeEvent e) {
|
102
|
updateStatusBar();
|
103
|
refreshToolbarElement(ToggleInsertOverwriteHandler.COMMAND_ID);
|
104
|
}
|
105
|
});
|
106
|
}
|
107
|
|
108
|
|
109
|
private AlignmentArea createIndexArea(MultipleAlignmentsContainer container) {
|
110
|
AlignmentArea result = new AlignmentArea(container);
|
111
|
result.setAllowVerticalScrolling(false);
|
112
|
result.getContentArea().getDataAreas().getTopAreas().add(new SequenceIndexArea(result.getContentArea()));
|
113
|
return result;
|
114
|
}
|
115
|
|
116
|
|
117
|
private AlignmentArea createEditableAlignmentArea(MultipleAlignmentsContainer container, boolean allowVerticalScrolling) {
|
118
|
AlignmentArea result = new AlignmentArea(container);
|
119
|
result.setAllowVerticalScrolling(allowVerticalScrolling);
|
120
|
|
121
|
TokenSet<NucleotideCompound> tokenSet = new BioJavaTokenSet<NucleotideCompound>(new DNACompoundSet(), true);
|
122
|
SequenceDataProvider<NucleotideCompound> provider = new PackedSequenceDataProvider<NucleotideCompound>(tokenSet);
|
123
|
result.getContentArea().setSequenceProvider(provider, false);
|
124
|
|
125
|
return result;
|
126
|
}
|
127
|
|
128
|
|
129
|
private AlignmentArea createConsensusHintArea(MultipleAlignmentsContainer container,
|
130
|
SequenceDataProvider<?> sequenceProvider) {
|
131
|
|
132
|
AlignmentArea result = new AlignmentArea(container);
|
133
|
result.setAllowVerticalScrolling(false);
|
134
|
result.getContentArea().getDataAreas().getBottomAreas().add(
|
135
|
new ConsensusSequenceArea(result.getContentArea(), sequenceProvider));
|
136
|
return result;
|
137
|
}
|
138
|
|
139
|
|
140
|
private MultipleAlignmentsContainer getAlignmentsContainer() {
|
141
|
if (alignmentsContainer == null) {
|
142
|
alignmentsContainer = new MultipleAlignmentsContainer();
|
143
|
|
144
|
AlignmentAreaList list = alignmentsContainer.getAlignmentAreas();
|
145
|
list.add(createIndexArea(alignmentsContainer));
|
146
|
AlignmentArea readsArea = createEditableAlignmentArea(alignmentsContainer, true);
|
147
|
list.add(readsArea); // Make sure READS_AREA_INDEX is correct.
|
148
|
list.add(createEditableAlignmentArea(alignmentsContainer, false)); // Make sure COMSENSUS_AREA_INDEX is correct.
|
149
|
list.add(createConsensusHintArea(alignmentsContainer,
|
150
|
readsArea.getContentArea().getSequenceProvider()));
|
151
|
|
152
|
registerEditSettingListener(alignmentsContainer);
|
153
|
}
|
154
|
return alignmentsContainer;
|
155
|
}
|
156
|
|
157
|
|
158
|
private AlignmentArea getReadsArea() {
|
159
|
return getAlignmentsContainer().getAlignmentAreas().get(READS_AREA_INDEX);
|
160
|
}
|
161
|
|
162
|
|
163
|
private AlignmentArea getConsensusArea() {
|
164
|
return getAlignmentsContainer().getAlignmentAreas().get(CONSENSUS_AREA_INDEX);
|
165
|
}
|
166
|
|
167
|
|
168
|
/* (non-Javadoc)
|
169
|
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
|
170
|
*/
|
171
|
@Override
|
172
|
public void createPartControl(Composite parent) {
|
173
|
getAlignmentsContainer().createSWTWidget(parent, SWT.NONE);
|
174
|
updateStatusBar();
|
175
|
|
176
|
// Just for testing:
|
177
|
try {
|
178
|
addRead(new File("D:/Users/BenStoever/Documents/Studium/Projekte/Promotion/EDITor/Quelltexte/LibrAlign branch/Repository/eu.etaxonomy.taxeditor.editor/src/main/resources/AlignmentTestData/JR430_JR-P01.ab1").toURI());
|
179
|
addRead(new File("D:/Users/BenStoever/Documents/Studium/Projekte/Promotion/EDITor/Quelltexte/LibrAlign branch/Repository/eu.etaxonomy.taxeditor.editor/src/main/resources/AlignmentTestData/JR444_JR-P05.ab1").toURI());
|
180
|
|
181
|
// Add test consensus sequence:
|
182
|
SequenceDataProvider consensusProvider = getConsensusArea().getContentArea().getSequenceProvider();
|
183
|
int id = consensusProvider.addSequence("Consensus");
|
184
|
Collection<Object> tokens = new ArrayList<Object>(); // First save tokens in a collection to avoid GUI updated for each token.
|
185
|
tokens.add(consensusProvider.getTokenSet().tokenByKeyChar('A'));
|
186
|
tokens.add(consensusProvider.getTokenSet().tokenByKeyChar('C'));
|
187
|
tokens.add(consensusProvider.getTokenSet().tokenByKeyChar('G'));
|
188
|
tokens.add(consensusProvider.getTokenSet().tokenByKeyChar('T'));
|
189
|
consensusProvider.insertTokensAt(id, 0, tokens);
|
190
|
}
|
191
|
catch (Exception e) {
|
192
|
throw new RuntimeException(e);
|
193
|
}
|
194
|
}
|
195
|
|
196
|
|
197
|
private void updateStatusBar() {
|
198
|
IActionBars bars = getEditorSite().getActionBars();
|
199
|
bars.getStatusLineManager().setMessage("Edit mode: " +
|
200
|
(getReadsArea().getContentArea().getEditSettings().isInsert() ? "Insert" : "Overwrite") + " " +
|
201
|
"Insertion in pherogram: " +
|
202
|
(getReadsArea().getContentArea().getEditSettings().isInsertLeftInDataArea() ? "Left" : "Right"));
|
203
|
}
|
204
|
|
205
|
|
206
|
/* (non-Javadoc)
|
207
|
* @see org.eclipse.ui.part.EditorPart#doSave(org.eclipse.core.runtime.IProgressMonitor)
|
208
|
*/
|
209
|
@Override
|
210
|
public void doSave(IProgressMonitor monitor) {
|
211
|
// TODO Auto-generated method stub
|
212
|
|
213
|
}
|
214
|
|
215
|
|
216
|
/* (non-Javadoc)
|
217
|
* @see org.eclipse.ui.part.EditorPart#doSaveAs()
|
218
|
*/
|
219
|
@Override
|
220
|
public void doSaveAs() {
|
221
|
// TODO Auto-generated method stub
|
222
|
|
223
|
}
|
224
|
|
225
|
|
226
|
/* (non-Javadoc)
|
227
|
* @see org.eclipse.ui.part.EditorPart#init(org.eclipse.ui.IEditorSite, org.eclipse.ui.IEditorInput)
|
228
|
*/
|
229
|
@Override
|
230
|
public void init(IEditorSite site, IEditorInput input) throws PartInitException {
|
231
|
setSite(site);
|
232
|
setInput(input);
|
233
|
}
|
234
|
|
235
|
|
236
|
/* (non-Javadoc)
|
237
|
* @see org.eclipse.ui.part.EditorPart#isDirty()
|
238
|
*/
|
239
|
@Override
|
240
|
public boolean isDirty() {
|
241
|
// TODO Auto-generated method stub
|
242
|
return false;
|
243
|
}
|
244
|
|
245
|
|
246
|
/* (non-Javadoc)
|
247
|
* @see org.eclipse.ui.part.EditorPart#isSaveAsAllowed()
|
248
|
*/
|
249
|
@Override
|
250
|
public boolean isSaveAsAllowed() {
|
251
|
// TODO Auto-generated method stub
|
252
|
return false;
|
253
|
}
|
254
|
|
255
|
|
256
|
@Override
|
257
|
public void setFocus() {}
|
258
|
|
259
|
|
260
|
public boolean isInsertMode() {
|
261
|
return getAlignmentsContainer().getEditSettings().isInsert();
|
262
|
}
|
263
|
|
264
|
|
265
|
public boolean isInsertLeftInPherogram() {
|
266
|
return getAlignmentsContainer().getEditSettings().isInsertLeftInDataArea();
|
267
|
}
|
268
|
|
269
|
|
270
|
public void toggleLeftRightInsertionInPherogram() {
|
271
|
getAlignmentsContainer().getEditSettings().toggleInsertLeftInDataArea();
|
272
|
}
|
273
|
|
274
|
|
275
|
public void toggleInsertOverwrite() {
|
276
|
getAlignmentsContainer().getEditSettings().toggleInsert();
|
277
|
}
|
278
|
|
279
|
|
280
|
public static PherogramProvider readPherogram(URI uri) throws IOException, UnsupportedChromatogramFormatException {
|
281
|
PherogramProvider result;
|
282
|
InputStream stream = uri.toURL().openStream();
|
283
|
try {
|
284
|
result = new BioJavaPherogramProvider(ChromatogramFactory.create(stream));
|
285
|
}
|
286
|
finally {
|
287
|
stream.close();
|
288
|
}
|
289
|
return result;
|
290
|
}
|
291
|
|
292
|
|
293
|
private String newReadName() {
|
294
|
int index = 1;
|
295
|
while (getReadsArea().getContentArea().getSequenceProvider().sequenceIDByName(DEFAULT_READ_NAME_PREFIX + index)
|
296
|
!= SequenceDataProvider.NO_SEQUENCE_FOUND) {
|
297
|
|
298
|
index++;
|
299
|
}
|
300
|
return DEFAULT_READ_NAME_PREFIX + index;
|
301
|
}
|
302
|
|
303
|
|
304
|
public void addRead(URI pherogramURI) throws IOException, UnsupportedChromatogramFormatException {
|
305
|
addRead(newReadName(), pherogramURI);
|
306
|
}
|
307
|
|
308
|
|
309
|
public void addRead(String name, URI pherogramURI) throws IOException, UnsupportedChromatogramFormatException {
|
310
|
AlignmentContentArea contentArea = getReadsArea().getContentArea();
|
311
|
SequenceDataProvider provider = contentArea.getSequenceProvider();
|
312
|
PherogramProvider pherogramProvider = readPherogram(pherogramURI); // Must happen before a sequence is added, because it might throw an exception.
|
313
|
|
314
|
// Create sequence:
|
315
|
provider.addSequence(name);
|
316
|
int id = provider.sequenceIDByName(name);
|
317
|
|
318
|
// Copy base call sequence into alignment:
|
319
|
Collection<Object> tokens = new ArrayList<Object>(); // First save tokens in a collection to avoid GUI updated for each token.
|
320
|
for (int i = 0; i < pherogramProvider.getSequenceLength(); i++) {
|
321
|
tokens.add(provider.getTokenSet().tokenByKeyChar(
|
322
|
pherogramProvider.getBaseCall(i).getUpperedBase().charAt(0)));
|
323
|
}
|
324
|
provider.insertTokensAt(id, 0, tokens);
|
325
|
|
326
|
// Add data area:
|
327
|
PherogramArea pherogramArea = new PherogramArea(contentArea, pherogramProvider);
|
328
|
pherogramArea.addMouseListener(new PherogramMouseListener(pherogramURI));
|
329
|
contentArea.getDataAreas().getSequenceAreas(id).add(pherogramArea);
|
330
|
|
331
|
// Save source URI:
|
332
|
uriMap.put(id, pherogramURI);
|
333
|
}
|
334
|
}
|