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

Last change on this file since 8093 was 7865, checked in by Don-vip, 9 years ago

fix NPE, typo

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