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.Dimension;
21  import java.awt.FlowLayout;
22  import java.awt.GridBagConstraints;
23  import java.awt.GridBagLayout;
24  import java.awt.Insets;
25  import java.text.NumberFormat;
26  
27  import javax.swing.BorderFactory;
28  import javax.swing.Icon;
29  import javax.swing.ImageIcon;
30  import javax.swing.JComponent;
31  import javax.swing.JLabel;
32  import javax.swing.JPanel;
33  import javax.swing.SwingConstants;
34  import javax.swing.SwingUtilities;
35  import javax.swing.border.Border;
36  
37  import org.apache.log4j.chainsaw.icons.ChainsawIcons;
38  import org.apache.log4j.chainsaw.messages.MessageCenter;
39  
40  
41  /**
42   * A general purpose status bar for all Frame windows
43   *
44   * @author Paul Smith <psmith@apache.org>
45   *
46   */
47  public class ChainsawStatusBar extends JPanel {
48    private static final int DELAY_PERIOD = 5000;
49    private static final String DEFAULT_MSG = "Welcome to Chainsaw v2!";
50    private final JLabel statusMsg = new JLabel(DEFAULT_MSG);
51    private final JLabel searchMatchLabel = new JLabel("", SwingConstants.CENTER);
52    private final JLabel pausedLabel = new JLabel("", SwingConstants.CENTER);
53    private final JLabel lineSelectionLabel = new JLabel("", SwingConstants.CENTER);
54    private final JLabel eventCountLabel = new JLabel("", SwingConstants.CENTER);
55    private final JLabel receivedEventLabel = new JLabel("", SwingConstants.CENTER);
56    private final JLabel receivedConnectionlabel = new JLabel("", SwingConstants.CENTER);
57    private volatile long lastReceivedConnection = System.currentTimeMillis();
58    private final Thread connectionThread;
59    private final Icon pausedIcon = new ImageIcon(ChainsawIcons.PAUSE);
60    private final Icon netConnectIcon =
61      new ImageIcon(ChainsawIcons.ANIM_NET_CONNECT);
62    private final NumberFormat nf = NumberFormat.getNumberInstance();
63    private final Border statusBarComponentBorder =
64      BorderFactory.createLineBorder(statusMsg.getBackground().darker());
65    private final LogUI logUI;
66  
67      public ChainsawStatusBar(LogUI logUI) {
68      setLayout(new GridBagLayout());
69      this.logUI = logUI;
70      nf.setMaximumFractionDigits(0);
71      nf.setMinimumFractionDigits(0);
72      nf.setGroupingUsed(false);
73  
74      JPanel statusMsgPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 2));
75      
76      statusMsgPanel.add(statusMsg);
77      statusMsgPanel.setBorder(statusBarComponentBorder);
78      
79      pausedLabel.setBorder(statusBarComponentBorder);
80      pausedLabel.setMinimumSize(
81        new Dimension(pausedIcon.getIconWidth(), pausedIcon.getIconHeight()));
82  
83      pausedLabel.setToolTipText(
84        "Shows whether the current Log panel is paused or not");
85  
86      receivedEventLabel.setBorder(statusBarComponentBorder);
87      receivedEventLabel.setToolTipText(
88        "Indicates whether Chainsaw is receiving events, and how fast it is processing them");
89      receivedEventLabel.setMinimumSize(
90        new Dimension(
91          receivedEventLabel.getFontMetrics(receivedEventLabel.getFont())
92                            .stringWidth("99999999999.9/s") + 5,
93          (int) receivedEventLabel.getPreferredSize().getHeight()));
94  
95  	eventCountLabel.setBorder(statusBarComponentBorder);
96  	eventCountLabel.setToolTipText("<# viewable events>:<# total events>");
97  	eventCountLabel.setMinimumSize(
98  	new Dimension(
99  	eventCountLabel.getFontMetrics(eventCountLabel.getFont())
100 						.stringWidth("Filtered/Total: 999999999999:999999999999") + 5,
101 	  (int) eventCountLabel.getPreferredSize().getHeight()));
102 	  
103     searchMatchLabel.setBorder(statusBarComponentBorder);
104     searchMatchLabel.setToolTipText("<# viewable events>:<# total events>");
105     searchMatchLabel.setMinimumSize(
106     new Dimension(
107     searchMatchLabel.getFontMetrics(eventCountLabel.getFont()).stringWidth("Find matches: 999999999999") + 5,
108             (int) searchMatchLabel.getPreferredSize().getHeight()));
109 
110     receivedConnectionlabel.setBorder(statusBarComponentBorder);
111     receivedConnectionlabel.setToolTipText(
112       "Indicates whether Chainsaw has received a remote connection");
113     receivedConnectionlabel.setMinimumSize(
114       new Dimension(
115         netConnectIcon.getIconWidth() + 4,
116         (int) receivedConnectionlabel.getPreferredSize().getHeight()));
117 
118     lineSelectionLabel.setBorder(statusBarComponentBorder);
119     lineSelectionLabel.setMinimumSize(
120       new Dimension(
121         lineSelectionLabel.getFontMetrics(lineSelectionLabel.getFont())
122                           .stringWidth("999999999"),
123         (int) lineSelectionLabel.getPreferredSize().getHeight()));
124     lineSelectionLabel.setToolTipText(
125       "The current line # selected");
126 
127     JComponent[] toFix =
128       new JComponent[] {
129         searchMatchLabel, eventCountLabel,
130         receivedConnectionlabel, lineSelectionLabel, receivedEventLabel,
131         pausedLabel
132       };
133 
134     for (int i = 0; i < toFix.length; i++) {
135       toFix[i].setPreferredSize(toFix[i].getMinimumSize());
136       toFix[i].setMaximumSize(toFix[i].getMinimumSize());
137     }
138 
139     statusMsg.setMinimumSize(pausedLabel.getPreferredSize());
140     statusMsg.setToolTipText("Shows messages from Chainsaw");
141 
142     GridBagConstraints c = new GridBagConstraints();
143     c.insets = new Insets(2, 2, 2, 2);
144     c.weightx = 1.0;
145     c.weighty = 1.0;
146     c.ipadx = 2;
147     c.ipady = 2;
148     c.gridx = 0;
149     c.gridy = 0;
150     c.fill = GridBagConstraints.BOTH;
151     c.anchor = GridBagConstraints.WEST;
152 
153     add(statusMsgPanel, c);
154 
155     c.weightx = 0.0;
156     c.weighty = 0.0;
157     c.gridx = 1;
158     add(receivedConnectionlabel, c);
159 
160 	c.weightx = 0.0;
161 	c.weighty = 0.0;
162 	c.gridx = 2;
163 	add(lineSelectionLabel, c);
164 	
165     c.weightx = 0.0;
166     c.weighty = 0.0;
167     c.gridx = 3;
168     add(searchMatchLabel, c);
169 
170 	c.weightx = 0.0;
171 	c.weighty = 0.0;
172 	c.gridx = 4;
173 	add(eventCountLabel, c);
174 
175     c.weightx = 0.0;
176     c.weighty = 0.0;
177     c.gridx = 5;
178     add(receivedEventLabel, c);
179 
180     c.weightx = 0.0;
181     c.weighty = 0.0;
182     c.gridx = 6;
183 
184     add(pausedLabel, c);
185 
186     connectionThread =
187       new Thread(
188         new Runnable() {
189           public void run() {
190             while (true) {
191               try {
192                 Thread.sleep(DELAY_PERIOD);
193               } catch (InterruptedException e) {
194               }
195 
196               Icon icon = null;
197 
198               if (
199                 (System.currentTimeMillis() - lastReceivedConnection) < DELAY_PERIOD) {
200                 icon = netConnectIcon;
201               }
202 
203               final Icon theIcon = icon;
204               SwingUtilities.invokeLater(
205                 new Runnable() {
206                   public void run() {
207                     receivedConnectionlabel.setIcon(theIcon);
208                   }
209                 });
210             }
211           }
212         });
213     connectionThread.start();
214   }
215 
216   void setDataRate(final double dataRate) {
217     SwingUtilities.invokeLater(
218       new Runnable() {
219         public void run() {
220           receivedEventLabel.setText(nf.format(dataRate) + "/s");
221         }
222       });
223   }
224 
225   /**
226    * Indicates a new connection has been established between
227    * Chainsaw and some remote host
228    * @param source
229    */
230   void remoteConnectionReceived(String source) {
231     lastReceivedConnection = System.currentTimeMillis();
232     MessageCenter.getInstance().getLogger().info("Connection received from " + source);
233     connectionThread.interrupt();
234 
235     //    TODO and maybe play a sound?
236   }
237 
238   /**
239    * Called when the paused state of the LogPanel has been updated
240    * @param isPaused
241    * @param tabName
242    */
243   void setPaused(final boolean isPaused, String tabName) {
244     if (tabName.equals(logUI.getActiveTabName())) {
245       Runnable runnable =
246         new Runnable() {
247           public void run() {
248               pausedLabel.setIcon(isPaused ? pausedIcon : null);
249               pausedLabel.setToolTipText(
250                 isPaused ? "This Log panel is currently paused"
251                          : "This Log panel is not paused");
252           }
253       };
254       SwingUtilities.invokeLater(runnable);
255     }
256   }
257 
258   void setSelectedLine(
259           final int selectedLine, final int lineCount, final int total, String tabName) {
260     if (tabName.equals(logUI.getActiveTabName())) {
261         SwingUtilities.invokeLater(
262           new Runnable() {
263             public void run() {
264               lineSelectionLabel.setText(selectedLine+"");
265               eventCountLabel.setText("Filtered/Total: " + lineCount + ":" + total);
266             }
267           });
268     }
269   }
270 
271   void setSearchMatchCount(int searchMatchCount, String tabName) {
272       if (tabName.equals(logUI.getActiveTabName())) {
273           if (searchMatchCount == 0) {
274             searchMatchLabel.setText("");
275           } else {
276             searchMatchLabel.setText("Find matches: " + searchMatchCount);
277           }
278       }
279   }
280 
281   void setNothingSelected() {
282     SwingUtilities.invokeLater(
283       new Runnable() {
284         public void run() {
285           lineSelectionLabel.setText("");
286         }
287       });
288   }
289 
290   void clear() {
291     setMessage(DEFAULT_MSG);
292     setNothingSelected();
293     SwingUtilities.invokeLater(
294       new Runnable() {
295         public void run() {
296           receivedEventLabel.setText("");
297         }
298       });
299   }
300 
301   public void setMessage(final String msg) {
302     SwingUtilities.invokeLater(
303       new Runnable() {
304         public void run() {
305           statusMsg.setText(" " + msg);
306         }
307       });
308   }
309 }