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