View Javadoc
1   //
2   // $Id: JUploadPanelImpl.java 303 2007-07-21 07:42:51 +0000 (sam., 21 juil.
3   // 2007)
4   // etienne_sf $
5   //
6   // jupload - A file upload applet.
7   // Copyright 2007 The JUpload Team
8   //
9   // Created: ?
10  // Creator: William JinHua Kwong
11  // Last modified: $Date: 2015-03-10 20:59:42 +0100 (mar., 10 mars 2015) $
12  //
13  // This program is free software; you can redistribute it and/or modify it under
14  // the terms of the GNU General Public License as published by the Free Software
15  // Foundation; either version 2 of the License, or (at your option) any later
16  // version. This program is distributed in the hope that it will be useful, but
17  // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19  // details. You should have received a copy of the GNU General Public License
20  // along with this program; if not, write to the Free Software Foundation, Inc.,
21  // 675 Mass Ave, Cambridge, MA 02139, USA.
22  
23  package wjhk.jupload2.gui;
24  
25  import java.awt.Frame;
26  import java.awt.Point;
27  import java.awt.dnd.DnDConstants;
28  import java.awt.dnd.DropTarget;
29  import java.awt.dnd.DropTargetDropEvent;
30  import java.awt.event.ActionEvent;
31  import java.awt.event.ActionListener;
32  import java.awt.event.InputEvent;
33  import java.awt.event.MouseEvent;
34  import java.awt.event.MouseListener;
35  
36  import javax.swing.Action;
37  import javax.swing.ActionMap;
38  import javax.swing.ImageIcon;
39  import javax.swing.JButton;
40  import javax.swing.JComponent;
41  import javax.swing.JFileChooser;
42  import javax.swing.JLabel;
43  import javax.swing.JPanel;
44  import javax.swing.JProgressBar;
45  import javax.swing.JScrollPane;
46  import javax.swing.ScrollPaneConstants;
47  import javax.swing.SwingConstants;
48  import javax.swing.TransferHandler;
49  
50  import wjhk.jupload2.JUploadApplet;
51  import wjhk.jupload2.gui.filepanel.FilePanel;
52  import wjhk.jupload2.gui.filepanel.FilePanelTableImp;
53  import wjhk.jupload2.policies.UploadPolicy;
54  import wjhk.jupload2.upload.FileUploadManagerThread;
55  import wjhk.jupload2.upload.FileUploadManagerThreadImpl;
56  
57  /**
58   * Standard implementation for the {@link JUploadPanel} interface. It contains the actual creation of the GUI items.
59   * 
60   * @author etienne_sf
61   * @version $Revision: 1715 $
62   */
63  public class JUploadPanelImpl extends JPanel implements ActionListener, JUploadPanel, MouseListener {
64  
65      /** A generated serialVersionUID, to avoid warning during compilation */
66      private static final long serialVersionUID = -1212601012568225757L;
67  
68      /** The debug popup menu of the applet */
69      private JUploadDebugPopupMenu jUploadDebugPopupMenu;
70  
71      /** The main popup menu of the applet */
72      private JUploadMainPopupMenu jUploadMainPopupMenu;
73  
74      // ------------- VARIABLES ----------------------------------------------
75  
76      /**
77       * The Drag and Drop listener, that will manage the drop event. All pplet element should register this instance, so
78       * that the user see the whole applet as a unique drop target.
79       */
80      private DnDListener dndListener = null;
81  
82      private JButton browseButton = null, removeButton = null, removeAllButton = null, uploadButton = null,
83              stopButton = null;
84  
85      private JUploadFileChooser fileChooser = null;
86  
87      private FilePanel filePanel = null;
88  
89      private JProgressBar preparationProgressBar = null;
90  
91      private JProgressBar uploadProgressBar = null;
92  
93      private JLabel statusLabel = null;
94  
95      /**
96       * The log window. It's created by {@link JUploadApplet}.
97       */
98      private JUploadTextArea logWindow = null;
99  
100     /**
101      * The log window pane contains the log window, and the relevant scroll bars. It's actually this pane that is
102      * displayed, as a view on the log window.
103      */
104     private JScrollPane jLogWindowPane = null;
105 
106     private UploadPolicy uploadPolicy = null;
107 
108     private FileUploadManagerThread fileUploadManagerThread = null;
109 
110     // ------------- CONSTRUCTOR --------------------------------------------
111 
112     /**
113      * Standard constructor.
114      * 
115      * @param logWindow The log window that should already have been created. This allows putting text into it, before
116      *            the effective creation of the layout.
117      * @param uploadPolicyParam The current UploadPolicy. Null if a new one must be created.
118      * @throws Exception
119      */
120     public JUploadPanelImpl(JUploadTextArea logWindow, UploadPolicy uploadPolicyParam) throws Exception {
121         this.logWindow = logWindow;
122         this.uploadPolicy = uploadPolicyParam;
123         this.jUploadDebugPopupMenu = new JUploadDebugPopupMenu(this.uploadPolicy);
124         this.jUploadMainPopupMenu = new JUploadMainPopupMenu(this.uploadPolicy, this);
125 
126         // First: create standard components.
127         createStandardComponents();
128         logWindow.addMouseListener(this);
129 
130         // Define the drop target.
131         this.dndListener = new DnDListener(this, this.uploadPolicy);
132         new DropTarget(this, this.dndListener);
133         new DropTarget(this.filePanel.getDropComponent(), this.dndListener);
134         new DropTarget(this.logWindow, this.dndListener);
135 
136         // Define the TransfertHandler, to manage paste operations.
137         JUploadTransferHandler jUploadTransfertHandler = new JUploadTransferHandler(this.uploadPolicy, this);
138         this.setTransferHandler(jUploadTransfertHandler);
139         this.filePanel.setTransferHandler(jUploadTransfertHandler);
140         ActionMap map = this.getActionMap();
141         map.put(TransferHandler.getPasteAction().getValue(Action.NAME), TransferHandler.getPasteAction());
142 
143         // The JUploadPanelImpl will listen to Mouse messages for the standard
144         // component. The current only application of this, it the CTRL+Righ
145         // Click, that triggers the popup menu, which allow to switch debug on.
146         this.browseButton.addMouseListener(this);
147         this.removeAllButton.addMouseListener(this);
148         this.removeButton.addMouseListener(this);
149         this.stopButton.addMouseListener(this);
150         this.uploadButton.addMouseListener(this);
151 
152         this.jLogWindowPane.addMouseListener(this);
153         logWindow.addMouseListener(this);
154         this.preparationProgressBar.addMouseListener(this);
155         this.uploadProgressBar.addMouseListener(this);
156         this.statusLabel.addMouseListener(this);
157 
158         // Then: display them on the applet
159         this.uploadPolicy.addComponentsToJUploadPanel(this);
160     }
161 
162     // ----------------------------------------------------------------------
163 
164     /**
165      * Creates all components used by the default upload policy. <BR>
166      * You can change the component position of these components on the applet, by creating a new upload policy, and
167      * override the {@link UploadPolicy#addComponentsToJUploadPanel(JUploadPanel)} method.<BR>
168      * You should keep these components, as there content is managed by the internal code of the applet. <BR>
169      * <U>Note:</U> this method will create component only if they were not already created. That is only if the
170      * relevant attribute contain a null value. If it's not the case, the already created component are keeped
171      * unchanged.
172      */
173     private void createStandardComponents() {
174         // -------- JButton browse --------
175         if (this.browseButton == null) {
176             this.browseButton = new JButton(this.uploadPolicy.getLocalizedString("buttonBrowse"));
177             this.browseButton.setIcon(new ImageIcon(getClass().getResource("/images/explorer.gif")));
178         }
179         this.browseButton.addActionListener(this);
180 
181         // -------- JButton remove --------
182         if (this.removeButton == null) {
183             this.removeButton = new JButton(this.uploadPolicy.getLocalizedString("buttonRemoveSelected"));
184             this.removeButton.setIcon(new ImageIcon(getClass().getResource("/images/recycle.gif")));
185         }
186         this.removeButton.setEnabled(false);
187         this.removeButton.addActionListener(this);
188 
189         // -------- JButton removeAll --------
190         if (this.removeAllButton == null) {
191             this.removeAllButton = new JButton(this.uploadPolicy.getLocalizedString("buttonRemoveAll"));
192             this.removeAllButton.setIcon(new ImageIcon(getClass().getResource("/images/cross.gif")));
193         }
194         this.removeAllButton.setEnabled(false);
195         this.removeAllButton.addActionListener(this);
196 
197         // -------- JButton upload --------
198         if (null == this.uploadButton) {
199             this.uploadButton = new JButton(this.uploadPolicy.getLocalizedString("buttonUpload"));
200             this.uploadButton.setIcon(new ImageIcon(getClass().getResource("/images/up.gif")));
201         }
202         this.uploadButton.setEnabled(false);
203         this.uploadButton.addActionListener(this);
204 
205         // -------- The main thing: the file panel --------
206         this.filePanel = new FilePanelTableImp(this, this.uploadPolicy);
207 
208         // -------- JProgressBar progress --------
209         if (null == this.preparationProgressBar) {
210             this.preparationProgressBar = new JProgressBar(SwingConstants.HORIZONTAL);
211             this.preparationProgressBar.setStringPainted(true);
212         }
213         if (null == this.uploadProgressBar) {
214             this.uploadProgressBar = new JProgressBar(SwingConstants.HORIZONTAL);
215             this.uploadProgressBar.setStringPainted(true);
216         }
217 
218         // -------- JButton stop --------
219         if (null == this.stopButton) {
220             this.stopButton = new JButton(this.uploadPolicy.getLocalizedString("buttonStop"));
221             this.stopButton.setIcon(new ImageIcon(getClass().getResource("/images/cross.gif")));
222         }
223         this.stopButton.setEnabled(false);
224         this.stopButton.addActionListener(this);
225 
226         // -------- JButton stop --------
227         if (this.jLogWindowPane == null) {
228             this.jLogWindowPane = new JScrollPane();
229             this.jLogWindowPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
230             this.jLogWindowPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
231         }
232         this.jLogWindowPane.getViewport().add(this.logWindow);
233         this.jLogWindowPane.setPreferredSize(null);
234 
235         // -------- statusLabel --------
236         this.statusLabel = new JLabel("JUpload applet " + this.uploadPolicy.getContext().getDetailedVersionMessage());
237     }
238 
239     /** {@inheritDoc} */
240     public void showOrHideLogWindow() {
241         if ((this.uploadPolicy.getShowLogWindow().equals(UploadPolicy.SHOWLOGWINDOW_TRUE))
242                 || (this.uploadPolicy.getShowLogWindow().equals(UploadPolicy.SHOWLOGWINDOW_ONERROR) && this.uploadPolicy
243                         .getLastException() != null)) {
244             // The log window should be visible.
245             this.jLogWindowPane.setVisible(true);
246         } else {
247             // It should be hidden.
248             this.jLogWindowPane.setVisible(false);
249         }
250         // Let's recalculate the component display
251         validate();
252     }
253 
254     // ///////////////////////////////////////////////////////////////////////////////
255     // ///////////////// Action methods
256     // ///////////////////////////////////////////////////////////////////////////////
257 
258     /** {@inheritDoc} */
259     public void doBrowse() {
260         // If the file chooser was not created, we create it now.
261         if (null == this.fileChooser) {
262             // Setup File Chooser.
263             try {
264                 this.uploadPolicy.displayDebug("Before this.uploadPolicy.createFileChooser()", 80);
265                 this.fileChooser = this.uploadPolicy.createFileChooser();
266                 this.uploadPolicy.displayDebug("After this.uploadPolicy.createFileChooser()", 80);
267             } catch (Exception e) {
268                 this.uploadPolicy.displayErr(e);
269             }
270 
271         }
272 
273         // If the fileChooser succeed (should be the case), we go on.
274         if (null != this.fileChooser) {
275             try {
276                 int ret = this.fileChooser.showOpenDialog(new Frame());
277                 if (JFileChooser.APPROVE_OPTION == ret)
278                     this.filePanel.addFiles(this.fileChooser.getSelectedFiles());
279                 // We stop any running task for the JUploadFileView
280                 this.uploadPolicy.setCurrentBrowsingDirectory(this.fileChooser.getCurrentDirectory().getAbsolutePath());
281                 this.fileChooser.shutdownNow();
282             } catch (Exception ex) {
283                 this.uploadPolicy.displayErr(ex);
284             }
285         }
286     }
287 
288     /** {@inheritDoc} */
289     public void doRemove() {
290         this.filePanel.removeSelected();
291         if (0 >= this.filePanel.getFilesLength()) {
292             this.removeButton.setEnabled(false);
293             this.removeAllButton.setEnabled(false);
294             this.uploadButton.setEnabled(false);
295         }
296     }
297 
298     /** {@inheritDoc} */
299     public void doRemoveAll() {
300         this.filePanel.removeAll();
301         this.removeButton.setEnabled(false);
302         this.removeAllButton.setEnabled(false);
303         this.uploadButton.setEnabled(false);
304     }
305 
306     /** {@inheritDoc} */
307     public void doStartUpload() {
308         // Check that the upload is ready (we ask the uploadPolicy. Then,
309         // we'll call beforeUpload for each
310         // FileData instance, that exists in allFiles[].
311 
312         // ///////////////////////////////////////////////////////////////////////////////////////////////
313         // IMPORTANT: It's up to the UploadPolicy to explain to the user
314         // that the upload is not ready!
315         // ///////////////////////////////////////////////////////////////////////////////////////////////
316         try {
317             if (this.uploadPolicy.beforeUpload()) {
318                 // When called from the javascript handler, there may be no
319                 // file in the filelist.
320                 if (getFilePanel().getFilesLength() > 0) {
321                     // The FileUploadManagerThread will manage everything around
322                     // upload, including GUI part.
323                     this.fileUploadManagerThread = new FileUploadManagerThreadImpl(this.uploadPolicy);
324                     this.fileUploadManagerThread.start();
325                 }
326             } // if isIploadReady()
327         } catch (Exception e) {
328             // If an exception occurs here, it fails silently. The exception is
329             // thrown to the AWT event dispatcher.
330             this.uploadPolicy.displayErr(e.getClass().getName() + " in JUploadPanelImpl.doStartUpload()", e);
331         }
332     }
333 
334     /** {@inheritDoc} */
335     public void doStopUpload() {
336         this.fileUploadManagerThread.stopUpload();
337     }
338 
339     // ///////////////////////////////////////////////////////////////////////////////
340     // ///////////////// Implementation of the ActionListener
341     // ///////////////////////////////////////////////////////////////////////////////
342 
343     /**
344      * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
345      */
346     public void actionPerformed(ActionEvent e) {
347         // Let's log some info.
348         this.uploadPolicy.displayDebug("Action : " + e.getActionCommand(), 1);
349 
350         final String actionPaste = (String) TransferHandler.getPasteAction().getValue(Action.NAME);
351 
352         if (e.getActionCommand().equals(actionPaste)) {
353             Action a = getActionMap().get(actionPaste);
354             if (a != null) {
355                 a.actionPerformed(new ActionEvent(this.filePanel, ActionEvent.ACTION_PERFORMED, e.getActionCommand()));
356                 this.uploadPolicy.afterFileDropped(new DropTargetDropEvent(new DropTarget(this.filePanel
357                         .getDropComponent(), this.dndListener).getDropTargetContext(), new Point(),
358                         DnDConstants.ACTION_MOVE, DnDConstants.ACTION_COPY_OR_MOVE));
359             }
360         } else if (e.getActionCommand() == this.browseButton.getActionCommand()) {
361             doBrowse();
362         } else if (e.getActionCommand() == this.removeButton.getActionCommand()) {
363             // Remove clicked
364             doRemove();
365         } else if (e.getActionCommand() == this.removeAllButton.getActionCommand()) {
366             // Remove All clicked
367             doRemoveAll();
368         } else if (e.getActionCommand() == this.uploadButton.getActionCommand()) {
369             // Upload clicked
370             doStartUpload();
371         } else if (e.getActionCommand() == this.stopButton.getActionCommand()) {
372             // We request the thread to stop its job.
373             doStopUpload();
374         }
375         // focus the table. This is necessary in order to enable mouse
376         // events
377         // for triggering tooltips.
378         this.filePanel.focusTable();
379     }
380 
381     // ///////////////////////////////////////////////////////////////////////////////
382     // ///////////////// Implementation of the MouseListener
383     // ///////////////////////////////////////////////////////////////////////////////
384 
385     /**
386      * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
387      */
388     public void mouseClicked(MouseEvent mouseEvent) {
389         maybeOpenPopupMenu(mouseEvent);
390     }
391 
392     /**
393      * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
394      */
395     public void mouseEntered(MouseEvent mouseEvent) {
396         maybeOpenPopupMenu(mouseEvent);
397     }
398 
399     /**
400      * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
401      */
402     public void mouseExited(MouseEvent mouseEvent) {
403         maybeOpenPopupMenu(mouseEvent);
404     }
405 
406     /**
407      * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
408      */
409     public void mousePressed(MouseEvent mouseEvent) {
410         maybeOpenPopupMenu(mouseEvent);
411     }
412 
413     /**
414      * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
415      */
416     public void mouseReleased(MouseEvent mouseEvent) {
417         if (mouseEvent.getClickCount() == 2) {
418             // We have a double-click. Let's tell it to the current upload
419             // policy...
420             this.uploadPolicy.onFileDoubleClicked(this.filePanel.getFileDataAt(mouseEvent.getPoint()));
421         } else {
422             maybeOpenPopupMenu(mouseEvent);
423         }
424     }
425 
426     /** {@inheritDoc} */
427     public boolean maybeOpenPopupMenu(MouseEvent mouseEvent) {
428         // Should we open one out of the numerous (2!) popup menus ?
429         if (mouseEvent.isPopupTrigger()) {
430             if ((mouseEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) {
431                 // We open the debug menu
432                 if (this.jUploadDebugPopupMenu != null) {
433                     this.jUploadDebugPopupMenu.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
434                     return true;
435                 }
436             } else {
437                 // Let's open the main popup menu
438                 if (this.jUploadMainPopupMenu != null) {
439                     this.jUploadMainPopupMenu.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
440                     return true;
441                 }
442             }
443         }
444         return false;
445     }
446 
447     /** {@inheritDoc} */
448     public void updateButtonState() {
449         if (this.fileUploadManagerThread != null && this.fileUploadManagerThread.isAlive()
450                 && !this.fileUploadManagerThread.isUploadFinished()) {
451             // An upload is running on.
452             this.browseButton.setEnabled(false);
453             this.removeButton.setEnabled(false);
454             this.removeAllButton.setEnabled(false);
455             this.uploadButton.setEnabled(false);
456             this.stopButton.setEnabled(true);
457             // Let's delegate any additional work to the upload policy.
458             this.uploadPolicy.updateButtonState(UploadPolicy.EXEC_STATUS_UPLOADING);
459         } else {
460             // No upload running on.
461             this.browseButton.setEnabled(true);
462             this.stopButton.setEnabled(false);
463 
464             boolean enabled = (this.filePanel.getFilesLength() > 0);
465             this.removeButton.setEnabled(enabled);
466             this.removeAllButton.setEnabled(enabled);
467             this.uploadButton.setEnabled(enabled);
468             // Let's delegate any additional work to the upload policy.
469             this.uploadPolicy.updateButtonState(UploadPolicy.EXEC_STATUS_READY);
470         }
471 
472     }
473 
474     /** {@inheritDoc} */
475     public void clearLogWindow() {
476         this.logWindow.setText("");
477     }
478 
479     /** {@inheritDoc} */
480     public void copyLogWindow() {
481         this.logWindow.copyLogWindow();
482     }
483 
484     /** {@inheritDoc} */
485     public ActionListener getActionListener() {
486         return this;
487     }
488 
489     /** {@inheritDoc} */
490     public JButton getBrowseButton() {
491         return this.browseButton;
492     }
493 
494     /** {@inheritDoc} */
495     public JComponent getJComponent() {
496         return this;
497     }
498 
499     /** {@inheritDoc} */
500     public DnDListener getDndListener() {
501         return this.dndListener;
502     }
503 
504     /** {@inheritDoc} */
505     public FilePanel getFilePanel() {
506         return this.filePanel;
507     }
508 
509     /** {@inheritDoc} */
510     public JScrollPane getJLogWindowPane() {
511         return this.jLogWindowPane;
512     }
513 
514     /**
515      * Get the log window, that is: the component where messages (debug, info, error...) are written. You should not use
516      * this component directly, but:
517      * <UL>
518      * <LI>To display messages: use the UploadPolicy.displayXxx methods.
519      * <LI>To place this component on the applet, when overriding the
520      * {@link UploadPolicy#addComponentsToJUploadPanel(JUploadPanel)} method: use the {@link #getJLogWindowPane()}
521      * method instead. The {@link #logWindow} is embbeded in it.
522      * </UL>
523      * 
524      * @return the logWindow
525      */
526     protected JUploadTextArea getLogWindow() {
527         return this.logWindow;
528     }
529 
530     /** {@inheritDoc} */
531     public MouseListener getMouseListener() {
532         return this;
533     }
534 
535     /** {@inheritDoc} */
536     public JProgressBar getPreparationProgressBar() {
537         return this.preparationProgressBar;
538     }
539 
540     /** {@inheritDoc} */
541     public JProgressBar getUploadProgressBar() {
542         return this.uploadProgressBar;
543     }
544 
545     /** {@inheritDoc} */
546     public JButton getRemoveAllButton() {
547         return this.removeAllButton;
548     }
549 
550     /** {@inheritDoc} */
551     public JButton getRemoveButton() {
552         return this.removeButton;
553     }
554 
555     /** {@inheritDoc} */
556     public JLabel getStatusLabel() {
557         return this.statusLabel;
558     }
559 
560     /** {@inheritDoc} */
561     public JButton getStopButton() {
562         return this.stopButton;
563     }
564 
565     /** {@inheritDoc} */
566     public JButton getUploadButton() {
567         return this.uploadButton;
568     }
569 
570     /** {@inheritDoc} */
571     public void setFilePanel(FilePanel filePanel) {
572         this.filePanel = filePanel;
573     }
574 
575     /** {@inheritDoc} */
576     public FileUploadManagerThread getFileUploadManagerThread() {
577         return fileUploadManagerThread;
578     }
579 
580 }