/*
Datei............: Aufg2005.java
Projekt..........: Einführung in die Java-Programmierung
Erstellt.........: 07.12.97, Guido Krüger
Geändert.........: --
Aufgabe..........: Musterlösung zu Aufgabe 20.05
Kommentare.......:

Die Lösung zu dieser Aufgabe unterteilt sich in drei Klassen:

- Die Klasse Aufg2005 stellt den Programmrahmen dar und stellt das 
  Menü zur Fontauswahl und zum Beenden des Programms zur Verfügung.
- Die Klasse FontDialog implementiert den modelan Fontauswahldialog.
- Die Klasse FontPreviewCanvas stellt ein Dialogelement zur 
  Font-Vorschau zur Verfügung.

Weitere Details finden sich in den Dokumentationskommentaren zu den
einzelnen Klassen.
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class Aufg2005
extends Frame
implements ActionListener
{
  //Instanzmerkmale
  Font currentfont;

  public static void main(String[] args)
  {
	Aufg2005 wnd = new Aufg2005();
	wnd.setSize(400, 400);
	wnd.setVisible(true);
  }

  public Aufg2005()
  {
	super("Aufg2005");
	setBackground(Color.lightGray);
	//Menü erzeugen
	Menu menu = new Menu("Datei");
	MenuItem mi = new MenuItem("Fontauswahl");
	mi.setActionCommand("Fontauswahl");
	mi.addActionListener(this);
	menu.add(mi);
	menu.addSeparator();
	mi = new MenuItem("Beenden");
	mi.setActionCommand("DateiBeenden");
	mi.addActionListener(this);
	menu.add(mi);
	MenuBar mainmenu = new MenuBar();
	mainmenu.add(menu);
	setMenuBar(mainmenu);
	//WindowListener registrieren
	addWindowListener(
	  new WindowAdapter() {
        public void windowClosing(WindowEvent event) {
		  System.exit(0);
		}
	  }
    );
	//Standardfont erzeugen
	currentfont = new Font("Serif", Font.PLAIN, 24);
  }

  /**
   * Dispatcher für die Menüeinträge. Hier wird der Fontauswahldialog
   * aufgerufen und sein Rückgabewert verarbeitet.
   */
  public void actionPerformed(ActionEvent event)
  {
	String cmd = event.getActionCommand();
	if (cmd.equals("Fontauswahl")) {
	  FontDialog dlg = new FontDialog(this, currentfont);
	  dlg.setVisible(true);
	  Font returnfont = dlg.getCurrentFont();
	  if (returnfont != null) {
		currentfont = returnfont;
		repaint();
	  }
	} else if (cmd.equals("DateiBeenden")) {
	  System.exit(0);
	}
  }

  /**
   * Gibt unter Verwendung des aktuellen Fonts einen Teststring auf dem
   * Bildschirm aus.
   */
  public void paint(Graphics g)
  {
	int top = getInsets().top;
	int left = getInsets().left;
	g.setColor(Color.red);
	g.setFont(currentfont);
	FontMetrics fm = g.getFontMetrics();
	g.drawString("Dies ist ein Test", left + 10, top + 10 + fm.getAscent());
  }
}


/**
 * Diese Klasse stellt einen modalen Fontauswahldialog zur Verfügung. Dazu
 * ist ein Objekt dieser Klasse zu instanzieren und neben dem Ownerframe
 * der aktuelle Font zu übergeben. Nach Aufruf von setVisible(true) erlaubt
 * der Dialog das Einstellen der wichtigsten Fontparameter und bietet eine
 * Vorschau auf das zu erwartende Ergebnis. Nach Schließen des Dialogs kann
 * mit getCurrentFont auf den vom Anwender ausgewählten Font zugegriffen
 * werden. Falls der Dialog mit "Abbrechen" beendet wurde, liefert 
 * getCurrentFont den Wert null.
 */
