package hirondelle.stocks.help;
import hirondelle.stocks.preferences.LoggingPreferencesEditor;
import hirondelle.stocks.util.Args;
import hirondelle.stocks.util.Consts;
import hirondelle.stocks.util.FileUtil;
import hirondelle.stocks.util.Util;
import hirondelle.stocks.util.ui.UiConsts;
import hirondelle.stocks.util.ui.UiUtil;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
public final class AboutAction extends AbstractAction {
public AboutAction(JFrame aFrame) {
super("About " + Consts.APP_NAME);
Args.checkForNull(aFrame);
fFrame = aFrame;
putValue(SHORT_DESCRIPTION, "About this application");
putValue(LONG_DESCRIPTION, "Displays details regarding the StocksMonitor application.");
putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_A) );
}
@Override public void actionPerformed(ActionEvent e) {
fLogger.info("Showing the about box.");
showAboutBox();
}
private JFrame fFrame;
private JLabel fObjectHeapSize;
private javax.swing.Timer fTimer;
private ActionListener fHeapSizeUpdater;
private static final int UPDATE_FREQ = 2 * Consts.MILLISECONDS_PER_SECOND;
private static final long SLEEP_INTERVAL = 100;
private static final String ABOUT_TEXT_FILE = "About.txt";
private static final Dimension ABOUT_TEXT_SIZE = new Dimension(100,250);
private static final Logger fLogger = Util.getLogger(AboutAction.class);
private void showAboutBox(){
JTabbedPane aboutPane = new JTabbedPane();
aboutPane.addTab( "About" , getAboutPanel() );
aboutPane.setMnemonicAt(0, KeyEvent.VK_A);
aboutPane.addTab( "System Info" , getSystemInfoPanel() );
aboutPane.setMnemonicAt(1, KeyEvent.VK_S);
startHeapSizeTimer();
Icon image = UiUtil.getImageIcon("xray-small.jpg", this.getClass()) ;
String title = UiUtil.getDialogTitle("About");
JOptionPane.showMessageDialog(fFrame, aboutPane, title, JOptionPane.OK_OPTION, image);
stopHeapSizeTimer();
}
private JComponent getAboutPanel(){
JPanel aboutPanel = new JPanel();
aboutPanel.setLayout( new BoxLayout(aboutPanel, BoxLayout.Y_AXIS) );
String appNameAndVersion = Consts.APP_NAME + Consts.SPACE + Consts.APP_VERSION;
String text = appNameAndVersion + Consts.NEW_LINE + getAboutFileContents();
JTextArea aboutText = UiUtil.getStandardTextAreaHardNewLines( text );
JScrollPane scrollPane = new JScrollPane(aboutText);
scrollPane.setPreferredSize(ABOUT_TEXT_SIZE);
aboutPanel.add(scrollPane);
return aboutPanel;
}
private String getAboutFileContents(){
return FileUtil.asString(ABOUT_TEXT_FILE, this.getClass());
}
private JComponent getSystemInfoPanel(){
JPanel infoPanel = getStandardPanel();
Map<String, String> info = new HashMap<String, String>();
addSysProperty(info, "Java Version","java.version");
addSysProperty(info, "Java VM", "java.vm.info");
addSysProperty(info, "Java Home", "java.home");
addSysProperty(info, "Java Vendor", "java.vendor");
addSysProperty(info, "User Current Directory", "user.dir" );
addSysProperty(info, "User Home Directory", "user.home" );
StringBuilder osInfo = new StringBuilder();
osInfo.append( getProperty("os.arch") );
osInfo.append( Consts.SPACE);
osInfo.append( getProperty("os.name") );
osInfo.append( Consts.SPACE);
osInfo.append( getProperty("os.version") );
info.put("Operating System", osInfo.toString());
LoggingPreferencesEditor loggingPrefs = new LoggingPreferencesEditor();
info.put("Logging Config File", loggingPrefs.getLogConfigFile().toString() );
UiUtil.addSimpleDisplayFields( infoPanel, new TreeMap<String, String>(info) );
fObjectHeapSize = UiUtil.addSimpleDisplayField(
infoPanel,
"Object Heap Size",
getHeapSize(),
UiUtil.getConstraints(8,0),
true
);
fObjectHeapSize.setToolTipText("Total memory consumption is much larger");
addGarbageCollectionButton(infoPanel);
return infoPanel;
}
private void addGarbageCollectionButton(JPanel aInfoPanel){
JButton collectGarbage = new JButton("Collect Garbage");
collectGarbage.setToolTipText("Request garbage collection by JVM");
collectGarbage.setMnemonic(KeyEvent.VK_C);
collectGarbage.addActionListener( new ActionListener() {
@Override public void actionPerformed(ActionEvent event) {
putOutTheGarbage(); updateHeapSizeDisplay();
}
});
GridBagConstraints constraints = UiUtil.getConstraints(9,1);
constraints.insets = new Insets(UiConsts.ONE_SPACE, 0,0,0);
aInfoPanel.add(collectGarbage, constraints );
}
private JPanel getStandardPanel(){
JPanel result = new JPanel();
result.setLayout(new GridBagLayout());
result.setBorder(UiUtil.getStandardBorder());
return result;
}
private void updateHeapSizeDisplay(){
fLogger.fine("Updating heap size...");
fObjectHeapSize.setText(getHeapSize());
}
private String getHeapSize(){
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
Long memoryUseKB = new Long( (totalMemory - freeMemory)/Consts.ONE_KILOBYTE );
StringBuilder result = new StringBuilder();
result.append(UiUtil.getLocalizedInteger(memoryUseKB));
result.append(" KB");
return result.toString();
}
private void startHeapSizeTimer(){
fHeapSizeUpdater = new ActionListener() {
@Override public void actionPerformed(ActionEvent evt) {
updateHeapSizeDisplay();
}
};
fTimer = new javax.swing.Timer(UPDATE_FREQ, fHeapSizeUpdater);
fTimer.start();
fLogger.fine("Starting timer...");
}
private void stopHeapSizeTimer(){
fLogger.fine("Stopping timer...");
fTimer.stop(); fTimer.removeActionListener(fHeapSizeUpdater); fHeapSizeUpdater = null;
fTimer = null;
}
private static void putOutTheGarbage() {
collectGarbage();
collectGarbage();
}
private static void collectGarbage() {
try {
System.gc();
Thread.currentThread().sleep(SLEEP_INTERVAL);
System.runFinalization();
Thread.currentThread().sleep(SLEEP_INTERVAL);
}
catch (InterruptedException ex){
ex.printStackTrace();
}
}
private void addSysProperty(Map<String, String> aMap, String aKey, String aPropertyName){
aMap.put(aKey, getProperty(aPropertyName));
}
private String getProperty(String aName){
return System.getProperty(aName);
}
}