source: trunk/gli/src/org/greenstone/gatherer/util/Utility.java@ 5785

Last change on this file since 5785 was 5785, checked in by mdewsnip, 20 years ago

Commented out about 60 unused functions.

  • Property svn:keywords set to Author Date Id Revision
File size: 37.2 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 index directory for the collection. */
120 static final public String INDEX_DIR = "index" + File.separator;
121 static final public String LANGUAGE_ATTRIBUTE = "language";
122 /** Definition of an important directory name, in this case the log directory for the collection. */
123 static final public String LOG_DIR = "log" + File.separator;
124 /** Definition of an important directory name, in this case the location of the expected collection metadata sets.. */
125 static final public String META_DIR = "metadata" + File.separator; // Col. Copy
126 /** Definition of an important directory name, in this case the location of the default metadata sets. */
127 static final public String METADATA_DIR = BASE_DIR + "metadata" + File.separator;
128 /** The location the gatherer expects to find metadata set information. */
129 static final public String METADATA_SET_TEMPLATE = "xml/template.mds";
130 static final public String METADATA_VALUE_TEMPLATE = "xml/template.mdv";
131 static final public String METADATA_XML = "metadata.xml";
132 static final public String NAME_ELEMENT = "Name";
133 /** The default name of the perl executable under unix. */
134 static final public String PERL_EXECUTABLE_UNIX = "perl";
135 /** The default name of the perl executable under windows. */
136 static final public String PERL_EXECUTABLE_WINDOWS = "Perl.exe";
137 /** The default profile file */
138 static final public String PROFILE_TEMPLATE = "xml/protemp.xml";
139 /** The name of the Gatherer. */
140 static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
141 /** The current version of the Gatherer. */
142 static final public String PROGRAM_VERSION = "ver 2.0";
143 /** Definition of an important directory name, in this case the location of the recycled files location. */
144 static final public String RECYCLE = BASE_DIR + "recycle" + File.separator;
145 /** Definition of an important directory name, in this case the location of image and other resources. */
146 static final public String RES_DIR = BASE_DIR + "resource" + File.separator;
147 static final public String SERVER_EXE = "server.exe";
148 /** Definition of an important directory name, in this case the location of opening (or welcome) screen html. */
149 static final public String WELCOME_DIR = BASE_DIR + "welcome" + File.separator;
150 static final public String WORKSPACE_TREE = "Workspace";
151 static final public String XML_DIRECTORY = "xml" + File.separator;
152 // These are out of alphabetic order to avoid forward reference error.
153 /** The default icon to produce a 'help-icon' sized blank space before a menu entry. */
154 static final public ImageIcon BLANK_ICON = new ImageIcon(ClassLoader.getSystemResource("images/blank.gif"));
155 /** The default error icon image. */
156 static final public ImageIcon ERROR_ICON = new ImageIcon(ClassLoader.getSystemResource("images/error.gif"));
157 static final public ImageIcon HELP_ICON = new ImageIcon(ClassLoader.getSystemResource("images/help.gif"));
158 /** The image for a toggle button whose state is 'on'. */
159 static final public ImageIcon ON_ICON = new ImageIcon(ClassLoader.getSystemResource("images/check.gif"));
160 /** The image for a toggle button whose state is 'off'. */
161 static final public ImageIcon OFF_ICON = new ImageIcon(ClassLoader.getSystemResource("images/cross.gif"));
162
163 /** Decodes a string of text so its safe to use in a Greenstone configuration file. Esentially replaces "\n" with a newline.
164 * @param raw The <strong>String</strong> before decoding, read from the configuration file..
165 * @return A <strong>String</strong> ready to be placed in a component.
166 */
167 static public String decodeGreenstone(String raw) {
168 raw = raw.replaceAll("&apos;", "\'");
169 raw = raw.replaceAll("&gt;", ">");
170 raw = raw.replaceAll("&lt;", "<");
171 raw = raw.replaceAll("&quot;", "\"");
172 raw = raw.replaceAll("&#39;", "\'");
173 raw = raw.replaceAll("\\\\n", "\n");
174 return raw;
175 }
176
177 /** 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.
178 * @param encoded The url-safe <strong>String</strong> to be decoded.
179 * @return The decoded <strong>String</strong>.
180 */
181 /* private static String decodeString(String encoded) {
182 String decoded = "";
183 for(int i = 0; i < encoded.length(); i++) {
184 if(encoded.charAt(i) == '%') {
185 if(hexidecimal(encoded.charAt(i+1)) != -1
186 && hexidecimal(encoded.charAt(i+2)) != -1) {
187 char unsafe_chr = (char)
188 ((hexidecimal(encoded.charAt(i+1)) * 16) +
189 hexidecimal(encoded.charAt(i+2)));
190 decoded = decoded + unsafe_chr;
191 i = i + 2;
192 }
193 }
194 else {
195 decoded = decoded + encoded.charAt(i);
196 }
197 }
198 return decoded;
199 } */
200 /** 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.
201 * @param file The <strong>File</strong> you want to delete.
202 * @return A <i>boolean</i> which is <i>true</i> if the file specified was successfully deleted, <i>false</i> otherwise.
203 */
204 static public boolean delete(File file) {
205 boolean result = true;
206 // If files a directory, delete files children.
207 if(file.isDirectory()) {
208 File files[] = file.listFiles();
209 for(int i = 0; files != null && result && i < files.length; i++) {
210 result = delete(files[i]);
211 }
212 }
213 if(result) {
214 // Delete file.
215 return file.delete();
216 }
217 return result;
218 }
219
220 /* static private String encodeGreenstone(String raw) {
221 raw = raw.replaceAll("<", "&lt;");
222 raw = raw.replaceAll(">", "&gt;");
223 raw = raw.replaceAll("\n", "\\\\n");
224 return raw;
225 } */
226
227 /** 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. */
228 static public boolean export(Document document, String filename) {
229 return export(document, new File(filename));
230 }
231
232 static public boolean export(Document document, File file) {
233 try {
234 OutputStream os = new FileOutputStream(file);
235 // Create an output format for our document.
236 OutputFormat f = new OutputFormat(document);
237 f.setEncoding(ENCODING);
238 f.setIndenting(true);
239 f.setLineWidth(0); // Why isn't this working!
240 f.setPreserveSpace(false);
241 // Create the necessary writer stream for serialization.
242 OutputStreamWriter osw = new OutputStreamWriter(os, ENCODING);
243 Writer w = new BufferedWriter(osw);
244 // Generate a new serializer from the above.
245 XMLSerializer s = new XMLSerializer(w, f);
246 s.asDOMSerializer();
247 // Finally serialize the document to file.
248 s.serialize(document);
249 // And close.
250 os.close();
251 return true;
252 }
253 // 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.
254 catch (FileNotFoundException fnf_exception) {
255 if(!file.getName().endsWith(METADATA_XML)) {
256 fnf_exception.printStackTrace();
257 return false;
258 }
259 return true;
260 }
261 catch (IOException ioe) {
262 ioe.printStackTrace();
263 return false;
264 }
265 }
266
267 /** Given a starting directory, searches for the collect.cfg file and returns it if found.
268 * @return The collect.cfg File or null if not found.
269 */
270 static final public File findConfigFile(File start) {
271 if(start == null) {
272 return null;
273 }
274 // See if the collect.cfg files here.
275 File collect_cfg = new File(start, "collect.cfg");
276 if(collect_cfg.exists()) {
277 return collect_cfg;
278 }
279 // Search for the existance of collect.cfg in a etc directory.
280 File etc_dir = new File(start, "etc" + File.separator + "collect.cfg");
281 if(etc_dir.exists()) {
282 return etc_dir;
283 }
284 // Otherwise search this directories parent if its not null.
285 return findConfigFile(start.getParentFile());
286 }
287
288 /** Convert a long, detailing the length of a file in bytes, into a nice human readable string using b, kb, Mb and Gb. */
289 static final public String BYTE_SUFFIX = " b";
290 static final public long GIGABYTE = 1024000000l;
291 static final public String GIGABYTE_SUFFIX = " Gb";
292 static final public long KILOBYTE = 1024l;
293 static final public String KILOBYTE_SUFFIX = " kb";
294 static final public long MEGABYTE = 1024000l;
295 static final public String MEGABYTE_SUFFIX = " mb";
296 static final public String formatFileLength(long length) {
297 StringBuffer result = new StringBuffer("");
298 float number = 0f;
299 String suffix = null;
300 // Determine the floating point number and the suffix (radix) used.
301 if(length >= GIGABYTE) {
302 number = (float) length / (float) GIGABYTE;
303 suffix = GIGABYTE_SUFFIX;
304 }
305 else if(length >= MEGABYTE) {
306 number = (float) length / (float) MEGABYTE;
307 suffix = MEGABYTE_SUFFIX;
308 }
309 else if(length >= KILOBYTE) {
310 number = (float) length / (float) KILOBYTE;
311 suffix = KILOBYTE_SUFFIX;
312 }
313 else {
314 // Don't need to do anything fancy if the file is smaller than a kilobyte
315 return length + BYTE_SUFFIX;
316 }
317 // 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.
318 String number_str = Float.toString(number);
319 char number_char[] = number_str.toCharArray();
320 int pos = 0;
321 // Print the characters up to the '.'
322 while(number_char != null && pos < number_char.length && number_char[pos] != '.') {
323 result.append(number_char[pos]);
324 pos++;
325 }
326 if(pos < number_char.length) {
327 // Print the '.' and at most two characters after it
328 result.append(number_char[pos]);
329 pos++;
330 for(int i = 0; i < 2 && pos < number_char.length; i++, pos++) {
331 result.append(number_char[pos]);
332 }
333 // Search through the remaining string for 'E'
334 while(pos < number_char.length && number_char[pos] != 'E') {
335 pos++;
336 }
337 // If we still have string then we found an E. Copy the remaining string.
338 while(pos < number_char.length) {
339 result.append(number_char[pos]);
340 pos++;
341 }
342 }
343 // Add suffix
344 result.append(suffix);
345 // Done
346 return result.toString();
347 }
348
349 /** This method formats a given string, using HTML markup, so its width does not exceed the given width and its appearance if justified.
350 * @param text The <strong>String</strong> requiring formatting.
351 * @param width The maximum width per line as an <i>int</i>.
352 * @return A <strong>String</strong> formatted so as to have no line longer than the specified width.
353 * 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.
354 */
355 static public String formatHTMLWidth(String text, int width) {
356 HTMLStringTokenizer html = new HTMLStringTokenizer(text);
357 int current_width = 0;
358 int threshold = width / 2;
359 Stack lines = new Stack();
360 String line = "";
361 while(html.hasMoreTokens()) {
362 String token = html.nextToken();
363 while(token != null) {
364 if(html.isTag()) {
365 // Insert smart HTML tag code here.
366 token = null;
367 }
368 else {
369 // If the token is bigger than two thirds width, before we've even started break it down.
370 if(current_width + 1 + token.length() > width && token.length() > threshold) {
371 String prefix = token.substring(0, width - 1 - current_width);
372 token = token.substring(prefix.length());
373 if(current_width == 0) {
374 line = line + prefix;
375 }
376 else {
377 line = line + " " + prefix;
378 }
379 lines.push(line);
380 line = "";
381 current_width = 0;
382 }
383 // If adding the next token would push us over the maximum line width.
384 else if(current_width + 1 + token.length() > width) {
385 line = space(line, width, current_width);
386 lines.push(line);
387 line = token;
388 current_width = token.length();
389 token = null;
390 }
391 // Otherwise we should be able to just add the token, give or take.
392 else {
393 if(current_width == 0) {
394 line = line + token;
395 current_width = token.length();
396 }
397 else {
398 // Special case for standard punctuation which may exist after a tag like so:
399 // My name is <scratchy>Slim Shady</scratchy>. <-- Annoying punctuation.
400 if(token.equals(".") || token.equals(",") || token.equals("!") || token.equals("?")) {
401 line = line + token;
402 current_width = current_width + 1;
403 }
404 else {
405 line = line + " " + token;
406 current_width = current_width + 1 + token.length();
407 }
408 }
409 token = null;
410 }
411 }
412 }
413 }
414 String result = line;
415 while(!lines.empty()) {
416 result = (String)lines.pop() + "<BR>" + result;
417 }
418 // Replace ' ' with "&nbsp;"
419 boolean tag = false;
420 int pos = 0;
421 while(pos < result.length()) {
422 if(result.charAt(pos) == '<') {
423 tag = true;
424 }
425 else if(result.charAt(pos) == '>') {
426 tag = false;
427 }
428 else if(result.charAt(pos) == ' ' && !tag) {
429 String prefix = result.substring(0, pos);
430 String suffix = result.substring(pos + 1);
431 result = prefix + "&nbsp;" + suffix;
432 }
433 pos++;
434 }
435 result = "<HTML>" + result + "</HTML>";
436 return result;
437 }
438 /** Format the given filename path string so that it is no longer than the given width. If it is wider replace starting directories with ...
439 * @param key The key <strong>String</Strong> used to retrieve a phrase from the dictionary for this item.
440 * @param raw The raw filename path <strong>String</strong>.
441 * @param width The maximum width as an <i>int</i>.
442 * @return A path <strong>String</strong> no longer than width.
443 */
444 static public String formatPath(String key, String raw, int width) {
445 JLabel label = new JLabel(Dictionary.get(key, raw));
446 int position = -1;
447 while(label.getPreferredSize().width > width && (position = raw.indexOf(File.separator)) != -1) {
448 raw = "..." + raw.substring(position + 1);
449 label.setText(Dictionary.get(key, raw));
450 }
451 if(raw.indexOf(File.separator) == -1 && raw.startsWith("...")) {
452 raw = raw.substring(3);
453 }
454 return raw;
455 }
456
457 /** Method which constructs the archive directory given a certain collection.
458 * @param col_dir The location of the collection directory as a <strong>String</strong>.
459 * @return The location of the given collections archive directory, also as a <strong>String</strong>.
460 */
461 static public String getArchiveDir(String gsdl_path, String col_name) {
462 return gsdl_path + File.separator + COL_DIR + col_name + File.separator + ARCHIVE_DIR;
463 }
464 /** Method which constructs the build directory given a certain collection.
465 * @param col_dir The location of the collection directory as a <strong>String</strong>.
466 * @return The location of the given collections build directory, also as a <strong>String</strong>.
467 */
468 static public String getBuildDir(String col_dir) {
469 if(col_dir == null) {
470 return BASE_DIR + BUILD_DIR;
471 }
472 return col_dir + BUILD_DIR;
473 }
474 /** Builds the private cache dir by appending col_dir and 'cache'.
475 * @param col_dir A String representing the directory path of the current collection.
476 * @return A String representing the path to the private file cache within the current collection.
477 */
478 public static String getCacheDir(String col_dir) {
479 return col_dir + GCACHE_DIR;
480 }
481 /** Method which constructs the collection directory for Greenstone.
482 * @param gsdl_path The location of the gsdl installation directory as a <strong>String</strong>.
483 * @return The location of the collection directory, also as a <strong>String</strong>.
484 */
485 public static String getCollectionDir(String gsdl_path) {
486 return gsdl_path + COL_DIR;
487 }
488 /** Method which constructs the configuration file given a certain collection.
489 * @param col_dir The location of the collection directory as a <strong>String</strong>.
490 * @return The location of the given collections configuration file, also as a <strong>String</strong>.
491 */
492 static public String getConfigDir(String col_dir) {
493 return col_dir + CONFIG_DIR;
494 }
495
496 static public String getDateString() {
497 Calendar current = Calendar.getInstance();
498 String day_name = null;
499 switch(current.get(Calendar.DAY_OF_WEEK)) {
500 case Calendar.MONDAY: day_name = "Dates.Mon"; break;
501 case Calendar.TUESDAY: day_name = "Dates.Tue"; break;
502 case Calendar.WEDNESDAY: day_name = "Dates.Wed"; break;
503 case Calendar.THURSDAY: day_name = "Dates.Thu"; break;
504 case Calendar.FRIDAY: day_name = "Dates.Fri"; break;
505 case Calendar.SATURDAY: day_name = "Dates.Sat"; break;
506 case Calendar.SUNDAY: day_name = "Dates.Sun"; break;
507 default: day_name = "";
508 }
509 String month_name = null;
510 switch(current.get(Calendar.MONTH)) {
511 case Calendar.JANUARY: month_name = "Dates.Jan"; break;
512 case Calendar.FEBRUARY: month_name = "Dates.Feb"; break;
513 case Calendar.MARCH: month_name = "Dates.Mar"; break;
514 case Calendar.APRIL: month_name = "Dates.Apr"; break;
515 case Calendar.MAY: month_name = "Dates.May"; break;
516 case Calendar.JUNE: month_name = "Dates.Jun"; break;
517 case Calendar.JULY: month_name = "Dates.Jul"; break;
518 case Calendar.AUGUST: month_name = "Dates.Aug"; break;
519 case Calendar.SEPTEMBER: month_name = "Dates.Sep"; break;
520 case Calendar.OCTOBER: month_name = "Dates.Oct"; break;
521 case Calendar.NOVEMBER: month_name = "Dates.Nov"; break;
522 case Calendar.DECEMBER: month_name = "Dates.Dec"; break;
523 default: month_name = "";
524 }
525 int day = current.get(Calendar.DAY_OF_MONTH);
526 int hour = current.get(Calendar.HOUR_OF_DAY);
527 int minute = current.get(Calendar.MINUTE);
528 int second = current.get(Calendar.SECOND);
529 int year = current.get(Calendar.YEAR);
530
531 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);
532 }
533
534 /** Retrieves and formats the depth field of the config file to four characters.
535 * @param length The length of the desired string as an <i>int</i>.
536 * @return A <strong>String</strong> representation of the mirroring depth padded to length characters.
537 */
538 /* private static String getDepthString(int length) {
539 return pad("" + Gatherer.self.config.getInt("mirroring.depth", false), length);
540 } */
541 /** Method which constructs the etc directory given a certain collection.
542 * @param col_dir The location of the collection directory as a <strong>String</strong>.
543 * @return The location of the given collections etc directory, also as a <strong>String</strong>.
544 */
545 public static String getEtcDir(String col_dir) {
546 return col_dir + ETC_DIR;
547 }
548 /** Method to retrieve an image icon with the given filename found in classpath or the resouces directory.
549 * @return The specified <strong>ImageIcon</strong>, or an error image replacement if no such images exists.
550 */
551 static public ImageIcon getImage(String filename) {
552 ImageIcon image = null;
553 try {
554 image = new ImageIcon(ClassLoader.getSystemResource("images/" + Dictionary.get("Version") + "/" + filename));
555 }
556 catch(NullPointerException exception) {
557 image = new ImageIcon(ClassLoader.getSystemResource("images/" + filename));
558 }
559 if(image == null) {
560 image = ERROR_ICON;
561 }
562 return image;
563 }
564
565 /** Method which constructs the import directory given a certain collection.
566 * @param col_dir The location of the collection directory as a <strong>String</strong>.
567 * @return The location of the given collections import directory, also as a <strong>String</strong>.
568 */
569 public static String getImportDir(String col_dir) {
570 return col_dir + IMPORT_DIR;
571 }
572 /** Method which constructs the index directory given a certain collection.
573 * @param col_dir The location of the collection directory as a <strong>String</strong>.
574 * @return The location of the given collections index directory, also as a <strong>String</strong>.
575 */
576 static public String getIndexDir(String col_dir) {
577 return col_dir + INDEX_DIR;
578 }
579 /** Method which constructs the log directory given a certain collection.
580 * @param col_dir The location of the collection directory as a <strong>String</strong>.
581 * @return The location of the given collections log directory, also as a <strong>String</strong>.
582 */
583 public static String getLogDir(String col_dir) {
584 return col_dir + LOG_DIR;
585 }
586 /** Determine this machines name.
587 * @return The name as a <strong>String</strong>.
588 */
589 static public String getMachineName() {
590 try {
591 return InetAddress.getLocalHost().getHostName();
592 }
593 catch(UnknownHostException ex) {
594 }
595 return "Unknown Machine";
596 }
597 /** Method which constructs the metadata directory given a certain collection.
598 * @param col_dir The location of the collection directory as a <strong>String</strong>.
599 * @return The location of the given collections metadata directory, also as a <strong>String</strong>.
600 */
601 static public String getMetadataDir(String col_dir) {
602 return col_dir + META_DIR;
603 }
604
605
606 /* static private File getRecycleDirectory() {
607 return new File(RECYCLE);
608 } */
609
610 /** Determine whether a character is a hexidecimal one.
611 * @param chr The <i>char</i> in question.
612 * @return An <i>int</i> representing the value of the hexidecimal character or -1 if not a hexidecimal.
613 */
614 static private int hexidecimal(char chr) {
615 switch(chr) {
616 case '0':
617 return 0;
618 case '1':
619 return 1;
620 case '2':
621 return 2;
622 case '3':
623 return 3;
624 case '4':
625 return 4;
626 case '5':
627 return 5;
628 case '6':
629 return 6;
630 case '7':
631 return 7;
632 case '8':
633 return 8;
634 case '9':
635 return 9;
636 case 'A':
637 return 10;
638 case 'B':
639 return 11;
640 case 'C':
641 return 12;
642 case 'D':
643 return 13;
644 case 'E':
645 return 14;
646 case 'F':
647 return 15;
648 default:
649 return -1;
650 }
651 }
652
653 /** A string is a valid hierarchy index if it matches '[0-9](\.[0-9])*' */
654 static public boolean isIndex(String raw) {
655 boolean result = true;
656 for(int i = 0; result && i < raw.length(); i++) {
657 char c = raw.charAt(i);
658 if(Character.isDigit(c) || (c == '.' && (i != 0 || i != raw.length() - 1))) {
659 // Valid index
660 }
661 else {
662 result = false;
663 }
664 }
665 return result;
666 }
667
668 /** Determines if the given file is a descendant of the folder described.
669 * @param pos_parent the possible parent folder as a String
670 * @param child the child File which we are checking
671 * @return true if the child is a descendant of the pos_parent, false otherwise
672 */
673 static public boolean isParentFolderOf(String pos_parent, File child) {
674 while(child != null) {
675 if(pos_parent.equals(child.getAbsolutePath())) {
676 return true;
677 }
678 // 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.
679 child = child.getParentFile();
680 }
681 return false;
682 }
683
684 /** Method to determine if the host system is Microsoft Windows based.
685 * @return A <i>boolean</i> which is <i>true</i> if the platform is Windows, <i>false</i> otherwise.
686 */
687 public static boolean isWindows() {
688 Properties props = System.getProperties();
689 String os_name = props.getProperty("os.name","");
690 if(os_name.startsWith("Windows")) {
691 return true;
692 }
693 return false;
694 }
695 /** Takes a string and a desired length and pads out the string to the length by adding spaces to the left.
696 * @param str The target <strong>String</strong> that needs to be padded.
697 * @param length The desired length of the string as an <i>int</i>.
698 * @return A <strong>String</strong> made from appending space characters with the string until it has a length equal to length.
699 */
700 public static String pad(String str, int length) {
701 return pad(str, length, ' ', true);
702 }
703 public static String pad(String str_raw, int length, char fill, boolean end) {
704 StringBuffer str = new StringBuffer(str_raw);
705 while(str.length() < length) {
706 if(end) {
707 str.insert(0, fill);
708 }
709 else {
710 str.append(fill);
711 }
712 }
713 return str.toString();
714 }
715
716 /** 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. */
717 static public Document parse(String filename, boolean use_classloader) {
718 File file = null;
719 if(use_classloader) {
720 try {
721 URL url = ClassLoader.getSystemResource(filename);
722 file = new File(URLDecoder.decode(url.getFile(), ENCODING));
723 url = null;
724 }
725 catch (Exception error) {
726 // Most likely file name.
727 file = new File("classes" + File.separator + filename);
728 //Gatherer.printStackTrace(error);
729 }
730 }
731 if(file == null) {
732 file = new File(filename);
733 }
734 return parse(file, true);
735 }
736 /** Parse in a xml document from a given file. */
737 static public Document parse(File file) {
738 return parse(file, true);
739 }
740 /** Parse in a xml document from a given file. */
741 static public Document parse(File file, boolean noisey) {
742 Document document = null;
743 try {
744 FileInputStream fis = new FileInputStream(file);
745 InputStreamReader isr = new InputStreamReader(fis, ENCODING);
746 Reader r = new BufferedReader(isr);
747 InputSource isc = new InputSource(r);
748 DOMParser parser = new DOMParser();
749 parser.setFeature("http://xml.org/sax/features/validation", false);
750 parser.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
751 // May or may not be ignored, the documentation for Xerces is contradictory. If it works then parsing -should- be faster.
752 parser.setFeature("http://apache.org/xml/features/dom/defer-node-expansion", true);
753 parser.setFeature("http://apache.org/xml/features/dom/include-ignorable-whitespace", false);
754 parser.parse(isc);
755 document = parser.getDocument();
756 isr.close();
757 fis.close();
758 parser = null;
759 isc = null;
760 r = null;
761 isr = null;
762 fis = null;
763 file = null;
764 }
765 catch (Exception error) {
766 if(noisey) {
767 error.printStackTrace();
768 Gatherer.printStackTrace(error);
769 }
770 }
771 return document;
772 }
773
774 /** 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.
775 * @param original The <strong>String</strong> to justify.
776 * @param width The desired width as an <i>int</i>.
777 * @param current_width An <i>int</i> representing the current width of the string, which takes into account special characters.
778 * @return The newly justified <strong>String</strong>.
779 */
780 static public String space(String original, int width, int current_width) {
781 // Strip trailing whitespace.
782 while(original.charAt(original.length() - 1) == ' ') {
783 original = original.substring(0, original.length() - 2);
784 }
785 int diff = width - current_width;
786 // Now add diff spaces, one at each existing space.
787 int pos = 0;
788 while(diff > 0) {
789 if(pos == original.length()) {
790 pos = 0;
791 }
792 if(original.charAt(pos) == ' ') {
793 // Insert a space.
794 String prefix = original.substring(0, pos);
795 String suffix = original.substring(pos);
796 original = prefix + " " + suffix;
797 pos = pos + 2;
798 diff--;
799 }
800 pos++;
801 }
802 return original;
803 }
804 /** 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.
805 * @param raw The <strong>Strong</strong> containing the mangled text.
806 * @return A <strong>String</strong> with new lines and extra spaces removed.
807 */
808 static public String stripNL(String raw_str) {
809 byte raw[] = raw_str.getBytes();
810 byte formatted[] = new byte[raw.length];
811 byte previous = '\0';
812 int j = 0;
813 for(int i = 0; i < raw.length; i++) {
814 if(raw[i] == '\n') {
815 // Skip new lines.
816 }
817 else if(raw[i] == '\t') {
818 // Skip tabs.
819 }
820 else if(raw[i] == ' ' && raw[i] == previous) {
821 // Skip erroneous whitespace.
822 }
823 else {
824 formatted[j] = raw[i];
825 j++;
826 }
827 previous = raw[i];
828 }
829 byte finish[] = new byte[j];
830 System.arraycopy(formatted, 0, finish, 0, j);
831 return new String(finish);
832 }
833 /** Trims the string text to the length specified removing end characters and adding if necessary.
834 * @param text A <strong>String</strong> which you wish to ensure is shorter than length.
835 * @param length An <i>int</i> specifying the strings maximum length after which its trimmed.
836 * @return The trimmed <strong>String</strong>.
837 */
838 public static String trim(String text, int length) {
839 if(text.length() > length) {
840 text = text.substring(0, length);
841 text = text + "...";
842 }
843 return text;
844 }
845
846 static public String trimCenter(String text, int length) {
847 if(text.length() > length) {
848 int half = (length - 3) / 2;
849 StringBuffer temp = new StringBuffer(text.substring(0, half));
850 temp.append("...");
851 temp.append(text.substring(text.length() - half));
852 text = temp.toString();
853 }
854 return text;
855 }
856 /** 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).
857 * @param roots A <strong>File[]</strong> containing all of the file system roots registered on this system.
858 * @return A filtered <strong>File[]</strong> containing only those drives that are accessible and/or are floppy-disk media drives.
859 */
860 /* private static File[] validateDrives(File roots[]) {
861 Vector valid = new Vector();
862 for(int i = 0; i < roots.length; i++) {
863 String name = roots[i].getAbsolutePath();
864 name = name.toLowerCase();
865 if(!name.startsWith("a:") && !name.startsWith("b:")) {
866 valid.add(roots[i]);
867 }
868 }
869 roots = new File[valid.size()];
870 for(int i = 0; i < roots.length; i++) {
871 roots[i] = (File)valid.get(i);
872 }
873 return roots;
874 } */
875}
Note: See TracBrowser for help on using the repository browser.