source: src/main/java/weka/gui/SetInstancesPanel.java @ 24

Last change on this file since 24 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 12.5 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 *    SetInstancesPanel.java
19 *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui;
24
25import weka.core.Instances;
26import weka.core.converters.ConverterUtils;
27import weka.core.converters.FileSourcedConverter;
28import weka.core.converters.IncrementalConverter;
29import weka.core.converters.URLSourcedLoader;
30
31import java.awt.BorderLayout;
32import java.awt.FlowLayout;
33import java.awt.GridLayout;
34import java.awt.event.ActionEvent;
35import java.awt.event.ActionListener;
36import java.beans.PropertyChangeListener;
37import java.beans.PropertyChangeSupport;
38import java.io.File;
39import java.net.URL;
40
41import javax.swing.BorderFactory;
42import javax.swing.JButton;
43import javax.swing.JFileChooser;
44import javax.swing.JFrame;
45import javax.swing.JOptionPane;
46import javax.swing.JPanel;
47
48/**
49 * A panel that displays an instance summary for a set of instances and
50 * lets the user open a set of instances from either a file or URL.
51 *
52 * Instances may be obtained either in a batch or incremental fashion.
53 * If incremental reading is used, then
54 * the client should obtain the Loader object (by calling
55 * getLoader()) and read the instances one at a time. If
56 * batch loading is used, then SetInstancesPanel will load
57 * the data into memory inside of a separate thread and notify
58 * the client when the operation is complete. The client can
59 * then retrieve the instances by calling getInstances().
60 *
61 * @author Len Trigg (trigg@cs.waikato.ac.nz)
62 * @version $Revision: 5298 $
63 */
64public class SetInstancesPanel
65  extends JPanel {
66
67  /** for serialization */
68  private static final long serialVersionUID = -384804041420453735L;
69 
70  /** Click to open instances from a file */
71  protected JButton m_OpenFileBut = new JButton("Open file...");
72
73  /** Click to open instances from a URL */
74  protected JButton m_OpenURLBut = new JButton("Open URL...");
75
76  /** Click to close the dialog */
77  protected JButton m_CloseBut = new JButton("Close");
78
79  /** The instance summary component */
80  protected InstancesSummaryPanel m_Summary = new InstancesSummaryPanel();
81
82  /** The file chooser for selecting arff files */
83  protected ConverterFileChooser m_FileChooser
84    = new ConverterFileChooser(new File(System.getProperty("user.dir")));
85
86  /** Stores the last URL that instances were loaded from */
87  protected String m_LastURL = "http://";
88
89  /** The thread we do loading in */
90  protected Thread m_IOThread;
91
92  /**
93   * Manages sending notifications to people when we change the set of
94   * working instances.
95   */
96  protected PropertyChangeSupport m_Support = new PropertyChangeSupport(this);
97
98  /** The current set of instances loaded */
99  protected Instances m_Instances;
100
101  /** The current loader used to obtain the current instances */
102  protected weka.core.converters.Loader m_Loader;
103 
104  /** the parent frame. if one is provided, the close-button is displayed */
105  protected JFrame m_ParentFrame = null;
106
107  /** the panel the Close-Button is located in */
108  protected JPanel m_CloseButPanel = null;
109
110  protected boolean m_readIncrementally = true;
111 
112  protected boolean m_showZeroInstancesAsUnknown = false;
113 
114  public SetInstancesPanel() {
115    this(false);
116  }
117 
118  /**
119   * Create the panel.
120   */
121  public SetInstancesPanel(boolean showZeroInstancesAsUnknown) {
122    m_showZeroInstancesAsUnknown = showZeroInstancesAsUnknown;
123   
124    m_OpenFileBut.setToolTipText("Open a set of instances from a file");
125    m_OpenURLBut.setToolTipText("Open a set of instances from a URL");
126    m_CloseBut.setToolTipText("Closes the dialog");
127    m_FileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
128    m_OpenURLBut.addActionListener(new ActionListener() {
129      public void actionPerformed(ActionEvent e) {
130        setInstancesFromURLQ();
131      }
132    });
133    m_OpenFileBut.addActionListener(new ActionListener() {
134      public void actionPerformed(ActionEvent e) {
135        setInstancesFromFileQ();
136      }
137    });
138    m_CloseBut.addActionListener(new ActionListener() {
139      public void actionPerformed(ActionEvent e) {
140        closeFrame();
141      }
142    });
143    m_Summary.setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 10));
144
145    JPanel buttons = new JPanel();
146    buttons.setLayout(new GridLayout(1, 2));
147    buttons.add(m_OpenFileBut);
148    buttons.add(m_OpenURLBut);
149   
150    m_CloseButPanel = new JPanel();
151    m_CloseButPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
152    m_CloseButPanel.add(m_CloseBut);
153    m_CloseButPanel.setVisible(false);
154   
155    JPanel buttonsAll = new JPanel();
156    buttonsAll.setLayout(new BorderLayout());
157    buttonsAll.add(buttons, BorderLayout.CENTER);
158    buttonsAll.add(m_CloseButPanel, BorderLayout.SOUTH);
159   
160    setLayout(new BorderLayout());
161    add(m_Summary, BorderLayout.CENTER);
162    add(buttonsAll, BorderLayout.SOUTH);
163  }
164
165  /**
166   * Sets the frame, this panel resides in. Used for displaying the close
167   * button, i.e., the close-button is visible if the given frame is not null.
168   * @param parent        the parent frame
169   */
170  public void setParentFrame(JFrame parent) {
171    m_ParentFrame = parent;
172    m_CloseButPanel.setVisible(m_ParentFrame != null);
173  }
174 
175  /**
176   * Returns the current frame the panel knows of, that it resides in. Can be
177   * null.
178   * @return the current parent frame
179   */
180  public JFrame getParentFrame() {
181    return m_ParentFrame;
182  }
183
184  /**
185   * closes the frame, i.e., the visibility is set to false
186   */
187  public void closeFrame() {
188    if (m_ParentFrame != null)
189      m_ParentFrame.setVisible(false);
190  }
191
192  /**
193   * Queries the user for a file to load instances from, then loads the
194   * instances in a background process. This is done in the IO
195   * thread, and an error message is popped up if the IO thread is busy.
196   */
197  public void setInstancesFromFileQ() {
198   
199    if (m_IOThread == null) {
200      int returnVal = m_FileChooser.showOpenDialog(this);
201      if (returnVal == JFileChooser.APPROVE_OPTION) {
202        final File selected = m_FileChooser.getSelectedFile();
203        m_IOThread = new Thread() {
204          public void run() {
205            setInstancesFromFile(selected);
206            m_IOThread = null;
207          }
208        };
209        m_IOThread.setPriority(Thread.MIN_PRIORITY); // UI has most priority
210        m_IOThread.start();
211      }
212    } else {
213      JOptionPane.showMessageDialog(this,
214                                    "Can't load at this time,\n"
215                                    + "currently busy with other IO",
216                                    "Load Instances",
217                                    JOptionPane.WARNING_MESSAGE);
218    }
219  }
220   
221  /**
222   * Queries the user for a URL to load instances from, then loads the
223   * instances in a background process. This is done in the IO
224   * thread, and an error message is popped up if the IO thread is busy.
225   */
226  public void setInstancesFromURLQ() {
227   
228    if (m_IOThread == null) {
229      try {
230        String urlName = (String) JOptionPane.showInputDialog(this,
231                        "Enter the source URL",
232                        "Load Instances",
233                        JOptionPane.QUESTION_MESSAGE,
234                        null,
235                        null,
236                        m_LastURL);
237        if (urlName != null) {
238          m_LastURL = urlName;
239          final URL url = new URL(urlName);
240          m_IOThread = new Thread() {
241            public void run() {
242              setInstancesFromURL(url);
243              m_IOThread = null;
244            }
245          };
246          m_IOThread.setPriority(Thread.MIN_PRIORITY); // UI has most priority
247          m_IOThread.start();
248        }
249      } catch (Exception ex) {
250        JOptionPane.showMessageDialog(this,
251                                      "Problem with URL:\n"
252                                      + ex.getMessage(),
253                                      "Load Instances",
254                                      JOptionPane.ERROR_MESSAGE);
255      }
256    } else {
257      JOptionPane.showMessageDialog(this,
258                                    "Can't load at this time,\n"
259                                    + "currently busy with other IO",
260                                    "Load Instances",
261                                    JOptionPane.WARNING_MESSAGE);
262    }
263  }
264 
265
266  /**
267   * Loads results from a set of instances contained in the supplied
268   * file.
269   *
270   * @param f a value of type 'File'
271   */
272  protected void setInstancesFromFile(File f) {
273    boolean incremental = m_readIncrementally;
274   
275    try {
276      m_Loader = ConverterUtils.getLoaderForFile(f);
277      if (m_Loader == null)
278        throw new Exception("No suitable FileSourcedConverter found for file!\n" + f);
279     
280      // not an incremental loader?
281      if (!(m_Loader instanceof IncrementalConverter))
282        incremental = false;
283
284      // load
285      ((FileSourcedConverter) m_Loader).setFile(f);
286      if (incremental) {
287        m_Summary.setShowZeroInstancesAsUnknown(m_showZeroInstancesAsUnknown);
288        setInstances(m_Loader.getStructure());
289      } else {
290        // If we are batch loading then we will know for sure that
291        // the data has no instances
292        m_Summary.setShowZeroInstancesAsUnknown(false);
293        setInstances(m_Loader.getDataSet());
294      }
295    } catch (Exception ex) {
296      JOptionPane.showMessageDialog(this,
297                                    "Couldn't read from file:\n"
298                                    + f.getName(),
299                                    "Load Instances",
300                                    JOptionPane.ERROR_MESSAGE);
301    }
302  }
303
304  /**
305   * Loads instances from a URL.
306   *
307   * @param u the URL to load from.
308   */
309  protected void setInstancesFromURL(URL u) {
310    boolean incremental = m_readIncrementally;
311   
312    try {
313      m_Loader = ConverterUtils.getURLLoaderForFile(u.toString());
314      if (m_Loader == null)
315        throw new Exception("No suitable URLSourcedLoader found for URL!\n" + u);
316     
317      // not an incremental loader?
318      if (!(m_Loader instanceof IncrementalConverter))
319        incremental = false;
320
321      // load
322      ((URLSourcedLoader) m_Loader).setURL(u.toString());
323      if (incremental) {
324        m_Summary.setShowZeroInstancesAsUnknown(m_showZeroInstancesAsUnknown);
325        setInstances(m_Loader.getStructure());
326      } else {
327        m_Summary.setShowZeroInstancesAsUnknown(false);
328        setInstances(m_Loader.getDataSet());
329      }
330    } catch (Exception ex) {
331      JOptionPane.showMessageDialog(this,
332                                    "Couldn't read from URL:\n"
333                                    + u,
334                                    "Load Instances",
335                                    JOptionPane.ERROR_MESSAGE);
336    }
337  }
338
339  /**
340   * Updates the set of instances that is currently held by the panel
341   *
342   * @param i a value of type 'Instances'
343   */
344  public void setInstances(Instances i) {
345
346    m_Instances = i;
347    m_Summary.setInstances(m_Instances);
348    // Fire property change event for those interested.
349    m_Support.firePropertyChange("", null, null);
350  }
351
352  /**
353   * Gets the set of instances currently held by the panel
354   *
355   * @return a value of type 'Instances'
356   */
357  public Instances getInstances() {
358   
359    return m_Instances;
360  }
361
362  /**
363   * Gets the currently used Loader
364   *
365   * @return a value of type 'Loader'
366   */
367  public weka.core.converters.Loader getLoader() {
368    return m_Loader;
369  }
370
371  /**
372   * Gets the instances summary panel associated with
373   * this panel
374   * @return the instances summary panel
375   */
376  public InstancesSummaryPanel getSummary() {
377    return m_Summary;
378  }
379
380  /**
381   * Sets whether or not instances should be read incrementally
382   * by the Loader. If incremental reading is used, then
383   * the client should obtain the Loader object (by calling
384   * getLoader()) and read the instances one at a time. If
385   * batch loading is used, then SetInstancesPanel will load
386   * the data into memory inside of a separate thread and notify
387   * the client when the operation is complete. The client can
388   * then retrieve the instances by calling getInstances().
389   *
390   * @param incremental true if instances are to be read incrementally
391   *
392   */
393  public void setReadIncrementally(boolean incremental) {
394    m_readIncrementally = incremental;
395  }
396
397  /**
398   * Gets whether instances are to be read incrementally or not
399   *
400   * @return true if instances are to be read incrementally
401   */
402  public boolean getReadIncrementally() {
403    return m_readIncrementally;
404  }
405 
406  /**
407   * Adds a PropertyChangeListener who will be notified of value changes.
408   *
409   * @param l a value of type 'PropertyChangeListener'
410   */
411  public void addPropertyChangeListener(PropertyChangeListener l) {
412    m_Support.addPropertyChangeListener(l);
413  }
414
415  /**
416   * Removes a PropertyChangeListener.
417   *
418   * @param l a value of type 'PropertyChangeListener'
419   */
420  public void removePropertyChangeListener(PropertyChangeListener l) {
421    m_Support.removePropertyChangeListener(l);
422  }
423}
Note: See TracBrowser for help on using the repository browser.