Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ProjectExplorerTable.java

Go to the documentation of this file.
00001 /*
00002  * ProjectExplorerTable.java
00003  *
00004  * Copyright (C) 2005 Project SQUID, http://www.cs.helsinki.fi/group/squid/
00005  *
00006  * This file is part of Ikayaki.
00007  *
00008  * Ikayaki is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Ikayaki is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Ikayaki; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00021  */
00022 
00023 package ikayaki.gui;
00024 
00025 import ikayaki.*;
00026 
00027 import javax.swing.*;
00028 import javax.swing.border.Border;
00029 import javax.swing.event.ListSelectionEvent;
00030 import javax.swing.event.ListSelectionListener;
00031 import javax.swing.table.AbstractTableModel;
00032 import javax.swing.table.TableColumn;
00033 import javax.swing.table.TableColumnModel;
00034 import java.awt.*;
00035 import java.awt.event.ActionEvent;
00036 import java.awt.event.ActionListener;
00037 import java.awt.event.MouseAdapter;
00038 import java.awt.event.MouseEvent;
00039 import java.io.File;
00040 import java.io.FileFilter;
00041 import java.text.DateFormat;
00042 import java.util.Arrays;
00043 import java.util.Comparator;
00044 import java.util.Date;
00045 
00051 public class ProjectExplorerTable extends JTable implements ProjectListener {
00052 
00056     private final ProjectComponent parent;
00057 
00061     private boolean isCalibration;
00062 
00063     private final ProjectExplorerTableModel explorerTableModel;
00064 
00065     private final Comparator<File> explorerTableComparator = new ProjectExplorerTableComparator();
00066 
00071     private Thread projectTypeCacher = new Thread();
00072 
00076     private File directory;
00077 
00081     private File[] files = new File[0];
00082 
00086     private int selectedFile = -1;
00087 
00091     private int explorerTableSortColumn = 0;
00092 
00093     // possible columns and their names
00094     private static final int COLUMN_UNDEFINED = -1;
00095     public static final int COLUMN_FILENAME = 0;
00096     public static final int COLUMN_TYPE = 1;
00097     public static final int COLUMN_LASTMOD = 2;
00098     public static final int COLUMN_LASTMEASURE = 3;
00099     public static final int COLUMN_UNMEASURED = 4;
00100     public static final String[] column_name = {"Name", "Type", "Modified", "Measured", "Elapsed"};
00101 
00102     // default column configurations for different table types
00103     public static final int[] default_columns = {COLUMN_FILENAME, COLUMN_TYPE, COLUMN_LASTMOD};
00104     public static final int[] calibration_columns = {COLUMN_FILENAME, COLUMN_LASTMEASURE, COLUMN_UNMEASURED};
00105 
00110     private int[] columns = new int[0];
00111 
00117     public ProjectExplorerTable(ProjectComponent parent) {
00118         this(parent, false);
00119     }
00120 
00127     public ProjectExplorerTable(ProjectComponent parent, boolean isCalibration) {
00128         this.parent = parent;
00129         this.isCalibration = isCalibration;
00130 
00131         // create TableModel only after columns are set
00132         explorerTableModel = new ProjectExplorerTableModel();
00133         this.setModel(explorerTableModel);
00134 
00135         // allow multiple line selection for multi-file-export
00136         // this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
00137         this.getTableHeader().setReorderingAllowed(false);
00138         this.getTableHeader().setResizingAllowed(false);
00139         this.setShowGrid(false);
00140         this.setIntercellSpacing(new Dimension(0, 0));
00141         this.setDefaultRenderer(StyledWrapper.class, new StyledTableCellRenderer());
00142 
00143         // TODO: what should be here anyway?
00144         // this.setPreferredScrollableViewportSize(new Dimension(280, 400));
00145 
00146         // set the right visible columns for table type
00147         if (this.isCalibration) {
00148             setColumns(calibration_columns);
00149         } else {
00150             setColumns(default_columns);
00151         }
00152 
00153         // ProjectExplorerTable events
00154 
00160         this.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
00161             public void valueChanged(ListSelectionEvent e) {
00162 
00163                 /* TODO:
00164                  * It is possible by CTRL-clicking to deselect the selected row. This can cause problems
00165                  * because after that the user will not anymore see which of the files is open. Change it
00166                  * so that if for some reason no row is selected and the currently open project is in this
00167                  * directory, select that project's file.
00168                  */
00169                 // - done, see below
00170 
00171                 // we only want the actually selected row, and don't want to react to an already selected line
00172                 // (which could also mean that we had a load error, and that selection was reverted)
00173                 if (e.getValueIsAdjusting() || getSelectedRow() == selectedFile) return;
00174                 if (getSelectedRowCount() > 1) return; // do nothing if multiple files selected
00175 
00176                 Project project = getSelectedRow() == -1 ? null : Project.loadProject(files[getSelectedRow()]);
00177 
00178                 // if load error, or nothing selected, revert back to old selection
00179                 if (project == null) {
00180                     // TODO: flash selected row red for 100 ms, perhaps? - might require a custom cell renderer
00181                     if (selectedFile == -1) {
00182                         clearSelection();
00183                     } else {
00184                         setRowSelectionInterval(selectedFile, selectedFile);
00185                     }
00186                 } else {
00187                     ProjectExplorerTable.this.parent.setProject(project);
00188                 }
00189             }
00190         });
00191 
00196         this.addMouseListener(new MouseAdapter() {
00197             public void mouseClicked(MouseEvent e) {
00198                 // only right-click brings popup menu
00199                 if (e.getButton() != MouseEvent.BUTTON3) return;
00200 
00201                 int[] row;
00202                 if (getSelectedRowCount() > 1) {
00203                     row = getSelectedRows();
00204                 } else {
00205                     row = new int[]{rowAtPoint(e.getPoint())};
00206                 }
00207 
00208                 // copy files matching selected (or clicked) rows
00209                 File[] file = new File[row.length];
00210                 for (int n = 0; n < row.length; n++) file[n] = files[row[n]];
00211 
00212                 // construct a new popup menu for every click
00213                 ProjectExplorerPopupMenu explorerTablePopup = new ProjectExplorerPopupMenu(file);
00214                 explorerTablePopup.show(ProjectExplorerTable.this, e.getX(), e.getY());
00215             }
00216         });
00217 
00221         this.getTableHeader().addMouseListener(new MouseAdapter() {
00222             public void mouseClicked(MouseEvent e) {
00223                 // only left-click changes sorting
00224                 if (e.getButton() != MouseEvent.BUTTON1) return;
00225 
00226                 TableColumnModel cm = getColumnModel();
00227                 int viewColumn = cm.getColumnIndexAtX(e.getX());
00228                 explorerTableSortColumn = cm.getColumn(viewColumn).getModelIndex();
00229 
00230                 // update all column headers and repaint header
00231                 for (int col = 0; col < getColumnCount(); col++) {
00232                     cm.getColumn(col).setHeaderValue(getColumnName(col));
00233                 }
00234                 getTableHeader().repaint();
00235 
00236                 // update table with sorted data, update selected file and table selection
00237                 setDirectory(directory);
00238             }
00239         });
00240     }
00241 
00247     public void setColumns(int[] columns) {
00248         if (columns != null) this.columns = columns;
00249 
00250         // StructureChanged resets columns' PreferredWidths, so they must be set again...
00251         explorerTableModel.fireTableStructureChanged();
00252 
00253         // set column default widths. if these are not wide enough, fitColumnWidths() will make them wider.
00254         for (int col = 0; col < this.columns.length; col++) {
00255             TableColumn column = this.getColumnModel().getColumn(col);
00256             switch (this.columns[col]) {
00257             case COLUMN_FILENAME:
00258                 column.setPreferredWidth(130);
00259                 break;
00260             case COLUMN_TYPE:
00261                 column.setMinWidth(55);
00262                 column.setMaxWidth(55);
00263                 break;
00264             case COLUMN_LASTMOD:
00265                 column.setMinWidth(95);
00266                 column.setMaxWidth(95);
00267                 break;
00268             case COLUMN_LASTMEASURE:
00269                 column.setMinWidth(100);
00270                 column.setMaxWidth(100);
00271                 break;   // should be wide enough for dates like "22.12.2005 22:22" with bold font
00272             case COLUMN_UNMEASURED:
00273                 column.setMinWidth(45);
00274                 column.setMaxWidth(45);
00275                 break;
00276             }
00277         }
00278     }
00279 
00287     public void fitColumnWidths() {
00288         for (int col = 0; col < columns.length; col++) {
00289             if (columns[col] != COLUMN_FILENAME) {
00290 
00291                 // find out the column's preferred width using the actual cell contents
00292                 int width = 0;
00293                 Component comp;
00294                 for (int row = 0; row < getRowCount(); row++) {
00295                     comp = getCellRenderer(row, col).getTableCellRendererComponent(this,
00296                             getValueAt(row, col), false, false, row, col);
00297                     width = Math.max(width, comp.getPreferredSize().width);
00298                 }
00299                 width += 5;
00300                 if (columnModel.getColumn(col).getMaxWidth() < width) {
00301                     // setting min and max width must be done in the event thread
00302                     TableColumn c = columnModel.getColumn(col);
00303                     c.setMaxWidth(width); // must set max first to avoid "min > max"
00304                     c.setMinWidth(width);
00305                 }
00306             }
00307         }
00308     }
00309 
00315     public void setDirectory(File directory) {
00316         this.directory = directory;
00317         this.files = getProjectFiles(this.directory);
00318 
00319         // sort files if needed before updating table
00320         if (explorerTableSortColumn != COLUMN_UNDEFINED) Arrays.sort(files, explorerTableComparator);
00321 
00322         // search if any file in current directory matches currently open project file
00323         selectedFile = -1;
00324         if (parent.getProject() != null) {
00325             for (int n = 0; n < files.length; n++) {
00326                 if (parent.getProject().getFile().equals(files[n])) selectedFile = n;
00327             }
00328         }
00329 
00330         // update table data and selected project file
00331         explorerTableModel.fireTableDataChanged();
00332         if (selectedFile != -1) {
00333             setRowSelectionInterval(selectedFile, selectedFile);
00334             SwingUtilities.invokeLater(new Runnable() {
00335                 public void run() {
00336                     scrollToRow(selectedFile);
00337                 }
00338             });
00339         }
00340     }
00341 
00347     private void scrollToRow(int rowIndex) {
00348         scrollRectToVisible(getCellRect(rowIndex, rowIndex, true));
00349     }
00350 
00357     private File[] getProjectFiles(File directory) {
00358         if (directory == null) return new File[0];
00359 
00360         File[] files = directory.listFiles(new FileFilter() {
00361             public boolean accept(File file) {
00362                 return file.isFile() && file.getName().endsWith(Ikayaki.FILE_TYPE)
00363                         && (!isCalibration || Project.getType(file) == Project.Type.CALIBRATION);
00364             }
00365         });
00366 
00367         if (files == null) return new File[0];
00368 
00369         // build project type cache (Project caches those; we only need to call Project.getType(File) for each file)
00370         // by doing this, scrolling in a big directory for the first time becomes smoother
00371 
00372         // stop the old thread before messing with cacheFiles and starting a new thread
00373         try {
00374             projectTypeCacher.interrupt();
00375             projectTypeCacher.join(); // wait for old thread to die
00376         } catch (InterruptedException e) {
00377         }
00378 
00379         // need a copy of files to work on, as they might get sorted any time in setDirectory(File)
00380         final File[] cacheFiles = files.clone();
00381 
00382         projectTypeCacher = new Thread(new Runnable() {
00383             public void run() {
00384                 for (File file : cacheFiles) {
00385                     if (Thread.interrupted()) return;
00386                     if (file.canRead()) Project.getType(file);
00387 
00388                     // when everything is cached, resize the columns if all data does not fit
00389                     SwingUtilities.invokeLater(new Runnable() {
00390                         public void run() {
00391                             fitColumnWidths();
00392                         }
00393                     });
00394                 }
00395             }
00396         });
00397 
00398         // start the worker thread
00399         projectTypeCacher.setPriority(Thread.MIN_PRIORITY);
00400         projectTypeCacher.start();
00401 
00402         return files;
00403     }
00404 
00410     public void projectUpdated(ProjectEvent event) {
00411         explorerTableModel.projectUpdated(event);
00412     }
00413 
00417     private class ProjectExplorerTableModel extends AbstractTableModel implements ProjectListener {
00418 
00419         private final StyledWrapper defaultWrapper = Settings.getDefaultWrapperInstance();
00420         private final StyledWrapper measuringWrapper = Settings.getMeasuringWrapperInstance();
00421         private final StyledWrapper doneRecentlyWrapper = Settings.getDoneRecentlyWrapperInstance();
00422         private final Font calibrationNoticeFont = ProjectExplorerTable.this.getFont().deriveFont(Font.BOLD);
00423 
00427         private File measuringProjectFile;
00428 
00432         private File doneRecentlyProjectFile;
00433 
00434         public ProjectExplorerTableModel() {
00435 
00436             // hide the ugly table borders
00437             Border emptyBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1);
00438             defaultWrapper.border = emptyBorder;
00439             defaultWrapper.selectedBorder = emptyBorder;
00440             defaultWrapper.focusBorder = emptyBorder;
00441             defaultWrapper.selectedFocusBorder = emptyBorder;
00442             measuringWrapper.border = emptyBorder;
00443             measuringWrapper.selectedBorder = emptyBorder;
00444             measuringWrapper.focusBorder = emptyBorder;
00445             measuringWrapper.selectedFocusBorder = emptyBorder;
00446             doneRecentlyWrapper.border = emptyBorder;
00447             doneRecentlyWrapper.selectedBorder = emptyBorder;
00448             doneRecentlyWrapper.focusBorder = emptyBorder;
00449             doneRecentlyWrapper.selectedFocusBorder = emptyBorder;
00450 
00451             /*
00452              * Refresh the data at regular intervals (5 min) even if no other events would refresh it.
00453              * This is especially to update the time elapsed value of a calibration panel.
00454              */
00455             new Timer(5 * 60 * 1000, new ActionListener() {
00456                 public void actionPerformed(ActionEvent e) {
00457                     // don't want to mess with table selection, so just update all lines, as this
00458                     // doesn't mess with table selection (unlike fireTableDataChanged), which is nice :)
00459                     explorerTableModel.fireTableRowsUpdated(0, getRowCount() - 1);
00460                     // ProjectExplorerTable.this.setDirectory(directory);
00461                 }
00462             }).start();
00463         }
00464 
00465         public String getColumnName(int column) {
00466             // translate visible column -> all columns for column_name, _not_ for sort column
00467             // TODO: does this look better without the "*"?
00468             // - not to me, but don't really care anymore :)
00469             return column_name[columns[column]] /* + (column == explorerTableSortColumn ? " *" : "") */;
00470         }
00471 
00472         public int getRowCount() {
00473             return files.length;
00474         }
00475 
00476         public int getColumnCount() {
00477             return columns.length;
00478         }
00479 
00480         public Object getValueAt(int row, int column) {
00481 //            Object value = null;
00482 //            try {
00483             File file = files[row];
00484             Object value;
00485 
00486             switch (columns[column]) { // translate visible column -> all columns
00487             case COLUMN_FILENAME:
00488                 String filename = file.getName();
00489                 value = filename.substring(0, filename.length() - Ikayaki.FILE_TYPE.length());
00490                 break;
00491 
00492             case COLUMN_TYPE:
00493                 Project.Type type = Project.getType(file);
00494                 if (type != null) {
00495                     value = type.toString();
00496                 } else {
00497                     value = null;
00498                 }
00499                 break;
00500 
00501             case COLUMN_LASTMOD:
00502                 value = DateFormat.getInstance().format(file.lastModified());
00503 //                    value = "22.12.2005 22:22"; // testing if this fits to the table
00504                 break;
00505 
00506             case COLUMN_LASTMEASURE:
00507                 Project p = Project.loadProject(file);
00508                 if (p == null) {
00509                     value = null;
00510                     break;
00511                 }
00512                 Date date = p.getTimestamp();
00513 //                    date = new Date(105, 11, 22, 22, 22, 22); // testing if this fits to the table
00514                 if (date == null) {
00515                     value = null;
00516                 } else {
00517                     value = DateFormat.getInstance().format(date);
00518                 }
00519                 break;
00520 
00521             case COLUMN_UNMEASURED:
00522                 p = Project.loadProject(file);
00523                 if (p == null) {
00524                     value = null;
00525                     break;
00526                 }
00527                 date = p.getTimestamp();
00528                 if (date == null) {
00529                     value = null;
00530                 } else {
00531                     value = (new Date().getTime() - date.getTime()) / 3600000 + " h";
00532                 }
00533                 break;
00534 
00535             default:
00536                 assert false;
00537                 value = null;
00538                 break;
00539             }
00540 
00541             // choose the style according to the project's state
00542             StyledWrapper wrapper;
00543             if (file.equals(measuringProjectFile)) {
00544                 wrapper = measuringWrapper;
00545             } else if (file.equals(doneRecentlyProjectFile)) {
00546                 wrapper = doneRecentlyWrapper;
00547             } else {
00548                 wrapper = defaultWrapper;
00549             }
00550             wrapper.font = null;        // reset calibration notice font
00551 
00552             // styles for the calibration panel
00553             if (isCalibration) {
00554                 Project p = Project.loadProject(file);
00555                 if (p == null) {
00556                     return null;
00557                 }
00558                 Date date = p.getTimestamp();
00559                 if (date == null) {
00560                     wrapper.font = calibrationNoticeFont;
00561                 } else {
00562                     // alert the user if the calibration has not been done today
00563                     int hoursElapsed = (int) (new Date().getTime() - date.getTime()) / 3600000;
00564                     if (hoursElapsed >= 18) {
00565                         wrapper.font = calibrationNoticeFont;
00566                     }
00567                 }
00568             }
00569 
00570             // return the wrapped value
00571             wrapper.value = value;
00572             return wrapper;
00573 
00574 //            } finally {
00575 //                if (!isCalibration) {
00576 //                    System.err.print(column + " " + row + "\t");
00577 //                    System.err.print("'" + value + "'");
00578 //                    for (int i : columns) {
00579 //                        System.err.print("\t" + i);
00580 //                    }
00581 //                    System.err.println();
00582 //                }
00583 //            }
00584         }
00585 
00586         @Override public Class<?> getColumnClass(int columnIndex) {
00587             return StyledWrapper.class;
00588         }
00589 
00600         public void projectUpdated(ProjectEvent event) {
00601             if (event.getType() == ProjectEvent.Type.FILE_SAVED) {
00602                 File saved = event.getProject().getFile();
00603                 for (int i = 0; i < files.length; i++) {
00604                     if (files[i].equals(saved)) {
00605                         explorerTableModel.fireTableRowsUpdated(i, i);
00606                         return;
00607                     }
00608                 }
00609 
00610             } else if (event.getType() == ProjectEvent.Type.STATE_CHANGED) {
00611                 File file = event.getProject().getFile();
00612                 boolean repaintTable = false;
00613 
00614                 Project.State state = event.getProject().getState();
00615                 if (state == null) {
00616                     state = Project.State.IDLE; // avoid NullPointerException when recieving events from closed projects
00617                 }
00618                 switch (state) {
00619                 case IDLE:
00620                     if (file.equals(measuringProjectFile)) {
00621                         // the project's measurement has just ended
00622                         measuringProjectFile = null;
00623                         doneRecentlyProjectFile = file;
00624                         repaintTable = true;
00625                     }
00626                     break;
00627                 case MEASURING:
00628                 case PAUSED:
00629                 case ABORTED:
00630                     // the project has an active measurement
00631                     measuringProjectFile = file;
00632                     doneRecentlyProjectFile = null;
00633                     repaintTable = true;
00634                     break;
00635                 default:
00636                     assert false;
00637                     break;
00638                 }
00639 
00640                 // repaint the table to show updated project states
00641                 if (repaintTable) {
00642                     // save the selections, or they will be lost in fireTableDataChanged()
00643                     int[] selectedRows = ProjectExplorerTable.this.getSelectedRows();
00644                     fireTableDataChanged();
00645                     for (int i : selectedRows) {
00646                         ProjectExplorerTable.this.getSelectionModel().addSelectionInterval(i, i);
00647                     }
00648                 }
00649             }
00650         }
00651     }
00652 
00656     private class ProjectExplorerTableComparator implements Comparator<File> {
00657         public int compare(File a, File b) {
00658             switch (columns[explorerTableSortColumn]) { // translate sort column
00659             case COLUMN_FILENAME:
00660                 return a.compareTo(b);
00661             case COLUMN_TYPE:
00662                 // WARNING: might choke Project.getType(File) with O(n log n) requests
00663                 Project.Type atype = Project.getType(a), btype = Project.getType(b);
00664                 if (atype == null && btype == null) return 0;
00665                 if (atype == null) return 1;
00666                 if (btype == null) return -1;
00667                 // NOTE: calibration-projects appear first because of enum-compareTo, but that's just fine, right?
00668                 return atype.compareTo(btype);
00669             case COLUMN_LASTMOD:
00670                 long diff = a.lastModified() - b.lastModified();
00671                 return diff == 0 ? 0 : (diff < 0 ? -1 : 1);
00672             case COLUMN_LASTMEASURE:
00673                 return compareTimestamps(a, b);
00674             case COLUMN_UNMEASURED:
00675                 return -compareTimestamps(a, b);
00676             default:
00677                 return 0;
00678             }
00679         }
00680 
00688         private int compareTimestamps(File a, File b) {
00689             Project aproject = Project.loadProject(a);
00690             Project bproject = Project.loadProject(b);
00691             Date adate = aproject == null ? null : aproject.getTimestamp();
00692             Date bdate = bproject == null ? null : bproject.getTimestamp();
00693             if (adate == null && bdate == null) return 0;
00694             if (adate == null) return -1;
00695             if (bdate == null) return 1;
00696             return adate.compareTo(bdate);
00697         }
00698     }
00699 
00705     private class ProjectExplorerPopupMenu extends JPopupMenu {
00706 
00710         private File[] files;
00711 
00715         private File directory;
00716 
00722         public ProjectExplorerPopupMenu(File[] xfiles) {
00723             if (xfiles == null || xfiles.length == 0) return; // stupid caller
00724 
00725             this.files = xfiles;
00726             this.directory = files[0].getParentFile();
00727 
00728             String filename, basename;
00729             if (files.length == 1) {
00730                 filename = files[0].getName();
00731                 basename = filename;
00732                 if (basename.toLowerCase().endsWith(Ikayaki.FILE_TYPE)) {
00733                     basename = basename.substring(0, basename.length() - Ikayaki.FILE_TYPE.length());
00734                 }
00735             } else {
00736                 filename = "selected " + files.length + " files";
00737                 basename = "*";
00738             }
00739 
00740             JMenuItem export = new JMenuItem("Export " + filename + " to");
00741             export.setFont(export.getFont().deriveFont(Font.BOLD));
00742             export.setEnabled(false);
00743             this.add(export);
00744 
00745             // TODO: some portable way to get a File for disk drive? Or maybe a Setting for export-dirs?
00746             for (File dir : new File[]{null, directory, new File("A:/")}) {
00747                 for (String type : new String[]{"dat", "tdt" /*, "srm" */}) {   // TODO: support for SRM files is missing
00748                     JMenuItem exportitem;
00749                     if (dir == null) {
00750                         exportitem = new JMenuItem(type.toUpperCase() + " file" +
00751                                 (files.length > 1 ? "s" : "") + "...");
00752                     } else {
00753                         exportitem = new JMenuItem(new File(dir, basename + "." + type).toString());
00754                     }
00755 
00756                     this.add(exportitem);
00757 
00762                     exportitem.addActionListener(new ActionListener() {
00763                         public void actionPerformed(ActionEvent e) {
00764                             String filename = e.getActionCommand();
00765                             String filetype = filename.substring(filename.length() - 3);
00766                             File exportdir;
00767                             boolean dirHasFile = false;
00768 
00769                             if (filetype.equals("...")) {
00770                                 filetype = filename.substring(0, 3).toLowerCase();
00771                                 JFileChooser chooser = new JFileChooser(directory);
00772 
00773                                 if (files.length > 1) {
00774                                     chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
00775                                 } else {
00776                                     dirHasFile = true; // we have explicit export-filename in exportdir
00777                                 }
00778 
00779                                 chooser.setFileFilter(
00780                                         new GenericFileFilter(filetype.toUpperCase() + " File", filetype));
00781 
00782                                 if (chooser.showSaveDialog(ProjectExplorerTable.this) == JFileChooser.APPROVE_OPTION) {
00783                                     exportdir = chooser.getSelectedFile();
00784                                 } else {
00785                                     return;
00786                                 }
00787 
00788                             } else {
00789                                 exportdir = new File(filename).getParentFile();
00790                             }
00791 
00792                             // execute export
00793                             for (File f : files) {
00794 
00795                                 /* TODO: This overwrites existing files without asking!
00796                                  *
00797                                  * Get a pointer to MainViewPanel and use the method
00798                                  * MainViewPanel.exportProject(Project,String,File)
00799                                  * because it prompts the user if the file exists, and
00800                                  * offers the option to change the output file name.
00801                                  *
00802                                  * Another option is to automatically rename the new file
00803                                  * to file.0.dat, file.1.dat and so on.
00804                                  */
00805 
00806                                 File exportfile;
00807                                 if (dirHasFile) {
00808                                     exportfile = exportdir;
00809                                     if (!exportfile.getName().toLowerCase().endsWith("." + filetype)) {
00810                                         exportfile = new File(exportfile.toString() + "." + filetype);
00811                                     }
00812                                 } else {
00813                                     String exportname = f.getName();
00814                                     if (exportname.toLowerCase().endsWith(Ikayaki.FILE_TYPE)) {
00815                                         exportname = exportname.substring(0,
00816                                                 exportname.length() - Ikayaki.FILE_TYPE.length());
00817                                     }
00818                                     exportname += "." + filetype;
00819                                     exportfile = new File(exportdir, exportname);
00820                                 }
00821 
00822 //                                System.out.print("Exporting " + exportfile + "... ");
00823 
00824                                 boolean ok = false;
00825                                 if (filetype.equals("dat")) {
00826                                     ok = Project.loadProject(f).exportToDAT(exportfile);
00827                                 } else if (filetype.equals("tdt")) {
00828                                     ok = Project.loadProject(f).exportToTDT(exportfile);
00829                                 } else if (filetype.equals("srm")) ok = Project.loadProject(f).exportToSRM(exportfile);
00830 
00831 //                                System.out.println(ok ? "ok" : "ERROR");
00832 /*
00833                                 // TODO: tell somehow, not with popup, if export was successful; statusbar perhaps?
00834                                 Component c = ProjectExplorerTable.this;
00835                                 while (c.getParent() != null) c = c.getParent();
00836                                 if (!ok) JOptionPane.showMessageDialog(c, "Unable to write to " + exportfile,
00837                                                                        "Error exporting files", JOptionPane.ERROR_MESSAGE);
00838 */
00839                             }
00840                         }
00841                     });
00842                 }
00843             }
00844         }
00845     }
00846 } // NOTE: what a nice end-brace-fallout :)

Generated on Fri May 6 16:00:32 2005 for Squid by  doxygen 1.4.1