net.bpfurtado.ljcolligo.gui.LJColligoFrame.java Source code

Java tutorial

Introduction

Here is the source code for net.bpfurtado.ljcolligo.gui.LJColligoFrame.java

Source

/**
 * Created by Bruno Patini Furtado [http://bpfurtado.livejournal.com]
 * Created on 20/11/2007 11:34:43
 *
 * This file is part of LJColligo.
 *
 * LJColligo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * LJColligo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LJColligo.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project page: http://sourceforge.net/projects/ljcolligo/
 */

package net.bpfurtado.ljcolligo.gui;

import java.awt.BorderLayout;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Collection;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

import net.bpfurtado.ljcolligo.LJColligo;
import net.bpfurtado.ljcolligo.LJColligoException;
import net.bpfurtado.ljcolligo.LJColligoListener;
import net.bpfurtado.ljcolligo.util.Conf;

import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

public class LJColligoFrame extends JFrame implements LJColligoListener, DownloadInBackgroundClient {
    private static final long serialVersionUID = -1664443660071340253L;

    private static final Logger logger = Logger.getLogger(LJColligoFrame.class);

    private static final Font FONT = new Font("Tahoma", Font.PLAIN, 14);
    private static final Font TA_FONT = new Font("Tahoma", Font.PLAIN, 12);
    private static final Font DOWNLOAD_BT_FONT = new Font("Tahoma", Font.BOLD, 14);

    private final Conf conf = Conf.getInstance();

    private LJColligo ljcolligo = new LJColligo();
    private JFileChooser chooser = new JFileChooser();
    private final JTextField outputDirTf = new JTextField(30);

    private JTextField userNameTf;
    private JPasswordField passwordTf;
    private JTextArea outputTA;
    private JButton chooseOutputDirBt;
    private JButton downloadBt;
    private JProgressBar progressBar;

    private ComponentsEnabler enabler;

    private File generatedOutputFile;

    private JButton openBt;

    public LJColligoFrame() {
    }

    public void launch() {
        ljcolligo.addListener(this);

        this.enabler = new ComponentsEnabler();

        initView();
    }

    private void downloadEvents(String userName, String password) {
        outputTA.setText("");
        progressBar.setIndeterminate(true);
        DownloadInBackground task = new DownloadInBackground(this, ljcolligo, userName, password,
                outputDirTf.getText().trim());
        task.execute();
    }

    private void initView() {
        menu();
        widgets();

        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);

