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