001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: PathEditor.java,v $
023   Revision 1.9  2004/05/31 07:52:10  markl
024   partial rewrite to fix some usability problems
025
026   Revision 1.8  2004/03/16 06:43:39  markl
027   LocaleManager method change
028
029   Revision 1.7  2003/01/19 09:46:48  markl
030   replaced JScrollPane instances with KScrollPane.
031
032   Revision 1.6  2001/03/20 00:54:53  markl
033   Fixed deprecated calls.
034
035   Revision 1.5  2001/03/12 09:27:59  markl
036   Source code and Javadoc cleanup.
037
038   Revision 1.4  1999/11/15 03:36:13  markl
039   API fix.
040
041   Revision 1.3  1999/06/28 09:37:13  markl
042   I18N.
043
044   Revision 1.2  1999/01/10 02:56:27  markl
045   added GPL header & RCS tag
046   ----------------------------------------------------------------------------
047*/
048
049package kiwi.ui;
050
051import java.awt.*;
052import java.awt.event.*;
053import java.io.*;
054import java.util.*;
055import javax.swing.*;
056import javax.swing.border.*;
057import javax.swing.table.*;
058import javax.swing.event.*;
059
060import kiwi.ui.model.*;
061import kiwi.ui.dialog.*;
062import kiwi.util.*;
063
064/** This class represents a component for editing a path (a list of
065  * directories). It could be used for editing a binary search path, or a
066  * Java classpath, for example. It provides <i>New</i>, <i>Delete</i>,
067  * <i>Move Up</i>, and <i>Move Down</i> buttons.
068  *
069  * <p><center>
070  * <img src="snapshot/PathEditor.gif"><br>
071  * <i>An example PathEditor.</i>
072  * </center>
073  *
074  * @author Mark Lindner
075  */
076
077public class PathEditor extends KPanel implements ActionListener,
078                                       ListSelectionListener
079  {
080  private JTable paths;
081  private KButton b_delete, b_up, b_down, b_new;
082  private DefaultTableModel tmodel;
083  private PathListCellEditor cellEditor;
084  private ListSelectionModel sel;
085  private LocaleData loc, loc2;
086
087  /** Construct a new <code>PathEditor</code>. */
088
089  public PathEditor()
090    {
091    setBackground(SystemColor.control);
092    setLayout(new BorderLayout(5, 5));
093
094    KPanel panel1 = new KPanel();
095    panel1.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
096
097    JToolBar toolBar = new JToolBar();
098    toolBar.setOpaque(false);
099    toolBar.setFloatable(false);
100
101    ResourceManager rm = KiwiUtils.getResourceManager();
102    LocaleManager lm = LocaleManager.getDefault();
103    
104    loc = lm.getLocaleData("KiwiDialogs");
105    loc2 = lm.getLocaleData("KiwiMisc");
106    
107    b_new = new KButton(rm.getIcon("item-new.gif"));
108    b_new.addActionListener(this);
109    b_new.setToolTipText(loc.getMessage("kiwi.tooltip.new"));
110    toolBar.add(b_new);
111
112    b_delete = new KButton(rm.getIcon("delete.gif"));
113    b_delete.addActionListener(this);
114    b_delete.setToolTipText(loc.getMessage("kiwi.tooltip.delete"));
115    b_delete.setEnabled(false);
116    toolBar.add(b_delete);
117
118    b_up = new KButton(rm.getIcon("item-up.gif"));
119    b_up.addActionListener(this);
120    b_up.setToolTipText(loc.getMessage("kiwi.tooltip.move_up"));
121    b_up.setEnabled(false);
122    toolBar.add(b_up);
123
124    b_down = new KButton(rm.getIcon("item-down.gif"));
125    b_down.addActionListener(this);
126    b_down.setToolTipText(loc.getMessage("kiwi.tooltip.move_down"));
127    b_down.setEnabled(false);
128    toolBar.add(b_down);
129
130    panel1.add(toolBar);
131    
132    add("North", panel1);
133
134    String[] data = {};
135    paths = new KTable();
136    paths.setRowHeight(20);
137    tmodel = new DefaultTableModel();
138    paths.setModel(tmodel);
139    // paths.setTableHeader(null);
140    paths.setAutoCreateColumnsFromModel(false);
141    paths.setColumnSelectionAllowed(false);
142    paths.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
143    paths.setShowGrid(false);
144    sel = paths.getSelectionModel();
145    sel.addListSelectionListener(this);
146    Vector v = new Vector();
147
148    cellEditor = new PathListCellEditor();
149
150    cellEditor.addActionListener(this);
151
152    tmodel.addColumn(loc.getMessage("kiwi.label.directory_list"));
153    TableColumn col;
154
155    paths.addColumn(col = new TableColumn(0, 100));
156    col.setCellEditor(cellEditor);
157
158    for(int i = 0; i < data.length; i++)
159      tmodel.addRow(new Object[] { data[i] });
160
161    KScrollPane scrollPane = new KScrollPane(paths);
162    scrollPane.setBorder(new BevelBorder(BevelBorder.LOWERED));
163    scrollPane.setBackground(Color.white);
164    scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants
165                                          .VERTICAL_SCROLLBAR_ALWAYS);
166    scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants
167                                            .HORIZONTAL_SCROLLBAR_NEVER);
168    scrollPane.addComponentListener(new ComponentAdapter()
169      {
170      public void componentResized(ComponentEvent ev)
171        {
172        if(paths.isEditing())
173          paths.getCellEditor().cancelCellEditing();
174        
175        KScrollPane sp = (KScrollPane)ev.getComponent();
176        Dimension sz = sp.getViewport().getSize();
177        paths.setSize(sz);
178        }
179      });
180
181    add("Center", scrollPane);
182
183    setSize(400, 400);
184    }
185
186  /** Handle events. This method is public as an implementation side-effect. */
187
188  public void actionPerformed(ActionEvent evt)
189    {
190    Object o = evt.getSource();
191    boolean editing = paths.isEditing();
192
193    if(o == b_new && !editing)
194      {
195      int i = paths.getRowCount();
196      tmodel.addRow(new Object[] {""}); // root path???
197      sel.setSelectionInterval(i, i);
198      paths.editCellAt(i, 0);
199      }
200    else if(o == b_delete && !editing)
201      {
202      int i = paths.getSelectedRow();
203
204      System.out.println("selected row: " + i);
205      
206      if(i < 0)
207        return;
208      if(sel.isSelectionEmpty())
209        return;
210
211      tmodel.removeRow(i);
212      if(i >= paths.getRowCount())
213        i = 0;
214      
215      sel.setSelectionInterval(i, i);
216      }
217    else if(o == b_up && !editing)
218      {
219      int i = paths.getSelectedRow();
220      if(i < 1)
221        return;
222
223      tmodel.moveRow(i, i, i - 1);
224      sel.setSelectionInterval(i - 1, i - 1);
225      }
226    else if(o == b_down && !editing)
227      {
228      int i = paths.getSelectedRow();
229      if(i < 0 || i > (paths.getRowCount() - 2))
230        return;
231
232      tmodel.moveRow(i, i, i + 1);
233      sel.setSelectionInterval(i + 1, i + 1);
234      }
235    }
236
237  /** Return an array of the paths currently displayed by this view.
238    */
239  
240  public DirectoryPath getDirectoryPath()
241    {
242    int c = tmodel.getRowCount();
243    String[] paths = new String[c];
244    for(int i = 0; i < c; i++)
245      paths[i] = (String)tmodel.getValueAt(i, 0);
246
247    return(new DirectoryPath(paths));
248    }
249
250  /** Set the list of paths to be displayed by this view.
251    */
252
253  public void setDirectoryPath(DirectoryPath path)
254    {
255    String dirs[] = path.getDirectories();
256    
257    tmodel.setNumRows(0);
258    for(int i = 0; i < dirs.length; i++)
259      tmodel.addRow(new Object[] { dirs[i] });
260    }
261  
262  /* the custom cell editor */
263
264  private class PathListCellEditor extends AbstractCellEditor
265    implements TableCellEditor, ActionListener
266    {
267    private KPanel jp;
268    private JTextField text;
269    private JButton b_browse;
270    private Vector alisteners;
271    private int row = -1;
272    private KFileChooserDialog d_select = null;
273    private Frame parentFrame;
274
275    PathListCellEditor()
276      {
277      jp = new KPanel();
278      jp.setLayout(new BorderLayout(2, 2));
279
280      text = new JTextField();
281      text.addActionListener(this);
282      jp.add("Center", text);
283
284      b_browse = new KButton(loc.getMessage("kiwi.button.browse") + "...");
285      b_browse.setMargin(new Insets(0, 2, 0, 2));
286      b_browse.addActionListener(this);
287      jp.add("East", b_browse);
288
289      alisteners = new Vector();
290      }
291
292    public Component getTableCellEditorComponent(JTable table, Object value,
293                                                 boolean isSelected,
294                                                 int columnID, int rowIndex)
295      {
296      text.setText((String)value);
297      return(jp);
298      }
299
300    public Object getCellEditorValue()
301      {
302      return(text.getText());
303      }
304
305    public boolean isCellEditable(EventObject ev)
306      {
307      boolean ok = false;
308
309      if(ev == null)
310        {
311        text.requestFocus();
312        return(true);
313        }
314
315      MouseEvent mev = (MouseEvent)ev;
316      int newrow = ((JTable)mev.getSource())
317        .rowAtPoint(new Point(mev.getX(), mev.getY()));
318
319      if(newrow == row)
320        {
321        text.requestFocus();
322        ok = true;
323        }
324      else
325        row = newrow;
326
327      return(ok);
328      }
329
330    public boolean shouldSelectCell(EventObject evt)
331      {
332//      text.requestFocus();
333      return(true);
334      }
335
336    public boolean stopCellEditing()
337      {
338      // if input is valid...
339      fireEditingStopped();
340      return(true);
341      }
342
343    public void cancelCellEditing()
344      {
345      fireEditingCanceled();
346      }
347
348    public void addActionListener(ActionListener l)
349      {
350      alisteners.addElement(l);
351      }
352
353    public void removeActionListener(ActionListener l)
354      {
355      alisteners.removeElement(l);
356      }
357
358    public void actionPerformed(ActionEvent evt)
359      {
360      Object o = evt.getSource();
361
362      if(o == text)
363        {
364        // if input is valid...
365        fireEditingStopped();
366        }
367      else if(o == b_browse)
368        {
369        if(d_select == null)
370          {
371          d_select = new KFileChooserDialog(KiwiUtils.getPhantomFrame(),
372                                            "Directory Selection",
373                                            KFileChooser.OPEN_DIALOG);
374
375          d_select.setFileSelectionMode(KFileChooser.DIRECTORIES_ONLY);
376          }
377        KiwiUtils.centerWindow(d_select);
378        d_select.setVisible(true);
379        if(!d_select.isCancelled())
380          {
381          String p = d_select.getSelectedFile().getAbsolutePath();
382          if(p != null)
383            {
384            text.setText(p);
385            fireEditingStopped();
386            }
387          }
388        }
389      }
390    }
391
392  public void valueChanged(ListSelectionEvent evt)
393    {
394    boolean empty = sel.isSelectionEmpty();
395
396    b_up.setEnabled(! empty);
397    b_down.setEnabled(! empty);
398    b_delete.setEnabled(! empty);
399    }
400
401  }
402
403/* end of source file */