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