source: josm/trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java @ 4920

Revision 4404, 12.5 KB checked in by simon04, 5 months ago (diff)

fix #4743 - wrong error message when loading a non-existing file

  • Property svn:eol-style set to native
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.awt.event.ActionEvent;
9import java.awt.event.KeyEvent;
10import java.io.File;
11import java.io.IOException;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.HashSet;
17import java.util.LinkedHashSet;
18import java.util.LinkedList;
19import java.util.List;
20import java.util.Set;
21
22import javax.swing.JFileChooser;
23import javax.swing.JOptionPane;
24import javax.swing.SwingUtilities;
25import javax.swing.filechooser.FileFilter;
26
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.gui.HelpAwareOptionPane;
29import org.openstreetmap.josm.gui.PleaseWaitRunnable;
30import org.openstreetmap.josm.gui.help.HelpUtil;
31import org.openstreetmap.josm.io.AllFormatsImporter;
32import org.openstreetmap.josm.io.FileImporter;
33import org.openstreetmap.josm.io.OsmTransferException;
34import org.openstreetmap.josm.tools.MultiMap;
35import org.openstreetmap.josm.tools.Shortcut;
36import org.xml.sax.SAXException;
37
38/**
39 * Open a file chooser dialog and select an file to import. Then call the gpx-import driver. Finally
40 * open an internal frame into the main window with the gpx data shown.
41 *
42 * @author imi
43 */
44public class OpenFileAction extends DiskAccessAction {
45
46    /**
47     * Create an open action. The name is "Open a file".
48     */
49    public OpenFileAction() {
50        super(tr("Open..."), "open", tr("Open a file."),
51                Shortcut.registerShortcut("system:open", tr("File: {0}", tr("Open...")), KeyEvent.VK_O, Shortcut.GROUP_MENU));
52        putValue("help", ht("/Action/Open"));
53
54    }
55
56    public void actionPerformed(ActionEvent e) {
57        JFileChooser fc = createAndOpenFileChooser(true, true, null);
58        if (fc == null)
59            return;
60        File[] files = fc.getSelectedFiles();
61        OpenFileTask task = new OpenFileTask(Arrays.asList(files), fc.getFileFilter());
62        task.setRecordHistory(true);
63        Main.worker.submit(task);
64    }
65
66    @Override
67    protected void updateEnabledState() {
68        setEnabled(! Main.applet);
69    }
70
71    /**
72     * Open a list of files. The complete list will be passed to batch importers.
73     * @param fileList A list of files
74     */
75    static public void openFiles(List<File> fileList) {
76        openFiles(fileList, false);
77    }
78
79    static public void openFiles(List<File> fileList, boolean recordHistory) {
80        OpenFileTask task = new OpenFileTask(fileList, null);
81        task.setRecordHistory(recordHistory);
82        Main.worker.submit(task);
83    }
84
85    static public class OpenFileTask extends PleaseWaitRunnable {
86        private List<File> files;
87        private List<File> successfullyOpenedFiles = new ArrayList<File>();
88        private FileFilter fileFilter;
89        private boolean canceled;
90        private boolean recordHistory = false;
91
92        public OpenFileTask(List<File> files, FileFilter fileFilter, String title) {
93            super(title, false /* don't ignore exception */);
94            this.files = new ArrayList<File>(files);
95            this.fileFilter = fileFilter;
96        }
97
98        public OpenFileTask(List<File> files, FileFilter fileFilter) {
99            this(files, fileFilter, tr("Opening files"));
100        }
101
102        /**
103         * save filename in history (for list of recently opened files)
104         * default: false
105         */
106        public void setRecordHistory(boolean recordHistory) {
107            this.recordHistory = recordHistory;
108        }
109
110        public boolean isRecordHistory() {
111            return recordHistory;
112        }
113
114        @Override
115        protected void cancel() {
116            this.canceled = true;
117        }
118
119        @Override
120        protected void finish() {
121            // do nothing
122        }
123
124        protected void alertFilesNotMatchingWithImporter(Collection<File> files, FileImporter importer) {
125            final StringBuffer msg = new StringBuffer();
126            msg.append("<html>");
127            msg.append(
128                    trn(
129                            "Cannot open {0} file with the file importer ''{1}''.",
130                            "Cannot open {0} files with the file importer ''{1}''.",
131                            files.size(),
132                            files.size(),
133                            importer.filter.getDescription()
134                    )
135            ).append("<br>");
136            msg.append("<ul>");
137            for (File f: files) {
138                msg.append("<li>").append(f.getAbsolutePath()).append("</li>");
139            }
140            msg.append("</ul>");
141
142            HelpAwareOptionPane.showMessageDialogInEDT(
143                    Main.parent,
144                    msg.toString(),
145                    tr("Warning"),
146                    JOptionPane.WARNING_MESSAGE,
147                    HelpUtil.ht("/Action/Open#ImporterCantImportFiles")
148            );
149        }
150
151        protected void alertFilesWithUnknownImporter(Collection<File> files) {
152            final StringBuffer msg = new StringBuffer();
153            msg.append("<html>");
154            msg.append(
155                    trn(
156                            "Cannot open {0} file because file does not exist or no suitable file importer is available.",
157                            "Cannot open {0} files because files do not exist or no suitable file importer is available.",
158                            files.size(),
159                            files.size()
160                    )
161            ).append("<br>");
162            msg.append("<ul>");
163            for (File f: files) {
164                msg.append("<li>");
165                msg.append(f.getAbsolutePath());
166                msg.append(" (<i>");
167                msg.append(f.exists() ? tr("no importer") : tr("does not exist"));
168                msg.append("</i>)</li>");
169            }
170            msg.append("</ul>");
171
172            HelpAwareOptionPane.showMessageDialogInEDT(
173                    Main.parent,
174                    msg.toString(),
175                    tr("Warning"),
176                    JOptionPane.WARNING_MESSAGE,
177                    HelpUtil.ht("/Action/Open#MissingImporterForFiles")
178            );
179        }
180
181        @Override
182        protected void realRun() throws SAXException, IOException, OsmTransferException {
183            if (files == null || files.isEmpty()) return;
184
185            /**
186             * Find the importer with the chosen file filter
187             */
188            FileImporter chosenImporter = null;
189            for (FileImporter importer : ExtensionFileFilter.importers) {
190                if (fileFilter == importer.filter) {
191                    chosenImporter = importer;
192                }
193            }
194            /**
195             * If the filter hasn't been changed in the dialog, chosenImporter is null now.
196             * When the filter has been set explicitly to AllFormatsImporter, treat this the same.
197             */
198            if (chosenImporter instanceof AllFormatsImporter) {
199                chosenImporter = null;
200            }
201            getProgressMonitor().setTicksCount(files.size());
202
203            if (chosenImporter != null) {
204                // The importer was explicitly chosen, so use it.
205                List<File> filesNotMatchingWithImporter = new LinkedList<File>();
206                List<File> filesMatchingWithImporter = new LinkedList<File>();
207                for (final File f : files) {
208                    if (!chosenImporter.acceptFile(f)) {
209                        if (f.isDirectory()) {
210                            SwingUtilities.invokeLater(new Runnable() {
211                                public void run() {
212                                    JOptionPane.showMessageDialog(Main.parent, tr(
213                                            "<html>Cannot open directory ''{0}''.<br>Please select a file.</html>",
214                                            f.getAbsolutePath()), tr("Open file"), JOptionPane.ERROR_MESSAGE);
215                                }
216                            });
217                            // TODO when changing to Java 6: Don't cancel the
218                            // task here but use different modality. (Currently 2 dialogs
219                            // would block each other.)
220                            return;
221                        } else {
222                            filesNotMatchingWithImporter.add(f);
223                        }
224                    } else {
225                        filesMatchingWithImporter.add(f);
226                    }
227                }
228
229                if (!filesNotMatchingWithImporter.isEmpty()) {
230                    alertFilesNotMatchingWithImporter(filesNotMatchingWithImporter, chosenImporter);
231                }
232                if (!filesMatchingWithImporter.isEmpty()) {
233                    importData(chosenImporter, filesMatchingWithImporter);
234                }
235            } else {
236                // find appropriate importer
237                MultiMap<FileImporter, File> importerMap = new MultiMap<FileImporter, File>();
238                List<File> filesWithUnknownImporter = new LinkedList<File>();
239                FILES: for (File f : files) {
240                    for (FileImporter importer : ExtensionFileFilter.importers) {
241                        if (importer.acceptFile(f)) {
242                            importerMap.put(importer, f);
243                            continue FILES;
244                        }
245                    }
246                    filesWithUnknownImporter.add(f);
247                }
248                if (!filesWithUnknownImporter.isEmpty()) {
249                    alertFilesWithUnknownImporter(filesWithUnknownImporter);
250                }
251                List<FileImporter> importers = new ArrayList<FileImporter>(importerMap.keySet());
252                Collections.sort(importers);
253                Collections.reverse(importers);
254
255                Set<String> fileHistory = new LinkedHashSet<String>();
256                Set<String> failedAll = new HashSet<String>();
257
258                for (FileImporter importer : importers) {
259                    List<File> files = new ArrayList<File>(importerMap.get(importer));
260                    importData(importer, files);
261                    // suppose all files will fail to load
262                    List<File> failedFiles = new ArrayList<File>(files);
263
264                    if (recordHistory && !importer.isBatchImporter()) {
265                        // remove the files which didn't fail to load from the failed list
266                        failedFiles.removeAll(successfullyOpenedFiles);
267                        for (File f : successfullyOpenedFiles) {
268                            fileHistory.add(f.getCanonicalPath());
269                        }
270                        for (File f : failedFiles) {
271                            failedAll.add(f.getCanonicalPath());
272                        }
273                    }
274                }
275
276                if (recordHistory) {
277                    Collection<String> oldFileHistory = Main.pref.getCollection("file-open.history");
278                    fileHistory.addAll(oldFileHistory);
279                    // remove the files which failed to load from the list
280                    fileHistory.removeAll(failedAll);
281                    int maxsize = Math.max(0, Main.pref.getInteger("file-open.history.max-size", 15));
282                    Main.pref.putCollectionBounded("file-open.history", maxsize, fileHistory);
283                }
284            }
285        }
286
287        public void importData(FileImporter importer, List<File> files) {
288            if (importer.isBatchImporter()) {
289                if (canceled) return;
290                String msg = trn("Opening {0} file...", "Opening {0} files...", files.size(), files.size());
291                getProgressMonitor().setCustomText(msg);
292                getProgressMonitor().indeterminateSubTask(msg);
293                if (importer.importDataHandleExceptions(files, getProgressMonitor().createSubTaskMonitor(files.size(), false))) {
294                    successfullyOpenedFiles.addAll(files);
295                }
296            } else {
297                for (File f : files) {
298                    if (canceled) return;
299                    getProgressMonitor().indeterminateSubTask(tr("Opening file ''{0}'' ...", f.getAbsolutePath()));
300                    if (importer.importDataHandleExceptions(f, getProgressMonitor().createSubTaskMonitor(1, false))) {
301                        successfullyOpenedFiles.add(f);
302                    }
303                }
304            }
305        }
306
307        public List<File> getSuccessfullyOpenedFiles() {
308            return successfullyOpenedFiles;
309        }
310    }
311}
Note: See TracBrowser for help on using the repository browser.