001: /*
002: * Gruntspud
003: *
004: * Copyright (C) 2002 Brett Smith.
005: *
006: * Written by: Brett Smith <t_magicthize@users.sourceforge.net>
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU Library General Public License
010: * as published by the Free Software Foundation; either version 2 of
011: * the License, or (at your option) any later version.
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU Library General Public License for more details.
016: *
017: * You should have received a copy of the GNU Library General Public
018: * License along with this program; if not, write to the Free Software
019: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
020: */
021:
022: package gruntspud;
023:
024: import gruntspud.ui.MultilineLabel;
025:
026: import java.awt.Component;
027: import java.io.BufferedInputStream;
028: import java.io.BufferedOutputStream;
029: import java.io.File;
030: import java.io.FileOutputStream;
031: import java.io.IOException;
032: import java.io.InputStream;
033: import java.io.OutputStream;
034: import java.io.PrintWriter;
035: import java.io.StringWriter;
036: import java.text.DateFormat;
037: import java.text.DecimalFormat;
038: import java.text.NumberFormat;
039: import java.text.SimpleDateFormat;
040: import java.util.Date;
041: import java.util.StringTokenizer;
042: import java.util.TimeZone;
043:
044: import javax.swing.JOptionPane;
045:
046: import org.netbeans.lib.cvsclient.connection.AuthenticationException;
047:
048: /**
049: * Description of the Class
050: *
051: *@author magicthize
052: *@created 26 May 2002
053: */
054: public class GruntspudUtil {
055: private final static NumberFormat FILE_SIZE_FORMAT = new DecimalFormat();
056:
057: public final static File PREFERENCES_DIRECTORY = new File(System
058: .getProperty("user.home")
059: + File.separator + ".gruntspud");
060:
061: static {
062: FILE_SIZE_FORMAT.setMinimumFractionDigits(1);
063: FILE_SIZE_FORMAT.setMaximumFractionDigits(1);
064: }
065:
066: private static char[] XML_SPECIAL_CHARACTERS = { '&', '<', '>',
067: '\'' };
068: private static String[] XML_REPLACEMENT_CHACTERS = { "&", "<", ">",
069: "'" };
070:
071: public static String encodeXML(String text) {
072: StringBuffer buffer = new StringBuffer();
073: boolean replaced;
074: for (int i = 0; i < text.length(); i++) {
075: char ch = text.charAt(i);
076: replaced = false;
077: for (int k = 0; k < XML_SPECIAL_CHARACTERS.length
078: && !replaced; k++) {
079: if (ch == XML_SPECIAL_CHARACTERS[k]) {
080: buffer.append(XML_REPLACEMENT_CHACTERS[k]);
081: replaced = true;
082: }
083: }
084: if (!replaced)
085: buffer.append(ch);
086: }
087: return buffer.toString();
088: }
089:
090: /**
091: * Show an error dialog given an exception
092: *
093: * @param component parent component
094: * @param title
095: * @param execption exception
096: */
097: public static void showErrorMessage(Component parent, String title,
098: Throwable exception) {
099: showErrorMessage(parent, null, title, exception);
100: }
101:
102: /**
103: * Show an error dialog given an exception
104: *
105: * @param component parent component
106: * @param mesg option message
107: * @param title title
108: * @param execption exception
109: */
110: public static void showErrorMessage(Component parent, String mesg,
111: String title, Throwable exception) {
112: boolean details = false;
113: while (true) {
114: String[] opts = new String[] {
115: details ? "Hide Details" : "Details", "Ok" };
116: StringBuffer buf = new StringBuffer();
117: if (mesg != null) {
118: buf.append(mesg);
119: }
120: appendException(exception, 0, buf, details);
121: MultilineLabel message = new MultilineLabel(buf.toString());
122: int opt = JOptionPane.showOptionDialog(parent, message,
123: title, JOptionPane.OK_CANCEL_OPTION,
124: JOptionPane.ERROR_MESSAGE, null, opts, opts[1]);
125: if (opt == 0) {
126: details = !details;
127: } else {
128: break;
129: }
130: }
131: }
132:
133: private static void appendException(Throwable exception, int level,
134: StringBuffer buf, boolean details) {
135: if (exception.getMessage() != null
136: && exception.getMessage().length() > 0) {
137: if (details && level > 0)
138: buf.append("\n \nCaused by ...\n");
139: buf.append(exception.getMessage());
140: }
141: if (details) {
142: if (exception.getMessage() == null
143: || exception.getMessage().length() == 0) {
144: buf.append("\n \nCaused by ...");
145: } else {
146: buf.append("\n \n");
147: }
148: StringWriter sw = new StringWriter();
149: exception.printStackTrace(new PrintWriter(sw));
150: buf.append(sw.toString());
151: }
152: if (exception instanceof GruntspudException
153: && ((GruntspudException) exception).getRootCause() != null) {
154: appendException(((GruntspudException) exception)
155: .getRootCause(), level + 1, buf, details);
156: } else if (exception instanceof AuthenticationException
157: && ((AuthenticationException) exception)
158: .getUnderlyingThrowable() != null) {
159: buf.append(" \nCaused by ...\n \n");
160: appendException(((AuthenticationException) exception)
161: .getUnderlyingThrowable(), level + 1, buf, details);
162: } else {
163: try {
164: java.lang.reflect.Method method = exception.getClass()
165: .getMethod("getCause", new Class[] {});
166: Throwable cause = (Throwable) method.invoke(exception,
167: null);
168: if (cause != null) {
169: appendException(cause, level + 1, buf, details);
170: }
171: } catch (Exception e) {
172: Constants.SYSTEM_LOG
173: .warn("Cause of exception could not be determined");
174: }
175: }
176: }
177:
178: /**
179: * Copy the input from one stream to the output of another until EOF. It
180: * is up to the invoker to close the streams.
181: *
182: * @param in input stream
183: * @param out output stream
184: * @param buf buffer size (-1 means don't buffer)
185: */
186: public static void copyStreams(InputStream in, OutputStream out,
187: int buf) throws IOException {
188: copyStreams(in, out, buf, -1);
189: }
190:
191: /**
192: * Copy the input from one stream to the output of another for a number of
193: * bytes (-1 means until EOF)
194: *
195: * @param in input stream
196: * @param out output stream
197: * @param buf buffer size (-1 means don't buffer)
198: * @param bytes bytes to copy
199: */
200: public static void copyStreams(InputStream in, OutputStream out,
201: int buf, long bytes) throws IOException {
202: InputStream bin = (buf == -1) ? in : new BufferedInputStream(
203: in, buf);
204: OutputStream bout = (buf == -1) ? out
205: : new BufferedOutputStream(out, buf);
206: byte[] b = null;
207: int r = 0;
208:
209: while (true && ((bytes == -1) || (r >= bytes))) {
210: int a = bin.available();
211:
212: if (a == -1) {
213: break;
214: } else if (a == 0) {
215: a = 1;
216:
217: }
218: if ((bytes != -1) && ((r + a) > bytes)) {
219: a -= ((r + a) - bytes);
220:
221: }
222: b = new byte[a];
223: a = bin.read(b);
224:
225: if (a == -1) {
226: break;
227: }
228:
229: r += a;
230: bout.write(b, 0, a);
231: }
232:
233: bout.flush();
234: }
235:
236: /**
237: * Gets the selectedGlobalCVSRoot attribute of the GruntspudUtil class
238: *
239: *@param host Description of the Parameter
240: *@return The selectedGlobalCVSRoot value
241: */
242: public static CVSRoot getSelectedGlobalCVSRoot(
243: GruntspudContext context) {
244: StringTokenizer s = new StringTokenizer(context.getHost()
245: .getProperty(Constants.OPTIONS_CONNECTION_ROOT_LIST,
246: "|"), "");
247:
248: while (s.hasMoreTokens()) {
249: boolean sel = false;
250: String t = s.nextToken();
251:
252: if (t.startsWith("&")) {
253: t = t.substring(1);
254: sel = true;
255: }
256:
257: if (sel) {
258: try {
259: return new CVSRoot(t);
260: } catch (IllegalArgumentException iae) {
261: }
262: }
263: }
264:
265: return null;
266: }
267:
268: public static File getPreferenceFile(String name, boolean create) {
269: File d = new File(PREFERENCES_DIRECTORY, name);
270: if (!PREFERENCES_DIRECTORY.exists()
271: && !PREFERENCES_DIRECTORY.mkdirs()) {
272: Constants.SYSTEM_LOG
273: .error("Could not create preferences directory.");
274: return null;
275: } else {
276: if (!d.exists() && create) {
277: FileOutputStream out = null;
278: Constants.SYSTEM_LOG.info("Creating preferences file "
279: + d.getAbsolutePath());
280: try {
281: out = new FileOutputStream(d);
282: } catch (IOException ioe) {
283: Constants.SYSTEM_LOG.error(
284: "Failed to create preferences file "
285: + d.getAbsolutePath(), ioe);
286: return null;
287: } finally {
288: GruntspudUtil.closeStream(out);
289: }
290: }
291: return d;
292: }
293: }
294:
295: /**
296: * Create a fake stack trace
297: */
298: public static void stackTrace() {
299: try {
300: throw new Exception("STACK TRACE");
301: } catch (Exception e) {
302: e.printStackTrace();
303: }
304: }
305:
306: /**
307: * Close an input stream and don't worry about any exceptions, but return
308: * true or false instead. If <code>null</code> is supplied as they stream
309: * then it is just ignored
310: *
311: * @param stream stream to close
312: * @return closed ok
313: */
314: public static boolean closeStream(InputStream in) {
315: try {
316: if (in != null) {
317: in.close();
318:
319: }
320: return true;
321: } catch (IOException ioe) {
322: return false;
323: }
324: }
325:
326: /**
327: * Close an output stream and don't worry about any exceptions, but return
328: * true or false instead. If <code>null</code> is supplied as they stream
329: * then it is just ignored
330: *
331: * @param stream stream to close
332: * @return closed ok
333: */
334: public static boolean closeStream(OutputStream out) {
335: try {
336: if (out != null) {
337: out.close();
338:
339: }
340: return true;
341: } catch (IOException ioe) {
342: return false;
343: }
344: }
345:
346: /**
347: * Format a date to GMT
348: */
349: public static String formatDate(Date date, GruntspudContext context) {
350: DateFormat format = new SimpleDateFormat(StringListModel
351: .getSelectedItemForStringListPropertyString(context
352: .getHost().getProperty(
353: Constants.OPTIONS_DISPLAY_DATE_FORMAT,
354: "&" + Constants.DEFAULT_DATE_FORMAT)));
355: format.setTimeZone(TimeZone.getTimeZone("GMT+0000"));
356:
357: return format.format(date);
358: }
359:
360: /**
361: *
362: */
363: public static String formatFileSize(long size) {
364: double bytes = (double) size;
365:
366: if (bytes < 1024) {
367: return String.valueOf((int) bytes) + " bytes";
368: } else if (bytes < 1048576) {
369: return FILE_SIZE_FORMAT.format(bytes / 1024) + " K";
370: } else {
371:
372: return FILE_SIZE_FORMAT.format(bytes / 1024 / 1024) + " MB";
373: }
374: }
375: }
|