source: tags/gsdl-2_41-distribution/gli/src/org/greenstone/gatherer/util/Utility.java@ 6186

Last change on this file since 6186 was 5916, checked in by jmt12, 21 years ago

The getImage method can now be called with a boolean to indicate if the process should block until the image is completed - one way or the other

  • Property svn:keywords set to Author Date Id Revision
File size: 38.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 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.util;
38
39import java.awt.*;
40import java.io.*;
41import java.net.*;
42import java.util.*;
43import javax.swing.*;
44import javax.swing.tree.*;
45import org.apache.xerces.parsers.*;
46import org.apache.xml.serialize.*;
47import org.greenstone.gatherer.Dictionary;
48import org.greenstone.gatherer.Gatherer;
49import org.greenstone.gatherer.util.HTMLStringTokenizer;
50import org.w3c.dom.*;
51import org.xml.sax.*;
52
53/** To provide a library of common methods, in a static context, for use in the Gatherer.
54 * @author John Thompson, Greenstone Digital Library, University of Waikato
55 * @version 2.3b
56 */
57public class Utility {
58 static final public Dimension BUTTON_SIZE = new Dimension(160, 35);
59 static final public Dimension DOUBLE_IMAGE_BUTTON_SIZE = new Dimension(190, 35);
60 static final public Dimension LABEL_SIZE = new Dimension(150, 25);
61 /** The default size of a gatherer progress bar, in either the download view or the build view. */
62 static final public Dimension PROGRESS_BAR_SIZE = new Dimension(580,65);
63 /** The number of kilobytes to use as a io buffer. */
64 static final public int FACTOR = 1;
65 /** The size of the io buffer, calculated as FACTOR * 1024. */
66 static final public int BUFFER_SIZE = FACTOR * 1024;
67 /** Definition of an important directory name, in this case the archive directory for the collection. */
68 static final public String ARCHIVE_DIR = "archives" + File.separator;
69 /** Definition of an important directory name, in this case the base dir, or the working directory of the Gatherer. */
70 static final public String BASE_DIR = System.getProperty("user.dir") + File.separator;
71 static final public String BUILD_CFG_FILENAME = "build.cfg";
72 /** Definition of an important directory name, in this case the building directory for the collection. */
73 static final public String BUILD_DIR = "building" + File.separator;
74 /** Definition of an important directory name, in this case the public web cache for the Gatherer. */
75 static final public String CACHE_DIR = BASE_DIR + "cache" + File.separator;
76 static final public String CFG_COLLECTIONMETA_COLLECTIONNAME = "collectionmeta\tcollectionname";
77 static final public String CFG_COLLECTIONMETA_COLLECTIONEXTRA = "collectionmeta\tcollectionextra";
78 static final public String CFG_COLLECTIONMETA_ICONCOLLECTION = "collectionmeta\ticoncollection";
79 static final public String CFG_CLASSIFY = "classify";
80 static final public String CFG_CLASSIFY_BUTTONNAME = "-buttonname";
81 static final public String CFG_CLASSIFY_HFILE = "-hfile";
82 static final public String CFG_CLASSIFY_METADATA = "-metadata";
83 static final public String CFG_CLASSIFY_SORT = "-sort";
84 static final public String CFG_CREATOR = "creator";
85 static final public String CFG_FORMAT = "format";
86 static final public String CFG_MAINTAINER = "maintainer";
87 /** Definition of an important directory name, in this case the parent directory of all the collections in the gsdl. */
88 static final public String COL_DIR = "collect" + File.separator;
89 static final public String COLLECTION_DEMO = "greenstone demo";
90 static final public String COLLECTION_DEMO_DIRECTORY = "demo" + File.separator;
91 static final public String COLLECTION_DLS = "Development Library Subset";
92 static final public String COLLECTION_DLS_DIRECTORY = "dls" + File.separator;
93 static final public String COLLECTION_TREE = "Collection";
94 /** Definition of an important directory name, in this case the file the collection configuration is expect to be in. */
95 static final public String CONFIG_DIR = "etc" + File.separator + "collect.cfg";
96 /** The default file name for the urls missing any file. */
97 static final public String DEFAULT_FILE = "index.html";
98 static final public String DEFAULT_NAMESPACE = "gsp";
99 /** The default protocol header for those urls missing any protocol. */
100 static final public String DEFAULT_PROTOCOL = "http://";
101 /** The default dictionary to load. */
102 static final public String DICTIONARY = "dictionary";
103 static final public String DLS_MDS = "dls.mds";
104 static final public String ENCODING = "UTF-8";
105 static final public String ENGLISH_VALUE = "en";
106 /** Definition of an important directory name, in this case the etc (or extra information) directory for the collection. */
107 static final public String ETC_DIR = "etc" + File.separator;
108 static final public String EXTRACTED_METADATA_NAMESPACE = "ex";
109 /** The location of the default greenstone metadata file. */
110 static final public String GREENSTONEDIRECTORYMETADATA_TEMPLATE = "xml/metadata.xml";
111 /** Definition of an important directory name, in this case the private web cache directory for the collection. */
112 static final public String GCACHE_DIR = "cache" + File.separator;
113 static final public String GLI_ARCHIVE = "GLI.jar";
114 static final public String GLI_EXTENSION = ".col";
115 /** Definition of an important directory name, in this case the location of help documentation. */
116 static final public String HELP_DIR = BASE_DIR + "help" + File.separator;
117 /** Definition of an important directory name, in this case the import directory for the collection. */
118 static final public String IMPORT_DIR = "import" + File.separator;
119 /** Definition of an important directory name, in this case the backup import directory for the collection. */
120 static final public String IMPORT_BAK_DIR = "import.bak" + File.separator;
121 /** Definition of an important directory name, in this case the index directory for the collection. */
122 static final public String INDEX_DIR = "index" + File.separator;
123 static final public String LANGUAGE_ATTRIBUTE = "language";
124 /** Definition of an important directory name, in this case the log directory for the collection. */
125 static final public String LOG_DIR = "log" + File.separator;
126 /** Definition of an important directory name, in this case the location of the expected collection metadata sets.. */
127 static final public String META_DIR = "metadata" + File.separator; // Col. Copy
128 /** Definition of an important directory name, in this case the location of the default metadata sets. */
129 static final public String METADATA_DIR = BASE_DIR + "metadata" + File.separator;
130 /** The location the gatherer expects to find metadata set information. */
131 static final public String METADATA_SET_TEMPLATE = "xml/template.mds";
132 static final public String METADATA_VALUE_TEMPLATE = "xml/template.mdv";
133 static final public String METADATA_XML = "metadata.xml";
134 static final public String NAME_ELEMENT = "Name";
135 /** The default name of the perl executable under unix. */
136 static final public String PERL_EXECUTABLE_UNIX = "perl";
137 /** The default name of the perl executable under windows. */
138 static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
139 /** The default profile file */
140 static final public String PROFILE_TEMPLATE = "xml/protemp.xml";
141 /** The name of the Gatherer. */
142 static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
143 /** The current version of the Gatherer. */
144 static final public String PROGRAM_VERSION = "v2.41";
145 /** Definition of an important directory name, in this case the location of the recycled files location. */
146 static final public String RECYCLE = BASE_DIR + "recycle" + File.separator;
147 /** Definition of an important directory name, in this case the location of image and other resources. */
148 static final public String RES_DIR = BASE_DIR + "resource" + File.separator;
149 static final public String SERVER_EXE = "server.exe";
150 /** Definition of an important directory name, in this case the location of opening (or welcome) screen html. */
151 static final public String WELCOME_DIR = BASE_DIR + "welcome" + File.separator;
152 static final public String WORKSPACE_TREE = "Workspace";
153 static final public String XML_DIRECTORY = "xml" + File.separator;
154 // These are out of alphabetic order to avoid forward reference error.
155 /** The default icon to produce a 'help-icon' sized blank space before a menu entry. */
156 static final public ImageIcon BLANK_ICON = new ImageIcon(ClassLoader.getSystemResource("images/blank.gif"));
157 /** The default error icon image. */
158 static final public ImageIcon ERROR_ICON = new ImageIcon(ClassLoader.getSystemResource("images/error.gif"));
159 static final public ImageIcon HELP_ICON = new ImageIcon(ClassLoader.getSystemResource("images/help.gif"));
160 /** The image for a toggle button whose state is 'on'. */
161 static final public ImageIcon ON_ICON = new ImageIcon(ClassLoader.getSystemResource("images/check.gif"));
162 /** The image for a toggle button whose state is 'off'. */
163 static final public ImageIcon OFF_ICON = new ImageIcon(ClassLoader.getSystemResource("images/cross.gif"));
164
165 /** Decodes a string of text so its safe to use in a Greenstone configuration file. Esentially replaces "\n" with a newline.
166 * @param raw The <strong>String</strong> before decoding, read from the configuration file..
167 * @return A <strong>String</strong> ready to be placed in a component.
168 */
169 static public String decodeGreenstone(String raw) {
170 raw = raw.replaceAll("&apos;", "\'");
171 raw = raw.replaceAll("&gt;", ">");
172 raw = raw.replaceAll("&lt;", "<");
173 raw = raw.replaceAll("&quot;", "\"");
174 raw = raw.replaceAll("&#39;", "\'");
175 raw = raw.replaceAll("\\\\n", "\n");
176 return raw;
177 }
178
179 /** Takes a rfc2616 'safe' String and translates it back into its 'unsafe' form. Basically the native c wget decode_string() function, but without pointer stuff. If searches through the String looking for the pattern %xy where x and y are hexidecimal digits and where xy maps to a character.<BR> If x or y are not hexidecimal or % is followed by a \0 then the pattern is left as is.
180 * @param encoded The url-safe <strong>String</strong> to be decoded.
181 * @return The decoded <strong>String</strong>.
182 */
183 /* private static String decodeString(String encoded) {
184 String decoded = "";
185 for(int i = 0; i < encoded.length(); i++) {
186 if(encoded.charAt(i) == '%') {
187 if(hexidecimal(encoded.charAt(i+1)) != -1
188 && hexidecimal(encoded.charAt(i+2)) != -1) {
189 char unsafe_chr = (char)
190 ((hexidecimal(encoded.charAt(i+1)) * 16) +
191 hexidecimal(encoded.charAt(i+2)));
192 decoded = decoded + unsafe_chr;
193 i = i + 2;
194 }
195 }
196 else {
197 decoded = decoded + encoded.charAt(i);
198 }
199 }
200 return decoded;
201 } */
202 /** It turns out that in Java you have to make sure a directory is empty before you delete it (much like unix I suppose), and so just like unix I'll have to set up a recursive delete function.
203 * @param file The <strong>File</strong> you want to delete.
204 * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
205 */
206 static public boolean delete(File file) {
207 boolean result = true;
208 // If files a directory, delete files children.
209 if(file.isDirectory()) {
210 File files[] = file.listFiles();
211 for(int i = 0; files != null && result && i < files.length; i++) {
212 result = delete(files[i]);
213 }
214 }
215 if(result) {
216 // Delete file.
217 return file.delete();
218 }
219 return result;
220 }
221
222 /* static private String encodeGreenstone(String raw) {
223 raw = raw.replaceAll("<", "&lt;");
224 raw = raw.replaceAll(">", "&gt;");
225 raw = raw.replaceAll("\n", "\\\\n");
226 return raw;
227 } */
228
229 /** Using this method we can request that a certain document be written, as valid XML, to a certain output stream. This makes use of the Xerces Serialization suite, which should in no way be confused with the usual method of Serialization used by Java. */
230 static public boolean export(Document document, String filename) {
231 return export(document, new File(filename));
232 }
233
234 static public boolean export(Document document, File file) {
235 try {
236 OutputStream os = new FileOutputStream(file);
237 // Create an output format for our document.
238 OutputFormat f = new OutputFormat(document);
239 f.setEncoding(ENCODING);
240 f.setIndenting(true);
241 f.setLineWidth(0); // Why isn't this working!
242 f.setPreserveSpace(false);
243 // Create the necessary writer stream for serialization.
244 OutputStreamWriter osw = new OutputStreamWriter(os, ENCODING);
245 Writer w = new BufferedWriter(osw);
246 // Generate a new serializer from the above.
247 XMLSerializer s = new XMLSerializer(w, f);
248 s.asDOMSerializer();
249 // Finally serialize the document to file.
250 s.serialize(document);
251 // And close.
252 os.close();
253 return true;
254 }
255 // A file not found exception is most likely thrown because the directory the metadata.xml file is attempting to be written to no longer has any files in it. I'll add a test in GDMDocument to test for this, but if it still happens ignore it (a non-existant directory can't really have metadata added to it any way.
256 catch (FileNotFoundException fnf_exception) {
257 if(!file.getName().endsWith(METADATA_XML)) {
258 fnf_exception.printStackTrace();
259 return false;
260 }
261 return true;
262 }
263 catch (IOException ioe) {
264 ioe.printStackTrace();
265 return false;
266 }
267 }
268
269 /** Given a starting directory, searches for the collect.cfg file and returns it if found.
270 * @return The collect.cfg File or null if not found.
271 */
272 static final public File findConfigFile(File start) {
273 if(start == null) {
274 return null;
275 }
276 // See if the collect.cfg files here.
277 File collect_cfg = new File(start, "collect.cfg");
278 if(collect_cfg.exists()) {
279 return collect_cfg;
280 }
281 // Search for the existance of collect.cfg in a etc directory.
282 File etc_dir = new File(start, "etc" + File.separator + "collect.cfg");
283 if(etc_dir.exists()) {
284 return etc_dir;
285 }
286 // Otherwise search this directories parent if its not null.
287 return findConfigFile(start.getParentFile());
288 }
289
290 /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
291 static final public String BYTE_SUFFIX = " b";
292 static final public long GIGABYTE = 1024000000l;
293 static final public String GIGABYTE_SUFFIX = " Gb";
294 static final public long KILOBYTE = 1024l;
295 static final public String KILOBYTE_SUFFIX = " kb";
296 static final public long MEGABYTE = 1024000l;
297 static final public String MEGABYTE_SUFFIX = " mb";
298 static final public String formatFileLength(long length) {
299 StringBuffer result = new StringBuffer("");
300 float number = 0f;
301 String suffix = null;
302 // Determine the floating point number and the suffix (radix) used.
303 if(length >= GIGABYTE) {
304 number = (float) length / (float) GIGABYTE;
305 suffix = GIGABYTE_SUFFIX;
306 }
307 else if(length >= MEGABYTE) {
308 number = (float) length / (float) MEGABYTE;
309 suffix = MEGABYTE_SUFFIX;
310 }
311 else if(length >= KILOBYTE) {
312 number = (float) length / (float) KILOBYTE;
313 suffix = KILOBYTE_SUFFIX;
314 }
315 else {
316 // Don't need to do anything fancy if the file is smaller than a kilobyte
317 return length + BYTE_SUFFIX;
318 }
319 // Create the formatted string remembering to round the number to 2.d.p. To do this copy everything in the number string from the start to the first occurance of '.' then copy two more digits. Finally search for and print anything that appears after (and including) the optional 'E' delimter.
320 String number_str = Float.toString(number);
321 char number_char[] = number_str.toCharArray();
322 int pos = 0;
323 // Print the characters up to the '.'
324 while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
325 result.append(number_char[pos]);
326 pos++;
327 }
328 if(pos < number_char.length) {
329 // Print the '.' and at most two characters after it
330 result.append(number_char[pos]);
331 pos++;
332 for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
333 result.append(number_char[pos]);
334 }
335 // Search through the remaining string for 'E'
336 while(pos < number_char.length && number_char[pos] != 'E') {
337 pos++;
338 }
339 // If we still have string then we found an E. Copy the remaining string.
340 while(pos < number_char.length) {
341 result.append(number_char[pos]);
342 pos++;
343 }
344 }
345 // Add suffix
346 result.append(suffix);
347 // Done
348 return result.toString();
349 }
350
351 /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
352 * @param text The <strong>String</strong> requiring formatting.
353 * @param width The maximum width per line as an <i>int</i>.
354 * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
355 * TODO Currently HTML formatting tags are simply removed from the text, as the effects of spreading HTML tags over a break are undetermined. To solve this we need to associate tags with a certain text token so if it gets broken on to the next line the tags go with it, or if the tags cover a sequence of words that are broken we need to close then reopen the tags. However all this is a major task and well beyond anything I have time to 'muck-round' on.
356 */
357 static public String formatHTMLWidth(String text, int width) {
358 if(text == null) {
359 return "Error";
360 }
361 HTMLStringTokenizer html = new HTMLStringTokenizer(text);
362 int current_width = 0;
363 int threshold = width / 2;
364 Stack lines = new Stack();
365 String line = "";
366 while(html.hasMoreTokens()) {
367 String token = html.nextToken();
368 while(token != null) {
369 if(html.isTag()) {
370 // Insert smart HTML tag code here.
371 token = null;
372 }
373 else {
374 // If the token is bigger than two thirds width, before we've even started break it down.
375 if(current_width + 1 + token.length() > width && token.length() > threshold) {
376 String prefix = token.substring(0, width - 1 - current_width);
377 token = token.substring(prefix.length());
378 if(current_width == 0) {
379 line = line + prefix;
380 }
381 else {
382 line = line + " " + prefix;
383 }
384 lines.push(line);
385 line = "";
386 current_width = 0;
387 }
388 // If adding the next token would push us over the maximum line width.
389 else if(current_width + 1 + token.length() > width) {
390 line = space(line, width, current_width);
391 lines.push(line);
392 line = token;
393 current_width = token.length();
394 token = null;
395 }
396 // Otherwise we should be able to just add the token, give or take.
397 else {
398 if(current_width == 0) {
399 line = line + token;
400 current_width = token.length();
401 }
402 else {
403 // Special case for standard punctuation which may exist after a tag like so:
404 // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
405 if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
406 line = line + token;
407 current_width = current_width + 1;
408 }
409 else {
410 line = line + " " + token;
411 current_width = current_width + 1 + token.length();
412 }
413 }
414 token = null;
415 }
416 }
417 }
418 }
419 String result = line;
420 while(!lines.empty()) {
421 result = (String)lines.pop() + "<BR>" + result;
422 }
423 // Replace ' ' with "&nbsp;"
424 boolean tag = false;
425 int pos = 0;
426 while(pos < result.length()) {
427 if(result.charAt(pos) == '<') {
428 tag = true;
429 }
430 else if(result.charAt(pos) == '>') {
431 tag = false;
432 }
433 else if(result.charAt(pos) == ' ' && !tag) {
434 String prefix = result.substring(0, pos);
435 String suffix = result.substring(pos + 1);
436 result = prefix + "&nbsp;" + suffix;
437 }
438 pos++;
439 }
440 result = "<HTML>" + result + "</HTML>";
441 return result;
442 }
443 /** Format the given filename path string so that it is no longer than the given width. If it is wider replace starting directories with ...
444 * @param key The key <strong>String</Strong> used to retrieve a phrase from the dictionary for this item.
445 * @param raw The raw filename path <strong>String</strong>.
446 * @param width The maximum width as an <i>int</i>.
447 * @return A path <strong>String</strong> no longer than width.
448 */
449 static public String formatPath(String key, String raw, int width) {
450 JLabel label = new JLabel(Dictionary.get(key, raw));
451 int position = -1;
452 while(label.getPreferredSize().width > width && (position = raw.indexOf(File.separator)) != -1) {
453 raw = "..." + raw.substring(position + 1);
454 label.setText(Dictionary.get(key, raw));
455 }
456 if(raw.indexOf(File.separator) == -1 && raw.startsWith("...")) {
457 raw = raw.substring(3);
458 }
459 return raw;
460 }
461
462 /** Method which constructs the archive directory given a certain collection.
463 * @param col_dir The location of the collection directory as a <strong>String</strong>.
464 * @return The location of the given collections archive directory, also as a <strong>String</strong>.
465 */
466 static public String getArchiveDir(String gsdl_path, String col_name) {
467 return gsdl_path + File.separator + COL_DIR + col_name + File.separator + ARCHIVE_DIR;
468 }
469 /** Method which constructs the build directory given a certain collection.
470 * @param col_dir The location of the collection directory as a <strong>String</strong>.
471 * @return The location of the given collections build directory, also as a <strong>String</strong>.
472 */
473 static public String getBuildDir(String col_dir) {
474 if(col_dir == null) {
475 return BASE_DIR + BUILD_DIR;
476 }
477 return col_dir + BUILD_DIR;
478 }
479 /** Builds the private cache dir by appending col_dir and 'cache'.
480 * @param col_dir A String representing the directory path of the current collection.
481 * @return A String representing the path to the private file cache within the current collection.
482 */
483 public static String getCacheDir(String col_dir) {
484 return col_dir + GCACHE_DIR;
485 }
486 /** Method which constructs the collection directory for Greenstone.
487 * @param gsdl_path The location of the gsdl installation directory as a <strong>String</strong>.
488 * @return The location of the collection directory, also as a <strong>String</strong>.
489 */
490 public static String getCollectionDir(String gsdl_path) {
491 return gsdl_path + COL_DIR;
492 }
493 /** Method which constructs the configuration file given a certain collection.
494 * @param col_dir The location of the collection directory as a <strong>String</strong>.
495 * @return The location of the given collections configuration file, also as a <strong>String</strong>.
496 */
497 static public String getConfigDir(String col_dir) {
498 return col_dir + CONFIG_DIR;
499 }
500
501 static public String getDateString() {
502 Calendar current = Calendar.getInstance();
503 String day_name = null;
504 switch(current.get(Calendar.DAY_OF_WEEK)) {
505 case Calendar.MONDAY: day_name = "Dates.Mon"; break;
506 case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
507 case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
508 case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
509 case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
510 case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
511 case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
512 default: day_name = "";
513 }
514 String month_name = null;
515 switch(current.get(Calendar.MONTH)) {
516 case Calendar.JANUARY: month_name = "Dates.Jan"; break;
517 case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
518 case Calendar.MARCH: month_name = "Dates.Mar"; break;
519 case Calendar.APRIL: month_name = "Dates.Apr"; break;
520 case Calendar.MAY: month_name = "Dates.May"; break;
521 case Calendar.JUNE: month_name = "Dates.Jun"; break;
522 case Calendar.JULY: month_name = "Dates.Jul"; break;
523 case Calendar.AUGUST: month_name = "Dates.Aug"; break;
524 case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
525 case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
526 case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
527 case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
528 default: month_name = "";
529 }
530 int day = current.get(Calendar.DAY_OF_MONTH);
531 int hour = current.get(Calendar.HOUR_OF_DAY);
532 int minute = current.get(Calendar.MINUTE);
533 int second = current.get(Calendar.SECOND);
534 int year = current.get(Calendar.YEAR);
535
536 return Dictionary.get(day_name) + " " + Dictionary.get(month_name) + " " + day + " " + year + " " + Utility.pad(String.valueOf(hour), 2, '0', true) + ":" + Utility.pad(String.valueOf(minute), 2, '0', true) + ":" + Utility.pad(String.valueOf(second), 2, '0', true);
537 }
538
539 /** Retrieves and formats the depth field of the config file to four characters.
540 * @param length The length of the desired string as an <i>int</i>.
541 * @return A <strong>String</strong> representation of the mirroring depth padded to length characters.
542 */
543 /* private static String getDepthString(int length) {
544 return pad("" + Gatherer.self.config.getInt("mirroring.depth", false), length);
545 } */
546 /** Method which constructs the etc directory given a certain collection.
547 * @param col_dir The location of the collection directory as a <strong>String</strong>.
548 * @return The location of the given collections etc directory, also as a <strong>String</strong>.
549 */
550 public static String getEtcDir(String col_dir) {
551 return col_dir + ETC_DIR;
552 }
553 /** Method to retrieve an image icon with the given filename found in classpath or the resouces directory.
554 * @return The specified <strong>ImageIcon</strong>, or an error image replacement if no such images exists.
555 */
556 static public ImageIcon getImage(String filename) {
557 return getImage(filename, false);
558 }
559
560 static public ImageIcon getImage(String filename, boolean wait_until_complete) {
561 ImageIcon image = null;
562 try {
563 image = new ImageIcon(ClassLoader.getSystemResource("images/" + Dictionary.get("Version") + "/" + filename));
564 }
565 catch(NullPointerException exception) {
566 image = new ImageIcon(ClassLoader.getSystemResource("images/" + filename));
567 }
568 if(image == null) {
569 image = ERROR_ICON;
570 }
571
572 if(wait_until_complete) {
573 int load_status;
574 do {
575 load_status = image.getImageLoadStatus();
576 }
577 while(load_status != MediaTracker.ABORTED && load_status != MediaTracker.ERRORED && load_status != MediaTracker.COMPLETE);
578 }
579 return image;
580 }
581
582 /** Method which constructs the import directory given a certain collection.
583 * @param col_dir The location of the collection directory as a <strong>String</strong>.
584 * @return The location of the given collections import directory, also as a <strong>String</strong>.
585 */
586 public static String getImportDir(String col_dir) {
587 return col_dir + IMPORT_DIR;
588 }
589 /** Method which constructs the index directory given a certain collection.
590 * @param col_dir The location of the collection directory as a <strong>String</strong>.
591 * @return The location of the given collections index directory, also as a <strong>String</strong>.
592 */
593 static public String getIndexDir(String col_dir) {
594 return col_dir + INDEX_DIR;
595 }
596 /** Method which constructs the log directory given a certain collection.
597 * @param col_dir The location of the collection directory as a <strong>String</strong>.
598 * @return The location of the given collections log directory, also as a <strong>String</strong>.
599 */
600 public static String getLogDir(String col_dir) {
601 return col_dir + LOG_DIR;
602 }
603 /** Determine this machines name.
604 * @return The name as a <strong>String</strong>.
605 */
606 static public String getMachineName() {
607 try {
608 return InetAddress.getLocalHost().getHostName();
609 }
610 catch(UnknownHostException ex) {
611 }
612 return "Unknown Machine";
613 }
614 /** Method which constructs the metadata directory given a certain collection.
615 * @param col_dir The location of the collection directory as a <strong>String</strong>.
616 * @return The location of the given collections metadata directory, also as a <strong>String</strong>.
617 */
618 static public String getMetadataDir(String col_dir) {
619 return col_dir + META_DIR;
620 }
621
622
623 /* static private File getRecycleDirectory() {
624 return new File(RECYCLE);
625 } */
626
627 /** Determine whether a character is a hexidecimal one.
628 * @param chr The <i>char</i> in question.
629 * @return An <i>int</i> representing the value of the hexidecimal character or -1 if not a hexidecimal.
630 */
631 static private int hexidecimal(char chr) {
632 switch(chr) {
633 case '0':
634 return 0;
635 case '1':
636 return 1;
637 case '2':
638 return 2;
639 case '3':
640 return 3;
641 case '4':
642 return 4;
643 case '5':
644 return 5;
645 case '6':
646 return 6;
647 case '7':
648 return 7;
649 case '8':
650 return 8;
651 case '9':
652 return 9;
653 case 'A':
654 return 10;
655 case 'B':
656 return 11;
657 case 'C':
658 return 12;
659 case 'D':
660 return 13;
661 case 'E':
662 return 14;
663 case 'F':
664 return 15;
665 default:
666 return -1;
667 }
668 }
669
670 /** A string is a valid hierarchy index if it matches '[0-9](\.[0-9])*' */
671 static public boolean isIndex(String raw) {
672 boolean result = true;
673 for(int i = 0; result && i < raw.length(); i++) {
674 char c = raw.charAt(i);
675 if(Character.isDigit(c) || (c == '.' && (i != 0 || i != raw.length() - 1))) {
676 // Valid index
677 }
678 else {
679 result = false;
680 }
681 }
682 return result;
683 }
684
685 /** Determines if the given file is a descendant of the folder described.
686 * @param pos_parent the possible parent folder as a String
687 * @param child the child File which we are checking
688 * @return true if the child is a descendant of the pos_parent, false otherwise
689 */
690 static public boolean isParentFolderOf(String pos_parent, File child) {
691 while(child != null) {
692 if(pos_parent.equals(child.getAbsolutePath())) {
693 return true;
694 }
695 // Just keep looping checking each of childs parent folders. Not a brilliantly efficient algorithm, but it should still be pretty fast compared to the algorithm for merging elements.
696 child = child.getParentFile();
697 }
698 return false;
699 }
700
701 /** Method to determine if the host system is Microsoft Windows based.
702 * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
703 */
704 public static boolean isWindows() {
705 Properties props = System.getProperties();
706 String os_name = props.getProperty("os.name","");
707 if(os_name.startsWith("Windows")) {
708 return true;
709 }
710 return false;
711 }
712 public static boolean isWindows9x() {
713 Properties props = System.getProperties();
714 String os_name = props.getProperty("os.name","");
715 if(os_name.startsWith("Windows") && os_name.indexOf("9") != -1) {
716 return true;
717 }
718 return false;
719 }
720 /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
721 * @param str The target <strong>String</strong> that needs to be padded.
722 * @param length The desired length of the string as an <i>int</i>.
723 * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
724 */
725 public static String pad(String str, int length) {
726 return pad(str, length, ' ', true);
727 }
728 public static String pad(String str_raw, int length, char fill, boolean end) {
729 StringBuffer str = new StringBuffer(str_raw);
730 while(str.length() < length) {
731 if(end) {
732 str.insert(0, fill);
733 }
734 else {
735 str.append(fill);
736 }
737 }
738 return str.toString();
739 }
740
741 /** Parse in a xml document from a given filename. Note that this filename may need to be resolved by the class loader, especially for template files within a jar. */
742 static public Document parse(String filename, boolean use_classloader) {
743 File file = null;
744 if(use_classloader) {
745 try {
746 URL url = ClassLoader.getSystemResource(filename);
747 file = new File(URLDecoder.decode(url.getFile(), ENCODING));
748 url = null;
749 }
750 catch (Exception error) {
751 // Most likely file name.
752 file = new File("classes" + File.separator + filename);
753 //Gatherer.printStackTrace(error);
754 }
755 }
756 if(file == null) {
757 file = new File(filename);
758 }
759 return parse(file, true);
760 }
761 /** Parse in a xml document from a given file. */
762 static public Document parse(File file) {
763 return parse(file, true);
764 }
765 /** Parse in a xml document from a given file. */
766 static public Document parse(File file, boolean noisey) {
767 Document document = null;
768 try {
769 FileInputStream fis = new FileInputStream(file);
770 InputStreamReader isr = new InputStreamReader(fis, ENCODING);
771 Reader r = new BufferedReader(isr);
772 InputSource isc = new InputSource(r);
773 DOMParser parser = new DOMParser();
774 parser.setFeature("http://xml.org/sax/features/validation", false);
775 parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
776 // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster.
777 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
778 parser.setFeature("http://apache.org/xml/features/dom/include-ignorable-whitespace", false);
779 parser.parse(isc);
780 document = parser.getDocument();
781 isr.close();
782 fis.close();
783 parser = null;
784 isc = null;
785 r = null;
786 isr = null;
787 fis = null;
788 file = null;
789 }
790 catch (Exception error) {
791 if(noisey) {
792 error.printStackTrace();
793 Gatherer.printStackTrace(error);
794 }
795 }
796 return document;
797 }
798
799 /** Method to spread out a line of text so that is is justified to the given width, by attempting to widen white-spacing in a balanced way.
800 * @param original The <strong>String</strong> to justify.
801 * @param width The desired width as an <i>int</i>.
802 * @param current_width An <i>int</i> representing the current width of the string, which takes into account special characters.
803 * @return The newly justified <strong>String</strong>.
804 */
805 static public String space(String original, int width, int current_width) {
806 // Strip trailing whitespace.
807 while(original.charAt(original.length() - 1) == ' ') {
808 original = original.substring(0, original.length() - 2);
809 }
810 int diff = width - current_width;
811 // Now add diff spaces, one at each existing space.
812 int pos = 0;
813 while(diff > 0) {
814 if(pos == original.length()) {
815 pos = 0;
816 }
817 if(original.charAt(pos) == ' ') {
818 // Insert a space.
819 String prefix = original.substring(0, pos);
820 String suffix = original.substring(pos);
821 original = prefix + " " + suffix;
822 pos = pos + 2;
823 diff--;
824 }
825 pos++;
826 }
827 return original;
828 }
829 /** Method to strip new lines and extra spaces from a string. Used to restore text that has been mangled into width formatted blocks by the DOM parser.
830 * @param raw The <strong>Strong</strong> containing the mangled text.
831 * @return A <strong>String</strong> with new lines and extra spaces removed.
832 */
833 static public String stripNL(String raw_str) {
834 byte raw[] = raw_str.getBytes();
835 byte formatted[] = new byte[raw.length];
836 byte previous = '\0';
837 int j = 0;
838 for(int i = 0; i < raw.length; i++) {
839 if(raw[i] == '\n') {
840 // Skip new lines.
841 }
842 else if(raw[i] == '\t') {
843 // Skip tabs.
844 }
845 else if(raw[i] == ' ' && raw[i] == previous) {
846 // Skip erroneous whitespace.
847 }
848 else {
849 formatted[j] = raw[i];
850 j++;
851 }
852 previous = raw[i];
853 }
854 byte finish[] = new byte[j];
855 System.arraycopy(formatted, 0, finish, 0, j);
856 return new String(finish);
857 }
858 /** Trims the string text to the length specified removing end characters and adding if necessary.
859 * @param text A <strong>String</strong> which you wish to ensure is shorter than length.
860 * @param length An <i>int</i> specifying the strings maximum length after which its trimmed.
861 * @return The trimmed <strong>String</strong>.
862 */
863 public static String trim(String text, int length) {
864 if(text.length() > length) {
865 text = text.substring(0, length);
866 text = text + "...";
867 }
868 return text;
869 }
870
871 static public String trimCenter(String text, int length) {
872 if(text.length() > length) {
873 int half = (length - 3) / 2;
874 StringBuffer temp = new StringBuffer(text.substring(0, half));
875 temp.append("...");
876 temp.append(text.substring(text.length() - half));
877 text = temp.toString();
878 }
879 return text;
880 }
881 /** This method checks to see what registered file system root directorys are mounted, and returns only accessible ones. The exception is removable media drives (in particular floppy-disk drives) which will throw all sorts of error if we test them here. Instead they are assumed to be always accessible, but a test is conducted at the time you attempt to map them to test for actual accessibility (then at least the errors are thrown after the user tries to initiate the mapping of the drive which has no disk in it).
882 * @param roots A <strong>File[]</strong> containing all of the file system roots registered on this system.
883 * @return A filtered <strong>File[]</strong> containing only those drives that are accessible and/or are floppy-disk media drives.
884 */
885 /* private static File[] validateDrives(File roots[]) {
886 Vector valid = new Vector();
887 for(int i = 0; i < roots.length; i++) {
888 String name = roots[i].getAbsolutePath();
889 name = name.toLowerCase();
890 if(!name.startsWith("a:") && !name.startsWith("b:")) {
891 valid.add(roots[i]);
892 }
893 }
894 roots = new File[valid.size()];
895 for(int i = 0; i < roots.length; i++) {
896 roots[i] = (File)valid.get(i);
897 }
898 return roots;
899 } */
900}
Note: See TracBrowser for help on using the repository browser.