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

Last change on this file since 37677 was 37677, checked in by anupama, 13 months ago

GLI now tries to set the linux file association launch command to the default linux open command that works for the linux distribution, out of a limited set of known possibilities that may or may not be installed. For ubuntu xdg-open comes pre-installed, but this is not true for all linux distributions. Now GLI tries to help a little to see if any common known command works out.

  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 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.Gatherer;
33import org.greenstone.gatherer.Configuration;
34import org.greenstone.gatherer.DebugStream;
35import org.greenstone.gatherer.Dictionary;
36import org.greenstone.gatherer.gui.FileAssociationDialog;
37import org.greenstone.gatherer.gui.PreviewCommandDialog;
38import org.greenstone.gatherer.util.SafeProcess;
39import org.greenstone.gatherer.util.StaticStrings;
40import org.greenstone.gatherer.util.Utility;
41import org.greenstone.gatherer.util.XMLTools;
42import org.w3c.dom.*;
43
44public class FileAssociationManager
45 extends AbstractTableModel {
46 static final public String FILENAME_ARG = "%1";
47 static final private String ESCAPE = "\\\\"; // '\'
48 static final private String ESCAPED_ESCAPE = "\\\\\\\\"; // '\\'
49 static final private String SPACE = " ";
50 static final private String ESCAPED_SPACE = "\\\\ ";
51 private Element associations_element;
52 private File data_file;
53
54 public FileAssociationManager() {
55 // Retrieve the associations_element from the config
56 associations_element = Configuration.getFileAssociations();
57 // Initialize the associations. This involves looking through all current associations searching for those with a command of "".
58 if(associations_element != null) {
59 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
60 for(int i = 0; i < entries.getLength(); i++) {
61 Element entry = (Element) entries.item(i);
62 String command = XMLTools.getValue(entry);
63 // If we encounter a command of ""...
64 if(command.length() == 0) {
65 // if we are on windows, we default to the start command
66 if(Utility.isWindows()) {
67 if (Utility.isWindows9x()) {
68 XMLTools.setValue(entry, StaticStrings.WIN_9X_OPEN_COMMAND);
69 } else {
70 XMLTools.setValue(entry, StaticStrings.WIN_OPEN_COMMAND);
71 }
72 }
73 // and if we are on mac, we default to the open program
74 else if(Utility.isMac()) {
75 XMLTools.setValue(entry, StaticStrings.MAC_OPEN_COMMAND);
76 }
77 else { // On Linux, we need to discover which of a range of possible solutions
78 // works on this machine. If any works, we remember and use that choice
79 // for all file extensions for which no file association has been set yet.
80
81 // If we worked out the default linux file open command in a previous
82 // round of the FileAssociationManager loop, use it for the current file
83 // extension also
84
85 if(StaticStrings.LINUX_OPEN_COMMAND != null &&
86 !StaticStrings.LINUX_OPEN_COMMAND.equals("")) {
87
88 XMLTools.setValue(entry, StaticStrings.LINUX_OPEN_COMMAND);
89 } else if(StaticStrings.LINUX_OPEN_COMMAND == null) {
90 // StaticStrings.LINUX_OPEN_COMMAND not set yet: if we never tried to
91 // work out the default linux file launch command yet, then we'll test
92 // whether any known linux open command is available on this linux.
93
94 // xdg-open comes pre-installed on Ubuntu linux, but not on all linux
95 // https://www.cyberciti.biz/faq/unix-linux-command-to-view-file/
96 // Listing xdg-open 1st as it works on Ubuntu, reducing GLI load time
97 final String[] linux_open_cmds = {"xdg-open", "kde-open", "gnome-open"};
98
99 for(String open_cmd : linux_open_cmds) {
100 Gatherer.ProgramInstalledTest installTest = new Gatherer.ProgramInstalledTest(open_cmd);
101 if(installTest.found()) {
102 System.err.println("*********** Linux file open command " + installTest + " was found to be installed.");
103 StaticStrings.LINUX_OPEN_COMMAND = open_cmd + " %1";
104 XMLTools.setValue(entry, StaticStrings.LINUX_OPEN_COMMAND);
105 break;
106 } else {
107 System.err.println("*********** Linux file open command " + installTest + " was not installed.");
108 }
109 }
110
111 // either we have a default linux open command or not
112 // If we don't, set it to empty, so we don't work out
113 // linux value for each file extension (for each time
114 // FileAssociationManager is called) hereafter.
115 if(StaticStrings.LINUX_OPEN_COMMAND == null) {
116 StaticStrings.LINUX_OPEN_COMMAND = "";
117 }
118 }
119 // else StaticStrings.LINUX_OPEN_COMMAND = ""; which means
120 // we could never work out a feasible file open command on this linux
121 }
122 }
123 command = null;
124 entry = null;
125 }
126 entries = null;
127 }
128 else {
129 DebugStream.println("Didn't parse anything. About to crash.");
130 }
131 }
132
133 public void edit() {
134 FileAssociationDialog dialog = new FileAssociationDialog(this);
135 dialog.display(null);
136 dialog = null;
137 }
138
139 public String getBrowserCommand(String url) {
140 DebugStream.println("Get browser command: " + url);
141 // First off we try to retrieve one from the configuration
142 String command = Configuration.getPreviewCommand();
143 // If that worked, substitute in the url and return
144 if(command != null && command.length() > 0) {
145 command = command.replaceAll("%1", url);
146 DebugStream.println("Result = " + command);
147 return command;
148 }
149 command = null;
150 // Failing that we have a guess at a sensible default
151 if(Utility.isWindows()) {
152 // we use cmd and start
153 if (Utility.isWindows9x()) {
154 command = StaticStrings.WIN_9X_OPEN_COMMAND;//"command.com /c start \""+url+"\"";
155 } else {
156 command = StaticStrings.WIN_OPEN_COMMAND;//"cmd.exe /c start \"\" \""+url+"\"";
157 }
158 } else if (Utility.isMac()) {
159 command = StaticStrings.MAC_OPEN_COMMAND; // "open %1"
160 } else {
161 // we try to look for a browser
162 String [] browsers = new String [] {"mozilla", "netscape", "firefox"};
163 for (int i=0; i<browsers.length; i++) {
164 if (SafeProcess.isAvailable(browsers[i])) {
165 command = browsers[i]+ " %1";
166 break;
167 }
168 }
169 //if (command == null) { command = StaticStrings.LINUX_OPEN_COMMAND; } // "xdg-open %1"
170 }
171
172 // if we still haven't found something, prompt the user
173 if (command == null) {
174 PreviewCommandDialog dialog = new PreviewCommandDialog();
175 command = dialog.display();
176 dialog.dispose();
177 dialog = null;
178 }
179
180 // Store the result if any
181 if(command != null && !command.equals("")) {
182 Configuration.setPreviewCommand(command);
183 command = command.replaceAll(FILENAME_ARG, url);
184 DebugStream.println("Result = " + command);
185 return command;
186 }
187 // if we haven't got a command by now, we'll never get one
188 DebugStream.println("Result = null");
189 return null;
190
191 }
192
193 public int getColumnCount() {
194 return 2;
195 }
196
197 public String getColumnName(int column) {
198 String name;
199 switch(column) {
200 case 0:
201 name = Dictionary.get("FileAssociationDialog.Table.Extension");
202 break;
203 default:
204 name = Dictionary.get("FileAssociationDialog.Table.Command");
205 }
206 return name;
207 }
208
209 public String [] getCommand(File file) {
210 String command = null;
211 String [] commands = null;
212 if(file.isFile()) {
213 // Determine extension
214 String filename = file.getAbsolutePath();
215 String extension = filename.substring(filename.lastIndexOf(".") + 1);
216 // Try to retrieve a value from cache
217 Element entry = getCommand(extension);
218 if(entry != null) {
219 ///ystem.err.println("Retrieved Value From Cache");
220 command = XMLTools.getValue(entry);
221 }
222 if(command == null || command.length() == 0) {
223 ///ystem.err.println("No Existing Command");
224 // If command is null, and we are on windows try searching the registry.
225 if(Utility.isWindows()) {
226 //try the start command
227 if (Utility.isWindows9x()) {
228 command = StaticStrings.WIN_9X_OPEN_COMMAND;
229 } else {
230 command = StaticStrings.WIN_OPEN_COMMAND;
231 }
232
233 }
234
235 // If we are on a mac, default to using the open program
236 else if(Utility.isMac()) {
237 command = StaticStrings.MAC_OPEN_COMMAND;
238 }
239
240 //else { command = StaticStrings.LINUX_OPEN_COMMAND; } // If linux, default to using xdg-open
241
242 // Otherwise display the dialog and ask the user to enter launching command.
243 if(command == null || command.length() == 0) {
244 ///ystem.err.println("Show Dialog");
245 // Show the dialog which forces a user to select the launch command for a certain file.
246 FileAssociationDialog dialog = new FileAssociationDialog(this);
247 command = dialog.display(extension);
248 dialog = null;
249 }
250
251 // Hopefully by now we have a command, or else we're never going to get one. Add the association.
252 if (command != null && !command.equals("")) {
253 // If no previous entry existed create one.
254 if(entry == null) {
255 entry = associations_element.getOwnerDocument().createElement(StaticStrings.ENTRY_ELEMENT);
256 entry.setAttribute(StaticStrings.EXTENSION_ATTRIBUTE, extension);
257 associations_element.appendChild(entry);
258 }
259 // 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
260 //XMLTools.setValue(entry, command.replaceAll(filename, FILENAME_ARG));
261 XMLTools.setValue(entry, command);
262 }
263 }
264
265 if (command != null && !command.equals("")) {
266
267 // Make the command into a string []
268 commands = command.split(" ");
269
270 // Now substitute any occurrences of %1 with its filename
271 // Note this is done after the split on spaces to avoid
272 // any conflict with filenames with spaces in them.
273
274 // We have to fix filename under windows to escape the backslashes
275 filename = filename.replaceAll(ESCAPE, ESCAPED_ESCAPE);
276
277 // dealing with spaces in filepath when using start command
278 if(Utility.isWindows() && filename.indexOf(" ") != -1 && command.indexOf("start") != -1) {
279 // On Windows, start command used spaces in filepath. In this case:
280 // start and its arguments all together need to go into one element of the commands array
281 // otherwise <cmd /c start "window title" "%1"> does not work if there are spaces in the
282 // file path %1, when running the Process with a command array.
283
284 // Need <"start \"window\" \"%1\""> to be an element in the command array:
285 String[] tmp = commands;
286 int index = 0;
287
288 for(int i = 0; i < commands.length; i++) {
289 if(commands[i].indexOf("start") != -1) {
290 index = i;
291 }
292 }
293
294 commands = new String[index+1];
295 for(int i = 0; i < index; i++) {
296 commands[i] = tmp[i];
297 }
298
299 commands[index] = tmp[index];
300 for(int i = index+1; i < tmp.length; i++) {
301 commands[index] = commands[index] + " " + tmp[i];
302 }
303
304 }
305
306 for (int i=0; i<commands.length; i++) {
307 // Replace %1 with the appropriate filename
308 commands[i] = commands[i].replaceAll(FILENAME_ARG, filename);
309 }
310 }
311
312 entry = null;
313 extension = null;
314 filename = null;
315 }
316 return commands;
317 }
318
319 public Element getCommand(String target_extension) {
320 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
321 for(int i = 0; i < entries.getLength(); i++) {
322 Element entry = (Element) entries.item(i);
323 String extension = entry.getAttribute(StaticStrings.EXTENSION_ATTRIBUTE);
324 if(extension.equalsIgnoreCase(target_extension)) {
325 entries = null;
326 extension = null;
327 return entry;
328 }
329 }
330 entries = null;
331 return null;
332 }
333
334 public String getCommandString(String target_extension) {
335 Element entry = getCommand(target_extension);
336 if(entry != null) {
337 return XMLTools.getValue(entry);
338 }
339 else {
340 return "";
341 }
342 }
343
344 public String getExtension(int index) {
345 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
346 if(0 <= index && index < entries.getLength()) {
347 Element entry = (Element) entries.item(index);
348 return entry.getAttribute(StaticStrings.EXTENSION_ATTRIBUTE);
349 }
350 return "";
351 }
352
353 public int getRowCount() {
354 return size();
355 }
356
357 public Object getValueAt(int row, int column) {
358 String extension = getExtension(row);
359 switch(column) {
360 case 0:
361 return extension;
362 default:
363 return getCommandString(extension);
364 }
365 }
366
367 public void save() {
368 }
369
370 public void setCommand(String extension, String command) {
371 DebugStream.println("Set Launch: " + extension + " with " + command);
372 // Retrieve any existing entry for this extension
373 Element entry = getCommand(extension);
374 // If no previous entry existed create one.
375 if(entry == null && command != null) {
376 entry = associations_element.getOwnerDocument().createElement(StaticStrings.ENTRY_ELEMENT);
377 entry.setAttribute(StaticStrings.EXTENSION_ATTRIBUTE, extension);
378 associations_element.appendChild(entry);
379 }
380
381 if(command != null) {
382 // Replace the text in this node. If the user has used filename instead of %1 then too bad.
383 XMLTools.setValue(entry, command);
384 }
385 else {
386 // Remove the entry
387 associations_element.removeChild(entry);
388 }
389 entry = null;
390 fireTableDataChanged(); // Can't be anymore efficient as DOM does not gareuntee ordering of new child nodes is consistant
391 }
392
393 public int size() {
394 NodeList entries = associations_element.getElementsByTagName(StaticStrings.ENTRY_ELEMENT);
395 return entries.getLength();
396 }
397
398}
Note: See TracBrowser for help on using the repository browser.