0001: /*
0002: * Utilities.java
0003: *
0004: * Copyright (C) 1998-2004 Peter Graves
0005: * $Id: Utilities.java,v 1.37 2004/09/17 18:14:05 piso Exp $
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License
0009: * as published by the Free Software Foundation; either version 2
0010: * of the License, or (at your option) any later version.
0011: *
0012: * This program is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015: * GNU General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * along with this program; if not, write to the Free Software
0019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0020: */
0021:
0022: package org.armedbear.j;
0023:
0024: import gnu.regexp.RE;
0025: import gnu.regexp.REMatch;
0026: import gnu.regexp.UncheckedRE;
0027: import java.awt.Color;
0028: import java.awt.Component;
0029: import java.awt.Graphics;
0030: import java.awt.event.KeyEvent;
0031: import java.io.BufferedInputStream;
0032: import java.io.BufferedOutputStream;
0033: import java.io.BufferedReader;
0034: import java.io.FileOutputStream;
0035: import java.io.IOException;
0036: import java.io.InputStream;
0037: import java.io.InputStreamReader;
0038: import java.io.OutputStream;
0039: import java.io.UnsupportedEncodingException;
0040: import java.lang.reflect.InvocationTargetException;
0041: import java.lang.reflect.Method;
0042: import java.net.URL;
0043: import java.util.ArrayList;
0044: import java.util.List;
0045: import java.util.Properties;
0046: import java.util.StringTokenizer;
0047: import java.util.zip.GZIPInputStream;
0048: import java.util.zip.ZipInputStream;
0049: import javax.swing.BorderFactory;
0050: import javax.swing.BoxLayout;
0051: import javax.swing.ImageIcon;
0052: import javax.swing.JPanel;
0053: import javax.swing.KeyStroke;
0054: import javax.swing.border.Border;
0055: import javax.swing.border.TitledBorder;
0056: import org.xml.sax.XMLReader;
0057: import org.xml.sax.helpers.XMLReaderFactory;
0058:
0059: public final class Utilities implements Constants {
0060: // Returns false if the string contains any upper case letters, true
0061: // otherwise. "abc123" and "123" are lower case.
0062: public static boolean isLowerCase(String s) {
0063: for (int i = s.length() - 1; i >= 0; i--) {
0064: if (Character.isUpperCase(s.charAt(i)))
0065: return false;
0066: }
0067: return true;
0068: }
0069:
0070: // For a string to be upper case, it must have at least one upper case
0071: // letter, and no lower case letters. "ABC123" is upper case, but "123" is
0072: // not.
0073: public static boolean isUpperCase(String s) {
0074: boolean containsLetter = false;
0075: for (int i = s.length() - 1; i >= 0; i--) {
0076: char c = s.charAt(i);
0077: if (Character.isLetter(c)) {
0078: if (!Character.isUpperCase(c))
0079: return false;
0080: containsLetter = true;
0081: }
0082: }
0083: // We didn't encounter any letters that weren't upper case.
0084: return containsLetter;
0085: }
0086:
0087: public static boolean isWhitespace(String s) {
0088: for (int i = s.length() - 1; i >= 0; i--) {
0089: if (!Character.isWhitespace(s.charAt(i)))
0090: return false;
0091: }
0092: return true;
0093: }
0094:
0095: public static int countLines(String s) {
0096: int count = 0;
0097: for (int i = s.length(); i-- > 0;)
0098: if (s.charAt(i) == '\n')
0099: ++count;
0100: return count;
0101: }
0102:
0103: public static boolean isDelimited(Buffer buffer, Position pos,
0104: int length) {
0105: if (buffer != null)
0106: return isDelimited(buffer.getMode(), pos, length);
0107: else
0108: return isDelimited(pos, length);
0109: }
0110:
0111: public static boolean isDelimited(Mode mode, Position pos,
0112: int length) {
0113: if (mode == null)
0114: return isDelimited(pos, length);
0115: final int before = pos.getOffset() - 1;
0116: if (before >= 0
0117: && mode.isIdentifierPart(pos.getLine().charAt(before)))
0118: return false;
0119: final int after = pos.getOffset() + length;
0120: if (after < pos.getLineLength()
0121: && mode.isIdentifierPart(pos.getLine().charAt(after)))
0122: return false;
0123: return true;
0124: }
0125:
0126: public static boolean isDelimited(Position pos, int length) {
0127: final int before = pos.getOffset() - 1;
0128: if (before >= 0
0129: && Character.isJavaIdentifierPart(pos.getLine().charAt(
0130: before)))
0131: return false;
0132: final int after = pos.getOffset() + length;
0133: if (after < pos.getLineLength()
0134: && Character.isJavaIdentifierPart(pos.getLine().charAt(
0135: after)))
0136: return false;
0137: return true;
0138: }
0139:
0140: public static boolean isDelimited(String s, int index, int length) {
0141: final int before = index - 1;
0142: if (before >= 0
0143: && Character.isJavaIdentifierPart(s.charAt(before)))
0144: return false;
0145: final int after = index + length;
0146: if (after < s.length()
0147: && Character.isJavaIdentifierPart(s.charAt(after)))
0148: return false;
0149: return true;
0150: }
0151:
0152: public static boolean isDelimited(String s, int index, int length,
0153: Mode mode) {
0154: if (mode == null)
0155: return isDelimited(s, index, length);
0156: final int before = index - 1;
0157: if (before >= 0 && mode.isIdentifierPart(s.charAt(before)))
0158: return false;
0159: final int after = index + length;
0160: if (after < s.length()
0161: && mode.isIdentifierPart(s.charAt(after)))
0162: return false;
0163: return true;
0164: }
0165:
0166: public static boolean isDelimited(Mode mode, String s,
0167: int startIndex, int endIndex) {
0168: if (mode == null)
0169: mode = JavaMode.getMode();
0170: final int before = startIndex - 1;
0171: if (before >= 0 && mode.isIdentifierPart(s.charAt(before)))
0172: return false;
0173: if (endIndex < s.length()
0174: && mode.isIdentifierPart(s.charAt(endIndex)))
0175: return false;
0176: return true;
0177: }
0178:
0179: // Returns extension including leading '.'
0180: public static String getExtension(String filename) {
0181: int indexOfLastDot = filename.lastIndexOf('.');
0182: if (indexOfLastDot < 0)
0183: return null;
0184: int indexOfLastFileSeparatorChar = filename
0185: .lastIndexOf(LocalFile.getSeparatorChar());
0186: if (indexOfLastDot < indexOfLastFileSeparatorChar)
0187: return null; // Last dot was in path prefix.
0188: else
0189: return filename.substring(indexOfLastDot);
0190: }
0191:
0192: // Returns extension including leading '.'
0193: public static String getExtension(File file) {
0194: // Only consider last component of filename.
0195: String name = file.getName();
0196: int index = name.lastIndexOf('.');
0197: if (index < 0)
0198: return null;
0199: else
0200: return name.substring(index);
0201: }
0202:
0203: public static final File getTempFile() {
0204: return getTempFile(Directories.getTempDirectory());
0205: }
0206:
0207: public static final File getTempFile(File dir) {
0208: return getTempFile(dir, "");
0209: }
0210:
0211: public static final File getTempFile(String dir) {
0212: return getTempFile(File.getInstance(dir), "");
0213: }
0214:
0215: // Implementation.
0216: // Guarantee that getTempFile() will generate unique filenames even if
0217: // it's called twice with the same value of System.currentTimeMillis().
0218: private static int tempFileCount = 0;
0219:
0220: public static synchronized File getTempFile(File dir,
0221: String extension) {
0222: if (dir == null)
0223: return null;
0224:
0225: if (extension == null) {
0226: extension = "";
0227: } else if (extension.length() > 0) {
0228: if (extension.charAt(0) != '.')
0229: extension = ".".concat(extension);
0230: }
0231:
0232: long date = System.currentTimeMillis();
0233:
0234: for (int i = 0; i < 100; i++) {
0235: File file = File.getInstance(dir, String.valueOf(
0236: date + tempFileCount).concat(extension));
0237: ++tempFileCount;
0238: if (!file.exists())
0239: return file;
0240: }
0241:
0242: return null;
0243: }
0244:
0245: public static boolean isDirectoryWritable(File dir) {
0246: boolean isWritable = false;
0247: File file = getTempFile(dir);
0248: if (file != null) {
0249: try {
0250: // getOutputStream() will throw FileNotFoundException if
0251: // directory is not writable.
0252: FileOutputStream out = file.getOutputStream();
0253: out.close();
0254: if (file.isFile()) {
0255: isWritable = true;
0256: file.delete();
0257: }
0258: } catch (IOException e) {
0259: }
0260: }
0261: return isWritable;
0262: }
0263:
0264: public static String detab(String s, int tabWidth, int startCol) {
0265: if (tabWidth <= 0)
0266: return s;
0267: int limit = s.length();
0268: int i;
0269: for (i = 0; i < limit; i++) {
0270: if (s.charAt(i) == '\t')
0271: break;
0272: }
0273: if (i == limit)
0274: return s; // No tab characters in string.
0275:
0276: // If we get here, we're looking at the first tab character in the string.
0277:
0278: // Copy the first part of the string to a char array.
0279: char[] charArray = new char[limit * tabWidth];
0280: s.getChars(0, i, charArray, 0);
0281: int col = startCol + i;
0282: // Handle the first tab character.
0283: do {
0284: charArray[col - startCol] = ' ';
0285: ++col;
0286: } while ((col % tabWidth) != 0);
0287: // SKip past the tab char in the input string.
0288: ++i;
0289: // Process the rest of the string.
0290: while (i < limit) {
0291: char c = s.charAt(i++);
0292: if (c == '\t') {
0293: for (int j = tabWidth - col % tabWidth - 1; j >= 0; j--) {
0294: charArray[col - startCol] = ' ';
0295: ++col;
0296: }
0297: } else {
0298: charArray[col - startCol] = c;
0299: ++col;
0300: }
0301: }
0302: return charArray == null ? s : new String(charArray, 0, col
0303: - startCol);
0304: }
0305:
0306: public static final String detab(String s, int tabWidth) {
0307: return detab(s, tabWidth, 0);
0308: }
0309:
0310: public static String entab(String s, int tabWidth, int startCol) {
0311: if (tabWidth <= 0)
0312: return s;
0313: int limit = s.length();
0314: if (limit < tabWidth)
0315: return s;
0316: s = detab(s, tabWidth, startCol); // Clean start.
0317:
0318: // The length may have changed when we detabbed the string.
0319: limit = s.length();
0320:
0321: FastStringBuffer sb = new FastStringBuffer(limit);
0322: int i = 0;
0323: while (i < limit) {
0324: char c = s.charAt(i);
0325: if (c == ' ') {
0326: int nextTabStop = ((startCol + i) / tabWidth + 1)
0327: * tabWidth;
0328: if (nextTabStop < startCol + limit
0329: && nextTabStop - (startCol + i) > 1) {
0330: boolean replace = true;
0331: int j = i + 1;
0332: while (j < nextTabStop - startCol) {
0333: if (s.charAt(j++) != ' ') {
0334: replace = false;
0335: break;
0336: }
0337: }
0338: if (replace) {
0339: sb.append('\t');
0340: i = j;
0341: continue;
0342: }
0343: }
0344: }
0345: sb.append(c);
0346: i++;
0347: }
0348: return sb.toString();
0349: }
0350:
0351: public static final String entab(String s, int tabWidth) {
0352: return entab(s, tabWidth, 0);
0353: }
0354:
0355: public static String makeTabsVisible(String s, int tabWidth) {
0356: if (tabWidth <= 0)
0357: return s;
0358: int limit = s.length();
0359: if (limit == 0)
0360: return s;
0361: final char tabChar = '^';
0362: FastStringBuffer sb = new FastStringBuffer(limit);
0363: int col = 0;
0364: for (int i = 0; i < limit; i++) {
0365: char c = s.charAt(i);
0366: if (c == '\t') {
0367: sb.append(tabChar);
0368: ++col;
0369: while ((col % tabWidth) != 0) {
0370: sb.append(' ');
0371: ++col;
0372: }
0373: } else {
0374: sb.append(c);
0375: ++col;
0376: }
0377: }
0378: return sb.toString();
0379: }
0380:
0381: public static String wrap(String s, int wrapCol, int tabWidth) {
0382: FastStringBuffer sb = new FastStringBuffer();
0383: int i = 0;
0384: final int limit = s.length();
0385: int startOffs = 0;
0386: while (i < limit) {
0387: int col = 0;
0388: int breakOffs = 0;
0389: startOffs = i;
0390: boolean inUrl = false;
0391: while (i < limit) {
0392: char c = s.charAt(i++);
0393: if (c == '\n') {
0394: sb.append(trimTrailing(s.substring(startOffs, i)));
0395: startOffs = i;
0396: break;
0397: }
0398: if (c == '\t')
0399: col += tabWidth - col % tabWidth;
0400: else
0401: ++col;
0402: if (!inUrl && col > wrapCol) {
0403: // Need to break.
0404: if (breakOffs <= startOffs)
0405: breakOffs = i;
0406: sb.append(trimTrailing(s.substring(startOffs,
0407: breakOffs)));
0408: sb.append('\n');
0409: i = breakOffs;
0410: // Skip whitespace.
0411: while (i < limit && s.charAt(i) == ' ')
0412: ++i;
0413: break;
0414: }
0415: if (c == ' ' || c == '\t') {
0416: // We've already incremented i to point past the whitespace char.
0417: breakOffs = i;
0418: inUrl = false;
0419: } else if (c == 'h' && lookingAt(s, i, "ttp://", false)) {
0420: inUrl = true;
0421: i += 6;
0422: } else if (c == 'h'
0423: && lookingAt(s, i, "ttps://", false)) {
0424: inUrl = true;
0425: i += 7;
0426: } else if (c == 'f' && lookingAt(s, i, "tp://", false)) {
0427: inUrl = true;
0428: i += 5;
0429: }
0430: }
0431: }
0432: if (i > startOffs)
0433: sb.append(trimTrailing(s.substring(startOffs, i)));
0434: return sb.toString();
0435: }
0436:
0437: public static int getDetabbedLength(String s, int tabWidth) {
0438: final int limit = s.length();
0439: int detabbedLength = 0;
0440: for (int i = 0; i < limit; i++) {
0441: if (s.charAt(i) == '\t')
0442: detabbedLength += tabWidth - detabbedLength % tabWidth;
0443: else
0444: ++detabbedLength;
0445: }
0446: return detabbedLength;
0447: }
0448:
0449: // Trims leading space characters only, not all whitespace.
0450: public static String trimLeading(String s) {
0451: final int length = s.length();
0452: int i = 0;
0453: while (i < length) {
0454: if (s.charAt(i) != ' ')
0455: break;
0456: ++i;
0457: }
0458: return s.substring(i);
0459: }
0460:
0461: // Trims trailing space characters only, not all whitespace.
0462: public static String trimTrailing(String s) {
0463: int length = s.length();
0464: if (length == 0 || s.charAt(length - 1) != ' ')
0465: return s;
0466: do {
0467: --length;
0468: } while (length > 0 && s.charAt(length - 1) == ' ');
0469: return s.substring(0, length);
0470: }
0471:
0472: // Returns true if the string to be inserted looks like a block of lines.
0473: public static boolean isLinePaste(String s) {
0474: final char c = s.charAt(s.length() - 1);
0475: return c == '\r' || c == '\n';
0476: }
0477:
0478: public static int getIntegerProperty(Properties props, String key,
0479: int defaultValue) {
0480: try {
0481: String s = props.getProperty(key);
0482: if (s != null)
0483: return Integer.parseInt(s);
0484: } catch (NumberFormatException e) {
0485: }
0486: return defaultValue;
0487: }
0488:
0489: /**
0490: * Extracts the name of an include file, enclosed in quotes or angle
0491: * brackets, from a #include line in a C or C++ source file.
0492: *
0493: * @param line the #include line
0494: * @return the name of the file, enclosed in quotes or angle
0495: * brackets as the case may be, or <code>null</code> if
0496: * the line in question is not a valid #include line.
0497: * @since 0.16.2
0498: */
0499: public static String extractInclude(String line) {
0500: String s = line.trim();
0501: if (s.length() < 12) // "#include <a>"
0502: return null;
0503: if (s.charAt(0) != '#')
0504: return null;
0505: REMatch match = includeRE.getMatch(s);
0506: if (match == null)
0507: return null;
0508: s = s.substring(match.getEndIndex()).trim();
0509: if (s.length() < 2)
0510: return null;
0511: char c = s.charAt(0);
0512: int lastIndex = -1;
0513: if (c == '"')
0514: lastIndex = s.indexOf('"', 1);
0515: else if (c == '<')
0516: lastIndex = s.indexOf('>', 1);
0517: if (lastIndex < 0)
0518: return null;
0519: return s.substring(0, lastIndex + 1);
0520: }
0521:
0522: private static final RE includeRE = new UncheckedRE(
0523: "#[ \t]*include[ \t]");
0524:
0525: /**
0526: * Finds an include file (C or C++).
0527: * <p>
0528: * If the filename is enclosed in quotes, we look for it in the current
0529: * directory first.
0530: *
0531: * @param s the name of the file, enclosed in quotes or
0532: * angle brackets as the case may be
0533: * @param path the include path
0534: * @param currentDirectory the current directory
0535: * @return the file, or <code>null</code> if not found
0536: * @since 0.16.2
0537: */
0538: public static File findInclude(String s, String path,
0539: File currentDirectory) {
0540: char c = s.charAt(0);
0541: final String fileName = s.substring(1, s.length() - 1);
0542: if (c == '"') {
0543: // The filename is enclosed in quotes. Look in the current
0544: // directory first.
0545: File file = File.getInstance(currentDirectory, fileName);
0546: if (file != null && file.isLocal() && file.isFile())
0547: return file;
0548: }
0549: return Utilities.findFileInPath(fileName, path,
0550: currentDirectory);
0551: }
0552:
0553: // We pass in currentDirectory in order to support relative paths.
0554: public static File findFileInPath(String filename, String path,
0555: File currentDirectory) {
0556: if (path != null) {
0557: int index;
0558: do {
0559: index = path.indexOf(LocalFile.getPathSeparatorChar());
0560: String dirname;
0561: if (index < 0) {
0562: dirname = path;
0563: } else {
0564: dirname = path.substring(0, index);
0565: path = path.substring(index + 1);
0566: }
0567: File dir;
0568: if (currentDirectory != null
0569: && currentDirectory.isLocal())
0570: dir = File.getInstance(currentDirectory, dirname);
0571: else
0572: dir = File.getInstance(dirname);
0573: if (dir != null) {
0574: File file = File.getInstance(dir, filename);
0575: if (file != null && file.isLocal() && file.isFile())
0576: return file;
0577: }
0578: } while (index >= 0);
0579: }
0580: return null;
0581: }
0582:
0583: // Returns a list of strings.
0584: public static List getDirectoriesInPath(String path) {
0585: ArrayList list = new ArrayList();
0586: if (path != null) {
0587: final char sep = LocalFile.getPathSeparatorChar();
0588: int begin = 0;
0589: int end;
0590: do {
0591: end = path.indexOf(sep, begin);
0592: String dir;
0593: if (end < 0) {
0594: dir = path.substring(begin);
0595: } else {
0596: dir = path.substring(begin, end);
0597: begin = end + 1;
0598: }
0599: if (dir.length() != 0)
0600: list.add(dir);
0601: } while (end >= 0);
0602: }
0603: return list;
0604: }
0605:
0606: // Looks for specified file in the source path and (if applicable) the
0607: // include path.
0608: public static File findFile(Editor editor, String filename) {
0609: final Buffer buffer = editor.getBuffer();
0610: final File currentDirectory = buffer != null ? buffer
0611: .getCurrentDirectory() : null;
0612:
0613: // Look for .h files in the include path.
0614: if (filename.toLowerCase().endsWith(".h")) {
0615: String includePath;
0616: if (buffer != null)
0617: includePath = buffer
0618: .getStringProperty(Property.INCLUDE_PATH);
0619: else
0620: includePath = Editor.preferences().getStringProperty(
0621: Property.INCLUDE_PATH);
0622: if (includePath != null) {
0623: File file = findFileInPath(filename, includePath,
0624: currentDirectory);
0625: if (file != null)
0626: return file;
0627: }
0628: }
0629:
0630: // Try the source path.
0631: String sourcePath;
0632: if (buffer != null)
0633: sourcePath = buffer.getStringProperty(Property.SOURCE_PATH);
0634: else
0635: sourcePath = Editor.preferences().getStringProperty(
0636: Property.SOURCE_PATH);
0637: if (sourcePath != null) {
0638: File file = findFileInPath(filename, sourcePath,
0639: currentDirectory);
0640: if (file != null)
0641: return file;
0642: }
0643:
0644: // Try the source path of the default mode for the file we're looking
0645: // for.
0646: Mode mode = Editor.getModeList().getModeForFileName(filename);
0647: if (mode != null) {
0648: sourcePath = mode.getStringProperty(Property.SOURCE_PATH);
0649: if (sourcePath != null) {
0650: File file = findFileInPath(filename, sourcePath,
0651: currentDirectory);
0652: if (file != null)
0653: return file;
0654: }
0655: }
0656:
0657: // Try global source path.
0658: sourcePath = Editor.preferences().getStringProperty(
0659: Property.SOURCE_PATH);
0660: if (sourcePath != null) {
0661: File file = findFileInPath(filename, sourcePath,
0662: currentDirectory);
0663: if (file != null)
0664: return file;
0665: }
0666:
0667: return null;
0668: }
0669:
0670: // If parent directory exists, returns true; otherwise displays standard
0671: // error dialog using context as title and returns false.
0672: public static boolean checkParentDirectory(File file, String context) {
0673: File parent = file.getParentFile();
0674: if (parent != null && parent.isDirectory())
0675: return true;
0676: FastStringBuffer sb = new FastStringBuffer("Invalid path \"");
0677: sb.append(file.netPath());
0678: sb.append('"');
0679: MessageDialog.showMessageDialog(sb.toString(), context);
0680: return false;
0681: }
0682:
0683: public static boolean isFilenameAbsolute(String filename) {
0684: final int length = filename.length();
0685: if (length > 0) {
0686: char c0 = filename.charAt(0);
0687: if (c0 == '\\' || c0 == '/')
0688: return true;
0689: if (length > 2) {
0690: if (Platform.isPlatformWindows()) {
0691: // Check for drive letter.
0692: char c1 = filename.charAt(1);
0693: if (c1 == ':') {
0694: if (c0 >= 'a' && c0 <= 'z')
0695: return true;
0696: if (c0 >= 'A' && c0 <= 'Z')
0697: return true;
0698: }
0699: } else if (Platform.isPlatformUnix()) {
0700: if (filename.equals("~")
0701: || filename.startsWith("~/"))
0702: return true;
0703: }
0704: if (File.hasRemotePrefix(filename))
0705: return true;
0706: if (File.hasLocalPrefix(filename))
0707: return true;
0708: }
0709: }
0710: return false;
0711: }
0712:
0713: // Helper for getFileType.
0714: private static String getStringFromUnicodeBytes(byte[] bytes,
0715: int start, int length, boolean isLittleEndian) {
0716: FastStringBuffer sb = new FastStringBuffer(length);
0717: int i = start;
0718: int limit = start + length;
0719: while (i < limit - 1) {
0720: byte b1 = bytes[i++];
0721: byte b2 = bytes[i++];
0722: if (isLittleEndian)
0723: sb.append((char) ((b2 << 16) + b1));
0724: else
0725: sb.append((char) ((b1 << 16) + b2));
0726: }
0727: return sb.toString();
0728: }
0729:
0730: // Returns FILETYPE_UNKNOWN if file is null or does not exist.
0731: public static int getFileType(File file) {
0732: if (file == null)
0733: return FILETYPE_UNKNOWN;
0734: int fileType = FILETYPE_UNKNOWN;
0735: try {
0736: InputStream in = file.getInputStream();
0737: byte[] bytes = new byte[4096];
0738: int bytesRead = in.read(bytes);
0739: in.close();
0740: boolean isUnicode = false;
0741: boolean isLittleEndian = false;
0742: if (bytesRead >= 2) {
0743: if (bytes[0] == (byte) 0xfe && bytes[1] == (byte) 0xff) {
0744: isUnicode = true;
0745: isLittleEndian = false;
0746: } else if (bytes[0] == (byte) 0xff
0747: && bytes[1] == (byte) 0xfe)
0748: isUnicode = true;
0749: }
0750: if (!isUnicode) {
0751: for (int i = 0; i < bytesRead; i++) {
0752: if (bytes[i] == 0) {
0753: fileType = FILETYPE_BINARY;
0754: break;
0755: }
0756: }
0757: }
0758: if (fileType == FILETYPE_BINARY) {
0759: if (bytesRead > 2) {
0760: if (bytes[0] == (byte) 0xd0
0761: && bytes[1] == (byte) 0xcf)
0762: fileType = FILETYPE_WORD;
0763: else if (bytes[0] == (byte) 0xff
0764: && bytes[1] == (byte) 0xd8)
0765: fileType = FILETYPE_JPEG;
0766: else if (bytes[0] == (byte) 'P' && bytes[1] == 'K') {
0767: // Looks like a zip file.
0768: try {
0769: ZipInputStream istream = new ZipInputStream(
0770: file.getInputStream());
0771: fileType = FILETYPE_ZIP;
0772: istream.close();
0773: } catch (Exception e) {
0774: }
0775: } else {
0776: try {
0777: GZIPInputStream istream = new GZIPInputStream(
0778: file.getInputStream());
0779: fileType = FILETYPE_GZIP;
0780: istream.close();
0781: } catch (IOException e) {
0782: }
0783: }
0784: }
0785: } else {
0786: // Not binary.
0787: fileType = FILETYPE_TEXT;
0788: String s;
0789: if (isUnicode)
0790: s = getStringFromUnicodeBytes(bytes, 2, bytesRead,
0791: isLittleEndian);
0792: else
0793: s = new String(bytes, 0, bytesRead);
0794: if (s.length() >= 3) {
0795: if (s.charAt(0) == '#' && s.charAt(1) == '!') {
0796: // Only consider the first line.
0797: int index = s.indexOf('\n');
0798: if (index >= 0)
0799: s = s.substring(0, index);
0800: index = s.indexOf('\r');
0801: if (index >= 0)
0802: s = s.substring(0, index);
0803: if (s.indexOf("/bin/sh") >= 0
0804: || s.indexOf("/bin/bash") >= 0
0805: || s.indexOf("/bin/tcsh") >= 0)
0806: fileType = FILETYPE_SHELLSCRIPT;
0807: else if (s.indexOf("/bin/perl") >= 0)
0808: fileType = FILETYPE_PERL;
0809: } else if (s.startsWith("<?xml")) {
0810: fileType = FILETYPE_XML;
0811: } else if (s.startsWith("<?php")) {
0812: fileType = FILETYPE_PHP;
0813: } else if (s.startsWith("<?")
0814: && Character.isWhitespace(s.charAt(2))) {
0815: fileType = FILETYPE_PHP;
0816: }
0817: }
0818: }
0819: } catch (Exception e) {
0820: }
0821: return fileType;
0822: }
0823:
0824: public static boolean deleteRename(File source, File destination) {
0825: if (!source.isFile()) {
0826: Log.warn("deleteRename source file " + source
0827: + " does not exist");
0828: return false;
0829: }
0830: // The delete/rename operation sometimes fails on NT at first, but then
0831: // succeeds later, so we do some retries here if necessary.
0832: for (int i = 0; i < 5; i++) {
0833: if (destination.exists())
0834: destination.delete();
0835: if (source.renameTo(destination))
0836: return true;
0837: Log.warn("deleteRename renameTo failed i = " + i);
0838: System.gc();
0839: try {
0840: Thread.sleep(100);
0841: } catch (InterruptedException ex) {
0842: }
0843: }
0844: // Last resort.
0845: // We might not have delete rights in the destination directory. Try to
0846: // overwrite the destination file in place.
0847: Log.warn("deleteRename calling overwriteFile");
0848: if (overwriteFile(source, destination)) {
0849: source.delete();
0850: return true;
0851: }
0852: Log.warn("deleteRename returning false");
0853: return false;
0854: }
0855:
0856: public static boolean copyFile(File source, File destination) {
0857: if (!source.isFile()) {
0858: Log.error("copyFile error - source is not a file: "
0859: + source);
0860: return false;
0861: }
0862: if (destination.isDirectory()) {
0863: Log.error("copyFile error - destination is a directory: "
0864: + destination);
0865: return false;
0866: }
0867: if (destination.isFile() && !destination.canWrite()) {
0868: Log.error("copyFile error - destination is read only: "
0869: + destination);
0870: return false;
0871: }
0872: boolean error = false;
0873: File tempFile = getTempFile(destination.getParent());
0874: final long length = source.length();
0875: long bytesCopied = 0;
0876: InputStream in = null;
0877: OutputStream out = null;
0878: // Copy source to tempFile.
0879: try {
0880: in = source.getInputStream();
0881: out = tempFile.getOutputStream();
0882: final int bufsize = length < 32768 ? (int) length : 32768;
0883: byte[] buffer = new byte[bufsize];
0884: while (bytesCopied < length) {
0885: int bytesRead = in.read(buffer, 0, bufsize);
0886: if (bytesRead > 0) {
0887: out.write(buffer, 0, bytesRead);
0888: bytesCopied += bytesRead;
0889: } else
0890: break;
0891: }
0892: } catch (IOException e) {
0893: error = true;
0894: }
0895: try {
0896: if (in != null)
0897: in.close();
0898: if (out != null) {
0899: out.flush();
0900: out.close();
0901: }
0902: } catch (IOException e) {
0903: Log.error(e);
0904: error = true;
0905: }
0906: if (error) {
0907: Log.error("copyFile error");
0908: tempFile.delete();
0909: return false;
0910: }
0911: if (bytesCopied != length) {
0912: Log.error("copyFile error - bytesCopied != length");
0913: tempFile.delete();
0914: return false;
0915: }
0916: if (destination.exists()) {
0917: destination.delete();
0918: if (destination.exists()) {
0919: // Unable to delete existing destination file.
0920: Log
0921: .error("copyFile error - unable to delete existing destination file: "
0922: + destination);
0923: tempFile.delete();
0924: return false;
0925: }
0926: }
0927: if (!tempFile.renameTo(destination)) {
0928: Log
0929: .error("copyFile error - unable to rename temporary file");
0930: Log.error("tempFile = " + tempFile.netPath());
0931: Log.error("destination = " + destination.netPath());
0932: tempFile.delete();
0933: return false;
0934: }
0935: if (Platform.isPlatformUnix())
0936: destination.setPermissions(source.getPermissions());
0937: destination.setLastModified(source.lastModified());
0938: return true; // Success!
0939: }
0940:
0941: private static boolean overwriteFile(File source, File destination) {
0942: if (!source.isFile())
0943: return false;
0944: boolean error = false;
0945: long length = source.length();
0946: long totalBytes = 0;
0947: BufferedInputStream in = null;
0948: BufferedOutputStream out = null;
0949: try {
0950: in = new BufferedInputStream(source.getInputStream());
0951: out = new BufferedOutputStream(destination
0952: .getOutputStream());
0953: final int bufsize = 4096;
0954: byte[] buffer = new byte[bufsize];
0955: while (totalBytes < length) {
0956: int numBytes = in.read(buffer, 0, bufsize);
0957: if (numBytes > 0) {
0958: out.write(buffer, 0, numBytes);
0959: totalBytes += numBytes;
0960: } else
0961: break;
0962: }
0963: } catch (IOException e) {
0964: Log.error(e);
0965: error = true;
0966: }
0967:
0968: try {
0969: if (in != null)
0970: in.close();
0971: if (out != null) {
0972: out.flush();
0973: out.close();
0974: }
0975: } catch (IOException e) {
0976: Log.error(e);
0977: error = true;
0978: }
0979: if (error)
0980: return false;
0981: if (totalBytes != length)
0982: return false;
0983: return true;
0984: }
0985:
0986: public static boolean makeBackup(File file, boolean keepOriginal) {
0987: return makeBackup(file, file.getName(), keepOriginal);
0988: }
0989:
0990: public static boolean makeBackup(File file, String name,
0991: boolean keepOriginal) {
0992: // No need to back it up if it doesn't exist.
0993: if (!file.isFile())
0994: return true;
0995: File backupDir = null;
0996: String backupDirectory = Editor.preferences()
0997: .getStringProperty(Property.BACKUP_DIRECTORY);
0998: if (backupDirectory != null) {
0999: backupDir = File.getInstance(backupDirectory);
1000: } else {
1001: // Use default location.
1002: backupDir = File.getInstance(Directories
1003: .getUserHomeDirectory(), "backup");
1004: }
1005: if (backupDir == null)
1006: return false;
1007: if (!backupDir.isDirectory() && !backupDir.mkdirs()) {
1008: Log.error("can't create backup directory ".concat(backupDir
1009: .canonicalPath()));
1010: return false;
1011: }
1012: File backupFile = File.getInstance(backupDir, name);
1013: if (!keepOriginal) {
1014: if (backupFile.isFile() && !backupFile.delete())
1015: Log.error("can't delete old backupFile file "
1016: .concat(backupFile.toString()));
1017: if (file.renameTo(backupFile))
1018: return true;
1019: }
1020: if (copyFile(file, backupFile))
1021: return true;
1022: // If copyFile() failed because the existing backup file is not
1023: // writable, delete that file and try again.
1024: if (backupFile.isFile() && !backupFile.canWrite()) {
1025: Log.debug("deleting old backup file " + backupFile);
1026: backupFile.delete();
1027: Log.debug("retrying copyFile...");
1028: if (copyFile(file, backupFile))
1029: return true;
1030: }
1031: Log.error("makeBackup copyFile failed, returning false");
1032: return false;
1033: }
1034:
1035: public static Color getColor(String s) {
1036: Color color = null;
1037: s = s.trim();
1038: if (s.equals("black"))
1039: color = Color.black;
1040: else if (s.equals("white"))
1041: color = Color.white;
1042: else if (s.equals("yellow"))
1043: color = Color.yellow;
1044: else if (s.equals("blue"))
1045: color = Color.blue;
1046: else if (s.equals("red"))
1047: color = Color.red;
1048: else if (s.equals("gray"))
1049: color = Color.gray;
1050: else if (s.equals("green"))
1051: color = Color.green;
1052: else {
1053: try {
1054: // The string must consist of three numbers for the R, G, B
1055: // components.
1056: StringTokenizer st = new StringTokenizer(s);
1057: if (st.countTokens() == 3) {
1058: int r = Integer.parseInt(st.nextToken());
1059: int g = Integer.parseInt(st.nextToken());
1060: int b = Integer.parseInt(st.nextToken());
1061: color = new Color(r, g, b);
1062: }
1063: } catch (Exception e) {
1064: Log.error(e);
1065: }
1066: }
1067: return color;
1068: }
1069:
1070: // BUG! Not really correct!
1071: private static final String filenameChars = "#-./0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZ\\_abcdefghijklmnopqrstuvwxyz~";
1072:
1073: public static boolean isFilenameChar(char c) {
1074: return (filenameChars.indexOf(c) >= 0);
1075: }
1076:
1077: public static boolean isProcessAlive(Process process) {
1078: if (process == null)
1079: return false;
1080: try {
1081: process.exitValue();
1082: // If process is alive, we won't reach here.
1083: return false;
1084: } catch (IllegalThreadStateException e) {
1085: // If this exception is thrown, the process is still alive.
1086: return true;
1087: }
1088: }
1089:
1090: public static void kill(int pid) {
1091: if (Platform.isPlatformUnix()) {
1092: try {
1093: String[] cmdarray = { "/bin/sh", "-c", "kill -9 " + pid };
1094: Process p = Runtime.getRuntime().exec(cmdarray);
1095: p.waitFor();
1096: } catch (Throwable t) {
1097: Log.error(t);
1098: }
1099: }
1100: }
1101:
1102: private static int haveJpty = -1;
1103:
1104: public static boolean haveJpty() {
1105: if (haveJpty == -1)
1106: haveJpty = have("jpty") ? 1 : 0;
1107: return haveJpty == 1;
1108: }
1109:
1110: private static int haveLs = -1;
1111:
1112: public static boolean haveLs() {
1113: if (haveLs == -1)
1114: haveLs = have("ls") ? 1 : 0;
1115: return haveLs == 1;
1116: }
1117:
1118: public static boolean have(final String s) {
1119: try {
1120: final Process p = Runtime.getRuntime().exec(s);
1121: if (p != null) {
1122: Thread t = new Thread("Utilities.have(\"" + s
1123: + "\") destroy") {
1124: public void run() {
1125: try {
1126: final BufferedReader reader = new BufferedReader(
1127: new InputStreamReader(p
1128: .getInputStream()));
1129: while (reader.readLine() != null)
1130: ;
1131: p.getInputStream().close();
1132: p.getOutputStream().close();
1133: p.getErrorStream().close();
1134: } catch (IOException e) {
1135: Log.error(e);
1136: }
1137: p.destroy();
1138: try {
1139: p.waitFor();
1140: } catch (InterruptedException e) {
1141: Log.error(e);
1142: }
1143: }
1144: };
1145: t.setDaemon(true);
1146: t.setPriority(Thread.MIN_PRIORITY);
1147: t.start();
1148: return true;
1149: }
1150: } catch (Throwable t) {
1151: }
1152: return false;
1153: }
1154:
1155: private static String userHome;
1156:
1157: public static final void setUserHome(String s) {
1158: Debug.bugIfNot(userHome == null); // We only want to do this once!
1159: userHome = s;
1160: }
1161:
1162: public static String getUserHome() {
1163: if (userHome == null) {
1164: if (Platform.isPlatformWindows()) {
1165: String[] cmdarray = { "bash", "-c", "echo $HOME" };
1166: String output = exec(cmdarray);
1167: if (output != null) {
1168: output = output.trim();
1169: if (output.length() > 0) {
1170: if (output.indexOf('/') >= 0)
1171: userHome = uncygnify(output);
1172: else
1173: userHome = output;
1174: }
1175: }
1176: }
1177: if (userHome == null) {
1178: userHome = System.getProperty("user.home");
1179: // Expand links.
1180: File home = File.getInstance(userHome);
1181: if (home != null)
1182: userHome = home.canonicalPath();
1183: }
1184: }
1185: return userHome;
1186: }
1187:
1188: public static String cygnify(String s) {
1189: String[] cmdArray = { "cygpath", "-u", s };
1190: String converted = Utilities.exec(cmdArray);
1191: return converted != null ? converted : s;
1192: }
1193:
1194: public static String uncygnify(String s) {
1195: String[] cmdArray = { "cygpath", "-w", s };
1196: String converted = Utilities.exec(cmdArray);
1197: return converted != null ? converted : s;
1198: }
1199:
1200: public static String exec(String[] cmdarray) {
1201: try {
1202: Process process = Runtime.getRuntime().exec(cmdarray);
1203: BufferedReader reader = new BufferedReader(
1204: new InputStreamReader(process.getInputStream()));
1205: FastStringBuffer sb = new FastStringBuffer();
1206: String s;
1207: while ((s = reader.readLine()) != null) {
1208: if (s.length() > 0) {
1209: if (sb.length() > 0)
1210: sb.append('\n');
1211: sb.append(s);
1212: }
1213: }
1214: process.getInputStream().close();
1215: process.getOutputStream().close();
1216: process.getErrorStream().close();
1217: process.waitFor();
1218: return sb.toString();
1219: } catch (Throwable t) {
1220: Log.error(t);
1221: return null;
1222: }
1223: }
1224:
1225: public static ImageIcon getIconFromFile(String iconFile) {
1226: URL url = Editor.class.getResource("images/".concat(iconFile));
1227: if (url == null)
1228: return null;
1229: return new ImageIcon(url);
1230: }
1231:
1232: // Parses integer from string. Parsing stops when we encounter a non-digit.
1233: public static int parseInt(String s) throws NumberFormatException {
1234: final int limit = s.length();
1235: int i;
1236: for (i = 0; i < limit; i++) {
1237: if (!Character.isDigit(s.charAt(i)))
1238: break;
1239: }
1240: if (i == 0) // No digit found.
1241: throw new NumberFormatException();
1242: return Integer.parseInt(s.substring(0, i));
1243: }
1244:
1245: public static String rightJustify(int n, int fieldWidth) {
1246: String s = String.valueOf(n);
1247: int pad = fieldWidth - s.length();
1248: if (pad <= 0)
1249: return s;
1250: FastStringBuffer sb = new FastStringBuffer(spaces(pad));
1251: sb.append(s);
1252: return sb.toString();
1253: }
1254:
1255: public static String rightJustify(String s, int fieldWidth) {
1256: int pad = fieldWidth - s.length();
1257: if (pad <= 0)
1258: return s;
1259: FastStringBuffer sb = new FastStringBuffer(spaces(pad));
1260: sb.append(s);
1261: return sb.toString();
1262: }
1263:
1264: public static final boolean lookingAt(String s, int i,
1265: String pattern, boolean ignoreCase) {
1266: return s.regionMatches(ignoreCase, i, pattern, 0, pattern
1267: .length());
1268: }
1269:
1270: public static boolean isOneOf(String s, String[] strings) {
1271: if (s != null) {
1272: for (int i = strings.length - 1; i >= 0; i--)
1273: if (s.equals(strings[i]))
1274: return true;
1275: }
1276: return false;
1277: }
1278:
1279: private static final String SPACES;
1280: private static final int SPACES_LENGTH = 256;
1281:
1282: static {
1283: char[] chars = new char[SPACES_LENGTH];
1284: for (int i = 0; i < SPACES_LENGTH; i++)
1285: chars[i] = ' ';
1286: SPACES = new String(chars);
1287: }
1288:
1289: public static String spaces(int count) {
1290: if (count <= 0)
1291: return "";
1292: else if (count <= SPACES_LENGTH)
1293: return SPACES.substring(0, count);
1294: else {
1295: FastStringBuffer sb = new FastStringBuffer(count);
1296: for (int i = 0; i < count; i++)
1297: sb.append(' ');
1298: return sb.toString();
1299: }
1300: }
1301:
1302: public static final String getCharsetFromContentType(
1303: String contentType) {
1304: if (contentType == null)
1305: return null;
1306: int index = contentType.toLowerCase().indexOf("charset=");
1307: if (index < 0)
1308: return null;
1309: String s = contentType.substring(index + 8);
1310: FastStringBuffer sb = new FastStringBuffer();
1311: boolean inQuote = false;
1312: for (int i = 0; i < s.length(); i++) {
1313: char c = s.charAt(i);
1314: if (i == 0 && c == '"') {
1315: inQuote = true;
1316: continue;
1317: }
1318: if (inQuote && c == '"')
1319: break; // Reached end of quoted string.
1320: if (!inQuote && c == ';')
1321: break; // Reached end of parameter value.
1322: sb.append(c); // Normal character.
1323: }
1324: return sb.toString();
1325: }
1326:
1327: public static final String getEncodingFromCharset(String charset) {
1328: if (charset == null)
1329: return "iso-8859-1";
1330: String lower = charset.toLowerCase();
1331: if (lower.equals("unknown-8bit") || lower.equals("x-unknown")
1332: || lower.equals("us-ascii")
1333: || lower.equals("default_charset")
1334: || lower.equals("latin-iso8859-1"))
1335: return "iso-8859-1";
1336: return charset;
1337: }
1338:
1339: public static boolean isSupportedEncoding(String encoding) {
1340: if (encoding != null) {
1341: try {
1342: "test".getBytes(encoding);
1343: return true;
1344: } catch (UnsupportedEncodingException e) {
1345: }
1346: }
1347: return false;
1348: }
1349:
1350: // Extracts XML or HTML tag name (e.g. "a" or "/a") from string.
1351: public static String getTagName(String s) {
1352: Debug.assertTrue(s != null);
1353: Debug.assertTrue(s.length() > 0);
1354: Debug.assertTrue(s.charAt(0) == '<');
1355: int length = s.length();
1356: int start = 1;
1357: for (int i = start; i < length; i++) {
1358: switch (s.charAt(i)) {
1359: case ' ':
1360: case '>':
1361: case '\t':
1362: case '\n':
1363: case '\r':
1364: return s.substring(start, i);
1365: }
1366: }
1367: return s;
1368: }
1369:
1370: // Does not handle embedded single-quoted strings.
1371: public static List tokenize(String s) {
1372: ArrayList list = new ArrayList();
1373: if (s != null) {
1374: FastStringBuffer sb = new FastStringBuffer();
1375: boolean inQuote = false;
1376: final int limit = s.length();
1377: for (int i = 0; i < limit; i++) {
1378: char c = s.charAt(i);
1379: switch (c) {
1380: case ' ':
1381: if (inQuote)
1382: sb.append(c);
1383: else if (sb.length() > 0) {
1384: list.add(sb.toString());
1385: sb.setLength(0);
1386: }
1387: break;
1388: case '"':
1389: if (inQuote) {
1390: if (sb.length() > 0) {
1391: list.add(sb.toString());
1392: sb.setLength(0);
1393: }
1394: inQuote = false;
1395: } else
1396: inQuote = true;
1397: break;
1398: default:
1399: sb.append(c);
1400: break;
1401: }
1402: }
1403: if (sb.length() > 0)
1404: list.add(sb.toString());
1405: }
1406: return list;
1407: }
1408:
1409: public static String getFirstIdentifier(String s, Mode mode) {
1410: FastStringBuffer sb = new FastStringBuffer();
1411: int length = s.length();
1412: if (length > 0) {
1413: char c = s.charAt(0);
1414: if (mode.isIdentifierStart(c)) {
1415: sb.append(c);
1416: for (int i = 1; i < length; i++) {
1417: c = s.charAt(i);
1418: if (mode.isIdentifierPart(c))
1419: sb.append(c);
1420: else
1421: break;
1422: }
1423: }
1424: }
1425: return sb.toString();
1426: }
1427:
1428: public static KeyStroke getKeyStroke(String keyText) {
1429: if (keyText == null)
1430: return null;
1431: keyText = keyText.trim();
1432: if (keyText.length() == 0)
1433: return null;
1434: if (keyText.startsWith("'")) {
1435: if (keyText.length() != 3)
1436: return null;
1437: if (keyText.charAt(2) != '\'')
1438: return null;
1439: return KeyStroke.getKeyStroke(keyText.charAt(1));
1440: }
1441: int modifiers = 0;
1442: while (true) {
1443: if (keyText.startsWith("Ctrl ")
1444: || keyText.startsWith("Ctrl\t")) {
1445: modifiers |= CTRL_MASK;
1446: keyText = keyText.substring(5).trim();
1447: continue;
1448: }
1449: if (keyText.startsWith("Shift ")
1450: || keyText.startsWith("Shift\t")) {
1451: modifiers |= SHIFT_MASK;
1452: keyText = keyText.substring(6).trim();
1453: continue;
1454: }
1455: if (keyText.startsWith("Alt ")
1456: || keyText.startsWith("Alt\t")) {
1457: modifiers |= ALT_MASK;
1458: keyText = keyText.substring(4).trim();
1459: continue;
1460: }
1461: if (keyText.startsWith("Meta ")
1462: || keyText.startsWith("Meta\t")) {
1463: modifiers |= META_MASK;
1464: keyText = keyText.substring(5).trim();
1465: continue;
1466: }
1467: // No more modifiers. What's left is the key name.
1468: break;
1469: }
1470: if (modifiers == 0 && keyText.length() == 1) {
1471: char c = keyText.charAt(0);
1472: return KeyStroke.getKeyStroke(c);
1473: }
1474: if (modifiers == SHIFT_MASK && keyText.length() == 1) {
1475: char c = keyText.charAt(0);
1476: char lower = Character.toLowerCase(c);
1477: char upper = Character.toUpperCase(c);
1478: if (lower != upper)
1479: return KeyStroke.getKeyStroke(upper);
1480: }
1481: int keyCode = getKeyCode(keyText);
1482: if (keyCode == 0)
1483: return null;
1484: return KeyStroke.getKeyStroke(keyCode, modifiers);
1485: }
1486:
1487: public static final String getKeyText(KeyStroke keyStroke) {
1488: return getKeyText(keyStroke.getKeyChar(), keyStroke
1489: .getKeyCode(), keyStroke.getModifiers());
1490: }
1491:
1492: public static String getKeyText(char keyChar, int keyCode,
1493: int modifiers) {
1494: FastStringBuffer sb = new FastStringBuffer();
1495: if (keyChar != 0 && keyChar != 0xffff) {
1496: // Mapping is defined by character.
1497: if (keyChar >= 'A' && keyChar <= 'Z') {
1498: sb.append("Shift ");
1499: sb.append(keyChar);
1500: } else {
1501: sb.append('\'');
1502: sb.append(keyChar);
1503: sb.append('\'');
1504: }
1505: } else {
1506: // Mapping is defined by key code and modifiers.
1507: if ((modifiers & CTRL_MASK) != 0)
1508: sb.append("Ctrl ");
1509: if ((modifiers & SHIFT_MASK) != 0)
1510: sb.append("Shift ");
1511: if ((modifiers & ALT_MASK) != 0)
1512: sb.append("Alt ");
1513: if ((modifiers & META_MASK) != 0)
1514: sb.append("Meta ");
1515: sb.append(getKeyName(keyCode));
1516: }
1517: return sb.toString();
1518: }
1519:
1520: private static String[] keyNames = { "Enter", "Backspace", "Tab",
1521: "Escape", "Space", "Page Up", "Page Down", "Home", "End",
1522: "Delete", "Left", "Right", "Up", "Down", "NumPad Left",
1523: "NumPad Right", "NumPad Up", "NumPad Down", "NumPad *",
1524: "NumPad +", "NumPad -", "NumPad Insert", "Mouse-1",
1525: "Double Mouse-1", "Mouse-2", "Double Mouse-2", "Mouse-3",
1526: "Double Mouse-3" };
1527:
1528: private static int[] keyCodes = { KeyEvent.VK_ENTER,
1529: KeyEvent.VK_BACK_SPACE, KeyEvent.VK_TAB,
1530: KeyEvent.VK_ESCAPE, KeyEvent.VK_SPACE, KeyEvent.VK_PAGE_UP,
1531: KeyEvent.VK_PAGE_DOWN, KeyEvent.VK_HOME, KeyEvent.VK_END,
1532: KeyEvent.VK_DELETE, KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT,
1533: KeyEvent.VK_UP, KeyEvent.VK_DOWN, KeyEvent.VK_KP_LEFT,
1534: KeyEvent.VK_KP_RIGHT, KeyEvent.VK_KP_UP,
1535: KeyEvent.VK_KP_DOWN, 0x6a, 0x6b, 0x6d, 0x9b, VK_MOUSE_1,
1536: VK_DOUBLE_MOUSE_1, VK_MOUSE_2, VK_DOUBLE_MOUSE_2,
1537: VK_MOUSE_3, VK_DOUBLE_MOUSE_3 };
1538:
1539: private static int getKeyCode(String keyName) {
1540: if (keyName.length() == 0)
1541: return 0;
1542: if (keyName.length() == 1)
1543: return (int) keyName.charAt(0);
1544: if (keyName.startsWith("0x")) {
1545: try {
1546: return Integer.parseInt(keyName.substring(2), 16);
1547: } catch (NumberFormatException e) {
1548: Log.error(e);
1549: }
1550: return 0;
1551: }
1552: for (int i = 0; i < keyNames.length; i++) {
1553: if (keyName.equals(keyNames[i]))
1554: return keyCodes[i];
1555: }
1556: if (keyName.charAt(0) == 'F') {
1557: try {
1558: int n = Integer.parseInt(keyName.substring(1));
1559: return KeyEvent.VK_F1 + n - 1;
1560: } catch (NumberFormatException e) {
1561: Log.error(e);
1562: }
1563: }
1564: return 0;
1565: }
1566:
1567: private static String getKeyName(int keyCode) {
1568: if (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9
1569: || keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z)
1570: return String.valueOf((char) keyCode);
1571: if (keyCode >= KeyEvent.VK_F1 && keyCode <= KeyEvent.VK_F12)
1572: return "F" + Integer.toString(keyCode - KeyEvent.VK_F1 + 1);
1573: if (",./;=[\\]".indexOf(keyCode) >= 0)
1574: return String.valueOf((char) keyCode);
1575: for (int i = 0; i < keyCodes.length; i++) {
1576: if (keyCode == keyCodes[i])
1577: return keyNames[i];
1578: }
1579: return "0x" + Integer.toString(keyCode, 16);
1580: }
1581:
1582: public static String propertyToXml(String name, String value) {
1583: FastStringBuffer sb = new FastStringBuffer("<property name=\"");
1584: sb.append(name);
1585: sb.append("\" value=\"");
1586: sb.append(value);
1587: sb.append("\"/>");
1588: return sb.toString();
1589: }
1590:
1591: public static JPanel createPanel(String title) {
1592: JPanel panel = new JPanel();
1593: panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
1594: Border border = new TitledBorder(BorderFactory
1595: .createEtchedBorder(), title) {
1596: public void paintBorder(Component c, Graphics g, int x,
1597: int y, int width, int height) {
1598: Display.setRenderingHints(g);
1599: super .paintBorder(c, g, x, y, width, height);
1600: }
1601: };
1602: panel.setBorder(border);
1603: return panel;
1604: }
1605:
1606: private static String defaultXMLReaderImpl;
1607: static {
1608: if (Platform.isJava14()) {
1609: // Sun/Blackdown 1.4.x.
1610: defaultXMLReaderImpl = "org.apache.crimson.parser.XMLReaderImpl";
1611: } else {
1612: // 1.5
1613: defaultXMLReaderImpl = "com.sun.org.apache.xerces.internal.parsers.SAXParser";
1614: }
1615: }
1616:
1617: public static synchronized XMLReader getDefaultXMLReader() {
1618: if (defaultXMLReaderImpl != null) {
1619: try {
1620: return XMLReaderFactory
1621: .createXMLReader(defaultXMLReaderImpl);
1622: } catch (Exception e) {
1623: // Not available (IBM 1.4.0/1.4.1).
1624: Log.debug(defaultXMLReaderImpl + " is not available");
1625: // Don't use this code path again!
1626: defaultXMLReaderImpl = null;
1627: // Fall through...
1628: }
1629: }
1630: try {
1631: // This should work with IBM 1.4.0/1.4.1.
1632: return XMLReaderFactory.createXMLReader();
1633: } catch (Throwable t) {
1634: // We've got a real problem...
1635: Log.error(t);
1636: return null;
1637: }
1638: }
1639: }
|