001: /*
002: License $Id: LogPanel.java,v 1.10 2005/06/20 20:52:44 hendriks73 Exp $
003:
004: Copyright (c) 2001-2005 tagtraum industries.
005:
006: LGPL
007: ====
008:
009: jo! is free software; you can redistribute it and/or
010: modify it under the terms of the GNU Lesser General Public
011: License as published by the Free Software Foundation; either
012: version 2.1 of the License, or (at your option) any later version.
013:
014: jo! is distributed in the hope that it will be useful,
015: but WITHOUT ANY WARRANTY; without even the implied warranty of
016: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: Lesser General Public License for more details.
018:
019: You should have received a copy of the GNU Lesser General Public
020: License along with this library; if not, write to the Free Software
021: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022:
023: For LGPL see <http://www.fsf.org/copyleft/lesser.txt>
024:
025:
026: Sun license
027: ===========
028:
029: This release contains software by Sun Microsystems. Therefore
030: the following conditions have to be met, too. They apply to the
031: files
032:
033: - lib/mail.jar
034: - lib/activation.jar
035: - lib/jsse.jar
036: - lib/jcert.jar
037: - lib/jaxp.jar
038: - lib/crimson.jar
039: - lib/servlet.jar
040: - lib/jnet.jar
041: - lib/jaas.jar
042: - lib/jaasmod.jar
043:
044: contained in this release.
045:
046: a. Licensee may not modify the Java Platform
047: Interface (JPI, identified as classes contained within the javax
048: package or any subpackages of the javax package), by creating additional
049: classes within the JPI or otherwise causing the addition to or modification
050: of the classes in the JPI. In the event that Licensee creates any
051: Java-related API and distribute such API to others for applet or
052: application development, you must promptly publish broadly, an accurate
053: specification for such API for free use by all developers of Java-based
054: software.
055:
056: b. Software is confidential copyrighted information of Sun and
057: title to all copies is retained by Sun and/or its licensors. Licensee
058: shall not modify, decompile, disassemble, decrypt, extract, or otherwise
059: reverse engineer Software. Software may not be leased, assigned, or
060: sublicensed, in whole or in part. Software is not designed or intended
061: for use in on-line control of aircraft, air traffic, aircraft navigation
062: or aircraft communications; or in the design, construction, operation or
063: maintenance of any nuclear facility. Licensee warrants that it will not
064: use or redistribute the Software for such purposes.
065:
066: c. Software is provided "AS IS," without a warranty
067: of any kind. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES,
068: INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
069: PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
070:
071: d. This License is effective until terminated. Licensee may
072: terminate this License at any time by destroying all copies of Software.
073: This License will terminate immediately without notice from Sun if Licensee
074: fails to comply with any provision of this License. Upon such termination,
075: Licensee must destroy all copies of Software.
076:
077: e. Software, including technical data, is subject to U.S.
078: export control laws, including the U.S. Export Administration Act and its
079: associated regulations, and may be subject to export or import regulations
080: in other countries. Licensee agrees to comply strictly with all such
081: regulations and acknowledges that it has the responsibility to obtain
082: licenses to export, re-export, or import Software. Software may not be
083: downloaded, or otherwise exported or re-exported (i) into, or to a national
084: or resident of, Cuba, Iraq, Iran, North Korea, Libya, Sudan, Syria or any
085: country to which the U.S. has embargoed goods; or (ii) to anyone on the
086: U.S. Treasury Department's list of Specially Designated Nations or the U.S.
087: Commerce Department's Table of Denial Orders.
088:
089:
090: Feedback
091: ========
092:
093: We encourage your feedback and suggestions and want to use your feedback to
094: improve the Software. Send all such feedback to:
095: <feedback@tagtraum.com>
096:
097: For more information on tagtraum industries and jo!
098: please see <http://www.tagtraum.com/>.
099:
100:
101: */
102: package com.tagtraum.framework.log;
103:
104: import com.tagtraum.jo.gui.ExternalViewer;
105: import com.tagtraum.framework.util.URLDecoder;
106:
107: import javax.swing.*;
108: import javax.swing.border.TitledBorder;
109: import javax.swing.event.ChangeEvent;
110: import javax.swing.event.ChangeListener;
111: import javax.swing.event.HyperlinkEvent;
112: import javax.swing.event.HyperlinkListener;
113: import javax.swing.text.BadLocationException;
114: import javax.swing.text.Element;
115: import javax.swing.text.html.HTMLDocument;
116: import javax.swing.text.html.HTMLEditorKit;
117: import javax.swing.text.html.StyleSheet;
118: import java.awt.*;
119: import java.awt.event.ActionEvent;
120: import java.awt.event.ActionListener;
121: import java.io.IOException;
122: import java.util.ResourceBundle;
123:
124: /**
125: * GUI for a log.
126: *
127: * @author Hendrik Schreiber
128: * @version 1.1beta1 $Id: LogPanel.java,v 1.10 2005/06/20 20:52:44 hendriks73 Exp $
129: * @see Log
130: */
131: public class LogPanel extends JPanel implements ChangeListener,
132: ActionListener, I_LogEventListener, I_LogControlEventListener {
133:
134: /**
135: * Source-Version
136: */
137: public static String vcid = "$Id: LogPanel.java,v 1.10 2005/06/20 20:52:44 hendriks73 Exp $";
138: private static ResourceBundle localStrings = ResourceBundle
139: .getBundle("com.tagtraum.framework.log.localStrings");
140:
141: public static String LineSeparator;
142:
143: private Log myLog;
144: private JButton myClearButton;
145: private JSlider mySlider;
146: private JTextPane textPane;
147:
148: public LogPanel(Log aLog) {
149: super (new GridBagLayout());
150: LineSeparator = System.getProperty("line.separator");
151: myLog = aLog;
152: myLog.addI_LogEventListener(this );
153:
154: final HTMLEditorKit htmlEditorKit = new HTMLEditorKit();
155: StyleSheet styleSheet = new StyleSheet();
156: styleSheet.addRule("P {margin: 0; padding: 0}");
157: styleSheet
158: .addRule("A {color: #0000cc; text-decoration: underline;}");
159: htmlEditorKit.setStyleSheet(styleSheet);
160:
161: final HTMLDocument document = (HTMLDocument) htmlEditorKit
162: .createDefaultDocument();
163: textPane = new JTextPane(document);
164: textPane.addHyperlinkListener(new HyperlinkListener() {
165: /**
166: * Called when a hypertext link is updated.
167: *
168: * @param e the event responsible for the update
169: */
170: public void hyperlinkUpdate(HyperlinkEvent e) {
171: if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
172: try {
173: ExternalViewer.displayURL(e.getURL());
174: } catch (IOException e1) {
175: e1.printStackTrace();
176: }
177: }
178: }
179: });
180: textPane.setEditable(false);
181: textPane.setEditorKit(htmlEditorKit);
182: //textPane.setLineWrap(true);
183: //textPane.setWrapStyleWord(true);
184:
185: JScrollPane scrollPane = new JScrollPane(textPane);
186:
187: myClearButton = new JButton(localStrings
188: .getString("button_clear"));
189: myClearButton.setToolTipText(localStrings
190: .getString("button_clear_tooltip"));
191:
192: //JLabel myLoglevelLabel = new JLabel("Loglevel:");
193:
194: mySlider = new JSlider(0, 5, aLog.getLevel());
195: mySlider.setToolTipText(localStrings
196: .getString("slider_loglevel_tooltip"));
197: mySlider.setSnapToTicks(true);
198: mySlider.setPaintLabels(true);
199: mySlider.setBorder(new TitledBorder(localStrings
200: .getString("panel_title")));
201: setLabelTable();
202:
203: GridBagLayout gbl = (GridBagLayout) getLayout();
204: GridBagConstraints c = new GridBagConstraints();
205:
206: c.gridwidth = GridBagConstraints.RELATIVE;
207: c.fill = GridBagConstraints.HORIZONTAL;
208: c.gridwidth = GridBagConstraints.REMAINDER;
209: gbl.setConstraints(mySlider, c);
210: add(mySlider);
211:
212: c.fill = GridBagConstraints.BOTH;
213: c.weightx = 1.0;
214: c.weighty = 1.0;
215: gbl.setConstraints(scrollPane, c);
216: add(scrollPane);
217:
218: c.fill = GridBagConstraints.NONE;
219: c.anchor = GridBagConstraints.SOUTHEAST;
220: c.weightx = 0.0;
221: c.weighty = 0.0;
222: gbl.setConstraints(myClearButton, c);
223: add(myClearButton);
224:
225: myClearButton.addActionListener((ActionListener) this );
226: mySlider.addChangeListener((ChangeListener) this );
227: }
228:
229: /**
230: * Handle a {@link LogControlEvent}.
231: */
232: public void handleLogControlEvent(LogControlEvent le) {
233: if (myLog.getLevel() > mySlider.getMaximum()) {
234: mySlider.setMaximum(myLog.getLevel());
235: setLabelTable();
236: }
237: mySlider.setValue(myLog.getLevel());
238: }
239:
240: /**
241: * Handle a {@link LogEvent}.
242: */
243: public void handleLogEvent(LogEvent le) {
244: // make sure we don't let the panel get too big
245: String str = le.toString();
246: final HTMLDocument document = (HTMLDocument) textPane
247: .getDocument();
248: final Element root = document.getRootElements()[0];
249: final Element body = root.getElement(0);
250: final Element lastBodyChild = body.getElement(body
251: .getElementCount() - 1);
252: while (document.getLength() + str.length() > 32000) {
253: // remove a portion at the beginning.
254: try {
255: Element firstBodyChild = body.getElement(0);
256: document.remove(firstBodyChild.getStartOffset(),
257: firstBodyChild.getEndOffset()
258: - firstBodyChild.getStartOffset());
259: } catch (BadLocationException ble) {
260: break;
261: }
262: }
263: try {
264: document.insertAfterEnd(lastBodyChild, toHTML(le));
265: } catch (BadLocationException e) {
266: e.printStackTrace();
267: } catch (IOException e) {
268: e.printStackTrace();
269: }
270: }
271:
272: private static String logLevelToColor(int logLevel) {
273: switch (logLevel) {
274: case C_Log.ERROR:
275: return "#cc0000";
276: case C_Log.MODULE:
277: return "#000000";
278: case C_Log.METHOD:
279: return "#333333";
280: case C_Log.VERBOSE:
281: return "#444444";
282: default:
283: return "#666666";
284: }
285: }
286:
287: private static String toHTML(LogEvent logEvent) {
288: String s = logEvent.toString();
289: StringBuffer sb = new StringBuffer(s.length() * 2);
290: sb.append("<p><font color=\""
291: + logLevelToColor(logEvent.getLevel()) + "\">");
292: int linkOffset = -1;
293: for (int i = 0, max = s.length(); i < max; i++) {
294: final char c = s.charAt(i);
295: if (linkOffset >= 0) {
296: switch (c) {
297: case ' ':
298: case '\t':
299: case ',':
300: case '\r':
301: case '\n':
302: case ')':
303: case ']':
304: case '}':
305: case ';':
306: case '\'':
307: final String url = sb.substring(linkOffset);
308: sb.insert(linkOffset, "<a href=\"" + url + "\">");
309: sb.append("</a>");
310: linkOffset = -1;
311: break;
312: default:
313: }
314: }
315: switch (c) {
316: case '&':
317: sb.append("&");
318: break;
319: case '<':
320: sb.append("<");
321: break;
322: case '>':
323: sb.append(">");
324: break;
325: case ' ':
326: sb.append(" ");
327: break;
328: case '\t':
329: sb.append(" ");
330: break;
331: case '\n':
332: if (i + 1 < max) {
333: sb.append("<br>");
334: }
335: break;
336: case '\r':
337: break;
338: default:
339: sb.append(c);
340: }
341: // detect file:/ protocol
342: if (linkOffset < 0
343: && sb.substring(sb.length() - 6).equals("file:/")) {
344: linkOffset = sb.length() - 6;
345: }
346: }
347: sb.append("</p>");
348: return sb.toString();
349: }
350:
351: public void setLabelTable() {
352: mySlider.setLabelTable(mySlider.createStandardLabels(1));
353: }
354:
355: public void stateChanged(ChangeEvent ce) {
356: if (ce.getSource() == mySlider) {
357: myLog.setLevel(mySlider.getValue());
358: }
359: }
360:
361: public void actionPerformed(ActionEvent ae) {
362: if (ae.getSource() == myClearButton) {
363: textPane.setText(null);
364: }
365: }
366: }
|