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