class FontDialog
extends Dialog
{
  //Instanzmerkmale
  Font currentfont, returnfont;
  List fontlist, sizelist;
  FontPreviewCanvas previewcanvas;
  TextField previewtext;
  Checkbox boldbox;
  Checkbox italicbox;

  public FontDialog(Frame owner, Font font)
  {
	super(owner, true);
	currentfont = font;
	returnfont = null;
	setTitle("Fontauswahl");
	//WindowListener registrieren
	addWindowListener(
	  new WindowAdapter() {
        public void windowClosing(WindowEvent event) {
		  setVisible(false);
		  dispose();
		}
	  }
    );
	//Dialogelemente einfügen
	layoutDialog();
	setLocation(50, 50);
  }

  /**
   * Hier wird das Layout des Dialogs erstellt. Der Dialog besteht im 
   * wesentlichen aus zwei großen Panels, die in einem BorderLayout
   * übereinander liegen. Das oberere Panel enthält die beiden Listboxen
   * für den Namen und die Größe des Fonts sowie die Checkboxen für die
   * Attribute FETT und KURSIV und den Vorschautext. Das untere Panel
   * enthält den FontPreviewCanvas und die beiden Buttons. Teilweise
   * werden Subpanels verwendet, die ihre Dialogelemente über eigene
   * Layoutmanager anordnen.
   *
   * Die Klasse besitzt zwei Listener, die über lokale Klassen realisiert
   * wurden. Der erste ist für das Handling der Buttonereignisse zuständig,
   * der zweite implementiert die Interfaces ItemListener und TextListener
   * und reagiert auf alle Wertänderungen in den Dialogelementen. Wird 
   * einer der Fontparameter geändert, so sorgt die Methode updateCurrentFont
   * dafür, daß der aktuelle Font neu berechnet und das Vorschaufenster
   * aktualisiert wird. 
   */
  private void layoutDialog()
  {
	//ValueChangeListener instanzieren
	ValueChangeListener changelistener = new ValueChangeListener();
	//Panels erzeugen
	Panel p1 = new Panel();
	p1.setLayout(new BorderLayout());
	Panel p2 = new Panel();
	p2.setLayout(new BorderLayout());
	//Fontauswahlliste
	String FONTNAMES[] = {"Serif", "SansSerif", "MonoSpaced"};
	fontlist = new List();
	int selection = 0;
	for (int i = 0; i < FONTNAMES.length; ++i) {
	  fontlist.addItem(FONTNAMES[i]);
	  if (FONTNAMES[i].equals(currentfont.getName())) {
		selection = i;
	  }
	}
	fontlist.select(selection);
	fontlist.addItemListener(changelistener);
	p1.add("West", fontlist);
	//Größenauswahlliste
	int FONTSIZES[] = {6, 8, 10, 11, 12, 14, 18, 24, 36, 48, 72};
	sizelist = new List();
	selection = 0;
	for (int i = 0; i < FONTSIZES.length; ++i) {
	  sizelist.addItem("" + FONTSIZES[i]);
	  if (FONTSIZES[i] == currentfont.getSize()) {
		selection = i;
	  }
	}
	sizelist.select(selection);
	sizelist.addItemListener(changelistener);
	p1.add("Center", sizelist);
	//Checkboxen für Fontattribute
	Panel patt = new Panel();
	patt.setLayout(new BorderLayout(0, 0));
	boldbox = new Checkbox("Fett");
	boldbox.addItemListener(changelistener);
	if (currentfont.isBold()) {
	  boldbox.setState(true);
	}
	patt.add("North", boldbox);
	italicbox = new Checkbox("Kursiv");
	italicbox.addItemListener(changelistener);
	if (currentfont.isItalic()) {
	  boldbox.setState(true);
	}
	patt.add("Center", italicbox);
	p1.add("East", patt);
	//PreviewText
	previewtext = new TextField("Vorschautext", 40);
	previewtext.addTextListener(changelistener);
	p1.add("South", previewtext);
	//PreviewCanvas
	previewcanvas = new FontPreviewCanvas(currentfont, previewtext.getText());
	p2.add("North", previewcanvas);
	//Buttons
	ActionListener listener = new ButtonActionListener();
	Panel pbut = new Panel();
	pbut.setLayout(new FlowLayout(FlowLayout.CENTER));
	Button button;
	button = new Button("Abbrechen");
	button.addActionListener(listener);
	pbut.add(button);
	button = new Button("OK");
	button.addActionListener(listener);
	pbut.add(button);
	p2.add("South", pbut);
	//Panels einfügen
	setLayout(new BorderLayout());
	add("North", p1);
	add("South", p2);
	pack();
	updateCurrentFont();
  }

  /**
   * Listener für Buttonereignisse.
   */
  class ButtonActionListener
  implements ActionListener
  {
	public void actionPerformed(ActionEvent event)
	{
	  String cmd = event.getActionCommand();
	  if (cmd.equals("OK")) {
		returnfont = currentfont;
		setVisible(false);
		dispose();
	  } else if (cmd.equals("Abbrechen")) {
		setVisible(false);
		dispose();
	  }
	}
  }

  /**
   * Listener für alle Arten von Wertänderungen in den fontbestimmenden
   * Dialogelementen.
   */
  class ValueChangeListener
  implements ItemListener, TextListener
  {
	public void itemStateChanged(ItemEvent event)
	{
	  updateCurrentFont();
	}

	public void textValueChanged(TextEvent event) 
	{
	  updateCurrentFont();
	}
  }

  /**
   * Erezeugt ein neues aktuelles Fontobjekt aus den Werten der 
   * fontbestimmenden  Dialogelemente.
   */
  private void updateCurrentFont()
  {
	//Previewfont erzeugen
	String fontname = fontlist.getSelectedItem();
	int fontsize = Integer.parseInt(sizelist.getSelectedItem());
	int fontatts = Font.PLAIN;
	if (boldbox.getState()) {
	  fontatts |= Font.BOLD;
	}
	if (italicbox.getState()) {
	  fontatts |= Font.ITALIC;
	}
	currentfont = new Font(fontname, fontatts, fontsize);
	//PreviewCanvas updaten
	previewcanvas.setPreviewText(previewtext.getText());
	previewcanvas.setPreviewFont(currentfont);
  }

  /**
   * Diese Methode kann vom Aufrufer dazu verwendet werden, den Rückgabewert 
   * des Fontdialogs abzufragen. Sie liefert den aktuellen Font, wenn der 
   * Dialog mit dem OK-Button beendet wurde und null in allen anderen Fällen.
   */
  public Font getCurrentFont()
  {
	return returnfont;
  }
}

