View Javadoc
1   /*******************************************************************************
2    * Copyhacked (H) 2012-2025.
3    * This program and the accompanying materials
4    * are made available under no term at all, use it like
5    * you want, but share and discuss it
6    * every time possible with every body.
7    * 
8    * Contributors:
9    *      ron190 at ymail dot com - initial implementation
10   ******************************************************************************/
11  package com.jsql.view.swing.dialog;
12  
13  import com.jsql.util.I18nUtil;
14  import com.jsql.util.LogLevelUtil;
15  import com.jsql.util.StringUtil;
16  import com.jsql.view.swing.popupmenu.JPopupMenuText;
17  import com.jsql.view.swing.util.I18nViewUtil;
18  import com.jsql.view.swing.util.MediatorHelper;
19  import com.jsql.view.swing.util.UiUtil;
20  import org.apache.logging.log4j.LogManager;
21  import org.apache.logging.log4j.Logger;
22  
23  import javax.swing.*;
24  import javax.swing.event.HyperlinkEvent;
25  import java.awt.*;
26  import java.awt.event.*;
27  import java.io.BufferedReader;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.io.InputStreamReader;
31  import java.net.URI;
32  import java.net.URISyntaxException;
33  import java.nio.charset.StandardCharsets;
34  import java.util.Objects;
35  
36  /**
37   * A dialog displaying information about jSQL.
38   */
39  public class DialogAbout extends JDialog {
40      
41      private static final Logger LOGGER = LogManager.getRootLogger();
42  
43      /**
44       * Button receiving focus.
45       */
46      private JButton buttonClose = null;
47  
48      /**
49       * Create a dialog about project general information.
50       */
51      public DialogAbout() {
52          super(MediatorHelper.frame(), I18nUtil.valueByKey("ABOUT_WINDOW_TITLE") +" "+ StringUtil.APP_NAME, Dialog.ModalityType.MODELESS);
53          I18nViewUtil.addComponentForKey("ABOUT_WINDOW_TITLE", this);
54          this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
55          this.setIconImages(UiUtil.getIcons());  // Define a small and large app icon
56  
57          ActionListener escapeListener = actionEvent -> this.dispose();  // Action for ESCAPE key
58          this.getRootPane().registerKeyboardAction(
59              escapeListener,
60              KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
61              JComponent.WHEN_IN_FOCUSED_WINDOW
62          );
63          
64          this.setLayout(new BorderLayout());
65  
66          Container dialogPane = this.getContentPane();
67          JPanel lastLine = this.initLastLine(escapeListener);
68  
69          var labelIcon = new JLabel(UiUtil.APP_MIDDLE.getIcon());
70          labelIcon.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
71          dialogPane.add(labelIcon, BorderLayout.WEST);
72          dialogPane.add(lastLine, BorderLayout.SOUTH);
73  
74          final JEditorPane text = this.initEditorPane();  // Contact info, use HTML text
75          dialogPane.add(new JScrollPane(text), BorderLayout.CENTER);
76  
77          this.initDialog();
78      }
79  
80      private JPanel initLastLine(ActionListener escapeListener) {
81          final var buttonWebpage = new JButton(I18nUtil.valueByKey("ABOUT_WEBPAGE"));
82          I18nViewUtil.addComponentForKey("ABOUT_WEBPAGE", buttonWebpage);
83          buttonWebpage.addActionListener(ev -> {
84              try {
85                  Desktop.getDesktop().browse(new URI(MediatorHelper.model().getMediatorUtils().getPropertiesUtil().getProperty("github.url")));
86              } catch (IOException | URISyntaxException | UnsupportedOperationException e) {
87                  LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Browsing to Url failed", e);
88              }
89          });
90  
91          this.buttonClose = new JButton(I18nUtil.valueByKey("ABOUT_CLOSE"));
92          I18nViewUtil.addComponentForKey("ABOUT_CLOSE", this.buttonClose);
93          this.buttonClose.addActionListener(escapeListener);
94  
95          var lastLine = new JPanel();
96          lastLine.setLayout(new BoxLayout(lastLine, BoxLayout.LINE_AXIS));
97          lastLine.setBorder(UiUtil.BORDER_5PX);
98          lastLine.add(buttonWebpage);
99          lastLine.add(Box.createGlue());
100         lastLine.add(this.buttonClose);
101         return lastLine;
102     }
103 
104     private JEditorPane initEditorPane() {
105         var editorPane = new JEditorPane();
106         
107         // Fix #82540: NoClassDefFoundError on setText()
108         try (
109             InputStream inputStream = DialogAbout.class.getClassLoader().getResourceAsStream("swing/about.htm");
110             var inputStreamReader = new InputStreamReader(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8);
111             var reader = new BufferedReader(inputStreamReader)
112         ) {
113             editorPane.setContentType("text/html");
114             var result = new StringBuilder();
115             String line;
116             while ((line = reader.readLine()) != null) {
117                 result.append(line);
118             }
119             editorPane.setText(result.toString().replace(
120                 "%JSQLVERSION%",
121                 MediatorHelper.model().getPropertiesUtil().getVersionJsql()
122             ));
123         } catch (NoClassDefFoundError | IOException e) {
124             LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
125         }
126 
127         editorPane.addMouseListener(new MouseAdapter() {
128             @Override
129             public void mousePressed(MouseEvent e) {
130                 super.mousePressed(e);
131                 editorPane.requestFocusInWindow();
132             }
133         });
134         editorPane.addFocusListener(new FocusAdapter() {
135             @Override
136             public void focusGained(FocusEvent focusEvent) {
137                 editorPane.getCaret().setVisible(true);
138                 editorPane.getCaret().setSelectionVisible(true);
139             }
140         });
141 
142         editorPane.setDragEnabled(true);
143         editorPane.setEditable(false);
144         editorPane.getCaret().setBlinkRate(0);
145         editorPane.setCaretPosition(0);
146         editorPane.setComponentPopupMenu(new JPopupMenuText(editorPane));
147         editorPane.addHyperlinkListener(linkEvent -> {
148             if (HyperlinkEvent.EventType.ACTIVATED.equals(linkEvent.getEventType())) {
149                 try {
150                     Desktop.getDesktop().browse(linkEvent.getURL().toURI());
151                 } catch (IOException | URISyntaxException | UnsupportedOperationException e) {
152                     LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Browsing to Url failed", e);
153                 }
154             }
155         });
156         
157         return editorPane;
158     }
159 
160     /**
161      * Set back default setting for About frame.
162      */
163     public final void initDialog() {
164         this.setSize(560, 400);
165         this.setLocationRelativeTo(MediatorHelper.frame());
166         this.buttonClose.requestFocusInWindow();
167         this.getRootPane().setDefaultButton(this.buttonClose);
168     }
169 
170     public void requestButtonFocus() {
171         this.buttonClose.requestFocusInWindow();
172     }
173 }