001    /*
002     * This file is part of muCommander, http://www.mucommander.com
003     * Copyright (C) 2002-2008 Maxence Bernard
004     *
005     * muCommander is free software; you can redistribute it and/or modify
006     * it under the terms of the GNU General Public License as published by
007     * the Free Software Foundation; either version 3 of the License, or
008     * (at your option) any later version.
009     *
010     * muCommander is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    
019    package com.mucommander.ui.dialog.about;
020    
021    import com.mucommander.RuntimeConstants;
022    import com.mucommander.desktop.DesktopManager;
023    import com.mucommander.text.Translator;
024    import com.mucommander.ui.action.MuAction;
025    import com.mucommander.ui.dialog.FocusDialog;
026    import com.mucommander.ui.icon.IconManager;
027    import com.mucommander.ui.main.MainFrame;
028    import com.mucommander.ui.theme.Theme;
029    import com.mucommander.ui.theme.ThemeManager;
030    
031    import javax.swing.*;
032    import javax.swing.text.*;
033    import java.awt.*;
034    import java.awt.event.ActionEvent;
035    import java.awt.event.ActionListener;
036    import java.io.IOException;
037    import java.net.URL;
038    import java.util.Locale;
039    
040    /**
041     * Dialog displaying information about muCommander.
042     * @author Maxence Bernard, Nicolas Rinaudo
043     */
044    public class AboutDialog extends FocusDialog implements ActionListener {
045        // - Styles -----------------------------------------------------------------
046        // --------------------------------------------------------------------------
047        /** Style for normal text. */
048        private static final String STYLE_NORMAL  = "normal";
049        /** Style for headers. */
050        private static final String STYLE_HEADER  = "header";
051        /** Style for URLs. */
052        private static final String STYLE_URL     = "url";
053        /** Style for an item's details. */
054        private static final String STYLE_DETAILS = "details";
055        /** Style for a section title. */
056        private static final String STYLE_TITLE   = "title";
057        /** Line break string. */
058        private static final String LINE_BREAK    = System.getProperty("line.separator");
059    
060    
061    
062        // - UI components ----------------------------------------------------------
063        // --------------------------------------------------------------------------
064        /** Button that closes the dialog. */
065        private JButton     okButton;
066        /** Button that opens muCommander's homepage in a browser. */
067        private JButton     homeButton;
068        /** Button that opens the muCommander's license. */
069        private JButton     licenseButton;
070        /** Panel in which all the textual information is displayed. */
071        private JScrollPane textPanel;
072    
073    
074    
075        // - Initialisation ---------------------------------------------------------
076        // --------------------------------------------------------------------------
077        /**
078         * Creates a new AboutDialog.
079         * @param mainFrame frame this dialog is relative to.
080         */
081        public AboutDialog(MainFrame mainFrame) {
082            super(mainFrame, MuAction.getStandardLabel(com.mucommander.ui.action.ShowAboutAction.class), mainFrame);
083    
084            // Initialises the dialog's content.
085            Container contentPane = getContentPane();
086            contentPane.add(createIconPanel(), BorderLayout.WEST);
087            contentPane.add(createCreditsPanel(), BorderLayout.EAST);
088            setResizable(false);
089    
090            // Makes sure the scroll pane is properly initialised.
091            SwingUtilities.invokeLater(new Runnable() {
092                    public void run() {
093                        textPanel.getViewport().setViewPosition(new Point(0,0));
094                    }
095                });
096    
097            pack();
098    
099            // Makes OK the default action.
100            setInitialFocusComponent(okButton);
101            getRootPane().setDefaultButton(okButton);
102        }
103    
104        /**
105         * Creates the panel that contains all of the about box's text.
106         */
107        private JScrollPane createCreditsPanel() {
108            JTextPane      text;
109            StyledDocument doc;
110    
111            text = new JTextPane();
112            doc  = text.getStyledDocument();
113    
114            text.setBackground(ThemeManager.getCurrentColor(Theme.FILE_TABLE_BACKGROUND_COLOR));
115    
116            setStyles(doc);
117            text.setEditable(false);
118            try {
119                // Team.
120                insertTitle(doc,          "The muCommander team");
121    
122                // Core developers.
123                insertHeader(doc,         "Core developers");
124                insertNormalString(doc,   "Maxence Bernard");
125                insertNormalString(doc,   "Nicolas Rinaudo");
126                insertNormalString(doc,   "Arik Hadas");
127                insertNormalString(doc,   "Mariusz Jakubowski");
128                insertLineBreak(doc);
129    
130                // Contributors.
131                insertHeader(doc,         "Contributors");
132                insertNormalString(doc,   "Ivan Baidakov");
133                insertNormalString(doc,   "Vassil Dichev");
134                insertNormalString(doc,   "David Kovar");
135                insertNormalString(doc,   "Karel Klic");
136                insertNormalString(doc,   "Joshua Lebo");
137                insertNormalString(doc,   "Xavier Martin");
138                insertNormalString(doc,   "Alejandro Scandroli");
139                insertLineBreak(doc);
140    
141                // QA
142                insertHeader(doc,         "QA");
143                insertNormalString(doc,   "Joshua Lebo");
144                insertLineBreak(doc);
145    
146                // Translators.
147                insertHeader(doc,         "Translators");
148                insertDetailedString(doc, "4X_Pro",              "Russian");
149                insertDetailedString(doc, "Roberto Angeletti",   "Italian");
150                insertDetailedString(doc, "Tamás Balogh-Walder", "Hungarian");
151                insertDetailedString(doc, "Mykola Bilovus",      "Ukrainian");
152                insertDetailedString(doc, "György Varga",        "Hungarian");
153                insertDetailedString(doc, "Frank Berger",        "German");
154                insertDetailedString(doc, "Tony Klüver",         "German");
155                insertDetailedString(doc, "Marcos Cobeña",       "Spanish");
156                insertDetailedString(doc, "Cristiano Duarte",    "Brazilian Portuguese");
157                insertDetailedString(doc, "Jakob Ekström",       "Swedish");
158                insertDetailedString(doc, "Catalin Hritcu",      "Romanian");
159                insertDetailedString(doc, "Kent Hsu",            "Traditional Chinese");
160                insertDetailedString(doc, "Jioh L. Jung",        "Korean");
161                insertDetailedString(doc, "Andrzej Kosiński",    "Polish");
162                insertDetailedString(doc, "Joze Kovacic",        "Slovenian");
163                insertDetailedString(doc, "Pieter Kristensen",   "Dutch");
164                insertDetailedString(doc, "Ján Ľudvík",          "Slovak");
165                insertDetailedString(doc, "Jaromír Mára",        "Czech");
166                insertDetailedString(doc, "Jonathan Murphy",     "British English");
167                insertDetailedString(doc, "Nardog",              "Japanese");
168                insertDetailedString(doc, "Jeppe Toustrup",      "Danish");
169                insertDetailedString(doc, "Peter Vasko",         "Czech");
170                insertDetailedString(doc, "Woodie",              "Simplified Chinese");
171                insertLineBreak(doc);
172    
173                // Special thanks.
174                insertHeader(doc,         "Special thanks");
175                insertDetailedString(doc, "Stefano Perelli",    "muCommander icon");
176                insertLineBreak(doc);
177                insertLineBreak(doc);
178    
179                // Powered by.
180                insertTitle(doc,         "Powered by");
181    
182                // External Libraries.
183                insertHeader(doc,         "External libraries");
184                insertDetailedUrl(doc,    "Ant",                 "Apache License",                       "http://ant.apache.org");
185                insertDetailedUrl(doc,    "Furbelow",            "LGPL",                                 "http://sourceforge.net/projects/furbelow");
186                insertDetailedUrl(doc,    "ICU4J",               "ICU License",                          "http://www.icu-project.org");
187                insertDetailedUrl(doc,    "J2SSH",               "LGPL",                                 "http://sourceforge.net/projects/sshtools");
188                insertDetailedUrl(doc,    "Jakarta Commons Net", "Apache License",                       "http://jakarta.apache.org/commons/net");
189                insertDetailedUrl(doc,    "jCIFS",               "LGPL",                                 "http://jcifs.samba.org");
190                insertDetailedUrl(doc,    "JmDNS",               "LGPL",                                 "http://jmdns.sourceforge.net");
191                insertDetailedUrl(doc,    "JNA",                 "LGPL",                                 "http://jna.dev.java.net");
192                insertDetailedUrl(doc,    "JUnRar",              "Freeware",                             "http://sourceforge.net/projects/java-unrar");
193                insertDetailedUrl(doc,    "Mark James' icons",   "Creative Commons Attribution License", "http://famfamfam.com");
194                insertDetailedUrl(doc,    "Yanfs",               "BSD",                                  "http://yanfs.dev.java.net");
195                insertLineBreak(doc);
196    
197                // External tools.
198                insertHeader(doc,         "External tools");
199                insertDetailedUrl(doc,    "Ant",                 "Apache Software License",              "http://ant.apache.org");
200                insertDetailedUrl(doc,    "AntDoclet",           "GPL",                                  "http://antdoclet.neuroning.com/");
201                insertDetailedUrl(doc,    "jdeb",                "Apache Software License",              "http://vafer.org/projects/jdeb/");
202                insertDetailedUrl(doc,    "Launch4j",            "GPL",                                  "http://launch4j.sourceforge.net");
203                insertDetailedUrl(doc,    "NSIS",                "zlib/libpng license",                  "http://nsis.sourceforge.net");
204                insertDetailedUrl(doc,    "p7zip",               "LGPL",                                 "http://p7zip.sourceforge.net");
205                insertDetailedUrl(doc,    "ProGuard",            "GPL",                                  "http://proguard.sourceforge.net");
206                insertLineBreak(doc);
207                insertLineBreak(doc);
208    
209                // Version information
210                insertTitle(doc,         "Version information");
211    
212                // VM information.
213                insertHeader(doc,         "muCommander");
214                insertNormalString(doc,   "Version: " + RuntimeConstants.VERSION);
215                insertNormalString(doc,   "Build date: " + getFormatedDate());
216                insertLineBreak(doc);
217    
218                // VM information.
219                insertHeader(doc,         "Java VM");
220                insertNormalString(doc,   "Name: " + System.getProperty("java.vm.name"));
221                insertNormalString(doc,   "Version: " + System.getProperty("java.vm.version"));
222                insertNormalString(doc,   "Vendor: " + System.getProperty("java.vm.vendor"));
223                insertLineBreak(doc);
224    
225                // OS information.
226                insertHeader(doc,         "OS");
227                insertNormalString(doc,   "Name: " + System.getProperty("os.name"));
228                insertNormalString(doc,   "Version: " + System.getProperty("os.version"));
229                insertNormalString(doc,   "Architecture: " + System.getProperty("os.arch"));
230                insertLineBreak(doc);
231    
232                // Locale information.
233                Locale locale = Locale.getDefault();
234                insertHeader(doc,         "Locale");
235                insertNormalString(doc,   "Language: " + locale.getLanguage());
236                insertNormalString(doc,   "Country: " + locale.getCountry());
237                insertNormalString(doc,   "Encoding: " + System.getProperty("file.encoding"));
238            }
239            catch(Exception e) {}
240    
241            textPanel = new JScrollPane(text, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
242            textPanel.getViewport().setPreferredSize(new Dimension((int)text.getPreferredSize().getWidth(), 300));
243    
244            return textPanel;
245        }
246    
247        /**
248         * Creates the about box's left panel.
249         */
250        private JPanel createIconPanel() {
251            JPanel mainPanel;
252            JPanel tempPanel;
253            JPanel flowPanel;
254    
255            // Makes sure the panel's a bit roomier than the default configuration.
256            mainPanel = new JPanel(new BorderLayout()) {
257                    public Insets getInsets() {return new Insets(10, 10, 0, 10);}
258                };
259    
260            tempPanel = new JPanel(new BorderLayout());
261    
262            tempPanel.add(new JLabel(IconManager.getIcon("/about.png")), BorderLayout.NORTH);
263    
264            flowPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
265            flowPanel.add(createBoldLabel(RuntimeConstants.APP_STRING));
266            tempPanel.add(flowPanel, BorderLayout.CENTER);
267    
268            flowPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
269            flowPanel.add(new JLabel("©" + RuntimeConstants.COPYRIGHT + " Maxence Bernard"));
270            tempPanel.add(flowPanel, BorderLayout.SOUTH);
271            mainPanel.add(tempPanel, BorderLayout.NORTH);
272    
273            tempPanel = new JPanel(new BorderLayout());
274            if(DesktopManager.canBrowse()) {
275                tempPanel.add(homeButton = new JButton(MuAction.getStandardLabel(com.mucommander.ui.action.GoToWebsiteAction.class)), BorderLayout.NORTH);
276                homeButton.addActionListener(this);
277            }
278            else {
279                flowPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
280                flowPanel.add(new JLabel(com.mucommander.RuntimeConstants.HOMEPAGE_URL));
281                tempPanel.add(flowPanel, BorderLayout.NORTH);
282            }
283            tempPanel.add(licenseButton = new JButton(Translator.get("license")), BorderLayout.CENTER);
284            licenseButton.addActionListener(this);
285            tempPanel.add(okButton = new JButton(Translator.get("ok")), BorderLayout.SOUTH);
286            okButton.addActionListener(this);
287            mainPanel.add(tempPanel, BorderLayout.SOUTH);
288    
289            return mainPanel;
290        }
291    
292    
293    
294        // - Text panel handling ----------------------------------------------------
295        // --------------------------------------------------------------------------
296        /**
297         * Creates different styles in the specified <code>StyledDocument</code>
298         * @param doc document in which to create the styles.
299         */
300        private static void setStyles(StyledDocument doc) {
301            Style master;
302            Style currentStyle;
303            Font  font;
304    
305            master = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
306            font   = ThemeManager.getCurrentFont(Theme.FILE_TABLE_FONT);
307    
308            // Normal style.
309            master = doc.addStyle(STYLE_NORMAL, master);
310            StyleConstants.setFontFamily(master, font.getFamily());
311            StyleConstants.setFontSize(master, font.getSize());
312            StyleConstants.setForeground(master, ThemeManager.getCurrentColor(Theme.FILE_FOREGROUND_COLOR));
313            StyleConstants.setBackground(master, ThemeManager.getCurrentColor(Theme.FILE_TABLE_BACKGROUND_COLOR));
314            StyleConstants.setLeftIndent(master, 10);
315            StyleConstants.setRightIndent(master, 10);
316            StyleConstants.setLineSpacing(master, (float)0.2);
317            doc.setParagraphAttributes(0, 0, master, true);
318    
319            // Header style.
320            currentStyle = doc.addStyle(STYLE_HEADER, master);
321            StyleConstants.setBold(currentStyle, true);
322            StyleConstants.setFontSize(currentStyle, font.getSize() + 2);
323            StyleConstants.setForeground(currentStyle, ThemeManager.getCurrentColor(Theme.FOLDER_FOREGROUND_COLOR));
324            StyleConstants.setBackground(currentStyle, ThemeManager.getCurrentColor(Theme.FILE_TABLE_BACKGROUND_COLOR));
325    
326            // Title style.
327            currentStyle = doc.addStyle(STYLE_TITLE, currentStyle);
328            StyleConstants.setAlignment(currentStyle, StyleConstants.ALIGN_CENTER);
329            StyleConstants.setForeground(currentStyle, ThemeManager.getCurrentColor(Theme.ARCHIVE_FOREGROUND_COLOR));
330            StyleConstants.setBackground(currentStyle, ThemeManager.getCurrentColor(Theme.FILE_TABLE_BACKGROUND_COLOR));
331    
332            // Details style.
333            currentStyle = doc.addStyle(STYLE_DETAILS, master);
334            StyleConstants.setForeground(currentStyle, ThemeManager.getCurrentColor(Theme.HIDDEN_FILE_FOREGROUND_COLOR));
335            StyleConstants.setBackground(currentStyle, ThemeManager.getCurrentColor(Theme.FILE_TABLE_BACKGROUND_COLOR));
336    
337            // URL style.
338            currentStyle = doc.addStyle(STYLE_URL, master);
339            StyleConstants.setForeground(currentStyle, ThemeManager.getCurrentColor(Theme.SYMLINK_FOREGROUND_COLOR));
340            StyleConstants.setBackground(currentStyle, ThemeManager.getCurrentColor(Theme.FILE_TABLE_BACKGROUND_COLOR));
341            StyleConstants.setUnderline(currentStyle, true);
342        }
343    
344        /**
345         * Inserts the specified header in the specified document.
346         * @param  doc                  document in which to insert the text.
347         * @param  string               text to insert.
348         * @throws BadLocationException thrown if something wrong happened to the document.
349         */
350        private static void insertHeader(StyledDocument doc, String string) throws BadLocationException {
351            doc.insertString(doc.getLength(), string + LINE_BREAK, doc.getStyle(STYLE_HEADER));
352        }
353    
354        /**
355         * Inserts the specified string in the specified document.
356         * @param  doc                  document in which to insert the text.
357         * @param  string               text to insert.
358         * @throws BadLocationException thrown if something wrong happened to the document.
359         */
360        private static void insertNormalString(StyledDocument doc, String string) throws BadLocationException {
361            doc.insertString(doc.getLength(), string + LINE_BREAK, doc.getStyle(STYLE_NORMAL));
362        }
363    
364        /**
365         * Inserts the specified string and details in the specified document.
366         * @param  doc                  document in which to insert the text.
367         * @param  string               text to insert.
368         * @param  details              details that will be added to the text.
369         * @throws BadLocationException thrown if something wrong happened to the document.
370         */
371        private static void insertDetailedString(StyledDocument doc, String string, String details) throws BadLocationException {
372            doc.insertString(doc.getLength(), string + " ", doc.getStyle(STYLE_NORMAL));
373            doc.insertString(doc.getLength(), "(" + details + ")" + LINE_BREAK, doc.getStyle(STYLE_DETAILS));
374        }
375    
376        /**
377         * Inserts the specified URL in the specified document.
378         * @param  doc                  document in which to insert the text.
379         * @param  url                  url to insert.
380         * @throws BadLocationException thrown if something wrong happened to the document.
381         */
382        private static void insertUrl(StyledDocument doc, String url) throws BadLocationException {
383            doc.insertString(doc.getLength(), "    ", doc.getStyle(STYLE_NORMAL));
384            doc.insertString(doc.getLength(), url + LINE_BREAK, doc.getStyle(STYLE_URL));
385        }
386    
387        /**
388         * Inserts a line break in the specified document.
389         * @param  doc                  document in which to insert the text.
390         * @throws BadLocationException thrown if something wrong happened to the document.
391         */
392        private static void insertLineBreak(StyledDocument doc) throws BadLocationException {
393            doc.insertString(doc.getLength(), LINE_BREAK, doc.getStyle(STYLE_NORMAL));
394        }
395    
396        /**
397         * Inserts the specified string, details and URL in the specified document.
398         * @param  doc                  document in which to insert the text.
399         * @param  string               text to insert.
400         * @param  details              details that will be added to the text.
401         * @param  url                  url that will be added to the text.
402         * @throws BadLocationException thrown if something wrong happened to the document.
403         */
404        private static void insertDetailedUrl(StyledDocument doc, String string, String details, String url) throws BadLocationException {
405            insertDetailedString(doc, string, details);
406            insertUrl(doc, url);
407        }
408    
409        /**
410         * Inserts the specified title in the specified document.
411         * @param  doc                  document in which to insert the text.
412         * @param  string               text to insert.
413         * @throws BadLocationException thrown if something wrong happened to the document.
414         */
415        private static void insertTitle(StyledDocument doc, String string) throws BadLocationException {
416            int   pos;
417            Style style;
418    
419            string += LINE_BREAK;
420            doc.insertString(pos = doc.getLength(), string, style = doc.getStyle(STYLE_TITLE));
421            doc.setParagraphAttributes(pos, string.length(), style, true);
422            doc.setParagraphAttributes(doc.getLength(), 0, doc.getStyle(STYLE_NORMAL), true);
423    
424            insertLineBreak(doc);
425        }
426    
427    
428    
429        // - Action listening -------------------------------------------------------
430        // --------------------------------------------------------------------------
431        /**
432         * Reacts to validations of the <code>OK</code> or <code>home</code> buttons.
433         */
434        public void actionPerformed(ActionEvent e) {
435            if(e.getSource() == okButton)
436                dispose();
437            else if(e.getSource() == homeButton) {
438                try {DesktopManager.browse(new URL(RuntimeConstants.HOMEPAGE_URL));}
439                // Ignores errors here as there really isn't anything we can do.
440                catch(IOException ignored) {}
441            }
442            else if(e.getSource() == licenseButton)
443                new LicenseDialog(this).showDialog();
444        }
445    
446    
447    
448        // - Misc. methods ----------------------------------------------------------
449        // --------------------------------------------------------------------------
450        /**
451         * Returns a formatted version of muCommander's build date.
452         * @return a formatted version of muCommander's build date.
453         */
454        private String getFormatedDate() {
455            StringBuffer buffer;
456    
457            buffer = new StringBuffer(RuntimeConstants.RELEASE_DATE.substring(0, 4));
458            buffer.append('/');
459            buffer.append(RuntimeConstants.RELEASE_DATE.substring(4, 6));
460            buffer.append('/');
461            buffer.append(RuntimeConstants.RELEASE_DATE.substring(6, 8));
462    
463            return buffer.toString();
464        }
465    
466        /**
467         * Creates a <code>JLabel</code> displaying the specified text using a bold font.
468         * @param  text text to display in the label.
469         * @return       a <code>JLabel</code> displaying the specified text using a bold font.
470         */
471        private JLabel createBoldLabel(String text) {
472            JLabel label;
473            Font   font;
474    
475            label = new JLabel(text);
476            font  = label.getFont();
477            label.setFont(new Font(font.getFontName(), font.getStyle() | Font.BOLD, font.getSize()));
478    
479            return label;
480        }
481    
482    }