JAL-2435 slightly more sensible behaviour changing fonts in split frame
[jalview.git] / src / jalview / gui / FontChooser.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.gui;
22
23 import jalview.bin.Cache;
24 import jalview.jbgui.GFontChooser;
25 import jalview.util.MessageManager;
26
27 import java.awt.Font;
28 import java.awt.FontMetrics;
29 import java.awt.geom.Rectangle2D;
30
31 import javax.swing.JInternalFrame;
32 import javax.swing.JLayeredPane;
33
34 /**
35  * DOCUMENT ME!
36  * 
37  * @author $author$
38  * @version $Revision$
39  */
40 public class FontChooser extends GFontChooser
41 {
42   AlignmentPanel ap;
43
44   TreePanel tp;
45
46   /*
47    * The font on opening the dialog (to be restored on Cancel)
48    */
49   Font oldFont;
50
51   /*
52    * the state of 'scale protein as cDNA' on opening the dialog
53    */
54   boolean oldProteinScale;
55
56   /*
57    * the state of 'same font for protein and cDNA' on opening the dialog
58    */
59   boolean oldMirrorFont;
60
61   boolean init = true;
62
63   JInternalFrame frame;
64
65   /*
66    * The last font settings selected in the dialog
67    */
68   private Font lastSelected = null;
69
70   private boolean lastSelMono = false;
71
72   /**
73    * Creates a new FontChooser for a tree panel
74    * 
75    * @param treePanel
76    */
77   public FontChooser(TreePanel treePanel)
78   {
79     this.tp = treePanel;
80     ap = treePanel.treeCanvas.ap;
81     oldFont = treePanel.getTreeFont();
82     defaultButton.setVisible(false);
83     smoothFont.setEnabled(false);
84     init();
85   }
86
87   /**
88    * Creates a new FontChooser for an alignment panel
89    * 
90    * @param alignPanel
91    */
92   public FontChooser(AlignmentPanel alignPanel)
93   {
94     oldFont = alignPanel.av.getFont();
95     oldProteinScale = alignPanel.av.isScaleProteinAsCdna();
96     oldMirrorFont = alignPanel.av.isProteinFontAsCdna();
97
98     this.ap = alignPanel;
99     init();
100   }
101
102   void init()
103   {
104     frame = new JInternalFrame();
105     frame.setContentPane(this);
106
107     smoothFont.setSelected(ap.av.antiAlias);
108
109     /*
110      * Enable 'scale protein as cDNA' in a SplitFrame view. The selection is
111      * stored in the ViewStyle of both dna and protein Viewport. Also enable
112      * checkbox for copy font changes to other half of split frame.
113      */
114     boolean inSplitFrame = ap.av.getCodingComplement() != null;
115     if (inSplitFrame)
116     {
117       scaleAsCdna.setVisible(true);
118       scaleAsCdna.setSelected(ap.av.isScaleProteinAsCdna());
119       fontAsCdna.setVisible(true);
120       fontAsCdna.setSelected(ap.av.isProteinFontAsCdna());
121     }
122
123     if (tp != null)
124     {
125       Desktop.addInternalFrame(frame,
126               MessageManager.getString("action.change_font_tree_panel"),
127               400, 200, false);
128     }
129     else
130     {
131       Desktop.addInternalFrame(frame,
132               MessageManager.getString("action.change_font"), 380, 220,
133               false);
134     }
135
136     frame.setLayer(JLayeredPane.PALETTE_LAYER);
137
138     String[] fonts = java.awt.GraphicsEnvironment
139             .getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
140
141     for (int i = 0; i < fonts.length; i++)
142     {
143       fontName.addItem(fonts[i]);
144     }
145
146     for (int i = 1; i < 51; i++)
147     {
148       fontSize.addItem(i);
149     }
150
151     fontStyle.addItem("plain");
152     fontStyle.addItem("bold");
153     fontStyle.addItem("italic");
154
155     fontName.setSelectedItem(oldFont.getName());
156     fontSize.setSelectedItem(oldFont.getSize());
157     fontStyle.setSelectedIndex(oldFont.getStyle());
158
159     FontMetrics fm = getGraphics().getFontMetrics(oldFont);
160     monospaced.setSelected(fm.getStringBounds("M", getGraphics())
161             .getWidth() == fm.getStringBounds("|", getGraphics())
162             .getWidth());
163
164     init = false;
165   }
166
167   @Override
168   protected void smoothFont_actionPerformed()
169   {
170     ap.av.antiAlias = smoothFont.isSelected();
171     ap.getAnnotationPanel().image = null;
172     ap.paintAlignment(true);
173   }
174
175   /**
176    * DOCUMENT ME!
177    * 
178    * @param e
179    *          DOCUMENT ME!
180    */
181   @Override
182   protected void ok_actionPerformed()
183   {
184     try
185     {
186       frame.setClosed(true);
187     } catch (Exception ex)
188     {
189     }
190
191     if (ap != null)
192     {
193       if (ap.getOverviewPanel() != null)
194       {
195         ap.getOverviewPanel().updateOverviewImage();
196       }
197     }
198   }
199
200   /**
201    * DOCUMENT ME!
202    * 
203    * @param e
204    *          DOCUMENT ME!
205    */
206   @Override
207   protected void cancel_actionPerformed()
208   {
209     if (ap != null)
210     {
211       ap.av.setFont(oldFont, true);
212       ap.av.setScaleProteinAsCdna(oldProteinScale);
213       ap.av.setProteinFontAsCdna(oldMirrorFont);
214       ap.paintAlignment(true);
215
216       if (scaleAsCdna.isVisible() && scaleAsCdna.isEnabled())
217       {
218         ap.av.getCodingComplement().setScaleProteinAsCdna(oldProteinScale);
219         ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont);
220         ap.av.getCodingComplement().setFont(oldFont, true);
221       }
222     }
223     else if (tp != null)
224     {
225       tp.setTreeFont(oldFont);
226     }
227
228     try
229     {
230       frame.setClosed(true);
231     } catch (Exception ex)
232     {
233     }
234   }
235
236   /**
237    * DOCUMENT ME!
238    */
239   void changeFont()
240   {
241     if (lastSelected == null)
242     {
243       // initialise with original font
244       lastSelected = oldFont;
245       FontMetrics fm = getGraphics().getFontMetrics(oldFont);
246       double mw = fm.getStringBounds("M", getGraphics()).getWidth();
247       double iw = fm.getStringBounds("I", getGraphics()).getWidth();
248       lastSelMono = (mw == iw); // == on double - flaky?
249     }
250
251     Font newFont = new Font(fontName.getSelectedItem().toString(),
252             fontStyle.getSelectedIndex(),
253             (Integer) fontSize.getSelectedItem());
254     FontMetrics fm = getGraphics().getFontMetrics(newFont);
255     double mw = fm.getStringBounds("M", getGraphics()).getWidth();
256     final Rectangle2D iBounds = fm.getStringBounds("I", getGraphics());
257     double iw = iBounds.getWidth();
258     if (mw < 1 || iw < 1)
259     {
260       String message = iBounds.getHeight() < 1 ? MessageManager
261               .getString("label.font_doesnt_have_letters_defined")
262               : MessageManager.getString("label.font_too_small");
263       JvOptionPane.showInternalMessageDialog(this, message,
264               MessageManager.getString("label.invalid_font"),
265               JvOptionPane.WARNING_MESSAGE);
266       /*
267        * Restore the changed value - note this will reinvoke this method via the
268        * ActionListener, but now validation should pass
269        */
270       if (lastSelected.getSize() != (Integer) fontSize.getSelectedItem()) // autoboxing
271       {
272         fontSize.setSelectedItem(lastSelected.getSize());
273       }
274       if (!lastSelected.getName().equals(
275               fontName.getSelectedItem().toString()))
276       {
277         fontName.setSelectedItem(lastSelected.getName());
278       }
279       if (lastSelected.getStyle() != fontStyle.getSelectedIndex())
280       {
281         fontStyle.setSelectedIndex(lastSelected.getStyle());
282       }
283       if (lastSelMono != monospaced.isSelected())
284       {
285         monospaced.setSelected(lastSelMono);
286       }
287       return;
288     }
289     if (tp != null)
290     {
291       tp.setTreeFont(newFont);
292     }
293     else if (ap != null)
294     {
295       ap.av.setFont(newFont, true);
296       ap.fontChanged();
297
298       /*
299        * adjust other half of split frame if any, if either same
300        * font, or proportionate scaling, is selected
301        */
302       if (fontAsCdna.isEnabled())
303       {
304         if (fontAsCdna.isSelected())
305         {
306           /*
307            * copy the font
308            */
309           ap.av.getCodingComplement().setFont(newFont, true);
310         }
311         if (fontAsCdna.isSelected() || scaleAsCdna.isSelected())
312         {
313           /*
314            * adjust layout for font change and/or sizing
315            */
316           SplitFrame splitFrame = (SplitFrame) ap.alignFrame
317                   .getSplitViewContainer();
318           splitFrame.repaint();
319         }
320       }
321     }
322
323     monospaced.setSelected(mw == iw);
324
325     /*
326      * Remember latest valid selection, so it can be restored if followed by an
327      * invalid one
328      */
329     lastSelected = newFont;
330   }
331
332   /**
333    * Updates on change of selected font name
334    */
335   @Override
336   protected void fontName_actionPerformed()
337   {
338     if (init)
339     {
340       return;
341     }
342
343     changeFont();
344   }
345
346   /**
347    * Updates on change of selected font size
348    */
349   @Override
350   protected void fontSize_actionPerformed()
351   {
352     if (init)
353     {
354       return;
355     }
356
357     changeFont();
358   }
359
360   /**
361    * Updates on change of selected font style
362    */
363   @Override
364   protected void fontStyle_actionPerformed()
365   {
366     if (init)
367     {
368       return;
369     }
370
371     changeFont();
372   }
373
374   /**
375    * Make selected settings the defaults by storing them (via Cache class) in
376    * the .jalview_properties file (the file is only written when Jalview exits)
377    */
378   @Override
379   public void defaultButton_actionPerformed()
380   {
381     Cache.setProperty("FONT_NAME", fontName.getSelectedItem().toString());
382     Cache.setProperty("FONT_STYLE", fontStyle.getSelectedIndex() + "");
383     Cache.setProperty("FONT_SIZE", fontSize.getSelectedItem().toString());
384     Cache.setProperty("ANTI_ALIAS",
385             Boolean.toString(smoothFont.isSelected()));
386     Cache.setProperty(Preferences.SCALE_PROTEIN_TO_CDNA,
387             Boolean.toString(scaleAsCdna.isSelected()));
388   }
389
390   /**
391    * Turn on/off scaling of protein characters to 3 times the width of cDNA
392    * characters
393    */
394   @Override
395   protected void scaleAsCdna_actionPerformed()
396   {
397     ap.av.setScaleProteinAsCdna(scaleAsCdna.isSelected());
398     ap.av.getCodingComplement().setScaleProteinAsCdna(
399             scaleAsCdna.isSelected());
400     final SplitFrame splitFrame = (SplitFrame) ap.alignFrame
401             .getSplitViewContainer();
402     splitFrame.adjustLayout();
403     splitFrame.repaint();
404   }
405
406   /**
407    * Turn on/off mirroring of font across split frame. If turning on, also
408    * copies the current font across the split frame. If turning off, does not
409    * change fonts.
410    */
411   @Override
412   protected void mirrorFonts_actionPerformed()
413   {
414     boolean selected = fontAsCdna.isSelected();
415     ap.av.setProteinFontAsCdna(selected);
416     ap.av.getCodingComplement().setProteinFontAsCdna(selected);
417
418     if (selected)
419     {
420       changeFont();
421     }
422   }
423 }