summaryrefslogtreecommitdiff
path: root/BKUCommonGUI/src/main/java/at
diff options
context:
space:
mode:
Diffstat (limited to 'BKUCommonGUI/src/main/java/at')
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java40
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java603
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java293
-rw-r--r--BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java371
4 files changed, 759 insertions, 548 deletions
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
index 1043b6a1..4b079428 100644
--- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIFacade.java
@@ -43,6 +43,7 @@ public interface BKUGUIFacade {
public static final String MESSAGES_BUNDLE = "at/gv/egiz/bku/gui/Messages";
public static final String DEFAULT_BACKGROUND = "/images/BackgroundChipperling.png";
+ public static final String DEFAULT_ICON = "/images/ChipperlingLogo.png";
public static final String HELP_IMG = "/images/help.png";
public static final String HASHDATA_FONT = "Monospaced";
public static final Color ERROR_COLOR = Color.RED;
@@ -58,6 +59,7 @@ public interface BKUGUIFacade {
public static final String TITLE_WAIT = "title.wait";
public static final String TITLE_HASHDATA = "title.hashdata";
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";
@@ -102,42 +104,36 @@ public interface BKUGUIFacade {
public enum Style { tiny, simple, advanced };
-// public void init(Container contentPane, Locale locale, Style guiStyle, URL background, ActionListener helpListener);
-
/**
* BKUWorker needs to init signature card with locale
* @return
*/
public Locale getLocale();
-// public void showWelcomeDialog();
-
- /**
- *
- * @param waitMessage if null, a simple 'please wait' text is displayed
- */
-// public void showWaitDialog(String waitMessage);
-
-// public void showInsertCardDialog(ActionListener cancelListener, String actionCommand);
-
-// public void showCardNotSupportedDialog(ActionListener cancelListener, String actionCommand);
-
public void showCardPINDialog(PINSpec pinSpec, int numRetries,
ActionListener okListener, String okCommand,
ActionListener cancelListener, String cancelCommand);
-// public void showCardPINRetryDialog(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 hashdataListener, String hashdataCommand);
-
-// public void showSignaturePINRetryDialog(PINSpec pinSpec, int numRetries, ActionListener okListener, String okCommand, ActionListener cancelListener, String cancelCommand, ActionListener hashdataListener, String hashdataCommand);
+ public void showSignaturePINDialog(PINSpec pinSpec, int numRetries,
+ ActionListener signListener, String signCommand,
+ ActionListener cancelListener, String cancelCommand,
+ ActionListener viewerListener, String viewerCommand);
-// public void showPinpadSignaturePINDialog(PINSpec pinSpec, int retries);
+ public void showPinpadSignaturePINDialog(PINSpec pinSpec, int numRetries,
+ ActionListener viewerListener, String viewerCommand);
public char[] getPin();
- public void showSecureViewer(List<HashDataInput> signedReferences,
- ActionListener okListener, String okCommand);
+ /**
+ *
+ * @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);
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
index 928be249..a7eebbfd 100644
--- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/BKUGUIImpl.java
@@ -71,6 +71,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
protected HelpMouseListener helpListener;
+ protected SecureViewerDialog secureViewer;
protected Container contentPane;
protected ResourceBundle messages;
@@ -145,13 +146,16 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("initializing gui");
+ log.debug("initializing gui [" + Thread.currentThread().getName() + "]");
if (renderIconPanel) {
initIconPanel(background);
initContentPanel(null);
} else {
- initContentPanel(background);
+ initContentPanel((background == null) ?
+ getClass().getResource(DEFAULT_BACKGROUND) :
+ background
+ );
}
GroupLayout layout = new GroupLayout(contentPane);
@@ -159,15 +163,27 @@ public class BKUGUIImpl implements BKUGUIFacade {
if (renderIconPanel) {
layout.setHorizontalGroup(layout.createSequentialGroup()
- .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));
- layout.setVerticalGroup(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()
+ .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().addComponent(contentPanel));
- layout.setVerticalGroup(layout.createSequentialGroup().addComponent(contentPanel));
+ layout.setHorizontalGroup(layout.createSequentialGroup()
+ // left border
+ .addContainerGap()
+ .addComponent(contentPanel)
+ .addContainerGap());
+ layout.setVerticalGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(contentPanel)
+ .addContainerGap());
}
}
});
@@ -178,11 +194,12 @@ public class BKUGUIImpl implements BKUGUIFacade {
protected void initIconPanel(URL background) {
if (background == null) {
- background = getClass().getResource(DEFAULT_BACKGROUND);
+ background = getClass().getResource(DEFAULT_ICON);
}
if ("file".equals(background.getProtocol())) {
- log.warn("file:// background images not permitted: " + background);
- background = getClass().getResource(DEFAULT_BACKGROUND);
+ log.warn("file:// background images not permitted: " + background +
+ ", loading default background");
+ background = getClass().getResource(DEFAULT_ICON);
}
log.debug("loading icon panel background " + background);
@@ -194,26 +211,24 @@ public class BKUGUIImpl implements BKUGUIFacade {
iconPanel.setLayout(iconPanelLayout);
iconPanelLayout.setHorizontalGroup(
iconPanelLayout.createSequentialGroup()
- .addContainerGap()
.addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
- // no gap here (contentPanel has containerGap)
iconPanelLayout.setVerticalGroup(
iconPanelLayout.createSequentialGroup()
- .addContainerGap()
- .addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
+ .addComponent(iconLabel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE));
}
protected void initContentPanel(URL background) {
+// if (background == null) {
+// background = getClass().getResource(DEFAULT_BACKGROUND);
+// }
if (background == null) {
- background = getClass().getResource(DEFAULT_BACKGROUND);
- }
- if (background == null) {
+ log.debug("no background image set");
contentPanel = new JPanel();
} else {
if ("file".equals(background.getProtocol())) {
- log.warn("file:// background images not permitted: " + background);
+ log.warn("file:// background images not permitted: " + background +
+ ", loading default background");
background = getClass().getResource(DEFAULT_BACKGROUND);
}
log.debug("loading background " + background);
@@ -257,34 +272,29 @@ public class BKUGUIImpl implements BKUGUIFacade {
GroupLayout contentPanelLayout = new GroupLayout(contentPanel);
contentPanel.setLayout(contentPanelLayout);
- GroupLayout.ParallelGroup horizontalContentInner = contentPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING);
+ // align header, main and button to the right
+ GroupLayout.ParallelGroup horizontalContent =
+ contentPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING); //LEADING);
+ GroupLayout.SequentialGroup verticalContent =
+ contentPanelLayout.createSequentialGroup();
+
if (renderHeaderPanel) {
- horizontalContentInner
+ horizontalContent
.addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
+ verticalContent
+ .addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
+
}
- horizontalContentInner
+ horizontalContent
.addComponent(mainPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE);
- GroupLayout.SequentialGroup horizontalContentOuter = contentPanelLayout.createSequentialGroup();
- if (!renderIconPanel) {
- horizontalContentOuter
- .addContainerGap();
- }
- horizontalContentOuter
- .addGroup(horizontalContentInner)
- .addContainerGap();
- contentPanelLayout.setHorizontalGroup(horizontalContentOuter);
-
- GroupLayout.SequentialGroup verticalContent = contentPanelLayout.createSequentialGroup();
- verticalContent.addContainerGap();
- if (renderHeaderPanel) {
- verticalContent.addComponent(headerPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED);
- }
- verticalContent.addComponent(mainPanel, 0, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(buttonPanel, 0, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
- .addContainerGap();
+ .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);
}
@@ -521,7 +531,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show card-pin dialog");
+ log.debug("show card-pin dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -653,7 +663,6 @@ public class BKUGUIImpl implements BKUGUIFacade {
buttonPanel.setLayout(buttonPanelLayout);
GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
GroupLayout.Group buttonVertical;
@@ -701,6 +710,128 @@ public class BKUGUIImpl implements BKUGUIFacade {
// }
@Override
+ public void showPinpadSignaturePINDialog(final PINSpec pinSpec, final int numRetries,
+// final ActionListener cancelListener, final String cancelCommand,
+ final ActionListener hashdataListener, final String hashdataCommand) {
+
+ log.debug("scheduling pinpad signature-pin dialog");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("show pinpad signature-pin dialog [" + Thread.currentThread().getName() + "]");
+
+ mainPanel.removeAll();
+ buttonPanel.removeAll();
+
+ if (renderHeaderPanel) {
+ if (numRetries < 0) {
+ titleLabel.setText(getMessage(TITLE_SIGN));
+ } else {
+ titleLabel.setText(getMessage(TITLE_RETRY));
+ }
+ }
+
+ 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.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);
+ }
+ });
+ helpListener.setHelpTopic(HELP_SIGNPIN);
+ } else {
+ String retryPattern;
+ if (numRetries < 2) {
+ retryPattern = getMessage(MESSAGE_LAST_RETRY);
+ } else {
+ retryPattern = getMessage(MESSAGE_RETRIES);
+ }
+ 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);
+ helpListener.setHelpTopic(HELP_RETRY);
+ }
+
+ String pinSize = String.valueOf(pinSpec.getMinLength());
+ if (pinSpec.getMinLength() != pinSpec.getMaxLength()) {
+ pinSize += "-" + pinSpec.getMaxLength();
+ }
+
+ String msgPattern = getMessage(MESSAGE_ENTERPIN_PINPAD);
+ String msg = MessageFormat.format(msgPattern, new Object[] {
+ pinSpec.getLocalizedName(), pinSize });
+
+ 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(helpLabel);
+ infoVertical
+ .addComponent(helpLabel);
+ }
+
+ mainPanelLayout.setHorizontalGroup(
+ mainPanelLayout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(infoHorizontal)
+ .addComponent(msgLabel));
+
+ mainPanelLayout.setVerticalGroup(
+ mainPanelLayout.createSequentialGroup()
+ .addGroup(infoVertical)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(msgLabel));
+
+ //no cancel button (cancel via pinpad)
+// 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);
+//
+// GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
+// buttonPanel.setLayout(buttonPanelLayout);
+//
+// GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup()
+// .addComponent(cancelButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
+// GroupLayout.SequentialGroup buttonVertical = buttonPanelLayout.createSequentialGroup()
+// .addComponent(cancelButton);
+//
+// buttonPanelLayout.setHorizontalGroup(buttonHorizontal);
+// buttonPanelLayout.setVerticalGroup(buttonVertical);
+// }
+
+ contentPanel.validate();
+ }
+ });
+ }
+
+ @Override
public void showSignaturePINDialog(final PINSpec pinSpec, final int numRetries,
final ActionListener signListener, final String signCommand,
final ActionListener cancelListener, final String cancelCommand,
@@ -717,7 +848,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show signature-pin dialog");
+ log.debug("show signature-pin dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -730,6 +861,38 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
}
+ 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.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);
+ }
+ });
+ helpListener.setHelpTopic(HELP_SIGNPIN);
+ } else {
+ String retryPattern;
+ if (numRetries < 2) {
+ retryPattern = getMessage(MESSAGE_LAST_RETRY);
+ } else {
+ retryPattern = getMessage(MESSAGE_RETRIES);
+ }
+ 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);
+ helpListener.setHelpTopic(HELP_RETRY);
+ }
+
JButton signButton = new JButton();
signButton.setFont(signButton.getFont().deriveFont(signButton.getFont().getStyle() & ~java.awt.Font.BOLD));
signButton.setText(getMessage(BUTTON_SIGN));
@@ -765,46 +928,14 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
pinsizeLabel.setText(MessageFormat.format(pinsizePattern, new Object[]{pinSize}));
- 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.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);
- }
- });
- helpListener.setHelpTopic(HELP_SIGNPIN);
- } else {
- String retryPattern;
- if (numRetries < 2) {
- retryPattern = getMessage(MESSAGE_LAST_RETRY);
- } else {
- retryPattern = getMessage(MESSAGE_RETRIES);
- }
- 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);
- helpListener.setHelpTopic(HELP_RETRY);
- }
-
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)
@@ -814,8 +945,8 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
// align pinfield and pinsize to the right
- GroupLayout.ParallelGroup pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING);
- GroupLayout.Group pinVertical;
+ GroupLayout.Group pinHorizontal = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.TRAILING);
+ GroupLayout.SequentialGroup pinVertical = mainPanelLayout.createSequentialGroup();
if (pinLabelPos == PinLabelPosition.ABOVE) {
pinHorizontal
@@ -823,20 +954,25 @@ public class BKUGUIImpl implements BKUGUIFacade {
.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 = mainPanelLayout.createSequentialGroup()
+ pinVertical
.addComponent(signPinLabel)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(pinField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE);
- } else {
+ .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 = mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
- .addComponent(signPinLabel)
- .addComponent(pinField);
+ pinVertical
+ .addGroup(mainPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(signPinLabel)
+ .addComponent(pinField))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(pinsizeLabel);
}
mainPanelLayout.setHorizontalGroup(
@@ -848,18 +984,14 @@ public class BKUGUIImpl implements BKUGUIFacade {
mainPanelLayout.createSequentialGroup()
.addGroup(infoVertical)
.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(pinVertical)
- .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(pinsizeLabel));
+ .addGroup(pinVertical));
GroupLayout buttonPanelLayout = new GroupLayout(buttonPanel);
buttonPanel.setLayout(buttonPanelLayout);
- GroupLayout.SequentialGroup buttonHorizontal = buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(signButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
+ 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));
@@ -868,17 +1000,19 @@ public class BKUGUIImpl implements BKUGUIFacade {
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);
+ .addComponent(cancelButton);
} else {
+ buttonHorizontal
+ .addComponent(signButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE);
buttonVertical = buttonPanelLayout.createSequentialGroup()
.addComponent(signButton);
}
-
+
buttonPanelLayout.setHorizontalGroup(buttonHorizontal);
buttonPanelLayout.setVerticalGroup(buttonVertical);
@@ -951,7 +1085,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show message dialog");
+ log.debug("show message dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -1011,7 +1145,6 @@ public class BKUGUIImpl implements BKUGUIFacade {
buttonPanelLayout.setHorizontalGroup(
buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(okButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
buttonPanelLayout.setVerticalGroup(
buttonPanelLayout.createSequentialGroup()
@@ -1084,68 +1217,69 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
return null;
}
+
+
+ ////////////////////////////////////////////////////////////////////////////
+ // SECURE VIEWER
+ ////////////////////////////////////////////////////////////////////////////
+
/**
- * TODO handle multiple references in HashDataViewer
* @param signedReferences
- * @param okListener
+ * @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> signedReferences,
- final ActionListener okListener,
- final String okCommand) {
-
- if (signedReferences == null) {
- showErrorDialog(getMessage(ERR_NO_HASHDATA), new Object[] {"No SignedReferences provided"}, okListener, okCommand);
- return;
- }
+ public void showSecureViewer(final List<HashDataInput> dataToBeSigned,
+ final ActionListener backListener, final String backCommand) {
- if (signedReferences.size() == 1) {
+ if (dataToBeSigned == null) {
+ showErrorDialog(getMessage(ERR_NO_HASHDATA),
+ new Object[] {"no signature data provided"},
+ backListener, backCommand);
+ } else if (dataToBeSigned.size() == 1) {
try {
- log.debug("scheduling hashdata viewer");
+ log.debug("scheduling secure viewer");
- SwingUtilities.invokeAndWait(new Runnable() {
+ SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
- ActionListener saveHashDataListener = new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- HashDataInput hdi = signedReferences.get(0);
- showSaveHashDataInputDialog(Collections.singletonList(hdi), okListener, okCommand);
- }
- };
- showHashDataViewer(signedReferences.get(0), saveHashDataListener, "save");
+ showSecureViewer(dataToBeSigned.get(0));
}
});
- } catch (InterruptedException ex) {
- log.error("Failed to display HashDataViewer: " + ex.getMessage());
- } catch (InvocationTargetException ex) {
- log.error("Failed to display HashDataViewer: " + ex.getMessage());
+ } catch (Exception ex) { //InterruptedException InvocationTargetException
+ log.error("Failed to display secure viewer: " + ex.getMessage());
+ log.trace(ex);
+ showErrorDialog(ERR_UNKNOWN, null, backListener, backCommand);
}
} else {
- showSignedReferencesListDialog(signedReferences, okListener, okCommand);
+ showSignedReferencesListDialog(dataToBeSigned, backListener, backCommand);
}
}
/**
* has to be called from event dispatcher thread
+ * This method blocks until the dialog's close button is pressed.
* @param hashDataText
* @param saveListener
* @param saveCommand
*/
- private void showHashDataViewer(final HashDataInput hashDataInput, final ActionListener saveListener, final String saveCommand) {
+ private void showSecureViewer(HashDataInput dataToBeSigned) {
- log.debug("show hashdata viewer");
-
- ActionListener l = helpListener.getActionListener();
- HashDataViewer.showHashDataInput(contentPane, hashDataInput, messages, saveListener, saveCommand, l);
+ log.debug("show secure viewer [" + Thread.currentThread().getName() + "]");
+ if (secureViewer == null) {
+ secureViewer = new SecureViewerDialog(null, messages,
+ helpListener.getActionListener());
+ }
+ secureViewer.setContent(dataToBeSigned);
+ log.trace("show secure viewer returned");
}
- private void showSignedReferencesListDialog(final List<HashDataInput> signedReferences, final ActionListener backListener, final String backCommand) {
+ private void showSignedReferencesListDialog(final List<HashDataInput> signedReferences,
+ final ActionListener backListener, final String backCommand) {
log.debug("scheduling signed references list dialog");
@@ -1154,7 +1288,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
@Override
public void run() {
- log.debug("show signed references list dialog");
+ log.debug("show signed references list dialog [" + Thread.currentThread().getName() + "]");
mainPanel.removeAll();
buttonPanel.removeAll();
@@ -1202,13 +1336,7 @@ public class BKUGUIImpl implements BKUGUIFacade {
int selectionIdx = lsm.getMinSelectionIndex();
if (selectionIdx >= 0) {
final HashDataInput selection = signedReferences.get(selectionIdx);
- showHashDataViewer(selection, new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- showSaveHashDataInputDialog(Collections.singletonList(selection), null, null);
- }
- }, "save");
+ showSecureViewer(selection);
}
}
});
@@ -1255,9 +1383,8 @@ public class BKUGUIImpl implements BKUGUIFacade {
buttonPanel.setLayout(buttonPanelLayout);
buttonPanelLayout.setHorizontalGroup(buttonPanelLayout.createSequentialGroup()
- .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(backButton, GroupLayout.PREFERRED_SIZE, buttonSize, GroupLayout.PREFERRED_SIZE));
- buttonPanelLayout.setVerticalGroup(buttonPanelLayout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ buttonPanelLayout.setVerticalGroup(buttonPanelLayout.createSequentialGroup()
.addComponent(backButton));
contentPanel.validate();
@@ -1266,96 +1393,101 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
/**
- *
- * @param signedRefs
* @param okListener may be null
- * @param okCommand
*/
- private void showSaveHashDataInputDialog(final List<HashDataInput> signedRefs, final ActionListener okListener, final String okCommand) {
-
- log.debug("scheduling save hashdatainput dialog");
-
- SwingUtilities.invokeLater(new Runnable() {
+// private void showSaveDialog(final List<HashDataInput> signedRefs,
+// final ActionListener okListener, final String okCommand) {
+//
+// log.debug("scheduling save dialog");
+//
+// SwingUtilities.invokeLater(new Runnable() {
+//
+// @Override
+// public void run() {
+//
+// log.debug("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);
+// if (signedRefs.size() == 1) {
+// fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVE));
+// fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
+// String mimeType = signedRefs.get(0).getMimeType();
+// MimeFilter mimeFilter = new MimeFilter(mimeType, messages);
+// fileDialog.setFileFilter(mimeFilter);
+// String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + MimeFilter.getExtension(mimeType);
+// fileDialog.setSelectedFile(new File(userHome, filename));
+// } else {
+// fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVEDIR));
+// fileDialog.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+// }
+//
+// //parent contentPane -> placed over applet
+// switch (fileDialog.showSaveDialog(fileDialog)) {
+// case JFileChooser.APPROVE_OPTION:
+// File f = fileDialog.getSelectedFile();
+// for (HashDataInput hashDataInput : signedRefs) {
+// String mimeType = hashDataInput.getMimeType();
+// String id = hashDataInput.getReferenceId();
+// File file;
+// if (f.isDirectory()) {
+// String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + '_' + id + MimeFilter.getExtension(mimeType);
+// file = new File(f, filename);
+// } else {
+// file = f;
+// }
+// if (file.exists()) {
+// String ovrwrt = getMessage(MESSAGE_OVERWRITE);
+// int overwrite = JOptionPane.showConfirmDialog(fileDialog, MessageFormat.format(ovrwrt, file), getMessage(WINDOWTITLE_OVERWRITE), JOptionPane.OK_CANCEL_OPTION);
+// if (overwrite != JOptionPane.OK_OPTION) {
+// continue;
+// }
+// }
+// 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());
+// showErrorDialog(ERR_WRITE_HASHDATA, new Object[] {ex.getMessage()}, null, null);
+// ex.printStackTrace();
+// } finally {
+// try {
+// 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));
+// }
+// }
+// });
+// }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // UTILITY METHODS
+ ////////////////////////////////////////////////////////////////////////////
- @Override
- public void run() {
-
- log.debug("show save hashdatainput dialog");
-
- String userHome = System.getProperty("user.home");
-
- JFileChooser fileDialog = new JFileChooser(userHome);
- fileDialog.setMultiSelectionEnabled(false);
- fileDialog.setDialogType(JFileChooser.SAVE_DIALOG);
- fileDialog.setFileHidingEnabled(true);
- if (signedRefs.size() == 1) {
- fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVE));
- fileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
- String mimeType = signedRefs.get(0).getMimeType();
- MimeFilter mimeFilter = new MimeFilter(mimeType, messages);
- fileDialog.setFileFilter(mimeFilter);
- String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + MimeFilter.getExtension(mimeType);
- fileDialog.setSelectedFile(new File(userHome, filename));
- } else {
- fileDialog.setDialogTitle(getMessage(WINDOWTITLE_SAVEDIR));
- fileDialog.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
- }
-
- //parent contentPane -> placed over applet
- switch (fileDialog.showSaveDialog(fileDialog)) {
- case JFileChooser.APPROVE_OPTION:
- File f = fileDialog.getSelectedFile();
- for (HashDataInput hashDataInput : signedRefs) {
- String mimeType = hashDataInput.getMimeType();
- String id = hashDataInput.getReferenceId();
- File file;
- if (f.isDirectory()) {
- String filename = getMessage(SAVE_HASHDATAINPUT_PREFIX) + '_' + id + MimeFilter.getExtension(mimeType);
- file = new File(f, filename);
- } else {
- file = f;
- }
- if (file.exists()) {
- String ovrwrt = getMessage(MESSAGE_OVERWRITE);
- int overwrite = JOptionPane.showConfirmDialog(fileDialog, MessageFormat.format(ovrwrt, file), getMessage(WINDOWTITLE_OVERWRITE), JOptionPane.OK_CANCEL_OPTION);
- if (overwrite != JOptionPane.OK_OPTION) {
- continue;
- }
- }
- if (log.isDebugEnabled()) {
- log.debug("Writing HashDataInput " + 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 HashDataInput to file " + file + ": " + ex.getMessage());
- showErrorDialog(ERR_WRITE_HASHDATA, new Object[] {ex.getMessage()}, null, null);
- ex.printStackTrace();
- } finally {
- try {
- fos.close();
- } catch (IOException ex) {
- }
- }
- }
- }
- log.debug("done saving hashdatainput");
- if (okListener != null) {
- okListener.actionPerformed(new ActionEvent(fileDialog, ActionEvent.ACTION_PERFORMED, okCommand));
- }
- }
- });
- }
-
private void registerHelpListener(ActionListener helpListener) {
if (helpListener != null) {
this.helpListener = new HelpMouseListener(helpListener);
@@ -1371,6 +1503,11 @@ public class BKUGUIImpl implements BKUGUIFacade {
}
}
+
+ ////////////////////////////////////////////////////////////////////////////
+ // INITIALIZERS (MAY BE OVERRIDDEN BY SUBCLASSES)
+ ////////////////////////////////////////////////////////////////////////////
+
/**
* Called from constructor.
* Subclasses may override this method to ensure the message bundle is loaded
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java
deleted file mode 100644
index 6c097b2a..00000000
--- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/HashDataViewer.java
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * 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.html.RestrictedHTMLEditorKit;
-import at.gv.egiz.stal.HashDataInput;
-import java.awt.Component;
-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.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.Charset;
-import java.text.MessageFormat;
-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.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.LayoutStyle;
-import javax.swing.text.Document;
-import javax.swing.text.EditorKit;
-import javax.swing.text.StyledEditorKit;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- *
- * @author Clemens Orthacker <clemens.orthacker@iaik.tugraz.at>
- */
-public class HashDataViewer extends JDialog
- implements ActionListener {
-
- public static final String PLAINTEXT_FONT = "Monospaced";
- protected static final Log log = LogFactory.getLog(HashDataViewer.class);
-
- private static HashDataViewer dialog;
-
- protected ResourceBundle messages;
-
- /**
- *
- * @param signedReferences currently, only one hashdata input (the first in the list) is displayed
- */
- public static void showHashDataInput(HashDataInput hashDataInput,
- ResourceBundle messages,
- ActionListener saveListener,
- String saveCommand,
- ActionListener helpListener) {
- showHashDataInput(null, hashDataInput, messages, saveListener, saveCommand, helpListener);
- }
-
- /**
- *
- * @param frameComp owner
- */
- public static void showHashDataInput(Component frameComp,
- HashDataInput hashDataInput,
- ResourceBundle messages,
- ActionListener saveListener,
- String saveCommand,
- ActionListener helpListener) {
-
- Frame frame = null;
- if (frameComp != null) {
- JOptionPane.getFrameForComponent(frameComp);
- }
- dialog = new HashDataViewer(frame,
- messages,
- hashDataInput,
- saveListener,
- saveCommand,
- helpListener);
- dialog.setVisible(true);
- }
-
- private HashDataViewer(Frame frame,
- ResourceBundle messages,
- HashDataInput hashDataInput,
- ActionListener saveListener,
- String saveCommand,
- ActionListener helpListener) {
- super(frame, messages.getString(BKUGUIFacade.WINDOWTITLE_VIEWER), true);
- this.messages = messages;
-
- Charset cs;
- if (hashDataInput.getEncoding() == null) {
- cs = Charset.forName("UTF-8");
- } else {
- try {
- cs = Charset.forName(hashDataInput.getEncoding());
- } catch (Exception ex) {
- log.debug("charset " + hashDataInput.getEncoding() + " not supported, assuming UTF-8: " + ex.getMessage());
- cs = Charset.forName("UTF-8");
- }
- }
-
-
- InputStreamReader isr = new InputStreamReader(hashDataInput.getHashDataInput(), cs);
- Reader content = new BufferedReader(isr);
-
- JPanel hashDataPanel = createViewerPanel(content,
- hashDataInput.getMimeType(),
- helpListener);
- JPanel buttonPanel = createButtonPanel(saveListener, saveCommand);
- initContentPane(new Dimension(600, 400), hashDataPanel, 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());
- }
-
- /**
- *
- * @param messages
- * @param content
- * @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 helpListener may be null
- * @return
- */
- private JPanel createViewerPanel(Reader content,
- String mimeType,
- final ActionListener helpListener) {
-
- if (mimeType == null) {
- mimeType = "text/plain";
- }
- log.debug("viewer dialog: " + mimeType);
-
- JEditorPane viewer = new JEditorPane();
- viewer.setEditable(false);
- viewer.setContentType(mimeType);
-
- if ("text/plain".equals(mimeType)) {
- viewer.setEditorKit(new StyledEditorKit());
- viewer.setFont(new Font(PLAINTEXT_FONT, viewer.getFont().getStyle(), viewer.getFont().getSize()));
-// } else if ("text/html".equals(mimeType)) {
-// viewer.setEditorKit(new RestrictedHTMLEditorKit());
- } else if ("application/xhtml+xml".equals(mimeType)) {
- viewer.setContentType("text/html");
- }
-
- EditorKit editorKit = viewer.getEditorKit();
- Document document = editorKit.createDefaultDocument();
-// document.putProperty("IgnoreCharsetDirective", new Boolean(true));
-
- try {
- viewer.read(content, document);
- content.close();
- } catch (Exception ex) {
- log.error(ex.getMessage(), ex);
- String p = messages.getString(BKUGUIFacade.ERR_VIEWER);
- viewer.setText(MessageFormat.format(p, ex.getMessage()));
- }
-
- JScrollPane scrollPane = new JScrollPane(viewer);
- scrollPane.setPreferredSize(viewer.getPreferredSize());
- scrollPane.setAlignmentX(LEFT_ALIGNMENT);
- viewer.setCaretPosition(0);
-
- 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);
-
- if ("application/xhtml+xml".equals(mimeType)) {
- JLabel viewerLabel = new JLabel();
- viewerLabel.setText(messages.getString(BKUGUIFacade.WARNING_XHTML));
- viewerLabel.setFont(viewerLabel.getFont().deriveFont(viewerLabel.getFont().getStyle() | java.awt.Font.BOLD));
- viewerLabel.setLabelFor(viewer);
-
- infoHorizontal.addComponent(viewerLabel);
- infoVertical.addComponent(viewerLabel);
- }
-
- if (helpListener != null) {
- JLabel helpLabel = new JLabel();
- 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.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;
- }
-
- private JPanel createButtonPanel(ActionListener saveListener, String saveCommand) {
- JButton closeButton = new JButton();
- closeButton.setText(messages.getString(BKUGUIFacade.BUTTON_CLOSE));
- closeButton.addActionListener(this);
-
- JButton saveButton = new JButton();
- saveButton.setText(messages.getString(BKUGUIFacade.BUTTON_SAVE));
- saveButton.setActionCommand(saveCommand);
- saveButton.addActionListener(saveListener);
-
- 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;
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- HashDataViewer.dialog.setVisible(false);
- }
-}
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..6a16306b
--- /dev/null
+++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/SecureViewerDialog.java
@@ -0,0 +1,371 @@
+/*
+ * 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.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.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.BufferedOutputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.text.MessageFormat;
+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.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.LayoutStyle;
+import javax.swing.SwingUtilities;
+import javax.swing.text.Document;
+import javax.swing.text.EditorKit;
+import javax.swing.text.StyledEditorKit;
+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 implements ActionListener {
+
+ public static final String PLAINTEXT_FONT = "Monospaced";
+ public static final Dimension VIEWER_DIMENSION = new Dimension(600, 400);
+ 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
+
+ /**
+ * 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 static void showDataToBeSigned(HashDataInput dataToBeSigned,
+// ResourceBundle messages,
+// ActionListener saveListener, String saveCommand,
+// ActionListener helpListener) {
+//
+//// Frame ownerFrame = (owner != null) ?
+//// JOptionPane.getFrameForComponent(owner) :
+//// null;
+// dialog = new SecureViewerDialog(null, messages,
+// saveListener, saveCommand, helpListener);
+// dialog.setContent(dataToBeSigned);
+// dialog.setVisible(true);
+// }
+ public SecureViewerDialog(Frame owner, ResourceBundle messages,
+// ActionListener saveListener, String saveCommand,
+ ActionListener helpListener) {
+ super(owner, messages.getString(BKUGUIFacade.WINDOWTITLE_VIEWER), true);
+ this.messages = messages;
+
+ initContentPane(VIEWER_DIMENSION,
+ createViewerPanel(helpListener),
+ createButtonPanel()); //saveListener, saveCommand));
+
+ 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);
+
+ 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) {
+ JLabel helpLabel = new JLabel();
+ 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.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) {
+
+ this.content = 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);
+
+ if ("text/plain".equals(mimeType)) {
+ viewer.setEditorKit(new StyledEditorKit());
+ viewer.setFont(new Font(PLAINTEXT_FONT, viewer.getFont().getStyle(), viewer.getFont().getSize()));
+// } else if ("text/html".equals(mimeType)) {
+// viewer.setEditorKit(new RestrictedHTMLEditorKit());
+ } else if ("application/xhtml+xml".equals(mimeType)) {
+ viewer.setContentType("text/html");
+ }
+
+ EditorKit editorKit = viewer.getEditorKit();
+ Document document = editorKit.createDefaultDocument();
+// document.putProperty("IgnoreCharsetDirective", new Boolean(true));
+
+ try {
+ 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 (IllegalCharsetNameException ex) {
+// } catch (UnsupportedCharsetException ex) {
+ } catch (Exception ex) {
+ log.error(ex.getMessage(), ex);
+ String p = messages.getString(BKUGUIFacade.ERR_VIEWER);
+ 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("");
+ }
+
+ setVisible(true);
+ }
+
+ private JPanel createButtonPanel() { //ActionListener saveListener, String saveCommand) {
+ JButton closeButton = new JButton();
+ closeButton.setText(messages.getString(BKUGUIFacade.BUTTON_CLOSE));
+ closeButton.setActionCommand("close");
+ closeButton.addActionListener(this);
+
+ JButton saveButton = new JButton();
+ saveButton.setText(messages.getString(BKUGUIFacade.BUTTON_SAVE));
+ saveButton.setActionCommand("save");
+ saveButton.addActionListener(this);
+
+ 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;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if ("close".equals(e.getActionCommand())) {
+// SecureViewerDialog.dialog.setVisible(false);
+ log.trace("closing secure viewer");
+ setVisible(false);
+ log.trace("secure viewer closed");
+ } else if ("save".equals(e.getActionCommand())) {
+ log.trace("display secure viewer save dialog");
+ showSaveDialog(content, null, null);
+ log.trace("done secure viewer save");
+ } else {
+ log.warn("unknown action command " + e.getActionCommand());
+ }
+ }
+
+ private void showSaveDialog(final HashDataInput hashDataInput,
+ final ActionListener okListener, final String okCommand) {
+
+ log.debug("scheduling save dialog [" + Thread.currentThread().getName() + "]");
+
+ SwingUtilities.invokeLater(new Runnable() {
+
+ @Override
+ public void run() {
+
+ log.debug("show save dialog [" + Thread.currentThread().getName() + "]");
+
+ 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 = 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) {
+ return;
+ }
+ }
+ 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));
+ }
+ }
+ });
+ }
+}