DialogAbout.java
/*******************************************************************************
* Copyhacked (H) 2012-2025.
* This program and the accompanying materials
* are made available under no term at all, use it like
* you want, but share and discuss it
* every time possible with every body.
*
* Contributors:
* ron190 at ymail dot com - initial implementation
******************************************************************************/
package com.jsql.view.swing.dialog;
import com.jsql.util.I18nUtil;
import com.jsql.util.LogLevelUtil;
import com.jsql.util.StringUtil;
import com.jsql.view.swing.popupmenu.JPopupMenuText;
import com.jsql.view.swing.util.I18nViewUtil;
import com.jsql.view.swing.util.MediatorHelper;
import com.jsql.view.swing.util.UiUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.awt.event.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/**
* A dialog displaying information about jSQL.
*/
public class DialogAbout extends JDialog {
/**
* Log4j logger sent to view.
*/
private static final Logger LOGGER = LogManager.getRootLogger();
/**
* Button receiving focus.
*/
private JButton buttonClose = null;
/**
* Create a dialog about project general information.
*/
public DialogAbout() {
super(MediatorHelper.frame(), I18nUtil.valueByKey("ABOUT_WINDOW_TITLE") +" "+ StringUtil.APP_NAME, Dialog.ModalityType.MODELESS);
I18nViewUtil.addComponentForKey("ABOUT_WINDOW_TITLE", this);
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
this.setIconImages(UiUtil.getIcons()); // Define a small and large app icon
ActionListener escapeListener = actionEvent -> this.dispose(); // Action for ESCAPE key
this.getRootPane().registerKeyboardAction(
escapeListener,
KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
JComponent.WHEN_IN_FOCUSED_WINDOW
);
this.setLayout(new BorderLayout());
Container dialogPane = this.getContentPane();
JPanel lastLine = this.initLastLine(escapeListener);
var labelIcon = new JLabel(UiUtil.APP_MIDDLE.getIcon());
labelIcon.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
dialogPane.add(labelIcon, BorderLayout.WEST);
dialogPane.add(lastLine, BorderLayout.SOUTH);
final JEditorPane text = this.initEditorPane(); // Contact info, use HTML text
dialogPane.add(new JScrollPane(text), BorderLayout.CENTER);
this.initDialog();
}
private JPanel initLastLine(ActionListener escapeListener) {
final var buttonWebpage = new JButton(I18nUtil.valueByKey("ABOUT_WEBPAGE"));
I18nViewUtil.addComponentForKey("ABOUT_WEBPAGE", buttonWebpage);
buttonWebpage.addActionListener(ev -> {
try {
Desktop.getDesktop().browse(new URI(MediatorHelper.model().getMediatorUtils().getPropertiesUtil().getProperty("github.url")));
} catch (IOException | URISyntaxException | UnsupportedOperationException e) {
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Browsing to Url failed", e);
}
});
this.buttonClose = new JButton(I18nUtil.valueByKey("ABOUT_CLOSE"));
I18nViewUtil.addComponentForKey("ABOUT_CLOSE", this.buttonClose);
this.buttonClose.addActionListener(escapeListener);
var lastLine = new JPanel();
lastLine.setLayout(new BoxLayout(lastLine, BoxLayout.LINE_AXIS));
lastLine.setBorder(UiUtil.BORDER_5PX);
lastLine.add(buttonWebpage);
lastLine.add(Box.createGlue());
lastLine.add(this.buttonClose);
return lastLine;
}
private JEditorPane initEditorPane() {
var editorPane = new JEditorPane();
// Fix #82540: NoClassDefFoundError on setText()
try (
InputStream inputStream = DialogAbout.class.getClassLoader().getResourceAsStream("swing/about.htm");
var inputStreamReader = new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8);
var reader = new BufferedReader(inputStreamReader)
) {
editorPane.setContentType("text/html");
var result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
editorPane.setText(result.toString().replace(
"%JSQLVERSION%",
MediatorHelper.model().getPropertiesUtil().getVersionJsql()
));
} catch (NoClassDefFoundError | IOException e) {
LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
}
editorPane.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
editorPane.requestFocusInWindow();
}
});
editorPane.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent focusEvent) {
editorPane.getCaret().setVisible(true);
editorPane.getCaret().setSelectionVisible(true);
}
});
editorPane.setDragEnabled(true);
editorPane.setEditable(false);
editorPane.getCaret().setBlinkRate(0);
editorPane.setCaretPosition(0);
editorPane.setComponentPopupMenu(new JPopupMenuText(editorPane));
editorPane.addHyperlinkListener(linkEvent -> {
if (HyperlinkEvent.EventType.ACTIVATED.equals(linkEvent.getEventType())) {
try {
Desktop.getDesktop().browse(linkEvent.getURL().toURI());
} catch (IOException | URISyntaxException | UnsupportedOperationException e) {
LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Browsing to Url failed", e);
}
}
});
return editorPane;
}
/**
* Set back default setting for About frame.
*/
public final void initDialog() {
this.setSize(560, 400);
this.setLocationRelativeTo(MediatorHelper.frame());
this.buttonClose.requestFocusInWindow();
this.getRootPane().setDefaultButton(this.buttonClose);
}
public void requestButtonFocus() {
this.buttonClose.requestFocusInWindow();
}
}