diff options
Diffstat (limited to 'BKUCommonGUI/src/main')
35 files changed, 3971 insertions, 0 deletions
diff --git a/BKUCommonGUI/src/main/java/META-INF/MANIFEST.MF b/BKUCommonGUI/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 00000000..5e949512 --- /dev/null +++ b/BKUCommonGUI/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0
+Class-Path:
+
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)); + } + } + }); + } +} diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java b/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java new file mode 100644 index 00000000..b9416845 --- /dev/null +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/stal/impl/ByteArrayHashDataInput.java @@ -0,0 +1,107 @@ +/* +* 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.stal.impl; + +import at.gv.egiz.stal.HashDataInput; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * + * @author clemens + */ +public class ByteArrayHashDataInput implements HashDataInput { + + private static final Log log = LogFactory.getLog(ByteArrayHashDataInput.class); + + protected byte[] hashData; + protected String id; + protected String mimeType; + protected String encoding; + protected String filename; + + public ByteArrayHashDataInput(byte[] hashData, String id, String mimeType, String encoding, String filename) { + if (hashData == null) { + throw new NullPointerException("HashDataInput not provided."); + } + this.hashData = hashData; + this.id = id; + this.mimeType = mimeType; + this.encoding = encoding; + this.filename = filename; + } + + /** + * caches the hashdata input's stream + * @param hdi to be cached + */ + public ByteArrayHashDataInput(HashDataInput hdi) { + if (hdi == null) { + throw new NullPointerException("HashDataInput not provided."); + } + InputStream is = hdi.getHashDataInput(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + byte[] buffer = new byte[1024]; + for (int i = is.read(buffer); i > -1; i = is.read(buffer)) { + baos.write(buffer, 0, i); + } + this.hashData = baos.toByteArray(); + } catch (IOException ex) { + log.error("Failed to cache provided HashDataInput: " + ex.getMessage(), ex); + this.hashData = new byte[0]; + } + this.id = hdi.getReferenceId(); + this.mimeType = hdi.getMimeType(); + this.encoding = hdi.getEncoding(); + } + + @Override + public String getReferenceId() { + return id; + } + + @Override + public String getMimeType() { + return mimeType; + } + + @Override + public InputStream getHashDataInput() { + return new ByteArrayInputStream(hashData); + } + + /** + * may be null + * @return + */ + @Override + public String getEncoding() { + return encoding; + } + + @Override + public String getFilename() { + return filename; + } + + +} diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties new file mode 100644 index 00000000..c09433de --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages.properties @@ -0,0 +1,109 @@ +# 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. + +title.welcome=<html>Willkommen</html> +title.insertcard=<html>Keine B\u00FCrgerkarte gefunden</html> +title.cardnotsupported=<html>Die Karte wird nicht unterst\u00FCtzt</html> +title.verify.pin=<html>Karte wird gelesen</html> +title.sign=<html>Signatur erstellen</html> +title.verify.pinpad=<html>PIN eingeben +title.error=<html>Fehler</html> +title.warning=<html>Achtung +title.entry.timeout=<html>Zeit\u00FCberschreitung</html> +title.retry=<html>Falsche PIN</html> +title.wait=<html>Bitte warten</html> +title.signature.data=<html>Signaturdaten</html> +windowtitle.save=Signaturdaten speichern +windowtitle.error=Fehler +windowtitle.savedir=Signaturdaten in Verzeichnis speichern +windowtitle.overwrite=Datei \u00FCberschreiben? +windowtitle.viewer=Signaturdaten +windowtitle.help=Hilfe zur B\u00FCrgerkarte + +# removed message.* prefix to reuse keys as help keys +welcome=<html>Bitte warten...</html> +wait=<html>Bitte warten...</html> +cardnotsupported=<html>Bitte die B\u00FCrgerkarte in den Kartenleser stecken</html> +insertcard=<html>Bitte die B\u00FCrgerkarte in den Kartenleser stecken</html> +enterpin=<html>{0} eingeben</html> +enterpin.pinpad=<html>PIN am Kartenleser eingeben</html> +enterpin.pinpad.direct=<html>{0} ({1} stellig) am Kartenleser eingeben</html> +hashdatalink=<html><a href=\"anzeige\">Signaturdaten anzeigen</a></html> +hashdatalink.tiny=<html><a href=\"anzeige\">Signaturdaten</a></html> +hashdatalink.focus=<html><a href=\"anzeige\">[Signaturdaten anzeigen]</a></html> +hashdatalink.tiny.focus=<html><a href=\"anzeige\">[Signaturdaten]</a></html> +#message.hashdata=<html>Hinweis: Dies ist eine Voransicht des zu signierenden Inhalts. F\u00FCr eine standardkonforme Darstellung siehe Hilfe (i).</html> +#message.hashdata=<html>Dies ist eine Voransicht des zu signierenden Inhaltes. F\u00FCr Details siehe Hilfe (i).</html> +#verwenden sie bitte die von ihrem System zur Verf\u00FCgung gestellte {0} Anwendung. +hashdatalist=<html>{0} Signaturdaten:</html> +hashdata.viewer=<html>Signaturdaten werden im Betrachter angezeigt +unsupported.mimetype=<html>Signaturdaten k\u00F6nnen nicht angezeigt werden +retries.last=<html>Letzter Versuch!</html> +retries=<html>Noch {0} Versuche</html> +retries.pinpad.last=<html>Eingabe wiederholen, letzter Versuch!</html> +retries.pinpad=<html>Eingabe wiederholen, noch {0} Versuche</html> +overwrite=<html>M\u00F6chten Sie das existierende Dokument {0} \u00FCberschreiben?</html> +help=<html>Hilfe zu {0}</html> + +warning.xhtml=<html>Hinweis: Dies ist eine Voransicht des zu signierenden Inhalts. F\u00FCr eine standardkonforme Darstellung siehe Hilfe (i).</html> +label.pin=<html>{0}:</html> +label.pinsize=<html>({0} stellig)</html> +button.ok=OK +button.cancel=Abbrechen +button.back=Zur\u00FCck +button.sign=Signieren +button.save=Speichern... +button.close=Schlie\u00DFen +mimetype.desc.xml=XML-Dateien (.xml) +mimetype.desc.html=HTML-Dateien (.html, .htm) +mimetype.desc.xhtml=XHTML-Dateien (.xhtml) +mimetype.desc.txt=Textdateien (.txt) +mimetype.desc.pdf=Adobe PDF-Dateien (.pdf) +mimetype.desc.bin=Bin\u00E4rdateien (.bin) +mimetype.desc.doc=Microsoft Word-Dateien (.doc) +mimetype.desc.unknown=Alle Dateien (.*) +save.hashdatainput.prefix=Signaturdaten +alt.help=Hilfe + +# Error Messages +error.no.hashdata=<html>Keine Signaturdaten verf\u00FCgbar: {0}</html> +error.display.hashdata=<html>Signaturdaten konnten nicht dargestellt werden: {0}</html> +error.write.hashdata=<html>Die Signaturdaten konnten nicht gespeichert werden: {0}</html> +error.invalid.hash=<html>Die Signaturdaten sind ung\u00FCltig: {0}</html> +error.ws.unreachable=<html>Der Server ist nicht erreichbar</html> +#error.ws.unreachable=<html>Das Web-Service ist nicht erreichbar: {0}</html> +error.pcsc=<html>Es konnte keine PC/SC Schnittstelle gefunden werden</html> +error.cardterminal=<html>Es konnte kein Smartcard-Leser gefunden werden</html> +error.unknown.param=<html>Ein Fehler trat auf: {0}</html> +error.unknown=<html>Ein Fehler trat auf</html> +error.test=<html>Fehler1 {0} - Fehler2 {1}</html> +error.card.locked=<html>B\u00FCrgerkarte ist gesperrt</html> +error.card.notactivated=<html>Die B\u00FCrgerkarte ist nicht aktiviert</html> +error.pin.timeout=<html>Zeit\u00FCberschreitung bei Eingabe der PIN</html> +error.viewer=<html>Der Inhalt kann nicht dargestellt werden: {0} +error.external.link=<html>Externer Link {0} wird nicht ge\u00F6ffnet</html> +error.config=<html>Fehlerhafte Konfiguration des Systems: {0}</html> + +# Help Topics +help.welcome=Startseite +help.wait=Bitte Warten Bildschirm +help.cardnotsupported=Nicht unterst\u00FCtzte B\u00FCrgerkarte +help.insertcard=Keine B\u00FCrgerkarte im Kartenleser +help.cardpin=Pineingabe +help.signpin=Signatur-Pineingabe +help.retry=Falsche Pin +help.hashdata=Signierte Inhalte +help.hashdatalist=Signierte Inhalte +help.hashdataviewer=Anzeige signierter Inhalte
\ No newline at end of file diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties new file mode 100644 index 00000000..4d86d21b --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/Messages_en.properties @@ -0,0 +1,107 @@ +# 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. + +title.welcome=<html>Welcome</html> +title.insertcard=<html>No citizen card found</html> +title.cardnotsupported=<html>This card is not supported</html> +title.verify.pin=<html>Reading card</html> +title.sign=<html>Create signature</html> +title.verify.pinpad=<html>Enter PIN +title.error=<html>Error</html> +title.warning=<html>Warning +title.entry.timeout=<html>Timeout</html> +title.retry=<html>Wrong PIN</html> +title.wait=<html>Please wait</html> +title.signature.data=<html>Signature data</html> +windowtitle.save=Save signature data +windowtitle.error=Error +windowtitle.savedir=Save signature data to directory +windowtitle.overwrite=Overwrite file? +windowtitle.viewer=Signature data +windowtitle.help=Citizen card help + +# removed message.* prefix to reuse keys as help keys +welcome=<html>Please wait...</html> +wait=<html>Please wait...</html> +insertcard=<html>Please insert your citizen card into the reader</html> +cardnotsupported=<html>Please insert your citizen card into the reader</html> +enterpin=<html>Enter {0}</html> +enterpin.pinpad=<html>Enter PIN on card reader pinpad</html> +enterpin.pinpad.direct=<html>Enter {0} ({1} digits) on card reader pinpad</html> +hashdatalink=<html><a href=\"anzeige\">Display signature data</a></html> +hashdatalink.tiny=<html><a href=\"anzeige\">signature data</a></html> +hashdatalink.focus=<html><a href=\"anzeige\">[Display signature data]</a></html> +hashdatalink.tiny.focus=<html><a href=\"anzeige\">[signature data]</a></html> +#message.hashdata=<html>Remark: This is a preview of the data to-be signed. For standards compliant display see help.</html> +hashdatalist=<html>{0} signature data objects:</html> +hashdata.viewer=<html>Signature data is being displayed in viewer +unsupported.mimetype=<html>Signature data cannot be displayed +retries.last=<html>Last try!</html> +retries=<html>{0} tries left</html> +retries.pinpad.last=<html>Re-enter pin, last try!</html> +retries.pinpad=<html>Re-enter pin, {0} tries left</html> +overwrite=<html>Overwrite {0}?</html> +help=<html>Help topic {0}</html> + +warning.xhtml=<html>Remark: This is a preview of the data to-be signed. For standard-compliant display see help.</html> +label.pin=<html>{0}:</html> +label.pinsize=<html>({0} digits)</html> +button.ok=OK +button.cancel=Cancel +button.back=Back +button.sign=Sign +button.save=Save... +button.close=Close +mimetype.desc.xml=XML-files (.xml) +mimetype.desc.html=HTML-files (.html, .htm) +mimetype.desc.xhtml=XHTML-files (.xhtml) +mimetype.desc.txt=Textfiles (.txt) +mimetype.desc.pdf=Adobe PDF-files (.pdf) +mimetype.desc.bin=Binary files (.bin) +mimetype.desc.doc=Microsoft Word-files (.doc) +mimetype.desc.unknown=All files (.*) +save.hashdatainput.prefix=signaturedata +alt.help=help + +# Error Messages +error.no.hashdata=<html>No signature data available: {0}</html> +error.display.hashdata=<html>Could not display signature data: {0}</html> +error.write.hashdata=<html>Could not save signature data: {0}</html> +error.invalid.hash=<html>Invalid signature data: {0}</html> +error.ws.unreachable=<html>Server unreachable</html> +#error.ws.unreachable=<html>Web-service unreachable: {0}</html> +error.pcsc=<html>No PC/SC interface for smartcard access provided</html> +error.cardterminal=<html>Could not find smartcard reader</html> +error.unknown.param=<html>An error occured: {0}</html> +error.unknown=<html>An error occured</html> +error.test=<html>Error1 {0} - Error2 {1}</html> +error.card.locked=<html>Citizen card is locked</html> +error.card.notactivated=<html>Citizen card not activated</html> +error.pin.timeout=<html>Timeout during PIN entry</html> +error.viewer=<html>Failed to display contents: {0} +error.external.link=<html>Cannot open external link {0}</html> +error.config=<html>Incorrect system configuration: {0}</html> + +# Help Topics +help.welcome=Welcome page +help.wait=Wait screen +help.cardnotsupported=Unsupported citizen card +help.insertcard=No citizen card found +help.cardpin=Pin entry +help.signpin=Signature pin entry +help.retry=Wrong Pin +help.hashdata=Signed contents +help.hashdatalist=Signed contents +help.hashdataviewer=Display of signed contents
\ No newline at end of file diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip128.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip128.png Binary files differnew file mode 100644 index 00000000..c36d8079 --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip128.png diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip16.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip16.png Binary files differnew file mode 100644 index 00000000..96b580e9 --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip16.png diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip24.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip24.png Binary files differnew file mode 100644 index 00000000..efd6dbeb --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip24.png diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip32.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip32.png Binary files differnew file mode 100644 index 00000000..e7efb020 --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip32.png diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip48.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip48.png Binary files differnew file mode 100644 index 00000000..491fbcac --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chip48.png diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chiperling105.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chiperling105.png Binary files differnew file mode 100644 index 00000000..eee4be4f --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/chiperling105.png diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/help.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/help.png Binary files differnew file mode 100644 index 00000000..d1c36c33 --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/help.png diff --git a/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/help_focus.png b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/help_focus.png Binary files differnew file mode 100644 index 00000000..d650bea2 --- /dev/null +++ b/BKUCommonGUI/src/main/resources/at/gv/egiz/bku/gui/help_focus.png |