/* This file is part of Wattzap Community Edition.
*
* Wattzap Community Edtion is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Wattzap Community Edition is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Wattzap. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package com.omniscient.log4jcontrib.swingappender.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
/**
* Creates a UI to display log messages from a SwingAppender
*
* @author pshah
*
*/
public class SwingAppenderUI {
// UI attributes
private JFrame jframe;
private JButton startPause; // button for start/pause - toggles
private JButton stop; // stop button
private JButton clear; // button to clear the text area
private JButton search; // search button
private JTextField searchField; // search field
private JPanel buttonsPanel; // panel to hold all buttons
private JTextPane logMessagesDisp; // display area
private JScrollPane scrollPane;
// buffer to hold log statements when the UI is set to PAUSE
private List logBuffer;
// flag to indicate if we should display new log events
private int appState;
/* Constants */
public static final String STYLE_REGULAR = "regular";
public static final String STYLE_HIGHLIGHTED = "highlighted";
public static final String START = "start";
public static final String PAUSE = "pause";
public static final String STOP = "stop";
public static final String CLEAR = "clear";
public static final int STARTED = 0;
public static final int PAUSED = 1;
public static final int STOPPED = 2;
/**
* An instance for SwingAppenderUI class. This holds the Singleton.
*/
private static SwingAppenderUI instance;
/**
* Method to get an instance of the this class. This method ensures that
* SwingAppenderUI is a Singleton using a doule checked locking mechanism.
*
* @return An instance of SwingAppenderUI
*/
public static SwingAppenderUI getInstance() {
if (instance == null) {
synchronized (SwingAppenderUI.class) {
if (instance == null) {
instance = new SwingAppenderUI();
}
}
}
return instance;
}
/**
* Private constructer to ensure that this object cannot e instantiated from
* outside this class.
*/
private SwingAppenderUI() {
// set internal attributes
logBuffer = new ArrayList();
appState = STARTED;
// create main window
jframe = new JFrame();
jframe.setTitle("WattzAp Debug");
ImageIcon img = new ImageIcon("icons/preferences.jpg");
jframe.setIconImage(img.getImage());
// initialize buttons
initButtonsPanel();
// create text area to hold the log messages
initMessageDispArea();
// add components to the contentPane
jframe.getContentPane().add(BorderLayout.NORTH, buttonsPanel);
jframe.getContentPane().add(BorderLayout.CENTER, scrollPane);
jframe.setSize(800, 600);
jframe.setVisible(true);
}
/**
* Displays the log in the text area unless dispMsg is set to false in which
* case it adds the log to a buffer. When dispMsg becomes true, the buffer
* is first flushed and it's contents are displayed in the text area.
*
* @param log
* The log message to be displayed in the text area
*/
public void doLog(String log) {
if (appState == STARTED) {
try {
StyledDocument sDoc = logMessagesDisp.getStyledDocument();
if (!logBuffer.isEmpty()) {
Iterator iter = logBuffer.iterator();
while (iter.hasNext()) {
sDoc.insertString(0, (String) iter.next(),
sDoc.getStyle(STYLE_REGULAR));
iter.remove();
}
}
sDoc.insertString(0, log, sDoc.getStyle(STYLE_REGULAR));
} catch (BadLocationException ble) {
System.err.println("Bad Location Exception : "
+ ble.getMessage());
}
} else if (appState == PAUSED) {
logBuffer.add(log);
}
}
/**
* creates a panel to hold the buttons
*/
private void initButtonsPanel() {
// TODO: Add clear button to clear the log statements.
buttonsPanel = new JPanel();
startPause = new JButton(PAUSE);
startPause.addActionListener(new StartPauseActionListener());
stop = new JButton(STOP);
stop.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
appState = STOPPED;
startPause.setText(START);
}
});
clear = new JButton(CLEAR);
clear.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
logMessagesDisp.setText("");
}
});
searchField = new JTextField(25);
search = new JButton("Search");
search.addActionListener(new SearchActionListener());
buttonsPanel.add(startPause);
buttonsPanel.add(stop);
buttonsPanel.add(clear);
buttonsPanel.add(searchField);
buttonsPanel.add(search);
}
/**
* Creates a scrollable text area
*/
private void initMessageDispArea() {
logMessagesDisp = new JTextPane();
scrollPane = new JScrollPane(logMessagesDisp);
scrollPane
.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane
.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
// add styles
StyledDocument sDoc = logMessagesDisp.getStyledDocument();
Style def = StyleContext.getDefaultStyleContext().getStyle(
StyleContext.DEFAULT_STYLE);
Style s1 = sDoc.addStyle(STYLE_REGULAR, def);
StyleConstants.setFontFamily(def, "SansSerif");
Style s2 = sDoc.addStyle(STYLE_HIGHLIGHTED, s1);
StyleConstants.setBackground(s2, Color.BLUE);
}
/**************** inner classes *************************/
/**
* Accepts and responds to action events generated by the startPause button.
*/
class StartPauseActionListener implements ActionListener {
/**
* Toggles the value of the startPause button. Also toggles the value of
* dispMsg.
*
* @param evt
* The action event
*/
public void actionPerformed(ActionEvent evt) {
JButton srcButton = (JButton) evt.getSource();
if (srcButton.getText().equals(START)) {
srcButton.setText(PAUSE);
appState = STARTED;
} else if (srcButton.getText().equals(PAUSE)) {
appState = PAUSED;
srcButton.setText(START);
}
}
}
class SearchActionListener implements ActionListener {
public void actionPerformed(ActionEvent evt) {
JButton srcButton = (JButton) evt.getSource();
if (!"Search".equals(srcButton.getText())) {
return;
}
System.err.println("Highlighting search results");
String searchTerm = searchField.getText();
String allLogText = logMessagesDisp.getText();
int startIndex = 0;
int selectionIndex = -1;
Highlighter hLighter = logMessagesDisp.getHighlighter();
// clear all previous highlightes
hLighter.removeAllHighlights();
DefaultHighlighter.DefaultHighlightPainter highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(
Color.BLUE);
while ((selectionIndex = allLogText.indexOf(searchTerm, startIndex)) != -1) {
startIndex = selectionIndex + searchTerm.length();
try {
int newLines = getNumberOfNewLinesTillSelectionIndex(
allLogText, selectionIndex);
hLighter.addHighlight(selectionIndex - newLines,
(selectionIndex + searchTerm.length() - newLines),
highlightPainter);
} catch (BadLocationException ble) {
System.err.println("Bad Location Exception: "
+ ble.getMessage());
}
}
}
private int getNumberOfNewLinesTillSelectionIndex(String allLogText,
int selectionIndex) {
int numberOfNewlines = 0;
int pos = 0;
while ((pos = allLogText.indexOf("\n", pos)) != -1
&& pos <= selectionIndex) {
numberOfNewlines++;
pos++;
}
return numberOfNewlines;
}
}
public void close() {
// clean up code for UI goes here.
jframe.setVisible(false);
}
}