/*
* FreeMind - a program for creating and viewing mindmaps
* Copyright (C) 2000-2006 Joerg Mueller, Daniel Polansky, Christian Foltin and others.
* See COPYING for details
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package freemind.main;
//maybe move this class to another package like tools or something...
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.print.Paper;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import freemind.common.XmlBindingTools;
import freemind.controller.actions.generated.instance.CompoundAction;
import freemind.controller.actions.generated.instance.XmlAction;
import freemind.modes.MindMapNode;
import freemind.modes.mindmapmode.MindMapController;
import freemind.view.mindmapview.NodeView;
//OSSXP.COM: classes for .mm and .mmx join.
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
/**
* @author foltin
*
*/
public class Tools {
/**
*
*/
public static final String FREEMIND_LIB_FREEMIND_JAR = "lib/freemind.jar";
private static java.util.logging.Logger logger = null;
static {
logger = freemind.main.Resources.getInstance().getLogger("Tools");
}
public static final String CONTENTS_JAVA_FREEMIND_JAR = "Contents/Java/freemind.jar";
public static final String FREE_MIND_APP_CONTENTS_RESOURCES_JAVA = "Contents/Resources/Java/";
// public static final Set executableExtensions = new HashSet ({ "exe",
// "com", "vbs" });
// The Java programming language provides a shortcut syntax for creating and
// initializing an array. Here's an example of this syntax:
// boolean[] answers = { true, false, true, true, false };
public static final Set executableExtensions = new HashSet(
Arrays.asList(new String[] { "exe", "com", "vbs", "bat", "lnk" }));
private static Set availableFontFamilyNames = null; // Keep set of platform
private static String sEnvFonts[] = null;
// bug fix from Dimitri.
public static Random ran = new Random();
// fonts
public static boolean executableByExtension(String file) {
return executableExtensions.contains(getExtension(file));
}
public static String colorToXml(Color col) {
// if (col == null) throw new IllegalArgumentException("Color was
// null");
if (col == null)
return null;
String red = Integer.toHexString(col.getRed());
if (col.getRed() < 16)
red = "0" + red;
String green = Integer.toHexString(col.getGreen());
if (col.getGreen() < 16)
green = "0" + green;
String blue = Integer.toHexString(col.getBlue());
if (col.getBlue() < 16)
blue = "0" + blue;
return "#" + red + green + blue;
}
public static Color xmlToColor(String string) {
if (string == null)
return null;
string = string.trim();
if (string.length() == 7) {
int red = Integer.parseInt(string.substring(1, 3), 16);
int green = Integer.parseInt(string.substring(3, 5), 16);
int blue = Integer.parseInt(string.substring(5, 7), 16);
return new Color(red, green, blue);
} else {
throw new IllegalArgumentException("No xml color given by '"
+ string + "'.");
}
}
public static String PointToXml(Point col) {
if (col == null)
return null; // throw new IllegalArgumentException("Point was
// null");
Vector l = new Vector();
l.add(Integer.toString(col.x));
l.add(Integer.toString(col.y));
return listToString((List) l);
}
public static Point xmlToPoint(String string) {
if (string == null)
return null;
// fc, 3.11.2004: bug fix for alpha release of FM
if (string.startsWith("java.awt.Point")) {
string = string.replaceAll(
"java\\.awt\\.Point\\[x=(-*[0-9]*),y=(-*[0-9]*)\\]",
"$1;$2");
}
List l = stringToList(string);
ListIterator it = l.listIterator(0);
if (l.size() != 2)
throw new IllegalArgumentException(
"A point must consist of two numbers (and not: '" + string
+ "').");
int x = Integer.parseInt((String) it.next());
int y = Integer.parseInt((String) it.next());
return new Point(x, y);
}
public static String BooleanToXml(boolean col) {
return (col) ? "true" : "false";
}
public static boolean xmlToBoolean(String string) {
if (string == null)
return false;
if (string.equals("true"))
return true;
return false;
}
/**
* Converts a String in the format "value;value;value" to a List with the
* values (as strings)
*/
public static List stringToList(String string) {
StringTokenizer tok = new StringTokenizer(string, ";");
List list = new LinkedList();
while (tok.hasMoreTokens()) {
list.add(tok.nextToken());
}
return list;
}
public static String listToString(List list) {
ListIterator it = list.listIterator(0);
String str = new String();
while (it.hasNext()) {
str += it.next().toString() + ";";
}
return str;
}
/**
* Replaces a ~ in a filename with the users home directory
*/
public static String expandFileName(String file) {
// replace ~ with the users home dir
if (file.startsWith("~")) {
file = System.getProperty("user.home") + file.substring(1);
}
return file;
}
public static Set getAvailableFontFamilyNames() {
if (availableFontFamilyNames == null) {
String[] envFonts = getAvailableFonts();
availableFontFamilyNames = new HashSet();
for (int i = 0; i < envFonts.length; i++) {
availableFontFamilyNames.add(envFonts[i]);
}
// Add this one explicitly, Java defaults to it if the font is not
availableFontFamilyNames.add("dialog");
}
return availableFontFamilyNames;
}
/**
*/
private static String[] getAvailableFonts() {
if (sEnvFonts == null) {
GraphicsEnvironment gEnv = GraphicsEnvironment
.getLocalGraphicsEnvironment();
sEnvFonts = gEnv.getAvailableFontFamilyNames();
}
return sEnvFonts;
}
public static Vector getAvailableFontFamilyNamesAsVector() {
String[] envFonts = getAvailableFonts();
Vector availableFontFamilyNames = new Vector();
for (int i = 0; i < envFonts.length; i++) {
availableFontFamilyNames.add(envFonts[i]);
}
return availableFontFamilyNames;
}
public static boolean isAvailableFontFamily(String fontFamilyName) {
return getAvailableFontFamilyNames().contains(fontFamilyName);
}
/**
* Returns the lowercase of the extension of a file. Example:
* getExtension("fork.pork.MM") ==
* freemind.main.FreeMindCommon.FREEMIND_FILE_EXTENSION_WITHOUT_DOT
*/
public static String getExtension(File f) {
return getExtension(f.toString());
}
/**
* Returns the lowercase of the extension of a file name. Example:
* getExtension("fork.pork.MM") ==
* freemind.main.FreeMindCommon.FREEMIND_FILE_EXTENSION_WITHOUT_DOT
*/
public static String getExtension(String s) {
int i = s.lastIndexOf('.');
return (i > 0 && i < s.length() - 1) ? s.substring(i + 1).toLowerCase()
.trim() : "";
}
public static String removeExtension(String s) {
int i = s.lastIndexOf('.');
return (i > 0 && i < s.length() - 1) ? s.substring(0, i) : "";
}
public static boolean isAbsolutePath(String path) {
// On Windows, we cannot just ask if the file name starts with file
// separator.
// If path contains ":" at the second position, then it is not relative,
// I guess.
// However, if it starts with separator, then it is absolute too.
// Possible problems: Not tested on Macintosh, but should work.
// Koh, 1.4.2004: Resolved problem: I tested on Mac OS X 10.3.3 and
// worked.
String osNameStart = System.getProperty("os.name").substring(0, 3);
String fileSeparator = System.getProperty("file.separator");
if (osNameStart.equals("Win")) {
return ((path.length() > 1) && path.substring(1, 2).equals(":"))
|| path.startsWith(fileSeparator);
} else if (osNameStart.equals("Mac")) {
// Koh:Panther (or Java 1.4.2) may change file path rule
return path.startsWith(fileSeparator);
} else {
return path.startsWith(fileSeparator);
}
}
/**
* This is a correction of a method getFile of a class URL. Namely, on
* Windows it returned file paths like /C: etc., which are not valid on
* Windows. This correction is heuristic to a great extend. One of the
* reasons is that file:// is basically no protocol at all, but rather
* something every browser and every system uses slightly differently.
*/
public static String urlGetFile(URL url) {
if (isWindows() && isFile(url)) {
String fileName = url.toString().replaceFirst("^file:", "")
.replace('/', '\\');
return (fileName.indexOf(':') >= 0) ? fileName.replaceFirst(
"^\\\\*", "") : fileName;
} // Network path
else {
return url.getFile();
}
}
public static boolean isWindows() {
return System.getProperty("os.name").substring(0, 3).equals("Win");
}
public static boolean isFile(URL url) {
return url.getProtocol().equals("file");
}
/**
* @return "/" for absolute file names under Unix, "c:\\" or similar under
* windows, null otherwise
*/
public static String getPrefix(String pFileName) {
if (isWindows()) {
if (pFileName.matches("^[a-zA-Z]:\\\\.*")) {
return pFileName.substring(0, 3);
}
} else {
if (pFileName.startsWith(File.separator)) {
return File.separator;
}
}
return null;
}
/**
* This method converts an absolute url to an url relative to a given
* base-url. Something like this should be included in the librarys, but I
* couldn't find it. You can create a new absolute url with
* "new URL(URL context, URL relative)".
*/
public static String toRelativeURL(URL base, URL target) {
// Precondition: If URL is a path to folder, then it must end with '/'
// character.
if (base == null || !base.getProtocol().equals(target.getProtocol())
|| !base.getHost().equals(target.getHost())) {
return target.toString();
}
String baseString = base.getFile();
String targetString = target.getFile();
String result = "";
// remove filename from URL
targetString = targetString.substring(0,
targetString.lastIndexOf("/") + 1);
// remove filename from URL
baseString = baseString.substring(0, baseString.lastIndexOf("/") + 1);
// Algorithm
// look for same start:
int index = targetString.length() - 1;
while (!baseString.startsWith(targetString.substring(0, index + 1))) {
// remove last part:
index = targetString.lastIndexOf("/", index - 1);
if (index < 0) {
// no common part. This is strange, as both should start with /,
// but...
break;
}
}
// now, baseString is targetString + "/" + rest. we determine
// rest=baseStringRest now.
String baseStringRest = baseString
.substring(index, baseString.length());
// Maybe this causes problems under windows
StringTokenizer baseTokens = new StringTokenizer(baseStringRest, "/");
// Maybe this causes problems under windows
StringTokenizer targetTokens = new StringTokenizer(
targetString.substring(index + 1), "/");
String nextTargetToken = "";
while (baseTokens.hasMoreTokens()) {
result = result.concat("../");
baseTokens.nextToken();
}
while (targetTokens.hasMoreTokens()) {
nextTargetToken = targetTokens.nextToken();
result = result.concat(nextTargetToken + "/");
}
String temp = target.getFile();
result = result.concat(temp.substring(temp.lastIndexOf("/") + 1,
temp.length()));
return result;
}
/**
* If the preferences say, that links should be relative, a relative url is
* returned.
*
* @param input
* the file that is treated
* @param pMapFile
* the file, that input is made relative to
* @return in case of trouble the absolute path.
*/
public static String fileToRelativeUrlString(File input, File pMapFile) {
URL link;
String relative;
try {
link = Tools.fileToUrl(input);
relative = link.toString();
if ("relative".equals(Resources.getInstance().getProperty("links"))) {
// Create relative URL
relative = Tools.toRelativeURL(Tools.fileToUrl(pMapFile), link);
}
return relative;
} catch (MalformedURLException ex) {
freemind.main.Resources.getInstance().logException(ex);
}
return input.getAbsolutePath();
}
/**
* Tests a string to be equals with "true".
*
* @return true, iff the String is "true".
*/
public static boolean isPreferenceTrue(String option) {
return Tools.safeEquals(option, "true");
}
/**
* @param string1
* input (or null)
* @param string2
* input (or null)
* @return true, if equal (that means: same text or both null)
*/
public static boolean safeEquals(String string1, String string2) {
return (string1 != null && string2 != null && string1.equals(string2))
|| (string1 == null && string2 == null);
}
public static boolean safeEquals(Object obj1, Object obj2) {
return (obj1 != null && obj2 != null && obj1.equals(obj2))
|| (obj1 == null && obj2 == null);
}
public static boolean safeEqualsIgnoreCase(String string1, String string2) {
return (string1 != null && string2 != null && string1.toLowerCase()
.equals(string2.toLowerCase()))
|| (string1 == null && string2 == null);
}
public static boolean safeEquals(Color color1, Color color2) {
return (color1 != null && color2 != null && color1.equals(color2))
|| (color1 == null && color2 == null);
}
public static String firstLetterCapitalized(String text) {
if (text == null || text.length() == 0) {
return text;
}
return text.substring(0, 1).toUpperCase()
+ text.substring(1, text.length());
}
public static void setHidden(File file, boolean hidden,
boolean synchronously) {
// According to Web articles, UNIX systems do not have attribute hidden
// in general, rather, they consider files starting with . as hidden.
String osNameStart = System.getProperty("os.name").substring(0, 3);
if (osNameStart.equals("Win")) {
try {
Runtime.getRuntime().exec(
"attrib " + (hidden ? "+" : "-") + "H \""
+ file.getAbsolutePath() + "\"");
// Synchronize the effect, because it is asynchronous in
// general.
if (!synchronously) {
return;
}
int timeOut = 10;
while (file.isHidden() != hidden && timeOut > 0) {
Thread.sleep(10/* miliseconds */);
timeOut--;
}
} catch (Exception e) {
freemind.main.Resources.getInstance().logException(e);
}
}
}
/**
* Example: expandPlaceholders("Hello $1.","Dolly"); => "Hello Dolly."
*/
public static String expandPlaceholders(String message, String s1) {
String result = message;
if (s1 != null) {
s1 = s1.replaceAll("\\\\", "\\\\\\\\"); // Replace \ with \\
result = result.replaceAll("\\$1", s1);
}
return result;
}
public static String expandPlaceholders(String message, String s1, String s2) {
String result = message;
if (s1 != null) {
result = result.replaceAll("\\$1", s1);
}
if (s2 != null) {
result = result.replaceAll("\\$2", s2);
}
return result;
}
public static String expandPlaceholders(String message, String s1,
String s2, String s3) {
String result = message;
if (s1 != null) {
result = result.replaceAll("\\$1", s1);
}
if (s2 != null) {
result = result.replaceAll("\\$2", s2);
}
if (s3 != null) {
result = result.replaceAll("\\$3", s3);
}
return result;
}
public static class IntHolder {
private int value;
public IntHolder() {
}
public IntHolder(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public String toString() {
return new String("IntHolder(") + value + ")";
}
}
public static class BooleanHolder {
private boolean value;
public BooleanHolder() {
}
public BooleanHolder(boolean initialValue) {
value = initialValue;
}
public void setValue(boolean value) {
this.value = value;
}
public boolean getValue() {
return value;
}
}
public static class ObjectHolder {
Object object;
public ObjectHolder() {
}
public void setObject(Object object) {
this.object = object;
}
public Object getObject() {
return object;
}
}
public static class Pair {
Object first;
Object second;
public Pair(Object first, Object second) {
this.first = first;
this.second = second;
}
public Object getFirst() {
return first;
}
public Object getSecond() {
return second;
}
}
/** from: http://javaalmanac.com/egs/javax.crypto/PassKey.html */
public static class DesEncrypter {
private static final String SALT_PRESENT_INDICATOR = " ";
private static final int SALT_LENGTH = 8;
Cipher ecipher;
Cipher dcipher;
// 8-byte default Salt
byte[] salt = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
(byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03 };
// Iteration count
int iterationCount = 19;
private final char[] passPhrase;
private String mAlgorithm;
public DesEncrypter(StringBuffer pPassPhrase, String pAlgorithm) {
passPhrase = new char[pPassPhrase.length()];
pPassPhrase.getChars(0, passPhrase.length, passPhrase, 0);
mAlgorithm = pAlgorithm;
}
/**
*/
private void init(byte[] mSalt) {
if (mSalt != null) {
this.salt = mSalt;
}
if (ecipher == null) {
try {
// Create the key
KeySpec keySpec = new PBEKeySpec(passPhrase, salt,
iterationCount);
SecretKey key = SecretKeyFactory.getInstance(mAlgorithm)
.generateSecret(keySpec);
ecipher = Cipher.getInstance(mAlgorithm);
dcipher = Cipher.getInstance(mAlgorithm);
// Prepare the parameter to the ciphers
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(
salt, iterationCount);
// Create the ciphers
ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
} catch (java.security.InvalidAlgorithmParameterException e) {
} catch (java.security.spec.InvalidKeySpecException e) {
} catch (javax.crypto.NoSuchPaddingException e) {
} catch (java.security.NoSuchAlgorithmException e) {
} catch (java.security.InvalidKeyException e) {
}
}
}
public String encrypt(String str) {
try {
// Encode the string into bytes using utf-8
byte[] utf8 = str.getBytes("UTF8");
// determine salt by random:
byte[] newSalt = new byte[SALT_LENGTH];
for (int i = 0; i < newSalt.length; i++) {
newSalt[i] = (byte) (Math.random() * 256l - 128l);
}
init(newSalt);
// Encrypt
byte[] enc = ecipher.doFinal(utf8);
// Encode bytes to base64 to get a string
return Tools.toBase64(newSalt) + SALT_PRESENT_INDICATOR
+ Tools.toBase64(enc);
} catch (javax.crypto.BadPaddingException e) {
} catch (IllegalBlockSizeException e) {
} catch (UnsupportedEncodingException e) {
}
return null;
}
public String decrypt(String str) {
if (str == null) {
return null;
}
try {
byte[] salt = null;
// test if salt exists:
int indexOfSaltIndicator = str.indexOf(SALT_PRESENT_INDICATOR);
if (indexOfSaltIndicator >= 0) {
String saltString = str.substring(0, indexOfSaltIndicator);
str = str.substring(indexOfSaltIndicator + 1);
salt = Tools.fromBase64(saltString);
}
// Decode base64 to get bytes
str = str.replaceAll("\\s", "");
byte[] dec = Tools.fromBase64(str);
init(salt);
// Decrypt
byte[] utf8 = dcipher.doFinal(dec);
// Decode using utf-8
return new String(utf8, "UTF8");
} catch (javax.crypto.BadPaddingException e) {
} catch (IllegalBlockSizeException e) {
} catch (UnsupportedEncodingException e) {
}
return null;
}
}
public static class SingleDesEncrypter extends DesEncrypter {
public SingleDesEncrypter(StringBuffer pPassPhrase) {
super(pPassPhrase, "PBEWithMD5AndDES");
}
}
public static class TripleDesEncrypter extends DesEncrypter {
public TripleDesEncrypter(StringBuffer pPassPhrase) {
super(pPassPhrase, "PBEWithMD5AndTripleDES");
}
}
/**
*/
public static String toBase64(byte[] byteBuffer) {
return new String(Base64Coding.encode64(byteBuffer));
}
/** Method to be called from XSLT */
public static String toBase64(String text) {
return toBase64(text.getBytes());
}
/**
* @throws IOException
*/
public static byte[] fromBase64(String base64String) {
return Base64Coding.decode64(base64String);
}
public static String compress(String message) {
byte[] input = uTF8StringToByteArray(message);
// Create the compressor with highest level of compression
Deflater compressor = new Deflater();
compressor.setLevel(Deflater.BEST_COMPRESSION);
// Give the compressor the data to compress
compressor.setInput(input);
compressor.finish();
// Create an expandable byte array to hold the compressed data.
// You cannot use an array that's the same size as the orginal because
// there is no guarantee that the compressed data will be smaller than
// the uncompressed data.
ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
// Compress the data
byte[] buf = new byte[1024];
while (!compressor.finished()) {
int count = compressor.deflate(buf);
bos.write(buf, 0, count);
}
try {
bos.close();
} catch (IOException e) {
}
// Get the compressed data
byte[] compressedData = bos.toByteArray();
return toBase64(compressedData);
}
public static String decompress(String compressedMessage) {
byte[] compressedData = fromBase64(compressedMessage);
// Create the decompressor and give it the data to compress
Inflater decompressor = new Inflater();
decompressor.setInput(compressedData);
// Create an expandable byte array to hold the decompressed data
ByteArrayOutputStream bos = new ByteArrayOutputStream(
compressedData.length);
// Decompress the data
byte[] buf = new byte[1024];
boolean errorOccured = false;
while (!decompressor.finished() && !errorOccured) {
try {
int count = decompressor.inflate(buf);
bos.write(buf, 0, count);
} catch (DataFormatException e) {
errorOccured = true;
}
}
try {
bos.close();
} catch (IOException e) {
}
// Get the decompressed data
byte[] decompressedData = bos.toByteArray();
return byteArrayToUTF8String(decompressedData);
}
/**
*/
public static String byteArrayToUTF8String(byte[] compressedData) {
// Decode using utf-8
try {
return new String(compressedData, "UTF8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF8 packing not allowed");
}
}
/**
*/
public static byte[] uTF8StringToByteArray(String uncompressedData) {
// Code using utf-8
try {
return uncompressedData.getBytes("UTF8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("UTF8 packing not allowed");
}
}
/**
* Extracts a long from xml. Only useful for dates.
*/
public static Date xmlToDate(String xmlString) {
try {
return new Date(Long.valueOf(xmlString).longValue());
} catch (Exception e) {
return new Date(System.currentTimeMillis());
}
}
public static String dateToString(Date date) {
return Long.toString(date.getTime());
}
public static boolean safeEquals(BooleanHolder holder, BooleanHolder holder2) {
return (holder == null && holder2 == null)
|| (holder != null && holder2 != null && holder.getValue() == holder2
.getValue());
}
public static void setDialogLocationRelativeTo(JDialog dialog, Component c) {
if (c == null) {
// perhaps, the component is not yet existing.
return;
}
if (c instanceof NodeView) {
final NodeView nodeView = (NodeView) c;
nodeView.getMap().scrollNodeToVisible(nodeView);
c = nodeView.getMainView();
}
final Point compLocation = c.getLocationOnScreen();
final int cw = c.getWidth();
final int ch = c.getHeight();
final Container parent = dialog.getParent();
final Point parentLocation = parent.getLocationOnScreen();
final int pw = parent.getWidth();
final int ph = parent.getHeight();
final int dw = dialog.getWidth();
final int dh = dialog.getHeight();
final Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
final Dimension screenSize = defaultToolkit.getScreenSize();
final Insets screenInsets = defaultToolkit.getScreenInsets(dialog
.getGraphicsConfiguration());
final int minX = Math.max(parentLocation.x, screenInsets.left);
final int minY = Math.max(parentLocation.y, screenInsets.top);
final int maxX = Math.min(parentLocation.x + pw, screenSize.width
- screenInsets.right);
final int maxY = Math.min(parentLocation.y + ph, screenSize.height
- screenInsets.bottom);
int dx, dy;
if (compLocation.x + cw < minX) {
dx = minX;
} else if (compLocation.x > maxX) {
dx = maxX - dw;
} else // component X on screen
{
final int leftSpace = compLocation.x - minX;
final int rightSpace = maxX - (compLocation.x + cw);
if (leftSpace > rightSpace) {
if (leftSpace > dw) {
dx = compLocation.x - dw;
} else {
dx = minX;
}
} else {
if (rightSpace > dw) {
dx = compLocation.x + cw;
} else {
dx = maxX - dw;
}
}
}
if (compLocation.y + ch < minY) {
dy = minY;
} else if (compLocation.y > maxY) {
dy = maxY - dh;
} else // component Y on screen
{
final int topSpace = compLocation.y - minY;
final int bottomSpace = maxY - (compLocation.y + ch);
if (topSpace > bottomSpace) {
if (topSpace > dh) {
dy = compLocation.y - dh;
} else {
dy = minY;
}
} else {
if (bottomSpace > dh) {
dy = compLocation.y + ch;
} else {
dy = maxY - dh;
}
}
}
dialog.setLocation(dx, dy);
}
/**
* Creates a reader that pipes the input file through a XSLT-Script that
* updates the version to the current.
*
* @throws IOException
*/
public static Reader getUpdateReader(Reader pReader, String xsltScript,
FreeMindMain frame) throws IOException {
StringWriter writer = null;
InputStream inputStream = null;
final java.util.logging.Logger logger = frame.getLogger(Tools.class
.getName());
logger.info("Updating the reader " + pReader
+ " to the current version.");
boolean successful = false;
String errorMessage = null;
try {
// try to convert map with xslt:
URL updaterUrl = null;
updaterUrl = frame.getResource(xsltScript);
if (updaterUrl == null) {
throw new IllegalArgumentException(xsltScript + " not found.");
}
inputStream = updaterUrl.openStream();
final Source xsltSource = new StreamSource(inputStream);
// get output:
writer = new StringWriter();
final Result result = new StreamResult(writer);
String fileContents = getFile(pReader);
if (fileContents.length() > 10) {
logger.info("File start before UTF8 replacement: '"
+ fileContents.substring(0, 9) + "'");
}
fileContents = replaceUtf8AndIllegalXmlChars(fileContents);
if (fileContents.length() > 10) {
logger.info("File start after UTF8 replacement: '"
+ fileContents.substring(0, 9) + "'");
}
final StreamSource sr = new StreamSource(new StringReader(
fileContents));
// Dimitry: to avoid a memory leak and properly release resources
// after the XSLT transformation
// everything should run in own thread. Only after the thread dies
// the resources are released.
class TransformerRunnable implements Runnable {
private boolean successful = false;
private String errorMessage;
public void run() {
// create an instance of TransformerFactory
TransformerFactory transFact = TransformerFactory
.newInstance();
logger.info("TransformerFactory class: "
+ transFact.getClass());
Transformer trans;
try {
trans = transFact.newTransformer(xsltSource);
trans.transform(sr, result);
successful = true;
} catch (Exception ex) {
freemind.main.Resources.getInstance().logException(ex);
errorMessage = ex.toString();
}
}
public boolean isSuccessful() {
return successful;
}
public String getErrorMessage() {
return errorMessage;
}
}
final TransformerRunnable transformer = new TransformerRunnable();
Thread transformerThread = new Thread(transformer, "XSLT");
transformerThread.start();
transformerThread.join();
logger.info("Updating the reader " + pReader
+ " to the current version. Done."); // +
// writer.getBuffer().toString());
successful = transformer.isSuccessful();
errorMessage = transformer.getErrorMessage();
} catch (Exception ex) {
Resources.getInstance().logException(ex, xsltScript);
errorMessage = ex.getLocalizedMessage();
} finally {
if (inputStream != null) {
inputStream.close();
}
if (writer != null) {
writer.close();
}
}
if (successful) {
String content = writer.getBuffer().toString();
// logger.info("Content before transformation: " + content);
String replacedContent = Tools
.replaceUtf8AndIllegalXmlChars(content);
// logger.info("Content after transformation: " + replacedContent);
return new StringReader(replacedContent);
} else {
return new StringReader("<map><node TEXT='"
+ HtmlTools.toXMLEscapedText(errorMessage) + "'/></map>");
}
}
public static String replaceUtf8AndIllegalXmlChars(String fileContents) {
return HtmlTools.removeInvalidXmlCharacters(fileContents);
}
/**
* Creates a default reader that just reads the given file.
*
* @throws FileNotFoundException
*/
public static Reader getActualReader(Reader pReader)
throws FileNotFoundException {
return new BufferedReader(pReader);
}
/*
* OSSXP.COM: hacked FreeMind saved two seperate files, .mm and .mmx file.
* Join them in runtime using XSLT TransformerFactory.
* TODO: Improvement needed. the joining stage may very slow, so disable it.
*/
public static Reader getActualReader(File file, FreeMindMain frame) throws IOException {
if (!Resources.getInstance().getBoolProperty("wh_save_extra_attrs_in_aux_file"))
{
return getActualReaderXml(file);
}
// load .mmx file...
String ext = Tools.getExtension(file.getName());
String mmxFileName = "";
// OSSXP.COM: can disable join .mm with .mmx here.
// if(true) return getActualReaderXml(file);
if(!ext.equals("mm"))
{
mmxFileName = "." + file.getName()+".mmx";
}
else
{
mmxFileName = "." + Tools.removeExtension(file.getName()) + ".mmx";
}
File mmxfile = new File(file.getParent(), mmxFileName);
if (!mmxfile.exists())
{
return getActualReaderXml(file);
}
URL updaterUrl = null;
InputStream inputStream = null;
Source xsltSource = null;
StringWriter buffwriter = null;
Result result = null;
TransformerFactory tf = null;
Transformer transformer = null;
String mmxFileFullName = mmxfile.toURI().toString();
try {
// try to convert map with xslt:
updaterUrl = frame.getResource(
"freemind/modes/mindmapmode/freemind_join_mm_mmx.xslt");
if (updaterUrl == null) {
throw new IllegalArgumentException(
"freemind_join_mm_mmx.xslt not found.");
}
inputStream = updaterUrl.openStream();
xsltSource = new StreamSource(inputStream);
// get output:
buffwriter = new StringWriter();
result = new StreamResult(buffwriter);
/* OSSXP.COM: create an instance of TransformerFactory.
* the default xslt engine (com.sun.org.apache.xalan.internal.xsltc.trax...)
* may not support 'key()' in freemind_join_mm_mmx.xslt.
* Use saxon implement. */
System.setProperty("javax.xml.transform.TransformerFactory",
"com.icl.saxon.TransformerFactoryImpl");
tf = TransformerFactory.newInstance();
transformer = tf.newTransformer(xsltSource);
transformer.setParameter("mmx_file", mmxFileFullName);
transformer.transform(new StreamSource(file), result);
} catch (Exception ex) {
ex.printStackTrace();
// exception: we take the file itself:
return getActualReaderXml(file);
} finally {
if (inputStream != null) {
inputStream.close();
}
if (buffwriter != null) {
buffwriter.close();
}
inputStream = null;
xsltSource = null;
updaterUrl = null;
result = null;
transformer = null;
tf = null;
}
return new StringReader(buffwriter.getBuffer().toString());
}
/*
* OSSXP.COM: In this hacked version, .mm file is a true XML file.
* load XML file using DOM.
*/
private static Reader getActualReaderXml(File file) throws IOException {
try
{
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder domBuilder = domFactory.newDocumentBuilder();
Document doc = domBuilder.parse(file);
Source src = new DOMSource(doc);
StringWriter buffwriter = new StringWriter();
StreamResult result = new StreamResult(buffwriter);
transformer.transform(src, result);
return new StringReader(buffwriter.toString());
}
catch(Exception exp)
{
exp.printStackTrace();
}
return new BufferedReader(new FileReader(file));
}
/**
* In case of trouble, the method returns null.
*
* @param pInputFile
* the file to read.
* @return the complete content of the file. or null if an exception has
* occured.
*/
public static String getFile(File pInputFile) {
try {
return getFile(getReaderFromFile(pInputFile));
} catch (FileNotFoundException e) {
freemind.main.Resources.getInstance().logException(e);
return null;
}
}
public static Reader getReaderFromFile(File pInputFile)
throws FileNotFoundException {
return new FileReader(pInputFile);
}
public static String getFile(Reader pReader) {
StringBuffer lines = new StringBuffer();
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(pReader);
final String endLine = System.getProperty("line.separator");
String line;
while ((line = bufferedReader.readLine()) != null) {
lines.append(line).append(endLine);
}
bufferedReader.close();
} catch (Exception e) {
freemind.main.Resources.getInstance().logException(e);
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (Exception ex) {
freemind.main.Resources.getInstance().logException(ex);
}
}
return null;
}
return lines.toString();
}
public static void logTransferable(Transferable t) {
System.err.println();
System.err.println("BEGIN OF Transferable:\t" + t);
DataFlavor[] dataFlavors = t.getTransferDataFlavors();
for (int i = 0; i < dataFlavors.length; i++) {
System.out.println(" Flavor:\t" + dataFlavors[i]);
System.out.println(" Supported:\t"
+ t.isDataFlavorSupported(dataFlavors[i]));
try {
System.out.println(" Content:\t"
+ t.getTransferData(dataFlavors[i]));
} catch (Exception e) {
}
}
System.err.println("END OF Transferable");
System.err.println();
}
public static void addEscapeActionToDialog(final JDialog dialog) {
class EscapeAction extends AbstractAction {
private static final long serialVersionUID = 238333614987438806L;
public void actionPerformed(ActionEvent e) {
dialog.dispose();
};
}
addEscapeActionToDialog(dialog, new EscapeAction());
}
public static void addEscapeActionToDialog(JDialog dialog, Action action) {
addKeyActionToDialog(dialog, action, "ESCAPE", "end_dialog");
}
public static void addKeyActionToDialog(JDialog dialog, Action action,
String keyStroke, String actionId) {
action.putValue(Action.NAME, actionId);
// Register keystroke
dialog.getRootPane()
.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(keyStroke),
action.getValue(Action.NAME));
// Register action
dialog.getRootPane().getActionMap()
.put(action.getValue(Action.NAME), action);
}
/**
* Removes the "TranslateMe" sign from the end of not translated texts.
*/
public static String removeTranslateComment(String inputString) {
if (inputString != null
&& inputString.endsWith(FreeMindCommon.POSTFIX_TRANSLATE_ME)) {
// remove POSTFIX_TRANSLATE_ME:
inputString = inputString.substring(0, inputString.length()
- FreeMindCommon.POSTFIX_TRANSLATE_ME.length());
}
return inputString;
}
/**
* Returns the same URL as input with the addition, that the reference part
* "#..." is filtered out.
*
* @throws MalformedURLException
*/
public static URL getURLWithoutReference(URL input)
throws MalformedURLException {
return new URL(input.toString().replaceFirst("#.*", ""));
}
public static void copyStream(InputStream in, OutputStream out,
boolean pCloseOutput) throws IOException {
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
if (pCloseOutput) {
out.close();
}
}
public static Point convertPointToAncestor(Component c, Point p,
Component destination) {
int x, y;
while (c != destination) {
x = c.getX();
y = c.getY();
p.x += x;
p.y += y;
c = c.getParent();
}
return p;
}
public static void convertPointFromAncestor(Component source, Point p,
Component c) {
int x, y;
while (c != source) {
x = c.getX();
y = c.getY();
p.x -= x;
p.y -= y;
c = c.getParent();
}
;
}
public static void convertPointToAncestor(Component source, Point point,
Class ancestorClass) {
Component destination = SwingUtilities.getAncestorOfClass(
ancestorClass, source);
convertPointToAncestor(source, point, destination);
}
interface NameMnemonicHolder {
/**
*/
String getText();
/**
*/
void setText(String replaceAll);
/**
*/
void setMnemonic(char charAfterMnemoSign);
/**
*/
void setDisplayedMnemonicIndex(int mnemoSignIndex);
}
private static class ButtonHolder implements NameMnemonicHolder {
private AbstractButton btn;
public ButtonHolder(AbstractButton btn) {
super();
this.btn = btn;
}
/*
* (non-Javadoc)
*
* @see freemind.main.Tools.IAbstractButton#getText()
*/
public String getText() {
return btn.getText();
}
/*
* (non-Javadoc)
*
* @see
* freemind.main.Tools.IAbstractButton#setDisplayedMnemonicIndex(int)
*/
public void setDisplayedMnemonicIndex(int mnemoSignIndex) {
btn.setDisplayedMnemonicIndex(mnemoSignIndex);
}
/*
* (non-Javadoc)
*
* @see freemind.main.Tools.IAbstractButton#setMnemonic(char)
*/
public void setMnemonic(char charAfterMnemoSign) {
btn.setMnemonic(charAfterMnemoSign);
}
/*
* (non-Javadoc)
*
* @see freemind.main.Tools.IAbstractButton#setText(java.lang.String)
*/
public void setText(String text) {
btn.setText(text);
}
}
private static class ActionHolder implements NameMnemonicHolder {
private Action action;
public ActionHolder(Action action) {
super();
this.action = action;
}
/*
* (non-Javadoc)
*
* @see freemind.main.Tools.IAbstractButton#getText()
*/
public String getText() {
return action.getValue(Action.NAME).toString();
}
/*
* (non-Javadoc)
*
* @see
* freemind.main.Tools.IAbstractButton#setDisplayedMnemonicIndex(int)
*/
public void setDisplayedMnemonicIndex(int mnemoSignIndex) {
}
/*
* (non-Javadoc)
*
* @see freemind.main.Tools.IAbstractButton#setMnemonic(char)
*/
public void setMnemonic(char charAfterMnemoSign) {
int vk = (int) charAfterMnemoSign;
if (vk >= 'a' && vk <= 'z')
vk -= ('a' - 'A');
action.putValue(Action.MNEMONIC_KEY, new Integer(vk));
}
/*
* (non-Javadoc)
*
* @see freemind.main.Tools.IAbstractButton#setText(java.lang.String)
*/
public void setText(String text) {
action.putValue(Action.NAME, text);
}
}
public static class MindMapNodePair {
MindMapNode first;
MindMapNode second;
public MindMapNodePair(MindMapNode first, MindMapNode second) {
this.first = first;
this.second = second;
}
public MindMapNode getCorresponding() {
return first;
}
public MindMapNode getCloneNode() {
return second;
}
}
/**
* Ampersand indicates that the character after it is a mnemo, unless the
* character is a space. In "Find & Replace", ampersand does not label
* mnemo, while in "&About", mnemo is "Alt + A".
*/
public static void setLabelAndMnemonic(AbstractButton btn, String inLabel) {
setLabelAndMnemonic(new ButtonHolder(btn), inLabel);
}
/**
* Ampersand indicates that the character after it is a mnemo, unless the
* character is a space. In "Find & Replace", ampersand does not label
* mnemo, while in "&About", mnemo is "Alt + A".
*/
public static void setLabelAndMnemonic(Action action, String inLabel) {
setLabelAndMnemonic(new ActionHolder(action), inLabel);
}
private static void setLabelAndMnemonic(NameMnemonicHolder item,
String inLabel) {
String rawLabel = inLabel;
if (rawLabel == null)
rawLabel = item.getText();
if (rawLabel == null)
return;
item.setText(removeMnemonic(rawLabel));
int mnemoSignIndex = rawLabel.indexOf("&");
if (mnemoSignIndex >= 0 && mnemoSignIndex + 1 < rawLabel.length()) {
char charAfterMnemoSign = rawLabel.charAt(mnemoSignIndex + 1);
if (charAfterMnemoSign != ' ') {
// no mnemonics under Mac OS:
if (!isMacOsX()) {
item.setMnemonic(charAfterMnemoSign);
// sets the underline to exactly this character.
item.setDisplayedMnemonicIndex(mnemoSignIndex);
}
}
}
}
public static boolean isMacOsX() {
boolean underMac = false;
String osName = System.getProperty("os.name");
if (osName.startsWith("Mac OS")) {
underMac = true;
}
return underMac;
}
public static boolean isLinux() {
boolean underLinux = false;
String osName = System.getProperty("os.name");
if (osName.startsWith("Linux")) {
underLinux = true;
}
return underLinux;
}
public static String removeMnemonic(String rawLabel) {
return rawLabel.replaceFirst("&([^ ])", "$1");
}
public static KeyStroke getKeyStroke(final String keyStrokeDescription) {
if (keyStrokeDescription == null) {
return null;
}
final KeyStroke keyStroke = KeyStroke
.getKeyStroke(keyStrokeDescription);
if (keyStroke != null)
return keyStroke;
return KeyStroke.getKeyStroke("typed " + keyStrokeDescription);
}
public static final String JAVA_VERSION = System
.getProperty("java.version");
public static URL fileToUrl(File pFile) throws MalformedURLException {
if (pFile == null)
return null;
return pFile.toURI().toURL();
}
public static boolean isBelowJava6() {
return JAVA_VERSION.compareTo("1.6.0") < 0;
}
public static boolean isAboveJava4() {
return JAVA_VERSION.compareTo("1.4.0") > 0;
}
public static File urlToFile(URL pUrl) throws URISyntaxException {
// fix for java1.4 and java5 only.
if (isBelowJava6()) {
return new File(urlGetFile(pUrl));
}
return new File(new URI(pUrl.toString()));
}
public static void restoreAntialiasing(Graphics2D g, Object renderingHint) {
if (RenderingHints.KEY_ANTIALIASING.isCompatibleValue(renderingHint)) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, renderingHint);
}
}
public static String getFileNameProposal(MindMapNode node) {
String rootText = node.getPlainTextContent();
rootText = rootText.replaceAll("[&:/\\\\\0%$#~\\?\\*]+", "");
return rootText;
}
public static void waitForEventQueue() {
try {
// wait until AWT thread starts
// final Exception e = new IllegalArgumentException("HERE");
if (!EventQueue.isDispatchThread()) {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
// logger.info("Waited for event queue.");
// e.printStackTrace();
};
});
} else {
logger.warning("Can't wait for event queue, if I'm inside this queue!");
}
} catch (Exception e) {
freemind.main.Resources.getInstance().logException(e);
}
}
/**
* Logs the stacktrace via a dummy exception.
*/
public static void printStackTrace() {
freemind.main.Resources.getInstance().logException(
new IllegalArgumentException("HERE"));
}
/**
* Logs the stacktrace into a string.
*/
public static String getStackTrace() {
IllegalArgumentException ex = new IllegalArgumentException("HERE");
ByteArrayOutputStream b = new ByteArrayOutputStream();
ex.printStackTrace(new PrintStream(b));
return b.toString();
}
/**
* Adapts the font size inside of a component to the zoom
*
* @param c
* component
* @param zoom
* zoom factor
* @param normalFontSize
* "unzoomed" normal font size.
* @return a copy of the input font (if the size was effectively changed)
* with the correct scale.
*/
public static Font updateFontSize(Font font, float zoom, int normalFontSize) {
if (font != null) {
float oldFontSize = font.getSize2D();
float newFontSize = normalFontSize * zoom;
if (oldFontSize != newFontSize) {
font = font.deriveFont(newFontSize);
}
}
return font;
}
public static String compareText(String pText1, String pText2) {
if (pText1 == null || pText2 == null) {
return "One of the Strings is null " + pText1 + ", " + pText2;
}
StringBuffer b = new StringBuffer();
if (pText1.length() > pText2.length()) {
b.append("First string is longer :"
+ pText1.substring(pText2.length()) + "\n");
}
if (pText1.length() < pText2.length()) {
b.append("Second string is longer :"
+ pText2.substring(pText1.length()) + "\n");
}
for (int i = 0; i < Math.min(pText1.length(), pText2.length()); i++) {
if (pText1.charAt(i) != pText2.charAt(i)) {
b.append("Difference at " + i + ": " + pText1.charAt(i) + "!="
+ pText2.charAt(i) + "\n");
}
}
return b.toString();
}
public static String getHostName() {
String hostname = "UNKNOWN";
try {
InetAddress addr = InetAddress.getLocalHost();
hostname = addr.getHostName();
} catch (UnknownHostException e) {
}
return hostname;
}
public static String getUserName() {
// Get host name
String hostname = getHostName();
return System.getProperty("user.name") + "@" + hostname;
}
public static String marshall(XmlAction action) {
return XmlBindingTools.getInstance().marshall(action);
}
public static XmlAction unMarshall(String inputString) {
return XmlBindingTools.getInstance().unMarshall(inputString);
}
public static String getFileNameFromRestorable(String restoreable) {
StringTokenizer token = new StringTokenizer(restoreable, ":");
String fileName;
if (token.hasMoreTokens()) {
token.nextToken();
// fix for windows (??, fc, 25.11.2005).
fileName = token.nextToken("").substring(1);
} else {
fileName = null;
}
return fileName;
}
public static String getModeFromRestorable(String restoreable) {
StringTokenizer token = new StringTokenizer(restoreable, ":");
String mode;
if (token.hasMoreTokens()) {
mode = token.nextToken();
} else {
mode = null;
}
return mode;
}
public static Vector getVectorWithSingleElement(Object obj) {
Vector nodes = new Vector();
nodes.add(obj);
return nodes;
}
public static void swapVectorPositions(Vector pVector, int src, int dst) {
if (src >= pVector.size() || dst >= pVector.size() || src < 0
|| dst < 0) {
throw new IllegalArgumentException("One index is out of bounds "
+ src + ", " + dst + ", size= " + pVector.size());
}
pVector.set(dst, pVector.set(src, pVector.get(dst)));
}
public static Object getField(Object[] pObjects, String pField)
throws IllegalArgumentException, SecurityException,
IllegalAccessException, NoSuchFieldException {
for (int i = 0; i < pObjects.length; i++) {
Object object = pObjects[i];
for (int j = 0; j < object.getClass().getFields().length; j++) {
Field f = object.getClass().getFields()[j];
if (Tools.safeEquals(pField, f.getName())) {
return object.getClass().getField(pField).get(object);
}
}
}
return null;
}
public static boolean isUnix() {
return (File.separatorChar == '/') || isMacOsX();
}
// {{{ setPermissions() method
/**
* Sets numeric permissions of a file. On non-Unix platforms, does nothing.
* From jEdit
*/
public static void setPermissions(String path, int permissions) {
if (permissions != 0) {
if (isUnix()) {
String[] cmdarray = { "chmod",
Integer.toString(permissions, 8), path };
try {
Process process = Runtime.getRuntime().exec(cmdarray);
process.getInputStream().close();
process.getOutputStream().close();
process.getErrorStream().close();
// Jun 9 2004 12:40 PM
// waitFor() hangs on some Java
// implementations.
/*
* int exitCode = process.waitFor(); if(exitCode != 0)
* Log.log
* (Log.NOTICE,FileVFS.class,"chmod exited with code " +
* exitCode);
*/
}
// Feb 4 2000 5:30 PM
// Catch Throwable here rather than Exception.
// Kaffe's implementation of Runtime.exec throws
// java.lang.InternalError.
catch (Throwable t) {
}
}
}
} // }}}
public static String arrayToUrls(String[] pArgs) {
StringBuffer b = new StringBuffer();
for (int i = 0; i < pArgs.length; i++) {
String fileName = pArgs[i];
try {
b.append(fileToUrl(new File(fileName)));
b.append('\n');
} catch (MalformedURLException e) {
freemind.main.Resources.getInstance().logException(e);
}
}
return b.toString();
}
public static Vector/* <URL> */urlStringToUrls(String pUrls) {
String[] urls = pUrls.split("\n");
Vector ret = new Vector();
for (int i = 0; i < urls.length; i++) {
String url = urls[i];
try {
ret.add(new URL(url));
} catch (MalformedURLException e) {
freemind.main.Resources.getInstance().logException(e);
}
}
return ret;
}
/**
* @return
*/
public static boolean isHeadless() {
return GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadless();
}
/**
* @param pNode
* @param pMindMapController
* @return
*/
public static String getNodeTextHierarchy(MindMapNode pNode,
MindMapController pMindMapController) {
return pNode.getShortText(pMindMapController)
+ ((pNode.isRoot()) ? "" : (" <- " + getNodeTextHierarchy(
pNode.getParentNode(), pMindMapController)));
}
/**
*/
public static Clipboard getClipboard() {
return Toolkit.getDefaultToolkit().getSystemClipboard();
}
public static void addFocusPrintTimer() {
Timer timer = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent pE) {
logger.info("Component: "
+ KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getFocusOwner()
+ ", Window: "
+ KeyboardFocusManager.getCurrentKeyboardFocusManager()
.getFocusedWindow());
}
});
timer.start();
}
/**
* copied from HomePane.java 15 mai 2006
*
* Sweet Home 3D, Copyright (c) 2006 Emmanuel PUYBARET / eTeks
* <info@eteks.com>
*
* - This listener manages accelerator keys that may require the use of
* shift key depending on keyboard layout (like + - or ?)
*/
public static void invokeActionsToKeyboardLayoutDependantCharacters(
KeyEvent pEvent, Action[] specialKeyActions, Object pObject) {
// on purpose without shift.
int modifiersMask = KeyEvent.ALT_MASK | KeyEvent.CTRL_MASK
| KeyEvent.META_MASK;
for (int i = 0; i < specialKeyActions.length; i++) {
Action specialKeyAction = specialKeyActions[i];
KeyStroke actionKeyStroke = (KeyStroke) specialKeyAction
.getValue(Action.ACCELERATOR_KEY);
if (pEvent.getKeyChar() == actionKeyStroke.getKeyChar()
&& (pEvent.getModifiers() & modifiersMask) == (actionKeyStroke
.getModifiers() & modifiersMask)
&& specialKeyAction.isEnabled()) {
specialKeyAction.actionPerformed(new ActionEvent(pObject,
ActionEvent.ACTION_PERFORMED, (String) specialKeyAction
.getValue(Action.ACTION_COMMAND_KEY)));
pEvent.consume();
}
}
}
/**
* @param pString
* @param pSearchString
* @return the amount of occurrences of pSearchString in pString.
*/
public static int countOccurrences(String pString, String pSearchString) {
int amount = 0;
while (true) {
final int index = pString.indexOf(pSearchString);
if (index < 0) {
break;
}
amount++;
pString = pString.substring(index + pSearchString.length());
}
return amount;
}
public static void correctJSplitPaneKeyMap() {
InputMap map = (InputMap) UIManager.get("SplitPane.ancestorInputMap");
KeyStroke keyStrokeF6 = KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0);
KeyStroke keyStrokeF8 = KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0);
map.remove(keyStrokeF6);
map.remove(keyStrokeF8);
}
/**
* @param pPageFormat
* @param pPageFormatProperty
*/
public static void setPageFormatFromString(Paper pPaper,
String pPageFormatProperty) {
try {
// parse string:
StringTokenizer tokenizer = new StringTokenizer(
pPageFormatProperty, ";");
if (tokenizer.countTokens() != 6) {
logger.warning("Page format property has not the correct format:"
+ pPageFormatProperty);
return;
}
pPaper.setSize(nt(tokenizer), nt(tokenizer));
pPaper.setImageableArea(nt(tokenizer), nt(tokenizer),
nt(tokenizer), nt(tokenizer));
} catch (Exception e) {
freemind.main.Resources.getInstance().logException(e);
}
}
/**
* @param pTokenizer
* @return
*/
private static double nt(StringTokenizer pTokenizer) {
String nextToken = pTokenizer.nextToken();
try {
return Double.parseDouble(nextToken);
} catch (Exception e) {
freemind.main.Resources.getInstance().logException(e);
}
return 0;
}
/**
* @param pPageFormat
* @return
*/
public static String getPageFormatAsString(Paper pPaper) {
return pPaper.getWidth() + ";" + pPaper.getHeight() + ";"
+ pPaper.getImageableX() + ";" + pPaper.getImageableY() + ";"
+ pPaper.getImageableWidth() + ";"
+ pPaper.getImageableHeight();
}
/**
* @return
*/
public static String getHostIpAsString() {
try {
return InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
freemind.main.Resources.getInstance().logException(e);
}
return null;
}
public static String printXmlAction(XmlAction pAction) {
final String classString = pAction.getClass().getName()
.replaceAll(".*\\.", "");
if (pAction instanceof CompoundAction) {
CompoundAction compound = (CompoundAction) pAction;
StringBuffer buf = new StringBuffer("[");
for (Iterator it = compound.getListChoiceList().iterator(); it
.hasNext();) {
if (buf.length() > 1) {
buf.append(',');
}
XmlAction subAction = (XmlAction) it.next();
buf.append(printXmlAction(subAction));
}
buf.append(']');
return classString + " " + buf.toString();
}
return classString;
}
public static XmlAction deepCopy(XmlAction action) {
return (XmlAction) unMarshall(marshall(action));
}
public static String generateID(String proposedID, HashMap hashMap,
String prefix) {
String myProposedID = new String((proposedID != null) ? proposedID : "");
String returnValue;
do {
if (!myProposedID.isEmpty()) {
// there is a proposal:
returnValue = myProposedID;
// this string is tried only once:
myProposedID = "";
} else {
/*
* The prefix is to enable the id to be an ID in the sense of
* XML/DTD.
*/
returnValue = prefix
+ Integer.toString(Tools.ran.nextInt(2000000000));
}
} while (hashMap.containsKey(returnValue));
return returnValue;
}
/**
* Call this method, if you don't know, if you are in the event thread or
* not. It checks this and calls the invokeandwait or the runnable directly.
*
* @param pRunnable
* @throws InterruptedException
* @throws InvocationTargetException
*/
public static void invokeAndWait(Runnable pRunnable)
throws InvocationTargetException, InterruptedException {
if (EventQueue.isDispatchThread()) {
pRunnable.run();
} else {
EventQueue.invokeAndWait(pRunnable);
}
}
public static String getFreeMindBasePath()
throws UnsupportedEncodingException {
String path = FreeMindStarter.class.getProtectionDomain()
.getCodeSource().getLocation().getPath();
String decodedPath = URLDecoder.decode(path, "UTF-8");
logger.info("Path: " + decodedPath);
if (decodedPath.endsWith(CONTENTS_JAVA_FREEMIND_JAR)) {
decodedPath = decodedPath.substring(0, decodedPath.length()
- CONTENTS_JAVA_FREEMIND_JAR.length());
decodedPath = decodedPath + FREE_MIND_APP_CONTENTS_RESOURCES_JAVA;
logger.info("macPath: " + decodedPath);
} else if (decodedPath.endsWith(FREEMIND_LIB_FREEMIND_JAR)) {
decodedPath = decodedPath.substring(0, decodedPath.length()
- FREEMIND_LIB_FREEMIND_JAR.length());
logger.info("reducded Path: " + decodedPath);
}
return decodedPath;
}
public static Properties copyChangedProperties(Properties props2,
Properties defProps2) {
Properties toBeStored = new Properties();
for (Iterator it = props2.keySet().iterator(); it.hasNext();) {
String key = (String) it.next();
if (!safeEquals(props2.get(key), defProps2.get(key))) {
toBeStored.put(key, props2.get(key));
}
}
return toBeStored;
}
}