/**
 * Diese Klasse stellt ein Dialogelement zur Fontansicht zur Verfügung.
 * Sie wird mit zwei Parametern, einem Font- und einem Stringobjekt
 * instanziert und kann an beliebiger Stelle innerhalb eines Dialogs
 * verwendet werden. Ihre Aufgabe besteht darin, den angegeben Text in 
 * dem angegebenen Font in einem umrandeten Fenster auf grauem Grund
 * auszugeben. Mit Hilfe der Methoden setPreviewText und setPreviewFont
 * können sowohl Font als auch Vorschautext verändert werden.
 *
 * Die Implementierung dieses Dialogelements entspricht dem in Kapitel 23
 * vorgestellten Verfahren. Die Klasse überlagert die Methoden 
 * getMinimumSize und getPreferredSize, um ihre Größe bekanntzugeben
 * und stellt in paint die gewünschte Ausgabe zur Verfügung. 
 * Interaktionsmöglichkeiten des Anwenders gibt es hier nicht.
 */
class FontPreviewCanvas
extends Canvas
{
  //Instanzmerkmale
  Font previewfont;
  String previewtext;

  public FontPreviewCanvas(Font previewfont, String previewtext)
  {
	this.previewfont = previewfont;
	this.previewtext = previewtext;
	setBackground(Color.lightGray);
  }

  public Dimension getPreferredSize()
  {
	return new Dimension(400, 100);
  }

  public Dimension getMinimumSize()
  {
	return new Dimension(150, 50);
  }

  public void paint(Graphics g)
  {
	int width = getSize().width;
	int height = getSize().height;
	g.setColor(Color.black);
	g.setFont(previewfont);
	g.drawRect(0, 0, width - 1, height - 1);
	FontMetrics fm = g.getFontMetrics();
	int strwidth = fm.stringWidth(previewtext);
	int strheight = fm.getHeight();
	int strleft = strwidth < width ? (width - strwidth) / 2 : 0;
	int strtop = strheight < height ? (height - strheight) / 2: 0;
	strtop += fm.getAscent();
	g.drawString(previewtext, strleft, strtop);
  }

  public void setPreviewFont(Font previewfont)
  {
	this.previewfont = previewfont;
	repaint();
  }

  public void setPreviewText(String previewtext)
  {
	this.previewtext = previewtext;
	repaint();
  }
}

