8b74e324d8d14b343c398a739183b4f4b288c062
[jalview.git] / src / jalview / appletgui / 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.appletgui;
22
23 import jalview.util.MessageManager;
24
25 import java.awt.BorderLayout;
26 import java.awt.Button;
27 import java.awt.Checkbox;
28 import java.awt.Choice;
29 import java.awt.Color;
30 import java.awt.FlowLayout;
31 import java.awt.Font;
32 import java.awt.FontMetrics;
33 import java.awt.Frame;
34 import java.awt.GraphicsEnvironment;
35 import java.awt.Label;
36 import java.awt.Panel;
37 import java.awt.event.ActionEvent;
38 import java.awt.event.ActionListener;
39 import java.awt.event.ItemEvent;
40 import java.awt.event.ItemListener;
41
42 /**
43  * This dialog allows the user to try different font settings and related
44  * options. Changes are immediately visible on the alignment or tree. The user
45  * can dismiss the dialog by confirming changes with 'OK', or reverting to
46  * previous settings with 'Cancel'.
47  */
48 @SuppressWarnings("serial")
49 public class FontChooser extends Panel implements ItemListener
50 {
51   private static final Font VERDANA_11PT = new Font("Verdana", 0, 11);
52
53   private Choice fontSize = new Choice();
54
55   private Choice fontStyle = new Choice();
56
57   private Choice fontName = new Choice();
58
59   private Checkbox scaleAsCdna = new Checkbox();
60
61   private Checkbox fontAsCdna = new Checkbox();
62
63   private Button ok = new Button();
64
65   private Button cancel = new Button();
66
67   private AlignmentPanel ap;
68
69   private TreePanel tp;
70
71   private Font oldFont;
72
73   private Font oldComplementFont;
74
75   private int oldCharWidth = 0;
76
77   /*
78    * the state of 'scale protein to cDNA' on opening the dialog
79    */
80   private boolean oldScaleProtein = false;
81
82   /*
83    * the state of 'same font for protein and cDNA' on opening the dialog
84    */
85   boolean oldMirrorFont;
86
87   private Font lastSelected = null;
88
89   private int lastSelStyle = 0;
90
91   private int lastSelSize = 0;
92
93   private boolean init = true;
94
95   private Frame frame;
96
97   boolean inSplitFrame = false;
98
99   /**
100    * Constructor for a TreePanel font chooser
101    * 
102    * @param tp
103    */
104   public FontChooser(TreePanel tp)
105   {
106     try
107     {
108       jbInit();
109     } catch (Exception e)
110     {
111       e.printStackTrace();
112     }
113
114     this.tp = tp;
115     oldFont = tp.getTreeFont();
116     init();
117   }
118
119   /**
120    * Constructor for an AlignmentPanel font chooser
121    * 
122    * @param ap
123    */
124   public FontChooser(AlignmentPanel ap)
125   {
126     this.ap = ap;
127     oldFont = ap.av.getFont();
128     oldCharWidth = ap.av.getCharWidth();
129     oldScaleProtein = ap.av.isScaleProteinAsCdna();
130     oldMirrorFont = ap.av.isProteinFontAsCdna();
131
132     try
133     {
134       jbInit();
135     } catch (Exception e)
136     {
137       e.printStackTrace();
138     }
139     init();
140   }
141
142   /**
143    * Populate choice lists and open this dialog
144    */
145   void init()
146   {
147     // String fonts[] = Toolkit.getDefaultToolkit().getFontList();
148     String fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
149             .getAvailableFontFamilyNames();
150     for (int i = 0; i < fonts.length; i++)
151     {
152       fontName.addItem(fonts[i]);
153     }
154
155     for (int i = 1; i < 31; i++)
156     {
157       fontSize.addItem(i + "");
158     }
159
160     fontStyle.addItem("plain");
161     fontStyle.addItem("bold");
162     fontStyle.addItem("italic");
163
164     fontName.select(oldFont.getName());
165     fontSize.select(oldFont.getSize() + "");
166     fontStyle.select(oldFont.getStyle());
167
168     this.frame = new Frame();
169     frame.add(this);
170     jalview.bin.JalviewLite.addFrame(frame,
171             MessageManager.getString("action.change_font"), 440, 145);
172
173     init = false;
174   }
175
176   /**
177    * Actions on change of font name, size or style.
178    */
179   @Override
180   public void itemStateChanged(ItemEvent evt)
181   {
182     final Object source = evt.getSource();
183     if (source == fontName)
184     {
185       fontName_actionPerformed();
186     }
187     else if (source == fontSize)
188     {
189       fontSize_actionPerformed();
190     }
191     else if (source == fontStyle)
192     {
193       fontStyle_actionPerformed();
194     }
195     else if (source == scaleAsCdna)
196     {
197       scaleAsCdna_actionPerformed();
198     }
199     else if (source == fontAsCdna)
200     {
201       mirrorFont_actionPerformed();
202     }
203   }
204
205   /**
206    * Action on checking or unchecking 'use same font across split screen'
207    * option. When checked, the font settings are copied to the other half of the
208    * split screen. When unchecked, the other half is restored to its initial
209    * settings.
210    */
211   protected void mirrorFont_actionPerformed()
212   {
213     boolean selected = fontAsCdna.getState();
214     ap.av.setProteinFontAsCdna(selected);
215     ap.av.getCodingComplement().setProteinFontAsCdna(selected);
216
217     if (!selected)
218     {
219       ap.av.getCodingComplement().setFont(oldComplementFont, true);
220     }
221     changeFont();
222   }
223
224   /**
225    * Close this dialog on OK to confirm any changes. Also updates the overview
226    * window if displayed.
227    */
228   protected void ok_actionPerformed()
229   {
230     frame.setVisible(false);
231     if (ap != null)
232     {
233       if (ap.getOverviewPanel() != null)
234       {
235         ap.getOverviewPanel().updateOverviewImage();
236       }
237     }
238   }
239
240   /**
241    * Close this dialog on Cancel, reverting to previous font settings.
242    */
243   protected void cancel_actionPerformed()
244   {
245     if (ap != null)
246     {
247       ap.av.setScaleProteinAsCdna(oldScaleProtein);
248       ap.av.setProteinFontAsCdna(oldMirrorFont);
249
250       if (ap.av.getCodingComplement() != null)
251       {
252         ap.av.getCodingComplement().setScaleProteinAsCdna(oldScaleProtein);
253         ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont);
254         ap.av.getCodingComplement().setFont(oldComplementFont, true);
255         SplitFrame splitFrame = ap.alignFrame.getSplitFrame();
256         splitFrame.adjustLayout();
257         splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged();
258         splitFrame.repaint();
259       }
260
261       ap.av.setFont(oldFont, true);
262       if (ap.av.getCharWidth() != oldCharWidth)
263       {
264         ap.av.setCharWidth(oldCharWidth);
265       }
266       ap.paintAlignment(true, false);
267     }
268     else if (tp != null)
269     {
270       tp.setTreeFont(oldFont);
271       tp.treeCanvas.repaint();
272     }
273
274     fontName.select(oldFont.getName());
275     fontSize.select(oldFont.getSize() + "");
276     fontStyle.select(oldFont.getStyle());
277
278     frame.setVisible(false);
279   }
280
281   /**
282    * DOCUMENT ME!
283    */
284   void changeFont()
285   {
286     if (lastSelected == null)
287     {
288       // initialise with original font
289       lastSelected = oldFont;
290       lastSelSize = oldFont.getSize();
291       lastSelStyle = oldFont.getStyle();
292     }
293
294     Font newFont = new Font(fontName.getSelectedItem().toString(),
295             fontStyle.getSelectedIndex(),
296             Integer.parseInt(fontSize.getSelectedItem().toString()));
297     FontMetrics fm = getGraphics().getFontMetrics(newFont);
298     double mw = fm.getStringBounds("M", getGraphics()).getWidth(),
299             iw = fm.getStringBounds("I", getGraphics()).getWidth();
300     if (mw < 1 || iw < 1)
301     {
302       // TODO: JAL-1100
303       fontName.select(lastSelected.getName());
304       fontStyle.select(lastSelStyle);
305       fontSize.select("" + lastSelSize);
306       JVDialog d = new JVDialog(this.frame,
307               MessageManager.getString("label.invalid_font"), true, 350,
308               200);
309       Panel mp = new Panel();
310       d.cancel.setVisible(false);
311       mp.setLayout(new FlowLayout());
312       mp.add(new Label(
313               "Font doesn't have letters defined\nso cannot be used\nwith alignment data."));
314       d.setMainPanel(mp);
315       d.setVisible(true);
316       return;
317     }
318     if (tp != null)
319     {
320       tp.setTreeFont(newFont);
321     }
322     else if (ap != null)
323     {
324       ap.av.setFont(newFont, true);
325       ap.fontChanged();
326
327       /*
328        * and change font in other half of split frame if any
329        */
330       if (inSplitFrame)
331       {
332         if (fontAsCdna.getState())
333         {
334           ap.av.getCodingComplement().setFont(newFont, true);
335         }
336         SplitFrame splitFrame = ap.alignFrame.getSplitFrame();
337         splitFrame.adjustLayout();
338         splitFrame.getComplement(ap.alignFrame).alignPanel.fontChanged();
339         splitFrame.repaint();
340       }
341     }
342     // remember last selected
343     lastSelected = newFont;
344   }
345
346   protected void fontName_actionPerformed()
347   {
348     if (init)
349     {
350       return;
351     }
352     changeFont();
353   }
354
355   protected void fontSize_actionPerformed()
356   {
357     if (init)
358     {
359       return;
360     }
361     changeFont();
362   }
363
364   protected void fontStyle_actionPerformed()
365   {
366     if (init)
367     {
368       return;
369     }
370     changeFont();
371   }
372
373   /**
374    * Construct this panel's contents
375    * 
376    * @throws Exception
377    */
378   private void jbInit() throws Exception
379   {
380     this.setLayout(new BorderLayout());
381     this.setBackground(Color.white);
382
383     Label fontLabel = new Label(MessageManager.getString("label.font"));
384     fontLabel.setFont(VERDANA_11PT);
385     fontLabel.setAlignment(Label.RIGHT);
386     fontSize.setFont(VERDANA_11PT);
387     fontSize.addItemListener(this);
388     fontStyle.setFont(VERDANA_11PT);
389     fontStyle.addItemListener(this);
390
391     Label sizeLabel = new Label(MessageManager.getString("label.size"));
392     sizeLabel.setAlignment(Label.RIGHT);
393     sizeLabel.setFont(VERDANA_11PT);
394
395     Label styleLabel = new Label(MessageManager.getString("label.style"));
396     styleLabel.setAlignment(Label.RIGHT);
397     styleLabel.setFont(VERDANA_11PT);
398
399     fontName.setFont(VERDANA_11PT);
400     fontName.addItemListener(this);
401
402     scaleAsCdna.setLabel(MessageManager.getString("label.scale_as_cdna"));
403     scaleAsCdna.setFont(VERDANA_11PT);
404     scaleAsCdna.addItemListener(this);
405     scaleAsCdna.setState(ap.av.isScaleProteinAsCdna());
406
407     fontAsCdna.setLabel(MessageManager.getString("label.font_as_cdna"));
408     fontAsCdna.setFont(VERDANA_11PT);
409     fontAsCdna.addItemListener(this);
410     fontAsCdna.setState(ap.av.isProteinFontAsCdna());
411
412     ok.setFont(VERDANA_11PT);
413     ok.setLabel(MessageManager.getString("action.ok"));
414     ok.addActionListener(new ActionListener()
415     {
416       @Override
417       public void actionPerformed(ActionEvent e)
418       {
419         ok_actionPerformed();
420       }
421     });
422     cancel.setFont(VERDANA_11PT);
423     cancel.setLabel(MessageManager.getString("action.cancel"));
424     cancel.addActionListener(new ActionListener()
425     {
426       @Override
427       public void actionPerformed(ActionEvent e)
428       {
429         cancel_actionPerformed();
430       }
431     });
432
433     Panel fontPanel = new Panel();
434     fontPanel.setLayout(new BorderLayout());
435     Panel stylePanel = new Panel();
436     stylePanel.setLayout(new BorderLayout());
437     Panel sizePanel = new Panel();
438     sizePanel.setLayout(new BorderLayout());
439     Panel scalePanel = new Panel();
440     scalePanel.setLayout(new BorderLayout());
441     Panel okCancelPanel = new Panel();
442     Panel optionsPanel = new Panel();
443
444     fontPanel.setBackground(Color.white);
445     stylePanel.setBackground(Color.white);
446     sizePanel.setBackground(Color.white);
447     okCancelPanel.setBackground(Color.white);
448     optionsPanel.setBackground(Color.white);
449
450     fontPanel.add(fontLabel, BorderLayout.WEST);
451     fontPanel.add(fontName, BorderLayout.CENTER);
452     stylePanel.add(styleLabel, BorderLayout.WEST);
453     stylePanel.add(fontStyle, BorderLayout.CENTER);
454     sizePanel.add(sizeLabel, BorderLayout.WEST);
455     sizePanel.add(fontSize, BorderLayout.CENTER);
456     scalePanel.add(scaleAsCdna, BorderLayout.NORTH);
457     scalePanel.add(fontAsCdna, BorderLayout.SOUTH);
458     okCancelPanel.add(ok, null);
459     okCancelPanel.add(cancel, null);
460
461     optionsPanel.add(fontPanel, null);
462     optionsPanel.add(sizePanel, null);
463     optionsPanel.add(stylePanel, null);
464
465     /*
466      * Only show 'scale protein as cDNA' in a SplitFrame
467      */
468     this.add(optionsPanel, BorderLayout.NORTH);
469     if (ap.alignFrame.getSplitFrame() != null)
470     {
471       inSplitFrame = true;
472       oldComplementFont = ((AlignViewport) ap.av.getCodingComplement())
473               .getFont();
474       this.add(scalePanel, BorderLayout.CENTER);
475     }
476     this.add(okCancelPanel, BorderLayout.SOUTH);
477   }
478
479   /**
480    * Turn on/off scaling of protein characters to 3 times the width of cDNA
481    * characters
482    */
483   protected void scaleAsCdna_actionPerformed()
484   {
485     ap.av.setScaleProteinAsCdna(scaleAsCdna.getState());
486     ap.av.getCodingComplement()
487             .setScaleProteinAsCdna(scaleAsCdna.getState());
488     changeFont();
489   }
490
491 }