*** empty log message ***
[cyberduck.git] / source / ch / cyberduck / ui / ListPanel.java
blobdb992fe07afc9c8ce26b850bc22cfe565e398f43
1 package ch.cyberduck.ui;
3 /*
4 * ch.cyberduck.ui.ListPanel.java
5 * Cyberduck
7 * $Header$
8 * $Revision$
9 * $Date$
11 * Copyright (c) 2003 David Kocher. All rights reserved.
12 * http://icu.unizh.ch/~dkocher/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * Bug fixes, suggestions and comments should be sent to:
25 * dkocher@cyberduck.ch
28 import javax.swing.*;
29 import javax.swing.event.ListSelectionEvent;
30 import javax.swing.event.ListSelectionListener;
31 import java.awt.*;
32 import java.awt.event.*;
33 import java.util.Observable;
34 import java.util.Observer;
35 import java.util.Vector;
37 import ch.cyberduck.Cyberduck;
38 import ch.cyberduck.CyberduckMenu;
39 import ch.cyberduck.Preferences;
40 import ch.cyberduck.connection.Bookmark;
41 import ch.cyberduck.connection.Path;
42 import ch.cyberduck.connection.TransferAction;
43 import ch.cyberduck.ui.action.ActionMap;
44 import ch.cyberduck.ui.common.GUIFactory;
45 import ch.cyberduck.ui.model.ListTableModel;
47 /**
48 * @version $Id$
50 public class ListPanel extends JPanel implements Observer {
52 private ListTable listingTable;
53 private ListTableModel listingTableModel;
55 /**
56 * The currently selected bookmark
58 private Bookmark selected;
60 private JScrollPane pane;
61 private JComboBox comboBox;
62 private ComboPathModel comboModel;
63 private ActionListener comboActionListener;
64 private ItemListener comboItemListener;
66 private Action backAction;
67 private Action upAction;
68 private Action refreshAction;
69 private Action newDirectoryAction;
70 private Action renameAction;
71 private Action deleteAction;
72 private Action downloadAction;
73 private Action permissionAction;
74 private Action abortAction;
75 private Action disconnectAction;
77 public ListPanel() {
78 super();
79 this.init();
82 public void update(Observable o, Object arg) {
83 this.listingTable.update(o, arg);
84 if(arg.equals(Bookmark.SELECTION) || arg.equals(Bookmark.LIST)) {
85 this.selected = (Bookmark)o;
86 boolean valid = false;
88 valid = selected.isValid();
89 valid = selected.getProtocol().equals(ch.cyberduck.connection.Session.FTP);
90 valid = selected.isListing() && selected.getListing() != null;
92 backAction.setEnabled(valid);
93 upAction.setEnabled(valid);
94 refreshAction.setEnabled(valid);
95 newDirectoryAction.setEnabled(valid);
96 abortAction.setEnabled(valid);
97 disconnectAction.setEnabled(valid);
99 downloadAction.setEnabled(false);
100 renameAction.setEnabled(false);
101 deleteAction.setEnabled(false);
102 permissionAction.setEnabled(false);
104 if(selected.isListing()) {
105 Path cwd = selected.getCurrentPath();
106 if(cwd != null) {
107 //@workaround because changing the model of JComboBox fires the ActionListener
108 this.comboBox.removeItemListener(comboItemListener);
109 this.comboModel.removeAll();
110 int depth = cwd.getPathDepth();
111 for(int i = 0; i <= depth; i++) {
112 this.comboModel.addElement(cwd.getPathFragment(i));
114 // selected the last added item
115 this.comboModel.setSelectedItem(comboModel.getElementAt(comboModel.getSize()-1));
116 this.comboBox.addItemListener(comboItemListener);
122 public Dimension getPreferredSize() {
123 Cyberduck.DEBUG("[ListPanel] getMinimumSize()");
124 return listingTable.getPreferredScrollableViewportSize();
128 public Dimension getMinimumSize() {
129 Dimension d = new Dimension(listingTable.getPreferredScrollableViewportSize().width, 300);
130 Cyberduck.DEBUG("[ListPanel] getMinimumSize():" + d.toString());
131 return d;
136 * Initialize the graphical user interface; the table and associated TableModel
138 private void init() {
139 Cyberduck.DEBUG("[ListPanel] init()");
140 listingTable = new ListTable();
141 listingTableModel = (ListTableModel)listingTable.getModel();
142 this.setLayout(new BorderLayout());
144 backAction = new BackAction();
145 upAction = new UpAction();
146 refreshAction = new RefreshAction();
147 abortAction = new AbortAction();
148 downloadAction = new ListingDownloadAction();
149 newDirectoryAction = new NewDirectoryAction();
150 renameAction = new RenameAction();
151 deleteAction = new DeleteAction();
152 permissionAction = new PermissionAction();
153 disconnectAction = new DisconnectAction();
155 this.updateFtpMenu();
157 ListSelectionModel selectionModel = listingTable.getSelectionModel();
158 selectionModel.addListSelectionListener(new ListSelectionListener() {
159 public void valueChanged(ListSelectionEvent e) {
160 if(!e.getValueIsAdjusting()) {
161 //Cyberduck.DEBUG(e.paramString());
162 ListSelectionModel lsm = (ListSelectionModel)e.getSource();
163 boolean selection = !(lsm.isSelectionEmpty());
165 downloadAction.setEnabled(selection);
166 renameAction.setEnabled(selection);
167 deleteAction.setEnabled(selection);
168 permissionAction.setEnabled(selection);
170 updateFtpMenu();
176 //table
177 pane = new JScrollPane(listingTable);
178 pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
179 pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
182 final javax.swing.JPopupMenu popupMenu = new javax.swing.JPopupMenu();
183 popupMenu.add(downloadAction);
184 popupMenu.addSeparator();
185 popupMenu.add(newDirectoryAction);
186 popupMenu.add(renameAction);
187 popupMenu.add(deleteAction);
188 popupMenu.add(permissionAction);
190 listingTable.addMouseListener(new java.awt.event.MouseAdapter() {
191 public void mousePressed(java.awt.event.MouseEvent e) {
192 maybeShowPopup(e);
194 public void mouseReleased(java.awt.event.MouseEvent e) {
195 maybeShowPopup(e);
197 private void maybeShowPopup(java.awt.event.MouseEvent e) {
198 if (e.isPopupTrigger()) {
199 popupMenu.show(e.getComponent(), e.getX(), e.getY());
206 this.add(new NavigationPanel(), BorderLayout.NORTH);
207 this.add(pane, BorderLayout.CENTER);
208 this.add(new ButtonPanel(), BorderLayout.SOUTH);
211 private void updateFtpMenu() {
212 final JMenuItem[] ftpMenuItems = {
213 CyberduckMenu.instance().menuItemBuilder(newDirectoryAction),
214 CyberduckMenu.instance().menuItemBuilder(renameAction),
215 CyberduckMenu.instance().menuItemBuilder(deleteAction),
216 CyberduckMenu.instance().menuItemBuilder(permissionAction),
217 //null,
218 CyberduckMenu.instance().menuItemBuilder(disconnectAction)
221 JMenu ftpMenu = CyberduckMenu.instance().getMenu(CyberduckMenu.FTP_MENU);
222 ftpMenu.removeAll();
223 for(int i = 0; i < ftpMenuItems.length; i++) {
224 ftpMenu.add(ftpMenuItems[i]);
228 private class ButtonPanel extends JPanel {
229 public ButtonPanel() {
230 super();
231 this.setLayout(new FlowLayout(FlowLayout.LEFT));
232 JButton downloadButton = GUIFactory.buttonBuilder(GUIFactory.FONT_SMALL, downloadAction);
233 downloadButton.setIcon(new ImageIcon("ToolBarUI"));
234 JButton newDirectoryButton = GUIFactory.buttonBuilder(GUIFactory.FONT_SMALL, newDirectoryAction);
235 newDirectoryButton.setIcon(new ImageIcon("ToolBarUI"));
236 JButton renameButton = GUIFactory.buttonBuilder(GUIFactory.FONT_SMALL, renameAction);
237 renameButton.setIcon(new ImageIcon("ToolBarUI"));
238 JButton deleteButton = GUIFactory.buttonBuilder(GUIFactory.FONT_SMALL, deleteAction);
239 deleteButton.setIcon(new ImageIcon("ToolBarUI"));
240 JButton permissionButton = GUIFactory.buttonBuilder(GUIFactory.FONT_SMALL, permissionAction);
241 permissionButton.setIcon(new ImageIcon("ToolBarUI"));
242 JButton disconnectButton = GUIFactory.buttonBuilder(GUIFactory.FONT_SMALL, disconnectAction);
243 disconnectButton.setIcon(new ImageIcon("ToolBarUI"));
245 this.add(downloadButton);
246 this.add(newDirectoryButton);
247 this.add(renameButton);
248 this.add(deleteButton);
249 this.add(permissionButton);
250 this.add(disconnectButton);
254 private class NavigationPanel extends JPanel {
255 public NavigationPanel() {
256 super();
257 this.setLayout(new FlowLayout(FlowLayout.LEFT));
258 this.add(GUIFactory.buttonBuilder(backAction));
259 this.add(GUIFactory.buttonBuilder(upAction));
260 this.add(GUIFactory.buttonBuilder(refreshAction));
261 //directory selection
262 comboBox = new JComboBox();
263 comboBox.setEditable(false);
264 comboBox.setModel(comboModel = new ComboPathModel());
265 comboBox.setRenderer(new ComboPathRenderer());
266 comboBox.addItemListener(comboItemListener = new ItemListener() {
267 public void itemStateChanged(ItemEvent e) {
268 if(e.getStateChange() == ItemEvent.SELECTED) {
269 Cyberduck.DEBUG(e.paramString());
270 Path p = (Path)e.getItem();
271 selected.transfer(new TransferAction(TransferAction.LIST, p));
276 this.add(comboBox);
277 this.add(GUIFactory.buttonBuilder(abortAction));
281 // ************************************************************************************************************
283 private class ComboPathRenderer extends DefaultListCellRenderer {
284 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
285 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
286 if(value instanceof Path) {
287 Path p = (Path)value;
288 if(p.getPathDepth() > 0) {
289 this.setIcon(new IndentIcon(GUIFactory.FOLDER_ICON, p.getPathDepth()));
290 this.setText(p.getName());
292 else {
293 this.setIcon(new IndentIcon(GUIFactory.HARDDRIVE_ICON, p.getPathDepth()));
294 this.setText(selected.getHost());
297 return this;
301 private class IndentIcon implements Icon {
302 Icon icon = null;
303 int depth = 0;
305 public IndentIcon(Icon i, int d) {
306 icon = i;
307 depth = d;
309 public void paintIcon(Component c, Graphics g, int x, int y) {
310 if(icon!=null)
311 icon.paintIcon(c, g, 10 + x + depth * 10, y);
313 public int getIconWidth() {
314 return 10 + depth * 10 + (icon != null ? icon.getIconWidth() : 0);
316 public int getIconHeight() {
317 return (icon != null ? icon.getIconHeight() : 1);
321 // ************************************************************************************************************
323 private class ComboPathModel extends AbstractListModel implements MutableComboBoxModel {
324 Object selected = null;
325 Vector paths = new Vector();
327 public int getSize() {
328 return paths.size();
331 public void addElement(Object o) {
332 // Cyberduck.DEBUG("[ComboPathModel] addElement(" + o + ")");
333 paths.add(o);
334 // this.fireIntervalAdded(this, this.getSize() - 1, this.getSize() - 1);
336 public void insertElementAt(Object o, int index) {
337 Cyberduck.DEBUG("[ComboPathModel] insertElementAt(" + o + "," + index + ")");
338 paths.add(index, o);
339 this.fireIntervalAdded(this, index, index);
341 public void removeElement(Object o) {
342 Cyberduck.DEBUG("[ComboPathModel] removeElement(" + o + ")");
343 paths.removeElement(o);
344 this.fireContentsChanged(this, 0, this.getSize());
346 public void removeElementAt(int index) {
347 Cyberduck.DEBUG("[ComboPathModel] removeElementAt(" + index + ")");
348 paths.removeElementAt(index);
349 this.fireIntervalRemoved(this, index, index);
351 public void removeAll() {
352 paths.clear();
353 this.fireContentsChanged(this, 0, this.getSize());
355 public boolean isEmpty() {
356 return paths.isEmpty();
358 public Object getElementAt(int index) {
359 // Cyberduck.DEBUG("[ComboPathModel] getElementAt(" + index + ")");
360 return paths.elementAt(index);//.getPath();
362 public void setSelectedItem(Object item) {
363 // Cyberduck.DEBUG("[ComboPathModel] setSelectedItem(" + item + ")");
364 this.selected = item;
365 this.fireContentsChanged(this, 0, this.getSize());
366 // comboBox.addActionListener(comboActionListener);
369 public Object getSelectedItem() {
370 // Cyberduck.DEBUG("[ComboPathModel] getSelectedItem()");
371 if(selected instanceof java.lang.String)
372 return new Path((String)selected);
373 return this.selected;
378 // ************************************************************************************************************
380 private class UpAction extends AbstractAction {
381 public UpAction() {
382 // super("List parent");
383 this.putValue(SHORT_DESCRIPTION, "List parent directory");
384 this.putValue(SMALL_ICON, Cyberduck.getIcon(Cyberduck.getResource(this.getClass(), "up_small.gif")));
385 this.setEnabled(true);
386 //ActionMap.instance().put(this.getValue(NAME), this);
388 public void actionPerformed(ActionEvent ae) {
389 Cyberduck.DEBUG(ae.paramString());
390 selected.transfer(new TransferAction(TransferAction.LIST, selected.getCurrentPath().getParent()));
394 private class BackAction extends AbstractAction {
395 public BackAction() {
396 // super("Go Back");
397 this.putValue(SHORT_DESCRIPTION, "List previous directory");
398 this.putValue(SMALL_ICON, Cyberduck.getIcon(Cyberduck.getResource(this.getClass(), "back_small.gif")));
399 this.setEnabled(true);
400 //ActionMap.instance().put(this.getValue(NAME), this);
402 public void actionPerformed(ActionEvent ae) {
403 Cyberduck.DEBUG(ae.paramString());
404 selected.transfer(new TransferAction(TransferAction.LIST, selected.getPreviousPath()));
408 private class RefreshAction extends AbstractAction {
409 public RefreshAction() {
410 // super("Refresh");
411 this.putValue(SHORT_DESCRIPTION, "Refresh directory listing");
412 this.putValue(SMALL_ICON, Cyberduck.getIcon(Cyberduck.getResource(this.getClass(), "refresh_small.gif")));
413 this.setEnabled(true);
414 //ActionMap.instance().put(this.getValue(NAME), this);
416 public void actionPerformed(ActionEvent ae) {
417 Cyberduck.DEBUG(ae.paramString());
418 selected.transfer(new TransferAction(TransferAction.LIST, comboModel.getElementAt(comboModel.getSize() - 1)));
422 private class AbortAction extends AbstractAction {
423 public AbortAction() {
424 //super("Stop");
425 this.putValue(SHORT_DESCRIPTION, "Abort last action");
426 this.putValue(SMALL_ICON, Cyberduck.getIcon(Cyberduck.getResource(this.getClass(), "stop_small.gif")));
427 this.setEnabled(true);
428 //ActionMap.instance().put(this.getValue(NAME), this);
430 public void actionPerformed(ActionEvent ae) {
431 Cyberduck.DEBUG(ae.paramString());
432 //selected.transfer(new TransferAction(TransferAction.ABORT));
433 selected.status.setCanceled(true);
434 //((Action)ActionMap.instance().get("Stop")).actionPerformed(new ActionEvent(selected, ae.getID(), ae.getActionCommand()));
438 private class NewDirectoryAction extends AbstractAction {
439 public NewDirectoryAction() {
440 super("New Folder");
441 this.putValue(SHORT_DESCRIPTION, "Create new directory");
442 //this.putValue(SMALL_ICON, GUIFactory.NEW_FOLDER_ICON);
443 this.setEnabled(false);
444 //ActionMap.instance().put(this.getValue(NAME), this);
446 public void actionPerformed(ActionEvent ae) {
447 Cyberduck.DEBUG(ae.paramString());
448 Object input = JOptionPane.showInputDialog(
449 null,
450 "Name of the new folder:",
451 "New Folder",
452 JOptionPane.QUESTION_MESSAGE,
453 null,
454 null,
455 null
457 if(input != null) {
458 if(input instanceof String) {
459 selected.transfer(new TransferAction(TransferAction.MKDIR, (String)input));
465 private class DeleteAction extends AbstractAction {
466 public DeleteAction() {
467 super("Delete");
468 this.putValue(SHORT_DESCRIPTION, "Delete file or folder");
469 this.setEnabled(false);
470 //ActionMap.instance().put(this.getValue(NAME), this);
472 public void actionPerformed(ActionEvent ae) {
473 Cyberduck.DEBUG(ae.paramString());
474 if(listingTable.getSelectedRowCount() < 1 )
475 Cyberduck.beep();
476 else {
477 int[] rows = listingTable.getSelectedRows();
478 StringBuffer candidates = new StringBuffer();
479 for (int i = 0; i < rows.length; i++) {
480 candidates.append("\t"+listingTableModel.getEntry(rows[i])+"\n");
481 if(i > 10) {
482 candidates.append("\t... and "+(rows.length - i)+" more files.");
483 break;
486 String sep = System.getProperty("line.separator");
487 int input = JOptionPane.showConfirmDialog(null,
488 "Do you really want to delete all selected files?"+sep+candidates.toString()+sep+"You cannot undo this action.",
489 "Delete",
490 JOptionPane.YES_NO_OPTION,
491 JOptionPane.QUESTION_MESSAGE
493 if(input == JOptionPane.YES_OPTION) {
494 Path delete = null;
495 Cyberduck.DEBUG("[ListPanel] Deleting " + rows.length + " files");
496 for(int i = 0; i < rows.length; i++) {
497 delete = (Path)listingTableModel.getEntry(rows[i]);
498 selected.transfer(new TransferAction(TransferAction.DELE, delete), true);
500 selected.startQueue();
506 private class RenameAction extends AbstractAction {
507 public RenameAction() {
508 super("Rename");
509 this.putValue(SHORT_DESCRIPTION, "Rename file or folder");
510 this.setEnabled(false);
511 //ActionMap.instance().put(this.getValue(NAME), this);
513 public void actionPerformed(ActionEvent ae) {
514 Cyberduck.DEBUG(ae.paramString());
515 if(listingTable.getSelectedRowCount() > 1)
516 Cyberduck.beep();
517 if(listingTable.getSelectedRowCount() < 1)
518 Cyberduck.beep();
519 else {
520 Path from = (Path)listingTableModel.getEntry(listingTable.getSelectedRow());
521 Object input = JOptionPane.showInputDialog(null,
522 "Rename '" + from.getName() + "' to:",
523 "Rename",
524 JOptionPane.QUESTION_MESSAGE,
525 null,
526 null,
527 from.getName()
529 if(input != null) {
530 if(input instanceof String) {
531 selected.transfer(new TransferAction(TransferAction.RNFR, from, new Path(from.getParent().getPath(), (String)input)));
538 private class DisconnectAction extends AbstractAction {
539 public DisconnectAction() {
540 super("Disconnect");
541 this.putValue(SHORT_DESCRIPTION, "Disconnect from remote host");
542 this.setEnabled(false);
543 //ActionMap.instance().put(this.getValue(NAME), this);
545 public void actionPerformed(ActionEvent ae) {
546 Cyberduck.DEBUG(ae.paramString());
547 selected.transfer(new TransferAction(TransferAction.QUIT));
551 private class ListingDownloadAction extends AbstractAction {
552 public ListingDownloadAction() {
553 super("Download");
554 this.putValue(SHORT_DESCRIPTION, "Download selected file or folder");
555 this.setEnabled(false);
556 //ActionMap.instance().put(this.getValue(NAME), this);
558 public void actionPerformed(ActionEvent ae) {
559 Cyberduck.DEBUG(ae.paramString());
560 if(listingTable.getSelectedRowCount() < 1 )
561 Cyberduck.beep();
562 else {
563 Bookmark t = selected.copy();
564 Path p = (Path)listingTableModel.getEntry(listingTable.getSelectedRow());
565 t.setServerPath(p.toString());
566 t.setLocalPath(new java.io.File(Preferences.instance().getProperty("download.path"), p.getName()));
567 ((Action)(ActionMap.instance().get("New Bookmark"))).actionPerformed(new ActionEvent(t, ActionEvent.ACTION_PERFORMED, "New Bookmark"));
568 t.transfer(new TransferAction(TransferAction.GET));
574 * Show permission dialog
575 * @see ch.cyberduck.ui.PermissionDialog
577 private class PermissionAction extends AbstractAction {
578 public PermissionAction() {
579 super("Set Permissions");
580 this.putValue(SHORT_DESCRIPTION, "Edit file permissions");
581 this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_I, GUIFactory.MENU_MASK));
582 this.setEnabled(false);
583 //ActionMap.instance().put(this.getValue(NAME), this);
585 public void actionPerformed(ActionEvent ae) {
586 Cyberduck.DEBUG(ae.paramString());
587 if(listingTable.getSelectedRowCount() < 1 )
588 Cyberduck.beep();
589 else {
590 Path file = (Path)listingTableModel.getEntry(listingTable.getSelectedRow());
591 javax.swing.JDialog d = new PermissionDialog(selected, file);
592 d.show();