// // $Id: FilePanelDataModel2.java 448 2008-04-24 20:51:51Z etienne_sf $ // // jupload - A file upload applet. // Copyright 2007 The JUpload Team // // Created: 2006-04-21 // Creator: etienne_sf // Last modified: $Date: 2008-04-24 13:51:51 -0700 (Thu, 24 Apr 2008) $ // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 2 of the License, or (at your option) any later // version. This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more // details. You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation, Inc., // 675 Mass Ave, Cambridge, MA 02139, USA. package wjhk.jupload2.gui; import java.io.File; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.Vector; import javax.swing.JOptionPane; import javax.swing.table.AbstractTableModel; import wjhk.jupload2.exception.JUploadExceptionStopAddingFiles; import wjhk.jupload2.exception.JUploadException; import wjhk.jupload2.filedata.FileData; import wjhk.jupload2.filedata.DefaultFileData; import wjhk.jupload2.policies.UploadPolicy; /** * This class replaces FilePanelDataModel. The data for each row is now * contained in an instance of FileData (or one of its subclasses, like * {@link wjhk.jupload2.filedata.PictureFileData}). This allow easy add of new * functionalites, during upload, by adding attributes or methods to these * classes, or create new ones. <BR> * Some ides of improvements : * <UL> * <LI> Compression of picture before Upload (see * {@link wjhk.jupload2.filedata.PictureFileData}) * <LI> Could be XML validation before sending to the server * <LI> Up to your imagination... * </UL> */ class FilePanelDataModel2 extends AbstractTableModel { /** * */ private static final long serialVersionUID = 1473262424494858913L; /** * The default colum indices of the columns, as displayed by the applet. * Index of the column "Filename" */ public static final int COLINDEX_NAME = 0; /** * The default colum indices of the columns, as displayed by the applet. * Index of the column "Filename" */ public static final int COLINDEX_SIZE = 1; /** * The default colum indices of the columns, as displayed by the applet. * Index of the column "Filesize" */ public static final int COLINDEX_DIRECTORY = 2; /** * The default colum indices of the columns, as displayed by the applet. * Index of the column "Last modified" */ public static final int COLINDEX_MODIFIED = 3; /** * The default colum indices of the columns, as displayed by the applet. * Index of the column "Readable" */ public static final int COLINDEX_READABLE = 4; /** * The uploadPolicy contains all current parameter, including the * FileDataParam */ private UploadPolicy uploadPolicy = null; /** * The column names, as displayed on the applet. They are not real final * values, as they are translated: we need to have an uploadPolicy for this * translation, and the uploadPolicy is 'given' to the constructor. */ private String COL_NAME = null; private String COL_SIZE = null; private String COL_DIRECTORY = null; private String COL_MODIFIED = null; private String COL_READABLE = null; protected String[] columnNames = null; protected int[] columnSize = null; protected Class<?> columnClasses[] = null; /** * This Vector contains all FileData. */ private Vector<FileData> rows = new Vector<FileData>(); /** * @param uploadPolicy * */ public FilePanelDataModel2(UploadPolicy uploadPolicy) { // Property initialization is done ... for each property. Nothing to do // here. super(); // this.uploadPolicy = uploadPolicy; // Initialization for column name, type and size. this.COL_NAME = uploadPolicy.getString("colName"); this.COL_SIZE = uploadPolicy.getString("colSize"); this.COL_DIRECTORY = uploadPolicy.getString("colDirectory"); this.COL_MODIFIED = uploadPolicy.getString("colModified"); this.COL_READABLE = uploadPolicy.getString("colReadable"); this.columnNames = new String[] { this.COL_NAME, this.COL_SIZE, this.COL_DIRECTORY, this.COL_MODIFIED, this.COL_READABLE }; this.columnSize = new int[] { 150, 75, 199, 130, 75 }; this.columnClasses = new Class[] { String.class, Long.class, String.class, Date.class, Boolean.class }; } /** * Does this table contain this file ? * * @param file : the file that could be contained... * @return true if the table contains this file. */ public boolean contains(File file) { Iterator<FileData> i = this.rows.iterator(); while (i.hasNext()) { if (file.equals(i.next().getFile())) { return true; } } return false; } public FileData getFilebByExternalId(String fid) { Iterator<FileData> i = this.rows.iterator(); FileData fd; this.uploadPolicy.displayDebug( "fpdm2 getFileByExternalId - Looking for "+fid, 50); while (i.hasNext()) { fd = i.next(); this.uploadPolicy.displayDebug( "getFileByExternalId - "+fd.external_id(), 50); if (fid.equals(fd.external_id())) { return fd; } } return null; } public FileData getFileByExternalIndex(Integer index) { Iterator<FileData> i = this.rows.iterator(); FileData fd; while (i.hasNext()) { fd = i.next(); if (index.equals(fd.external_index())) { return fd; } } return null; } /** * Add a file to the panel (at the end of the list) * * @param file * @param root * @throws JUploadExceptionStopAddingFiles */ public void addFile(File file, File root) throws JUploadExceptionStopAddingFiles { if (contains(file)) { this.uploadPolicy.displayWarn("File " + file.getName() + " already exists"); } else if (!this.uploadPolicy.fileFilterAccept(file)) { String msg = file.getName() + " : " + this.uploadPolicy.getString("errForbiddenExtension"); this.uploadPolicy.displayWarn(msg); if (JOptionPane.showConfirmDialog(null, msg, "alert", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) { // The user want to stop to add files to the list. For instance, // when he/she added a whole directory, and it contains a lot of // files that don't match the allowed file extension. throw new JUploadExceptionStopAddingFiles("Stopped by the user"); } } else if (this.uploadPolicy.getMaxFileSize()<file.length()) { String msg = String.format(uploadPolicy.getString("errFileTooBig"), file.getPath(), file.length(), DefaultFileData.human_readable_file_size(this.uploadPolicy.getMaxFileSize()), DefaultFileData.human_readable_file_size(file.length())); this.uploadPolicy.displayWarn(msg); if (JOptionPane.showConfirmDialog(null, msg, "alert", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) { // The user want to stop to add files to the list. For instance, // when he/she added a whole directory, and it contains a lot of // files that don't match the allowed file extension. throw new JUploadExceptionStopAddingFiles("Stopped by the user"); } } else { // We first call the upload policy, to get : // - The correct fileData instance (for instance the // PictureUploadPolicy returns a PictureFileData) // - The reference to this newly FileData, or null if an error // occurs (for instance: invalid file content, // according to the current upload policy). FileData df = this.uploadPolicy.createFileData(file, root); String cmd; if (df != null) { // The file is Ok, let's add it. this.rows.add(df); if (null != (cmd = this.uploadPolicy.getCallBackString(UploadPolicy.PROP_CALLBACK_FILE_QUEUED))) { // callback to javascript... String cmd_string = cmd; //+"("+df.getJSON(this.rows.indexOf(df))+")"; this.uploadPolicy.displayWarn("CMD - " + cmd_string); try { String[] args = { df.getJSON() }; this.uploadPolicy.performCallback(cmd_string,args,true); // instance call } catch (JUploadException e) { this.uploadPolicy.displayErr(e); } } // // implement to_JSON for default file data // use df.to_JSON to get the string // fireTableDataChanged(); } } } /** * Ask for the file contained at specified row number. * * @param row The row number * @return The return instance of File. */ public File getFileAt(int row) { return this.rows.get(row).getFile(); } /** * Ask for the file contained at specified row number. * * @param row The row number * @return The return instance of File. */ public FileData getFileDataAt(int row) { try { return this.rows.get(row); } catch (ArrayIndexOutOfBoundsException e) { // Nothing to do. It seems that it can occurs when upload is very // fast (for instance: small files to localhost). uploadPolicy.displayWarn(e.getClass().getName() + " in FilePanelDataModel2.getFileDataAt(" + row + ")"); } return null; } /** * Remove a specified row. * * @param row The row to remove. */ public synchronized void removeRow(int row) { this.rows.remove(row); fireTableDataChanged(); } /** * Removes fileData from the current list. There should be only one. * * @param fileData */ public synchronized void removeRow(FileData fileData) { Iterator<FileData> i = this.rows.iterator(); FileData item; while (i.hasNext()) { item = i.next(); if (item.getFile().equals(fileData.getFile())) { this.rows.removeElement(item); fireTableDataChanged(); break; } } } public synchronized FileData removeFilebByExternalId(String fid) { FileData fd; Iterator<FileData> i = this.rows.iterator(); FileData item; this.uploadPolicy.displayDebug("removeFilebByExternalId: removing by external id ", 10); if (fid!=null) this.uploadPolicy.displayDebug("removeFilebByExternalId: external id is "+fid, 10); while (i.hasNext()) { item = i.next(); if (item.external_id() == fid || null == fid) { /* either find the one to remove, or remove the first one */ this.rows.removeElement(item); fireTableDataChanged(); String cmd; item.uploadError(-280,"Cancelled"); return item; } } return null; } /** @see javax.swing.table.TableModel#getColumnCount() */ public int getColumnCount() { return this.columnNames.length; } /** @see javax.swing.table.TableModel#getRowCount() */ public int getRowCount() { return this.rows.size(); } /** * Always return false here : no editable cell. * * @see javax.swing.table.TableModel#isCellEditable(int, int) */ @Override public boolean isCellEditable(@SuppressWarnings("unused") int arg0, @SuppressWarnings("unused") int arg1) { // No editable columns. return false; } /** * Sort the rows, according to one column. * * @param col The index of the column to sort * @param ascending true if ascending, false if descending. */ @SuppressWarnings("unchecked") public void sortColumn(int col, boolean ascending) { Collections.sort(this.rows, new ColumnComparator(col, ascending)); fireTableDataChanged(); } /** * Return true if this column can be sorted. * * @param col The index of the column which can sortable or not. * @return true if the column can be sorted. false otherwise. */ public boolean isSortable(int col) { return (Boolean.class != getColumnClass(col)); } /** * @see javax.swing.table.TableModel#getColumnClass(int) */ @SuppressWarnings("unchecked") @Override public Class getColumnClass(int arg0) { return this.columnClasses[arg0]; } /** * @see javax.swing.table.TableModel#getValueAt(int, int) */ public Object getValueAt(int row, int col) { FileData fileData = getFileDataAt(row); if (null == fileData) { this.uploadPolicy.displayWarn("Row index out of bounds " + this.getClass().getName() + ": " + row); return null; } String colName = getColumnName(col); // Don't know if it will be useful, but the switch below allows the // column to be in any order. if (colName.equals(this.COL_NAME)) { return fileData.getFileName(); } else if (colName.equals(this.COL_SIZE)) { return new Long(fileData.getFileLength()); } else if (colName.equals(this.COL_DIRECTORY)) { return fileData.getDirectory(); } else if (colName.equals(this.COL_MODIFIED)) { return fileData.getLastModified(); } else if (colName.equals(this.COL_READABLE)) { return new Boolean(fileData.canRead()); } else { this.uploadPolicy.displayErr("Unknown column in " + this.getClass().getName() + ": " + colName); return null; } } /** * This method doesn't do anything : no changeable values. * * @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int) */ @Override public void setValueAt(@SuppressWarnings("unused") Object arg0, @SuppressWarnings("unused") int arg1, @SuppressWarnings("unused") int arg2) { this.uploadPolicy.displayWarn(this.getClass().getName() + ".setValueAt: no action"); } /** * @see javax.swing.table.TableModel#getColumnName(int) */ @Override public String getColumnName(int arg0) { return this.columnNames[arg0]; } /** * Retrieves the default colum size of a column. * * @param col The index of the column to query. * @return the default size of the requested column. */ public int getColumnSize(int col) { return this.columnSize[col]; } }