1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest.exec;
  28 
  29 
  30 import com.sun.javatest.TestSuite;
  31 import com.sun.javatest.WorkDirectory;
  32 import com.sun.javatest.logging.FilteredLogModel;
  33 import com.sun.javatest.logging.LogModel;
  34 import com.sun.javatest.tool.UIFactory;
  35 import com.sun.javatest.tool.ToolDialog;
  36 import com.sun.javatest.logging.LoggerFactory;
  37 import com.sun.javatest.tool.FileChooser;
  38 import com.sun.javatest.tool.Preferences;
  39 
  40 import java.awt.*;
  41 import java.awt.event.ActionEvent;
  42 import java.awt.event.ActionListener;
  43 import java.awt.event.ItemEvent;
  44 import java.awt.event.ItemListener;
  45 import java.io.File;
  46 import java.io.IOException;
  47 import java.util.ArrayList;
  48 import java.util.EventObject;
  49 import java.util.Random;
  50 import java.util.HashSet;
  51 import java.util.logging.Level;
  52 import java.util.logging.Logger;
  53 import javax.swing.AbstractAction;
  54 import javax.swing.DefaultListCellRenderer;
  55 import javax.swing.JButton;
  56 import javax.swing.JCheckBox;
  57 import javax.swing.JComboBox;
  58 import javax.swing.JComponent;
  59 import javax.swing.JDialog;
  60 import javax.swing.JFileChooser;
  61 import javax.swing.JLabel;
  62 import javax.swing.JList;
  63 import javax.swing.JOptionPane;
  64 import javax.swing.JPanel;
  65 import javax.swing.JScrollBar;
  66 import javax.swing.JScrollPane;
  67 import javax.swing.JSeparator;
  68 import javax.swing.JTextField;
  69 import javax.swing.JTextPane;
  70 import javax.swing.JTree;
  71 import javax.swing.ListCellRenderer;
  72 import javax.swing.SwingConstants;
  73 import javax.swing.SwingUtilities;
  74 import javax.swing.text.AbstractDocument;
  75 import javax.swing.text.BadLocationException;
  76 import javax.swing.text.BoxView;
  77 import javax.swing.text.ComponentView;
  78 import javax.swing.text.Element;
  79 import javax.swing.text.IconView;
  80 import javax.swing.text.LabelView;
  81 import javax.swing.text.ParagraphView;
  82 import javax.swing.text.Style;
  83 import javax.swing.text.StyleConstants;
  84 import javax.swing.text.StyleContext;
  85 import javax.swing.text.StyledDocument;
  86 import javax.swing.text.StyledEditorKit;
  87 import javax.swing.text.View;
  88 import javax.swing.text.ViewFactory;
  89 import javax.swing.tree.DefaultMutableTreeNode;
  90 import javax.swing.tree.DefaultTreeCellEditor;
  91 import javax.swing.tree.DefaultTreeCellRenderer;
  92 import javax.swing.tree.TreeCellRenderer;
  93 import javax.swing.tree.DefaultTreeModel;
  94 import javax.swing.tree.TreePath;
  95 
  96 class LogViewer extends ToolDialog {
  97 
  98     public LogViewer(WorkDirectory workDir, UIFactory uif, Component parent) {
  99         super(parent, uif, "logviewer");
 100         String fileName = workDir.getLogFileName();
 101         this.uif = uif;
 102         this.workDir = workDir;
 103         makeLogger(workDir);
 104         if (debug > 1 && log != null) {
 105             log.info("New LogViewer started");
 106         }
 107         model = new FilteredLogModel(workDir.getTestSuite().getObservedFile(fileName), fileName);
 108         model.setLogger(log);
 109 
 110         initGUI();
 111 
 112         model.addNewLoggerListener(new LogModel.LoggerListener() {
 113             public void onNewLogger(String logName) {
 114                 if (debug > 1) {
 115                     String text = "Loggers : " + model.getLoggers().size();
 116                     loggerCounter.setText(text);
 117                 }
 118             }
 119 
 120 
 121             public void onRemoveAllLoggers() {
 122                 if (debug > 1) {
 123                     String text = "Loggers : " + model.getLoggers().size();
 124                     loggerCounter.setText(text);
 125                 }
 126             }
 127 
 128         });
 129 
 130         model.addNewPageListener(new LogModel.NewPageListener() {
 131             public void onNewPage(final int from, final int to, final int page) {
 132                 synchronized (thePane) {
 133 
 134                     if (debugPages > 1) {
 135                         System.out.println("isStable=" + model.isStableState() + " onNewPage from=" + from + " to=" + to + " page=" + page + " thePane.page=" + thePane.page);
 136                         String text = "Records : " + model.recordsRead();
 137                         counter.setText(text);
 138                         text = "Pages : " + model.pagesRead();
 139                         pageCounter.setText(text);
 140                     }
 141 
 142                     if (thePane.page == 0 && model.isStableState()) {
 143                         setPage(page);
 144                     } else if (thePane.page == page && model.isStableState()){
 145                         updatePage(from, to);
 146                     } else if (model.isStableState()) {
 147                         updateNavBtns();
 148                     }
 149                 }
 150             }
 151         });
 152 
 153         model.addFilterChangedListener(new FilteredLogModel.FilterChangedListener() {
 154             public void onFilterChanged() {
 155                 synchronized (thePane) {
 156                     thePane.page = 0;
 157                     thePane.fromRec = 0;
 158                 }
 159             }
 160         });
 161 
 162         model.init();
 163         updateNavBtns();
 164         setVisible(true);
 165 
 166         setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
 167 
 168         LV_Scroller autoScroller = new LV_Scroller();
 169         autoScroller.start();
 170     }
 171 
 172     protected void windowClosingAction(AWTEvent e) {
 173         onClose(null);
 174     }
 175 
 176     private void makeLogger(final WorkDirectory workDir) {
 177         log = Logger.getLogger("LogViewer");
 178         try {
 179             log = workDir.getTestSuite().createLog(workDir, null, "LogViewer");
 180         } catch (TestSuite.DuplicateLogNameFault ex) {
 181             try {
 182                 log = workDir.getTestSuite().getLog(workDir, "LogViewer");
 183             } catch (TestSuite.NoSuchLogFault exe) {
 184                 exe.printStackTrace();
 185             }
 186         }
 187     }
 188 
 189     protected void initGUI() {
 190 
 191         working1 = uif.getI18NString("logviewer.working1");
 192         working2 = uif.getI18NString("logviewer.working2");
 193 
 194         JPanel body = new JPanel();
 195         addWindowToList();
 196         setI18NTitle("logviewer.title", windowCounter);
 197 
 198         GridBagConstraints gridBagConstraints;
 199 
 200         JPanel filterPanel = new JPanel();
 201         filterPanel.setLayout(new GridBagLayout());
 202 
 203         Object[] items = {
 204             uif.getI18NString("logviewer.combobox.actions"),
 205             new JSeparator(),
 206             new FilterComboboxItem(uif.getI18NString("logviewer.combobox.selectall"), true),
 207             new FilterComboboxItem(uif.getI18NString("logviewer.combobox.clearall"), false),
 208             new JSeparator(),
 209             new FilterComboboxItem(uif.getI18NString("logviewer.combobox.select") + levelNames[0], levels[0]),
 210             new FilterComboboxItem(uif.getI18NString("logviewer.combobox.select") + levelNames[1], levels[1]),
 211             new FilterComboboxItem(uif.getI18NString("logviewer.combobox.select") + levelNames[2], levels[2]),
 212             new FilterComboboxItem(uif.getI18NString("logviewer.combobox.select") + levelNames[3], levels[3])
 213         };
 214 
 215         filterCombo = uif.createLiteralChoice("logviewer.combobox", items);   //new JComboBox(items);
 216         uif.setAccessibleName(filterCombo, filterCombo.getName());
 217         filterCombo.setRenderer(new CustomRenderer());
 218         filterTreeScroll = new JScrollPane();
 219 
 220         createFilterTree(filterTreeScroll);
 221 
 222         JLabel filterSubstringLbl = uif.createLabel("logviewer.label.find");
 223         final JTextField filterSubstring = uif.createInputField("logviewer.fitertext");
 224         uif.setAccessibleInfo(filterSubstring, filterSubstring.getName());
 225         filterSubstring.addActionListener(new ActionListener() {
 226             public void actionPerformed(ActionEvent e) {
 227                 model.getFilter().setSubstring(filterSubstring.getText());
 228             }
 229         });
 230 
 231         autoScrollCheckBox = uif.createCheckBox("logviewer.autoscroll");
 232         autoScroll = Boolean.parseBoolean(prefs.getPreference(AUTOSCROLL_PREF, Boolean.toString(true)));
 233         autoScrollCheckBox.setSelected(autoScroll);
 234         autoScrollCheckBox.addItemListener(new ItemListener() {
 235             public void itemStateChanged(ItemEvent e) {
 236                 autoScroll = (e.getStateChange() == ItemEvent.SELECTED);
 237                 prefs.setPreference(AUTOSCROLL_PREF, Boolean.toString(autoScroll));
 238             }
 239         });
 240 
 241         JCheckBox wordWrapCheckBox = uif.createCheckBox("logviewer.wordwarp");
 242         wordWrap = Boolean.parseBoolean(prefs.getPreference(WORDWRAP_PREF, Boolean.toString(false)));
 243         wordWrapCheckBox.setSelected(wordWrap);
 244         wordWrapCheckBox.addItemListener(new ItemListener() {
 245             public void itemStateChanged(ItemEvent e) {
 246                 wordWrap = (e.getStateChange() == ItemEvent.SELECTED);
 247                 synchronized (thePane) {
 248 
 249                     // try to restore position (not exactly)  -
 250                     Point vp = scrollPane.getViewport().getViewPosition();
 251                     Dimension vs = scrollPane.getViewport().getViewSize();
 252                     final double magic = vp.getY()/vs.getHeight();
 253 
 254                     int p = thePane.page;
 255                     clearPane(0);
 256                     setPage(p);
 257                     SwingUtilities.invokeLater(new Runnable() {
 258                         public void run() {
 259                             double newMagic = thePane.getDocument().getLength()*magic;
 260                             thePane.setCaretPosition((int)newMagic);
 261                         }
 262                     });
 263                 }
 264                 prefs.setPreference(WORDWRAP_PREF, Boolean.toString(wordWrap));
 265             }
 266         });
 267 
 268         scrollPane = new JScrollPane();
 269         thePane = new LogPane();
 270 
 271 
 272         thePane.setEditorKit(new LogEditorKit());
 273         JButton btnClose = uif.createButton("logviewer.button.close");
 274         JButton btnNew = uif.createButton("logviewer.button.open");
 275         btnSave = uif.createButton("logviewer.button.save");
 276         btnClear = uif.createButton("logviewer.button.clear");
 277         if (debug != 0 || debugPages != 0) {
 278             counter = new JLabel();
 279             pageCounter = new JLabel();
 280             loggerCounter = new JLabel();
 281             currPage = new JLabel();
 282         }
 283         naviPanel = new JPanel();
 284         processLabel = new JLabel();
 285         Font old = processLabel.getFont();
 286         processLabel.setFont(old.deriveFont(old.getSize()-1));
 287         JPanel naviBtnPanel = new JPanel();
 288         lblPageCounter = new JLabel();
 289         lblPageCounter.setVerticalAlignment(SwingConstants.TOP);
 290         btnFirst = uif.createButton("logviewer.firstpage");
 291         btnNext = uif.createButton("logviewer.nextpage");
 292         btnPrev = uif.createButton("logviewer.previouspage");
 293         btnLast = uif.createButton("logviewer.lastspage");
 294 
 295         body.setLayout(new GridBagLayout());
 296 
 297         thePane.setEditable(false);
 298         thePane.setPreferredSize(new Dimension(600, 400));
 299         scrollPane.setViewportView(thePane);
 300 
 301         gridBagConstraints = new GridBagConstraints();
 302         gridBagConstraints.insets = new Insets(0, 0, 5, 0);
 303         filterPanel.add(filterCombo, gridBagConstraints);
 304 
 305         gridBagConstraints = new java.awt.GridBagConstraints();
 306         gridBagConstraints.gridx = 0;
 307         gridBagConstraints.gridy = 1;
 308         gridBagConstraints.weighty = 1.0;
 309         gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
 310         filterPanel.add(filterTreeScroll, gridBagConstraints);
 311 
 312         gridBagConstraints = new GridBagConstraints();
 313         gridBagConstraints.gridx = 0;
 314         gridBagConstraints.gridy = 2;
 315         gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 316         gridBagConstraints.insets = new Insets(5, 0, 0, 0);
 317         filterPanel.add(filterSubstringLbl, gridBagConstraints);
 318 
 319         gridBagConstraints = new GridBagConstraints();
 320         gridBagConstraints.gridx = 0;
 321         gridBagConstraints.gridy = 3;
 322         gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
 323         filterPanel.add(filterSubstring, gridBagConstraints);
 324 
 325         gridBagConstraints = new GridBagConstraints();
 326         gridBagConstraints.gridx = 0;
 327         gridBagConstraints.gridy = 0;
 328         gridBagConstraints.fill = GridBagConstraints.BOTH;
 329         gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 330         gridBagConstraints.weighty = 1.0;
 331         gridBagConstraints.insets = new Insets(11, 11, 5, 5);
 332 
 333         body.add(filterPanel, gridBagConstraints);
 334 
 335         initPane();
 336 
 337         gridBagConstraints = new GridBagConstraints();
 338         gridBagConstraints.gridx = 1;
 339         gridBagConstraints.gridy = 0;
 340         gridBagConstraints.fill = GridBagConstraints.BOTH;
 341         gridBagConstraints.weightx = 1.0;
 342         gridBagConstraints.weighty = 1.0;
 343         gridBagConstraints.insets = new Insets(11, 5, 5, 11);
 344         body.add(scrollPane, gridBagConstraints);
 345 
 346         btnClose.addActionListener(new ActionListener() {
 347             public void actionPerformed(ActionEvent evt) {
 348                 onClose(evt);
 349             }
 350         });
 351 
 352         btnNew.addActionListener(new ActionListener() {
 353             public void actionPerformed(ActionEvent evt) {
 354                 onNew(evt);
 355             }
 356         });
 357 
 358         btnSave.addActionListener(new ActionListener() {
 359             public void actionPerformed(ActionEvent evt) {
 360                 onSave(evt);
 361             }
 362         });
 363 
 364         btnClear.addActionListener(new ActionListener() {
 365             public void actionPerformed(ActionEvent evt) {
 366                 onClear(evt);
 367             }
 368         });
 369 
 370 
 371         gridBagConstraints = new GridBagConstraints();
 372         gridBagConstraints.gridx = 0;
 373         gridBagConstraints.gridy = 1;
 374         gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 375         gridBagConstraints.insets = new Insets(0, 11, 0, 0);
 376         body.add(autoScrollCheckBox, gridBagConstraints);
 377 
 378         gridBagConstraints = new GridBagConstraints();
 379         gridBagConstraints.gridx = 0;
 380         gridBagConstraints.gridy = 2;
 381         gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 382         gridBagConstraints.insets = new Insets(0, 11, 0, 0);
 383         body.add(wordWrapCheckBox, gridBagConstraints);
 384 
 385         if (debug != 0) {
 386 
 387             counter.setText("Records : ");
 388             gridBagConstraints = new GridBagConstraints();
 389             gridBagConstraints.gridx = 0;
 390             gridBagConstraints.gridy = 3;
 391             gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 392             gridBagConstraints.insets = new Insets(0, 5, 0, 5);
 393             body.add(counter, gridBagConstraints);
 394 
 395             pageCounter.setText("Pages : ");
 396             gridBagConstraints = new GridBagConstraints();
 397             gridBagConstraints.gridx = 0;
 398             gridBagConstraints.gridy = 4;
 399             gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 400             gridBagConstraints.insets = new Insets(0, 5, 0, 5);
 401             body.add(pageCounter, gridBagConstraints);
 402 
 403             loggerCounter.setText("Loggers : ");
 404             gridBagConstraints = new GridBagConstraints();
 405             gridBagConstraints.gridx = 0;
 406             gridBagConstraints.gridy = 5;
 407             gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 408             gridBagConstraints.insets = new Insets(0, 5, 0, 5);
 409             body.add(loggerCounter, gridBagConstraints);
 410 
 411             currPage.setText("Current page ");
 412             gridBagConstraints = new GridBagConstraints();
 413             gridBagConstraints.gridx = 0;
 414             gridBagConstraints.gridy = 6;
 415             gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 416             gridBagConstraints.insets = new Insets(0, 5, 5, 5);
 417             body.add(currPage, gridBagConstraints);
 418 
 419             JButton btnGen = new JButton(new AbstractAction("Generate !") {
 420                 public void actionPerformed(ActionEvent e) {
 421                     log.config("Config");
 422                 }
 423             });
 424             JButton btnGen2 = new JButton(new AbstractAction("Generate 2") {
 425                 public void actionPerformed(ActionEvent e) {
 426                     for (int i = 0; i < 10000; i++) {
 427                         Random r = new Random();
 428                         Logger myLog = getLogger();
 429                         myLog.log(Level.FINE, "To be, or not to be: that is the question:\n"+
 430                                 "Whether 'tis nobler in the mind to suffer\n"+
 431                                 "The slings and arrows of outrageous fortune,\n"+
 432                                 "Or to take arms against a sea of troubles,\n"+
 433                                 "And by opposing end them? To die: to sleep;");
 434                         myLog.log(Level.INFO, "Random long " + r.nextLong());
 435                         myLog.log(Level.WARNING, "The World Health Organization says a cluster of bird flu cases in Indonesia may have been caused by human-to-human transmission. \nAn outbreak of bird flu that infected at least seven Indonesian family members earlier this month in north Sumatra was not a mutated version of the often deadly H5N1 form of the virus, World Health Organization spokesman Peter Cordingly told CNN.");
 436                         myLog.config("Config");
 437                     }
 438                 }
 439             });
 440 
 441             gridBagConstraints = new GridBagConstraints();
 442             gridBagConstraints.gridx = 1;
 443             gridBagConstraints.gridy = 3;
 444             body.add(btnGen, gridBagConstraints);
 445             gridBagConstraints.gridy = 4;
 446             body.add(btnGen2, gridBagConstraints);
 447         }
 448 
 449         naviBtnPanel.setLayout(new GridLayout(1, 4, 10, 10));
 450         btnFirst.setEnabled(false);
 451         btnFirst.addActionListener(new ActionListener() {
 452             public void actionPerformed(ActionEvent evt) {
 453                 goFirst(evt);
 454             }
 455         });
 456 
 457         naviBtnPanel.add(btnFirst);
 458 
 459         btnPrev.setEnabled(false);
 460         btnPrev.addActionListener(new ActionListener() {
 461             public void actionPerformed(ActionEvent evt) {
 462                 goPrev(evt);
 463             }
 464         });
 465 
 466         naviBtnPanel.add(btnPrev);
 467 
 468         btnNext.setEnabled(false);
 469         btnNext.addActionListener(new ActionListener() {
 470             public void actionPerformed(ActionEvent evt) {
 471                 goNext(evt);
 472             }
 473         });
 474 
 475         naviBtnPanel.add(btnNext);
 476 
 477         btnLast.setEnabled(false);
 478         btnLast.addActionListener(new ActionListener() {
 479             public void actionPerformed(ActionEvent evt) {
 480                 goLast(evt);
 481             }
 482         });
 483 
 484         naviBtnPanel.add(btnLast);
 485 
 486         naviPanel.setLayout(new BorderLayout());
 487         naviPanel.add(lblPageCounter, BorderLayout.WEST);
 488         naviPanel.add(naviBtnPanel, BorderLayout.EAST);
 489 
 490 
 491         gridBagConstraints = new GridBagConstraints();
 492         gridBagConstraints.gridx = 1;
 493         gridBagConstraints.gridy = 1;
 494         gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
 495         gridBagConstraints.anchor = GridBagConstraints.NORTHWEST;
 496         gridBagConstraints.weightx = 1.0;
 497         gridBagConstraints.gridheight = 2;
 498         gridBagConstraints.insets = new Insets(0, 5, 0, 0);
 499         body.add(processLabel, gridBagConstraints);
 500 
 501 
 502         gridBagConstraints = new GridBagConstraints();
 503         gridBagConstraints.gridx = 1;
 504         gridBagConstraints.gridy = 2;
 505         gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
 506         gridBagConstraints.anchor = GridBagConstraints.NORTHEAST;
 507         gridBagConstraints.weightx = 1.0;
 508         gridBagConstraints.gridheight = 2;
 509         gridBagConstraints.insets = new Insets(0, 5, 5, 11);
 510         body.add(naviPanel, gridBagConstraints);
 511 
 512         setButtons(new JButton[] {btnClear, btnSave, btnNew, btnClose}, btnClose);
 513 
 514         setBody(body);
 515     }
 516 
 517     private void createFilterTree(final JScrollPane filterTreeScroll) {
 518         treeRoot = new DefaultMutableTreeNode(new JCheckBox("Root"));
 519         filterTree = new JTree();
 520         LoggersTreeModel ltm = new LoggersTreeModel();
 521         filterTree.setModel(ltm);
 522         filterTree.setCellRenderer(new CheckBoxRenderer());
 523         filterTree.setCellEditor(new CheckBoxEditor(filterTree));
 524         filterTree.setRootVisible(false);
 525         filterTree.setEditable(true);
 526         filterTreeScroll.setViewportView(filterTree);
 527         if (filterComboBoxListener != null) {
 528             filterCombo.removeActionListener(filterComboBoxListener);
 529         }
 530         filterComboBoxListener = new FilterComboBoxListener(ltm);
 531         filterCombo.addActionListener(filterComboBoxListener);
 532         filterTree.setName("logviewer.logtree");
 533         uif.setAccessibleInfo(filterTree, filterTree.getName());
 534     }
 535 
 536     private Logger getLogger() {
 537         Random r = new Random();
 538         String lName = "log_" + r.nextInt(10);
 539         Logger ret = null;
 540 
 541         try {
 542             ret = workDir.getTestSuite().createLog(workDir, null, lName);
 543         } catch (TestSuite.DuplicateLogNameFault ex) {
 544             try {
 545                 ret = workDir.getTestSuite().getLog(workDir, lName);
 546             } catch (TestSuite.NoSuchLogFault exe) {
 547                 exe.printStackTrace();
 548             }
 549         }
 550         return ret;
 551     }
 552 
 553     private class EditorFiller extends Thread {
 554         EditorFiller(int from, int to, int pagenum) {
 555             super("editorFiller");
 556             this.from=from;
 557             this.to=to;
 558             this.pagenum=pagenum;
 559         }
 560 
 561         public void run() {
 562             if (noWindow) return;
 563             if (Thread.currentThread().isInterrupted()) {
 564                 return;
 565             }
 566             ArrayList<LogModel.LiteLogRecord> records = model.getRecords();
 567             for (int i = from; i <= to && i < records.size() && i >= 0; i++) {
 568                 if (noWindow) return;
 569                 LogModel.LiteLogRecord rec = records.get(i);
 570                 if (rec == null) {
 571                     continue;
 572                 }
 573                 if (Thread.currentThread().isInterrupted()) {
 574                     return;
 575                 }
 576                 final String msg = model.getRecordMessage(rec);
 577                 final int level = rec.severety;
 578                 String hd = rec.getHeader(model.getLogname(rec.loggerID));
 579                 final String header = debug > 1 ? "#" + (i+1) + " " + hd : hd;
 580                 final String substr = model.getFilter().getSubstring();
 581                 final int iter = i;
 582                 SwingUtilities.invokeLater(new Runnable() {
 583                     public void run() {
 584                         if (noWindow) return;
 585                         synchronized (thePane) {
 586                             if (iter <= thePane.fromRec) return;
 587                             thePane.page = pagenum;
 588                             thePane.fromRec = iter;
 589                         }
 590                         try {
 591                             int pos = doc.getEndPosition().getOffset()-1;
 592                             if (thePane.getCaret() == null) {
 593                                 thePane.setCaretPosition(0);
 594                             }
 595                             int oldPos = thePane.getCaretPosition();
 596                             doc.insertString(pos, header, getStyle(level));
 597                             doc.insertString(doc.getEndPosition().getOffset()-1, "\n", getStyle(level));
 598 
 599                             if (!"".equals(substr)) {
 600                                 String up = header.toUpperCase();
 601                                 int s = 0; int ss;
 602                                 while ((ss = up.indexOf(substr, s)) >= 0) {
 603                                     doc.setCharacterAttributes(pos + ss, substr.length(), selected, false);
 604                                     s += substr.length();
 605                                 }
 606                             }
 607                             pos = doc.getEndPosition().getOffset()-1;
 608                             doc.insertString(pos, msg, styleMsg);
 609                             doc.insertString(doc.getEndPosition().getOffset()-1, "\n", getStyle(level));
 610 
 611                             if (!"".equals(substr)) {
 612                                 String up = msg.toUpperCase();
 613                                 int s = 0; int ss;
 614                                 while ((ss = up.indexOf(substr, s)) >= 0) {
 615                                     doc.setCharacterAttributes(pos + ss, substr.length(), selected, false);
 616                                     s += substr.length();
 617                                 }
 618                             }
 619                             thePane.setCaretPosition(oldPos);
 620                             if (noWindow) return;
 621                         } catch (BadLocationException ex) {
 622                             ex.printStackTrace();
 623                         }
 624                     }
 625                 } );
 626             }
 627         }
 628 
 629 
 630         private int pagenum;
 631         private int to;
 632         private int from;
 633     }
 634 
 635 
 636     private void setRecords(final int from, final int to, final int pagenum) {
 637         if (editorThread != null && editorThread.isAlive()) {
 638             editorThread.interrupt();
 639             try {
 640                 editorThread.join();
 641             } catch (InterruptedException ex) {
 642                 // it's ok
 643             }
 644         }
 645         editorThread = new EditorFiller(from, to, pagenum);
 646         editorThread.setPriority(Thread.MIN_PRIORITY);
 647         editorThread.start();
 648     }
 649 
 650 
 651     private void clearPane(final int from) {
 652         SwingUtilities.invokeLater(new Runnable() {
 653             public void run() {
 654                 if (doc != null) {
 655                     try {
 656                         doc.remove(0, doc.getEndPosition().getOffset()-1);
 657                         synchronized (thePane) {
 658                             thePane.fromRec = from-1;
 659                         }
 660                     } catch (BadLocationException ex) {
 661                         ex.printStackTrace();
 662                     }
 663                 }
 664             }
 665         } );
 666     }
 667 
 668 
 669     private Style getStyle(int level) {
 670         if (level < Level.INFO.intValue()) {
 671             return styleOther;
 672         } else if (level < Level.WARNING.intValue()) {
 673             return styleInfo;
 674         } else if (level < Level.SEVERE.intValue()) {
 675             return styleWarning;
 676         } else {
 677             return styleSevere;
 678         }
 679     }
 680 
 681 
 682     private void goLast(ActionEvent evt) {
 683         // it's important to put it to the end of the queue !
 684         SwingUtilities.invokeLater(new Runnable() {
 685             public void run() {
 686                 synchronized (thePane) {
 687                     setPage(model.pagesRead());
 688                 }
 689             }
 690         });
 691     }
 692 
 693     private void goPrev(ActionEvent evt) {
 694         // it's important to put it to the end of the queue !
 695         SwingUtilities.invokeLater(new Runnable() {
 696             public void run() {
 697                 synchronized (thePane) {
 698                     autoScrollCheckBox.setSelected(false);
 699                     autoScroll = false;
 700                     setPage(thePane.page-1);
 701                 }
 702             }
 703         });
 704     }
 705 
 706     private void goNext(ActionEvent evt) {
 707         // it's important to put it to the end of the queue !
 708         SwingUtilities.invokeLater(new Runnable() {
 709             public void run() {
 710                 synchronized (thePane) {
 711                     setPage(thePane.page+1);
 712                 }
 713             }
 714         });
 715     }
 716 
 717     private void goFirst(ActionEvent evt) {
 718         // it's important to put it to the end of the queue !
 719         SwingUtilities.invokeLater(new Runnable() {
 720             public void run() {
 721                 synchronized (thePane) {
 722                     autoScrollCheckBox.setSelected(false);
 723                     autoScroll = false;
 724                     setPage(1);
 725                 }
 726             }
 727         });
 728     }
 729 
 730     private void onClose(ActionEvent evt) {
 731         dispose();
 732     }
 733 
 734     private void onNew(ActionEvent evt) {
 735         LogViewer lv = new LogViewer(workDir, uif, parent);
 736         Point newL = getLocation();
 737         newL.translate(20, 20);
 738         lv.setLocation(newL);
 739     }
 740 
 741     private void onSave(ActionEvent evt) {
 742         FileChooser fileChooser = new FileChooser(true);
 743         fileChooser.addChoosableExtension(".xml",
 744                 uif.getI18NString("logviewer.save.ext.xml"));
 745         fileChooser.setDialogTitle(uif.getI18NString("logviewer.save.title"));
 746         if (fileChooser.showDialog(parent, uif.getI18NString("ce.save.btn")) != JFileChooser.APPROVE_OPTION) {
 747             // user has canceled or closed the chooser
 748             return;
 749         }
 750         File f = fileChooser.getSelectedFile();
 751         if (f != null) {
 752 
 753             if (!f.getName().toLowerCase().endsWith(".xml")) {
 754                 f = new File(f.getPath() + ".xml");
 755             }
 756 
 757             LogViewerTools rm = new LogViewerTools(model, f, log, parent, uif);
 758             rm.go();
 759         }
 760     }
 761 
 762     private void onClear(ActionEvent evt) {
 763         if (uif.showYesNoDialog("logviewer.clearconfirm") == JOptionPane.YES_OPTION) {
 764             try {
 765                 workDir.getTestSuite().eraseLog(workDir);
 766             } catch (IOException ex) {
 767                 ex.printStackTrace();
 768             }
 769         }
 770     }
 771 
 772     private void updatePage(int from, int to) {
 773         setRecords(from, to, thePane.page);
 774         updateNavBtns();
 775     }
 776 
 777     private void setPage(int pageNum) {
 778         int from, to;
 779         from = (pageNum - 1) * model.getPageSize() ;
 780         to = pageNum * model.getPageSize() - 1;
 781 
 782         synchronized (thePane) {
 783             thePane.page = pageNum;
 784         }
 785 
 786         clearPane(from);
 787         setRecords(from, to, pageNum);
 788 
 789         updateNavBtns();
 790 
 791         if (debugPages > 1) {
 792             System.out.println("setPage " + pageNum + " thePane.page=" + thePane.page );
 793             SwingUtilities.invokeLater(new Runnable() {
 794                 public void run() {
 795                     if (thePane != null && currPage != null) {
 796                         currPage.setText("Current page " + thePane.page );
 797                     }
 798                 }
 799             });
 800         }
 801     }
 802 
 803     private void updateNavBtns() {
 804         // can be called not from swing thread
 805         SwingUtilities.invokeLater(new Runnable(){
 806             public void run() {
 807                 if (noWindow) return;
 808                 synchronized (thePane) {
 809                     if (model != null && btnFirst != null && btnLast != null &&
 810                             btnPrev != null && btnNext != null && lblPageCounter != null &&
 811                             naviPanel != null && btnSave != null) {
 812                         btnFirst.setEnabled(thePane.page > 1);
 813                         btnLast.setEnabled(thePane.page < model.pagesRead() && model.pagesRead() > 1);
 814                         btnPrev.setEnabled(thePane.page > 1);
 815                         btnNext.setEnabled(thePane.page < model.pagesRead() && model.pagesRead() > 1);
 816                         String pop = uif.getI18NString("logviewer.pageofpage",
 817                                 new Object[] {thePane.page, model.pagesRead()});
 818                         lblPageCounter.setText(pop);
 819                         naviPanel.setVisible(btnFirst.isEnabled() ||
 820                                 btnFirst.isEnabled() ||
 821                                 btnLast.isEnabled() ||
 822                                 btnNext.isEnabled());
 823                         btnSave.setEnabled(model.isStableState() && model.recordsRead() > 0);
 824                         btnClear.setEnabled(model.pagesRead() > 0);
 825                     }
 826                 }
 827             }
 828         });
 829     }
 830 
 831     private void initPane() {
 832         doc = thePane.getStyledDocument();
 833         Style def = StyleContext.getDefaultStyleContext().
 834                 getStyle(StyleContext.DEFAULT_STYLE);
 835 
 836         styleMsg = doc.addStyle("msg_text", def);
 837         StyleConstants.setFontFamily(styleMsg, "Monospaced");
 838 
 839         styleWait  = doc.addStyle("blink", styleMsg);
 840         StyleConstants.setBold(styleWait, true);
 841 
 842         styleInfo = doc.addStyle("info_text", styleMsg);
 843         Color darkGreen = new Color(0, 180, 0);
 844         StyleConstants.setForeground(styleInfo, darkGreen);
 845 
 846         styleWarning = doc.addStyle("warning_text", styleMsg);
 847         StyleConstants.setForeground(styleWarning, new Color(200, 150, 0));
 848 
 849         styleSevere = doc.addStyle("severe_text", styleMsg);
 850         StyleConstants.setForeground(styleSevere, Color.RED);
 851 
 852         styleOther = doc.addStyle("other_text", styleMsg);
 853         StyleConstants.setForeground(styleOther, Color.BLUE);
 854 
 855         selected = doc.addStyle("selected", null);
 856         StyleConstants.setBackground(selected, Color.YELLOW);
 857 
 858     }
 859 
 860 
 861     private class LogEditorKit extends StyledEditorKit {
 862 
 863 
 864         public ViewFactory getViewFactory() {
 865             if (fact == null) {
 866                 fact = new LogViewFactory();
 867             }
 868             return fact;
 869         }
 870         ViewFactory fact;
 871 
 872         class NoWrapLabelView extends LabelView {
 873             public NoWrapLabelView(Element elem) {
 874                 super(elem);
 875             }
 876 
 877             public int getBreakWeight(int axis, float pos, float len) {
 878                 return BadBreakWeight;
 879             }
 880         }
 881 
 882         private class LogViewFactory implements ViewFactory {
 883             public View create(Element elem) {
 884                 String kind = elem.getName();
 885                 if (kind != null) {
 886                     if (kind.equals(AbstractDocument.ContentElementName)) {
 887                         if (!wordWrap) {
 888                             return new NoWrapLabelView(elem)/* LabelView(elem)*/;
 889                         } else {
 890                             return new LabelView(elem);
 891                         }
 892                     } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
 893                         return new ParagraphView(elem);
 894                     } else if (kind.equals(AbstractDocument.SectionElementName)) {
 895                         return new BoxView(elem, View.Y_AXIS);
 896                     } else if (kind.equals(StyleConstants.ComponentElementName)) {
 897                         return new ComponentView(elem);
 898                     } else if (kind.equals(StyleConstants.IconElementName)) {
 899                         return new IconView(elem);
 900                     }
 901                 }
 902 
 903                 // default to text display
 904                 return new LabelView(elem);
 905             }
 906         }
 907 
 908     }
 909 
 910     private class LogPane extends JTextPane {
 911         int page;
 912         int fromRec;
 913         public LogPane() {
 914             super();
 915             setName("logviewer.viewerpane");
 916             uif.setAccessibleName(this, getName());
 917 
 918         }
 919     }
 920 
 921     private class CheckBoxEditor extends DefaultTreeCellEditor {
 922         CheckBoxEditor(JTree tree) {
 923             super(tree, new DefaultTreeCellRenderer());
 924         }
 925 
 926         public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected, boolean expanded, boolean leaf, int row) {
 927             if (value instanceof DefaultMutableTreeNode) {
 928                 DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
 929                 Object o = node.getUserObject();
 930                 if (o instanceof JCheckBox) {
 931                     JCheckBox cb = (JCheckBox) o;
 932                     cb.setBackground(tree.getBackground());
 933                     return cb;
 934                 }
 935             }
 936 
 937             return super.getTreeCellEditorComponent(tree, value, isSelected, expanded, leaf, row);
 938         }
 939 
 940         // no expand/collaps !!
 941         // edit this to change
 942         public boolean isCellEditable(EventObject event) {
 943             return true;
 944         }
 945 
 946     }
 947 
 948     private class CheckBoxRenderer extends JCheckBox
 949             implements TreeCellRenderer {
 950 
 951         public CheckBoxRenderer() {
 952             super();
 953             setBackground(filterTree.getBackground());
 954         }
 955 
 956         public Component getTreeCellRendererComponent(JTree tree,
 957                 Object value, boolean isSelected, boolean expanded,
 958                 boolean leaf, int row, boolean hasFocus) {
 959 
 960             if (value instanceof DefaultMutableTreeNode) {
 961                 DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
 962                 Object o = node.getUserObject();
 963                 if (o instanceof JCheckBox) {
 964                     JCheckBox cb = (JCheckBox) o;
 965                     setText(cb.getText());
 966                     setSelected(cb.isSelected());
 967                     return this;
 968                 }
 969             }
 970 
 971             return defRend.getTreeCellRendererComponent(tree,
 972                     value, isSelected, expanded, leaf, row, hasFocus);
 973         }
 974         DefaultTreeCellRenderer defRend = new DefaultTreeCellRenderer();
 975     }
 976 
 977 
 978     private class CustomRenderer extends JComponent
 979             implements ListCellRenderer<Object> {
 980         public Component getListCellRendererComponent(
 981                 JList list, Object value, int index, boolean isSelected,
 982                 boolean cellHasFocus) {
 983             if (!(value instanceof JSeparator) && !(value instanceof JCheckBox)) {
 984                 DefaultListCellRenderer defRend = new DefaultListCellRenderer();
 985                 return defRend.getListCellRendererComponent(list, value, index,
 986                         isSelected, cellHasFocus);
 987             } else if (value instanceof JSeparator) {
 988                 return (JSeparator)value;
 989             } else if (value instanceof JCheckBox) {
 990                 if (isSelected) {
 991                     ((JCheckBox)value).setBackground(list.getSelectionBackground());
 992                     ((JCheckBox)value).setForeground(list.getSelectionForeground());
 993                 } else {
 994                     ((JCheckBox)value).setBackground(list.getBackground());
 995                     ((JCheckBox)value).setForeground(list.getForeground());
 996                 }
 997 
 998                 return (JCheckBox)value;
 999             }
1000             return this;
1001         }
1002     }
1003 
1004     private class LoggersTreeModel extends DefaultTreeModel {
1005         LoggersTreeModel() {
1006             super(treeRoot);
1007             model.removeNewLoggerListeners();
1008             model.addNewLoggerListener(new LogModel.LoggerListener() {
1009                 public void onNewLogger(final String name) {
1010                     // it calls from Worker thread
1011                     SwingUtilities.invokeLater(new Runnable() {
1012                         public void run() {
1013                             // check for the same
1014 
1015                             final PropagatedCheckBox ch = new PropagatedCheckBox(name);
1016                             ch.setSelected(true);
1017                             DefaultMutableTreeNode newLogger = new DefaultMutableTreeNode(ch, true);
1018 
1019                             for (int i = 0 ; i < levels.length; i++) {
1020                                 final JCheckBox chh = new FilterTreeItem(name, levels[i].intValue(), levelNames[i]);
1021                                 chh.setSelected(true);
1022                                 final int level = levels[i].intValue();
1023                                 chh.addItemListener( new ItemListener() {
1024                                     {
1025                                         box = chh;
1026                                         l = level;
1027                                         logName = name;
1028                                     }
1029                                     public void itemStateChanged(ItemEvent e) {
1030                                         model.getFilter().enableLogger(logName, l, box.isSelected());
1031                                     }
1032                                     JCheckBox box;
1033                                     int l;
1034                                     String logName;
1035                                 });
1036                                 ch.addChild(chh);
1037                                 DefaultMutableTreeNode node = new DefaultMutableTreeNode(chh);
1038                                 newLogger.add(node);
1039                             }
1040 
1041                             treeRoot.add(newLogger);
1042                             nodesWereInserted(treeRoot, new int [] {treeRoot.getIndex(newLogger)});
1043                             filterTree.expandPath(new TreePath(newLogger.getPath()));
1044 
1045                         }
1046                     });
1047 
1048                 }
1049 
1050                 public void onRemoveAllLoggers() {
1051                     createFilterTree(filterTreeScroll);
1052                 }
1053             });
1054         }
1055     }
1056 
1057     private class PropagatedCheckBox extends JCheckBox {
1058         PropagatedCheckBox(final String name) {
1059             super(name);
1060             this.addItemListener( new ItemListener() {
1061                 public void itemStateChanged(ItemEvent e) {
1062                     for (JCheckBox aChildren : children) {
1063                         boolean s = isSelected();
1064                         if (aChildren.isSelected() != s) {
1065                             aChildren.setSelected(s);
1066                             if (debug > 1) {
1067                                 System.out.println(aChildren.getText() + " selected " + s);
1068                             }
1069                         }
1070                     }
1071                     filterTree.repaint();
1072                 }
1073             });
1074         }
1075 
1076         public void fireEvent() {
1077             fireItemStateChanged(
1078                     new ItemEvent(this,
1079                     ItemEvent.ITEM_STATE_CHANGED,
1080                     this,
1081                     this.isSelected() ?  ItemEvent.SELECTED : ItemEvent.DESELECTED));
1082         }
1083 
1084         public void addChild(JCheckBox ch) {
1085             children.add(ch);
1086         }
1087 
1088         private ArrayList<JCheckBox> children = new ArrayList<JCheckBox>();
1089     }
1090 
1091 
1092     private class FilterTreeItem extends JCheckBox {
1093         public FilterTreeItem(String logName, int level, String levelName) {
1094             super(levelName);
1095             this.logName = logName;
1096             this.level = level;
1097         }
1098         String logName;
1099         int level;
1100     }
1101 
1102     private class FilterComboboxItem {
1103 
1104         public FilterComboboxItem(String txt, Level l) {
1105             label = txt;
1106             level = l.intValue();
1107             kind = false;
1108         }
1109 
1110         public FilterComboboxItem(String txt, boolean s) {
1111             label = txt;
1112             select = s;
1113             kind = true;
1114         }
1115 
1116 
1117         public String toString() {
1118             return label;
1119         }
1120 
1121         // true - select all / unselect all
1122         // false - select particular level
1123         boolean kind;
1124 
1125         private String label;
1126         int level;
1127         boolean select;
1128 
1129     }
1130 
1131 
1132     private class FilterComboBoxListener implements ActionListener {
1133         public FilterComboBoxListener(LoggersTreeModel m) {
1134             model = m;
1135         }
1136 
1137         public void actionPerformed(ActionEvent e) {
1138             JComboBox cb = (JComboBox) e.getSource();
1139             Object o = cb.getSelectedItem();
1140             if (o instanceof FilterComboboxItem) {
1141                 FilterComboboxItem fc = (FilterComboboxItem) o;
1142                 DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
1143                 if (debug > 1 && fc.kind) {
1144                     System.err.println(fc.select ? "Select all" : "Unselect all");
1145                 }
1146                 for (int i=0; i < root.getChildCount(); i++) {
1147                     DefaultMutableTreeNode fstLevelCh = (DefaultMutableTreeNode) root.getChildAt(i);
1148                     PropagatedCheckBox chLog = (PropagatedCheckBox) fstLevelCh.getUserObject();
1149                     if (fc.kind) {
1150                         boolean needToFire = chLog.isSelected() == fc.select;
1151                         chLog.setSelected(fc.select);
1152                         if (needToFire) {
1153                             chLog.fireEvent();
1154                         }
1155                     } else {
1156                         boolean allSelected = true;
1157                         for (int j=0; j < fstLevelCh.getChildCount(); j++) {
1158                             DefaultMutableTreeNode secondLevelCh = (DefaultMutableTreeNode) fstLevelCh.getChildAt(j);
1159                             FilterTreeItem chLev = (FilterTreeItem) secondLevelCh.getUserObject();
1160                             if (chLev.level == fc.level && !chLev.isSelected()) {
1161                                 chLev.setSelected(true);
1162                                 filterTree.repaint();
1163                             } else {
1164                                 allSelected = allSelected && chLev.isSelected();
1165                             }
1166                         }
1167                         if (allSelected && !chLog.isSelected()) {
1168                             chLog.setSelected(true);
1169                             filterTree.repaint();
1170                         }
1171                     }
1172                 }
1173                 cb.setSelectedIndex(0);
1174             }
1175         }
1176 
1177         private LoggersTreeModel model;
1178 
1179     }
1180 
1181     public void setVisible(boolean b) {
1182         super.setVisible(b);
1183         if (!b) {
1184             dispose();
1185         }
1186     }
1187 
1188     public void dispose() {
1189         removeWindowFromList();
1190         if (noWindow) {
1191             return;
1192         }
1193         noWindow = true;
1194         model.dispose();
1195         super.dispose();
1196         try {
1197             doc.remove(0, doc.getLength());
1198         } catch (BadLocationException ex) {
1199             ex.printStackTrace();
1200         }
1201         thePane = null;
1202         doc = null;
1203         model = null;
1204         workDir = null;
1205         scrollPane = null;
1206         if (debug > 1 && log != null) {
1207             log.info("LogViewer closed");
1208         }
1209         log = null;
1210     }
1211 
1212     private void removeWindowFromList() {
1213         windowList.remove(windowCounter);
1214     }
1215 
1216     private void addWindowToList() {
1217         for (int i = 1; i < Integer.MAX_VALUE; i++) {
1218             if (!windowList.contains(i)) {
1219                 windowCounter = i;
1220                 windowList.add(i);
1221                 return;
1222             }
1223         }
1224         windowCounter = 0;
1225     }
1226 
1227     private class LV_Scroller extends Thread {
1228 
1229         public LV_Scroller() {
1230             super("LV_scroller");
1231         }
1232 
1233         public void run() {
1234             try {
1235                 while (true) {
1236                     if (noWindow) return;
1237                     boolean reset = false;
1238                     if (model.isStableState()) {
1239                         if (autoScroll) {
1240                             reset = thePane.page != model.pagesRead();
1241                         } else {
1242                             reset = thePane.page > model.pagesRead() || thePane.page == 0;
1243                         }
1244                     }
1245                     if (reset) {
1246                         setPage(model.pagesRead());
1247                         setBusy(!model.isStableState());
1248                         sleep(500);
1249                         continue;
1250                     }
1251                     if (model.isStableState()) {
1252                         setBusy(false);
1253                         if (autoScroll) {
1254                             synchronized (thePane) {
1255                                 final JScrollBar sb = scrollPane.getVerticalScrollBar();
1256                                 if (sb != null) {
1257                                     SwingUtilities.invokeLater(new Runnable() {
1258                                         public void run() {
1259                                             sb.setValue(sb.getMaximum());
1260                                         }
1261 
1262                                     });
1263                                 }
1264                             }
1265                         } else {
1266                             if (thePane.getCaret() == null)
1267                                 thePane.setCaretPosition(0);
1268                         }
1269                     } else {
1270                         setBusy(true);
1271                     }
1272                     sleep(500);
1273                 }
1274             } catch (InterruptedException ex) {
1275                 // ok
1276             }
1277         }
1278 
1279         private void setBusy(boolean b) {
1280             if (!b) {
1281                 processLabel.setText("");
1282             } else {
1283                 String oldText = processLabel.getText();
1284                 if ("".equals(oldText) || working1.equals(oldText)) {
1285                     processLabel.setText(working2);
1286                 } else {
1287                     processLabel.setText(working1);
1288                 }
1289             }
1290         }
1291     }
1292 
1293     private UIFactory uif;
1294 
1295     private final Level  [] levels = { Level.SEVERE, Level.WARNING, Level.INFO, Level.FINE } ;
1296     private final String [] levelNames =
1297     {LoggerFactory.getLocalizedLevelName(Level.SEVERE),
1298      LoggerFactory.getLocalizedLevelName(Level.WARNING),
1299      LoggerFactory.getLocalizedLevelName(Level.INFO),
1300      LoggerFactory.getLocalizedLevelName(Level.FINE) } ;
1301 
1302     private DefaultMutableTreeNode treeRoot;
1303     private JComboBox<?> filterCombo;
1304     private JTree filterTree ;
1305 
1306     private boolean noWindow = false;
1307     private JLabel lblPageCounter;
1308     private JButton btnFirst;
1309     private JButton btnLast;
1310     private JButton btnNext;
1311     private JButton btnPrev;
1312     private JCheckBox autoScrollCheckBox;
1313     private JLabel counter;
1314     private JLabel currPage;
1315     private JButton btnSave;
1316     private JButton btnClear;
1317     private JPanel naviPanel;
1318     private JScrollPane scrollPane;
1319     private LogPane thePane;
1320     private JLabel loggerCounter;
1321     private JLabel pageCounter;
1322     private JLabel processLabel;
1323     private WorkDirectory workDir;
1324     private Thread editorThread;
1325 
1326     private StyledDocument doc;
1327     private Style styleMsg, styleInfo, styleWarning, styleSevere, styleOther, styleWait, selected;
1328     private FilteredLogModel model;
1329     private Logger log;
1330 
1331     private final int debug = 0;
1332     private final int debugPages = 0;
1333     private boolean autoScroll = true;
1334 
1335     private FilterComboBoxListener filterComboBoxListener;
1336 
1337     private JScrollPane filterTreeScroll;
1338 
1339     private boolean wordWrap = false;
1340 
1341     private Preferences prefs = Preferences.access();
1342     private static final String AUTOSCROLL_PREF = "logviewer.autoScroll";
1343     private static final String WORDWRAP_PREF = "logviewer.wordWrap";
1344     private int windowCounter = 0;
1345     private static HashSet<Integer> windowList = new HashSet<Integer>();
1346     private String working1;
1347     private String working2;
1348 
1349 }