View Javadoc
1   //
2   // $Id: FilePanelTableImp.java 1721 2015-03-29 17:48:44Z etienne_sf $
3   //
4   // jupload - A file upload applet.
5   // Copyright 2007 The JUpload Team
6   //
7   // Created: ?
8   // Creator: William JinHua Kwong
9   // Last modified: $Date: 2015-03-29 19:48:44 +0200 (dim., 29 mars 2015) $
10  //
11  // This program is free software; you can redistribute it and/or modify it under
12  // the terms of the GNU General Public License as published by the Free Software
13  // Foundation; either version 2 of the License, or (at your option) any later
14  // version. This program is distributed in the hope that it will be useful, but
15  // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17  // details. You should have received a copy of the GNU General Public License
18  // along with this program; if not, write to the Free Software Foundation, Inc.,
19  // 675 Mass Ave, Cambridge, MA 02139, USA.
20  package wjhk.jupload2.gui.filepanel;
21  
22  import java.awt.BorderLayout;
23  import java.awt.Color;
24  import java.awt.Component;
25  import java.awt.Font;
26  import java.awt.Point;
27  import java.awt.event.ComponentEvent;
28  import java.awt.event.ComponentListener;
29  import java.io.File;
30  import java.util.List;
31  
32  import javax.swing.JPanel;
33  import javax.swing.JScrollPane;
34  import javax.swing.table.TableColumnModel;
35  
36  import wjhk.jupload2.exception.JUploadExceptionStopAddingFiles;
37  import wjhk.jupload2.filedata.FileData;
38  import wjhk.jupload2.gui.JUploadPanel;
39  import wjhk.jupload2.gui.filepanel.treeview.FolderNode;
40  import wjhk.jupload2.gui.filepanel.treeview.FileDataTreeViewModel;
41  import wjhk.jupload2.gui.filepanel.treeview.MyTreeTable;
42  import wjhk.jupload2.gui.filepanel.treeview.MyTreeTableModel;
43  import wjhk.jupload2.gui.filepanel.treeview.TreeFileDataNode;
44  import wjhk.jupload2.policies.UploadPolicy;
45  
46  /**
47   * Implementation of the FilePanel : it creates the {@link wjhk.jupload2.gui.filepanel.FilePanelJFlatTable}, and handles
48   * the necessary functionalities.<BR/>
49   * Since version 6.0, this class manages the link with the hierarchical (tree) view of the files to upload. This class
50   * remains the central point for file management, even if it's not visible. That is: even if the list displayed is the
51   * hierarchical view.
52   * 
53   * @author William JinHua Kwong
54   * @version $Revision: 1721 $
55   */
56  public class FilePanelTableImp extends JPanel implements FilePanel, ComponentListener {
57  
58      /** A generated serialVersionUID, to avoid warning during compilation */
59      static final long serialVersionUID = -8273990467324350526L;
60  
61      /** The main panel of the applet. */
62      JUploadPanel juploadPanel = null;
63  
64      /** The table, for the flat list */
65      FilePanelJFlatTable flatTable;
66  
67      /** the data model, for the flat list */
68      FilePanelFlatDataModel2 flatModel;
69  
70      /** The table, for the tree view */
71      MyTreeTable treeTable;
72  
73      /** the data model, for the tree view */
74      MyTreeTableModel<TreeFileDataNode> /* FileDataTreeViewModel */treeModel;
75  
76      /** The view, which displays the flat view. */
77      JScrollPane flatScrollPane = null;
78  
79      /** The view, which displays the tree view. */
80      JScrollPane treeScrollPane = null;
81  
82      /** The current display mode, for the file list. The default value is FLAT */
83      FileListViewMode fileListViewMode = FileListViewMode.FLAT;
84  
85      /** The current policy, always useful. */
86      UploadPolicy uploadPolicy = null;
87  
88      /**
89       * Creates a new instance.
90       * 
91       * @param juploadPanel The upload panel (parent).
92       * @param uploadPolicy The upload policy to apply.
93       */
94      public FilePanelTableImp(JUploadPanel juploadPanel, UploadPolicy uploadPolicy) {
95          this.juploadPanel = juploadPanel;
96          this.uploadPolicy = uploadPolicy;
97  
98          setLayout(new BorderLayout());
99          addMouseListener(juploadPanel.getMouseListener());
100         setTransferHandler(juploadPanel.getTransferHandler());
101 
102         // Construction of the flat view
103         this.flatTable = new FilePanelJFlatTable(juploadPanel, uploadPolicy);
104         this.flatModel = new FilePanelFlatDataModel2(uploadPolicy);
105         this.flatTable.setModel(this.flatModel);
106         this.flatScrollPane = new JScrollPane(this.flatTable);
107         this.flatScrollPane.addMouseListener(juploadPanel.getMouseListener());
108         // We must resize columns, when the size of the view changes.
109         this.flatScrollPane.getViewport().addComponentListener(this);
110 
111         // Construction of the tree view
112         treeModel = new FileDataTreeViewModel(uploadPolicy, this.flatModel);
113         treeTable = new MyTreeTable(treeModel);
114         treeModel.setTree(treeTable.getTree());
115         this.treeScrollPane = new JScrollPane(this.treeTable);
116         this.treeScrollPane.addMouseListener(juploadPanel.getMouseListener());
117         // We must resize columns, when the size of the view changes.
118         this.treeScrollPane.getViewport().addComponentListener(this);
119 
120         // Let's display the chosen mode.
121         this.fileListViewMode = this.uploadPolicy.getFileListViewMode();
122         switch (this.fileListViewMode) {
123             case FLAT:
124                 add(this.flatScrollPane, BorderLayout.CENTER);
125                 break;
126             case TREE_VIEW:
127             case INDEPENDENT_TREE_VIEW:
128                 add(this.treeScrollPane, BorderLayout.CENTER);
129                 break;
130         }// switch
131     }
132 
133     /** @see FilePanel#getFileListMode() */
134     public FileListViewMode getFileListMode() {
135         return this.fileListViewMode;
136     }
137 
138     /** @see FilePanel#setFileListViewMode(wjhk.jupload2.gui.filepanel.FilePanel.FileListViewMode) */
139     public void setFileListViewMode(FileListViewMode fileListViewMode) {
140         if (this.fileListViewMode != fileListViewMode) {
141             switch (fileListViewMode) {
142                 case FLAT:
143                     remove(this.treeScrollPane);
144                     add(this.flatScrollPane, BorderLayout.CENTER);
145                     // this.flatScrollPane.setVisible(true);
146                     // this.treeScrollPane.setVisible(false);
147                     break;
148                 case TREE_VIEW:
149                     remove(this.flatScrollPane);
150                     add(this.treeScrollPane, BorderLayout.CENTER);
151                     // this.flatScrollPane.setVisible(false);
152                     // this.treeScrollPane.setVisible(true);
153                     break;
154                 default:
155                     IllegalArgumentException e = new IllegalArgumentException("Unknown value for fileListMode:"
156                             + fileListViewMode.toString());
157                     uploadPolicy.displayErr(e);
158                     throw e;
159             }
160             this.fileListViewMode = fileListViewMode;
161             this.uploadPolicy.setFileListViewMode(fileListViewMode);
162         }
163     }
164 
165     /**
166      * @see wjhk.jupload2.gui.filepanel.FilePanel#addFiles(java.io.File[],java.io.File)
167      */
168     public final void addFiles(File[] filesToAdd) {
169         // adding file can be long. Let's add a time counter, there...
170         long startTime = System.currentTimeMillis();
171         int nbFiles = 0;
172 
173         if (null == filesToAdd) {
174             String msg = "FilePanelTableImpl: filesToUpload may not be null)";
175             uploadPolicy.displayErr(msg);
176             throw new java.lang.IllegalArgumentException(msg);
177         } else {
178             try {
179                 for (int i = 0; i < filesToAdd.length; i++) {
180                     nbFiles += treeModel.attachObject(filesToAdd[i]);
181                 }// for
182             } catch (JUploadExceptionStopAddingFiles e) { // The user want to stop here. Nothing else to do.
183                 this.uploadPolicy.displayWarn(getClass().getName() + ".addFiles() [" + e.getClass().getName() + "]: "
184                         + e.getMessage());
185             } catch (Exception e) {
186                 this.uploadPolicy.displayErr("Unexpected error during file adding: " + getClass().getName()
187                         + ".addFiles() [" + e.getClass().getName() + "]: " + e.getMessage());
188             }
189         }
190         this.juploadPanel.updateButtonState();
191 
192         // Update of the flat view
193         this.flatModel.fireTableDataChanged();
194 
195         // Update of the tree view. In flat mode and tree_view mode, the visible root may have changed after adding
196         // files.
197         if (this.uploadPolicy.getFileListViewMode().equals(FileListViewMode.FLAT)
198                 || this.uploadPolicy.getFileListViewMode().equals(FileListViewMode.TREE_VIEW)) {
199             FolderNode visibleRoot = (FolderNode) treeModel.getTreePathForObject(flatModel.getFileRoot())
200                     .getLastPathComponent();
201             if (visibleRoot == null) {
202                 uploadPolicy.displayErr("[Internal Error] Folder Node not found for folder "
203                         + flatModel.getFileRoot().getAbsolutePath());
204             } else {
205                 treeModel.setRoot(visibleRoot);
206             }
207         } else {
208             // We still need to refresh the data
209             reload();
210         }
211 
212         // adding file can be long. Let's add a time counter, there...
213         long finishTime = System.currentTimeMillis();
214         uploadPolicy.displayInfo("Added " + nbFiles + " files in " + ((finishTime - startTime) / 1000) + " seconds");
215     }
216 
217     /**
218      * @see wjhk.jupload2.gui.filepanel.FilePanel#getFiles()
219      */
220     public final List<FileData> getFiles() {
221         return this.flatModel.getFiles();
222     }
223 
224     /**
225      * @see wjhk.jupload2.gui.filepanel.FilePanel#getFilesLength()
226      */
227     public final int getFilesLength() {
228         return this.flatTable.getRowCount();
229     }
230 
231     /**
232      * @see wjhk.jupload2.gui.filepanel.FilePanel#removeSelected()
233      */
234     public final void removeSelected() {
235         synchronized (this.flatModel.getFiles()) {
236             int[] rows = this.flatTable.getSelectedRows();
237             for (int i = rows.length - 1; 0 <= i; i--) {
238                 removeRow(rows[i], null);
239             }
240         }
241     }
242 
243     /**
244      * @see java.awt.Container#removeAll()
245      */
246     @Override
247     public final void removeAll() {
248         synchronized (this.flatModel.getFiles()) {
249             for (int i = getFilesLength() - 1; 0 <= i; i--) {
250                 removeRow(i, null);
251             }
252         }
253     }
254 
255     /** {@inheritDoc} */
256     public void remove(FileData[] files) {
257         for (FileData fd : files) {
258             removeRow(null, fd);
259         }
260         this.treeModel.reload();
261     }
262 
263     /** @see FilePanel#removeFileNotToUpload() */
264     public void removeFileNotToUpload() {
265         // We remove all files, for which getUploadFlag() returns false.
266         // To do that, we can not do a standard for loop, to avoid the ConcurrentModificationException. So we do a
267         // specific counter management.
268         int i = 0;
269         FileData fd;
270         List<FileData> files = this.flatModel.getFiles();
271         while (i < files.size()) {
272             fd = files.get(i);
273             if (fd.getUploadFlag()) {
274                 // This file is to be uploaded. Let's pass it, to check the next one.
275                 i += 1;
276             } else {
277                 // This file is to be removed. We remove it, and keep the same index, which will contain the next file
278                 // in the next loop.
279                 removeRow(i, fd);
280             }
281         }// while
282     }
283 
284     /**
285      * Removes all occurences of a file from the list. Each file should only appear once here, but nobody knows !
286      * 
287      * @param fileData The file to remove
288      */
289     public final void remove(FileData fileData) {
290         removeRow(null, fileData);
291     }
292 
293     /**
294      * Removes a File from the FileList, with either the rowNumber or the FileData (or both). This method is internal to
295      * this class. If only one of these parameters is sent, the other one is calculated from the given one. If both
296      * parameters are sent, it's up to the calling method to guaranty that they both represents the same FileData.
297      * 
298      * @param rowNumber The row number in the flat view.
299      * @param fileData The fileData to remove.
300      */
301     final void removeRow(Integer rowNumberParam, FileData fileDataParam) {
302         synchronized (this.flatModel.getFiles()) {
303             if (rowNumberParam == null && fileDataParam == null) {
304                 uploadPolicy
305                         .displayErr("rowNumberParam and fileDataParam may not be both null (in FilePanelTableImpl.removeRow(Integer,FileData)");
306             }
307 
308             Integer rowNumber = rowNumberParam;
309             FileData fileData = fileDataParam;
310             if (rowNumber == null) {
311                 rowNumber = this.flatModel.getRow(fileDataParam);
312             } else if (fileData == null) {
313                 fileData = this.flatModel.getFileDataAt(rowNumber);
314             }
315 
316             // Removes the row, from the flat view .. If it exists.
317             if (rowNumber == null || rowNumber < 0) {
318                 uploadPolicy.displayWarn("The row " + rowNumber
319                         + " doesn't exist (in FilePanelTableImpl.removeRow(Integer,FileData)");
320             } else {
321                 this.flatModel.removeRow(rowNumber);
322             }
323 
324             // Removes the row, from the tree view
325             if (fileData == null) {
326                 uploadPolicy.displayWarn("The fileData for " + rowNumber
327                         + " doesn't exist (in FilePanelTableImpl.removeRow(Integer,FileData)");
328             } else {
329                 // FIXME Pour changer ├ža: passer par tous les noeuds, et trouver le FileData
330                 try {
331                     this.treeModel.remove(fileData.getTreeFileDataNode());
332                 } catch (Exception e) {
333                     uploadPolicy.displayErr(e);
334                 }
335                 /*
336                  * TreePath tp = treeModel.getTreePath(fileData.getTreeFileDataNode()); if (tp == null) {
337                  * uploadPolicy.displayWarn("The fileData for file " + fileData.getAbsolutePath() +
338                  * " doesn't exist (in FilePanelTableImpl.removeRow(Integer,FileData)"); } else if
339                  * (!(tp.getLastPathComponent() instanceof FileDataNode)) {
340                  * uploadPolicy.displayErr("The node for the fileData " + fileData.getAbsolutePath() +
341                  * " should be a FileDataNode (in FilePanelTableImpl.removeRow(Integer,FileData)"); } else { try {
342                  * this.treeModel.remove((FileDataNode) tp.getLastPathComponent()); } catch (Exception e) {
343                  * uploadPolicy.displayErr(e); } }
344                  */
345             }
346         }// synchronized
347     }
348 
349     /**
350      * Clear the current selection in the JTable.
351      */
352     public final void clearSelection() {
353         this.flatTable.clearSelection();
354     }
355 
356     /** @see wjhk.jupload2.gui.filepanel.FilePanel#focusTable() */
357     public final void focusTable() {
358         if (0 < this.flatTable.getRowCount()) {
359             this.flatTable.requestFocus();
360         }
361     }
362 
363     /** @see wjhk.jupload2.gui.filepanel.FilePanel#getFileDataAt(Point) */
364     public FileData getFileDataAt(Point point) {
365         int row = this.flatTable.rowAtPoint(point);
366         return this.flatModel.getFileDataAt(row);
367     }
368 
369     /**
370      * Return the component on which drop event can occur. Used by {@link JUploadPanel}, when initializing the
371      * DropTarget.
372      * 
373      * @return Component on which the drop event can occur.
374      */
375     public Component getDropComponent() {
376         return this;
377     }
378 
379     /**
380      * Catches the <I>hidden</I> event on the JViewport. {@inheritDoc}
381      */
382     public void componentHidden(ComponentEvent arg0) {
383         // We don't care...
384     }
385 
386     /**
387      * Catches the <I>moved</I> event on the JViewport. {@inheritDoc}
388      */
389     public void componentMoved(ComponentEvent arg0) {
390         // We don't care...
391     }
392 
393     /**
394      * When the size of the file list (actually the JViewport) changes, we adapt the size if the columns. {@inheritDoc}
395      */
396     public void componentResized(ComponentEvent arg0) {
397         // Is the width set?
398         if (getWidth() > 0) {
399             // First: we resize the flat table.
400             TableColumnModel flatColumnModel = this.flatTable.getColumnModel();
401             for (int i = 0; i < this.flatModel.getColumnCount(); i++) {
402                 flatColumnModel.getColumn(i)
403                         .setPreferredWidth(
404                                 (this.flatModel.getColumnSizePercentage(i) * this.flatScrollPane.getViewport()
405                                         .getWidth()) / 100);
406             }// for
407 
408             // Then the tree view
409             TableColumnModel treeviewColumnModel = this.treeTable.getColumnModel();
410             for (int i = 0; i < this.treeModel.getColumnCount(); i++) {
411                 treeviewColumnModel.getColumn(i)
412                         .setPreferredWidth(
413                                 (this.treeModel.getColumnSizePercentage(i) * this.treeScrollPane.getViewport()
414                                         .getWidth()) / 100);
415             }// for
416         }
417     }
418 
419     /**
420      * Catches the <I>shown</I> event on the JViewport. {@inheritDoc}
421      */
422     public void componentShown(ComponentEvent arg0) {
423         // We don't care...
424     }
425 
426     /**
427      * Set color of files list grid border.
428      * 
429      * @param color awt Color
430      */
431     public void setGridBorderColor(Color color) {
432         this.flatTable.setGridColor(color);
433     }
434 
435     /**
436      * Set back color of table header
437      * 
438      * @param color awt Color
439      */
440     public void setTableHeaderBackColor(Color color) {
441         this.flatTable.getTableHeader().setBackground(color);
442     }
443 
444     /**
445      * Set table header text font
446      * 
447      * @param color awt Color
448      */
449     public void setTableHeaderFont(Font font) {
450         this.flatTable.getTableHeader().setFont(font);
451     }
452 
453     /**
454      * Set text color of table header
455      * 
456      * @param color awt Color
457      */
458     public void setTableHeaderTextColor(Color color) {
459         this.flatTable.getTableHeader().setForeground(color);
460     }
461 
462     /** {@inheritDoc} */
463     public void reload() {
464         this.treeModel.reload();
465     }
466 
467     /** {@inheritDoc} */
468     public void cleanHierarchy() {
469         this.treeModel.cleanHierarchy();
470         reload();
471     }
472 
473 }