All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.pdx.cs410J.family.FamilyTreeGUI Maven / Gradle / Ivy

There is a newer version: 2024.0.1
Show newest version
package edu.pdx.cs410J.family;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.swing.ButtonGroup;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

/**
 * This class is a graphical user interface that lets the user edit a
 * family tree.
 */
@SuppressWarnings("serial")
public class FamilyTreeGUI extends FamilyTreePanel {
  private File file;        // Where FamilyTree lives
  private boolean isDirty = false;  // Has the family tree been modified?

  // GUI components worth holding onto
  private JMenuItem saveItem;       // Disabled until we have a tree
  private JMenuItem saveAsItem;     // Disabled until we have a tree
  private JMenu personMenu;         // Disabled until a person is selected
  private JMenuItem motherItem;
  private JMenuItem fatherItem;
  private JFrame frame;             // Frame containing this GUI

  /**
   * Creates a new FamilyTreeGUI
   */
  public FamilyTreeGUI(String title) {
    // Implicit call to super class's constructor
    super.addComponents();

    // Create a JFrame
    this.frame = new JFrame(title);

    // Add the menus
    JMenuBar menuBar = new JMenuBar();
    this.frame.setJMenuBar(menuBar);
    this.addFileMenu(menuBar);
    this.addPersonMenu(menuBar);
    this.addPlafMenu(menuBar);

    // Add myself to the frame
    System.out.println("Adding this");
    this.frame.getContentPane().add(this);

    // Initially, we're not dirty
    this.setDirty(false);

    // Handle exit events
    this.frame.addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
          exit();
        }
      });

  }

  /**
   * Returns true if this GUI can be used to edit a
   * family tree.
   */
  boolean canEdit() {
    return true;
  }

  /**
   * Creates the File menu
   */
  private void addFileMenu(JMenuBar menuBar) {
    JMenu fileMenu = new JMenu("File");
    fileMenu.setMnemonic(KeyEvent.VK_F);
    menuBar.add(fileMenu);

    JMenuItem openItem = new JMenuItem("Open...", KeyEvent.VK_O);
    openItem.setAccelerator(KeyStroke.getKeyStroke(
                      KeyEvent.VK_O, ActionEvent.CTRL_MASK));
    openItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          open();
        }
      });
    fileMenu.add(openItem);
    
    this.saveItem = new JMenuItem("Save", KeyEvent.VK_S);
    saveItem.setAccelerator(KeyStroke.getKeyStroke(
                      KeyEvent.VK_S, ActionEvent.CTRL_MASK));
    saveItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          save();
        }
      });
    fileMenu.add(saveItem);
    
    this.saveAsItem = new JMenuItem("Save As...", KeyEvent.VK_A);
    saveAsItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          saveAs();
        }
      });
    fileMenu.add(saveAsItem);

    fileMenu.addSeparator();

    JMenuItem exitItem = new JMenuItem("Exit", KeyEvent.VK_X);
    exitItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          exit();
        }
      });
    fileMenu.add(exitItem);
  }

  /**
   * Creates the Person menu
   */
  private void addPersonMenu(JMenuBar menuBar) {
    this.personMenu = new JMenu("Person");
    personMenu.setMnemonic(KeyEvent.VK_P);
    personMenu.setEnabled(false);
    menuBar.add(personMenu);

    fatherItem = new JMenuItem("Father", KeyEvent.VK_F);
    fatherItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          displayFather();
        }
      });
    personMenu.add(fatherItem);
    
    motherItem = new JMenuItem("Mother", KeyEvent.VK_M);
    motherItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          displayMother();
        }
      });
    personMenu.add(motherItem);

    personMenu.addSeparator();

    JMenuItem editItem = new JMenuItem("Edit...", KeyEvent.VK_E);
    editItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          editPerson();
        }
      });
    personMenu.add(editItem);
    
    JMenuItem marriageItem = new JMenuItem("Add Marriage...",
                                           KeyEvent.VK_M);
    marriageItem.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          addMarriage();
        }
      });
    personMenu.add(marriageItem);
  }

  /**
   * Creates menu that allows the user to change the look and feel of
   * this FamilyTreeGUI.
   */
  private void addPlafMenu(JMenuBar menuBar) {
    JMenu plafMenu = new JMenu("Look & Feel");
    plafMenu.setMnemonic(KeyEvent.VK_L);
    menuBar.add(plafMenu);

    ButtonGroup bg = new ButtonGroup();

    UIManager.LookAndFeelInfo[] infos =
      UIManager.getInstalledLookAndFeels();
    for (int i = 0; i < infos.length; i++) {
      final UIManager.LookAndFeelInfo info = infos[i];

      JRadioButtonMenuItem plafItem;
      if (info.getName().equals(UIManager.getLookAndFeel().getName()))
        {
          plafItem = new JRadioButtonMenuItem(info.getName(), true);

        } else {
          plafItem = new JRadioButtonMenuItem(info.getName(), false);
        }

      plafItem.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            try {
              UIManager.setLookAndFeel(info.getClassName());
              SwingUtilities.updateComponentTreeUI(FamilyTreeGUI.this);
              FamilyTreeGUI.this.pack();

            } catch (Exception ex) {
              error(ex.toString());
              return;
            }
          }
        });

      bg.add(plafItem);
      plafMenu.add(plafItem);
    }
  }

  /**
   * Pops up a dialog box that notifies the user of a non-fatal
   * error. 
   */
  private void error(String message) {
    JOptionPane.showMessageDialog(this, new String[] {
      message},
                                   "An error has occurred",
                                   JOptionPane.ERROR_MESSAGE);
  }

  /**
   * Brings up a dialog box that edits the current Person
   */
  void editPerson() {
    Person person = this.treeList.getSelectedPerson();
    if (person == null) {
      return;
    }

    EditPersonDialog dialog = 
      new EditPersonDialog(person, this.getFrame(), this.tree);
    dialog.pack();
    dialog.setLocationRelativeTo(this);
    dialog.setVisible(true);

    person = dialog.getPerson();
    if (person != null) {
      // Assume some change was made
      this.setDirty(true);

      this.showPerson(person);
      this.treeList.fillInList(this.tree);
    }
  }

  /**
   * Sets the Person displayed in the GUI
   */
  void showPerson(Person person) {
    if (person == null) {
      this.personMenu.setEnabled(false);

    } else {
      this.personMenu.setEnabled(true);

      // Can we enable the Mother and Father menus?
      this.motherItem.setEnabled(person.getMother() != null);
      this.fatherItem.setEnabled(person.getFather() != null);
    }

    this.personPanel.showPerson(person);
  }

  /**
   * Brings up a dialog box for editing the a new Person
   */
  void newPerson() {
    EditPersonDialog dialog = 
      new EditPersonDialog(this.getFrame(), this.tree);
    dialog.pack();
    dialog.setLocationRelativeTo(this);
    dialog.setVisible(true);

    Person newPerson = dialog.getPerson();
    if (newPerson != null) {
      // A change was made
      this.setDirty(true);

      this.tree.addPerson(newPerson);
      this.treeList.fillInList(this.tree);
    }
  }

  /**
   * Brings up a dialog box for noting the current
   * Person's marriage.
   */
  void addMarriage() {
    Person person = this.treeList.getSelectedPerson();

    EditMarriageDialog dialog = 
      new EditMarriageDialog(person, this.getFrame(), this.tree);
    dialog.pack();
    dialog.setLocationRelativeTo(this);
    dialog.setVisible(true);
   
    Marriage newMarriage = dialog.getMarriage();
    if (newMarriage != null) {
      // A change was made and update person panel
      this.setDirty(true);
      this.showPerson(person);
    }
  }

  /**
   * Saves the family tree to a file
   */
  private void save() {
    if (this.file == null) {
      saveAs();
      return;
    }

//     System.out.println("Saving to an XML file");

    try {
      XmlDumper dumper = new XmlDumper(this.file);
      dumper.dump(this.tree);
      this.setDirty(false);

    } catch (IOException ex) {
      error("Error while saving family tree: " + ex);
    }

  }

  /**
   * Creates a JFileChooser suitable for dealing with
   * text files.
   */
  private JFileChooser getFileChooser() {
    JFileChooser chooser = new JFileChooser();
    if (this.file == null) {
      String cwd = System.getProperty("user.dir");
      chooser.setCurrentDirectory(new File(cwd));

    } else {
      chooser.setCurrentDirectory(this.file.getParentFile());
    }

    chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
        public boolean accept(File file) {
          if (file.isDirectory()) {
            return true;
          }

          String fileName = file.getName();
          return fileName.endsWith(".xml");
        }

        public String getDescription() {
          return "XML files (*.xml)";
        }
      });
    chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
    chooser.setMultiSelectionEnabled(false);

    return chooser;
  }

  /**
   * Displays a dialog box that allows the user to select an XML file
   * to save the family tree to.
   */
  private void saveAs() {
//     System.out.println("Saving as...");

    JFileChooser chooser = this.getFileChooser();
    chooser.setDialogTitle("Save As...");
    chooser.setDialogType(JFileChooser.SAVE_DIALOG);
    int response = chooser.showSaveDialog(this);

    if (response == JFileChooser.APPROVE_OPTION) {
      this.file = chooser.getSelectedFile();

      if (this.file.exists()) {
        response = 
          JOptionPane.showConfirmDialog(this, new String[] {
            "File " + this.file + " already exists.",
            "Do you want to overwrite it?"}, 
                                        "Overwrite file?",
                                        JOptionPane.YES_NO_OPTION,
                                        JOptionPane.QUESTION_MESSAGE);

        if (response == JOptionPane.NO_OPTION) {
          // Try it again...
          saveAs();
          return;      // Only save once
        }
      }

      save();
    }
  }

  /**
   * Pops open a dialog box for choosing an XML file
   */
  private void open() {
//     System.out.println("Opening an XML file");

    if (this.isDirty) {
      int response = 
        JOptionPane.showConfirmDialog(this, new String[] {
          "You have made changes to your family tree.",
          "Do you want to save them?"},
                                      "Confirm changes",
                                      JOptionPane.YES_NO_CANCEL_OPTION,
                                      JOptionPane.QUESTION_MESSAGE);
    
      if (response == JOptionPane.YES_OPTION) {
        save();

      } else if (response == JOptionPane.CANCEL_OPTION) {
        // Don't open new file, keep working with old
        return;
      }

      // Otherwise, discard changes and open new file
    }

    JFileChooser chooser = this.getFileChooser();
    chooser.setDialogTitle("Open text file");
    chooser.setDialogType(JFileChooser.OPEN_DIALOG);
    int response = chooser.showOpenDialog(this);

    if (response == JFileChooser.APPROVE_OPTION) {
      File file = chooser.getSelectedFile();
      FamilyTree tree = null;

      try {
        XmlParser parser = new XmlParser(file);
        tree = parser.parse();

      } catch (FileNotFoundException ex) {
        error(ex.toString());

      } catch (FamilyTreeException ex) {
        error(ex.toString());
      }


      if (tree != null) {
        // Everything is okay
        this.file = file;
        this.sourceLocation.setText(this.file.getName());
        this.tree = tree;
        this.setDirty(false);

        this.treeList.fillInList(this.tree);
        this.sourceLocation.setText(this.file.getPath());
      }
    }
  }

  /**
   * Called when the family tree changes dirtiness
   */
  void setDirty(boolean isDirty) {
    this.isDirty = isDirty;
    this.saveAsItem.setEnabled(isDirty);
    this.saveItem.setEnabled(isDirty);
  }

  /**
   * Returns the JFrame associated with this GUI.
   */
  JFrame getFrame() {
    return this.frame;
  }

  /**
   * If the family tree has been modified and not saved, prompt the
   * user to verify that he really wants to exit.
   */
  private void exit() {
    if (this.isDirty) {
      int response = 
        JOptionPane.showConfirmDialog(this, new String[] {
          "You have made changes to your family tree.",
          "Do you want to save them?"},
                                      "Confirm changes",
                                      JOptionPane.YES_NO_CANCEL_OPTION,
                                      JOptionPane.QUESTION_MESSAGE);
    
      if (response == JOptionPane.YES_OPTION) {
        save();
        System.exit(0);

      } else if (response == JOptionPane.NO_OPTION) {
        System.exit(0);
      }

      // Otherwise continue working
      
    } else {
      System.exit(0);
    }
  }

  /**
   * Overridden to pack the containing JFrame.
   */
  public void pack() {
    this.frame.pack();
  }

  /**
   * Overridden to set the visibility of the containing
   * JFrame.
   */
  public void setVisible(boolean isVisible) {
    this.frame.setVisible(isVisible);
  }

  /**
   * Creates a FamilyTreeGUI
   */
  public static void main(String[] args) {
    FamilyTreeGUI gui = new FamilyTreeGUI("Family Tree Program");
    gui.pack();
    gui.setVisible(true);
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy