source: src/main/java/weka/gui/LogWindow.java @ 6

Last change on this file since 6 was 4, checked in by gnappo, 14 years ago

Import di weka.

File size: 13.8 KB
Line 
1/*
2 *    This program is free software; you can redistribute it and/or modify
3 *    it under the terms of the GNU General Public License as published by
4 *    the Free Software Foundation; either version 2 of the License, or
5 *    (at your option) any later version.
6 *
7 *    This program is distributed in the hope that it will be useful,
8 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 *    GNU General Public License for more details.
11 *
12 *    You should have received a copy of the GNU General Public License
13 *    along with this program; if not, write to the Free Software
14 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16
17/*
18 * LogWindow.java
19 * Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
20 *
21 */
22
23package weka.gui;
24
25import weka.core.Tee;
26import weka.core.Utils;
27
28import java.awt.BorderLayout;
29import java.awt.Color;
30import java.awt.Container;
31import java.awt.Dimension;
32import java.awt.FlowLayout;
33import java.awt.GridLayout;
34import java.awt.event.ActionEvent;
35import java.awt.event.ActionListener;
36import java.awt.event.ItemEvent;
37import java.awt.event.ItemListener;
38import java.io.PrintStream;
39
40import javax.swing.JButton;
41import javax.swing.JCheckBox;
42import javax.swing.JFrame;
43import javax.swing.JLabel;
44import javax.swing.JPanel;
45import javax.swing.JScrollPane;
46import javax.swing.JSpinner;
47import javax.swing.JTextPane;
48import javax.swing.SpinnerNumberModel;
49import javax.swing.event.CaretEvent;
50import javax.swing.event.CaretListener;
51import javax.swing.event.ChangeEvent;
52import javax.swing.event.ChangeListener;
53import javax.swing.text.Style;
54import javax.swing.text.StyleConstants;
55import javax.swing.text.StyleContext;
56import javax.swing.text.StyledDocument;
57
58/**
59 * Frame that shows the output from stdout and stderr.
60 *
61 * @author  FracPete (fracpete at waikato dot ac dot nz)
62 * @version $Revision: 4973 $
63 */
64public class LogWindow 
65  extends JFrame
66  implements CaretListener, ChangeListener {
67
68  /** for serialization */
69  private static final long serialVersionUID = 5650947361381061112L;
70
71  /** the name of the style for stdout */
72  public final static String STYLE_STDOUT = "stdout";
73
74  /** the name of the style for stderr */
75  public final static String STYLE_STDERR = "stderr";
76
77  /** the color of the style for stdout */
78  public final static Color COLOR_STDOUT = Color.BLACK;
79
80  /** the Color of the style for stderr */
81  public final static Color COLOR_STDERR = Color.RED;
82
83  /** whether we're debugging - enables output on stdout */
84  public final static boolean DEBUG = false;
85
86  /** whether the JTextPane has wordwrap or not */
87  public boolean m_UseWordwrap = true;
88 
89  /** the output */
90  protected JTextPane m_Output = new JTextPane();
91
92  /** the clear button */
93  protected JButton m_ButtonClear = new JButton("Clear");
94
95  /** the close button */
96  protected JButton m_ButtonClose = new JButton("Close");
97
98  /** the current size */
99  protected JLabel m_LabelCurrentSize = new JLabel("currently: 0");
100
101  /** the spinner for the max number of chars */
102  protected JSpinner m_SpinnerMaxSize = new JSpinner();
103
104  /** whether to allow wordwrap or not */
105  protected JCheckBox m_CheckBoxWordwrap = new JCheckBox("Use wordwrap");
106
107  /** for redirecting stdout */
108  protected static Tee m_TeeOut = null;
109
110  /** for redirecting stderr */
111  protected static Tee m_TeeErr = null;
112
113  /** inner class for printing to the window, is used instead of standard
114   * System.out and System.err */
115  protected class LogWindowPrintStream extends PrintStream {
116    /** the parent */
117    protected LogWindow m_Parent = null;
118
119    /** the style of the printstream */
120    protected String m_Style = null;
121   
122    /**
123     * the constructor
124     * @param parent      the parent frame
125     * @param stream      the stream (used for constructor of superclass)
126     * @param style       the style name associated with this output
127     */
128    public LogWindowPrintStream( LogWindow parent, 
129                                 PrintStream stream, 
130                                 String style ) {
131      super(stream);
132
133      m_Parent = parent;
134      m_Style  = style;
135    }
136   
137    /**
138     * flushes the printstream
139     */
140    public synchronized void flush() {
141      // ignored
142    }
143
144    /**
145     * prints the given int
146     */
147    public synchronized void print(int x) {
148      print(new Integer(x).toString());
149    }
150
151    /**
152     * prints the given boolean
153     */
154    public synchronized void print(boolean x) {
155      print(new Boolean(x).toString());
156    }
157
158    /**
159     * prints the given string
160     */
161    public synchronized void print(String x) {
162      StyledDocument      doc;
163      int                 size;
164      int                 maxSize;
165      int                 pos;
166     
167      doc = m_Parent.m_Output.getStyledDocument();
168
169      try {
170        // insert text
171        doc.insertString(doc.getLength(), x, doc.getStyle(m_Style));
172       
173        // move cursor to end
174        m_Parent.m_Output.setCaretPosition(doc.getLength());
175
176        // trim size if necessary
177        m_Parent.trim();
178      }
179      catch (Exception e) {
180        e.printStackTrace();
181      }
182    }
183
184    /**
185     * prints the given object
186     */
187    public synchronized void print(Object x) {
188      String                  line;
189      Throwable               t;
190      StackTraceElement[]     trace;
191      int                     i;
192
193      if (x instanceof Throwable) {
194        t     = (Throwable) x;
195        trace = t.getStackTrace();
196        line  = t.getMessage() + "\n";
197        for (i = 0; i < trace.length; i++)
198          line += "\t" + trace[i].toString() + "\n";
199        x = line;
200      }
201
202      if (x == null)
203        print("null");
204      else
205        print(x.toString());
206    }
207
208    /**
209     * prints a new line
210     */
211    public synchronized void println() {
212      print("\n");
213    }
214
215    /**
216     * prints the given int
217     */
218    public synchronized void println(int x) {
219      print(x);
220      println();
221    }
222
223    /**
224     * prints the given boolean
225     */
226    public synchronized void println(boolean x) {
227      print(x);
228      println();
229    }
230
231    /**
232     * prints the given string
233     */
234    public synchronized void println(String x) {
235      print(x);
236      println();
237    }
238
239    /**
240     * prints the given object (for Throwables we print the stack trace)
241     */
242    public synchronized void println(Object x) {
243      print(x);
244      println();
245    }
246  }
247 
248  /**
249   * creates the frame
250   */
251  public LogWindow() {
252    super("Weka - Log");
253
254    createFrame();
255
256    // styles
257    StyledDocument      doc;
258    Style               style;
259    boolean             teeDone;
260
261    doc   = m_Output.getStyledDocument();
262    style = StyleContext.getDefaultStyleContext()
263                        .getStyle(StyleContext.DEFAULT_STYLE);
264    style = doc.addStyle(STYLE_STDOUT, style);
265    StyleConstants.setFontFamily(style, "monospaced");
266    StyleConstants.setForeground(style, COLOR_STDOUT);
267   
268    style = StyleContext.getDefaultStyleContext()
269                        .getStyle(StyleContext.DEFAULT_STYLE);
270    style = doc.addStyle(STYLE_STDERR, style);
271    StyleConstants.setFontFamily(style, "monospaced");
272    StyleConstants.setForeground(style, COLOR_STDERR);
273
274    // print streams (instantiate only once!)
275    teeDone = !((m_TeeOut == null) && (m_TeeErr == null));
276    if (!DEBUG) {
277      if (!teeDone) {
278        m_TeeOut = new Tee(System.out);
279        System.setOut(m_TeeOut);
280      }
281      m_TeeOut.add(
282          new LogWindowPrintStream(this, m_TeeOut.getDefault(), STYLE_STDOUT));
283    }
284
285    if (!teeDone) {
286      m_TeeErr = new Tee(System.err);
287      System.setErr(m_TeeErr);
288    }
289    m_TeeErr.add(
290        new LogWindowPrintStream(this, m_TeeErr.getDefault(), STYLE_STDERR));
291  }
292
293  /**
294   * creates the frame and all its components
295   */
296  protected void createFrame() {
297    JPanel                panel;
298    JPanel                panel2;
299    JPanel                panel3;
300    JPanel                panel4;
301    SpinnerNumberModel    model;
302    int                   width;
303    JLabel                label;
304
305    // set layout
306    setSize(600, 400);
307    width = getBounds().width;
308    setLocation(
309        getGraphicsConfiguration().getBounds().width - width, getLocation().y);
310    getContentPane().setLayout(new BorderLayout());
311   
312    // output
313    getContentPane().add(new JScrollPane(m_Output), BorderLayout.CENTER);
314    setWordwrap(m_UseWordwrap);
315   
316    // button(s)
317    panel = new JPanel(new BorderLayout());
318    getContentPane().add(panel, BorderLayout.SOUTH);
319    panel3 = new JPanel(new BorderLayout());
320    panel.add(panel3, BorderLayout.SOUTH);
321    panel2 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
322    panel3.add(panel2, BorderLayout.EAST);
323
324    m_ButtonClear.setMnemonic('C');
325    m_ButtonClear.addActionListener(new ActionListener() {
326        public void actionPerformed(ActionEvent e) {
327          clear();
328        }
329      });
330    panel2.add(m_ButtonClear);
331
332    m_ButtonClose.setMnemonic('l');
333    m_ButtonClose.addActionListener(new ActionListener() {
334        public void actionPerformed(ActionEvent e) {
335          close();
336        }
337      });
338    panel2.add(m_ButtonClose);
339
340    // size + current size + wordwrap
341    panel2 = new JPanel(new GridLayout(1, 3));
342    panel3.add(panel2, BorderLayout.WEST);
343   
344    // size
345    panel4 = new JPanel(new FlowLayout());
346    panel2.add(panel4);
347    model = (SpinnerNumberModel) m_SpinnerMaxSize.getModel();
348    model.setMinimum(new Integer(1));
349    model.setStepSize(new Integer(1000));
350    model.setValue(new Integer(100000));
351    model.addChangeListener(this);
352
353    label = new JLabel("max. Size");
354    label.setDisplayedMnemonic('m');
355    label.setLabelFor(m_SpinnerMaxSize);
356
357    panel4.add(label);
358    panel4.add(m_SpinnerMaxSize);
359
360    // current size
361    panel4 = new JPanel(new FlowLayout());
362    panel2.add(panel4);
363    panel4.add(m_LabelCurrentSize);
364
365    // wordwrap
366    panel4 = new JPanel(new FlowLayout());
367    panel2.add(panel4);
368    m_CheckBoxWordwrap.setSelected(m_UseWordwrap);
369    m_CheckBoxWordwrap.addItemListener(new ItemListener() {
370        public void itemStateChanged(ItemEvent e) {
371          setWordwrap(m_CheckBoxWordwrap.isSelected());
372        }
373      });
374    panel4.add(m_CheckBoxWordwrap);
375  }
376
377  /**
378   * clears the output
379   */
380  public void clear() {
381    m_Output.setText("");
382  }
383
384  /**
385   * closes the frame
386   */
387  public void close() {
388    setVisible(false);
389  }
390
391  /**
392   * trims the JTextPane, if too big
393   */
394  public void trim() {
395    StyledDocument      doc;
396    int                 size;
397    int                 maxSize;
398    int                 pos;
399   
400    doc = m_Output.getStyledDocument();
401
402    // too large?
403    size    = doc.getLength();
404    maxSize = ((Integer) m_SpinnerMaxSize.getValue()).intValue();
405    if (size > maxSize) {
406      try {
407        // determine EOL after which to cut
408        pos = size - maxSize;
409        while (!doc.getText(pos, 1).equals("\n"))
410          pos++;
411        while (doc.getText(pos, 1).equals("\n")) 
412          pos++;
413        // delete text
414        doc.remove(0, pos);
415      }
416      catch (Exception ex) {
417        // don't print it, otherwise we get an endless loop!
418        if (DEBUG)
419          System.out.println(ex);
420      }
421    }
422   
423    // move cursor to end
424    m_Output.setCaretPosition(doc.getLength());
425  }
426
427  /**
428   * returns a string representation (#RGB) of the given color
429   */
430  protected String colorToString(Color c) {
431    String      result;
432   
433    result = "#" + Utils.padLeft(Integer.toHexString(c.getRed()),   2)
434                 + Utils.padLeft(Integer.toHexString(c.getGreen()), 2)
435                 + Utils.padLeft(Integer.toHexString(c.getBlue()),  2);
436
437    result = result.replaceAll("\\ ", "0").toUpperCase();
438   
439    return result;
440  }
441
442  /**
443   * toggles the wordwrap<br/>
444   * override wordwrap from:
445   * http://forum.java.sun.com/thread.jspa?threadID=498535&messageID=2356174
446   */
447  public void setWordwrap(boolean wrap) {
448    Container   parent;
449    JTextPane   outputOld;
450   
451    m_UseWordwrap = wrap;
452    if (m_CheckBoxWordwrap.isSelected() != m_UseWordwrap)
453      m_CheckBoxWordwrap.setSelected(m_UseWordwrap);
454
455    // create new JTextPane
456    parent    = m_Output.getParent();
457    outputOld = m_Output;
458    if (m_UseWordwrap)
459      m_Output = new JTextPane();
460    else
461      m_Output = new JTextPane(){
462        private static final long serialVersionUID = -8275856175921425981L;
463        public void setSize(Dimension d) {   
464          if (d.width < getGraphicsConfiguration().getBounds().width) 
465            d.width = getGraphicsConfiguration().getBounds().width; 
466          super.setSize(d);
467        }
468
469        public boolean getScrollableTracksViewportWidth() { 
470          return false; 
471        }
472      };
473    m_Output.setEditable(false);
474    m_Output.addCaretListener(this);
475    m_Output.setDocument(outputOld.getDocument());
476    m_Output.setCaretPosition(m_Output.getDocument().getLength());
477    //m_Output.setToolTipText(
478    //      "stdout = " + colorToString(COLOR_STDOUT) + ", "
479    //    + "stderr = " + colorToString(COLOR_STDERR));
480    parent.add(m_Output);
481    parent.remove(outputOld);
482  }
483
484  /**
485   * Called when the caret position is updated.
486   */
487  public void caretUpdate(CaretEvent e) {
488    m_LabelCurrentSize.setText(
489        "currently: " + m_Output.getStyledDocument().getLength());
490
491    if (DEBUG)
492      System.out.println(e);
493  }
494
495  /**
496   * Invoked when the target of the listener has changed its state.
497   */
498  public void stateChanged(ChangeEvent e) {
499    // check max size if Spinner is changed
500    if (e.getSource() == m_SpinnerMaxSize.getModel()) {
501      trim();
502      validate();
503      caretUpdate(null);
504    }
505  }
506
507  /**
508   * for testing only
509   */
510  public static void main(String[] args) {
511    LogWindow       log;
512
513    LookAndFeel.setLookAndFeel();
514   
515    log = new LogWindow();
516    log.setVisible(true);
517    log.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
518
519    // test output
520    System.out.print("a");
521    System.err.print("a");
522    System.out.print("a");
523    System.out.println();
524    System.err.println(new java.util.Date());
525  }
526}
Note: See TracBrowser for help on using the repository browser.