// License: GPL. Copyright 2007 by Immanuel Scholz and others package org.openstreetmap.josm.actions; import static org.openstreetmap.josm.gui.help.HelpUtil.ht; import static org.openstreetmap.josm.tools.I18n.tr; import static org.openstreetmap.josm.tools.I18n.trn; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.filechooser.FileFilter; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.gui.HelpAwareOptionPane; import org.openstreetmap.josm.gui.PleaseWaitRunnable; import org.openstreetmap.josm.gui.help.HelpUtil; import org.openstreetmap.josm.io.AllFormatsImporter; import org.openstreetmap.josm.io.FileImporter; import org.openstreetmap.josm.io.OsmTransferException; import org.openstreetmap.josm.tools.MultiMap; import org.openstreetmap.josm.tools.Shortcut; import org.xml.sax.SAXException; /** * Open a file chooser dialog and select an file to import. Then call the gpx-import driver. Finally * open an internal frame into the main window with the gpx data shown. * * @author imi */ public class OpenFileAction extends DiskAccessAction { /** * Create an open action. The name is "Open a file". */ public OpenFileAction() { super(tr("Open..."), "open", tr("Open a file."), Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open...")), KeyEvent.VK_O, Shortcut.GROUP_MENU)); putValue("help", ht("/Action/OpenFile")); } public void actionPerformed(ActionEvent e) { JFileChooser fc = createAndOpenFileChooser(true, true, null); if (fc == null) return; File[] files = fc.getSelectedFiles(); OpenFileTask task = new OpenFileTask(Arrays.asList(files), fc.getFileFilter()); Main.worker.submit(task); } @Override protected void updateEnabledState() { setEnabled(! Main.applet); } /** * Open a list of files. The complete list will be passed to batch importers. * @param fileList A list of files */ static public void openFiles(List<File> fileList) { OpenFileTask task = new OpenFileTask(fileList, null); Main.worker.submit(task); } static public class OpenFileTask extends PleaseWaitRunnable { private List<File> files; private FileFilter fileFilter; private boolean cancelled; public OpenFileTask(List<File> files, FileFilter fileFilter) { super(tr("Opening files"), false /* don't ignore exception */); this.files = new ArrayList<File>(files); this.fileFilter = fileFilter; } @Override protected void cancel() { this.cancelled = true; } @Override protected void finish() { // do nothing } protected void alertFilesNotMatchingWithImporter(Collection<File> files, FileImporter importer) { final StringBuffer msg = new StringBuffer(); msg.append("<html>"); msg.append( trn( "Cannot open {0} file with the file importer ''{1}''.", "Cannot open {0} files with the file importer ''{1}''.", files.size(), files.size(), importer.filter.getDescription() ) ).append("<br>"); msg.append("<ul>"); for (File f: files) { msg.append("<li>").append(f.getAbsolutePath()).append("</li>"); } msg.append("</ul>"); SwingUtilities.invokeLater(new Runnable() { public void run() { HelpAwareOptionPane.showOptionDialog( Main.parent, msg.toString(), tr("Warning"), JOptionPane.WARNING_MESSAGE, HelpUtil.ht("/Action/OpenFile#ImporterCantImportFiles") ); } }); } protected void alertFilesWithUnknownImporter(Collection<File> files) { final StringBuffer msg = new StringBuffer(); msg.append("<html>"); msg.append( trn( "Cannot open {0} file because no suitable file importer is available.", "Cannot open {0} files because no suitable file importer is available.", files.size(), files.size() ) ).append("<br>"); msg.append("<ul>"); for (File f: files) { msg.append("<li>").append(f.getAbsolutePath()).append("</li>"); } msg.append("</ul>"); SwingUtilities.invokeLater(new Runnable() { public void run() { HelpAwareOptionPane.showOptionDialog( Main.parent, msg.toString(), tr("Warning"), JOptionPane.WARNING_MESSAGE, HelpUtil.ht("/Action/OpenFile#MissingImporterForFiles") ); } }); } @Override protected void realRun() throws SAXException, IOException, OsmTransferException { if (files == null || files.isEmpty()) return; /** * Find the importer with the chosen file filter */ FileImporter chosenImporter = null; for (FileImporter importer : ExtensionFileFilter.importers) { if (fileFilter == importer.filter) { chosenImporter = importer; } } /** * If the filter wasn't changed in the dialog, chosenImporter is null now. * When the filter was explicitly set to AllFormatsImporter, treat this the same. */ if (chosenImporter instanceof AllFormatsImporter) { chosenImporter = null; } getProgressMonitor().setTicksCount(files.size()); if (chosenImporter != null) { // The importer was expicitely chosen, so use it. List<File> filesNotMatchingWithImporter = new LinkedList<File>(); List<File> filesMatchingWithImporter = new LinkedList<File>(); for (final File f : files) { if (!chosenImporter.acceptFile(f)) { if (f.isDirectory()) { SwingUtilities.invokeLater(new Runnable() { public void run() { JOptionPane.showMessageDialog(Main.parent, tr( "<html>Cannot open directory ''{0}''.<br>Please select a file.</html>", f.getAbsolutePath()), tr("Open file"), JOptionPane.ERROR_MESSAGE); } }); // TODO when changing to Java 6: Don't cancel the // task here but use different modality. (Currently 2 dialogs // would block each other.) return; } else { filesNotMatchingWithImporter.add(f); } } else { filesMatchingWithImporter.add(f); } } if (!filesNotMatchingWithImporter.isEmpty()) { alertFilesNotMatchingWithImporter(filesNotMatchingWithImporter, chosenImporter); // TODO when changing to Java 6: Don't cancel the // task here but use different modality. (Currently 2 dialogs // would block each other.) return; } if (!filesMatchingWithImporter.isEmpty()) { importData(chosenImporter, filesMatchingWithImporter); } } else { // find appropriate importer MultiMap<FileImporter, File> map = new MultiMap<FileImporter, File>(); List<File> filesWithKnownImporter = new LinkedList<File>(); List<File> filesWithUnknownImporter = new LinkedList<File>(); FILES: for (File f : files) { for (FileImporter importer : ExtensionFileFilter.importers) { if (importer.acceptFile(f)) { map.put(importer, f); filesWithKnownImporter.add(f); continue FILES; } } filesWithUnknownImporter.add(f); } if (!filesWithUnknownImporter.isEmpty()) { alertFilesWithUnknownImporter(filesWithUnknownImporter); // TODO when changing to Java 6: Don't cancel the // task here but use different modality. (Currently 2 dialogs // would block each other.) return; } List<FileImporter> ims = new ArrayList<FileImporter>(map.keySet()); Collections.sort(ims); Collections.reverse(ims); for (FileImporter importer : ims) { List<File> files = new ArrayList<File>(map.get(importer)); importData(importer, files); } } } public void importData(FileImporter importer, List<File> files) { if (importer.isBatchImporter()) { if (cancelled) return; String msg; if (files.size() == 1) { msg = tr("Opening 1 file..."); } else { msg = trn("Opening {0} file...", "Opening {0} files...", files.size(), files.size()); } getProgressMonitor().setCustomText(msg); getProgressMonitor().indeterminateSubTask(msg); importer.importDataHandleExceptions(files, getProgressMonitor().createSubTaskMonitor(files.size(), false)); } else { for (File f : files) { if (cancelled) return; getProgressMonitor().indeterminateSubTask(tr("Opening file ''{0}'' ...", f.getAbsolutePath())); importer.importDataHandleExceptions(f, getProgressMonitor().createSubTaskMonitor(1, false)); } } } } }