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