Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
FeatureEditor | 66 | 224 | 52 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
7 | * Jalview is free software: you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation, either version 3 | |
10 | * of the License, or (at your option) any later version. | |
11 | * | |
12 | * Jalview is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty | |
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
15 | * PURPOSE. See the GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Jalview. If not, see <http://www.gnu.org/licenses/>. | |
19 | * The Jalview Authors are detailed in the 'AUTHORS' file. | |
20 | */ | |
21 | package jalview.gui; | |
22 | ||
23 | import java.awt.BorderLayout; | |
24 | import java.awt.Color; | |
25 | import java.awt.Dimension; | |
26 | import java.awt.Font; | |
27 | import java.awt.GridLayout; | |
28 | import java.awt.event.ActionEvent; | |
29 | import java.awt.event.ActionListener; | |
30 | import java.awt.event.ItemEvent; | |
31 | import java.awt.event.ItemListener; | |
32 | import java.awt.event.MouseAdapter; | |
33 | import java.awt.event.MouseEvent; | |
34 | import java.util.ArrayList; | |
35 | import java.util.List; | |
36 | ||
37 | import javax.swing.JComboBox; | |
38 | import javax.swing.JLabel; | |
39 | import javax.swing.JPanel; | |
40 | import javax.swing.JScrollPane; | |
41 | import javax.swing.JSpinner; | |
42 | import javax.swing.JTextArea; | |
43 | import javax.swing.JTextField; | |
44 | import javax.swing.SpinnerNumberModel; | |
45 | import javax.swing.SwingConstants; | |
46 | import javax.swing.event.ChangeEvent; | |
47 | import javax.swing.event.ChangeListener; | |
48 | import javax.swing.event.DocumentEvent; | |
49 | import javax.swing.event.DocumentListener; | |
50 | ||
51 | import jalview.api.FeatureColourI; | |
52 | import jalview.datamodel.SearchResults; | |
53 | import jalview.datamodel.SearchResultsI; | |
54 | import jalview.datamodel.SequenceFeature; | |
55 | import jalview.datamodel.SequenceI; | |
56 | import jalview.gui.JalviewColourChooser.ColourChooserListener; | |
57 | import jalview.io.FeaturesFile; | |
58 | import jalview.schemes.FeatureColour; | |
59 | import jalview.util.ColorUtils; | |
60 | import jalview.util.MessageManager; | |
61 | ||
62 | /** | |
63 | * Provides a dialog allowing the user to add new features, or amend or delete | |
64 | * existing features | |
65 | */ | |
66 | public class FeatureEditor | |
67 | { | |
68 | /* | |
69 | * defaults for creating a new feature are the last created | |
70 | * feature type and group | |
71 | */ | |
72 | static String lastFeatureAdded = "feature_1"; | |
73 | ||
74 | static String lastFeatureGroupAdded = "Jalview"; | |
75 | ||
76 | /* | |
77 | * the sequence(s) with features to be created / amended | |
78 | */ | |
79 | final List<SequenceI> sequences; | |
80 | ||
81 | /* | |
82 | * the features (or template features) to be created / amended | |
83 | */ | |
84 | final List<SequenceFeature> features; | |
85 | ||
86 | /* | |
87 | * true if the dialog is to create a new feature, false if | |
88 | * for amend or delete of existing feature(s) | |
89 | */ | |
90 | final boolean forCreate; | |
91 | ||
92 | /* | |
93 | * index into the list of features | |
94 | */ | |
95 | int featureIndex; | |
96 | ||
97 | FeatureColourI oldColour; | |
98 | ||
99 | FeatureColourI featureColour; | |
100 | ||
101 | FeatureRenderer fr; | |
102 | ||
103 | AlignmentPanel ap; | |
104 | ||
105 | JTextField name; | |
106 | ||
107 | JTextField group; | |
108 | ||
109 | JTextArea description; | |
110 | ||
111 | JSpinner start; | |
112 | ||
113 | JSpinner end; | |
114 | ||
115 | JPanel mainPanel; | |
116 | ||
117 | /** | |
118 | * Constructor | |
119 | * | |
120 | * @param alignPanel | |
121 | * @param seqs | |
122 | * @param feats | |
123 | * @param create | |
124 | * if true create a new feature, else amend or delete an existing | |
125 | * feature | |
126 | */ | |
127 | 0 | public FeatureEditor(AlignmentPanel alignPanel, List<SequenceI> seqs, |
128 | List<SequenceFeature> feats, boolean create) | |
129 | { | |
130 | 0 | ap = alignPanel; |
131 | 0 | fr = alignPanel.getSeqPanel().seqCanvas.fr; |
132 | 0 | sequences = seqs; |
133 | 0 | features = feats; |
134 | 0 | this.forCreate = create; |
135 | ||
136 | 0 | init(); |
137 | } | |
138 | ||
139 | /** | |
140 | * Initialise the layout and controls | |
141 | */ | |
142 | 0 | protected void init() |
143 | { | |
144 | 0 | featureIndex = 0; |
145 | ||
146 | 0 | mainPanel = new JPanel(new BorderLayout()); |
147 | ||
148 | 0 | name = new JTextField(25); |
149 | 0 | name.getDocument().addDocumentListener(new DocumentListener() |
150 | { | |
151 | 0 | @Override |
152 | public void insertUpdate(DocumentEvent e) | |
153 | { | |
154 | 0 | warnIfTypeHidden(mainPanel, name.getText()); |
155 | } | |
156 | ||
157 | 0 | @Override |
158 | public void removeUpdate(DocumentEvent e) | |
159 | { | |
160 | 0 | warnIfTypeHidden(mainPanel, name.getText()); |
161 | } | |
162 | ||
163 | 0 | @Override |
164 | public void changedUpdate(DocumentEvent e) | |
165 | { | |
166 | 0 | warnIfTypeHidden(mainPanel, name.getText()); |
167 | } | |
168 | }); | |
169 | ||
170 | 0 | group = new JTextField(25); |
171 | 0 | group.getDocument().addDocumentListener(new DocumentListener() |
172 | { | |
173 | 0 | @Override |
174 | public void insertUpdate(DocumentEvent e) | |
175 | { | |
176 | 0 | warnIfGroupHidden(mainPanel, group.getText()); |
177 | } | |
178 | ||
179 | 0 | @Override |
180 | public void removeUpdate(DocumentEvent e) | |
181 | { | |
182 | 0 | warnIfGroupHidden(mainPanel, group.getText()); |
183 | } | |
184 | ||
185 | 0 | @Override |
186 | public void changedUpdate(DocumentEvent e) | |
187 | { | |
188 | 0 | warnIfGroupHidden(mainPanel, group.getText()); |
189 | } | |
190 | }); | |
191 | ||
192 | 0 | description = new JTextArea(3, 25); |
193 | ||
194 | 0 | start = new JSpinner(); |
195 | 0 | end = new JSpinner(); |
196 | 0 | start.setPreferredSize(new Dimension(80, 20)); |
197 | 0 | end.setPreferredSize(new Dimension(80, 20)); |
198 | ||
199 | /* | |
200 | * ensure that start can never be more than end | |
201 | */ | |
202 | 0 | start.addChangeListener(new ChangeListener() |
203 | { | |
204 | 0 | @Override |
205 | public void stateChanged(ChangeEvent e) | |
206 | { | |
207 | 0 | Integer startVal = (Integer) start.getValue(); |
208 | 0 | ((SpinnerNumberModel) end.getModel()).setMinimum(startVal); |
209 | } | |
210 | }); | |
211 | 0 | end.addChangeListener(new ChangeListener() |
212 | { | |
213 | 0 | @Override |
214 | public void stateChanged(ChangeEvent e) | |
215 | { | |
216 | 0 | Integer endVal = (Integer) end.getValue(); |
217 | 0 | ((SpinnerNumberModel) start.getModel()).setMaximum(endVal); |
218 | } | |
219 | }); | |
220 | ||
221 | 0 | final JLabel colour = new JLabel(); |
222 | 0 | colour.setOpaque(true); |
223 | 0 | colour.setMaximumSize(new Dimension(30, 16)); |
224 | 0 | colour.addMouseListener(new MouseAdapter() |
225 | { | |
226 | 0 | @Override |
227 | public void mousePressed(MouseEvent evt) | |
228 | { | |
229 | 0 | if (featureColour.isSimpleColour()) |
230 | { | |
231 | /* | |
232 | * open colour chooser on click in colour panel | |
233 | */ | |
234 | 0 | String title = MessageManager |
235 | .getString("label.select_feature_colour"); | |
236 | 0 | ColourChooserListener listener = new ColourChooserListener() |
237 | { | |
238 | 0 | @Override |
239 | public void colourSelected(Color c) | |
240 | { | |
241 | 0 | featureColour = new FeatureColour(c); |
242 | 0 | updateColourButton(mainPanel, colour, featureColour); |
243 | }; | |
244 | }; | |
245 | 0 | JalviewColourChooser.showColourChooser(Desktop.getDesktop(), |
246 | title, featureColour.getColour(), listener); | |
247 | } | |
248 | else | |
249 | { | |
250 | /* | |
251 | * variable colour dialog - on OK, refetch the updated | |
252 | * feature colour and update this display | |
253 | */ | |
254 | 0 | final String ft = features.get(featureIndex).getType(); |
255 | 0 | final String type = ft == null ? lastFeatureAdded : ft; |
256 | 0 | FeatureTypeSettings fcc = new FeatureTypeSettings(fr, type, true); |
257 | 0 | fcc.setRequestFocusEnabled(true); |
258 | 0 | fcc.requestFocus(); |
259 | 0 | fcc.addActionListener(new ActionListener() |
260 | { | |
261 | 0 | @Override |
262 | public void actionPerformed(ActionEvent e) | |
263 | { | |
264 | 0 | featureColour = fr.getFeatureStyle(ft); |
265 | 0 | fr.setColour(type, featureColour); |
266 | 0 | updateColourButton(mainPanel, colour, featureColour); |
267 | } | |
268 | }); | |
269 | } | |
270 | } | |
271 | }); | |
272 | 0 | JPanel gridPanel = new JPanel(new GridLayout(3, 1)); |
273 | ||
274 | 0 | if (!forCreate && features.size() > 1) |
275 | { | |
276 | /* | |
277 | * more than one feature at selected position - | |
278 | * add a drop-down to choose the feature to amend | |
279 | * space pad text if necessary to make entries distinct | |
280 | */ | |
281 | 0 | gridPanel = new JPanel(new GridLayout(4, 1)); |
282 | 0 | JPanel choosePanel = new JPanel(); |
283 | 0 | choosePanel.add(new JLabel( |
284 | MessageManager.getString("label.select_feature") + ":")); | |
285 | 0 | final JComboBox<String> overlaps = new JComboBox<>(); |
286 | 0 | List<String> added = new ArrayList<>(); |
287 | 0 | for (SequenceFeature sf : features) |
288 | { | |
289 | 0 | String text = String.format("%s/%d-%d (%s)", sf.getType(), |
290 | sf.getBegin(), sf.getEnd(), sf.getFeatureGroup()); | |
291 | 0 | while (added.contains(text)) |
292 | { | |
293 | 0 | text += " "; |
294 | } | |
295 | 0 | overlaps.addItem(text); |
296 | 0 | added.add(text); |
297 | } | |
298 | 0 | choosePanel.add(overlaps); |
299 | ||
300 | 0 | overlaps.addItemListener(new ItemListener() |
301 | { | |
302 | 0 | @Override |
303 | public void itemStateChanged(ItemEvent e) | |
304 | { | |
305 | 0 | int index = overlaps.getSelectedIndex(); |
306 | 0 | if (index != -1) |
307 | { | |
308 | 0 | featureIndex = index; |
309 | 0 | SequenceFeature sf = features.get(index); |
310 | 0 | name.setText(sf.getType()); |
311 | 0 | description.setText(sf.getDescription()); |
312 | 0 | group.setText(sf.getFeatureGroup()); |
313 | 0 | start.setValue(new Integer(sf.getBegin())); |
314 | 0 | end.setValue(new Integer(sf.getEnd())); |
315 | 0 | ((SpinnerNumberModel) start.getModel()).setMaximum(sf.getEnd()); |
316 | 0 | ((SpinnerNumberModel) end.getModel()).setMinimum(sf.getBegin()); |
317 | ||
318 | 0 | SearchResultsI highlight = new SearchResults(); |
319 | 0 | highlight.addResult(sequences.get(0), sf.getBegin(), |
320 | sf.getEnd()); | |
321 | ||
322 | 0 | ap.getSeqPanel().seqCanvas.highlightSearchResults(highlight); |
323 | } | |
324 | 0 | FeatureColourI col = fr.getFeatureStyle(name.getText()); |
325 | 0 | if (col == null) |
326 | { | |
327 | 0 | col = new FeatureColour( |
328 | ColorUtils.createColourFromName(name.getText())); | |
329 | } | |
330 | 0 | oldColour = featureColour = col; |
331 | 0 | updateColourButton(mainPanel, colour, col); |
332 | } | |
333 | }); | |
334 | ||
335 | 0 | gridPanel.add(choosePanel); |
336 | } | |
337 | ||
338 | 0 | JPanel namePanel = new JPanel(); |
339 | 0 | gridPanel.add(namePanel); |
340 | 0 | namePanel.add(new JLabel(MessageManager.getString("label.name:"), |
341 | JLabel.RIGHT)); | |
342 | 0 | namePanel.add(name); |
343 | ||
344 | 0 | JPanel groupPanel = new JPanel(); |
345 | 0 | gridPanel.add(groupPanel); |
346 | 0 | groupPanel.add(new JLabel(MessageManager.getString("label.group:"), |
347 | JLabel.RIGHT)); | |
348 | 0 | groupPanel.add(group); |
349 | ||
350 | 0 | JPanel colourPanel = new JPanel(); |
351 | 0 | gridPanel.add(colourPanel); |
352 | 0 | colourPanel.add(new JLabel(MessageManager.getString("label.colour"), |
353 | JLabel.RIGHT)); | |
354 | 0 | colourPanel.add(colour); |
355 | 0 | colour.setPreferredSize(new Dimension(150, 15)); |
356 | 0 | colour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 9)); |
357 | 0 | colour.setForeground(Color.black); |
358 | 0 | colour.setHorizontalAlignment(SwingConstants.CENTER); |
359 | 0 | colour.setVerticalAlignment(SwingConstants.CENTER); |
360 | 0 | colour.setHorizontalTextPosition(SwingConstants.CENTER); |
361 | 0 | colour.setVerticalTextPosition(SwingConstants.CENTER); |
362 | 0 | mainPanel.add(gridPanel, BorderLayout.NORTH); |
363 | ||
364 | 0 | JPanel descriptionPanel = new JPanel(); |
365 | 0 | descriptionPanel.add(new JLabel( |
366 | MessageManager.getString("label.description:"), JLabel.RIGHT)); | |
367 | 0 | description.setFont(JvSwingUtils.getTextAreaFont()); |
368 | 0 | description.setLineWrap(true); |
369 | 0 | descriptionPanel.add(new JScrollPane(description)); |
370 | ||
371 | 0 | if (!forCreate) |
372 | { | |
373 | 0 | mainPanel.add(descriptionPanel, BorderLayout.SOUTH); |
374 | ||
375 | 0 | JPanel startEndPanel = new JPanel(); |
376 | 0 | startEndPanel.add(new JLabel(MessageManager.getString("label.start"), |
377 | JLabel.RIGHT)); | |
378 | 0 | startEndPanel.add(start); |
379 | 0 | startEndPanel.add(new JLabel(MessageManager.getString("label.end"), |
380 | JLabel.RIGHT)); | |
381 | 0 | startEndPanel.add(end); |
382 | 0 | mainPanel.add(startEndPanel, BorderLayout.CENTER); |
383 | } | |
384 | else | |
385 | { | |
386 | 0 | mainPanel.add(descriptionPanel, BorderLayout.CENTER); |
387 | } | |
388 | ||
389 | /* | |
390 | * default feature type and group to that of the first feature supplied, | |
391 | * or to the last feature created if not supplied (null value) | |
392 | */ | |
393 | 0 | SequenceFeature firstFeature = features.get(0); |
394 | 0 | boolean useLastDefaults = firstFeature.getType() == null; |
395 | 0 | final String featureType = useLastDefaults ? lastFeatureAdded |
396 | : firstFeature.getType(); | |
397 | 0 | final String featureGroup = useLastDefaults ? lastFeatureGroupAdded |
398 | : firstFeature.getFeatureGroup(); | |
399 | 0 | name.setText(featureType); |
400 | 0 | group.setText(featureGroup); |
401 | ||
402 | 0 | start.setValue(new Integer(firstFeature.getBegin())); |
403 | 0 | end.setValue(new Integer(firstFeature.getEnd())); |
404 | 0 | ((SpinnerNumberModel) start.getModel()) |
405 | .setMaximum(firstFeature.getEnd()); | |
406 | 0 | ((SpinnerNumberModel) end.getModel()) |
407 | .setMinimum(firstFeature.getBegin()); | |
408 | ||
409 | 0 | description.setText(firstFeature.getDescription()); |
410 | 0 | featureColour = fr.getFeatureStyle(featureType); |
411 | 0 | oldColour = featureColour; |
412 | 0 | updateColourButton(mainPanel, colour, oldColour); |
413 | } | |
414 | ||
415 | /** | |
416 | * Presents a dialog allowing the user to add new features, or amend or delete | |
417 | * an existing feature. Currently this can be on | |
418 | * <ul> | |
419 | * <li>double-click on a sequence - Amend/Delete a selected feature at the | |
420 | * position</li> | |
421 | * <li>Create sequence feature(s) from pop-up menu on selected region</li> | |
422 | * <li>Create features for pattern matches from Find</li> | |
423 | * </ul> | |
424 | * If the supplied feature type is null, show (and update on confirm) the type | |
425 | * and group of the last new feature created (with initial defaults of | |
426 | * "feature_1" and "Jalview"). | |
427 | */ | |
428 | 0 | public void showDialog() |
429 | { | |
430 | 0 | Runnable okAction = forCreate ? getCreateAction() : getAmendAction(); |
431 | 0 | Runnable cancelAction = getCancelAction(); |
432 | ||
433 | /* | |
434 | * set dialog action handlers for OK (create/Amend) and Cancel options | |
435 | * also for Delete if applicable (when amending features) | |
436 | */ | |
437 | 0 | JvOptionPane dialog = JvOptionPane.newOptionDialog(ap.alignFrame) |
438 | .setResponseHandler(0, okAction) | |
439 | .setResponseHandler(2, cancelAction); | |
440 | 0 | if (!forCreate) |
441 | { | |
442 | 0 | dialog.setResponseHandler(1, getDeleteAction()); |
443 | } | |
444 | ||
445 | 0 | String title = null; |
446 | 0 | Object[] options = null; |
447 | 0 | if (forCreate) |
448 | { | |
449 | 0 | title = MessageManager |
450 | .getString("label.create_new_sequence_features"); | |
451 | 0 | options = new Object[] { MessageManager.getString("action.ok"), |
452 | MessageManager.getString("action.cancel") }; | |
453 | } | |
454 | else | |
455 | { | |
456 | 0 | title = MessageManager.formatMessage("label.amend_delete_features", |
457 | new String[] | |
458 | { sequences.get(0).getName() }); | |
459 | 0 | options = new Object[] { MessageManager.getString("label.amend"), |
460 | MessageManager.getString("action.delete"), | |
461 | MessageManager.getString("action.cancel") }; | |
462 | } | |
463 | ||
464 | 0 | dialog.showInternalDialog(mainPanel, title, |
465 | JvOptionPane.YES_NO_CANCEL_OPTION, JvOptionPane.PLAIN_MESSAGE, | |
466 | null, options, MessageManager.getString("action.ok")); | |
467 | } | |
468 | ||
469 | /** | |
470 | * Answers an action to run on Cancel in the dialog. This is just to remove | |
471 | * any feature highlighting from the display. Changes in the dialog are not | |
472 | * applied until it is dismissed with OK, Amend or Delete, so there are no | |
473 | * updates to reset on Cancel. | |
474 | * | |
475 | * @return | |
476 | */ | |
477 | 0 | protected Runnable getCancelAction() |
478 | { | |
479 | 0 | Runnable okAction = () -> { |
480 | 0 | ap.highlightSearchResults(null); |
481 | 0 | ap.paintAlignment(false, false); |
482 | }; | |
483 | 0 | return okAction; |
484 | } | |
485 | ||
486 | /** | |
487 | * Returns the action to be run on OK in the dialog when creating one or more | |
488 | * sequence features. Note these may have a pre-supplied feature type (such as | |
489 | * a Find pattern), or none, in which case the feature type and group default | |
490 | * to those last added through this dialog. The action includes refreshing the | |
491 | * Feature Settings panel (if it is open), to show any new feature type, or | |
492 | * amended colour for an existing type. | |
493 | * | |
494 | * @return | |
495 | */ | |
496 | 0 | protected Runnable getCreateAction() |
497 | { | |
498 | 0 | Runnable okAction = new Runnable() |
499 | { | |
500 | boolean useLastDefaults = features.get(0).getType() == null; | |
501 | ||
502 | 0 | @Override |
503 | public void run() | |
504 | { | |
505 | 0 | final String enteredType = name.getText().trim(); |
506 | 0 | final String enteredGroup = group.getText().trim(); |
507 | 0 | final String enteredDescription = description.getText() |
508 | .replaceAll("\n", " "); | |
509 | 0 | if (enteredType.length() > 0) |
510 | { | |
511 | /* | |
512 | * update default values only if creating using default values | |
513 | */ | |
514 | 0 | if (useLastDefaults) |
515 | { | |
516 | 0 | lastFeatureAdded = enteredType; |
517 | 0 | lastFeatureGroupAdded = enteredGroup; |
518 | // TODO: determine if the null feature group is valid | |
519 | 0 | if (lastFeatureGroupAdded.length() < 1) |
520 | { | |
521 | 0 | lastFeatureGroupAdded = null; |
522 | } | |
523 | } | |
524 | } | |
525 | ||
526 | 0 | if (enteredType.length() > 0) |
527 | { | |
528 | 0 | for (int i = 0; i < sequences.size(); i++) |
529 | { | |
530 | 0 | SequenceFeature sf = features.get(i); |
531 | 0 | SequenceFeature sf2 = new SequenceFeature(enteredType, |
532 | enteredDescription, sf.getBegin(), sf.getEnd(), | |
533 | enteredGroup); | |
534 | 0 | new FeaturesFile().parseDescriptionHTML(sf2, false); |
535 | 0 | sequences.get(i).addSequenceFeature(sf2); |
536 | } | |
537 | ||
538 | 0 | fr.setColour(enteredType, featureColour); |
539 | 0 | fr.featuresAdded(); |
540 | ||
541 | 0 | repaintPanel(); |
542 | } | |
543 | } | |
544 | }; | |
545 | 0 | return okAction; |
546 | } | |
547 | ||
548 | /** | |
549 | * Answers the action to run on Delete in the dialog. Note this includes | |
550 | * refreshing the Feature Settings (if open) in case the only instance of a | |
551 | * feature type or group has been deleted. | |
552 | * | |
553 | * @return | |
554 | */ | |
555 | 0 | protected Runnable getDeleteAction() |
556 | { | |
557 | 0 | Runnable deleteAction = () -> { |
558 | 0 | SequenceFeature sf = features.get(featureIndex); |
559 | 0 | sequences.get(0).getDatasetSequence().deleteFeature(sf); |
560 | 0 | fr.featuresAdded(); |
561 | 0 | ap.getSeqPanel().seqCanvas.highlightSearchResults(null); |
562 | 0 | ap.paintAlignment(true, true); |
563 | }; | |
564 | 0 | return deleteAction; |
565 | } | |
566 | ||
567 | /** | |
568 | * update the amend feature button dependent on the given style | |
569 | * | |
570 | * @param bigPanel | |
571 | * @param col | |
572 | * @param col | |
573 | */ | |
574 | 0 | protected void updateColourButton(JPanel bigPanel, JLabel colour, |
575 | FeatureColourI col) | |
576 | { | |
577 | 0 | colour.removeAll(); |
578 | 0 | colour.setIcon(null); |
579 | 0 | colour.setText(""); |
580 | ||
581 | 0 | if (col.isSimpleColour()) |
582 | { | |
583 | 0 | colour.setToolTipText(null); |
584 | 0 | colour.setBackground(col.getColour()); |
585 | } | |
586 | else | |
587 | { | |
588 | 0 | colour.setBackground(bigPanel.getBackground()); |
589 | 0 | colour.setForeground(Color.black); |
590 | 0 | colour.setToolTipText(FeatureSettings.getColorTooltip(col, false)); |
591 | 0 | FeatureSettings.renderGraduatedColor(colour, col); |
592 | } | |
593 | } | |
594 | ||
595 | /** | |
596 | * Show a warning message if the entered group is one that is currently hidden | |
597 | * | |
598 | * @param panel | |
599 | * @param group | |
600 | */ | |
601 | 0 | protected void warnIfGroupHidden(JPanel panel, String group) |
602 | { | |
603 | 0 | if (!fr.isGroupVisible(group)) |
604 | { | |
605 | 0 | String msg = MessageManager.formatMessage("label.warning_hidden", |
606 | MessageManager.getString("label.group"), group); | |
607 | 0 | JvOptionPane.showMessageDialog(panel, msg, "", |
608 | JvOptionPane.OK_OPTION); | |
609 | } | |
610 | } | |
611 | ||
612 | /** | |
613 | * Show a warning message if the entered type is one that is currently hidden | |
614 | * | |
615 | * @param panel | |
616 | * @param type | |
617 | */ | |
618 | 0 | protected void warnIfTypeHidden(JPanel panel, String type) |
619 | { | |
620 | 0 | if (fr.getRenderOrder().contains(type)) |
621 | { | |
622 | 0 | if (!fr.showFeatureOfType(type)) |
623 | { | |
624 | 0 | String msg = MessageManager.formatMessage("label.warning_hidden", |
625 | MessageManager.getString("label.feature_type"), type); | |
626 | 0 | JvOptionPane.showMessageDialog(panel, msg, "", |
627 | JvOptionPane.OK_OPTION); | |
628 | } | |
629 | } | |
630 | } | |
631 | ||
632 | /** | |
633 | * On closing the dialog - ensure feature display is turned on, to show any | |
634 | * new features - remove highlighting of the last selected feature - repaint | |
635 | * the panel to show any changes | |
636 | */ | |
637 | 0 | protected void repaintPanel() |
638 | { | |
639 | 0 | ap.alignFrame.showSeqFeatures.setSelected(true); |
640 | 0 | ap.av.setShowSequenceFeatures(true); |
641 | 0 | ap.av.setSearchResults(null); |
642 | 0 | ap.paintAlignment(true, true); |
643 | } | |
644 | ||
645 | /** | |
646 | * Returns the action to be run on OK in the dialog when amending a feature. | |
647 | * Note this may include refreshing the Feature Settings panel (if it is | |
648 | * open), if feature type, group or colour has changed (but not for | |
649 | * description or extent). | |
650 | * | |
651 | * @return | |
652 | */ | |
653 | 0 | protected Runnable getAmendAction() |
654 | { | |
655 | 0 | Runnable okAction = new Runnable() |
656 | { | |
657 | boolean useLastDefaults = features.get(0).getType() == null; | |
658 | ||
659 | String featureType = name.getText(); | |
660 | ||
661 | String featureGroup = group.getText(); | |
662 | ||
663 | 0 | @Override |
664 | public void run() | |
665 | { | |
666 | 0 | final String enteredType = name.getText().trim(); |
667 | 0 | final String enteredGroup = group.getText().trim(); |
668 | 0 | final String enteredDescription = description.getText() |
669 | .replaceAll("\n", " "); | |
670 | 0 | if (enteredType.length() > 0) |
671 | ||
672 | { | |
673 | /* | |
674 | * update default values only if creating using default values | |
675 | */ | |
676 | 0 | if (useLastDefaults) |
677 | { | |
678 | 0 | lastFeatureAdded = enteredType; |
679 | 0 | lastFeatureGroupAdded = enteredGroup; |
680 | // TODO: determine if the null feature group is valid | |
681 | 0 | if (lastFeatureGroupAdded.length() < 1) |
682 | { | |
683 | 0 | lastFeatureGroupAdded = null; |
684 | } | |
685 | } | |
686 | } | |
687 | ||
688 | 0 | SequenceFeature sf = features.get(featureIndex); |
689 | ||
690 | /* | |
691 | * Need to refresh Feature Settings if type, group or colour changed; | |
692 | * note we don't force the feature to be visible - the user has been | |
693 | * warned if a hidden feature type or group was entered | |
694 | */ | |
695 | 0 | boolean refreshSettings = (!featureType.equals(enteredType) |
696 | || !featureGroup.equals(enteredGroup)); | |
697 | 0 | refreshSettings |= (featureColour != oldColour); |
698 | 0 | fr.setColour(enteredType, featureColour); |
699 | 0 | int newBegin = sf.begin; |
700 | 0 | int newEnd = sf.end; |
701 | 0 | try |
702 | { | |
703 | 0 | newBegin = ((Integer) start.getValue()).intValue(); |
704 | 0 | newEnd = ((Integer) end.getValue()).intValue(); |
705 | } catch (NumberFormatException ex) | |
706 | { | |
707 | // JSpinner doesn't accept invalid format data :-) | |
708 | } | |
709 | ||
710 | /* | |
711 | * 'amend' the feature by deleting it and adding a new one | |
712 | * (to ensure integrity of SequenceFeatures data store) | |
713 | * note this dialog only updates one sequence at a time | |
714 | */ | |
715 | 0 | sequences.get(0).deleteFeature(sf); |
716 | 0 | SequenceFeature newSf = new SequenceFeature(sf, enteredType, |
717 | newBegin, newEnd, enteredGroup, sf.getScore()); | |
718 | 0 | newSf.setDescription(enteredDescription); |
719 | 0 | new FeaturesFile().parseDescriptionHTML(newSf, false); |
720 | 0 | sequences.get(0).addSequenceFeature(newSf); |
721 | ||
722 | 0 | if (refreshSettings) |
723 | { | |
724 | 0 | fr.featuresAdded(); |
725 | } | |
726 | 0 | repaintPanel(); |
727 | } | |
728 | }; | |
729 | 0 | return okAction; |
730 | } | |
731 | ||
732 | } |