source: src/main/java/weka/gui/arffviewer/ArffPanel.java @ 17

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

Import di weka.

File size: 28.6 KB
RevLine 
[4]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 * ArffPanel.java
19 * Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui.arffviewer;
24
25import weka.core.Instances;
26import weka.core.Undoable;
27import weka.core.Utils;
28import weka.gui.ComponentHelper;
29import weka.gui.JTableHelper;
30import weka.gui.ListSelectorDialog;
31
32import java.awt.BorderLayout;
33import java.awt.Cursor;
34import java.awt.Toolkit;
35import java.awt.datatransfer.Clipboard;
36import java.awt.datatransfer.StringSelection;
37import java.awt.event.ActionEvent;
38import java.awt.event.ActionListener;
39import java.awt.event.MouseEvent;
40import java.awt.event.MouseListener;
41import java.io.File;
42import java.util.Collections;
43import java.util.HashSet;
44import java.util.Iterator;
45import java.util.Vector;
46
47import javax.swing.JLabel;
48import javax.swing.JList;
49import javax.swing.JMenuItem;
50import javax.swing.JOptionPane;
51import javax.swing.JPanel;
52import javax.swing.JPopupMenu;
53import javax.swing.JScrollPane;
54import javax.swing.event.ChangeEvent;
55import javax.swing.event.ChangeListener;
56import javax.swing.event.TableModelEvent;
57
58/**
59 * A Panel representing an ARFF-Table and the associated filename.
60 *
61 *
62 * @author FracPete (fracpete at waikato dot ac dot nz)
63 * @version $Revision: 4769 $
64 */
65
66public class ArffPanel 
67  extends JPanel
68  implements ActionListener, ChangeListener, MouseListener, Undoable {
69 
70  /** for serialization */
71  static final long serialVersionUID = -4697041150989513939L;
72 
73  /** the name of the tab for instances that were set directly */
74  public final static String TAB_INSTANCES = "Instances";
75
76  /** the underlying table */
77  private ArffTable m_TableArff;
78  /** the popup menu for the header row */
79  private JPopupMenu m_PopupHeader;
80  /** the popup menu for the data rows */
81  private JPopupMenu m_PopupRows;
82  /** displays the relation name */
83  private JLabel m_LabelName;
84 
85  // menu items
86  private JMenuItem             menuItemMean;
87  private JMenuItem             menuItemSetAllValues;
88  private JMenuItem             menuItemSetMissingValues;
89  private JMenuItem             menuItemReplaceValues;
90  private JMenuItem             menuItemRenameAttribute;
91  private JMenuItem             menuItemAttributeAsClass;
92  private JMenuItem             menuItemDeleteAttribute;
93  private JMenuItem             menuItemDeleteAttributes;
94  private JMenuItem             menuItemSortInstances;
95  private JMenuItem             menuItemDeleteSelectedInstance;
96  private JMenuItem             menuItemDeleteAllSelectedInstances;
97  private JMenuItem             menuItemSearch;
98  private JMenuItem             menuItemClearSearch;
99  private JMenuItem             menuItemUndo;
100  private JMenuItem             menuItemCopy;
101  private JMenuItem             menuItemOptimalColWidth;
102  private JMenuItem             menuItemOptimalColWidths;
103 
104  /** the filename used in the title */
105  private String m_Filename;
106  /** the title prefix */
107  private String m_Title;
108  /** the currently selected column */
109  private int m_CurrentCol;
110  /** flag for whether data got changed */
111  private boolean m_Changed;
112  /** the listeners that listen for modifications */
113  private HashSet m_ChangeListeners;
114  /** the string used in the last search */
115  private String m_LastSearch;
116  /** the string used in the last replace */
117  private String m_LastReplace;
118 
119  /**
120   * initializes the panel with no data
121   */
122  public ArffPanel() {
123    super();
124   
125    initialize();
126    createPanel();
127  }
128 
129  /**
130   * initializes the panel and loads the specified file
131   *
132   * @param filename    the file to load
133   */
134  public ArffPanel(String filename) {
135    this();
136   
137    loadFile(filename);
138  }
139 
140  /**
141   * initializes the panel with the given data
142   *
143   * @param data        the data to use
144   */
145  public ArffPanel(Instances data) {
146    this();
147   
148    m_Filename = "";
149   
150    setInstances(data);
151  }
152 
153  /**
154   * any member variables are initialized here
155   */
156  protected void initialize() {
157    m_Filename        = "";
158    m_Title           = "";
159    m_CurrentCol      = -1;
160    m_LastSearch      = "";
161    m_LastReplace     = "";
162    m_Changed         = false;
163    m_ChangeListeners = new HashSet();
164  }
165 
166  /**
167   * creates all the components in the frame
168   */
169  protected void createPanel() {
170    JScrollPane                pane;
171   
172    setLayout(new BorderLayout());
173   
174    menuItemMean = new JMenuItem("Get mean...");
175    menuItemMean.addActionListener(this);
176    menuItemSetAllValues = new JMenuItem("Set all values to...");
177    menuItemSetAllValues.addActionListener(this);
178    menuItemSetMissingValues = new JMenuItem("Set missing values to...");
179    menuItemSetMissingValues.addActionListener(this);
180    menuItemReplaceValues = new JMenuItem("Replace values with...");
181    menuItemReplaceValues.addActionListener(this);
182    menuItemRenameAttribute = new JMenuItem("Rename attribute...");
183    menuItemRenameAttribute.addActionListener(this);
184    menuItemAttributeAsClass = new JMenuItem("Attribute as class");
185    menuItemAttributeAsClass.addActionListener(this);
186    menuItemDeleteAttribute = new JMenuItem("Delete attribute");
187    menuItemDeleteAttribute.addActionListener(this);
188    menuItemDeleteAttributes = new JMenuItem("Delete attributes...");
189    menuItemDeleteAttributes.addActionListener(this);
190    menuItemSortInstances = new JMenuItem("Sort data (ascending)");
191    menuItemSortInstances.addActionListener(this);
192    menuItemOptimalColWidth = new JMenuItem("Optimal column width (current)");
193    menuItemOptimalColWidth.addActionListener(this);
194    menuItemOptimalColWidths = new JMenuItem("Optimal column width (all)");
195    menuItemOptimalColWidths.addActionListener(this);
196
197    // row popup
198    menuItemUndo = new JMenuItem("Undo");
199    menuItemUndo.addActionListener(this);
200    menuItemCopy = new JMenuItem("Copy");
201    menuItemCopy.addActionListener(this);
202    menuItemSearch = new JMenuItem("Search...");
203    menuItemSearch.addActionListener(this);
204    menuItemClearSearch = new JMenuItem("Clear search");
205    menuItemClearSearch.addActionListener(this);
206    menuItemDeleteSelectedInstance = new JMenuItem("Delete selected instance");
207    menuItemDeleteSelectedInstance.addActionListener(this);
208    menuItemDeleteAllSelectedInstances = new JMenuItem("Delete ALL selected instances");
209    menuItemDeleteAllSelectedInstances.addActionListener(this);
210   
211    // table
212    m_TableArff = new ArffTable();
213    m_TableArff.setToolTipText("Right click (or left+alt) for context menu");
214    m_TableArff.getTableHeader().addMouseListener(this);
215    m_TableArff.getTableHeader().setToolTipText("<html><b>Sort view:</b> left click = ascending / Shift + left click = descending<br><b>Menu:</b> right click (or left+alt)</html>");
216    m_TableArff.getTableHeader().setDefaultRenderer(new ArffTableCellRenderer());
217    m_TableArff.addChangeListener(this);
218    m_TableArff.addMouseListener(this);
219    pane = new JScrollPane(m_TableArff);
220    add(pane, BorderLayout.CENTER);
221   
222    // relation name
223    m_LabelName   = new JLabel();
224    add(m_LabelName, BorderLayout.NORTH);
225  }
226
227  /**
228   * initializes the popup menus
229   */
230  private void initPopupMenus() {
231    // header popup
232    m_PopupHeader  = new JPopupMenu();
233    m_PopupHeader.addMouseListener(this);
234    m_PopupHeader.add(menuItemMean);
235    if (!isReadOnly()) {
236      m_PopupHeader.addSeparator();
237      m_PopupHeader.add(menuItemSetAllValues);
238      m_PopupHeader.add(menuItemSetMissingValues);
239      m_PopupHeader.add(menuItemReplaceValues);
240      m_PopupHeader.addSeparator();
241      m_PopupHeader.add(menuItemRenameAttribute);
242      m_PopupHeader.add(menuItemAttributeAsClass);
243      m_PopupHeader.add(menuItemDeleteAttribute);
244      m_PopupHeader.add(menuItemDeleteAttributes);
245      m_PopupHeader.add(menuItemSortInstances);
246    }
247    m_PopupHeader.addSeparator();
248    m_PopupHeader.add(menuItemOptimalColWidth);
249    m_PopupHeader.add(menuItemOptimalColWidths);
250   
251    // row popup
252    m_PopupRows = new JPopupMenu();
253    m_PopupRows.addMouseListener(this);
254    if (!isReadOnly()) {
255      m_PopupRows.add(menuItemUndo);
256      m_PopupRows.addSeparator();
257    }
258    m_PopupRows.add(menuItemCopy);
259    m_PopupRows.addSeparator();
260    m_PopupRows.add(menuItemSearch);
261    m_PopupRows.add(menuItemClearSearch);
262    if (!isReadOnly()) {
263      m_PopupRows.addSeparator();
264      m_PopupRows.add(menuItemDeleteSelectedInstance);
265      m_PopupRows.add(menuItemDeleteAllSelectedInstances);
266    }
267  }
268 
269  /**
270   * sets the enabled/disabled state of the menu items
271   */
272  private void setMenu() {
273    boolean                     isNumeric;
274    boolean                     hasColumns;
275    boolean                     hasRows;
276    boolean                     attSelected;
277    ArffSortedTableModel        model;
278    boolean                     isNull;
279   
280    model       = (ArffSortedTableModel) m_TableArff.getModel();
281    isNull      = (model.getInstances() == null);
282    hasColumns  = !isNull && (model.getInstances().numAttributes() > 0);
283    hasRows     = !isNull && (model.getInstances().numInstances() > 0);
284    attSelected = hasColumns && (m_CurrentCol > 0);
285    isNumeric   = attSelected && (model.getAttributeAt(m_CurrentCol).isNumeric());
286   
287    menuItemUndo.setEnabled(canUndo());
288    menuItemCopy.setEnabled(true);
289    menuItemSearch.setEnabled(true);
290    menuItemClearSearch.setEnabled(true);
291    menuItemMean.setEnabled(isNumeric);
292    menuItemSetAllValues.setEnabled(attSelected);
293    menuItemSetMissingValues.setEnabled(attSelected);
294    menuItemReplaceValues.setEnabled(attSelected);
295    menuItemRenameAttribute.setEnabled(attSelected);
296    menuItemDeleteAttribute.setEnabled(attSelected);
297    menuItemDeleteAttributes.setEnabled(attSelected);
298    menuItemSortInstances.setEnabled(hasRows && attSelected);
299    menuItemDeleteSelectedInstance.setEnabled(hasRows && m_TableArff.getSelectedRow() > -1);
300    menuItemDeleteAllSelectedInstances.setEnabled(hasRows && (m_TableArff.getSelectedRows().length > 0));
301  }
302 
303  /**
304   * returns the table component
305   *
306   * @return            the table
307   */
308  public ArffTable getTable() {
309    return m_TableArff;
310  }
311 
312  /**
313   * returns the title for the Tab, i.e. the filename
314   *
315   * @return            the title for the tab
316   */
317  public String getTitle() {
318    return m_Title;
319  }
320 
321  /**
322   * returns the filename
323   *
324   * @return            the filename
325   */
326  public String getFilename() {
327    return m_Filename;
328  }
329 
330  /**
331   * sets the filename
332   *
333   * @param filename    the new filename
334   */
335  public void setFilename(String filename) {
336    m_Filename = filename;
337    createTitle();
338  }
339 
340  /**
341   * returns the instances of the panel, if none then NULL
342   *
343   * @return            the instances of the panel
344   */
345  public Instances getInstances() {
346    Instances            result;
347   
348    result = null;
349   
350    if (m_TableArff.getModel() != null)
351      result = ((ArffSortedTableModel) m_TableArff.getModel()).getInstances();
352   
353    return result;
354  }
355 
356  /**
357   * displays the given instances, i.e. creates a tab with the title
358   * TAB_INSTANCES. if one already exists it closes it.<br>
359   * if a different instances object is used here, don't forget to clear
360   * the undo-history by calling <code>clearUndo()</code>
361   *
362   * @param data        the instances to display
363   * @see               #TAB_INSTANCES
364   * @see               #clearUndo()
365   */
366  public void setInstances(Instances data) {
367    ArffSortedTableModel         model;
368   
369    m_Filename = TAB_INSTANCES;
370   
371    createTitle();
372    model = new ArffSortedTableModel(data);
373   
374    m_TableArff.setModel(model);
375    clearUndo();
376    setChanged(false);
377    createName();
378  }
379 
380  /**
381   * returns a list with the attributes
382   *
383   * @return            a list of the attributes
384   */
385  public Vector getAttributes() {
386    Vector               result;
387    int                  i;
388   
389    result = new Vector();
390    for (i = 0; i < getInstances().numAttributes(); i++)
391      result.add(getInstances().attribute(i).name());
392    Collections.sort(result);
393   
394    return result;
395  }
396 
397  /**
398   * can only reset the changed state to FALSE
399   *
400   * @param changed             if false, resets the changed state
401   */
402  public void setChanged(boolean changed) {
403    if (!changed) {
404      this.m_Changed = changed;
405      createTitle();
406    }
407  }
408 
409  /**
410   * returns whether the content of the panel was changed
411   *
412   * @return            true if the content was changed
413   */
414  public boolean isChanged() {
415    return m_Changed;
416  }
417
418  /**
419   * returns whether the model is read-only
420   *
421   * @return            true if model is read-only
422   */
423  public boolean isReadOnly() {
424    if (m_TableArff == null)
425      return true;
426    else
427      return ((ArffSortedTableModel) m_TableArff.getModel()).isReadOnly();
428  }
429 
430  /**
431   * sets whether the model is read-only
432   *
433   * @param value       if true the model is set to read-only
434   */
435  public void setReadOnly(boolean value) {
436    if (m_TableArff != null)
437      ((ArffSortedTableModel) m_TableArff.getModel()).setReadOnly(value);
438  }
439
440  /**
441   * returns whether undo support is enabled
442   *
443   * @return            true if undo is enabled
444   */
445  public boolean isUndoEnabled() {
446    return ((ArffSortedTableModel) m_TableArff.getModel()).isUndoEnabled();
447  }
448 
449  /**
450   * sets whether undo support is enabled
451   *
452   * @param enabled             whether to enable/disable undo support
453   */
454  public void setUndoEnabled(boolean enabled) {
455    ((ArffSortedTableModel) m_TableArff.getModel()).setUndoEnabled(enabled);
456  }
457 
458  /**
459   * removes the undo history
460   */
461  public void clearUndo() {
462    ((ArffSortedTableModel) m_TableArff.getModel()).clearUndo();
463  }
464 
465  /**
466   * returns whether an undo is possible
467   *
468   * @return            true if undo is possible
469   */
470  public boolean canUndo() {
471    return ((ArffSortedTableModel) m_TableArff.getModel()).canUndo();
472  }
473 
474  /**
475   * performs an undo action
476   */
477  public void undo() {
478    if (canUndo()) {
479      ((ArffSortedTableModel) m_TableArff.getModel()).undo();
480     
481      // notify about update
482      notifyListener();
483    }
484  }
485 
486  /**
487   * adds the current state of the instances to the undolist
488   */
489  public void addUndoPoint() {
490    ((ArffSortedTableModel) m_TableArff.getModel()).addUndoPoint();
491       
492    // update menu
493    setMenu();
494  }
495 
496  /**
497   * sets the title (i.e. filename)
498   */
499  private void createTitle() {
500    File              file;
501   
502    if (m_Filename.equals("")) {
503      m_Title = "-none-";
504    }
505    else if (m_Filename.equals(TAB_INSTANCES)) {
506      m_Title = TAB_INSTANCES;
507    }
508    else {
509      try {
510        file  = new File(m_Filename);
511        m_Title = file.getName();
512      }
513      catch (Exception e) {
514        m_Title = "-none-";
515      }
516    }
517   
518    if (isChanged())
519      m_Title += " *";
520  }
521 
522  /**
523   * sets the relation name
524   */
525  private void createName() {
526    ArffSortedTableModel         model;
527   
528    model = (ArffSortedTableModel) m_TableArff.getModel();
529    if ((model != null) && (model.getInstances() != null))
530      m_LabelName.setText("Relation: " + model.getInstances().relationName());
531    else
532      m_LabelName.setText("");
533  }
534 
535  /**
536   * loads the specified file into the table
537   *
538   * @param filename            the file to load
539   */
540  private void loadFile(String filename) {
541    ArffSortedTableModel         model;
542   
543    this.m_Filename = filename;
544   
545    createTitle();
546   
547    if (filename.equals(""))   
548      model = null;
549    else
550      model = new ArffSortedTableModel(filename);
551   
552    m_TableArff.setModel(model);
553    setChanged(false);
554    createName();
555  }
556 
557  /**
558   * calculates the mean of the given numeric column
559   */
560  private void calcMean() {
561    ArffSortedTableModel   model;
562    int               i;
563    double            mean;
564   
565    // no column selected?
566    if (m_CurrentCol == -1)
567      return;
568   
569    model = (ArffSortedTableModel) m_TableArff.getModel();
570   
571    // not numeric?
572    if (!model.getAttributeAt(m_CurrentCol).isNumeric())
573      return;
574   
575    mean = 0;
576    for (i = 0; i < model.getRowCount(); i++)
577      mean += model.getInstances().instance(i).value(m_CurrentCol - 1);
578    mean = mean / model.getRowCount();
579   
580    // show result
581    ComponentHelper.showMessageBox(
582        getParent(), 
583        "Mean for attribute...",
584        "Mean for attribute '" 
585        + m_TableArff.getPlainColumnName(m_CurrentCol) 
586        + "':\n\t" + Utils.doubleToString(mean, 3),
587        JOptionPane.OK_CANCEL_OPTION,
588        JOptionPane.PLAIN_MESSAGE);
589  }
590 
591  /**
592   * sets the specified values in a column to a new value
593   *
594   * @param o           the menu item
595   */
596  private void setValues(Object o) {
597    String                     msg;
598    String                     title;
599    String                     value;
600    String                     valueNew;
601    int                        i;
602    ArffSortedTableModel      model;
603   
604    value    = "";
605    valueNew = "";
606   
607    if (o == menuItemSetMissingValues) {
608      title = "Replace missing values..."; 
609      msg   = "New value for MISSING values";
610    }
611    else if (o == menuItemSetAllValues) {
612      title = "Set all values..."; 
613      msg   = "New value for ALL values";
614    }
615    else if (o == menuItemReplaceValues) {
616      title = "Replace values..."; 
617      msg   = "Old value";
618    }
619    else
620      return;
621   
622    value = ComponentHelper.showInputBox(m_TableArff.getParent(), title, msg, m_LastSearch);
623   
624    // cancelled?
625    if (value == null)
626      return;
627
628    m_LastSearch = value;
629   
630    // replacement
631    if (o == menuItemReplaceValues) {
632      valueNew = ComponentHelper.showInputBox(m_TableArff.getParent(), title, "New value", m_LastReplace);
633      if (valueNew == null)
634        return;
635      m_LastReplace = valueNew;
636    }
637   
638    model = (ArffSortedTableModel) m_TableArff.getModel();
639    model.setNotificationEnabled(false);
640
641    // undo
642    addUndoPoint();
643    model.setUndoEnabled(false);
644    String valueCopy = value;
645    // set value
646    for (i = 0; i < m_TableArff.getRowCount(); i++) {
647      if (o == menuItemSetAllValues) {
648        if (valueCopy.equals("NaN") || valueCopy.equals("?")) {
649          value = null;
650        }
651        model.setValueAt(value, i, m_CurrentCol);
652      }
653      else
654        if ( (o == menuItemSetMissingValues) 
655            && model.isMissingAt(i, m_CurrentCol) )
656          model.setValueAt(value, i, m_CurrentCol);
657        else if ( (o == menuItemReplaceValues) 
658            && model.getValueAt(i, m_CurrentCol).toString().equals(value) )
659          model.setValueAt(valueNew, i, m_CurrentCol);
660    }
661    model.setUndoEnabled(true);
662    model.setNotificationEnabled(true);
663    model.notifyListener(new TableModelEvent(model, 0, model.getRowCount(), m_CurrentCol, TableModelEvent.UPDATE));
664   
665    // refresh
666    m_TableArff.repaint();
667  }
668 
669  /**
670   * deletes the currently selected attribute
671   */
672  public void deleteAttribute() {
673    ArffSortedTableModel   model;
674   
675    // no column selected?
676    if (m_CurrentCol == -1)
677      return;
678   
679    model = (ArffSortedTableModel) m_TableArff.getModel();
680
681    // really an attribute column?
682    if (model.getAttributeAt(m_CurrentCol) == null)
683      return;
684   
685    // really?
686    if (ComponentHelper.showMessageBox(
687        getParent(), 
688        "Confirm...",
689        "Do you really want to delete the attribute '" 
690        + model.getAttributeAt(m_CurrentCol).name() + "'?",
691        JOptionPane.YES_NO_OPTION,
692        JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION)
693      return;
694   
695    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
696    model.deleteAttributeAt(m_CurrentCol);
697    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
698  }
699 
700  /**
701   * deletes the chosen attributes
702   */
703  public void deleteAttributes() {
704    ListSelectorDialog    dialog;
705    ArffSortedTableModel       model;
706    Object[]              atts;
707    int[]                 indices;
708    int                   i;
709    JList                 list;
710    int                   result;
711   
712    list   = new JList(getAttributes());
713    dialog = new ListSelectorDialog(null, list);
714    result = dialog.showDialog();
715   
716    if (result != ListSelectorDialog.APPROVE_OPTION)
717      return;
718   
719    atts = list.getSelectedValues();
720   
721    // really?
722    if (ComponentHelper.showMessageBox(
723        getParent(), 
724        "Confirm...",
725        "Do you really want to delete these " 
726        + atts.length + " attributes?",
727        JOptionPane.YES_NO_OPTION,
728        JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION)
729      return;
730   
731    model   = (ArffSortedTableModel) m_TableArff.getModel();
732    indices = new int[atts.length];
733    for (i = 0; i < atts.length; i++)
734      indices[i] = model.getAttributeColumn(atts[i].toString());
735   
736    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
737    model.deleteAttributes(indices);
738    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
739  }
740 
741  /**
742   * sets the current attribute as class attribute, i.e. it moves it to the end
743   * of the attributes
744   */
745  public void attributeAsClass() {
746    ArffSortedTableModel   model;
747   
748    // no column selected?
749    if (m_CurrentCol == -1)
750      return;
751   
752    model   = (ArffSortedTableModel) m_TableArff.getModel();
753
754    // really an attribute column?
755    if (model.getAttributeAt(m_CurrentCol) == null)
756      return;
757   
758    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
759    model.attributeAsClassAt(m_CurrentCol);
760    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
761  }
762 
763  /**
764   * renames the current attribute
765   */
766  public void renameAttribute() {
767    ArffSortedTableModel   model;
768    String            newName;
769   
770    // no column selected?
771    if (m_CurrentCol == -1)
772      return;
773   
774    model   = (ArffSortedTableModel) m_TableArff.getModel();
775
776    // really an attribute column?
777    if (model.getAttributeAt(m_CurrentCol) == null)
778      return;
779   
780    newName = ComponentHelper.showInputBox(getParent(), "Rename attribute...", "Enter new Attribute name", model.getAttributeAt(m_CurrentCol).name());
781    if (newName == null)
782      return;
783   
784    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
785    model.renameAttributeAt(m_CurrentCol, newName);
786    setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
787  }
788 
789  /**
790   * deletes the currently selected instance
791   */
792  public void deleteInstance() {
793    int               index;
794   
795    index = m_TableArff.getSelectedRow();
796    if (index == -1)
797      return;
798   
799    ((ArffSortedTableModel) m_TableArff.getModel()).deleteInstanceAt(index);
800  }
801 
802  /**
803   * deletes all the currently selected instances
804   */
805  public void deleteInstances() {
806    int[]             indices;
807   
808    if (m_TableArff.getSelectedRow() == -1)
809      return;
810   
811    indices = m_TableArff.getSelectedRows();
812    ((ArffSortedTableModel) m_TableArff.getModel()).deleteInstances(indices);
813  }
814 
815  /**
816   * sorts the instances via the currently selected column
817   */
818  public void sortInstances() {
819    if (m_CurrentCol == -1)
820      return;
821   
822    ((ArffSortedTableModel) m_TableArff.getModel()).sortInstances(m_CurrentCol);
823  }
824 
825  /**
826   * copies the content of the selection to the clipboard
827   */
828  public void copyContent() {
829    StringSelection      selection;
830    Clipboard            clipboard;
831   
832    selection = getTable().getStringSelection();
833    if (selection == null)
834      return;
835   
836    clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
837    clipboard.setContents(selection, selection);
838  }
839 
840  /**
841   * searches for a string in the cells
842   */
843  public void search() {
844    String              searchString;
845   
846    // display dialog
847    searchString = ComponentHelper.showInputBox(getParent(), "Search...", "Enter the string to search for", m_LastSearch);
848    if (searchString != null)
849      m_LastSearch = searchString;
850   
851    getTable().setSearchString(searchString);
852  }
853 
854  /**
855   * clears the search, i.e. resets the found cells
856   */
857  public void clearSearch() {
858    getTable().setSearchString("");
859  }
860 
861  /**
862   * calculates the optimal column width for the current column
863   */
864  public void setOptimalColWidth() {
865    // no column selected?
866    if (m_CurrentCol == -1)
867      return;
868
869    JTableHelper.setOptimalColumnWidth(getTable(), m_CurrentCol);
870  }
871 
872  /**
873   * calculates the optimal column widths for all columns
874   */
875  public void setOptimalColWidths() {
876    JTableHelper.setOptimalColumnWidth(getTable());
877  }
878 
879  /**
880   * invoked when an action occurs
881   *
882   * @param e           the action event
883   */
884  public void actionPerformed(ActionEvent e) {
885    Object          o;
886   
887    o = e.getSource();
888   
889    if (o == menuItemMean)
890      calcMean();
891    else if (o == menuItemSetAllValues)
892      setValues(menuItemSetAllValues);
893    else if (o == menuItemSetMissingValues)
894      setValues(menuItemSetMissingValues);
895    else if (o == menuItemReplaceValues)
896      setValues(menuItemReplaceValues);
897    else if (o == menuItemRenameAttribute)
898      renameAttribute();
899    else if (o == menuItemAttributeAsClass)
900      attributeAsClass();
901    else if (o == menuItemDeleteAttribute)
902      deleteAttribute();
903    else if (o == menuItemDeleteAttributes)
904      deleteAttributes();
905    else if (o == menuItemDeleteSelectedInstance)
906      deleteInstance();
907    else if (o == menuItemDeleteAllSelectedInstances)
908      deleteInstances();
909    else if (o == menuItemSortInstances)
910      sortInstances();
911    else if (o == menuItemSearch)
912      search();
913    else if (o == menuItemClearSearch)
914      clearSearch();
915    else if (o == menuItemUndo)
916      undo();
917    else if (o == menuItemCopy)
918      copyContent();
919    else if (o == menuItemOptimalColWidth)
920      setOptimalColWidth();
921    else if (o == menuItemOptimalColWidths)
922      setOptimalColWidths();
923  }
924 
925  /**
926   * Invoked when a mouse button has been pressed and released on a component
927   *
928   * @param e           the mouse event
929   */
930  public void mouseClicked(MouseEvent e) {
931    int         col;
932    boolean     popup;
933   
934    col   = m_TableArff.columnAtPoint(e.getPoint());
935    popup =    ((e.getButton() == MouseEvent.BUTTON3) && (e.getClickCount() == 1))
936            || ((e.getButton() == MouseEvent.BUTTON1) && (e.getClickCount() == 1) && e.isAltDown() && !e.isControlDown() && !e.isShiftDown());
937    popup = popup && (getInstances() != null);
938   
939    if (e.getSource() == m_TableArff.getTableHeader()) {
940      m_CurrentCol = col;
941     
942      // Popup-Menu
943      if (popup) {
944        e.consume();
945        setMenu();
946        initPopupMenus();
947        m_PopupHeader.show(e.getComponent(), e.getX(), e.getY());
948      }
949    }
950    else if (e.getSource() == m_TableArff) {
951      // Popup-Menu
952      if (popup) {
953        e.consume();
954        setMenu();
955        initPopupMenus();
956        m_PopupRows.show(e.getComponent(), e.getX(), e.getY());
957      }
958    }
959   
960    // highlihgt column
961    if (    (e.getButton() == MouseEvent.BUTTON1) 
962         && (e.getClickCount() == 1) 
963         && (!e.isAltDown())
964         && (col > -1) ) {
965      m_TableArff.setSelectedColumn(col);
966    }
967  }
968 
969  /**
970   * Invoked when the mouse enters a component.
971   *
972   * @param e           the mouse event
973   */
974  public void mouseEntered(MouseEvent e) {
975  }
976 
977  /**
978   * Invoked when the mouse exits a component
979   *
980   * @param e           the mouse event
981   */
982  public void mouseExited(MouseEvent e) {
983  }
984 
985  /**
986   * Invoked when a mouse button has been pressed on a component
987   *
988   * @param e           the mouse event
989   */
990  public void mousePressed(MouseEvent e) {
991  }
992 
993  /**
994   * Invoked when a mouse button has been released on a component.
995   *
996   * @param e           the mouse event
997   */
998  public void mouseReleased(MouseEvent e) {
999  }
1000 
1001  /**
1002   * Invoked when the target of the listener has changed its state.
1003   *
1004   * @param e           the change event
1005   */
1006  public void stateChanged(ChangeEvent e) {
1007    m_Changed = true;
1008    createTitle();
1009    notifyListener();
1010  }
1011 
1012  /**
1013   * notfies all listener of the change
1014   */
1015  public void notifyListener() {
1016    Iterator                iter;
1017   
1018    iter = m_ChangeListeners.iterator();
1019    while (iter.hasNext())
1020      ((ChangeListener) iter.next()).stateChanged(new ChangeEvent(this));
1021  }
1022 
1023  /**
1024   * Adds a ChangeListener to the panel
1025   *
1026   * @param l           the listener to add
1027   */
1028  public void addChangeListener(ChangeListener l) {
1029    m_ChangeListeners.add(l);
1030  }
1031 
1032  /**
1033   * Removes a ChangeListener from the panel
1034   *
1035   * @param l           the listener to remove
1036   */
1037  public void removeChangeListener(ChangeListener l) {
1038    m_ChangeListeners.remove(l);
1039  }
1040}
Note: See TracBrowser for help on using the repository browser.