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