View Javadoc

1   /* OpenLogViewer
2    *
3    * Copyright 2012
4    *
5    * This file is part of the OpenLogViewer project.
6    *
7    * OpenLogViewer software is free software: you can redistribute it and/or modify
8    * it under the terms of the GNU General Public License as published by
9    * the Free Software Foundation, either version 3 of the License, or
10   * (at your option) any later version.
11   *
12   * OpenLogViewer software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with any OpenLogViewer software.  If not, see http://www.gnu.org/licenses/
19   *
20   * I ask that if you make any changes to this file you fork the code on github.com!
21   *
22   */
23  package org.diyefi.openlogviewer.subframes;
24  
25  import java.awt.BorderLayout;
26  import java.awt.Component;
27  import java.awt.Dimension;
28  import java.awt.Font;
29  import java.awt.Insets;
30  import java.io.IOException;
31  import java.text.DateFormat;
32  import java.text.SimpleDateFormat;
33  import java.util.Date;
34  import java.util.Locale;
35  import java.util.Properties;
36  
37  import javax.swing.BorderFactory;
38  import javax.swing.Box;
39  import javax.swing.BoxLayout;
40  import javax.swing.ImageIcon;
41  import javax.swing.JEditorPane;
42  import javax.swing.JFrame;
43  import javax.swing.JLabel;
44  import javax.swing.JPanel;
45  import javax.swing.JTextPane;
46  import javax.swing.UIManager;
47  import javax.swing.event.HyperlinkEvent;
48  import javax.swing.event.HyperlinkListener;
49  import javax.swing.text.SimpleAttributeSet;
50  import javax.swing.text.StyleConstants;
51  
52  import org.diyefi.openlogviewer.OpenLogViewer;
53  import org.diyefi.openlogviewer.utils.MathUtils;
54  
55  public final class AboutFrame extends JFrame {
56  	private static final double bytesPerMegaByte = 1048576;
57  	private static final long serialVersionUID = 1L;
58  	private static final int FRAME_WIDTH = 450;
59  	private static final int SPACER_HEIGHT = 20;
60  	private static final String LINK_CLOSE = "</a>";
61  
62  	private final Properties buildInfo;
63  
64  	private static final HyperlinkListener HLL = new HyperlinkListener() {
65  		public void hyperlinkUpdate(final HyperlinkEvent hle) {
66  			if (HyperlinkEvent.EventType.ACTIVATED.equals(hle.getEventType())) {
67  				try {
68  					java.awt.Desktop.getDesktop().browse(java.net.URI.create(hle.getDescription()));
69  				} catch (IOException e) {
70  					OpenLogViewer.getInstance().defaultBrowserNotFound();
71  				}
72  			}
73  		}
74  	};
75  
76  	private static AboutFrame aboutFrame; // Must not be changed outside of synchronized blocks
77  
78  	/**
79  	 * Shows the about box. If the box is already open, just hidden, it is simply raised.
80  	 * If the about box is not open, then it has been disposed of and is created again.
81  	 *
82  	 * @param buildInfo the properties from which to retrieve build details.
83  	 */
84  	public static void show(final Properties buildInfo) {
85  		synchronized(HLL) { // Mutex must not change, however it doesn't matter what it is, so we reuse this.
86  			if (aboutFrame != null) {
87  				aboutFrame.setVisible(true);
88  			} else {
89  				aboutFrame = new AboutFrame(buildInfo);
90  			}
91  		}
92  	}
93  
94  	private AboutFrame(final Properties buildInfo) {
95  		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
96  
97  		this.buildInfo = buildInfo;
98  		final BorderLayout lm = new BorderLayout();
99  		lm.setHgap(SPACER_HEIGHT);
100 		setLayout(lm);
101 
102 		OpenLogViewer.setupWindowKeyBindings(this);
103 
104 		final JPanel north = createNorthPanel();
105 		final JPanel center = createCenterPanel();
106 		final JPanel south = createSouthPanel();
107 		add(north, BorderLayout.NORTH);
108 		add(center, BorderLayout.CENTER);
109 		add(south, BorderLayout.SOUTH);
110 
111 		setTitle("About - " + buildInfo.getProperty("application.title"));
112 
113 		pack(); // Gets insets to be correct
114 
115 		final Insets insets = getInsets();
116 		final int width = FRAME_WIDTH + insets.left + insets.right;
117 		setPreferredSize(new Dimension(width, 0)); // Set the width so that component heights are correct
118 
119 		final int height = north.getHeight() + center.getHeight() + south.getHeight() + insets.top + insets.bottom;
120 		setMinimumSize(new Dimension(width, height));
121 		setPreferredSize(new Dimension(width, height));
122 
123 		pack(); // Makes the window be the size we want.
124 
125 		setVisible(true);
126 	}
127 
128 	private JPanel createNorthPanel() {
129 		final String appName = OpenLogViewer.class.getSimpleName();
130 		final JPanel northPanel = new JPanel();
131 		northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.Y_AXIS));
132 
133 		final ImageIcon icon = createImageIcon("logo64x64.png", appName + " Logo");
134 		final JLabel logo = new JLabel(icon);
135 		logo.setAlignmentX(Component.CENTER_ALIGNMENT);
136 		northPanel.add(logo);
137 
138 		addTextToPanel(northPanel, appName);
139 		addTextToPanel(northPanel, "Version: " + buildInfo.getProperty("project.version"));
140 		addTextToPanel(northPanel, "Detailed version: " + buildInfo.getProperty("git.commit.id.describe"));
141 		addTextToPanel(northPanel, "Git SHA1 hash: " + buildInfo.getProperty("git.commit.id"));
142 
143 		return northPanel;
144 	}
145 
146 	private JPanel createCenterPanel() {
147 		final JPanel centerPanel = new JPanel();
148 		centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
149 
150 		final JTextPane description = new JTextPane();
151 		final SimpleAttributeSet simpleAttrib = new SimpleAttributeSet();
152 		StyleConstants.setAlignment(simpleAttrib, StyleConstants.ALIGN_JUSTIFIED);
153 		description.setParagraphAttributes(simpleAttrib, false);
154 
155 		description.setText(buildInfo.getProperty("project.description"));
156 		description.setEditable(false);
157 		description.setOpaque(false);
158 		description.setBorder(BorderFactory.createEmptyBorder(SPACER_HEIGHT, SPACER_HEIGHT, SPACER_HEIGHT, SPACER_HEIGHT));
159 		description.setAlignmentX(Component.CENTER_ALIGNMENT);
160 		description.setSize(new Dimension(FRAME_WIDTH, Integer.MAX_VALUE)); // Must be set, or height shows up as one line (+other components) for the center panel
161 		centerPanel.add(description);
162 
163 		final String website = buildInfo.getProperty("project.url");
164 		final String forumUrl = buildInfo.getProperty("project.forum.url");
165 		final String issuesUrl = buildInfo.getProperty("project.issueManagement.url");
166 		addTextToPanel(centerPanel, "Website: <a href='" + website + "'>" + website + LINK_CLOSE);
167 		addTextToPanel(centerPanel, "Issues: <a href='" + issuesUrl + "'>" + issuesUrl + LINK_CLOSE);
168 		addTextToPanel(centerPanel, "Support: <a href='" + forumUrl + "'>" + forumUrl + LINK_CLOSE);
169 
170 		addTextToPanel(centerPanel, "Licensed under the <a href='http://www.gnu.org/licenses/quick-guide-gplv3.html'>GNU General Public License (GPL) V3</a>");
171 
172 		centerPanel.add(Box.createVerticalStrut(SPACER_HEIGHT));
173 
174 		return centerPanel;
175 	}
176 
177 	private JPanel createSouthPanel() {
178 		final JPanel southPanel = new JPanel();
179 		southPanel.setLayout(new BoxLayout(southPanel, BoxLayout.Y_AXIS));
180 
181 		addTextToPanel(southPanel, "Built by " + buildInfo.getProperty("git.build.user.name") + " using <a href='http://maven.apache.org/'>Maven " + buildInfo.getProperty("maven.version") + LINK_CLOSE);
182 		addTextToPanel(southPanel, "Built on " + buildInfo.getProperty("os.name") + " " + buildInfo.getProperty("os.arch") + " " + buildInfo.getProperty("os.version"));
183 		addTextToPanel(southPanel, "Built using Java " + buildInfo.getProperty("java.version") + " on a " + buildInfo.getProperty("java.vm.version") + " VM");
184 		addTextToPanel(southPanel, "Build date and time: " + buildInfo.getProperty("git.build.time"));
185 
186 		southPanel.add(Box.createVerticalStrut(SPACER_HEIGHT));
187 
188 		final Properties sys = System.getProperties();
189 		addTextToPanel(southPanel, "Running on " + sys.getProperty("os.name") + " " + sys.getProperty("os.arch") + " " + sys.getProperty("os.version"));
190 		addTextToPanel(southPanel, "Running using Java " + sys.getProperty("java.version") + " on a " + sys.getProperty("java.vm.version") + " VM");
191 		final DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy @ HH:mm:ss z", Locale.ENGLISH);
192 		addTextToPanel(southPanel, "Current date and time: " + dateFormat.format(new Date()));
193 
194 		southPanel.add(Box.createVerticalStrut(SPACER_HEIGHT));
195 
196 		final Runtime ourRuntime = Runtime.getRuntime();
197 		final double limitMax = ourRuntime.maxMemory() / bytesPerMegaByte;
198 		final double currentMax = ourRuntime.totalMemory() / bytesPerMegaByte;
199 		final double currentFree = ourRuntime.freeMemory() / bytesPerMegaByte;
200 		final double futureFree = limitMax - currentMax;
201 		final double limitFree = currentFree + futureFree;
202 		final double used = currentMax - currentFree;
203 
204 		addTextToPanel(southPanel, "Memory usage details: "
205 				+ "Used: "           // How much memory the application is actually using
206 				+ MathUtils.roundDecimalPlaces(used, 2)
207 				+ "MB");
208 		addTextToPanel(southPanel, "Current free/max: " // Instantaneous memory that the JVM can put new objects in
209 				+ MathUtils.roundDecimalPlaces(currentFree, 2)
210 				+ "MB/"  // Current maximum memory that the JVM exposes for use
211 				+ MathUtils.roundDecimalPlaces(currentMax, 2)
212 				+ "MB");
213 		addTextToPanel(southPanel, "Hard limit free/max: "   // Absolute maximum memory that the JVM can put new objects in
214 				+ MathUtils.roundDecimalPlaces(limitFree, 2)
215 				+ "MB/"    // Absolute total maximum memory that the JVM can allocate for use
216 				+ MathUtils.roundDecimalPlaces(limitMax, 2)
217 				+ "MB");
218 
219 		return southPanel;
220 	}
221 
222 	private void addTextToPanel(final JPanel panel, final String text) {
223 		final Font font = UIManager.getFont("Label.font");
224 		final StringBuilder bodyRule = new StringBuilder("body { font-family: ");
225 		bodyRule.append(font.getFamily());
226 		bodyRule.append("; font-size: ");
227 		bodyRule.append(font.getSize());
228 		bodyRule.append("pt; text-align: center;}");
229 		final JEditorPane newPane = new JEditorPane("text/html", text);
230 		((javax.swing.text.html.HTMLDocument) newPane.getDocument()).getStyleSheet().addRule(bodyRule.toString());
231 		newPane.addHyperlinkListener(HLL);
232 		newPane.setEditable(false);
233 		newPane.setBorder(null);
234 		newPane.setOpaque(false);
235 		newPane.setAlignmentX(Component.CENTER_ALIGNMENT);
236 
237 		panel.add(newPane);
238 	}
239 
240 	private ImageIcon createImageIcon(final String path, final String description) {
241 		final java.net.URL imgURL = OpenLogViewer.class.getResource(path);
242 		if (imgURL != null) {
243 			return new ImageIcon(imgURL, description);
244 		} else {
245 			System.err.println("Couldn't find file: " + path);
246 			return null;
247 		}
248 	}
249 
250 	// If closing, free resources
251 	@Override
252 	public void dispose() {
253 		synchronized (HLL) {
254 			aboutFrame = null;
255 			super.dispose();
256 		}
257 	}
258 }