/**
* Copyright (C) 2015 Valkyrie RCP
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.valkyriercp.application.support;
import com.google.common.collect.Lists;
import org.springframework.core.io.Resource;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.valkyriercp.application.ApplicationDescriptor;
import org.valkyriercp.command.support.AbstractCommand;
import org.valkyriercp.component.HtmlPane;
import org.valkyriercp.dialog.ApplicationDialog;
import org.valkyriercp.dialog.CloseAction;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* An implementation of an about box in a dialog. The dialog contents contain a
* simple, fixed area at the top showing the information from the
* ApplicationDescriptor configured in the context. Below that is a scrolling
* (animated) panel that displays the contents of a specified file.
*
* @author Keith Donald
* @author Oliver Hutchison
*
* @see #setAboutTextPath(org.springframework.core.io.Resource)
* @see org.valkyriercp.application.ApplicationDescriptor
* @see org.valkyriercp.component.HtmlPane
*/
public class AboutBox {
private Resource aboutTextPath;
public AboutBox() {
}
/**
* @param path
*/
public void setAboutTextPath(Resource path) {
this.aboutTextPath = path;
}
/**
* @return the aboutTextPath
*/
public Resource getAboutTextPath() {
return aboutTextPath;
}
public void display(Window parent) {
AboutDialog aboutMainDialog = new AboutDialog();
aboutMainDialog.setParentComponent(parent);
aboutMainDialog.setLocationRelativeTo(parent);
aboutMainDialog.showDialog();
}
protected class AboutDialog extends ApplicationDialog {
private HtmlScroller scroller;
public AboutDialog() {
setTitle("About " + getApplicationConfig().application().getName());
setResizable(false);
setCloseAction(CloseAction.DISPOSE);
}
protected void addDialogComponents() {
JComponent dialogContentPane = createDialogContentPane();
getDialogContentPane().add(dialogContentPane);
getDialogContentPane().add(createButtonBar(), BorderLayout.SOUTH);
}
/**
* Create the control that shows the application descriptor data (title,
* caption, description, version, and build id).
*
* @return control
*/
protected JComponent createApplicationDescriptorComponent() {
// Build the application descriptor data, if available
JTextArea txtDescriptor = getApplicationConfig().componentFactory()
.createTextAreaAsLabel();
txtDescriptor
.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0));
ApplicationDescriptor appDesc = getApplicationConfig()
.applicationDescriptor();
if (appDesc != null) {
String displayName = appDesc.getDisplayName();
String caption = appDesc.getCaption();
String description = appDesc.getDescription();
String version = appDesc.getVersion();
String buildId = appDesc.getBuildId();
StringBuffer sb = new StringBuffer();
if (StringUtils.hasText(displayName)) {
sb.append(displayName).append("\n");
}
if (StringUtils.hasText(caption)) {
sb.append(caption).append("\n\n");
}
if (StringUtils.hasText(description)) {
sb.append(description).append("\n\n");
}
if (StringUtils.hasText(version)) {
sb.append(
getApplicationConfig().messageResolver().getMessage(
"aboutBox.version.label")).append(": ")
.append(version).append("\n");
}
if (StringUtils.hasText(buildId)) {
sb.append(
getApplicationConfig().messageResolver().getMessage(
"aboutBox.buildId.label")).append(": ")
.append(buildId).append("\n");
}
txtDescriptor.setText(sb.toString());
}
return txtDescriptor;
}
/**
* Construct the main dialog pane.
*
* @return Constructed component
*/
protected JComponent createDialogContentPane() {
JPanel dialogPanel = new JPanel(new BorderLayout());
// Add in the application descriptor data, if available
dialogPanel.add(createApplicationDescriptorComponent(),
BorderLayout.NORTH);
// If a text file resource has been specified, then construct the
// scroller to show it.
if (aboutTextPath != null) {
try {
scroller = new HtmlScroller(false, 2000, 15, 10);
String text = FileCopyUtils
.copyToString(new BufferedReader(
new InputStreamReader(aboutTextPath
.getInputStream())));
scroller.setHtml(text);
} catch (IOException e) {
final IllegalStateException exp = new IllegalStateException(
"About text not accessible: " + e.getMessage());
exp.setStackTrace(e.getStackTrace());
throw exp;
}
dialogPanel.add(scroller);
dialogPanel.setPreferredSize(new Dimension(scroller
.getPreferredSize().width, 300));
} else {
// Set the preferred size
dialogPanel.setPreferredSize(new Dimension(300, 200));
}
dialogPanel.add(new JSeparator(), BorderLayout.SOUTH);
return dialogPanel;
}
protected void onAboutToShow() {
if (scroller != null) {
try {
String text = FileCopyUtils
.copyToString(new BufferedReader(
new InputStreamReader(aboutTextPath
.getInputStream())));
scroller.setHtml(text);
} catch (IOException e) {
final IllegalStateException exp = new IllegalStateException(
"About text not accessible: " + e.getMessage());
exp.setStackTrace(e.getStackTrace());
throw exp;
}
scroller.reset();
scroller.startScrolling();
}
}
protected boolean onFinish() {
if (scroller != null) {
scroller.pauseScrolling();
}
return true;
}
protected java.util.List<AbstractCommand> getCommandGroupMembers() {
return Lists.<AbstractCommand> newArrayList(getFinishCommand());
}
/**
* Get the scrolling HTML panel.
*
* @return scroller
*/
protected HtmlScroller getHtmlScroller() {
return scroller;
}
}
/**
* A panel that scrolls the content of a HTML document.
*
* @author Oliver Hutchison
*/
protected static class HtmlScroller extends JViewport implements
HyperlinkListener {
private HtmlPane htmlPane;
private Timer timer;
private int initalDelay;
private double incY = 0;
private double currentY = 0;
private double currentX = 0;
/**
* Created a new HtmlScroller.
*
* @param antiAlias
* antialias the rendered HTML
* @param initalDelay
* inital delay after which scrolling begins
* @param speedPixSec
* scoll speed in pixels per second
* @param fps
* number of updates per second
*/
public HtmlScroller(boolean antiAlias, int initalDelay,
int speedPixSec, int fps) {
this.initalDelay = initalDelay;
incY = (double) speedPixSec / (double) fps;
htmlPane = new HtmlPane();
htmlPane.setAntiAlias(antiAlias);
htmlPane.addHyperlinkListener(this);
setView(htmlPane);
timer = new Timer(1000 / fps, new ActionListener() {
public void actionPerformed(ActionEvent e) {
int maxY = htmlPane.getHeight() - getHeight();
currentY = Math.max(0, Math.min(currentY + incY, maxY));
if (currentY <= 0 || currentY == maxY) {
pauseScrolling();
}
setViewPositionInternal(new Point((int) currentX,
(int) currentY));
}
});
reset();
}
/**
* Sets the HTML that will be rendered by this component.
*/
public void setHtml(String html) {
htmlPane.setText(html);
setPreferredSize(htmlPane.getPreferredSize());
}
/**
* Resets this component to its inital state.
*/
public final void reset() {
currentX = 0;
currentY = 0;
timer.setInitialDelay(initalDelay);
setViewPositionInternal(new Point((int) currentX, (int) currentY));
}
/**
* Starts the scoller
*/
public void startScrolling() {
timer.start();
}
/**
* Pauses the scoller.
*/
public void pauseScrolling() {
timer.stop();
timer.setInitialDelay(0);
}
public void setViewPosition(Point p) {
// ignore calls that are not internal
}
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType().equals(HyperlinkEvent.EventType.ENTERED)) {
enteredLink();
} else if (e.getEventType().equals(HyperlinkEvent.EventType.EXITED)) {
exitedLink();
}
}
private void setViewPositionInternal(Point p) {
super.setViewPosition(p);
}
private void enteredLink() {
pauseScrolling();
}
private void exitedLink() {
startScrolling();
}
}
}