View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.log4j.chainsaw;
19  
20  import java.awt.BorderLayout;
21  import java.awt.Dimension;
22  import java.awt.Insets;
23  import java.awt.Toolkit;
24  import java.awt.event.ActionEvent;
25  import java.awt.event.ActionListener;
26  import java.awt.event.InputEvent;
27  import java.awt.event.KeyEvent;
28  import java.beans.PropertyChangeEvent;
29  import java.beans.PropertyChangeListener;
30  import java.util.ArrayList;
31  import java.util.Collection;
32  import java.util.Iterator;
33  import java.util.List;
34  
35  import javax.swing.AbstractAction;
36  import javax.swing.Action;
37  import javax.swing.Box;
38  import javax.swing.ImageIcon;
39  import javax.swing.JButton;
40  import javax.swing.JCheckBoxMenuItem;
41  import javax.swing.JComponent;
42  import javax.swing.JDialog;
43  import javax.swing.JEditorPane;
44  import javax.swing.JLabel;
45  import javax.swing.JMenu;
46  import javax.swing.JMenuBar;
47  import javax.swing.JMenuItem;
48  import javax.swing.JPanel;
49  import javax.swing.JRadioButtonMenuItem;
50  import javax.swing.JToolBar;
51  import javax.swing.KeyStroke;
52  import javax.swing.SwingConstants;
53  import javax.swing.SwingUtilities;
54  import javax.swing.UIManager;
55  import javax.swing.event.ChangeEvent;
56  import javax.swing.event.ChangeListener;
57  
58  import org.apache.log4j.chainsaw.filter.FilterModel;
59  import org.apache.log4j.chainsaw.help.HelpManager;
60  import org.apache.log4j.chainsaw.icons.ChainsawIcons;
61  import org.apache.log4j.chainsaw.osx.OSXIntegration;
62  import org.apache.log4j.chainsaw.receivers.ReceiversHelper;
63  
64  
65  /**
66   * Encapsulates the full Toolbar, and menus and all the actions that can be performed from it.
67   * @author Paul Smith <psmith@apache.org>
68   * @author Scott Deboy <sdeboy@apache.org>
69   */
70  class ChainsawToolBarAndMenus implements ChangeListener {
71    private final SmallToggleButton showReceiversButton;
72    private final Action changeModelAction;
73    private final Action clearAction;
74    private final Action toggleWelcomeVisibleAction;
75    private final Action findPreviousColorizedEventAction;
76    private final Action findNextColorizedEventAction;
77    private final Action findNextMarkerAction;
78    private final Action findPreviousMarkerAction;
79    private final Action toggleMarkerAction;
80    private final Action clearAllMarkersAction;
81    private final Action pauseAction;
82    private final Action showPreferencesAction;
83    private final Action showColorPanelAction;
84    private final Action showReceiversAction;
85    private final Action toggleLogTreeAction;
86    private final Action toggleScrollToBottomAction;
87    private final Action scrollToTopAction;
88    private final Action toggleDetailPaneAction;
89    private final Action toggleToolbarAction;
90    private final Action undockAction;
91    private final Action customExpressionPanelAction;
92    private final Collection lookAndFeelMenus = new ArrayList();
93    private final JCheckBoxMenuItem toggleShowReceiversCheck =
94      new JCheckBoxMenuItem();
95    private final JCheckBoxMenuItem toggleLogTreeMenuItem =
96      new JCheckBoxMenuItem();
97    private final JCheckBoxMenuItem toggleScrollToBottomMenuItem =
98      new JCheckBoxMenuItem();
99    private final JCheckBoxMenuItem toggleDetailMenuItem =
100     new JCheckBoxMenuItem();
101   private final JCheckBoxMenuItem toggleCyclicMenuItem =
102     new JCheckBoxMenuItem();
103   private final FileMenu fileMenu;
104   private final JCheckBoxMenuItem toggleStatusBarCheck =
105     new JCheckBoxMenuItem();
106   private final JMenu viewMenu = new JMenu("View");
107   private final JMenuBar menuBar;
108   private final JCheckBoxMenuItem menuShowWelcome = new JCheckBoxMenuItem();
109   private final JToolBar toolbar;
110   private final LogUI logui;
111   private final SmallButton clearButton = new SmallButton();
112   private final SmallToggleButton detailPaneButton = new SmallToggleButton();
113   private final SmallToggleButton logTreePaneButton = new SmallToggleButton();
114   private final SmallToggleButton scrollToBottomButton = new SmallToggleButton();
115   private final SmallToggleButton pauseButton = new SmallToggleButton();
116   private final SmallToggleButton toggleCyclicButton = new SmallToggleButton();
117   private final Action[] logPanelSpecificActions;
118   private final JMenu activeTabMenu = new JMenu("Current tab");
119 
120     ChainsawToolBarAndMenus(final LogUI logui) {
121     this.logui = logui;
122     toolbar = new JToolBar(SwingConstants.HORIZONTAL);
123     menuBar = new JMenuBar();
124     fileMenu = new FileMenu(logui);
125     toggleWelcomeVisibleAction = toggleWelcomeVisibleAction();
126     changeModelAction = createChangeModelAction();
127     findNextMarkerAction = createFindNextMarkerAction();
128     findPreviousColorizedEventAction = getFindPreviousColorizedEventAction();
129     findNextColorizedEventAction = getFindNextColorizedEventAction();
130     findPreviousMarkerAction = createFindPreviousMarkerAction();
131     toggleMarkerAction = createToggleMarkerAction();
132     clearAllMarkersAction = createClearAllMarkersAction();
133     customExpressionPanelAction = createCustomExpressionPanelAction();
134     showPreferencesAction = createShowPreferencesAction();
135     showColorPanelAction = createShowColorPanelAction();
136     toggleToolbarAction = createToggleToolbarAction();
137     toggleLogTreeAction = createToggleLogTreeAction();
138     toggleScrollToBottomAction = createScrollToBottomAction();
139     scrollToTopAction = createScrollToTopAction();
140     pauseAction = createPauseAction();
141     clearAction = createClearAction();
142     undockAction = createUndockAction();
143     showReceiversAction = createShowReceiversAction();
144     showReceiversButton = new SmallToggleButton(showReceiversAction);
145 
146     toggleDetailPaneAction = createToggleDetailPaneAction();
147     createMenuBar();
148     createToolbar();
149 
150     logPanelSpecificActions =
151       new Action[] {
152         pauseAction, findNextColorizedEventAction, findPreviousColorizedEventAction,
153         findNextMarkerAction, findPreviousMarkerAction,
154         toggleMarkerAction, clearAllMarkersAction, scrollToTopAction, clearAction,
155         fileMenu.getFileSaveAction(), toggleDetailPaneAction,
156         showPreferencesAction, showColorPanelAction, undockAction,
157         toggleLogTreeAction, toggleScrollToBottomAction, changeModelAction,
158       };
159 
160     logui.getApplicationPreferenceModel().addPropertyChangeListener(
161       "statusBar",
162       new PropertyChangeListener() {
163         public void propertyChange(PropertyChangeEvent evt) {
164           boolean value = ((Boolean) evt.getNewValue()).booleanValue();
165           toggleStatusBarCheck.setSelected(value);
166         }
167       });
168 
169     logui.getApplicationPreferenceModel().addPropertyChangeListener(
170       "receivers",
171       new PropertyChangeListener() {
172         public void propertyChange(PropertyChangeEvent evt) {
173           boolean value = ((Boolean) evt.getNewValue()).booleanValue();
174           showReceiversButton.setSelected(value);
175           toggleShowReceiversCheck.setSelected(value);
176         }
177       });
178   }
179 
180   /**
181    * @return
182    */
183   private Action createChangeModelAction() {
184     Action action =
185       new AbstractAction("Use Cyclic", new ImageIcon(ChainsawIcons.REFRESH)) {
186         public void actionPerformed(ActionEvent arg0) {
187           LogPanel logPanel = logui.getCurrentLogPanel();
188           logPanel.toggleCyclic();
189           scanState();
190         }
191       };
192 
193     action.putValue(
194       Action.SHORT_DESCRIPTION, "Changes between Cyclic and Unlimited mode.");
195 
196     return action;
197   }
198 
199   /**
200   * @return
201   */
202   private Action createToggleLogTreeAction() {
203     Action action =
204       new AbstractAction("Toggle the Logger Tree Pane") {
205         public void actionPerformed(ActionEvent e) {
206           if (logui.getCurrentLogPanel() != null) {
207             logui.getCurrentLogPanel().toggleLogTreeVisible();
208           }
209         }
210       };
211 
212     action.putValue(Action.SHORT_DESCRIPTION, "Toggles the Logger Tree Pane");
213     action.putValue("enabled", Boolean.TRUE);
214     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
215     action.putValue(
216       Action.ACCELERATOR_KEY,
217       KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
218     action.putValue(
219       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.WINDOW_ICON));
220 
221     return action;
222   }
223 
224   /**
225    * @return
226    */
227    private Action createScrollToBottomAction() {
228      Action action =
229        new AbstractAction("Toggle Scroll to Bottom") {
230          public void actionPerformed(ActionEvent e) {
231            if (logui.getCurrentLogPanel() != null) {
232              logui.getCurrentLogPanel().toggleScrollToBottom();
233            }
234          }
235        };
236 
237      action.putValue(Action.SHORT_DESCRIPTION, "Toggles Scroll to Bottom");
238      action.putValue("enabled", Boolean.TRUE);
239      action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_B));
240      action.putValue(
241        Action.ACCELERATOR_KEY,
242        KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
243      action.putValue(
244        Action.SMALL_ICON, new ImageIcon(ChainsawIcons.SCROLL_TO_BOTTOM));
245 
246      return action;
247    }
248 
249     private Action createScrollToTopAction() {
250       Action action =
251         new AbstractAction("Scroll to top") {
252           public void actionPerformed(ActionEvent e) {
253             if (logui.getCurrentLogPanel() != null) {
254               logui.getCurrentLogPanel().scrollToTop();
255             }
256           }
257         };
258 
259       action.putValue(Action.SHORT_DESCRIPTION, "Scroll to top");
260       action.putValue("enabled", Boolean.TRUE);
261       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
262       action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A,  Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
263 
264       return action;
265     }
266 
267      private Action createFindNextMarkerAction() {
268        Action action =
269          new AbstractAction("Find next marker") {
270            public void actionPerformed(ActionEvent e) {
271              if (logui.getCurrentLogPanel() != null) {
272                logui.getCurrentLogPanel().findNextMarker();
273              }
274            }
275          };
276 
277        action.putValue(Action.SHORT_DESCRIPTION, "Find the next marker from the current location");
278        action.putValue("enabled", Boolean.TRUE);
279        action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_N));
280        action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F2"));
281 
282        return action;
283      }
284 
285     private Action createFindPreviousMarkerAction() {
286       Action action =
287         new AbstractAction("Find previous marker") {
288           public void actionPerformed(ActionEvent e) {
289             if (logui.getCurrentLogPanel() != null) {
290               logui.getCurrentLogPanel().findPreviousMarker();
291             }
292           }
293         };
294 
295       action.putValue(Action.SHORT_DESCRIPTION, "Find the previous marker from the current location");
296       action.putValue("enabled", Boolean.TRUE);
297       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
298       action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  InputEvent.SHIFT_MASK));
299 
300       return action;
301     }
302 
303     private Action createToggleMarkerAction() {
304       Action action =
305         new AbstractAction("Toggle marker") {
306           public void actionPerformed(ActionEvent e) {
307             if (logui.getCurrentLogPanel() != null) {
308               logui.getCurrentLogPanel().toggleMarker();
309             }
310           }
311         };
312 
313       action.putValue(Action.SHORT_DESCRIPTION, "Toggle marker for selected row");
314       action.putValue("enabled", Boolean.TRUE);
315       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
316       action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
317 
318       return action;
319     }
320 
321     private Action createClearAllMarkersAction() {
322       Action action =
323         new AbstractAction("Clear all markers") {
324           public void actionPerformed(ActionEvent e) {
325             if (logui.getCurrentLogPanel() != null) {
326               logui.getCurrentLogPanel().clearAllMarkers();
327             }
328           }
329         };
330 
331       action.putValue(Action.SHORT_DESCRIPTION, "Removes all markers");
332       action.putValue("enabled", Boolean.TRUE);
333       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_R));
334       action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_MASK));
335 
336       return action;
337     }
338 
339    /**
340    * DOCUMENT ME!
341    */
342   public void stateChange() {
343     scanState();
344   }
345 
346   /**
347    * DOCUMENT ME!
348    *
349    * @param e DOCUMENT ME!
350    */
351   public void stateChanged(ChangeEvent e) {
352     scanState();
353   }
354 
355   JMenuBar getMenubar() {
356     return menuBar;
357   }
358 
359   JToolBar getToolbar() {
360     return toolbar;
361   }
362 
363   private Action createClearAction() {
364     final Action action =
365       new AbstractAction("Clear") {
366         public void actionPerformed(ActionEvent e) {
367           LogPanel logPanel = logui.getCurrentLogPanel();
368 
369           if (logPanel == null) {
370             return;
371           }
372 
373           logPanel.clearEvents();
374         }
375       };
376 
377     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_C));
378     action.putValue(
379       Action.ACCELERATOR_KEY,
380       KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
381     action.putValue(
382       Action.SHORT_DESCRIPTION, "Removes all the events from the current view");
383     action.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.DELETE));
384 
385     return action;
386   }
387 
388   private Action toggleWelcomeVisibleAction() {
389     final Action action =
390       new AbstractAction() {
391         public void actionPerformed(ActionEvent e) {
392           toggleWelcomeVisibleAction.putValue(Action.NAME, "Welcome tab");
393           if (menuShowWelcome.isSelected()) {
394             logui.addWelcomePanel();
395           } else {
396             logui.removeWelcomePanel();
397           }
398         }
399       };
400 
401     action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F1"));
402 
403     //    action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK));
404     action.putValue(Action.SHORT_DESCRIPTION, "Toggles the Welcome tab");
405     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_C));
406     action.putValue(Action.NAME, "Welcome tab");
407 
408     return action;
409   }
410 
411   private void createMenuBar() {
412     JMenuItem menuItemUseRightMouse =
413       new JMenuItem(
414         "Other options available via panel's right mouse button popup menu");
415     menuItemUseRightMouse.setEnabled(false);
416 
417     viewMenu.setMnemonic('V');
418 
419     final JCheckBoxMenuItem showToolbarCheck =
420       new JCheckBoxMenuItem(toggleToolbarAction);
421     showToolbarCheck.setSelected(
422       logui.getApplicationPreferenceModel().isToolbar());
423 
424     logui.getApplicationPreferenceModel().addPropertyChangeListener(
425       "toolbar",
426       new PropertyChangeListener() {
427         public void propertyChange(PropertyChangeEvent evt) {
428           boolean value = ((Boolean) evt.getNewValue()).booleanValue();
429           showToolbarCheck.setSelected(value);
430         }
431       });
432 
433     menuShowWelcome.setAction(toggleWelcomeVisibleAction);
434 
435     JCheckBoxMenuItem pause = new JCheckBoxMenuItem(pauseAction);
436     JMenuItem menuPrefs = new JMenuItem(showPreferencesAction);
437     menuPrefs.setText(
438       showPreferencesAction.getValue(Action.SHORT_DESCRIPTION).toString());
439 
440     JMenuItem menuCustomExpressionPanel =
441       new JMenuItem(customExpressionPanelAction);
442     menuCustomExpressionPanel.setText(
443       customExpressionPanelAction.getValue(Action.SHORT_DESCRIPTION).toString());
444 
445     JMenuItem menuShowColor = new JMenuItem(showColorPanelAction);
446     menuShowColor.setText(
447       showColorPanelAction.getValue(Action.SHORT_DESCRIPTION).toString());
448 
449     JMenuItem menuUndock = new JMenuItem(undockAction);
450 
451     JMenuItem showAppPrefs =
452       new JMenuItem("Show Application-wide Preferences...");
453 
454     showAppPrefs.addActionListener(
455       new ActionListener() {
456         public void actionPerformed(ActionEvent e) {
457           logui.showApplicationPreferences();
458         }
459       });
460 
461     toggleDetailMenuItem.setAction(toggleDetailPaneAction);
462     toggleDetailMenuItem.setSelected(true);
463 
464     toggleCyclicMenuItem.setAction(changeModelAction);
465 
466     toggleCyclicMenuItem.setSelected(true);
467 
468     toggleLogTreeMenuItem.setAction(toggleLogTreeAction);
469     toggleLogTreeMenuItem.setSelected(true);
470 
471     toggleScrollToBottomMenuItem.setAction(toggleScrollToBottomAction);
472 
473     final Action toggleStatusBarAction =
474       new AbstractAction("Show Status bar") {
475         public void actionPerformed(ActionEvent arg0) {
476           logui.getApplicationPreferenceModel().setStatusBar(
477             toggleStatusBarCheck.isSelected());
478         }
479       };
480 
481     toggleStatusBarAction.putValue(
482       Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_B));
483     toggleStatusBarCheck.setAction(toggleStatusBarAction);
484     toggleStatusBarCheck.setSelected(
485       logui.getApplicationPreferenceModel().isStatusBar());
486 
487     activeTabMenu.add(pause);
488     activeTabMenu.add(toggleCyclicMenuItem);
489     activeTabMenu.addSeparator();
490     activeTabMenu.add(toggleDetailMenuItem);
491     activeTabMenu.add(toggleLogTreeMenuItem);
492     activeTabMenu.addSeparator();
493     activeTabMenu.add(menuUndock);
494     activeTabMenu.add(menuShowColor);
495     activeTabMenu.add(menuPrefs);
496 
497     activeTabMenu.addSeparator();
498     activeTabMenu.add(new CopyEventsToClipboardAction(logui));
499     activeTabMenu.add(new JMenuItem(clearAction));
500 
501     activeTabMenu.addSeparator();
502     activeTabMenu.add(new JMenuItem(toggleMarkerAction));
503     activeTabMenu.add(new JMenuItem(findNextMarkerAction));
504     activeTabMenu.add(new JMenuItem(findPreviousMarkerAction));
505     activeTabMenu.add(new JMenuItem(clearAllMarkersAction));
506 
507     activeTabMenu.add(new JMenuItem(findNextColorizedEventAction));
508     activeTabMenu.add(new JMenuItem(findPreviousColorizedEventAction));
509 
510     activeTabMenu.addSeparator();
511     activeTabMenu.add(new JMenuItem(scrollToTopAction));
512     activeTabMenu.add(toggleScrollToBottomMenuItem);
513     activeTabMenu.add(menuItemUseRightMouse);
514     
515     viewMenu.add(showToolbarCheck);
516     viewMenu.add(toggleStatusBarCheck);
517     viewMenu.add(toggleShowReceiversCheck);
518     viewMenu.add(menuShowWelcome);
519     viewMenu.addSeparator();
520     viewMenu.add(menuCustomExpressionPanel);
521 
522     if (!OSXIntegration.IS_OSX) {
523         viewMenu.addSeparator();
524         viewMenu.add(showAppPrefs);
525     }
526 
527     JMenu helpMenu = new JMenu("Help");
528     helpMenu.setMnemonic('H');
529 
530     JMenuItem about = new JMenuItem("About Chainsaw v2...");
531     about.setMnemonic('A');
532     about.addActionListener(
533       new ActionListener() {
534         public void actionPerformed(ActionEvent e) {
535           logui.showAboutBox();
536         }
537       });
538 
539     Action startTutorial =
540       new AbstractAction("Tutorial...", new ImageIcon(ChainsawIcons.HELP)) {
541         public void actionPerformed(ActionEvent e) {
542           logui.setupTutorial();
543         }
544       };
545 
546     startTutorial.putValue(
547       Action.SHORT_DESCRIPTION, "Starts the tutorial process");
548     helpMenu.add(startTutorial);
549 
550     List knownReceivers =
551       ReceiversHelper.getInstance().getKnownReceiverClasses();
552     JMenu receiverHelp = new JMenu("Receiver JavaDoc");
553 
554     for (Iterator iter = knownReceivers.iterator(); iter.hasNext();) {
555       final Class clazz = (Class) iter.next();
556       receiverHelp.add(
557         new AbstractAction(clazz.getName()) {
558           public void actionPerformed(ActionEvent arg0) {
559             HelpManager.getInstance().showHelpForClass(clazz);
560           }
561         });
562     }
563 
564     helpMenu.add(receiverHelp);
565 
566     helpMenu.addSeparator();
567     helpMenu.add(CommonActions.getInstance().getShowReleaseNotes());
568     helpMenu.add(about);
569 
570     menuBar.add(fileMenu);
571     menuBar.add(viewMenu);
572     menuBar.add(activeTabMenu);
573     menuBar.add(helpMenu);
574   }
575 
576   private Action createPauseAction() {
577     final Action action =
578       new AbstractAction("Pause") {
579         public void actionPerformed(ActionEvent evt) {
580           LogPanel logPanel = logui.getCurrentLogPanel();
581 
582           if (logPanel == null) {
583             return;
584           }
585 
586           logPanel.setPaused(!logPanel.isPaused());
587           scanState();
588         }
589       };
590 
591     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
592     action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F12"));
593     action.putValue(
594       Action.SHORT_DESCRIPTION,
595       "Causes incoming events for this tab to be discarded");
596     action.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.PAUSE));
597 
598     return action;
599   }
600 
601   private Action createShowPreferencesAction() {
602     Action showPreferences =
603       new AbstractAction("", ChainsawIcons.ICON_PREFERENCES) {
604         public void actionPerformed(ActionEvent arg0) {
605           LogPanel logPanel = logui.getCurrentLogPanel();
606 
607           if (logPanel != null) {
608             logPanel.showPreferences();
609           }
610         }
611       };
612 
613     showPreferences.putValue(
614       Action.SHORT_DESCRIPTION, "Tab Preferences...");
615 
616     // TODO think of good mnemonics and HotKey for this action
617     return showPreferences;
618   }
619 
620   private Action createCustomExpressionPanelAction() {
621     final JDialog dialog = new JDialog(logui, "Define tab", true);
622     dialog.getContentPane().add(getCustomExpressionPanel());
623     dialog.setLocationRelativeTo(null);
624     dialog.pack();
625 
626     Action createExpressionPanel =
627       new AbstractAction("", ChainsawIcons.ICON_HELP) {
628         public void actionPerformed(ActionEvent arg0) {
629             LogPanel.centerAndSetVisible(dialog);
630         }
631       };
632 
633     createExpressionPanel.putValue(
634       Action.SHORT_DESCRIPTION, "Create tab from expression...   ");
635 
636     // TODO think of good mnemonics and HotKey for this action
637     return createExpressionPanel;
638   }
639 
640   private Action createShowColorPanelAction() {
641     Action showColorPanel =
642       new AbstractAction("", ChainsawIcons.ICON_PREFERENCES) {
643         public void actionPerformed(ActionEvent arg0) {
644           LogPanel logPanel = logui.getCurrentLogPanel();
645 
646           if (logPanel != null) {
647             logPanel.showColorPreferences();
648           }
649         }
650       };
651 
652     showColorPanel.putValue(
653       Action.SHORT_DESCRIPTION, "Color settings...");
654 
655     // TODO think of good mnemonics and HotKey for this action
656     return showColorPanel;
657   }
658 
659   /**
660    * @return
661    */
662   private Action createShowReceiversAction() {
663     final Action action =
664       new AbstractAction("Show Receivers") {
665         public void actionPerformed(ActionEvent arg0) {
666           logui.getApplicationPreferenceModel().setReceivers(
667             !logui.getApplicationPreferenceModel().isReceivers());
668         }
669       };
670 
671     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_E));
672     action.putValue(
673       Action.SHORT_DESCRIPTION,
674       "Shows the currently configured Log4j Receivers");
675     action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F6"));
676     action.putValue(
677       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.ANIM_NET_CONNECT));
678     toggleShowReceiversCheck.setAction(action);
679 
680     return action;
681   }
682 
683   private Action createToggleDetailPaneAction() {
684     Action action =
685       new AbstractAction("Show Detail Pane") {
686         public void actionPerformed(ActionEvent evt) {
687           LogPanel logPanel = logui.getCurrentLogPanel();
688 
689           if (logPanel == null) {
690             return;
691           }
692 
693           logPanel.toggleDetailVisible();
694         }
695       };
696 
697     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_D));
698     action.putValue(
699       Action.ACCELERATOR_KEY,
700       KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
701     action.putValue(Action.SHORT_DESCRIPTION, "Hides/Shows the Detail Pane");
702     action.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.INFO));
703 
704     return action;
705   }
706 
707   private Action createToggleToolbarAction() {
708     /**
709      * -== Begin of Show/Hide toolbar action
710      */
711     final Action action =
712       new AbstractAction("Show Toolbar") {
713         public void actionPerformed(ActionEvent e) {
714           logui.getApplicationPreferenceModel().setToolbar(
715             !logui.getApplicationPreferenceModel().isToolbar());
716         }
717       };
718 
719     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
720 
721     return action;
722   }
723 
724   private void createToolbar() {
725     Insets buttonMargins = new Insets(1, 1, 1, 1);
726 
727     FileMenu menu = (FileMenu) menuBar.getMenu(0);
728 
729     JButton fileOpenButton = new SmallButton(menu.getLog4JFileOpenAction());
730     fileOpenButton.setMargin(buttonMargins);
731 
732     JButton fileSaveButton = new SmallButton(menu.getFileSaveAction());
733     fileSaveButton.setMargin(buttonMargins);
734 
735     fileOpenButton.setText("");
736     fileSaveButton.setText("");
737 
738     toolbar.add(fileOpenButton);
739     toolbar.add(fileSaveButton);
740     toolbar.addSeparator();
741 
742     pauseButton.setAction(pauseAction);
743     pauseButton.setText("");
744 
745     //		pauseButton.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F12"),pauseAction.getValue(Action.NAME) );
746     pauseButton.getActionMap().put(
747       pauseAction.getValue(Action.NAME), pauseAction);
748 
749     toggleCyclicButton.setAction(changeModelAction);
750     toggleCyclicButton.setText(null);
751 
752     detailPaneButton.setAction(toggleDetailPaneAction);
753     detailPaneButton.setText(null);
754     detailPaneButton.getActionMap().put(
755       toggleDetailPaneAction.getValue(Action.NAME), toggleDetailPaneAction);
756     detailPaneButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
757       KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
758       toggleDetailPaneAction.getValue(Action.NAME));
759 
760     logTreePaneButton.setAction(toggleLogTreeAction);
761     logTreePaneButton.getActionMap().put(
762       toggleLogTreeAction.getValue(Action.NAME), toggleLogTreeAction);
763     logTreePaneButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
764       KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
765       toggleLogTreeAction.getValue(Action.NAME));
766     logTreePaneButton.setText(null);
767 
768     scrollToBottomButton.setAction(toggleScrollToBottomAction);
769     scrollToBottomButton.getActionMap().put(
770       toggleScrollToBottomAction.getValue(Action.NAME), toggleScrollToBottomAction);
771     scrollToBottomButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
772       KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
773       toggleScrollToBottomAction.getValue(Action.NAME));
774     scrollToBottomButton.setText(null);
775 
776     SmallButton prefsButton = new SmallButton(showPreferencesAction);
777     SmallButton undockButton = new SmallButton(undockAction);
778     undockButton.setText("");
779 
780     toolbar.add(undockButton);
781     toolbar.add(pauseButton);
782     toolbar.add(toggleCyclicButton);
783     toolbar.addSeparator();
784     toolbar.add(detailPaneButton);
785     toolbar.add(logTreePaneButton);
786     toolbar.add(scrollToBottomButton);
787     toolbar.add(prefsButton);
788     toolbar.addSeparator();
789 
790     toolbar.add(clearButton);
791     clearButton.setAction(clearAction);
792     clearButton.setText("");
793     toolbar.addSeparator();
794 
795     showReceiversButton.setText(null);
796     toolbar.add(showReceiversButton);
797 
798     toolbar.add(Box.createHorizontalGlue());
799 
800     toolbar.setMargin(buttonMargins);
801     toolbar.setFloatable(false);
802   }
803 
804   private Action createUndockAction() {
805     Action action =
806       new AbstractAction("Undock", ChainsawIcons.ICON_UNDOCK) {
807         public void actionPerformed(ActionEvent arg0) {
808           LogPanel logPanel = logui.getCurrentLogPanel();
809 
810           if (logPanel != null) {
811             logPanel.undock();
812           }
813         }
814       };
815 
816     action.putValue(
817       Action.SHORT_DESCRIPTION,
818       "Undocks the current Log panel into its own window");
819 
820     //	TODO think of some mnemonics and HotKeys for this action
821     return action;
822   }
823 
824   private void scanState() {
825     toggleStatusBarCheck.setSelected(logui.isStatusBarVisible());
826     toggleShowReceiversCheck.setSelected(
827       logui.getApplicationPreferenceModel().isReceivers());
828 
829     logTreePaneButton.setSelected(logui.isLogTreePanelVisible());
830     LogPanel panel = logui.getCurrentLogPanel();
831     if (panel != null) {
832     	scrollToBottomButton.setSelected(panel.isScrollToBottom());
833         toggleDetailMenuItem.setSelected(panel.isDetailVisible());
834     } else {
835     	scrollToBottomButton.setSelected(false);
836         toggleDetailMenuItem.setSelected(false);
837     }
838     showReceiversButton.setSelected(
839       logui.getApplicationPreferenceModel().isReceivers());
840     menuShowWelcome.setSelected(logui.getTabbedPane().containsWelcomePanel());
841 
842     /**
843      * We get the currently selected LogPanel, and if null, deactivate some
844      * actions
845      */
846     LogPanel logPanel = logui.getCurrentLogPanel();
847 
848     boolean activateLogPanelActions = true;
849 
850     if (logPanel == null) {
851       activateLogPanelActions = false;
852       activeTabMenu.setEnabled(false);
853       toggleWelcomeVisibleAction.setEnabled(true);
854       detailPaneButton.setSelected(false);
855       toggleCyclicButton.setSelected(false);
856     } else {
857       activeTabMenu.setEnabled(true);
858       fileMenu.getFileSaveAction().setEnabled(true);
859       pauseButton.getModel().setSelected(logPanel.isPaused());
860       toggleCyclicButton.setSelected(logPanel.isCyclic());
861       logui.getStatusBar().setPaused(logPanel.isPaused(), logPanel.getIdentifier());
862       toggleCyclicMenuItem.setSelected(logPanel.isCyclic());
863       detailPaneButton.getModel().setSelected(logPanel.isDetailVisible());
864       toggleLogTreeMenuItem.setSelected(logPanel.isLogTreeVisible());
865       toggleScrollToBottomMenuItem.setSelected(logPanel.isScrollToBottom());
866     }
867 
868     for (int i = 0; i < logPanelSpecificActions.length; i++) {
869       logPanelSpecificActions[i].setEnabled(activateLogPanelActions);
870     }
871 
872     String currentLookAndFeelName = UIManager.getLookAndFeel().getName();
873 
874     for (Iterator iter = lookAndFeelMenus.iterator(); iter.hasNext();) {
875       JRadioButtonMenuItem element = (JRadioButtonMenuItem) iter.next();
876 
877       if (element.getText().equals(currentLookAndFeelName)) {
878         element.setSelected(true);
879       } else {
880         element.setSelected(false);
881       }
882     }
883   }
884 
885     private Action getFindNextColorizedEventAction() {
886       final Action action =
887         new AbstractAction("Find next colorized event") {
888           public void actionPerformed(ActionEvent e) {
889             LogPanel p = logui.getCurrentLogPanel();
890             if (p != null) {
891               p.findNextColorizedEvent();
892             }
893           }
894         };
895         action.putValue(Action.SHORT_DESCRIPTION, "Find the next colorized event from the current location");
896         action.putValue("enabled", Boolean.TRUE);
897         action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_N));
898         action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
899 
900       return action;
901     }
902 
903     private Action getFindPreviousColorizedEventAction() {
904       final Action action =
905         new AbstractAction("Find previous colorized event") {
906           public void actionPerformed(ActionEvent e) {
907             LogPanel p = logui.getCurrentLogPanel();
908 
909             if (p != null) {
910               p.findPreviousColorizedEvent();
911             }
912           }
913         };
914         action.putValue(Action.SHORT_DESCRIPTION, "Find the next colorized event from the current location");
915         action.putValue("enabled", Boolean.TRUE);
916         action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
917         action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
918 
919       return action;
920     }
921 
922   private JPanel getCustomExpressionPanel() {
923     final JPanel panel = new JPanel(new BorderLayout());
924     panel.add(
925       new JLabel("Enter expression for new tab:  "), BorderLayout.NORTH);
926 
927     final JEditorPane entryField = new JEditorPane();
928     entryField.setPreferredSize(new Dimension(350, 75));
929     JTextComponentFormatter.applySystemFontAndSize(entryField);
930     entryField.addKeyListener(
931       new ExpressionRuleContext(new FilterModel(), entryField));
932     panel.add(entryField, BorderLayout.CENTER);
933 
934     JButton ok = new JButton(" OK ");
935     JButton close = new JButton(" Close ");
936     JPanel lowerPanel = new JPanel();
937     lowerPanel.add(ok);
938     lowerPanel.add(Box.createHorizontalStrut(7));
939     lowerPanel.add(close);
940     panel.add(lowerPanel, BorderLayout.SOUTH);
941 
942     ok.addActionListener(
943       new AbstractAction() {
944         public void actionPerformed(ActionEvent evt) {
945           logui.createCustomExpressionLogPanel(entryField.getText());
946           SwingUtilities.getAncestorOfClass(JDialog.class, panel).setVisible(
947             false);
948         }
949       });
950 
951     close.addActionListener(
952       new AbstractAction() {
953         public void actionPerformed(ActionEvent evt) {
954           SwingUtilities.getAncestorOfClass(JDialog.class, panel).setVisible(
955             false);
956         }
957       });
958 
959     //String expression = JOptionPane.showInputDialog(logui, "Enter expression", "Create custom expression LogPanel", JOptionPane.PLAIN_MESSAGE);
960     return panel;
961   }
962 }