source: trunk/gli/src/org/greenstone/gatherer/file/FileAssociationManager.java@ 10007

Last change on this file since 10007 was 9657, checked in by davidb, 19 years ago

Files with spaces in failed to launch properly. The relevant section
has been reworked to avoid this pitfall. The split on spaces now happens
*before* %1 is substituted with its real filename.

  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.file;
28
29import java.io.*;
30import java.util.regex.*;
31import javax.swing.table.*;
32import org.greenstone.gatherer.Configuration;
33import org.greenstone.gatherer.DebugStream;
34import org.greenstone.gatherer.Dictionary;
35import org.greenstone.gatherer.gui.FileAssociationDialog;
36import org.greenstone.gatherer.gui.PreviewCommandDialog;
37import org.greenstone.gatherer.util.ExternalProgram;
38import org.greenstone.gatherer.util.StaticStrings;
39import org.greenstone.gatherer.util.Utility;
40import org.greenstone.gatherer.util.XMLTools;
41import org.w3c.dom.*;
42
43public class FileAssociationManager
44 extends AbstractTableModel {
45 static final public String FILENAME_ARG = "%1";
46 static final private String ESCAPE = "\\\\"; // '\'
47 static final private String ESCAPED_ESCAPE = "\\\\\\\\"; // '\\'
48 static final private String SPACE = " ";
49 static final private String ESCAPED_SPACE = "\\\\ ";
50 private Element associations_element;
51 private File data_file;
52
53 public FileAssociationManager() {
54 // Retrieve the associations_element from the config
55 associations_element = Configuration.getFileAssociations();
56 // Initialize the associations. This involves looking through all current associations searching for those with a command of "".
57 if(associations_element != null) {
58 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
59 for(int i = 0; i < entries.getLength(); i++) {
60 Element entry = (Element) entries.item(i);
61 String command = XMLTools.getValue(entry);
62 // If we encounter a command of ""...
63 if(command.length() == 0) {
64 // if we are on windows, we default to the start command
65 if(Utility.isWindows()) {
66 if (Utility.isWindows9x()) {
67 XMLTools.setValue(entry, StaticStrings.WIN_9X_OPEN_COMMAND);
68 } else {
69 XMLTools.setValue(entry, StaticStrings.WIN_OPEN_COMMAND);
70 }
71 }
72 // and if we are on mac, we default to the open program
73 else if(Utility.isMac()) {
74 XMLTools.setValue(entry, StaticStrings.MAC_OPEN_COMMAND);
75 }
76 }
77 command = null;
78 entry = null;
79 }
80 entries = null;
81 }
82 else {
83 DebugStream.println("Didn't parse anything. About to crash.");
84 }
85 }
86
87 public void edit() {
88 FileAssociationDialog dialog = new FileAssociationDialog(this);
89 dialog.display(null);
90 dialog = null;
91 }
92
93 public String getBrowserCommand(String url) {
94 DebugStream.println("Get browser command: " + url);
95 // First off we try to retrieve one from the configuration
96 String command = Configuration.getPreviewCommand();
97 // If that worked, substitute in the url and return
98 if(command != null && command.length() > 0) {
99 command = command.replaceAll("%1", url);
100 DebugStream.println("Result = " + command);
101 return command;
102 }
103 command = null;
104 // Failing that we have a guess at a sensible default
105 if(Utility.isWindows()) {
106 // we use cmd and start
107 if (Utility.isWindows9x()) {
108 command = StaticStrings.WIN_9X_OPEN_COMMAND;//"command.com /c start \""+url+"\"";
109 } else {
110 command = StaticStrings.WIN_OPEN_COMMAND;//"cmd.exe /c start \"\" \""+url+"\"";
111 }
112 } else if (Utility.isMac()) {
113 command = StaticStrings.MAC_OPEN_COMMAND; // "open %1"
114 } else {
115 // we try to look for a browser
116 String [] browsers = new String [] {"mozilla", "netscape"};
117 for (int i=0; i<browsers.length; i++) {
118 if (isAvailable(browsers[i])) {
119 command = browsers[i]+ " %1";
120 break;
121 }
122 }
123 }
124
125 // if we still haven't found something, prompt the user
126 if (command == null) {
127 PreviewCommandDialog dialog = new PreviewCommandDialog();
128 command = dialog.display();
129 dialog.dispose();
130 dialog = null;
131 }
132
133 // Store the result if any
134 if(command != null && !command.equals("")) {
135 Configuration.setPreviewCommand(command);
136 command = command.replaceAll(FILENAME_ARG, url);
137 DebugStream.println("Result = " + command);
138 return command;
139 }
140 // if we haven't got a command by now, we'll never get one
141 DebugStream.println("Result = null");
142 return null;
143
144 }
145
146 public int getColumnCount() {
147 return 2;
148 }
149
150 public String getColumnName(int column) {
151 String name;
152 switch(column) {
153 case 0:
154 name = Dictionary.get("FileAssociationDialog.Table.Extension");
155 break;
156 default:
157 name = Dictionary.get("FileAssociationDialog.Table.Command");
158 }
159 return name;
160 }
161
162 public String [] getCommand(File file) {
163 String command = null;
164 String [] commands = null;
165 if(file.isFile()) {
166 // Determine extension
167 String filename = file.getAbsolutePath();
168 String extension = filename.substring(filename.lastIndexOf(".") + 1);
169 // Try to retrieve a value from cache
170 Element entry = getCommand(extension);
171 if(entry != null) {
172 ///ystem.err.println("Retrieved Value From Cache");
173 command = XMLTools.getValue(entry);
174 }
175 if(command == null || command.length() == 0) {
176 ///ystem.err.println("No Existing Command");
177 // If command is null, and we are on windows try searching the registry.
178 if(Utility.isWindows()) {
179 //try the start command
180 if (Utility.isWindows9x()) {
181 command = StaticStrings.WIN_9X_OPEN_COMMAND;
182 } else {
183 command = StaticStrings.WIN_OPEN_COMMAND;
184 }
185
186 }
187
188 // If we are on a mac, default to using the open program
189 else if(Utility.isMac()) {
190 command = StaticStrings.MAC_OPEN_COMMAND;
191 }
192
193 // Otherwise display the dialog and ask the user to enter launching command.
194 if(command == null || command.length() == 0) {
195 ///ystem.err.println("Show Dialog");
196 // Show the dialog which forces a user to select the launch command for a certain file.
197 FileAssociationDialog dialog = new FileAssociationDialog(this);
198 command = dialog.display(extension);
199 dialog = null;
200 }
201 // Hopefully by now we have a command, or else we're never going to get one. Add the association.
202 if(command != null) {
203 // If no previous entry existed create one.
204 if(entry == null) {
205 entry = associations_element.getOwnerDocument().createElement(StaticStrings.ENTRY_ELEMENT);
206 entry.setAttribute(StaticStrings.EXTENSION_ATTRIBUTE, extension);
207 associations_element.appendChild(entry);
208 }
209 // Replace the text in this node. Remember to replace the dummy filename with %1 - I dont think the filename will ever be in the comand now
210 //XMLTools.setValue(entry, command.replaceAll(filename, FILENAME_ARG));
211 XMLTools.setValue(entry, command);
212 }
213 }
214 if(command != null) {
215
216 // Make the command into a string []
217 commands = command.split(" ");
218
219 // Now substitute any occurrences of %1 with its filename
220 // Note this is done after the split on spaces to avoid
221 // any conflict with filenames with spaces in them.
222
223 // We have to fix filename under windows to escape the backslashes
224 filename = filename.replaceAll(ESCAPE, ESCAPED_ESCAPE);
225
226 for (int i=0; i<commands.length; i++) {
227 // Replace %1 with the appropriate filename
228 commands[i] = commands[i].replaceAll(FILENAME_ARG, filename);
229 }
230
231 }
232
233 entry = null;
234 extension = null;
235 filename = null;
236 }
237 return commands;
238 }
239
240 public Element getCommand(String target_extension) {
241 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
242 for(int i = 0; i < entries.getLength(); i++) {
243 Element entry = (Element) entries.item(i);
244 String extension = entry.getAttribute(StaticStrings.EXTENSION_ATTRIBUTE);
245 if(extension.equalsIgnoreCase(target_extension)) {
246 entries = null;
247 extension = null;
248 return entry;
249 }
250 }
251 entries = null;
252 return null;
253 }
254
255 public String getCommandString(String target_extension) {
256 Element entry = getCommand(target_extension);
257 if(entry != null) {
258 return XMLTools.getValue(entry);
259 }
260 else {
261 return "";
262 }
263 }
264
265 public String getExtension(int index) {
266 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
267 if(0 <= index && index < entries.getLength()) {
268 Element entry = (Element) entries.item(index);
269 return entry.getAttribute(StaticStrings.EXTENSION_ATTRIBUTE);
270 }
271 return "";
272 }
273
274 public int getRowCount() {
275 return size();
276 }
277
278 public Object getValueAt(int row, int column) {
279 String extension = getExtension(row);
280 switch(column) {
281 case 0:
282 return extension;
283 default:
284 return getCommandString(extension);
285 }
286 }
287
288 public void save() {
289 }
290
291 public void setCommand(String extension, String command) {
292 DebugStream.println("Set Launch: " + extension + " with " + command);
293 // Retrieve any existing entry for this extension
294 Element entry = getCommand(extension);
295 // If no previous entry existed create one.
296 if(entry == null && command != null) {
297 entry = associations_element.getOwnerDocument().createElement(StaticStrings.ENTRY_ELEMENT);
298 entry.setAttribute(StaticStrings.EXTENSION_ATTRIBUTE, extension);
299 associations_element.appendChild(entry);
300 }
301
302 if(command != null) {
303 // Replace the text in this node. If the user has used filename instead of %1 then too bad.
304 XMLTools.setValue(entry, command);
305 }
306 else {
307 // Remove the entry
308 associations_element.removeChild(entry);
309 }
310 entry = null;
311 fireTableDataChanged(); // Can't be anymore efficient as DOM does not gareuntee ordering of new child nodes is consistant
312 }
313
314 public int size() {
315 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
316 return entries.getLength();
317 }
318
319
320 protected boolean isAvailable(String program) {
321 try {
322 ExternalProgram e = new ExternalProgram("which", program);
323 e.exitProgram();
324 String out = e.getLineOfProgramOutput();
325 if (out == null) {
326 return false;
327 }
328 return true;
329 } catch (Exception exc) {
330 return false;
331 }
332 }
333}
Note: See TracBrowser for help on using the repository browser.