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