2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
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.
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.
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.
23 import java.awt.Container;
24 import java.awt.Dimension;
26 import java.awt.FontMetrics;
27 import java.awt.Rectangle;
29 import java.util.ArrayList;
30 import java.util.Hashtable;
31 import java.util.List;
33 import javax.swing.JInternalFrame;
35 import jalview.analysis.AlignmentUtils;
36 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
37 import jalview.api.AlignViewportI;
38 import jalview.api.AlignmentViewPanel;
39 import jalview.api.FeatureColourI;
40 import jalview.api.FeatureSettingsModelI;
41 import jalview.api.FeaturesDisplayedI;
42 import jalview.api.ViewStyleI;
43 import jalview.bin.Cache;
44 import jalview.bin.Console;
45 import jalview.commands.CommandI;
46 import jalview.datamodel.AlignedCodonFrame;
47 import jalview.datamodel.Alignment;
48 import jalview.datamodel.AlignmentI;
49 import jalview.datamodel.ColumnSelection;
50 import jalview.datamodel.ContactMatrixI;
51 import jalview.datamodel.HiddenColumns;
52 import jalview.datamodel.SearchResults;
53 import jalview.datamodel.SearchResultsI;
54 import jalview.datamodel.SequenceGroup;
55 import jalview.datamodel.SequenceI;
56 import jalview.io.AppletFormatAdapter;
57 import jalview.io.DataSourceType;
58 import jalview.io.FileFormatException;
59 import jalview.io.FileFormatI;
60 import jalview.io.FileFormats;
61 import jalview.io.FileLoader;
62 import jalview.io.IdentifyFile;
63 import jalview.renderer.ResidueShader;
64 import jalview.schemes.ColourSchemeI;
65 import jalview.schemes.ColourSchemeProperty;
66 import jalview.schemes.ResidueColourScheme;
67 import jalview.schemes.UserColourScheme;
68 import jalview.structure.SelectionSource;
69 import jalview.structure.StructureSelectionManager;
70 import jalview.structure.VamsasSource;
71 import jalview.util.ColorUtils;
72 import jalview.util.MessageManager;
73 import jalview.viewmodel.AlignmentViewport;
74 import jalview.ws.params.AutoCalcSetting;
80 * @version $Revision: 1.141 $
82 public class AlignViewport extends AlignmentViewport<AlignmentPanel>
83 implements SelectionSource
87 boolean cursorMode = false;
89 boolean antiAlias = false;
91 private Rectangle explodedGeometry = null;
93 private String viewName = null;
96 * Flag set true on the view that should 'gather' multiple views of the same
97 * sequence set id when a project is reloaded. Set false on all views when
98 * they are 'exploded' into separate windows. Set true on the current view
99 * when 'Gather' is performed, and also on the first tab when the first new
102 private boolean gatherViewsHere = false;
104 private AnnotationColumnChooser annotationColumnSelectionState;
107 * Creates a new AlignViewport object.
112 public AlignViewport(AlignmentI al)
119 * Create a new AlignViewport object with a specific sequence set ID
123 * (may be null - but potential for ambiguous constructor exception)
125 public AlignViewport(AlignmentI al, String seqsetid)
127 this(al, seqsetid, null);
130 public AlignViewport(AlignmentI al, String seqsetid, String viewid)
133 sequenceSetID = seqsetid;
135 // TODO remove these once 2.4.VAMSAS release finished
136 if (seqsetid != null)
139 "Setting viewport's sequence set id : " + sequenceSetID);
143 Console.debug("Setting viewport's view id : " + viewId);
150 * Create a new AlignViewport with hidden regions
154 * @param hiddenColumns
157 public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns)
160 if (hiddenColumns != null)
162 al.setHiddenColumns(hiddenColumns);
168 * New viewport with hidden columns and an existing sequence set id
171 * @param hiddenColumns
175 public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
178 this(al, hiddenColumns, seqsetid, null);
182 * New viewport with hidden columns and an existing sequence set id and viewid
185 * @param hiddenColumns
191 public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
192 String seqsetid, String viewid)
195 sequenceSetID = seqsetid;
197 // TODO remove these once 2.4.VAMSAS release finished
198 if (seqsetid != null)
201 "Setting viewport's sequence set id : " + sequenceSetID);
205 Console.debug("Setting viewport's view id : " + viewId);
208 if (hiddenColumns != null)
210 al.setHiddenColumns(hiddenColumns);
216 * Apply any settings saved in user preferences
218 private void applyViewProperties()
220 antiAlias = Cache.getDefault("ANTI_ALIAS", true);
222 viewStyle.setShowJVSuffix(Cache.getDefault("SHOW_JVSUFFIX", true));
223 setShowAnnotation(Cache.getDefault("SHOW_ANNOTATIONS", true));
225 setRightAlignIds(Cache.getDefault("RIGHT_ALIGN_IDS", false));
226 setCentreColumnLabels(Cache.getDefault("CENTRE_COLUMN_LABELS", false));
227 autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true);
229 setPadGaps(Cache.getDefault("PAD_GAPS", true));
230 setShowNPFeats(Cache.getDefault("SHOW_NPFEATS_TOOLTIP", true));
231 setShowDBRefs(Cache.getDefault("SHOW_DBREFS_TOOLTIP", true));
232 viewStyle.setSeqNameItalics(Cache.getDefault("ID_ITALICS", true));
233 viewStyle.setWrapAlignment(Cache.getDefault("WRAP_ALIGNMENT", false));
234 viewStyle.setShowUnconserved(
235 Cache.getDefault("SHOW_UNCONSERVED", false));
236 sortByTree = Cache.getDefault("SORT_BY_TREE", false);
237 followSelection = Cache.getDefault("FOLLOW_SELECTIONS", true);
238 sortAnnotationsBy = SequenceAnnotationOrder
239 .valueOf(Cache.getDefault(Preferences.SORT_ANNOTATIONS,
240 SequenceAnnotationOrder.NONE.name()));
241 showAutocalculatedAbove = Cache
242 .getDefault(Preferences.SHOW_AUTOCALC_ABOVE, false);
243 viewStyle.setScaleProteinAsCdna(
244 Cache.getDefault(Preferences.SCALE_PROTEIN_TO_CDNA, true));
249 applyViewProperties();
251 String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
252 String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + "");
253 String fontSize = Cache.getDefault("FONT_SIZE", "10");
257 if (fontStyle.equals("bold"))
261 else if (fontStyle.equals("italic"))
266 setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true);
269 .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
271 // We must set conservation and consensus before setting colour,
272 // as Blosum and Clustal require this to be done
273 if (hconsensus == null && !isDataset)
275 if (!alignment.isNucleotide())
277 showConservation = Cache.getDefault("SHOW_CONSERVATION", true);
278 showQuality = Cache.getDefault("SHOW_QUALITY", true);
279 showGroupConservation = Cache.getDefault("SHOW_GROUP_CONSERVATION",
282 showConsensusHistogram = Cache.getDefault("SHOW_CONSENSUS_HISTOGRAM",
284 showSequenceLogo = Cache.getDefault("SHOW_CONSENSUS_LOGO", false);
285 normaliseSequenceLogo = Cache.getDefault("NORMALISE_CONSENSUS_LOGO",
287 showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
288 showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
290 showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true);
292 initAutoAnnotation();
293 String colourProperty = alignment.isNucleotide()
294 ? Preferences.DEFAULT_COLOUR_NUC
295 : Preferences.DEFAULT_COLOUR_PROT;
296 String schemeName = Cache.getProperty(colourProperty);
297 if (schemeName == null)
299 // only DEFAULT_COLOUR available in Jalview before 2.9
300 schemeName = Cache.getDefault(Preferences.DEFAULT_COLOUR,
301 ResidueColourScheme.NONE);
303 ColourSchemeI colourScheme = ColourSchemeProperty.getColourScheme(this,
304 alignment, schemeName);
305 residueShading = new ResidueShader(colourScheme);
307 if (colourScheme instanceof UserColourScheme)
309 residueShading = new ResidueShader(
310 UserDefinedColours.loadDefaultColours());
311 residueShading.setThreshold(0, isIgnoreGapsConsensus());
314 if (residueShading != null)
316 residueShading.setConsensus(hconsensus);
318 setColourAppliesToAllGroups(true);
321 boolean validCharWidth;
327 public void setFont(Font f, boolean setGrid)
331 Container c = new Container();
335 FontMetrics fm = c.getFontMetrics(font);
336 int ww = fm.charWidth('M');
337 setCharHeight(fm.getHeight());
340 viewStyle.setFontName(font.getName());
341 viewStyle.setFontStyle(font.getStyle());
342 viewStyle.setFontSize(font.getSize());
344 validCharWidth = true;
348 public void setViewStyle(ViewStyleI settingsForView)
350 super.setViewStyle(settingsForView);
351 setFont(new Font(viewStyle.getFontName(), viewStyle.getFontStyle(),
352 viewStyle.getFontSize()), false);
358 * @return DOCUMENT ME!
360 public Font getFont()
372 public void setAlignment(AlignmentI align)
374 replaceMappings(align);
375 super.setAlignment(align);
379 * Replace any codon mappings for this viewport with those for the given
384 public void replaceMappings(AlignmentI align)
388 * Deregister current mappings (if any)
390 deregisterMappings();
393 * Register new mappings (if any)
397 StructureSelectionManager ssm = StructureSelectionManager
398 .getStructureSelectionManager(Desktop.instance);
399 ssm.registerMappings(align.getCodonFrames());
403 * replace mappings on our alignment
405 if (alignment != null && align != null)
407 alignment.setCodonFrames(align.getCodonFrames());
411 protected void deregisterMappings()
413 AlignmentI al = getAlignment();
416 List<AlignedCodonFrame> mappings = al.getCodonFrames();
417 if (mappings != null)
419 StructureSelectionManager ssm = StructureSelectionManager
420 .getStructureSelectionManager(Desktop.instance);
421 for (AlignedCodonFrame acf : mappings)
423 if (noReferencesTo(acf))
425 ssm.deregisterMapping(acf);
435 * @return DOCUMENT ME!
438 public char getGapCharacter()
440 return getAlignment().getGapCharacter();
449 public void setGapCharacter(char gap)
451 if (getAlignment() != null)
453 getAlignment().setGapCharacter(gap);
458 * get hash of undo and redo list for the alignment
460 * @return long[] { historyList.hashCode, redoList.hashCode };
462 public long[] getUndoRedoHash()
465 if (historyList == null || redoList == null)
467 return new long[] { -1, -1 };
469 return new long[] { historyList.hashCode(), this.redoList.hashCode() };
473 * test if a particular set of hashcodes are different to the hashcodes for
474 * the undo and redo list.
477 * the stored set of hashcodes as returned by getUndoRedoHash
478 * @return true if the hashcodes differ (ie the alignment has been edited) or
479 * the stored hashcode array differs in size
481 public boolean isUndoRedoHashModified(long[] undoredo)
483 if (undoredo == null)
487 long[] cstate = getUndoRedoHash();
488 if (cstate.length != undoredo.length)
493 for (int i = 0; i < cstate.length; i++)
495 if (cstate[i] != undoredo[i])
503 public boolean followSelection = true;
506 * @return true if view selection should always follow the selections
507 * broadcast by other selection sources
509 public boolean getFollowSelection()
511 return followSelection;
515 * Send the current selection to be broadcast to any selection listeners.
518 public void sendSelection()
520 jalview.structure.StructureSelectionManager
521 .getStructureSelectionManager(Desktop.instance)
522 .sendSelection(new SequenceGroup(getSelectionGroup()),
523 new ColumnSelection(getColumnSelection()),
524 new HiddenColumns(getAlignment().getHiddenColumns()),
528 public boolean getSortByTree()
533 public void setSortByTree(boolean sort)
539 * Returns the (Desktop) instance of the StructureSelectionManager
542 public StructureSelectionManager getStructureSelectionManager()
544 return StructureSelectionManager
545 .getStructureSelectionManager(Desktop.instance);
549 public boolean isNormaliseSequenceLogo()
551 return normaliseSequenceLogo;
554 public void setNormaliseSequenceLogo(boolean state)
556 normaliseSequenceLogo = state;
561 * @return true if alignment characters should be displayed
564 public boolean isValidCharWidth()
566 return validCharWidth;
569 private Hashtable<String, AutoCalcSetting> calcIdParams = new Hashtable<>();
571 public AutoCalcSetting getCalcIdSettingsFor(String calcId)
573 return calcIdParams.get(calcId);
576 public void setCalcIdSettingsFor(String calcId, AutoCalcSetting settings,
579 calcIdParams.put(calcId, settings);
580 // TODO: create a restart list to trigger any calculations that need to be
581 // restarted after load
582 // calculator.getRegisteredWorkersOfClass(settings.getWorkerClass())
585 Console.debug("trigger update for " + calcId);
590 * Method called when another alignment's edit (or possibly other) command is
593 * To allow for sequence mappings (e.g. protein to cDNA), we have to first
594 * 'unwind' the command on the source sequences (in simulation, not in fact),
595 * and then for each edit in turn:
597 * <li>compute the equivalent edit on the mapped sequences</li>
598 * <li>apply the mapped edit</li>
599 * <li>'apply' the source edit to the working copy of the source
608 public void mirrorCommand(CommandI command, boolean undo,
609 StructureSelectionManager ssm, VamsasSource source)
612 * Do nothing unless we are a 'complement' of the source. May replace this
613 * with direct calls not via SSM.
615 if (source instanceof AlignViewportI
616 && ((AlignViewportI) source).getCodingComplement() == this)
625 CommandI mappedCommand = ssm.mapCommand(command, undo, getAlignment(),
627 if (mappedCommand != null)
629 AlignmentI[] views = getAlignPanel().alignFrame.getViewAlignments();
630 mappedCommand.doCommand(views);
631 getAlignPanel().alignmentChanged();
636 * Add the sequences from the given alignment to this viewport. Optionally,
637 * may give the user the option to open a new frame, or split panel, with cDNA
638 * and protein linked.
643 public void addAlignment(AlignmentI toAdd, String title)
645 // TODO: promote to AlignViewportI? applet CutAndPasteTransfer is different
647 // JBPComment: title is a largely redundant parameter at the moment
648 // JBPComment: this really should be an 'insert/pre/append' controller
649 // JBPComment: but the DNA/Protein check makes it a bit more complex
651 // refactored from FileLoader / CutAndPasteTransfer / SequenceFetcher with
653 // TODO: create undo object for this JAL-1101
656 * Ensure datasets are created for the new alignment as
657 * mappings operate on dataset sequences
659 toAdd.setDataset(null);
662 * Check if any added sequence could be the object of a mapping or
663 * cross-reference; if so, make the mapping explicit
665 getAlignment().realiseMappings(toAdd.getSequences());
668 * If any cDNA/protein mappings exist or can be made between the alignments,
669 * offer to open a split frame with linked alignments
671 if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
673 if (AlignmentUtils.isMappable(toAdd, getAlignment()))
675 openLinkedAlignment(toAdd, title);
679 addDataToAlignment(toAdd);
683 * adds sequences to this alignment
687 void addDataToAlignment(AlignmentI toAdd)
689 // TODO: JAL-407 regardless of above - identical sequences (based on ID and
690 // provenance) should share the same dataset sequence
692 AlignmentI al = getAlignment();
693 String gap = String.valueOf(al.getGapCharacter());
694 for (int i = 0; i < toAdd.getHeight(); i++)
696 SequenceI seq = toAdd.getSequenceAt(i);
699 * - 'align' any mapped sequences as per existing
700 * e.g. cdna to genome, domain hit to protein sequence
701 * very experimental! (need a separate menu option for this)
702 * - only add mapped sequences ('select targets from a dataset')
704 if (true /*AlignmentUtils.alignSequenceAs(seq, al, gap, true, true)*/)
709 for (ContactMatrixI cm : toAdd.getContactMaps())
711 al.addContactList(cm);
713 ranges.setEndSeq(getAlignment().getHeight() - 1); // BH 2019.04.18
714 firePropertyChange("alignment", null, getAlignment().getSequences());
718 * Load a File into this AlignViewport attempting to detect format if not
719 * given or given as null.
724 public void addFile(File file, FileFormatI format)
726 DataSourceType protocol = AppletFormatAdapter.checkProtocol(file);
732 format = new IdentifyFile().identify(file, protocol);
733 } catch (FileFormatException e1)
735 jalview.bin.Console.error("Unknown file format for '" + file + "'");
738 else if (FileFormats.getInstance().isIdentifiable(format))
742 format = new IdentifyFile().identify(file, protocol);
743 } catch (FileFormatException e)
745 jalview.bin.Console.error("Unknown file format for '" + file + "'",
750 new FileLoader().LoadFile(this, file, DataSourceType.FILE, format);
753 public void addFile(File file)
759 * Show a dialog with the option to open and link (cDNA <-> protein) as a new
760 * alignment, either as a standalone alignment or in a split frame. Returns
761 * true if the new alignment was opened, false if not, because the user
762 * declined the offer.
767 protected void openLinkedAlignment(AlignmentI al, String title)
769 String[] options = new String[] { MessageManager.getString("action.no"),
770 MessageManager.getString("label.split_window"),
771 MessageManager.getString("label.new_window"), };
772 final String question = JvSwingUtils.wrapTooltip(true,
773 MessageManager.getString("label.open_split_window?"));
774 final AlignViewport us = this;
777 * options No, Split Window, New Window correspond to
778 * dialog responses 0, 1, 2 (even though JOptionPane shows them
781 JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop)
782 .setResponseHandler(0, () -> {
783 addDataToAlignment(al);
785 }).setResponseHandler(1, () -> {
786 us.openLinkedAlignmentAs(al, title, true);
788 }).setResponseHandler(2, () -> {
789 us.openLinkedAlignmentAs(al, title, false);
792 dialog.showDialog(question,
793 MessageManager.getString("label.open_split_window"),
794 JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null,
795 options, options[0]);
798 protected void openLinkedAlignmentAs(AlignmentI al, String title,
799 boolean newWindowOrSplitPane)
802 * Identify protein and dna alignments. Make a copy of this one if opening
803 * in a new split pane.
805 AlignmentI thisAlignment = newWindowOrSplitPane
806 ? new Alignment(getAlignment())
808 AlignmentI protein = al.isNucleotide() ? thisAlignment : al;
809 final AlignmentI cdna = al.isNucleotide() ? al : thisAlignment;
812 * Map sequences. At least one should get mapped as we have already passed
813 * the test for 'mappability'. Any mappings made will be added to the
814 * protein alignment. Note creating dataset sequences on the new alignment
815 * is a pre-requisite for building mappings.
818 AlignmentUtils.mapProteinAlignmentToCdna(protein, cdna);
821 * Create the AlignFrame for the added alignment. If it is protein, mappings
822 * are registered with StructureSelectionManager as a side-effect.
824 AlignFrame newAlignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
825 AlignFrame.DEFAULT_HEIGHT);
826 newAlignFrame.setTitle(title);
827 newAlignFrame.setStatus(MessageManager
828 .formatMessage("label.successfully_loaded_file", new Object[]
831 // TODO if we want this (e.g. to enable reload of the alignment from file),
832 // we will need to add parameters to the stack.
833 // if (!protocol.equals(DataSourceType.PASTE))
835 // alignFrame.setFileName(file, format);
838 if (!newWindowOrSplitPane)
840 Desktop.addInternalFrame(newAlignFrame, title,
841 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
846 newAlignFrame.setMaximum(Cache.getDefault("SHOW_FULLSCREEN", false));
847 } catch (java.beans.PropertyVetoException ex)
851 if (newWindowOrSplitPane)
853 al.alignAs(thisAlignment);
854 protein = openSplitFrame(newAlignFrame, thisAlignment);
859 * Helper method to open a new SplitFrame holding linked dna and protein
862 * @param newAlignFrame
863 * containing a new alignment to be shown
865 * cdna/protein complement alignment to show in the other split half
866 * @return the protein alignment in the split frame
868 protected AlignmentI openSplitFrame(AlignFrame newAlignFrame,
869 AlignmentI complement)
872 * Make a new frame with a copy of the alignment we are adding to. If this
873 * is protein, the mappings to cDNA will be registered with
874 * StructureSelectionManager as a side-effect.
876 AlignFrame copyMe = new AlignFrame(complement, AlignFrame.DEFAULT_WIDTH,
877 AlignFrame.DEFAULT_HEIGHT);
878 copyMe.setTitle(getAlignPanel().alignFrame.getTitle());
880 AlignmentI al = newAlignFrame.viewport.getAlignment();
881 final AlignFrame proteinFrame = al.isNucleotide() ? copyMe
883 final AlignFrame cdnaFrame = al.isNucleotide() ? newAlignFrame : copyMe;
884 cdnaFrame.setVisible(true);
885 proteinFrame.setVisible(true);
886 String linkedTitle = MessageManager
887 .getString("label.linked_view_title");
890 * Open in split pane. DNA sequence above, protein below.
892 JInternalFrame splitFrame = new SplitFrame(cdnaFrame, proteinFrame);
893 Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
895 return proteinFrame.viewport.getAlignment();
898 public AnnotationColumnChooser getAnnotationColumnSelectionState()
900 return annotationColumnSelectionState;
903 public void setAnnotationColumnSelectionState(
904 AnnotationColumnChooser currentAnnotationColumnSelectionState)
906 this.annotationColumnSelectionState = currentAnnotationColumnSelectionState;
910 public void setIdWidth(int i)
913 AlignmentPanel ap = getAlignPanel();
916 // modify GUI elements to reflect geometry change
917 Dimension idw = ap.getIdPanel().getIdCanvas().getPreferredSize();
919 ap.getIdPanel().getIdCanvas().setPreferredSize(idw);
923 public Rectangle getExplodedGeometry()
925 return explodedGeometry;
928 public void setExplodedGeometry(Rectangle explodedPosition)
930 this.explodedGeometry = explodedPosition;
933 public boolean isGatherViewsHere()
935 return gatherViewsHere;
938 public void setGatherViewsHere(boolean gatherViewsHere)
940 this.gatherViewsHere = gatherViewsHere;
944 * If this viewport has a (Protein/cDNA) complement, then scroll the
945 * complementary alignment to match this one.
947 public void scrollComplementaryAlignment()
950 * Populate a SearchResults object with the mapped location to scroll to. If
951 * there is no complement, or it is not following highlights, or no mapping
952 * is found, the result will be empty.
954 SearchResultsI sr = new SearchResults();
955 int verticalOffset = findComplementScrollTarget(sr);
958 // TODO would like next line without cast but needs more refactoring...
959 final AlignmentPanel complementPanel = ((AlignViewport) getCodingComplement())
961 complementPanel.setToScrollComplementPanel(false);
962 complementPanel.scrollToCentre(sr, verticalOffset);
963 complementPanel.setToScrollComplementPanel(true);
968 * Answers true if no alignment holds a reference to the given mapping
973 protected boolean noReferencesTo(AlignedCodonFrame acf)
975 AlignFrame[] frames = Desktop.getAlignFrames();
980 for (AlignFrame af : frames)
984 for (AlignmentViewPanel ap : af.getAlignPanels())
986 AlignmentI al = ap.getAlignment();
987 if (al != null && al.getCodonFrames().contains(acf))
998 * Applies the supplied feature settings descriptor to currently known
999 * features. This supports an 'initial configuration' of feature colouring
1000 * based on a preset or user favourite. This may then be modified in the usual
1001 * way using the Feature Settings dialogue.
1003 * @param featureSettings
1006 public void applyFeaturesStyle(FeatureSettingsModelI featureSettings)
1008 transferFeaturesStyles(featureSettings, false);
1012 * Applies the supplied feature settings descriptor to currently known
1013 * features. This supports an 'initial configuration' of feature colouring
1014 * based on a preset or user favourite. This may then be modified in the usual
1015 * way using the Feature Settings dialogue.
1017 * @param featureSettings
1020 public void mergeFeaturesStyle(FeatureSettingsModelI featureSettings)
1022 transferFeaturesStyles(featureSettings, true);
1026 * when mergeOnly is set, then group and feature visibility or feature colours
1027 * are not modified for features and groups already known to the feature
1028 * renderer. Feature ordering is always adjusted, and transparency is always
1031 * @param featureSettings
1034 private void transferFeaturesStyles(FeatureSettingsModelI featureSettings,
1037 if (featureSettings == null)
1042 FeatureRenderer fr = getAlignPanel().getSeqPanel().seqCanvas
1043 .getFeatureRenderer();
1044 List<String> origRenderOrder = new ArrayList<>();
1045 List<String> origGroups = new ArrayList<>();
1046 // preserve original render order - allows differentiation between user
1047 // configured colours and autogenerated ones
1048 origRenderOrder.addAll(fr.getRenderOrder());
1049 origGroups.addAll(fr.getFeatureGroups());
1051 fr.findAllFeatures(true);
1052 List<String> renderOrder = fr.getRenderOrder();
1053 FeaturesDisplayedI displayed = fr.getFeaturesDisplayed();
1056 // only clear displayed features if we are mergeing
1057 // displayed.clear();
1059 // TODO this clears displayed.featuresRegistered - do we care?
1061 // JAL-3330 - JBP - yes we do - calling applyFeatureStyle to a view where
1062 // feature visibility has already been configured is not very friendly
1064 * set feature colour if specified by feature settings
1065 * set visibility of all features
1067 for (String type : renderOrder)
1069 FeatureColourI preferredColour = featureSettings
1070 .getFeatureColour(type);
1071 FeatureColourI origColour = fr.getFeatureStyle(type);
1072 if (!mergeOnly || (!origRenderOrder.contains(type)
1073 || origColour == null
1074 || (!origColour.isGraduatedColour()
1075 && origColour.getColour() != null
1076 && origColour.getColour().equals(
1077 ColorUtils.createColourFromName(type)))))
1079 // if we are merging, only update if there wasn't already a colour
1082 if (preferredColour != null)
1084 fr.setColour(type, preferredColour);
1086 if (featureSettings.isFeatureDisplayed(type))
1088 displayed.setVisible(type);
1090 else if (featureSettings.isFeatureHidden(type))
1092 displayed.setHidden(type);
1098 * set visibility of feature groups
1100 for (String group : fr.getFeatureGroups())
1102 if (!mergeOnly || !origGroups.contains(group))
1104 // when merging, display groups only if the aren't already marked as not
1106 fr.setGroupVisibility(group,
1107 featureSettings.isGroupDisplayed(group));
1112 * order the features
1114 if (featureSettings.optimiseOrder())
1116 // TODO not supported (yet?)
1120 fr.orderFeatures(featureSettings);
1122 fr.setTransparency(featureSettings.getTransparency());
1124 fr.notifyFeaturesChanged();
1127 public String getViewName()
1132 public void setViewName(String viewName)
1134 this.viewName = viewName;