
// Un JFrame représente une fenêtre ou un dialogue
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
// Un JPanel peut contenir des composants graphiques (boutons etc.)
import javax.swing.JPanel;
// JComponent est la classe de base des composants Swing
import javax.swing.JComponent;
// Un JLabel affiche une chaîne de caractères ou une icône
import javax.swing.JLabel;
// Un JButton est un bouton à cliquer ("OK", "Cancel" etc.)
import javax.swing.JButton;
// Un JFileChooser est un dialogue permettant de choisir un fichier
import javax.swing.JFileChooser;

/* Les classes AWT */

// Un Graphics est un environnement pour le rendu de primitives graphiques :
// tracé de lignes, cercles, rectangles, affichage de texte etc.
import java.awt.Graphics;
// Une Dimension représente les dimensions (hauteur et largeur) d'un composant
import java.awt.Dimension;
// Color représente une couleur, utilisable dans un Graphics
import java.awt.Color;
// BorderLayout est un gestionnaire de positionnement des composants dans un 
// conteneur. Il définit la position des composants par le bord du conteneur
// le long duquel ils s'alignent : North, South, East, West et Center.
import java.awt.BorderLayout;
// ActionListener est l'interface qu'il faut implémenter pour être prévenu
// lorsqu'une action est effectuée sur un composant (clic sur un bouton).
import java.awt.event.ActionListener;
// Un ActionEvent décrit une action sur un composant.
import java.awt.event.ActionEvent;

/**
 * Classe principale. Affiche une fenêtre Swing.
 */
public class SwingApp {
  /** 
   * La méthode main crée l'interface graphique de l'application
   * et la rend visible. 
   */
  public static void main(String[] args) {
    // Les éléments graphiques Swing doivent être créés et utilisés
    // dans le thread de traitement des événements de Swing. On utilise
    // la méthode invokeAndWait pour 
    try {
      SwingUtilities.invokeAndWait(new Runnable() {
        public void run() {
          new GUI("Hello").setVisible(true);
        }
      });
    } catch (Exception e) {
      System.err.println("Erreur à la création de l'interface Swing.");
      System.err.println(e);
    }
  }
}

/** 
 * Interface graphique de l'application.
 * C'est une fenêtre de niveau principal (JFrame).
 */
class GUI extends JFrame implements ActionListener {
  /** Affiche le nom du fichier choisi, centré au milieu du label. */
  private JLabel fname_ = null;
  
  public GUI(String name) {
    super(name);  // le nom de la fenêtre est l'argument du constructeur
    // la ligne suivante indique que l'application termine
    // lorsqu'on ferme cette fenêtre.
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    // On ne doit pas ajouter directement des composants à un JFrame.
    // Il faut les ajouter à son Content Pane. Ce conteneur utilise
    // par défaut un BorderLayout. On ajoute donc ici un composant
    // "Dummy" au centre de la fenêtre.
    getContentPane().add(new Dummy(), BorderLayout.CENTER);
    // On crée maintenant un conteneur (JPanel) qui utilise
    // un BorderLayout, et on l'ajoute au bas (Sud) de la fenêtre.
    JPanel p = new JPanel(new BorderLayout());
    getContentPane().add(p, BorderLayout.SOUTH);
    // On crée un bouton pour choisir un fichier
    JButton b = new JButton("Choose a file...");
    // On s'abonne aux clics sur ce bouton.
    // À chaque fois qu'on cliquera sur le bouton, notre
    //  méthode "actionPerformed" sera appelée.
    b.addActionListener(this);
    // On place ce bouton sur la gauche du panel (West)
    p.add(b, BorderLayout.WEST);
    // On place un label (qui affichera le nom du fichier choisi)
    // au centre du panel.
    fname_ = new JLabel("",JLabel.CENTER);
    p.add(fname_, BorderLayout.CENTER);
    // pack() effectue le placement des composants de la fenêtre 
    // et lui donne sa taille "préférée".
    pack();
  }
  
  /** Traite un événement (clic sur le bouton "Choose a file...") */
  public void actionPerformed(ActionEvent e) {
    // On crée le dialogue de sélection de fichier Swing
    JFileChooser jfc = new JFileChooser();
    // On affiche le dialogue d'ouverture de fichier. 
    // Ce dialogue est positionné à l'écran relativement 
    // à la fenêtre principale de notre interface graphique.
    switch(jfc.showOpenDialog(this)) {
      // L'utilisateur a cliqué sur "Annuler" ou "Cancel"
      case JFileChooser.CANCEL_OPTION:
        fname_.setText("Cancelled");
        break;
    
      // L'utilisateur a cliqué sur "Open" ou "Ouvrir"
      case JFileChooser.APPROVE_OPTION:
        fname_.setText(jfc.getSelectedFile().getName());
        break;
    
      // Une erreur s'est produite
      case JFileChooser.ERROR_OPTION:
        fname_.setText("Too bad!!!");
        break;
    
      // Ne devrait jamais se produire, mais il faut être prudent.
      default:
        fname_.setText("Unknown code");
    }
  }
  
}

/**
 * Un composant inutile, juste pour montrer comment ça se définit.
 */
class Dummy extends JComponent {
  public Dummy() {
    // Indique la taille préférée pour ce composant
    setPreferredSize(new Dimension(300,200));    
  }
  
  /** Détermine l'aspect graphique du composant. */
  public void paintComponent(Graphics g) {
    // Laisse la super classe gérer les comportements génériques
    super.paintComponent(g);
    // On crée un copie de l'environnement graphique car on n'a 
    // pas le droit de modifier celui que l'on reçoit.
    Graphics tmp = g.create();
    Dimension size = getSize();
    // On affiche la taille en pixel du composant au quart de sa 
    // largeur et à la moitié de sa hauteur.
    tmp.drawString("" + size.width + "x" + size.height, size.width/4, size.height/2);
    // On trace une ellipse en retrait d'un pixel à l'intérieur du composant
    tmp.drawOval(1,1,size.width-3, size.height-3);
    // On change la couleur de tracé en rouge
    tmp.setColor(Color.red);
    // et on trace un rectangle à l'intérieur du composant.
    // Noter le "-1" sur les dimensions.
    tmp.drawRect(0,0, size.width-1, size.height-1);
  }
}
