Merge branch 'bug/JAL-3760_protsTreatedAsNucleotides' into releases/Release_2_11_1_Branch
[jalview.git] / src / jalview / appletgui / SplitFrame.java
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.appletgui;
22
23 import jalview.api.AlignmentViewPanel;
24 import jalview.api.ViewStyleI;
25 import jalview.bin.JalviewLite;
26 import jalview.datamodel.AlignmentI;
27 import jalview.structure.StructureSelectionManager;
28 import jalview.viewmodel.AlignmentViewport;
29
30 import java.awt.BorderLayout;
31 import java.awt.Dimension;
32 import java.awt.GridLayout;
33 import java.awt.Panel;
34
35 public class SplitFrame extends EmbmenuFrame
36 {
37   private static final long serialVersionUID = 1L;
38
39   private AlignFrame topFrame;
40
41   private AlignFrame bottomFrame;
42
43   private Panel outermost;
44
45   /**
46    * Constructs the split frame placing cdna in the top half. No 'alignment' is
47    * performed here, this should be done by the calling client if wanted.
48    */
49   public SplitFrame(AlignFrame af1, AlignFrame af2)
50   {
51     boolean af1IsNucleotide = af1.viewport.getAlignment().isNucleotide();
52     topFrame = af1IsNucleotide ? af1 : af2;
53     bottomFrame = topFrame == af1 ? af2 : af1;
54     init();
55   }
56
57   /**
58    * Creates a Panel containing two Panels, and adds the first and second
59    * AlignFrame's components to each. At this stage we have not yet committed to
60    * whether the enclosing panel will be added to this frame, for display as a
61    * separate frame, or added to the applet (embedded mode).
62    */
63   public void init()
64   {
65     constructSplit();
66
67     /*
68      * Try to make and add dna/protein sequence mappings
69      */
70     final AlignViewport topViewport = topFrame.viewport;
71     final AlignViewport bottomViewport = bottomFrame.viewport;
72     final AlignmentI topAlignment = topViewport.getAlignment();
73     final AlignmentI bottomAlignment = bottomViewport.getAlignment();
74     AlignmentViewport cdna = topAlignment.isNucleotide() ? topViewport
75             : (bottomAlignment.isNucleotide() ? bottomViewport : null);
76     AlignmentViewport protein = !topAlignment.isNucleotide() ? topViewport
77             : (!bottomAlignment.isNucleotide() ? bottomViewport : null);
78
79     final StructureSelectionManager ssm = StructureSelectionManager
80             .getStructureSelectionManager(topViewport.applet);
81     ssm.registerMappings(protein.getAlignment().getCodonFrames());
82     topViewport.setCodingComplement(bottomViewport);
83     ssm.addCommandListener(cdna);
84     ssm.addCommandListener(protein);
85
86     /*
87      * Compute cDNA consensus on protein alignment
88      */
89     protein.initComplementConsensus();
90     AlignmentViewPanel ap = topAlignment.isNucleotide()
91             ? bottomFrame.alignPanel
92             : topFrame.alignPanel;
93     protein.updateConsensus(ap);
94
95     adjustLayout();
96   }
97
98   /**
99    * 
100    */
101   protected void constructSplit()
102   {
103     setMenuBar(null);
104     outermost = new Panel(new GridLayout(2, 1));
105
106     Panel topPanel = new Panel();
107     Panel bottomPanel = new Panel();
108     outermost.add(topPanel);
109     outermost.add(bottomPanel);
110
111     addAlignFrameComponents(topFrame, topPanel);
112     addAlignFrameComponents(bottomFrame, bottomPanel);
113   }
114
115   /**
116    * Make any adjustments to the layout
117    */
118   protected void adjustLayout()
119   {
120     AlignmentViewport cdna = topFrame.getAlignViewport().getAlignment()
121             .isNucleotide() ? topFrame.viewport : bottomFrame.viewport;
122     AlignmentViewport protein = cdna == topFrame.viewport
123             ? bottomFrame.viewport
124             : topFrame.viewport;
125
126     /*
127      * Ensure sequence ids are the same width for good alignment.
128      */
129     // TODO should do this via av.getViewStyle/setViewStyle
130     // however at present av.viewStyle is not set in IdPanel.fontChanged
131     int w1 = topFrame.alignPanel.idPanel.idCanvas.getWidth();
132     int w2 = bottomFrame.alignPanel.idPanel.idCanvas.getWidth();
133     int w3 = Math.max(w1, w2);
134     if (w1 != w3)
135     {
136       Dimension d = topFrame.alignPanel.idPanel.idCanvas.getSize();
137       topFrame.alignPanel.idPanel.idCanvas
138               .setSize(new Dimension(w3, d.height));
139     }
140     if (w2 != w3)
141     {
142       Dimension d = bottomFrame.alignPanel.idPanel.idCanvas.getSize();
143       bottomFrame.alignPanel.idPanel.idCanvas
144               .setSize(new Dimension(w3, d.height));
145     }
146
147     /*
148      * Scale protein to either 1 or 3 times character width of dna
149      */
150     if (protein != null && cdna != null)
151     {
152       ViewStyleI vs = protein.getViewStyle();
153       int scale = vs.isScaleProteinAsCdna() ? 3 : 1;
154       vs.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
155       protein.setViewStyle(vs);
156     }
157   }
158
159   /**
160    * Add the menu bar, alignment panel and status bar from the AlignFrame to the
161    * panel. The menu bar is a panel 'reconstructed' from the AlignFrame's frame
162    * menu bar. This allows each half of the SplitFrame to have its own menu bar.
163    * 
164    * @param af
165    * @param panel
166    */
167   private void addAlignFrameComponents(AlignFrame af, Panel panel)
168   {
169     panel.setLayout(new BorderLayout());
170     Panel menuPanel = af.makeEmbeddedPopupMenu(af.getMenuBar(), true,
171             false);
172     panel.add(menuPanel, BorderLayout.NORTH);
173     panel.add(af.statusBar, BorderLayout.SOUTH);
174     panel.add(af.alignPanel, BorderLayout.CENTER);
175
176     af.setSplitFrame(this);
177   }
178
179   /**
180    * Display the content panel either as a new frame or embedded in the applet.
181    * 
182    * @param embedded
183    * @param applet
184    */
185   public void addToDisplay(boolean embedded, JalviewLite applet)
186   {
187     createSplitFrameWindow(embedded, applet);
188     validate();
189     topFrame.alignPanel.adjustAnnotationHeight();
190     topFrame.alignPanel.paintAlignment(true, true);
191     bottomFrame.alignPanel.adjustAnnotationHeight();
192     bottomFrame.alignPanel.paintAlignment(true, true);
193   }
194
195   /**
196    * Either show the content panel in this frame as a new frame, or (if
197    * embed=true) add it to the applet container instead.
198    * 
199    * @param embed
200    * @param applet
201    */
202   protected void createSplitFrameWindow(boolean embed, JalviewLite applet)
203   {
204     if (embed)
205     {
206       applet.add(outermost);
207       applet.validate();
208     }
209     else
210     {
211       this.add(outermost);
212       int width = Math.max(topFrame.frameWidth, bottomFrame.frameWidth);
213       int height = topFrame.frameHeight + bottomFrame.frameHeight;
214       jalview.bin.JalviewLite.addFrame(this, this.getTitle(), width,
215               height);
216     }
217   }
218
219   /**
220    * Returns the contained AlignFrame complementary to the one given (or null if
221    * no match to top or bottom component).
222    * 
223    * @param af
224    * @return
225    */
226   public AlignFrame getComplement(AlignFrame af)
227   {
228     if (topFrame == af)
229     {
230       return bottomFrame;
231     }
232     else if (bottomFrame == af)
233     {
234       return topFrame;
235     }
236     return null;
237   }
238 }