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 }