        setTitle("LJColligo - A LiveJournal backup tool");
        setResizable(false);
        setBounds(100, 100, 787, 472);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                logger.debug(LJColligoFrame.this.getSize());
            }
        });

        setVisible(true);
    }

    @Override
    public void receiveFromLJColligo(String message) {
        outputTA.append(message);
        outputTA.setCaretPosition(outputTA.getDocument().getLength());
    }

    private void widgets() {
        JPanel main = createMainPanel();
        main.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
        add(main);
    }

    private JPanel createMainPanel() {
        initComponents();

        JPanel main = new JPanel(new BorderLayout());
        FormLayout layout = new FormLayout("right:pref, 4dlu, 35dlu, 60dlu, 60dlu, 30dlu, 4dlu, 45dlu",
                "p, 6dlu, p, 6dlu, p, 6dlu, p, 6dlu, p, 6dlu, p, 6dlu, p");

        layout.setRowGroups(new int[][] { { 1, 3, 5 } });

        DefaultFormBuilder builder = new DefaultFormBuilder(layout);
        builder.setDefaultDialogBorder();

        CellConstraints cc = new CellConstraints();
        builder.add(label("User name:"), cc.xy(1, 1));

        builder.add(userNameTf, cc.xyw(3, 1, 2));

        builder.add(label("Password:"), cc.xy(1, 3));
        builder.add(passwordTf, cc.xyw(3, 3, 2));

        builder.add(label("Ouput folder:"), cc.xy(1, 5));
        builder.add(outputDirTf, cc.xyw(3, 5, 4));
        builder.add(chooseOutputDirBt, cc.xy(8, 5));

        builder.add(downloadBt, cc.xyw(1, 7, 8));

        builder.add(new JScrollPane(outputTA), cc.xyw(1, 9, 8));

        this.progressBar = new JProgressBar();
        progressBar.setPreferredSize(new Dimension(0, 25));
        builder.add(progressBar, cc.xyw(1, 11, 8));

        this.openBt = new JButton("Open Generated File");
        openBt.setMnemonic('o');
        openBt.setEnabled(false);
        openBt.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ev) {
                openGeneratedOutputFileAction();
            }
        });
        builder.add(openBt, cc.xyw(6, 13, 3));

        JPanel formPanel = builder.getPanel();

        main.add(createImagePanel(), BorderLayout.LINE_START);
        main.add(formPanel);

        return main;
    }

    private void initComponents() {
        this.userNameTf = new JTextField(Conf.getInstance().getUserName(), 20);
        userNameTf.setFont(FONT);
        addEnterEvent(userNameTf);

        this.passwordTf = new JPasswordField(Conf.getInstance().getPassword(), 20);
        passwordTf.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {
                JTextField t = (JTextField) e.getSource();
                t.selectAll();
            }

            @Override
            public void focusLost(FocusEvent e) {
            }
        });
        addEnterEvent(passwordTf);
        passwordTf.setFont(FONT);

        String lastFolder = conf.get(Conf.LAST_FOLDER);
        if (lastFolder == null)
            outputDirTf.setText(System.getProperty("user.home"));
        else {
            outputDirTf.setText(lastFolder);
        }
        addEnterEvent(outputDirTf);

        this.chooseOutputDirBt = new JButton("Choose...");
        chooseOutputDirBt.setMnemonic('c');
        chooseOutputDirBt.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                chooser.setCurrentDirectory(new File(outputDirTf.getText()));

                if (chooser.showOpenDialog(LJColligoFrame.this) == JFileChooser.APPROVE_OPTION) {
                    outputDirTf.setText(chooser.getSelectedFile().getAbsolutePath());
                }
            }
        });

        this.downloadBt = new JButton("One click to download them all!");
        downloadBt.setIcon(Util.getImage("24-em-down.png"));
        downloadBt.setFont(DOWNLOAD_BT_FONT);
        downloadBt.setPreferredSize(new Dimension(0, 40));
        downloadBt.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                downloadEntriesAction();
            }
        });
        downloadBt.setFont(new Font("Tahoma", Font.BOLD, 12));
        downloadBt.setMnemonic('d');
        downloadBt.setPreferredSize(new Dimension(230, 45));
        enabler.add(downloadBt);

        this.outputTA = new JTextArea(10, 45);
        outputTA.setFont(TA_FONT);
        outputTA.setLineWrap(true);
        outputTA.setWrapStyleWord(true);
        outputTA.setEditable(false);
    }

    private void addEnterEvent(JTextField tf) {
        KeyListener enterToDownloadClick = new KeyListener() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    LJColligoFrame.this.downloadBt.doClick();
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }

            @Override
            public void keyTyped(KeyEvent e) {
            }
        };
        tf.addKeyListener(enterToDownloadClick);
    }

    private JPanel createImagePanel() {
        JPanel p = new JPanel();
        final JLabel goatImage = new JLabel(Util.getImage("goat.jpg"));
        goatImage.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                goatImage.setVisible(false);
                Dimension size = LJColligoFrame.this.getSize();
                size.setSize(size.getWidth() - goatImage.getSize().getWidth(), size.getHeight());
                LJColligoFrame.this.setSize(size);
            }
        });
        goatImage.setToolTipText("Click me to give the application a more serious and boring look ;-)");
        p.add(goatImage, BorderLayout.LINE_START);
        return p;
    }

    private void menu() {
        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        JMenu mainMenu = new JMenu("LJ Colligo");
        mainMenu.setMnemonic('l');
        menuBar.add(mainMenu);

        JMenuItem downloadMnIt = new JMenuItem("Download Entries");
        downloadMnIt.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, ActionEvent.CTRL_MASK));
        downloadMnIt.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                downloadEntriesAction();
            }
        });
        enabler.add(downloadMnIt);
        mainMenu.add(downloadMnIt);

        mainMenu.add(new JSeparator());

        JMenuItem quitMnIt = new JMenuItem("Quit");
        quitMnIt.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
        quitMnIt.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
        mainMenu.add(quitMnIt);

        JMenu help = new JMenu("Help");
        help.setMnemonic('h');
        help.setAlignmentX(LEFT_ALIGNMENT);
        JMenuItem aboutMnIt = new JMenuItem("About");
        aboutMnIt.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new About(LJColligoFrame.this);
            }
        });
        help.add(aboutMnIt);

        menuBar.add(Box.createHorizontalGlue());
        menuBar.add(help);
    }

    private JLabel label(String s) {
        JLabel l = new JLabel(s);
        l.setFont(FONT);
        return l;
    }

    private void downloadEntriesAction() {
        String folderStr = outputDirTf.getText();
        File folder = new File(folderStr);

        String title = "Invalid output folder";
        if (!folder.exists()) {
            warn("The folder [" + folderStr + "] does not exist!", title);
            return;
        } else if (!folder.isDirectory()) {
            warn("[" + folderStr + "] is not a folder !", title);
            return;
        }

        conf.set(Conf.LAST_FOLDER, folderStr);

        enabler.setEnable(false);
        downloadEvents(userNameTf.getText(), new String(passwordTf.getPassword()));
    }

    private void warn(String message, String title) {
        JOptionPane.showMessageDialog(this, message, title, JOptionPane.WARNING_MESSAGE);
    }

    @Override
    public void append(String msg) {
        outputTA.append(msg);
    }

    @Override
    public void downloadDone(File outputFile) {
        enabler.setEnable(true);
        progressBar.setIndeterminate(false);
        openBt.setEnabled(true);
        this.generatedOutputFile = outputFile;
        try {

            conf.setUserName(userNameTf.getText().trim());
            Document d = passwordTf.getDocument();
            String pw = d.getText(0, d.getLength()).trim();
            conf.setPassword(pw);
            conf.save();
            openBt.requestFocusInWindow();
        } catch (BadLocationException e) {
            throw new LJColligoException(e);
        }
    }

    private void openGeneratedOutputFileAction() {
        try {
            logger.debug(generatedOutputFile);
            Desktop.getDesktop().open(generatedOutputFile);
        } catch (Exception e) {
            throw new LJColligoException("generatedOutputFile = " + generatedOutputFile, e);
        }
    }

    public static void handleError(final LJColligoFrame colligoFrame, Throwable e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        JOptionPane.showMessageDialog(colligoFrame, "An error has occured\nStacktrace:\n" + sw.toString() + "\n",
                "Exception: " + e.getMessage(), JOptionPane.ERROR_MESSAGE);
    }

    public static void main(String[] args) {
        final LJColligoFrame colligoFrame = new LJColligoFrame();
        final UncaughtExceptionHandler uncaughtExceptionHandler = new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, final Throwable e) {
                System.out.println(".main()");
                if (SwingUtilities.isEventDispatchThread()) {
                    handleError(colligoFrame, e);
                } else {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            handleError(colligoFrame, e);
                        }
                    });
                }
            }
        };
        Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    Thread.currentThread().setUncaughtExceptionHandler(uncaughtExceptionHandler);
                    colligoFrame.launch();
                } catch (Exception e) {
                    System.out.println(".run()");
                    handleError(colligoFrame, e);
                }
            }
        });
    }
}

class ComponentsEnabler {
    private Collection<JComponent> cs = new LinkedList<JComponent>();

    void add(JComponent c) {
        cs.add(c);
    }

    void setEnable(boolean b) {
        for (JComponent c : cs) {
            c.setEnabled(b);
        }
    }
}