summaryrefslogtreecommitdiff
path: root/BKUCommonGUI/src/main/java/at/gv/egiz/bku
diff options
context:
space:
mode:
Diffstat (limited to 'BKUCommonGUI/src/main/java/at/gv/egiz/bku')
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/AbstractHelpListener.java103
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java176
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java1665
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUIcons.java57
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/DefaultHelpListener.java81
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataTableModel.java63
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpKeyListener.java46
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpLinkFocusManager.java138
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpMouseListener.java54
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpViewer.java218
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java54
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/ImagePanel.java50
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java74
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java360
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusFocusListener.java38
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusListener.java44
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedHTMLEditorKit.java49
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedImageView.java67
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProvider.java40
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProviderException.java29
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java65
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java53
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java121
23 files changed, 3645 insertions, 0 deletions
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/AbstractHelpListener.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/AbstractHelpListener.java
new file mode 100644
index 00000000..6fd1ffea
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/AbstractHelpListener.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Implement the showDocument(URL) method to provide an actual HelpListener.
+ * This class does not keep a GUI reference and subclasses should not interfere with the GUI.
+ * Therefore, any errors occurring in showDocument() should be handled/displayed within
+ * showDocument() and exceptions thrown from showDocument() are logged, not displayed in the GUI.
+ * <br/>
+ * The help URL is build as [baseURL]/[locale]/[helpTopic].html
+ * (note that no session information is contained).
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public abstract class AbstractHelpListener implements ActionListener {
+
+ /**
+ * any locale not in the list will be mapped to 'de'
+ */
+ public static final String[] SUPPORTED_LANGUAGES = new String[] { "de" };
+
+ protected final static Log log = LogFactory.getLog(AbstractHelpListener.class);
+ protected URL baseURL;
+ protected Locale locale;
+ protected ResourceBundle messages;
+
+ public AbstractHelpListener(URL baseURL, Locale locale) {
+ if (baseURL == null || "".equals(baseURL.toString())) {
+ throw new RuntimeException("no help URL provided");
+ }
+ this.baseURL = baseURL;
+ this.locale = locale;
+ if (locale != null) {
+ messages = ResourceBundle.getBundle(BKUGUIFacade.MESSAGES_BUNDLE, locale);
+ } else {
+ messages = ResourceBundle.getBundle(BKUGUIFacade.MESSAGES_BUNDLE);
+ }
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ log.debug("received help action: " + e.getActionCommand());
+ URL helpURL = constructHelpURL(baseURL, e.getActionCommand());
+ try {
+ showDocument(helpURL, e.getActionCommand());
+ } catch (Exception ex) {
+ log.error("could not display help document " + helpURL + ": " + ex.getMessage());
+ }
+ }
+
+ private URL constructHelpURL(URL baseURL, String helpTopic) {
+ URL helpURL = baseURL;
+ log.trace("constructing help URL: " + helpURL);
+ try {
+ // not localized for now
+ //check if locale.getLanguage() supported and add default if not
+// if (locale != null) {
+// helpURL = new URL(helpURL, locale.toString() + "/");
+// log.trace("constructing help URL: " + helpURL);
+// }
+ if (helpTopic != null && !"".equals(helpTopic)) {
+ helpURL = new URL(helpURL, "de/" + helpTopic + ".html");
+ log.trace("constructing help URL: " + helpURL);
+ }
+ } catch (MalformedURLException ex) {
+ log.error("Failed to construct help URL for help item " + helpTopic + ": " + ex.getMessage());
+ }
+ return helpURL;
+ }
+
+ /**
+ * Errors from HelpListeners should not (are not) displayed in the applet,
+ * but should rather be in the HelpListener specific way.
+ * Therefore, implementations SHOULD NOT throw exceptions (these are only logged).
+ * @param helpDocument
+ * @throws java.lang.Exception
+ */
+ public abstract void showDocument(URL helpDocument, String helpTopic) throws Exception;
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java
new file mode 100644
index 00000000..1e23c64c
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+ import at.gv.egiz.stal.HashDataInput;
+import at.gv.egiz.smcc.PINSpec;
+import java.awt.Color;
+import java.awt.event.ActionListener;
+import java.util.List;
+import java.util.Locale;
+
+public interface BKUGUIFacade {
+
+ public static final String ERR_UNKNOWN_WITH_PARAM = "error.unknown.param";
+ public static final String ERR_UNKNOWN = "error.unknown";
+ public static final String ERR_SERVICE_UNREACHABLE = "error.ws.unreachable";
+ public static final String ERR_NO_PCSC = "error.pcsc";
+ public static final String ERR_NO_CARDTERMINAL = "error.cardterminal";
+ public static final String ERR_NO_HASHDATA = "error.no.hashdata";
+ public static final String ERR_DISPLAY_HASHDATA = "error.display.hashdata";
+ public static final String ERR_WRITE_HASHDATA = "error.write.hashdata";
+ public static final String ERR_INVALID_HASH = "error.invalid.hash";
+ public static final String ERR_CARD_LOCKED = "error.card.locked";
+ public static final String ERR_CARD_NOTACTIVATED = "error.card.notactivated";
+ public static final String ERR_PIN_TIMEOUT = "error.pin.timeout";
+ public static final String ERR_VIEWER = "error.viewer";
+ public static final String ERR_EXTERNAL_LINK = "error.external.link";
+ public static final String ERR_CONFIG = "error.config";
+
+ /** no leading slash for Messages resource, leading slash for images */
+ public static final String MESSAGES_BUNDLE = "at/gv/egiz/bku/gui/Messages";
+ public static final String DEFAULT_BACKGROUND = "/at/gv/egiz/bku/gui/chip32.png";
+ public static final String DEFAULT_ICON = "/at/gv/egiz/bku/gui/chiperling105.png";
+ public static final String HELP_IMG = "/at/gv/egiz/bku/gui/help.png";
+ public static final String HELP_IMG_FOCUS = "/at/gv/egiz/bku/gui/help.png"; //help_focus.png";
+ public static final String HASHDATA_FONT = "Monospaced";
+ public static final Color ERROR_COLOR = Color.RED;
+ public static final Color HYPERLINK_COLOR = Color.BLUE;
+ public static final String TITLE_WELCOME = "title.welcome";
+ public static final String TITLE_INSERTCARD = "title.insertcard";
+ public static final String TITLE_CARD_NOT_SUPPORTED = "title.cardnotsupported";
+ public static final String TITLE_VERIFY_PIN = "title.verify.pin";
+ public static final String TITLE_SIGN = "title.sign";
+ public static final String TITLE_VERIFY_PINPAD = "title.verify.pinpad";
+ public static final String TITLE_ERROR = "title.error";
+ public static final String TITLE_WARNING = "title.warning";
+ public static final String TITLE_ENTRY_TIMEOUT = "title.entry.timeout";
+ public static final String TITLE_RETRY = "title.retry";
+ public static final String TITLE_WAIT = "title.wait";
+ public static final String TITLE_SIGNATURE_DATA = "title.signature.data";
+ public static final String WINDOWTITLE_SAVE = "windowtitle.save";
+ public static final String WINDOWTITLE_ERROR = "windowtitle.error";
+ public static final String WINDOWTITLE_SAVEDIR = "windowtitle.savedir";
+ public static final String WINDOWTITLE_OVERWRITE = "windowtitle.overwrite";
+ public static final String WINDOWTITLE_VIEWER = "windowtitle.viewer";
+ public static final String WINDOWTITLE_HELP = "windowtitle.help";
+
+ // removed message.* prefix to reuse keys as help keys
+ public static final String MESSAGE_WELCOME = "welcome";
+ public static final String MESSAGE_WAIT = "wait";
+ public static final String MESSAGE_INSERTCARD = "insertcard";
+ public static final String MESSAGE_CARD_NOT_SUPPORTED = "cardnotsupported";
+ public static final String MESSAGE_ENTERPIN = "enterpin";
+ public static final String MESSAGE_ENTERPIN_PINPAD = "enterpin.pinpad";
+ public static final String MESSAGE_ENTERPIN_PINPAD_DIRECT = "enterpin.pinpad.direct";
+ public static final String MESSAGE_HASHDATALINK = "hashdatalink";
+ public static final String MESSAGE_HASHDATALINK_TINY = "hashdatalink.tiny";
+ public static final String MESSAGE_HASHDATALINK_FOCUS = "hashdatalink.focus";
+ public static final String MESSAGE_HASHDATALINK_TINY_FOCUS = "hashdatalink.tiny.focus";
+ public static final String MESSAGE_HASHDATALIST = "hashdatalist";
+ public static final String MESSAGE_HASHDATA_VIEWER = "hashdata.viewer";
+ public static final String MESSAGE_UNSUPPORTED_MIMETYPE = "unsupported.mimetype";
+ public static final String MESSAGE_RETRIES = "retries";
+ public static final String MESSAGE_LAST_RETRY = "retries.last";
+ public static final String MESSAGE_RETRIES_PINPAD = "retries.pinpad";
+ public static final String MESSAGE_LAST_RETRY_PINPAD = "retries.pinpad.last";
+ public static final String MESSAGE_OVERWRITE = "overwrite";
+ public static final String MESSAGE_HELP = "help";
+
+ public static final String WARNING_XHTML = "warning.xhtml";
+ public static final String LABEL_PIN = "label.pin";
+ public static final String LABEL_PINSIZE = "label.pinsize";
+ public static final String HELP_WELCOME = "help.welcome";
+ public static final String HELP_WAIT = "help.wait";
+ public static final String HELP_CARDNOTSUPPORTED = "help.cardnotsupported";
+ public static final String HELP_INSERTCARD = "help.insertcard";
+ public static final String HELP_VERIFY_PIN = "help.cardpin";
+ public static final String HELP_SIGNPIN = "help.signpin";
+ public static final String HELP_PINPAD = "help.pinpad";
+ public static final String HELP_RETRY = "help.retry";
+ public static final String HELP_HASHDATA = "help.hashdata";
+ public static final String HELP_HASHDATALIST = "help.hashdatalist";
+ public static final String HELP_HASHDATAVIEWER = "help.hashdataviewer";
+ public static final String BUTTON_OK = "button.ok";
+ public static final String BUTTON_CANCEL = "button.cancel";
+ public static final String BUTTON_BACK = "button.back";
+ public static final String BUTTON_SIGN = "button.sign";
+ public static final String BUTTON_SAVE = "button.save";
+ public static final String BUTTON_CLOSE = "button.close";
+ public static final String SAVE_HASHDATAINPUT_PREFIX = "save.hashdatainput.prefix";
+ public static final String ALT_HELP = "alt.help";
+
+ public void showEnterPINDirect(PINSpec spec, int retries);
+
+ public void showEnterPIN(PINSpec spec, int retries);
+
+ public void showSignatureDataDialog(PINSpec spec, ActionListener listener, String string, ActionListener aThis0, String string0, ActionListener aThis1, String string1);
+
+ public void correctionButtonPressed();
+
+ public void allKeysCleared();
+
+ public void validKeyPressed();
+
+ public enum Style { tiny, simple, advanced };
+
+ /**
+ * BKUWorker needs to init signature card with locale
+ * @return
+ */
+ public Locale getLocale();
+
+ public void showVerifyPINDialog(PINSpec pinSpec, int numRetries,
+ ActionListener okListener, String okCommand,
+ ActionListener cancelListener, String cancelCommand);
+
+ public void showSignaturePINDialog(PINSpec pinSpec, int numRetries,
+ ActionListener signListener, String signCommand,
+ ActionListener cancelListener, String cancelCommand,
+ ActionListener viewerListener, String viewerCommand);
+
+ public char[] getPin();
+
+ /**
+ *
+ * @param dataToBeSigned
+ * @param backListener if list of references hides pin dialog, backListener
+ * receives an action when user hits 'back' button (i.e. whenever the pin-dialog
+ * needs to be re-paint)
+ * @param backCommand
+ */
+ public void showSecureViewer(List<HashDataInput> dataToBeSigned,
+ ActionListener backListener, String backCommand);
+
+ public void showErrorDialog(String errorMsgKey, Object[] errorMsgParams,
+ ActionListener okListener, String okCommand);
+
+ public void showErrorDialog(String errorMsgKey, Object[] errorMsgParams);
+
+ public void showMessageDialog(String titleKey,
+ String msgKey, Object[] msgParams,
+ String buttonKey,
+ ActionListener okListener, String okCommand);
+
+ public void showMessageDialog(String titleKey,
+ String msgKey, Object[] msgParams);
+
+ public void showMessageDialog(String titleKey,
+ String msgKey);
+
+ public void getFocusFromBrowser();
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java
new file mode 100644
index 00000000..e005836c
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java
@@ -0,0 +1,1665 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import at.gv.egiz.bku.gui.viewer.FontProviderException;
+import at.gv.egiz.bku.gui.viewer.FontProvider;
+import at.gv.egiz.bku.gui.viewer.SecureViewerSaveDialog;
+import at.gv.egiz.smcc.PINSpec;
+import at.gv.egiz.stal.HashDataInput;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Font;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.GroupLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.LayoutStyle;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+
+
+/**
+ *
+ * @author clemens
+ */
+public class BKUGUIImpl implements BKUGUIFacade {
+
+ protected static final Log log = LogFactory.getLog(BKUGUIImpl.class);
+
+ protected enum PinLabelPosition {
+ LEFT, ABOVE
+ }
+
+ protected HelpMouseListener helpMouseListener;
+ protected HelpKeyListener helpKeyListener;
+ protected SwitchFocusFocusListener switchFocusKeyListener;
+ protected SecureViewerDialog secureViewer;
+ protected FontProvider fontProvider;
+
+ protected Container contentPane;
+ protected ResourceBundle messages;
+ /** left and right side main panels */
+ protected JPanel iconPanel;
+ protected JPanel contentPanel;
+ /** right side content panels and layouts */
+ protected JPanel headerPanel;
+ protected JPanel mainPanel;
+ protected JPanel buttonPanel;
+ /** right side fixed labels */
+ protected JLabel titleLabel;
+ protected JLabel helpLabel;
+ protected JLabel switchFocusDummyLabel;
+ /** remember the pinfield to return to worker */
+ protected JPasswordField pinField;
+ protected Document pinpadPIN;
+
+ protected int buttonSize;
+
+ /** gui style config (default 'simple') */
+ protected boolean renderHeaderPanel = false;
+ protected boolean renderIconPanel = false;
+ protected boolean renderCancelButton = false;
+ protected boolean shortText = false;
+ protected PinLabelPosition pinLabelPos = PinLabelPosition.LEFT;
+ protected boolean renderRefId = false;
+
+ /**
+ * set contentPane
+ * init message bundle
+ * configure the style
+ * register the help listener
+ * create GUI (on event-dispatching thread)
+ *
+ * @param contentPane
+ * @param locale
+ * @param guiStyle
+ * @param background
+ * @param helpListener
+ */
+ public BKUGUIImpl(Container contentPane,
+ Locale locale,
+ Style guiStyle,
+ URL background,
+ FontProvider fontProvider,
+ ActionListener helpListener,
+ SwitchFocusListener switchFocusListener) {
+ this.contentPane = contentPane;
+
+ loadMessageBundle(locale);
+
+ if (guiStyle == Style.advanced) {
+ renderHeaderPanel = true;
+ renderIconPanel = false;
+ renderCancelButton = true;
+ renderRefId = true;
+ } else if (guiStyle == Style.tiny) {
+ shortText = true;
+ pinLabelPos = PinLabelPosition.ABOVE;
+ }
+
+ // ensure that buttons can be fired with enter key too
+ UIManager.put("Button.defaultButtonFollowsFocus", Boolean.TRUE);
+
+ registerHelpListener(helpListener);
+
+ registerSwitchFocusListener(switchFocusListener);
+
+ this.fontProvider = fontProvider;
+ createGUI(background);
+ }
+
+ private void createGUI(final URL background) {
+
+ try {
+
+ log.debug("scheduling gui initialization");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("[" + Thread.currentThread().getName() + "] initializing gui");
+
+ if (renderIconPanel) {
+ initIconPanel(background);
+ initContentPanel(null);
+ } else {
+ initContentPanel(background);
+ }
+
+ GroupLayout layout = new GroupLayout(contentPane);
+ contentPane.setLayout(layout);
+
+ if (renderIconPanel) {
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(iconPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addContainerGap());
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(iconPanel, GroupLayout.Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(contentPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap());
+ } else {
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ // left border
+ .addContainerGap()
+ .addComponent(contentPanel)
+ .addContainerGap());
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(contentPanel)
+ .addContainerGap());
+ }
+ }
+ });
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed to init GUI: " + ex.getMessage());
+ }
+ }
+
+ protected void initIconPanel(URL background) {
+ if (background == null) {
+ background = getClass().getResource(DEFAULT_ICON);
+ }
+ if ("file".equals(background.getProtocol())) {
+ log.warn("file:// background images not permitted: " + background +
+ ", loading default background");
+ background = getClass().getResource(DEFAULT_ICON);
+ }
+ log.debug("loading icon panel background " + background);
+
+ iconPanel = new JPanel();
+ JLabel iconLabel = new JLabel();
+ iconLabel.setIcon(new ImageIcon(background));
+
+ GroupLayout iconPanelLayout = new GroupLayout(iconPanel);
+ iconPanel.setLayout(iconPanelLayout);
+ iconPanelLayout.setHorizontalGroup(
+ iconPanelLayout.createSequentialGroup()
+ .addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
+ iconPanelLayout.setVerticalGroup(
+ iconPanelLayout.createSequentialGroup()
+ .addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
+ }
+
+ protected void initContentPanel(URL background) {
+
+ if (background == null) {
+ log.debug("no background image set");
+// contentPanel = new ImagePanel(getClass().getResource(DEFAULT_BACKGROUND));
+ contentPanel = new JPanel();
+ } else if ("file".equals(background.getProtocol())) {
+ log.warn("file:// background images not permitted: " + background);
+ contentPanel = new JPanel();
+ } else {
+ log.debug("loading background " + background);
+ contentPanel = new ImagePanel(background);
+ }
+ contentPanel.setOpaque(false);
+ mainPanel = new JPanel();
+ mainPanel.setOpaque(false);
+ buttonPanel = new JPanel();
+ buttonPanel.setOpaque(false);
+
+ helpLabel = new JLabel();
+ helpLabel.setIcon(new ImageIcon(getClass().getResource(HELP_IMG)));
+ helpLabel.getAccessibleContext().setAccessibleName(getMessage(ALT_HELP));
+ helpLabel.setFocusable(true);
+ helpLabel.addMouseListener(helpMouseListener);
+ helpLabel.addKeyListener(helpKeyListener);
+ helpLabel.addFocusListener(new FocusAdapter() {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+
+ helpLabel.setIcon(new ImageIcon(getClass().getResource(HELP_IMG_FOCUS)));
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+
+ helpLabel.setIcon(new ImageIcon(getClass().getResource(HELP_IMG)));
+ }
+
+
+ });
+ helpLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+
+ switchFocusDummyLabel = new JLabel();
+ switchFocusDummyLabel.setText("");
+ switchFocusDummyLabel.setFocusable(true);
+ switchFocusDummyLabel.addFocusListener(switchFocusKeyListener);
+
+ buttonSize = initButtonSize();
+
+ if (renderHeaderPanel) {
+ headerPanel = new JPanel();
+ headerPanel.setOpaque(false);
+
+ titleLabel = new JLabel();
+ titleLabel.setFont(titleLabel.getFont().deriveFont(titleLabel.getFont().getStyle() |
+ java.awt.Font.BOLD, titleLabel.getFont().getSize() + 2));
+
+ GroupLayout headerPanelLayout = new GroupLayout(headerPanel);
+ headerPanel.setLayout(headerPanelLayout);
+
+ headerPanelLayout.setHorizontalGroup(
+ headerPanelLayout.createSequentialGroup()
+ .addComponent(titleLabel, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ );
+ headerPanelLayout.setVerticalGroup(
+ headerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(titleLabel, 0, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ );
+ }
+
+ GroupLayout contentPanelLayout = new GroupLayout(contentPanel);
+ contentPanel.setLayout(contentPanelLayout);
+
+ // align header, main and button to the right
+ GroupLayout.ParallelGroup horizontalContent =
+ contentPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING); //LEADING);
+ GroupLayout.SequentialGroup verticalContent =
+ contentPanelLayout.createSequentialGroup();
+
+ if (renderHeaderPanel) {
+ horizontalContent
+ .addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
+ verticalContent
+ .addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
+
+ }
+ horizontalContent
+ .addComponent(mainPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE); //Short.MAX_VALUE);
+ verticalContent
+ .addComponent(mainPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+
+ contentPanelLayout.setHorizontalGroup(horizontalContent); //Outer);
+ contentPanelLayout.setVerticalGroup(verticalContent);
+ }
+
+ /**
+ * BKUWorker inits signaturecard with locale
+ * @return
+ */
+ @Override
+ public Locale getLocale() {
+ return messages.getLocale();
+ }
+
+ /**
+ * to be overridden by subclasses providing additional resource messages
+ * @param key
+ * @return
+ */
+ protected String getMessage(String key) {
+ return messages.getString(key);
+ }
+
+ /**
+ * to be overridden by subclasses providing additional resource messages
+ * @param key
+ * @return
+ */
+ protected boolean hasMessage(String key) {
+ return messages.containsKey(key);
+ }
+
+ @Override
+ public void showVerifyPINDialog(final PINSpec pinSpec, final int numRetries,
+ final ActionListener okListener, final String okCommand,
+ final ActionListener cancelListener, final String cancelCommand) {
+
+ log.debug("scheduling verify pin dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("[" + Thread.currentThread().getName() + "] show verify pin dialog");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ if (numRetries < 0) {
+ String verifyTitle = getMessage(TITLE_VERIFY_PIN);
+ titleLabel.setText(MessageFormat.format(verifyTitle, new Object[]{pinSpec.getLocalizedName()}));
+ } else {
+ titleLabel.setText(getMessage(TITLE_RETRY));
+ }
+ }
+
+ JButton okButton = new JButton();
+ okButton.setFont(okButton.getFont().deriveFont(okButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ okButton.setText(getMessage(BUTTON_OK));
+ okButton.setEnabled(pinSpec.getMinLength() <= 0);
+ okButton.setActionCommand(okCommand);
+ okButton.addActionListener(okListener);
+
+ JLabel cardPinLabel = new JLabel();
+ cardPinLabel.setFont(cardPinLabel.getFont().deriveFont(cardPinLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ String pinLabel = getMessage(LABEL_PIN);
+ cardPinLabel.setText(MessageFormat.format(pinLabel, new Object[]{pinSpec.getLocalizedName()}));
+
+ pinField = new JPasswordField();
+ pinField.setText("");
+ pinField.setDocument(new PINDocument(pinSpec.getMinLength(), pinSpec.getMaxLength(), pinSpec.getRexepPattern(), okButton));
+ pinField.setActionCommand(okCommand);
+ pinField.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (pinField.getPassword().length >= pinSpec.getMinLength()) {
+ okListener.actionPerformed(e);
+ }
+ }
+ });
+
+ JLabel infoLabel = new JLabel();
+ if (numRetries < 0) {
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ String infoPattern = getMessage(MESSAGE_ENTERPIN);
+ if (shortText) {
+ infoLabel.setText(MessageFormat.format(infoPattern, new Object[] {"PIN"}));
+ } else {
+ infoLabel.setText(MessageFormat.format(infoPattern, new Object[] {pinSpec.getLocalizedName()}));
+ }
+ helpMouseListener.setHelpTopic(HELP_VERIFY_PIN);
+ helpKeyListener.setHelpTopic(HELP_VERIFY_PIN);
+ } else {
+ String retryPattern;
+ if (numRetries < 2) {
+ retryPattern = getMessage(MESSAGE_LAST_RETRY);
+ } else {
+ retryPattern = getMessage(MESSAGE_RETRIES);
+ }
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() | java.awt.Font.BOLD));
+ infoLabel.setText(MessageFormat.format(retryPattern, new Object[]{String.valueOf(numRetries)}));
+ infoLabel.setForeground(ERROR_COLOR);
+ helpMouseListener.setHelpTopic(HELP_RETRY);
+ helpKeyListener.setHelpTopic(HELP_RETRY);
+ }
+
+ JLabel pinsizeLabel = new JLabel();
+ pinsizeLabel.setFont(pinsizeLabel.getFont().deriveFont(pinsizeLabel.getFont().getStyle() & ~java.awt.Font.BOLD, pinsizeLabel.getFont().getSize()-2));
+ pinsizeLabel.setText(MessageFormat.format(getMessage(LABEL_PINSIZE), pinSpec.getLocalizedLength()));
+
+ GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
+ mainPanel.setLayout(mainPanelLayout);
+
+ GroupLayout.SequentialGroup infoHorizontal = mainPanelLayout.createSequentialGroup()
+ .addComponent(infoLabel);
+ GroupLayout.ParallelGroup infoVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(infoLabel);
+
+ if (!renderHeaderPanel) {
+ infoHorizontal
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ infoVertical
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ }
+
+ // align pinfield and pinsize to the right
+ GroupLayout.ParallelGroup pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING);
+ GroupLayout.Group pinVertical;
+
+ if (pinLabelPos == PinLabelPosition.ABOVE) {
+ pinHorizontal
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(cardPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+ pinVertical = mainPanelLayout.createSequentialGroup()
+ .addComponent(cardPinLabel)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+ } else {
+ pinHorizontal
+ .addGroup(mainPanelLayout.createSequentialGroup()
+ .addComponent(cardPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+ pinVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(cardPinLabel)
+ .addComponent(pinField);
+ }
+
+ mainPanelLayout.setHorizontalGroup(
+ mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(infoHorizontal)
+ .addGroup(pinHorizontal));
+
+ mainPanelLayout.setVerticalGroup(
+ mainPanelLayout.createSequentialGroup()
+ .addGroup(infoVertical)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(pinVertical)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel));
+
+
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup()
+ .addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
+ GroupLayout.Group buttonVertical;
+
+ if (renderCancelButton) {
+ JButton cancelButton = new JButton();
+ cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ cancelButton.setText(getMessage(BUTTON_CANCEL));
+ cancelButton.setActionCommand(cancelCommand);
+ cancelButton.addActionListener(cancelListener);
+
+ buttonHorizontal
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
+ buttonVertical = buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(okButton)
+ .addComponent(cancelButton);
+ } else {
+ buttonVertical = buttonPanelLayout.createSequentialGroup()
+ .addComponent(okButton);
+ }
+
+ buttonPanelLayout.setHorizontalGroup(buttonHorizontal);
+ buttonPanelLayout.setVerticalGroup(buttonVertical);
+
+// pinField.requestFocusInWindow();
+// helpLabel.requestFocus();
+ pinField.requestFocus();
+ contentPanel.validate();
+
+ }
+ });
+ }
+
+ @Override
+ public void showEnterPINDirect(PINSpec pinSpec, int retries) {
+ if (retries < 0) {
+ showMessageDialog(TITLE_VERIFY_PINPAD, MESSAGE_ENTERPIN_PINPAD_DIRECT, new Object[] {
+ pinSpec.getLocalizedName(), pinSpec.getLocalizedLength() });
+ } else {
+ showMessageDialog(TITLE_RETRY, MESSAGE_RETRIES, new Object[]{String.valueOf(retries) });
+ }
+ }
+
+ @Override
+ public void showEnterPIN(final PINSpec pinSpec, final int retries) {
+ showEnterPIN(pinSpec, retries, TITLE_VERIFY_PINPAD, MESSAGE_ENTERPIN_PINPAD, null);
+ }
+
+ protected void showEnterPIN(final PINSpec pinSpec, final int retries, final String titleKey, final String messageKey, final Object[] messageParams) {
+ log.debug("scheduling pinpad dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("[" + Thread.currentThread().getName() + "] show pinpad dialog");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ if (retries < 0) {
+ titleLabel.setText(getMessage(titleKey));
+ } else {
+ titleLabel.setText(getMessage(TITLE_RETRY));
+ }
+ }
+
+ final JLabel infoLabel = new JLabel();
+ if (retries < 0) {
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ infoLabel.setText(MessageFormat.format(getMessage(messageKey), messageParams));
+ helpMouseListener.setHelpTopic(HELP_PINPAD);
+ helpKeyListener.setHelpTopic(HELP_PINPAD);
+ } else {
+ String retryPattern;
+ if (retries == 1) {
+ retryPattern = getMessage(MESSAGE_LAST_RETRY);
+ } else {
+ retryPattern = getMessage(MESSAGE_RETRIES);
+ }
+ infoLabel.setText(MessageFormat.format(retryPattern, new Object[]{String.valueOf(retries)}));
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() | java.awt.Font.BOLD));
+ infoLabel.setForeground(ERROR_COLOR);
+ helpMouseListener.setHelpTopic(HELP_RETRY);
+ helpKeyListener.setHelpTopic(HELP_RETRY);
+ }
+
+ JLabel pinLabel = new JLabel();
+ pinLabel.setFont(pinLabel.getFont().deriveFont(pinLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ String pinName = getMessage(LABEL_PIN);
+ pinLabel.setText(MessageFormat.format(pinName, new Object[]{pinSpec.getLocalizedName()}));
+
+ JPasswordField pinpadPINField = new JPasswordField();
+ pinpadPINField.setText("");
+ pinpadPINField.setEnabled(false);
+ pinpadPIN = pinpadPINField.getDocument();
+
+ JLabel pinsizeLabel = new JLabel();
+ pinsizeLabel.setFont(pinsizeLabel.getFont().deriveFont(pinsizeLabel.getFont().getStyle() & ~java.awt.Font.BOLD, pinsizeLabel.getFont().getSize()-2));
+ pinsizeLabel.setText(MessageFormat.format(getMessage(LABEL_PINSIZE), pinSpec.getLocalizedLength()));
+
+ GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
+ mainPanel.setLayout(mainPanelLayout);
+
+ GroupLayout.SequentialGroup infoHorizontal = mainPanelLayout.createSequentialGroup()
+ .addComponent(infoLabel);
+ GroupLayout.ParallelGroup infoVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(infoLabel);
+
+ if (!renderHeaderPanel) {
+ infoHorizontal
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ infoVertical
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ }
+
+ // align pinfield and pinsize to the right
+ GroupLayout.Group pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING);
+ GroupLayout.SequentialGroup pinVertical = mainPanelLayout.createSequentialGroup();
+
+ if (pinLabelPos == PinLabelPosition.ABOVE) {
+ pinHorizontal
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(pinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(pinpadPINField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+ pinVertical
+ .addComponent(pinLabel)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinpadPINField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel);
+ } else { // PinLabelPosition.LEFT
+ pinHorizontal
+ .addGroup(mainPanelLayout.createSequentialGroup()
+ .addComponent(pinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinpadPINField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+ pinVertical
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(pinLabel)
+ .addComponent(pinpadPINField))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel);
+ }
+
+ mainPanelLayout.setHorizontalGroup(
+ mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(infoHorizontal)
+ .addGroup(pinHorizontal));
+
+ mainPanelLayout.setVerticalGroup(
+ mainPanelLayout.createSequentialGroup()
+ .addGroup(infoVertical)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(pinVertical));
+
+ contentPanel.validate();
+ }
+ });
+ }
+
+ @Override
+ public void showSignatureDataDialog(PINSpec spec,
+ final ActionListener enterPINListener, final String enterPINCommand,
+ final ActionListener cancelListener, final String cancelCommand,
+ final ActionListener hashdataListener, final String hashdataCommand) {
+
+ log.debug("scheduling signature-data dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("[" + Thread.currentThread().getName() + "] show signature-data dialog");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ titleLabel.setText(getMessage(TITLE_SIGNATURE_DATA));
+ }
+
+ final JLabel infoLabel = new JLabel();
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK));
+ }
+ infoLabel.setFocusable(true);
+ infoLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ infoLabel.setForeground(HYPERLINK_COLOR);
+ infoLabel.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent me) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, hashdataCommand);
+ hashdataListener.actionPerformed(e);
+ }
+ });
+
+ infoLabel.addKeyListener(new KeyAdapter() {
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+
+ if(e.getKeyCode() == KeyEvent.VK_ENTER) {
+ ActionEvent e1 = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, hashdataCommand);
+ hashdataListener.actionPerformed(e1);
+ }
+ }
+
+ });
+
+ infoLabel.addFocusListener(new FocusAdapter() {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY_FOCUS));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_FOCUS));
+ }
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK));
+ }
+
+ }
+
+ });
+
+ helpMouseListener.setHelpTopic(HELP_SIGNPIN);
+ helpKeyListener.setHelpTopic(HELP_SIGNPIN);
+
+ //TODO message panel
+
+// String msgPattern = getMessage(MESSAGE_ENTERPIN_PINPAD);
+// String msg = MessageFormat.format(msgPattern, new Object[] {
+// pinSpec.getLocalizedName(), pinSpec.getLocalizedLength() });
+//
+// JLabel msgLabel = new JLabel();
+// msgLabel.setFont(msgLabel.getFont().deriveFont(msgLabel.getFont().getStyle() & ~Font.BOLD));
+// msgLabel.setText(msg);
+
+ GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
+ mainPanel.setLayout(mainPanelLayout);
+
+ GroupLayout.SequentialGroup infoHorizontal = mainPanelLayout.createSequentialGroup()
+ .addComponent(infoLabel);
+ GroupLayout.ParallelGroup infoVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(infoLabel);
+
+ if (!renderHeaderPanel) {
+ infoHorizontal
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ infoVertical
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ }
+
+ mainPanelLayout.setHorizontalGroup(
+ infoHorizontal);
+// mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+// .addGroup(infoHorizontal)
+// .addComponent(msgLabel));
+
+ mainPanelLayout.setVerticalGroup(
+ infoVertical);
+// mainPanelLayout.createSequentialGroup()
+// .addGroup(infoVertical)
+// .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+// .addComponent(msgLabel));
+
+
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup();
+ GroupLayout.Group buttonVertical;
+
+ JButton enterPINButton = new JButton();
+ enterPINButton.setFont(enterPINButton.getFont().deriveFont(enterPINButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ enterPINButton.setText(getMessage(BUTTON_SIGN));
+ enterPINButton.setActionCommand(enterPINCommand);
+ enterPINButton.addActionListener(enterPINListener);
+
+ if (renderCancelButton) {
+ JButton cancelButton = new JButton();
+ cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ cancelButton.setText(getMessage(BUTTON_CANCEL));
+ cancelButton.setActionCommand(cancelCommand);
+ cancelButton.addActionListener(cancelListener);
+
+ buttonHorizontal
+ .addComponent(enterPINButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)
+ ;
+ buttonVertical = buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(enterPINButton)
+ .addComponent(cancelButton)
+ ;
+ } else {
+ buttonHorizontal
+ .addComponent(enterPINButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)
+ ;
+ buttonVertical = buttonPanelLayout.createSequentialGroup()
+ .addComponent(enterPINButton)
+ ;
+ }
+
+ buttonPanelLayout.setHorizontalGroup(buttonHorizontal);
+ buttonPanelLayout.setVerticalGroup(buttonVertical);
+
+ contentPanel.validate();
+ }
+ });
+ }
+
+ @Override
+ public void correctionButtonPressed() {
+ log.debug("[" + Thread.currentThread().getName() + "] correction button pressed");
+
+ if (pinpadPIN != null) {
+ try {
+ pinpadPIN.remove(0, 1);
+ } catch (BadLocationException ex) {
+ }
+ }
+ }
+
+ @Override
+ public void allKeysCleared() {
+ log.debug("[" + Thread.currentThread().getName() + "] all keys cleared");
+
+ if (pinpadPIN != null) {
+ try {
+ pinpadPIN.remove(0, pinpadPIN.getLength());
+ } catch (BadLocationException ex) {
+ }
+ }
+ }
+
+ @Override
+ public void validKeyPressed() {
+ log.debug("[" + Thread.currentThread().getName() + "] valid key pressed");
+
+ if (pinpadPIN != null) {
+ try {
+ pinpadPIN.insertString(0, "*", null);
+ } catch (BadLocationException ex) {
+ }
+ }
+ }
+
+ @Override
+ public void showSignaturePINDialog(final PINSpec pinSpec, final int numRetries,
+ final ActionListener signListener, final String signCommand,
+ final ActionListener cancelListener, final String cancelCommand,
+ final ActionListener hashdataListener, final String hashdataCommand) {
+
+ log.debug("scheduling signature-pin dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("[" + Thread.currentThread().getName() + "] show signature-pin dialog");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ if (numRetries < 0) {
+ titleLabel.setText(getMessage(TITLE_SIGN));
+ } else {
+ titleLabel.setText(getMessage(TITLE_RETRY));
+ }
+ }
+
+ final JLabel infoLabel = new JLabel();
+ if (numRetries < 0) {
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK));
+ }
+ infoLabel.setFocusable(true);
+ infoLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ infoLabel.setForeground(HYPERLINK_COLOR);
+ infoLabel.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent me) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, hashdataCommand);
+ hashdataListener.actionPerformed(e);
+ }
+ });
+
+ infoLabel.addKeyListener(new KeyAdapter() {
+
+ @Override
+ public void keyPressed(KeyEvent e) {
+
+ if(e.getKeyCode() == KeyEvent.VK_ENTER) {
+ ActionEvent e1 = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, hashdataCommand);
+ hashdataListener.actionPerformed(e1);
+ }
+ }
+
+ });
+
+ infoLabel.addFocusListener(new FocusAdapter() {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+
+
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY_FOCUS));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_FOCUS));
+ }
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+
+
+ if (shortText) {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK_TINY));
+ } else {
+ infoLabel.setText(getMessage(MESSAGE_HASHDATALINK));
+ }
+
+ }
+
+ });
+
+ helpMouseListener.setHelpTopic(HELP_SIGNPIN);
+ helpKeyListener.setHelpTopic(HELP_SIGNPIN);
+ } else {
+ String retryPattern;
+ if (numRetries < 2) {
+ retryPattern = getMessage(MESSAGE_LAST_RETRY);
+ } else {
+ retryPattern = getMessage(MESSAGE_RETRIES);
+ }
+ infoLabel.setFocusable(true);
+ infoLabel.setText(MessageFormat.format(retryPattern, new Object[]{String.valueOf(numRetries)}));
+ infoLabel.setFont(infoLabel.getFont().deriveFont(infoLabel.getFont().getStyle() | java.awt.Font.BOLD));
+ infoLabel.setForeground(ERROR_COLOR);
+ helpMouseListener.setHelpTopic(HELP_RETRY);
+ helpKeyListener.setHelpTopic(HELP_RETRY);
+ }
+
+ JButton signButton = new JButton();
+ signButton.setFont(signButton.getFont().deriveFont(signButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ signButton.setText(getMessage(BUTTON_SIGN));
+ signButton.setEnabled(pinSpec.getMinLength() <= 0);
+ signButton.setActionCommand(signCommand);
+ signButton.addActionListener(signListener);
+
+ JLabel signPinLabel = new JLabel();
+ signPinLabel.setFont(signPinLabel.getFont().deriveFont(signPinLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ String pinLabel = getMessage(LABEL_PIN);
+ signPinLabel.setText(MessageFormat.format(pinLabel, new Object[]{pinSpec.getLocalizedName()}));
+
+ pinField = new JPasswordField();
+ pinField.setText("");
+ pinField.setDocument(new PINDocument(pinSpec.getMinLength(), pinSpec.getMaxLength(), pinSpec.getRexepPattern(), signButton));
+ pinField.setActionCommand(signCommand);
+ pinField.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (pinField.getPassword().length >= pinSpec.getMinLength()) {
+ signListener.actionPerformed(e);
+ }
+ }
+ });
+
+
+ JLabel pinsizeLabel = new JLabel();
+ pinsizeLabel.setFont(pinsizeLabel.getFont().deriveFont(pinsizeLabel.getFont().getStyle() & ~java.awt.Font.BOLD, pinsizeLabel.getFont().getSize()-2));
+ pinsizeLabel.setText(MessageFormat.format(getMessage(LABEL_PINSIZE), pinSpec.getLocalizedLength()));
+
+ GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
+ mainPanel.setLayout(mainPanelLayout);
+
+ GroupLayout.SequentialGroup infoHorizontal = mainPanelLayout.createSequentialGroup()
+ .addComponent(infoLabel);
+ GroupLayout.ParallelGroup infoVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(infoLabel);
+
+ if (!renderHeaderPanel) {
+ infoHorizontal
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ infoVertical
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ }
+
+ // align pinfield and pinsize to the right
+ GroupLayout.Group pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING);
+ GroupLayout.SequentialGroup pinVertical = mainPanelLayout.createSequentialGroup();
+
+ if (pinLabelPos == PinLabelPosition.ABOVE) {
+ pinHorizontal
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(signPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+ pinVertical
+ .addComponent(signPinLabel)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel);
+ } else { // PinLabelPosition.LEFT
+ pinHorizontal
+ .addGroup(mainPanelLayout.createSequentialGroup()
+ .addComponent(signPinLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(pinsizeLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
+ pinVertical
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(signPinLabel)
+ .addComponent(pinField))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel);
+ }
+
+ mainPanelLayout.setHorizontalGroup(
+ mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(infoHorizontal)
+ .addGroup(pinHorizontal));
+
+ mainPanelLayout.setVerticalGroup(
+ mainPanelLayout.createSequentialGroup()
+ .addGroup(infoVertical)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(pinVertical));
+
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup();
+ GroupLayout.Group buttonVertical;
+
+ if (renderCancelButton) {
+ JButton cancelButton = new JButton();
+ cancelButton.setFont(cancelButton.getFont().deriveFont(cancelButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ cancelButton.setText(getMessage(BUTTON_CANCEL));
+ cancelButton.setActionCommand(cancelCommand);
+ cancelButton.addActionListener(cancelListener);
+
+ buttonHorizontal
+ .addComponent(signButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)
+ ;
+ buttonVertical = buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(signButton)
+ .addComponent(cancelButton)
+ ;
+ } else {
+ buttonHorizontal
+ .addComponent(signButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE)
+ ;
+ buttonVertical = buttonPanelLayout.createSequentialGroup()
+ .addComponent(signButton)
+ ;
+ }
+
+ buttonPanelLayout.setHorizontalGroup(buttonHorizontal);
+ buttonPanelLayout.setVerticalGroup(buttonVertical);
+
+// pinField.requestFocusInWindow();
+// helpLabel.requestFocus();
+ pinField.requestFocus();
+ contentPanel.validate();
+
+ }
+ });
+ }
+
+ @Override
+ public void showErrorDialog(
+ final String errorMsgKey, final Object[] errorMsgParams,
+ final ActionListener okListener, final String okCommand) {
+
+ showMessageDialog(TITLE_ERROR, ERROR_COLOR,
+ errorMsgKey, errorMsgParams, BUTTON_OK, okListener, okCommand);
+ }
+
+ @Override
+ public void showErrorDialog(
+ final String errorMsgKey, final Object[] errorMsgParams) {
+
+ showMessageDialog(TITLE_ERROR, ERROR_COLOR,
+ errorMsgKey, errorMsgParams, null, null, null);
+ }
+
+ @Override
+ public void showMessageDialog(
+ final String titleKey,
+ final String msgKey, final Object[] msgParams,
+ final String buttonKey,
+ final ActionListener okListener, final String okCommand) {
+
+ showMessageDialog(titleKey, null,
+ msgKey, msgParams, buttonKey, okListener, okCommand);
+ }
+
+ @Override
+ public void showMessageDialog(
+ final String titleKey,
+ final String msgKey, final Object[] msgParams) {
+
+ showMessageDialog(titleKey, null,
+ msgKey, msgParams, null, null, null);
+ }
+
+ @Override
+ public void showMessageDialog(
+ final String titleKey, final String msgKey) {
+
+ showMessageDialog(titleKey, null,
+ msgKey, null, null, null, null);
+ }
+
+ /**
+ *
+ * @param buttonKey if null defaults to BUTTON_OK
+ */
+ private void showMessageDialog(
+ final String titleKey, final Color titleColor,
+ final String msgKey, final Object[] msgParams,
+ final String buttonKey,
+ final ActionListener okListener, final String okCommand) {
+
+ log.debug("scheduling message dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("[" + Thread.currentThread().getName() + "] show message dialog");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ titleLabel.setText(getMessage(titleKey));
+ }
+
+ helpMouseListener.setHelpTopic(msgKey);
+ helpKeyListener.setHelpTopic(msgKey);
+
+ String msgPattern = getMessage(msgKey);
+ String msg = MessageFormat.format(msgPattern, msgParams);
+
+ JLabel msgLabel = new JLabel();
+ msgLabel.setFont(msgLabel.getFont().deriveFont(msgLabel.getFont().getStyle() & ~Font.BOLD));
+ msgLabel.setText(msg);
+
+ GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
+ mainPanel.setLayout(mainPanelLayout);
+
+ GroupLayout.ParallelGroup mainHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING);
+ GroupLayout.SequentialGroup mainVertical = mainPanelLayout.createSequentialGroup();
+
+ log.debug("focus to contentPanel");
+ contentPanel.requestFocus();
+
+ if (!renderHeaderPanel) {
+ JLabel titleLabel = new JLabel();
+ titleLabel.setFont(titleLabel.getFont().deriveFont(titleLabel.getFont().getStyle() | Font.BOLD));
+ titleLabel.setText(getMessage(titleKey));
+ if (titleColor != null) {
+ titleLabel.setForeground(titleColor);
+ }
+
+ mainHorizontal
+ .addGroup(mainPanelLayout.createSequentialGroup()
+ .addComponent(titleLabel)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ );
+ mainVertical
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(titleLabel)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ );
+
+ log.debug("focus to helpLabel");
+ helpLabel.requestFocus();
+ }
+
+ mainPanelLayout.setHorizontalGroup(mainHorizontal
+ .addComponent(msgLabel));
+ mainPanelLayout.setVerticalGroup(mainVertical
+ .addComponent(msgLabel));
+
+ if (okListener != null) {
+
+ JButton okButton = new JButton();
+ okButton.setFont(okButton.getFont().deriveFont(okButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ okButton.setText(getMessage((buttonKey != null) ? buttonKey : BUTTON_OK));
+ okButton.setActionCommand(okCommand);
+ okButton.addActionListener(okListener);
+
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ buttonPanelLayout.setHorizontalGroup(
+ buttonPanelLayout.createSequentialGroup()
+ .addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
+ buttonPanelLayout.setVerticalGroup(
+ buttonPanelLayout.createSequentialGroup()
+ .addComponent(okButton));
+
+ log.debug("focus to ok-button");
+ okButton.requestFocus();
+ }
+
+ contentPanel.validate();
+ }
+ });
+ }
+
+
+ @Override
+ public char[] getPin() {
+ if (pinField != null) {
+ char[] pin = pinField.getPassword(); //returns a copy
+ pinField = null; //garbage collect original pin (make sure to clear char[] after use)
+ return pin;
+ }
+ return null;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // SECURE VIEWER
+ ////////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * @param signedReferences
+ * @param backListener gets notified if pin-dialog has to be redrawn
+ * (signedRefencesList returns via BACK button)
+ * @param okCommand
+ */
+ @Override
+ public void showSecureViewer(final List<HashDataInput> dataToBeSigned,
+ final ActionListener backListener, final String backCommand) {
+
+ if (dataToBeSigned == null) {
+ showErrorDialog(getMessage(ERR_NO_HASHDATA),
+ new Object[] {"no signature data provided"},
+ backListener, backCommand);
+ } else if (dataToBeSigned.size() == 1) {
+ //TODO pull out (see also SignedReferencesSelectionListener)
+ if (SecureViewerDialog.SUPPORTED_MIME_TYPES.contains(dataToBeSigned.get(0).getMimeType())) {
+ try {
+ log.debug("[" + Thread.currentThread().getName() + "] scheduling secure viewer");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ showMessageDialog(TITLE_SIGNATURE_DATA, MESSAGE_HASHDATA_VIEWER);
+ showSecureViewer(dataToBeSigned.get(0), backListener, backCommand);
+ } catch (FontProviderException ex) {
+ log.error("failed to display secure viewer", ex);
+ showErrorDialog(ERR_VIEWER, new Object[] {ex.getMessage()}, backListener, backCommand);
+ }
+ }
+ });
+
+ } catch (Exception ex) { //InterruptedException InvocationTargetException
+ log.error("Failed to display secure viewer: " + ex.getMessage());
+ log.trace(ex);
+ showErrorDialog(ERR_UNKNOWN, null, backListener, backCommand);
+ }
+ } else {
+ log.debug("[" + Thread.currentThread().getName() + "] mime-type not supported by secure viewer, scheduling save dialog");
+ showMessageDialog(TITLE_SIGNATURE_DATA, MESSAGE_UNSUPPORTED_MIMETYPE);
+ SecureViewerSaveDialog.showSaveDialog(dataToBeSigned.get(0), messages, backListener, backCommand);
+ }
+ } else {
+ showSignedReferencesListDialog(dataToBeSigned, backListener, backCommand);
+ }
+ }
+
+ /**
+ * has to be called from event dispatcher thread
+ */
+ private void showSecureViewer(HashDataInput dataToBeSigned, ActionListener closeListener, String closeCommand) throws FontProviderException {
+
+ log.debug("[" + Thread.currentThread().getName() + "] show secure viewer");
+ SecureViewerDialog secureViewer = new SecureViewerDialog(null, messages,
+ closeListener, closeCommand,
+ fontProvider, helpMouseListener.getActionListener());
+
+ // workaround for [#439]
+ // avoid AlwaysOnTop at least in applet, otherwise make secureViewer AlwaysOnTop since MOCCA Dialog (JFrame created in LocalSTALFactory) is always on top.
+ Window window = SwingUtilities.getWindowAncestor(contentPane);
+ if (window != null && window.isAlwaysOnTop()) {
+ log.debug("make secureViewer alwaysOnTop");
+ secureViewer.setAlwaysOnTop(true);
+ }
+ secureViewer.setContent(dataToBeSigned);
+ log.trace("viewer setContent returned");
+ }
+
+
+
+ private void showSignedReferencesListDialog(final List<HashDataInput> signedReferences,
+ final ActionListener backListener, final String backCommand) {
+
+ log.debug("[" + Thread.currentThread().getName() + "] scheduling signed references list dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("[" + Thread.currentThread().getName() + "] show signed references list dialog");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ titleLabel.setText(getMessage(TITLE_SIGNATURE_DATA));
+ }
+
+ helpMouseListener.setHelpTopic(HELP_HASHDATALIST);
+ helpKeyListener.setHelpTopic(HELP_HASHDATALIST);
+
+ JLabel refIdLabel = new JLabel();
+ refIdLabel.setFont(refIdLabel.getFont().deriveFont(refIdLabel.getFont().getStyle() & ~java.awt.Font.BOLD));
+ String refIdLabelPattern = getMessage(MESSAGE_HASHDATALIST);
+ refIdLabel.setText(MessageFormat.format(refIdLabelPattern, new Object[]{signedReferences.size()}));
+
+ HashDataTableModel tableModel = new HashDataTableModel(signedReferences, renderRefId);
+ final JTable hashDataTable = new JTable(tableModel);
+ hashDataTable.setDefaultRenderer(HashDataInput.class, new HyperlinkRenderer(renderRefId));
+ hashDataTable.setTableHeader(null);
+
+ hashDataTable.addMouseMotionListener(new SignedReferencesMouseMotionListener(hashDataTable));
+
+ hashDataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ hashDataTable.getSelectionModel().addListSelectionListener(new SignedReferencesSelectionListener(signedReferences, backListener, backCommand));
+
+ JScrollPane hashDataScrollPane = new JScrollPane(hashDataTable);
+
+ GroupLayout mainPanelLayout = new GroupLayout(mainPanel);
+ mainPanel.setLayout(mainPanelLayout);
+
+ GroupLayout.SequentialGroup messageHorizontal = mainPanelLayout.createSequentialGroup()
+ .addComponent(refIdLabel);
+
+ GroupLayout.ParallelGroup messageVertical = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addComponent(refIdLabel);
+
+ if (!renderHeaderPanel) {
+ messageHorizontal
+ .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE)
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ messageVertical
+ .addComponent(switchFocusDummyLabel)
+ .addComponent(helpLabel)
+ ;
+ }
+
+ mainPanelLayout.setHorizontalGroup(
+ mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(messageHorizontal)
+ .addComponent(hashDataScrollPane, 0, 0, Short.MAX_VALUE));
+
+ mainPanelLayout.setVerticalGroup(
+ mainPanelLayout.createSequentialGroup()
+ .addGroup(messageVertical)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(hashDataScrollPane, 0, 0, hashDataTable.getPreferredSize().height+3));
+
+ JButton backButton = new JButton();
+ backButton.setFont(backButton.getFont().deriveFont(backButton.getFont().getStyle() & ~java.awt.Font.BOLD));
+ backButton.setText(getMessage(BUTTON_BACK));
+ backButton.setActionCommand(backCommand);
+ backButton.addActionListener(backListener);
+
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ buttonPanelLayout.setHorizontalGroup(buttonPanelLayout.createSequentialGroup()
+ .addComponent(backButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
+ buttonPanelLayout.setVerticalGroup(buttonPanelLayout.createSequentialGroup()
+ .addComponent(backButton));
+
+ contentPanel.validate();
+ }
+ });
+ }
+
+
+
+ /**
+ * not possible to add mouse listener to TableCellRenderer
+ * to change cursor on specific columns only, use table.columnAtPoint(e.getPoint())
+ *
+ */
+ private class SignedReferencesMouseMotionListener extends MouseMotionAdapter {
+
+ JTable hashDataTable;
+
+ public SignedReferencesMouseMotionListener(JTable table) {
+ this.hashDataTable = table;
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent e) {
+// if (hashDataTable.columnAtPoint(e.getPoint()) == 0) {
+ hashDataTable.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ }
+ }
+
+ ///////////
+ // SignedReferencesList (TODO pull out)
+
+ public class SignedReferencesSelectionListener implements ListSelectionListener {
+
+ List<HashDataInput> signedReferences;
+ ActionListener backListener;
+ String backCommand;
+
+ public SignedReferencesSelectionListener(List<HashDataInput> signedReferences, ActionListener backListener, String backCommand) {
+ this.signedReferences = signedReferences;
+ this.backListener = backListener;
+ this.backCommand = backCommand;
+ }
+
+ @Override
+ public void valueChanged(ListSelectionEvent event) {
+
+ if (event.getValueIsAdjusting()) {
+ return;
+ }
+
+ ListSelectionModel lsm = (ListSelectionModel) event.getSource();
+ int selectionIdx = lsm.getMinSelectionIndex();
+
+ log.debug("[" + Thread.currentThread().getName() + "] reference " + selectionIdx + " selected");
+
+ if (selectionIdx >= 0) {
+ final HashDataInput selection = signedReferences.get(selectionIdx);
+ final SignedReferencesListDisplayer backToListListener = new SignedReferencesListDisplayer(signedReferences, backListener, backCommand);
+
+ if (SecureViewerDialog.SUPPORTED_MIME_TYPES.contains(selection.getMimeType())) {
+ log.debug("[" + Thread.currentThread().getName() + "] scheduling secure viewer dialog");
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ showMessageDialog(TITLE_SIGNATURE_DATA, MESSAGE_HASHDATA_VIEWER);
+ showSecureViewer(selection, backToListListener, null);
+// SecureViewerDialog.showSecureViewer(selection, messages, fontProvider, helpMouseListener.getActionListener(), false);
+ } catch (FontProviderException ex) {
+ log.error("failed to display secure viewer", ex);
+ showErrorDialog(BKUGUIFacade.ERR_VIEWER, new Object[] {ex.getMessage()}, backToListListener, null);
+ }
+
+ }
+ });
+ } else {
+ log.debug("[" + Thread.currentThread().getName() + "] mime-type not supported by secure viewer, scheduling save dialog");
+ showMessageDialog(BKUGUIFacade.TITLE_SIGNATURE_DATA, BKUGUIFacade.MESSAGE_UNSUPPORTED_MIMETYPE);
+ SecureViewerSaveDialog.showSaveDialog(selection, messages, backToListListener, null);
+ }
+ }
+ }
+
+ /**
+ * ActionListener that returns to signed references list
+ */
+ private class SignedReferencesListDisplayer implements ActionListener {
+ List<HashDataInput> sr;
+ ActionListener bl;
+ String bc;
+
+ public SignedReferencesListDisplayer(List<HashDataInput> signedReferences, ActionListener backListener, String backCommand) {
+ sr = signedReferences;
+ bl = backListener;
+ bc = backCommand;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+// log.debug("[" + Thread.currentThread().getName() + "] displaying signed references list");
+ showSignedReferencesListDialog(sr, bl, bc);
+ }
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // UTILITY METHODS
+ ////////////////////////////////////////////////////////////////////////////
+
+ private void registerHelpListener(ActionListener helpListener) {
+ if (helpListener != null) {
+ this.helpMouseListener = new HelpMouseListener(helpListener);
+ this.helpKeyListener = new HelpKeyListener(helpListener);
+ } else {
+ log.error("no help listener provided, will not be able to display help");
+ this.helpMouseListener = new HelpMouseListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ log.error("no help listener registered (requested help topic: " + e.getActionCommand() + ")");
+ }
+ });
+ this.helpKeyListener = new HelpKeyListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ log.error("no help listener registered (requested help topic: " + e.getActionCommand() + ")");
+ }
+ });
+ }
+ }
+
+ private void registerSwitchFocusListener(ActionListener switchFocusListener) {
+ if (switchFocusListener != null) {
+ this.switchFocusKeyListener = new SwitchFocusFocusListener(switchFocusListener);
+
+ } else {
+
+ this.switchFocusKeyListener = new SwitchFocusFocusListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ log.warn("no switch focus listener registered");
+ }
+ });
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // INITIALIZERS (MAY BE OVERRIDDEN BY SUBCLASSES)
+ ////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Load applet messages bundle. Note that getBundle looks for classes based
+ * on the default Locale before it selects the base class!
+ *
+ * Called from constructor.
+ * Subclasses may override this method to ensure the message bundle is loaded
+ * once initButtonSize (called from constructor as well) is called.
+ * (Only relevant if initButtonSize is overridden as well)
+ * @param locale
+ */
+ protected void loadMessageBundle(Locale locale) {
+ if (locale != null) {
+ // see [#378] Ignoring post parameter 'locale': bundle resolve-order not correct?!
+ Locale lang = new Locale(locale.getLanguage().substring(0, 2));
+ log.debug("loading applet resources for language: " + lang.toString());
+ messages = ResourceBundle.getBundle(MESSAGES_BUNDLE, lang);
+ } else {
+ log.debug("loading default language applet resources");
+ messages = ResourceBundle.getBundle(MESSAGES_BUNDLE);
+ }
+ // how the f*** you know the default Messages.properties is de?!
+ log.debug("applet messages loaded: " + messages.getLocale());
+ }
+
+ protected int initButtonSize() {
+ int bs = 0;
+
+ JButton b = new JButton();
+ b.setText(getMessage(BUTTON_OK));
+ if (b.getPreferredSize().width > bs) {
+ bs = b.getPreferredSize().width;
+ }
+ // need cancel button for message dialog,
+ // even if renderCancelButton == false
+ b.setText(getMessage(BUTTON_CANCEL));
+ if (b.getPreferredSize().width > bs) {
+ bs = b.getPreferredSize().width;
+ }
+ b.setText(getMessage(BUTTON_SIGN));
+ if (b.getPreferredSize().width > bs) {
+ bs = b.getPreferredSize().width;
+ }
+ b.setText(getMessage(BUTTON_BACK));
+ if (b.getPreferredSize().width > bs) {
+ bs = b.getPreferredSize().width;
+ }
+ b.setText(getMessage(BUTTON_SAVE));
+ if (b.getPreferredSize().width > bs) {
+ bs = b.getPreferredSize().width;
+ }
+ return bs;
+ }
+
+ @Override
+ public void getFocusFromBrowser() {
+
+ // This method puts the focus to the helpLabel as this
+ // element is supposed to appear in each dialogue.
+ helpLabel.requestFocus();
+
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUIcons.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUIcons.java
new file mode 100644
index 00000000..92d6897b
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUIcons.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import java.awt.Image;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import javax.imageio.ImageIO;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class BKUIcons {
+
+ protected static final Log log = LogFactory.getLog(BKUIcons.class);
+
+ /** 16x16, 24x24, 32x32, 48x48, 128x128 pixels */
+ public static final ArrayList<Image> icons = new ArrayList<Image>();
+
+ static {
+ String[] iconResources = new String[] {
+ "/at/gv/egiz/bku/gui/chip16.png",
+ "/at/gv/egiz/bku/gui/chip24.png",
+ "/at/gv/egiz/bku/gui/chip32.png",
+ "/at/gv/egiz/bku/gui/chip48.png",
+ "/at/gv/egiz/bku/gui/chip128.png" };
+ for (String ir : iconResources) {
+ URL resource = BKUIcons.class.getResource(ir);
+ if (ir != null) {
+ try {
+ icons.add(ImageIO.read(resource));
+ } catch (IOException ex) {
+ log.warn("failed to load mocca icon " + ir, ex);
+ }
+ }
+ }
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/DefaultHelpListener.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/DefaultHelpListener.java
new file mode 100644
index 00000000..032c8fe5
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/DefaultHelpListener.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import java.applet.AppletContext;
+import java.net.URL;
+import java.util.Locale;
+import javax.swing.SwingUtilities;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class DefaultHelpListener extends AbstractHelpListener {
+
+ /**
+ * applet context to open external links in help pages,
+ * if null, no external links will be opened
+ */
+ protected AppletContext ctx;
+
+ /**
+ *
+ * @param ctx open external links via applet context
+ * @param helpURL
+ * @param locale
+ */
+ public DefaultHelpListener(AppletContext ctx, URL helpURL, Locale locale) {
+ super(helpURL, locale);
+ this.ctx = ctx;
+ }
+
+ /**
+ * external links in help document are not opened
+ * @param helpURL
+ * @param locale
+ */
+ public DefaultHelpListener(URL helpURL, Locale locale) {
+ super(helpURL, locale);
+ this.ctx = null;
+ }
+
+ /**
+ * blocks until help viewer returns (is closed)
+ * @param helpURL
+ * @param helpTopic ignored
+ */
+ @Override
+ public void showDocument(final URL helpURL, final String helpTopic) {
+ log.debug("schedule help dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("show help dialog");
+
+ if (ctx == null) {
+ HelpViewer.showHelpDialog(helpURL, messages);
+ } else {
+ HelpViewer.showHelpDialog(ctx, helpURL, messages);
+ }
+ }
+ });
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataTableModel.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataTableModel.java
new file mode 100644
index 00000000..70842102
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataTableModel.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import at.gv.egiz.stal.HashDataInput;
+import java.util.List;
+import javax.swing.table.DefaultTableModel;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+class HashDataTableModel extends DefaultTableModel {
+
+ protected static final Log log = LogFactory.getLog(HashDataTableModel.class);
+
+ /** HashDataInput in first column, register hyperlinkrenderer only here */
+ protected Class[] types;
+ protected List<HashDataInput> hashDataInputs;
+
+ public HashDataTableModel(List<HashDataInput> hashDataInputs, boolean twoColLayout) {
+ super(0, (twoColLayout) ? 2 : 1);
+ this.hashDataInputs = hashDataInputs;
+
+ if (twoColLayout) {
+ types = new Class[] { HashDataInput.class, String.class };
+ for (HashDataInput hdi : hashDataInputs) {
+ addRow(new Object[] { hdi, hdi.getMimeType() });
+ }
+ } else {
+ types = new Class[] { HashDataInput.class };
+ for (HashDataInput hdi : hashDataInputs) {
+ addRow(new Object[] { hdi });
+ }
+ }
+ }
+
+ @Override
+ public Class getColumnClass(int columnIndex) {
+ return types[columnIndex];
+ }
+
+ @Override
+ public boolean isCellEditable(int rowIndex, int columnIndex) {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpKeyListener.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpKeyListener.java
new file mode 100644
index 00000000..4ca20f7e
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpKeyListener.java
@@ -0,0 +1,46 @@
+package at.gv.egiz.bku.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Thomas Zefferer <thomas.zefferer@iaik.tugraz.at>
+ */
+public class HelpKeyListener extends KeyAdapter {
+
+ protected static final Log log = LogFactory.getLog(HelpKeyListener.class);
+
+ protected ActionListener helpListener;
+ protected String locale;
+ protected String topic;
+
+ public HelpKeyListener(ActionListener externalHelpListener) {
+ super();
+ this.helpListener = externalHelpListener;
+ }
+
+ public void setHelpTopic(String topic) {
+ log.trace("setting help topic: " + topic);
+ this.topic = topic;
+ }
+
+ public ActionListener getActionListener() {
+ return helpListener;
+ }
+
+ @Override
+ public void keyPressed(KeyEvent arg0) {
+
+ if(arg0.getKeyCode() == KeyEvent.VK_ENTER) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, topic);
+ helpListener.actionPerformed(e);
+ }
+ }
+
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpLinkFocusManager.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpLinkFocusManager.java
new file mode 100644
index 00000000..f5882b3d
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpLinkFocusManager.java
@@ -0,0 +1,138 @@
+package at.gv.egiz.bku.gui;
+
+import java.awt.Color;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.net.URL;
+
+import javax.accessibility.AccessibleHyperlink;
+import javax.accessibility.AccessibleHypertext;
+import javax.swing.JEditorPane;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.text.DefaultStyledDocument;
+import javax.swing.text.Element;
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+
+/**
+ *
+ * @author Thomas Zefferer <thomas.zefferer@iaik.tugraz.at>
+ */
+public final class HelpLinkFocusManager extends KeyAdapter {
+
+ private static final int FOCUS_UNDEFINED = -1;
+
+ private int focusedHyperlinkIndex = FOCUS_UNDEFINED;
+ private JEditorPane displayPane;
+
+ public HelpLinkFocusManager(JEditorPane displayPane) {
+
+ super();
+ this.displayPane = displayPane;
+ }
+
+ public void keyPressed(KeyEvent e) {
+
+ AccessibleHypertext accessibleHypertext = (AccessibleHypertext) this.displayPane
+ .getAccessibleContext().getAccessibleText();
+
+ if (accessibleHypertext.getLinkCount() > 0) {
+ switch (e.getKeyCode()) {
+
+ case KeyEvent.VK_RIGHT:
+ if (this.focusedHyperlinkIndex != FOCUS_UNDEFINED) {
+ removeHyperlinkFocus();
+ }
+
+ this.focusedHyperlinkIndex++;
+
+ if (this.focusedHyperlinkIndex >= accessibleHypertext
+ .getLinkCount()) {
+
+ this.focusedHyperlinkIndex = 0;
+ }
+
+ setHyperlinkFocus();
+ break;
+
+ case KeyEvent.VK_LEFT:
+ if (this.focusedHyperlinkIndex != FOCUS_UNDEFINED) {
+ removeHyperlinkFocus();
+ }
+
+ this.focusedHyperlinkIndex--;
+
+ if (this.focusedHyperlinkIndex < 0) {
+ this.focusedHyperlinkIndex = accessibleHypertext
+ .getLinkCount() - 1;
+ }
+
+ setHyperlinkFocus();
+ break;
+
+ case KeyEvent.VK_SPACE:
+ case KeyEvent.VK_ENTER:
+
+
+ AccessibleHyperlink link = accessibleHypertext
+ .getLink(this.focusedHyperlinkIndex);
+ if (link != null) {
+ URL url = (URL) link.getAccessibleActionObject(0);
+ Element element = ((DefaultStyledDocument) this.displayPane
+ .getDocument()).getCharacterElement(link
+ .getStartIndex());
+ HyperlinkEvent linkEvent = new HyperlinkEvent(
+ this.displayPane,
+ HyperlinkEvent.EventType.ACTIVATED, url, null,
+ element);
+ this.displayPane.fireHyperlinkUpdate(linkEvent);
+ }
+
+ removeHyperlinkFocus();
+ this.focusedHyperlinkIndex = FOCUS_UNDEFINED;
+ break;
+ default:
+ // nothig to do
+ break;
+ }
+ }
+ }
+
+ private void setHyperlinkFocus() {
+
+ AccessibleHypertext accessibleHypertext = (AccessibleHypertext) this.displayPane
+ .getAccessibleContext().getAccessibleText();
+ AccessibleHyperlink link = accessibleHypertext
+ .getLink(this.focusedHyperlinkIndex);
+
+ if (link != null) {
+
+ MutableAttributeSet style = new SimpleAttributeSet();
+ StyleConstants.setForeground(style, Color.RED);
+ ((DefaultStyledDocument) this.displayPane.getDocument())
+ .setCharacterAttributes(link.getStartIndex(), link
+ .getEndIndex()
+ - link.getStartIndex(), style, false);
+ }
+ }
+
+ private void removeHyperlinkFocus() {
+ Color textColor = Color.BLUE;
+ AccessibleHypertext accessibleHypertext = (AccessibleHypertext) this.displayPane
+ .getAccessibleContext().getAccessibleText();
+ AccessibleHyperlink link = accessibleHypertext
+ .getLink(this.focusedHyperlinkIndex);
+
+ if (link != null) {
+
+ MutableAttributeSet style = new SimpleAttributeSet();
+ StyleConstants.setForeground(style, textColor);
+ ((DefaultStyledDocument) this.displayPane.getDocument())
+ .setCharacterAttributes(link.getStartIndex(), link
+ .getEndIndex()
+ - link.getStartIndex(), style, false);
+ }
+ }
+
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpMouseListener.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpMouseListener.java
new file mode 100644
index 00000000..b7bbe971
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpMouseListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+public class HelpMouseListener extends MouseAdapter {
+
+ protected static final Log log = LogFactory.getLog(HelpMouseListener.class);
+
+ protected ActionListener helpListener;
+ protected String locale;
+ protected String topic;
+
+ public HelpMouseListener(ActionListener externalHelpListener) {
+ super();
+ this.helpListener = externalHelpListener;
+ }
+
+ public void setHelpTopic(String topic) {
+ log.trace("setting help topic: " + topic);
+ this.topic = topic;
+ }
+
+ public ActionListener getActionListener() {
+ return helpListener;
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent arg0) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, topic);
+ helpListener.actionPerformed(e);
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpViewer.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpViewer.java
new file mode 100644
index 00000000..0f887f78
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HelpViewer.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import java.applet.AppletContext;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.net.URL;
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+import javax.swing.GroupLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.LayoutStyle;
+import javax.swing.SwingUtilities;
+import javax.swing.event.HyperlinkEvent;
+import javax.swing.event.HyperlinkListener;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class HelpViewer extends JDialog
+ implements ActionListener {
+
+ protected static final Log log = LogFactory.getLog(HelpViewer.class);
+ private static HelpViewer dialog;
+ protected ResourceBundle messages;
+ protected AppletContext ctx;
+
+ /**
+ *
+ * @param ctx external links are opened via ctx.showDocument()
+ * @param helpURL
+ * @param helpTopic
+ * @param messages
+ */
+ public static void showHelpDialog(AppletContext ctx,
+ URL helpURL,
+// String helpTopic,
+ ResourceBundle messages) {
+ showHelpDialog(null, ctx, helpURL, messages); //helpTopic, messages);
+ }
+
+ public static void showHelpDialog(URL helpURL,
+// String helpTopic,
+ ResourceBundle messages) {
+ showHelpDialog(null, null, helpURL, messages); // helpTopic, messages);
+ }
+
+ public static void showHelpDialog(Component owner,
+ AppletContext ctx,
+ URL helpURL,
+// String helpTopic,
+ ResourceBundle messages) {
+
+ Frame frame = null;
+ if (owner != null) {
+ JOptionPane.getFrameForComponent(owner);
+ }
+ dialog = new HelpViewer(frame, messages, ctx, helpURL); //, helpTopic);
+ dialog.setVisible(true);
+ dialog.toFront();
+ }
+
+ private HelpViewer(Frame frame,
+ ResourceBundle messages,
+ AppletContext ctx,
+ URL helpURL) { //, String helpTopic) {
+ super(frame, messages.getString(BKUGUIFacade.WINDOWTITLE_HELP), true);
+ this.messages = messages;
+ this.ctx = ctx;
+
+// String p = messages.getString(BKUGUIFacade.MESSAGE_HELP);
+// String helpItem = messages.getString(helpTopic);
+// String viewerLabel = MessageFormat.format(p, new Object[]{helpItem});
+
+ JPanel helpPanel = createViewerPanel(helpURL); //viewerLabel, helpURL);
+ JPanel buttonPanel = createButtonPanel();
+
+ initContentPane(new Dimension(600, 600), helpPanel, buttonPanel);
+ pack();
+ if (frame != null) {
+ setLocationRelativeTo(frame);
+ } else {
+ setLocationByPlatform(true);
+ }
+ }
+
+ private void initContentPane(Dimension preferredSize, JPanel viewerPanel, JPanel buttonPanel) {
+ Container contentPane = getContentPane();
+ contentPane.setPreferredSize(preferredSize);
+
+ GroupLayout mainLayout = new GroupLayout(contentPane);
+ contentPane.setLayout(mainLayout);
+
+ mainLayout.setHorizontalGroup(
+ mainLayout.createSequentialGroup().addContainerGap().addGroup(
+ mainLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)).addContainerGap());
+ mainLayout.setVerticalGroup(
+ mainLayout.createSequentialGroup().addContainerGap().addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED).addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addContainerGap());
+ }
+
+ private JPanel createViewerPanel(URL helpURL) { //String viewerLabelText,
+ log.debug("viewer dialog: " + helpURL.toString());
+
+ final JEditorPane viewer = new JEditorPane();
+ viewer.setEditable(false);
+ try {
+ viewer.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+ viewer.setPage(helpURL);
+
+ HelpLinkFocusManager editorFocusManager = new HelpLinkFocusManager (viewer);
+ viewer.addKeyListener(editorFocusManager );
+
+ viewer.addHyperlinkListener(new HyperlinkListener() {
+
+ @Override
+ public void hyperlinkUpdate(HyperlinkEvent e) {
+ final URL url = e.getURL();
+ if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+ if (ctx != null) {
+ log.debug("open external link in help viewer: " + url);
+ ctx.showDocument(url, "_blank");
+ } else {
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+ String msgP = messages.getString(BKUGUIFacade.ERR_EXTERNAL_LINK);
+ String msg = MessageFormat.format(msgP, url);
+ String title = messages.getString(BKUGUIFacade.TITLE_ERROR);
+ JOptionPane.showMessageDialog(rootPane, msg, title, JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ }
+ }
+ }
+ });
+ } catch (IOException ex) {
+ String p = messages.getString(BKUGUIFacade.ERR_VIEWER);
+ viewer.setText(MessageFormat.format(p, new Object[]{ex.getMessage()}));
+ }
+ viewer.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ JScrollPane scrollPane = new JScrollPane(viewer);
+ scrollPane.setPreferredSize(viewer.getPreferredSize());
+ scrollPane.setAlignmentX(LEFT_ALIGNMENT);
+ viewer.setCaretPosition(0);
+
+// JLabel viewerLabel = new JLabel();
+// viewerLabel.setText(viewerLabelText);
+// viewerLabel.setFont(viewerLabel.getFont().deriveFont(viewerLabel.getFont().getStyle() | java.awt.Font.BOLD));
+// viewerLabel.setLabelFor(viewer);
+
+ JPanel viewerPanel = new JPanel();
+ GroupLayout viewerPanelLayout = new GroupLayout(viewerPanel);
+ viewerPanel.setLayout(viewerPanelLayout);
+
+ viewerPanelLayout.setHorizontalGroup(
+ viewerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+// .addComponent(viewerLabel)
+ .addComponent(scrollPane));
+ viewerPanelLayout.setVerticalGroup(
+ viewerPanelLayout.createSequentialGroup()
+// .addComponent(viewerLabel)
+// .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(scrollPane));
+
+ return viewerPanel;
+ }
+
+ private JPanel createButtonPanel() {
+ JButton closeButton = new JButton();
+ closeButton.setText(messages.getString(BKUGUIFacade.BUTTON_CLOSE));
+ closeButton.addActionListener(this);
+
+ JPanel buttonPanel = new JPanel();
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ buttonPanelLayout.setHorizontalGroup(
+ buttonPanelLayout.createSequentialGroup().addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(closeButton));
+ buttonPanelLayout.setVerticalGroup(
+ buttonPanelLayout.createSequentialGroup().addComponent(closeButton));
+ return buttonPanel;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ HelpViewer.dialog.setVisible(false);
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java
new file mode 100644
index 00000000..6af22815
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HyperlinkRenderer.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import at.gv.egiz.stal.HashDataInput;
+import javax.swing.table.DefaultTableCellRenderer;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class HyperlinkRenderer extends DefaultTableCellRenderer {
+
+ protected boolean renderReferenceId;
+
+ public HyperlinkRenderer(boolean renderReferenceId) {
+ this.renderReferenceId = renderReferenceId;
+ }
+
+ /**
+ * cannot change mouse cursor here, do in jTable
+ * @param value
+ */
+ @Override
+ protected void setValue(Object value) {
+ String hrefText;
+ if (((HashDataInput) value).getFilename() != null) {
+ hrefText = ((HashDataInput) value).getFilename();
+ } else {
+ if (renderReferenceId) {
+ hrefText = ((HashDataInput) value).getReferenceId();
+ } else {
+ hrefText = ((HashDataInput) value).getMimeType();
+ }
+ }
+ super.setText("<html><u>" + hrefText + "</u></html>");
+ setForeground(BKUGUIFacade.HYPERLINK_COLOR);
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/ImagePanel.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/ImagePanel.java
new file mode 100644
index 00000000..6a738acb
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/ImagePanel.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import java.awt.Graphics;
+import java.awt.Image;
+import java.net.URL;
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+
+/**
+ * paints the background image in the lower left corner of the component
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class ImagePanel extends JPanel {
+
+ protected Image backgroundImg;
+
+ public ImagePanel(URL background) {
+ this(new ImageIcon(background).getImage());
+ }
+
+ public ImagePanel(Image img) {
+ this.backgroundImg = img;
+ this.setOpaque(false);
+ }
+
+ @Override
+ public void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ g.drawImage(backgroundImg, 0, this.getHeight() - backgroundImg.getHeight(null), null);
+ }
+
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java
new file mode 100644
index 00000000..52a3d5fe
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.swing.JButton;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+
+/**
+ *
+ * @author clemens
+ */
+class PINDocument extends PlainDocument {
+
+ private static final long serialVersionUID = 1L;
+ protected Pattern pinPattern;
+ protected int minLength;
+ protected int maxLength;
+ protected JButton enterButton;
+
+ public PINDocument(int minLength, int maxLength, String pattern, JButton enterButton) {
+ if (enterButton == null) {
+ throw new NullPointerException("OK button null");
+ }
+ if (pattern != null) {
+ pinPattern = Pattern.compile(pattern);
+ } else {
+ pinPattern = Pattern.compile(".");
+ }
+ this.minLength = minLength;
+ this.maxLength = maxLength;
+ this.enterButton = enterButton;
+ }
+
+ @Override
+ public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
+ if (maxLength < 0 || maxLength >= (getLength() + str.length())) {
+ boolean matches = true;
+ for (int i = 0; i < str.length(); i++) {
+ Matcher m = pinPattern.matcher(str.substring(i, i + 1));
+ if (!m.matches()) {
+ matches = false;
+ }
+ }
+ if (matches) {
+ super.insertString(offs, str, a);
+ enterButton.setEnabled(getLength() >= minLength);
+ }
+ }
+ }
+
+ @Override
+ public void remove(int offs, int len) throws BadLocationException {
+ super.remove(offs, len);
+ enterButton.setEnabled(getLength() >= minLength);
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java
new file mode 100644
index 00000000..7db70c46
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui;
+
+import at.gv.egiz.bku.gui.viewer.FontProvider;
+import at.gv.egiz.bku.gui.viewer.SecureViewerSaveDialog;
+import at.gv.egiz.stal.HashDataInput;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ResourceBundle;
+import javax.swing.GroupLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JEditorPane;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.LayoutStyle;
+import javax.swing.WindowConstants;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.html.HTMLEditorKit;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class SecureViewerDialog extends JDialog {
+
+ /** don't import BKUFonts in order not to load BKUFonts.jar
+ * BKUApplet includes BKUFonts as runtime dependency only, the jar is copied to the applet dir in BKUOnline with dependency-plugin
+ * BKUViewer has compile dependency BKUFonts, transitive in BKUOnline and BKULocal
+ */
+ public static final Dimension VIEWER_DIMENSION = new Dimension(600, 400);
+
+ public static final List<String> SUPPORTED_MIME_TYPES = new ArrayList<String>();
+ static {
+ SUPPORTED_MIME_TYPES.add("text/plain");
+ SUPPORTED_MIME_TYPES.add("application/xhtml+xml");
+ }
+ protected static final Log log = LogFactory.getLog(SecureViewerDialog.class);
+// private static SecureViewerDialog dialog;
+ protected ResourceBundle messages;
+ protected JEditorPane viewer;
+ protected JLabel viewerLabel;
+ protected JScrollPane scrollPane;
+ protected HashDataInput content; //remember for save dialog
+ protected FontProvider fontProvider;
+
+ /**
+ * Create and display a modal SecureViewer dialog.
+ * This method blocks until the dialog's close button is pressed.
+ *
+ * @param owner, dialog is positioned relative to its owner
+ * (if null, at default location of native windowing system)
+ */
+ public SecureViewerDialog(Frame owner, ResourceBundle messages,
+ ActionListener closeListener, String closeCommand,
+ FontProvider fontProvider, ActionListener helpListener) {
+ super(owner, messages.getString(BKUGUIFacade.WINDOWTITLE_VIEWER), true);
+ this.setIconImages(BKUIcons.icons);
+ this.messages = messages;
+ this.fontProvider = fontProvider;
+
+ initContentPane(VIEWER_DIMENSION,
+ createViewerPanel(helpListener),
+ createButtonPanel(closeListener, closeCommand));
+
+ // also leave defaultWindowClosing HIDE_ON_CLOSE
+ this.addWindowListener(new WindowCloseListener(closeListener, closeCommand));
+ this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+
+ pack();
+ if (owner != null) {
+ setLocationRelativeTo(owner);
+ } else {
+ setLocationByPlatform(true);
+ }
+ }
+
+ private void initContentPane(Dimension preferredSize,
+ JPanel viewerPanel, JPanel buttonPanel) {
+ Container contentPane = getContentPane();
+ contentPane.setPreferredSize(preferredSize);
+
+ GroupLayout mainLayout = new GroupLayout(contentPane);
+ contentPane.setLayout(mainLayout);
+
+ mainLayout.setHorizontalGroup(
+ mainLayout.createSequentialGroup().addContainerGap().addGroup(
+ mainLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)).addContainerGap());
+ mainLayout.setVerticalGroup(
+ mainLayout.createSequentialGroup().addContainerGap().addComponent(viewerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED).addComponent(buttonPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addContainerGap());
+ }
+
+ /**
+ * @param helpListener may be null
+ */
+ private JPanel createViewerPanel(final ActionListener helpListener) {
+ viewer = new JEditorPane();
+ viewer.setEditable(false);
+ viewer.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
+
+ scrollPane = new JScrollPane();
+
+ JPanel viewerPanel = new JPanel();
+ GroupLayout viewerPanelLayout = new GroupLayout(viewerPanel);
+ viewerPanel.setLayout(viewerPanelLayout);
+
+ GroupLayout.SequentialGroup infoHorizontal = viewerPanelLayout.createSequentialGroup();
+ GroupLayout.ParallelGroup infoVertical = viewerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING);
+
+ viewerLabel = new JLabel();
+ viewerLabel.setFont(viewerLabel.getFont().deriveFont(viewerLabel.getFont().getStyle() | java.awt.Font.BOLD));
+// viewerLabel.setLabelFor(viewer);
+
+ infoHorizontal.addComponent(viewerLabel);
+ infoVertical.addComponent(viewerLabel);
+
+ if (helpListener != null) {
+ final JLabel helpLabel = new JLabel();
+ helpLabel.setFocusable(true);
+ helpLabel.setIcon(new ImageIcon(getClass().getResource(BKUGUIFacade.HELP_IMG)));
+ helpLabel.getAccessibleContext().setAccessibleName(messages.getString(BKUGUIFacade.ALT_HELP));
+ helpLabel.addMouseListener(new MouseAdapter() {
+
+ @Override
+ public void mouseClicked(MouseEvent arg0) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, BKUGUIFacade.HELP_HASHDATAVIEWER);
+ helpListener.actionPerformed(e);
+ }
+ });
+ helpLabel.addKeyListener(new KeyAdapter() {
+
+ @Override
+ public void keyPressed(KeyEvent arg0) {
+
+ if (arg0.getKeyCode() == KeyEvent.VK_ENTER) {
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, BKUGUIFacade.HELP_HASHDATAVIEWER);
+ helpListener.actionPerformed(e);
+ }
+ }
+ });
+
+ helpLabel.addFocusListener(new FocusAdapter() {
+
+ @Override
+ public void focusGained(FocusEvent e) {
+
+ helpLabel.setIcon(new ImageIcon(getClass().getResource(BKUGUIFacade.HELP_IMG_FOCUS)));
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+
+ helpLabel.setIcon(new ImageIcon(getClass().getResource(BKUGUIFacade.HELP_IMG)));
+ }
+ });
+ helpLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+
+ infoHorizontal.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, 0, Short.MAX_VALUE).addComponent(helpLabel);
+ infoVertical.addComponent(helpLabel);
+ }
+
+ viewerPanelLayout.setHorizontalGroup(
+ viewerPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup(infoHorizontal).addComponent(scrollPane));
+ viewerPanelLayout.setVerticalGroup(
+ viewerPanelLayout.createSequentialGroup().addGroup(infoVertical).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(scrollPane));
+
+ return viewerPanel;
+ }
+
+ /**
+ * Sets the hashdataInput to be displayed and makes the dialog visible.
+ * This method blocks until the dialog's close button is pressed.
+ *
+ * @param mimeType defaults to text/plain if null
+ * @param encoding must be null if document contains charset declaration (e.g. HTML page), otherwise the parser crashes
+
+ * @param hashDataInput
+ */
+ public void setContent(HashDataInput hashDataInput) { //throws FontProviderException {
+
+ log.debug("[" + Thread.currentThread().getName() + "] set viewer content");
+
+ this.content = null;
+ viewer.setText(null);
+
+ String mimeType = hashDataInput.getMimeType();
+ if (mimeType == null) {
+ mimeType = "text/plain";
+ }
+ log.debug("secure viewer mime type: " + mimeType);
+ // loads editorkit for text/plain if unrecognized
+ viewer.setContentType(mimeType);
+
+ try {
+
+ if ("text/plain".equals(mimeType)) {
+ viewer.setEditorKit(new StyledEditorKit());
+ viewer.setFont(fontProvider.getFont().deriveFont(Font.PLAIN, viewer.getFont().getSize()));
+ } else if ("application/xhtml+xml".equals(mimeType)) {
+ viewer.setEditorKit(new HTMLEditorKit());
+ //reset font if fontprovider font was set before (TODO also html font from fontprovider)
+ viewer.setFont(new Font("Dialog", Font.PLAIN, viewer.getFont().getSize())); //UIManager.getFont("Label.font"));
+ }
+
+ EditorKit editorKit = viewer.getEditorKit();
+ Document document = editorKit.createDefaultDocument();
+ // document.putProperty("IgnoreCharsetDirective", new Boolean(true));
+
+ Charset cs = (hashDataInput.getEncoding() == null) ? Charset.forName("UTF-8") : Charset.forName(hashDataInput.getEncoding());
+ log.debug("secure viewer encoding: " + cs.toString());
+
+ InputStreamReader isr = new InputStreamReader(hashDataInput.getHashDataInput(), cs);
+ Reader contentReader = new BufferedReader(isr);
+ viewer.read(contentReader, document);
+ contentReader.close();
+
+ this.content = hashDataInput;
+
+// } catch (Exception ex) // fontProvider
+// } catch (IllegalCharsetNameException ex) {
+// } catch (UnsupportedCharsetException ex) {
+// } catch (FontProviderException ex) {
+ } catch (Exception ex) {
+ log.error(ex.getMessage(), ex);
+ String p = messages.getString(BKUGUIFacade.ERR_VIEWER);
+ viewer.setContentType("text/plain");
+ viewer.setText(MessageFormat.format(p, ex.getMessage()));
+ }
+ viewer.setCaretPosition(0);
+
+ scrollPane.setViewportView(viewer);
+ scrollPane.setPreferredSize(viewer.getPreferredSize());
+ scrollPane.setAlignmentX(LEFT_ALIGNMENT);
+
+ if ("application/xhtml+xml".equals(mimeType)) {
+ viewerLabel.setText(messages.getString(BKUGUIFacade.WARNING_XHTML));
+ } else {
+ viewerLabel.setText("");
+ }
+
+ log.debug("VIEWER FONT: " + viewer.getFont());
+ setVisible(true);
+ toFront();
+ }
+
+ private JPanel createButtonPanel(ActionListener closeListener, String closeCommand) {
+ JButton closeButton = new JButton();
+ closeButton.setText(messages.getString(BKUGUIFacade.BUTTON_CLOSE));
+ closeButton.setActionCommand(closeCommand);
+ closeButton.addActionListener(new CloseButtonListener(closeListener));
+
+ JButton saveButton = new JButton();
+ saveButton.setText(messages.getString(BKUGUIFacade.BUTTON_SAVE));
+ saveButton.addActionListener(new SaveButtonListener());
+
+ int buttonSize = closeButton.getPreferredSize().width;
+ if (saveButton.getPreferredSize().width > buttonSize) {
+ buttonSize = saveButton.getPreferredSize().width;
+ }
+
+ JPanel buttonPanel = new JPanel();
+ GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+ buttonPanel.setLayout(buttonPanelLayout);
+
+ buttonPanelLayout.setHorizontalGroup(
+ buttonPanelLayout.createSequentialGroup().addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(saveButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addComponent(closeButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
+ buttonPanelLayout.setVerticalGroup(
+ buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE).addComponent(saveButton).addComponent(closeButton));
+
+ return buttonPanel;
+ }
+
+ public class WindowCloseListener extends WindowAdapter {
+
+ ActionListener closeListener;
+ String closeCommand;
+
+ public WindowCloseListener(ActionListener closeListener, String closeCommand) {
+ this.closeListener = closeListener;
+ this.closeCommand = closeCommand;
+ }
+
+ @Override
+ public void windowClosing(WindowEvent e) {
+ log.trace("[" + Thread.currentThread().getName() + "] closing secure viewer");
+ setVisible(false);
+ if (closeListener != null) {
+ closeListener.actionPerformed(new ActionEvent(e.getSource(), e.getID(), closeCommand));
+ }
+ }
+ }
+
+ public class CloseButtonListener implements ActionListener {
+
+ ActionListener closeListener;
+
+ public CloseButtonListener(ActionListener closeListener) {
+ this.closeListener = closeListener;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ log.trace("[" + Thread.currentThread().getName() + "] closing secure viewer");
+ setVisible(false);
+ if (closeListener != null) {
+ closeListener.actionPerformed(e);
+ }
+ }
+ }
+
+ public class SaveButtonListener implements ActionListener {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ log.trace("[" + Thread.currentThread().getName() + "] display secure viewer save dialog");
+ SecureViewerSaveDialog.showSaveDialog(content, messages, null, null);
+ }
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusFocusListener.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusFocusListener.java
new file mode 100644
index 00000000..06e37a89
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusFocusListener.java
@@ -0,0 +1,38 @@
+package at.gv.egiz.bku.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Thomas Zefferer <thomas.zefferer@iaik.tugraz.at>
+ */
+public class SwitchFocusFocusListener extends FocusAdapter {
+
+ protected static final Log log = LogFactory.getLog(SwitchFocusFocusListener.class);
+
+ protected ActionListener swichFocusListener;
+
+ public SwitchFocusFocusListener(ActionListener externalSwitchFocusListener) {
+ super();
+ this.swichFocusListener = externalSwitchFocusListener;
+ }
+
+ public ActionListener getActionListener() {
+ return swichFocusListener;
+ }
+
+ @Override
+ public void focusGained(FocusEvent arg0) {
+
+ ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null);
+ swichFocusListener.actionPerformed(e);
+ }
+
+
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusListener.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusListener.java
new file mode 100644
index 00000000..48b641e2
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SwitchFocusListener.java
@@ -0,0 +1,44 @@
+package at.gv.egiz.bku.gui;
+
+import java.applet.AppletContext;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ *
+ * @author Thomas Zefferer <thomas.zefferer@iaik.tugraz.at>
+ */
+public class SwitchFocusListener implements ActionListener {
+
+ protected final static Log log = LogFactory.getLog(SwitchFocusListener.class);
+
+ protected AppletContext ctx;
+ protected String javascriptFunction;
+
+ public SwitchFocusListener(AppletContext ctx, String javascriptFunction) {
+
+ this.ctx = ctx;
+ this.javascriptFunction = javascriptFunction;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+
+ try {
+ ctx.showDocument
+ (new URL("javascript:" + javascriptFunction));
+ }
+ catch (MalformedURLException me) {
+
+ log.warn("Unable to call external javascript function.", me);
+ }
+
+
+ }
+
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedHTMLEditorKit.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedHTMLEditorKit.java
new file mode 100644
index 00000000..680bf1a4
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedHTMLEditorKit.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui.html;
+
+import javax.swing.text.Element;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.View;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.HTMLEditorKit;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class RestrictedHTMLEditorKit extends HTMLEditorKit {
+
+
+ public static class RestrictedHTMLFactory extends HTMLFactory {
+
+ @Override
+ public View create(Element elem) {
+ Object o =
+ elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
+ if (o instanceof HTML.Tag) {
+ HTML.Tag kind = (HTML.Tag) o;
+ if (kind == HTML.Tag.IMG)
+ return new RestrictedImageView(elem);
+ }
+ return super.create( elem );
+ }
+
+ }
+
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedImageView.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedImageView.java
new file mode 100644
index 00000000..b1aa35db
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/html/RestrictedImageView.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui.html;
+
+import javax.swing.text.Element;
+import javax.swing.text.html.HTML;
+import javax.swing.text.html.ImageView;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+/**
+ * ImageViewer.refreshImage() (and loadImage()) is private :-(
+ */
+ public class RestrictedImageView extends ImageView {
+
+ public RestrictedImageView(Element elem) {
+ super(elem);
+ }
+
+// @Override
+// public Image getImage() {
+// int s = state;
+// if ((s & RELOAD_IMAGE_FLAG) != 0) {
+// refreshImage();
+// }
+// s = state;
+// if ((s & RELOAD_FLAG) != 0) {
+// synchronized(this) {
+// state = (state | RELOAD_FLAG) ^ RELOAD_FLAG;
+// }
+// setPropertiesFromAttributes();
+// }
+// return super.getImage();
+// }
+
+ /**
+ * check whether this URL corresponds to the data URI scheme
+ * (and the referenced content is directly included in the document).
+ * @return
+ */
+ private boolean isDataURI() {
+ String src = (String)getElement().getAttributes().
+ getAttribute(HTML.Attribute.SRC);
+ if (src == null) {
+ return false;
+ }
+
+ return src.toLowerCase().startsWith("data");
+ }
+ } \ No newline at end of file
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProvider.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProvider.java
new file mode 100644
index 00000000..8fb815b0
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProvider.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui.viewer;
+
+import java.awt.Font;
+
+/**
+ *
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public interface FontProvider {
+
+ /** will be replaced by more sophisticated font selection mechanism
+ * (see java.awt.Font int/String constants) */
+ String SANSMONO_FONT_RESOURCE = "DejaVuLGCSansMono.ttf";
+
+ /**
+ *
+ * @return
+ * @throws InterruptedException
+ * @throws FileNotFoundException if remote font file cannot be retrieved
+ */
+ Font getFont() throws FontProviderException;
+
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProviderException.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProviderException.java
new file mode 100644
index 00000000..5a6a277e
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/FontProviderException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2008 Federal Chancellery Austria and
+ * Graz University of Technology
+ *
+ * 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 at.gv.egiz.bku.gui.viewer;
+
+/**
+ * Encapsulates the reason why a font could not be loaded.
+ * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
+ */
+public class FontProviderException extends Exception {
+
+ public FontProviderException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java
new file mode 100644
index 00000000..5d64eb4f
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeFilter.java
@@ -0,0 +1,65 @@
+/*
+* Copyright 2008 Federal Chancellery Austria and
+* Graz University of Technology
+*
+* 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 at.gv.egiz.bku.gui.viewer;
+
+import java.io.File;
+import java.util.ResourceBundle;
+import javax.swing.filechooser.FileFilter;
+
+/**
+ *
+ * @author clemens
+ */
+class MimeFilter extends FileFilter {
+
+ protected String mimeType;
+ protected ResourceBundle messages;
+
+ public MimeFilter(String mimeType, ResourceBundle messages) {
+ this.mimeType = mimeType;
+ this.messages = messages;
+ }
+
+ @Override
+ public boolean accept(File f) {
+
+ if (f.isDirectory()) {
+ return true;
+ }
+ return MimeTypes.getExtension(mimeType).equalsIgnoreCase(getExtension(f));
+ }
+
+ private String getExtension(File f) {
+ String ext = null;
+ String s = f.getName();
+ int i = s.lastIndexOf('.');
+
+ if (i > 0 && i < s.length() - 1) {
+ ext = s.substring(i + 1).toLowerCase();
+ }
+ return ext;
+ }
+
+ @Override
+ public String getDescription() {
+ return messages.getString(MimeTypes.getDescriptionKey(mimeType));
+ }
+
+ public static String getExtension(String mimeType) {
+ return MimeTypes.getExtension(mimeType);
+ }
+} \ No newline at end of file
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java
new file mode 100644
index 00000000..4500fa71
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/MimeTypes.java
@@ -0,0 +1,53 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package at.gv.egiz.bku.gui.viewer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * @author clemens
+ */
+public class MimeTypes {
+
+ private static final Map<String , String> FILE_EXTENSIONS = new HashMap<String, String>() {{
+ put("application/msword", ".doc");
+ put("application/octet-stream", ".bin");
+ put("application/pdf", ".pdf");
+ put("application/xhtml+xml", ".xhtml");
+ put("text/html", ".html");
+ put("text/plain", ".txt");
+ put("text/xml", ".xml");
+ }};
+
+ private static final Map<String , String> DESCRIPTIONS = new HashMap<String, String>() {{
+ put("application/msword", "mimetype.desc.doc");
+ put("application/octet-stream", "mimetype.desc.bin");
+ put("application/pdf", "mimetype.desc.pdf");
+ put("application/xhtml+xml", "mimetype.desc.xhtml");
+ put("text/html", "mimetype.desc.html");
+ put("text/plain", "mimetype.desc.txt");
+ put("text/xml", "mimetype.desc.xml");
+ }};
+
+ public static String getExtension(String mimetype) {
+ if (FILE_EXTENSIONS.containsKey(mimetype)) {
+ return FILE_EXTENSIONS.get(mimetype);
+ }
+ return "";
+ }
+
+ /**
+ * @return bundle key to be resolved in message resource bundle
+ */
+ public static String getDescriptionKey(String mimetype) {
+ if (DESCRIPTIONS.containsKey(mimetype)) {
+ return DESCRIPTIONS.get(mimetype);
+ }
+ return "mimetype.desc.unknown";
+ }
+}
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java
new file mode 100644
index 00000000..3303d4ef
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/viewer/SecureViewerSaveDialog.java
@@ -0,0 +1,121 @@
+package at.gv.egiz.bku.gui.viewer;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import at.gv.egiz.bku.gui.BKUGUIFacade;
+import at.gv.egiz.stal.HashDataInput;
+
+public class SecureViewerSaveDialog {
+
+ protected static final Log log = LogFactory.getLog(SecureViewerSaveDialog.class);
+
+ public static void showSaveDialog(final HashDataInput hashDataInput, final ResourceBundle messages,
+ final ActionListener okListener, final String okCommand) {
+
+ log.debug("[" + Thread.currentThread().getName()
+ + "] scheduling save dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log
+ .debug("[" + Thread.currentThread().getName()
+ + "] show save dialog");
+
+ String userHome = System.getProperty("user.home");
+
+ JFileChooser fileDialog = new JFileChooser(userHome);
+ fileDialog.setMultiSelectionEnabled(false);
+ fileDialog.setDialogType(JFileChooser.SAVE_DIALOG);
+ fileDialog.setFileHidingEnabled(true);
+ fileDialog.setDialogTitle(messages
+ .getString(BKUGUIFacade.WINDOWTITLE_SAVE));
+ fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ String mimeType = hashDataInput.getMimeType();
+ MimeFilter mimeFilter = new MimeFilter(mimeType, messages);
+ fileDialog.setFileFilter(mimeFilter);
+ String filename = (hashDataInput.getFilename() != null) ?
+ hashDataInput.getFilename() :
+ messages.getString(BKUGUIFacade.SAVE_HASHDATAINPUT_PREFIX)
+ + MimeFilter.getExtension(mimeType);
+ fileDialog.setSelectedFile(new File(userHome, filename));
+
+ // parent contentPane -> placed over applet
+ switch (fileDialog.showSaveDialog(fileDialog)) {
+ case JFileChooser.APPROVE_OPTION:
+ File file = fileDialog.getSelectedFile();
+ String id = hashDataInput.getReferenceId();
+ if (file.exists()) {
+ String msgPattern = messages
+ .getString(BKUGUIFacade.MESSAGE_OVERWRITE);
+ int overwrite = JOptionPane.showConfirmDialog(fileDialog,
+ MessageFormat.format(msgPattern, file), messages
+ .getString(BKUGUIFacade.WINDOWTITLE_OVERWRITE),
+ JOptionPane.OK_CANCEL_OPTION);
+ if (overwrite != JOptionPane.OK_OPTION) {
+ break;
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("writing hashdata input " + id + " (" + mimeType
+ + ") to file " + file);
+ }
+ FileOutputStream fos = null;
+ try {
+ fos = new FileOutputStream(file);
+ BufferedOutputStream bos = new BufferedOutputStream(fos);
+ InputStream hdi = hashDataInput.getHashDataInput();
+ int b;
+ while ((b = hdi.read()) != -1) {
+ bos.write(b);
+ }
+ bos.flush();
+ bos.close();
+ } catch (IOException ex) {
+ log.error("Failed to write " + file + ": " + ex.getMessage());
+ log.debug(ex);
+ String errPattern = messages
+ .getString(BKUGUIFacade.ERR_WRITE_HASHDATA);
+ JOptionPane.showMessageDialog(fileDialog, MessageFormat.format(
+ errPattern, ex.getMessage()), messages
+ .getString(BKUGUIFacade.WINDOWTITLE_ERROR),
+ JOptionPane.ERROR_MESSAGE);
+ } finally {
+ try {
+ if (fos != null) {
+ fos.close();
+ }
+ } catch (IOException ex) {
+ }
+ }
+ break;
+ case JFileChooser.CANCEL_OPTION:
+ log.debug("cancelled save dialog");
+ break;
+ }
+ if (okListener != null) {
+ okListener.actionPerformed(new ActionEvent(fileDialog,
+ ActionEvent.ACTION_PERFORMED, okCommand));
+ }
+ }
+ });
+ }
+}