001package edu.pdx.cs410J.family;
002
003import java.awt.*;
004import java.awt.event.*;
005
006import java.net.*;
007
008import java.io.*;
009import javax.swing.*;
010import javax.swing.border.*;
011import javax.swing.event.*;
012
013/**
014 * This class is a <code>JPanel</code> that can be used to display a
015 * family tree. 
016 */
017@SuppressWarnings("serial")
018public class FamilyTreePanel extends JPanel {
019  protected FamilyTree tree = new FamilyTree();
020
021  // GUI components worth holding onto
022  protected JLabel sourceLocation;
023  protected FamilyTreeList treeList;
024  protected PersonPanel personPanel;
025
026  /**
027   * Creates a new <code>FamilyTreePanel</code>
028   */
029  public FamilyTreePanel() {
030    this.addComponents();
031  }
032
033  /**
034   * Adds the GUI components to a <code>FamilyTreePanel</code>
035   */
036  void addComponents() {
037    System.out.println("Creating Panel");
038
039    // Set up the content
040    Dimension minSizeLeft = new Dimension(50, 100);
041    this.treeList = new FamilyTreeList();
042    this.treeList.setToolTipText("Click to select a person in the " +
043                                 "family tree");
044    this.treeList.addListSelectionListener(new ListSelectionListener()
045      {
046        public void valueChanged(ListSelectionEvent e) {
047          Person person =
048            FamilyTreePanel.this.treeList.getSelectedPerson();
049          showPerson(person);
050        }
051      });
052    this.treeList.setMinimumSize(minSizeLeft);
053    JScrollPane scrollPane = new JScrollPane(this.treeList);
054    scrollPane.setMinimumSize(minSizeLeft);
055    
056    JPanel newPersonPanel = null;
057    if (this.canEdit()) {
058      newPersonPanel = new JPanel();
059      newPersonPanel.setLayout(new BoxLayout(newPersonPanel,
060                                             BoxLayout.X_AXIS));
061      newPersonPanel.add(Box.createHorizontalGlue());
062      JButton newPersonButton = new JButton("New Person");
063      newPersonButton.setToolTipText("Creates a new person");
064      newPersonButton.setMnemonic(KeyEvent.VK_N);
065      newPersonButton.addActionListener(new ActionListener() {
066          public void actionPerformed(ActionEvent e) {
067            newPerson();
068          }
069        });
070      newPersonPanel.add(newPersonButton);
071      newPersonPanel.add(Box.createHorizontalGlue());
072    }
073
074    JPanel treePanel = new JPanel();
075    treePanel.setLayout(new BorderLayout());
076    treePanel.add(scrollPane, BorderLayout.CENTER);
077    if (this.canEdit()) {
078      treePanel.add(newPersonPanel, BorderLayout.SOUTH);
079    }
080
081    this.personPanel = new PersonPanel(this);
082
083    JSplitPane splitPane = 
084      new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treePanel, this.personPanel);
085
086    this.setLayout(new BorderLayout());
087    this.add(splitPane, BorderLayout.CENTER);
088
089    JPanel sourcePanel = new JPanel();
090    sourcePanel.setLayout(new BoxLayout(sourcePanel, BoxLayout.X_AXIS));
091    this.sourceLocation = new JLabel();
092    this.sourceLocation.setToolTipText("Location of XML file");
093    sourcePanel.add(this.sourceLocation);
094    sourcePanel.add(Box.createHorizontalGlue());
095    
096    Border sourceBorder = BorderFactory.createEmptyBorder(2, 2, 2, 2);
097    sourcePanel.setBorder(sourceBorder);
098    
099    this.add(sourcePanel, BorderLayout.SOUTH);
100  }
101
102  /**
103   * Sets the text displayed in the source location label.
104   */
105  void setSourceText(String text) {
106    this.sourceLocation.setText(text);
107  }
108
109  /**
110   * Returns <code>true</code> if this GUI can be used to edit a person.
111   */
112  boolean canEdit() {
113    return false;
114  }
115
116  /**
117   * Sets the <code>Person</code> displayed in the GUI
118   */
119  void showPerson(Person person) {
120    this.personPanel.showPerson(person);
121  }
122
123  /**
124   * Displays the current <code>Person</code>'s mother
125   */
126  void displayMother() {
127    Person person = this.treeList.getSelectedPerson();
128    if (person != null) {
129      this.treeList.setSelectedPerson(person.getMother());
130    }
131  }
132
133  /**
134   * Displays the current <code>Person</code>'s father
135   */
136  void displayFather() {
137    Person person = this.treeList.getSelectedPerson();
138    if (person != null) {
139      this.treeList.setSelectedPerson(person.getFather());
140    }
141  }
142
143  /**
144   * Returns the <code>FamilyTree</code> being edited.
145   */
146  FamilyTree getFamilyTree() {
147    return this.tree;
148  }
149
150  /**
151   * Called when the family tree changes dirtiness.  Has no effect
152   * with the panel.
153   */
154  void setDirty(boolean isDirty) {
155
156  }
157
158  /**
159   * Called when a new person is to be created.  Has no effect with
160   * the panel.
161   */
162  void newPerson() {
163
164  }
165
166  /**
167   * Called when a person is to be edited.  No effect with the panel.
168   */
169  void editPerson() {
170
171  }
172
173  /**
174   * Called when a marriage is added.  No effect with the panel.
175   */
176  void addMarriage() {
177
178  }
179
180  /**
181   * Returns the <code>JFrame</code> associated with this GUI.
182   * Returns <code>null</code> for the panel.
183   */
184  JFrame getFrame() {
185    return null;
186  }
187
188  /**
189   * Sets the source of the XML file displayed in this GUI
190   */
191  protected void setURLSource(URL url) {
192    try {
193      this.tree = parseSource(url);
194
195    } catch (IOException ex) {
196      System.out.println("source = " + this.sourceLocation + ": " + ex);
197      this.sourceLocation.setText(ex.toString());
198      return;
199
200    } catch (FamilyTreeException ex) {
201      this.sourceLocation.setText(ex.toString());
202      return;
203    }
204
205    this.treeList.fillInList(this.tree);
206    this.sourceLocation.setText(url.toExternalForm());
207  }
208
209  /**
210   * Parses a <code>URL</code> and tries to extract a family tree in
211   * XML format from it.
212   */ 
213  protected FamilyTree parseSource(URL url) 
214    throws IOException, FamilyTreeException { 
215    
216    InputStream stream = url.openStream();
217
218    XmlParser parser = new XmlParser(new InputStreamReader(stream));
219    return parser.parse();
220  }
221
222  /**
223   * Creates a <code>FamilyTreePanel</code> that is displayed inside
224   * a <code>JFrame</code>
225   */
226  public static void main(String[] args) {
227    if (args.length < 1) {
228      System.err.println("** No URL Specified!!");
229      System.exit(1);
230    }
231
232    URL url = null;
233    try {
234      url = new URL(args[0]);
235
236    } catch (MalformedURLException ex) {
237      System.err.println(ex.toString());
238      System.exit(1);
239    }
240
241    FamilyTreePanel viewer = new FamilyTreePanel();
242    viewer.setURLSource(url);
243    
244
245    JFrame frame = new JFrame("Family Tree Panel");
246    frame.getContentPane().add(viewer);
247
248    frame.addWindowListener(new WindowAdapter() {
249        public void windowClosing(WindowEvent e) {
250          System.exit(0);
251        }
252      });
253
254    frame.pack();
255    frame.setVisible(true);
256  }
257
258}