net.pandoragames.far.ui.swing.FindAndReplace.java Source code

Java tutorial

Introduction

Here is the source code for net.pandoragames.far.ui.swing.FindAndReplace.java

Source

package net.pandoragames.far.ui.swing;

import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

import net.pandoragames.far.ui.ConfigurationException;
import net.pandoragames.far.ui.FARConfig;
import net.pandoragames.far.ui.FARConfigurationFactory;
import net.pandoragames.far.ui.model.FileNamePattern;
import net.pandoragames.far.ui.model.FindForm;
import net.pandoragames.far.ui.model.MessageBox;
import net.pandoragames.far.ui.model.OperationType;
import net.pandoragames.far.ui.model.ProgressListener;
import net.pandoragames.far.ui.model.TargetFile;
import net.pandoragames.far.ui.swing.component.ButtonPanel;
import net.pandoragames.far.ui.swing.component.FileSetTableModel;
import net.pandoragames.far.ui.swing.component.InfoLine;
import net.pandoragames.far.ui.swing.component.listener.FileImportNotifier;
import net.pandoragames.far.ui.swing.component.listener.OperationCallBackListener;
import net.pandoragames.far.ui.swing.dialog.HelpView;
import net.pandoragames.far.ui.swing.dialog.update.UpdateDialog;
import net.pandoragames.far.ui.swing.menu.MenuFactory;
import net.pandoragames.util.i18n.DefaultLocalizer;
import net.pandoragames.util.i18n.Localizer;
import net.pandoragames.util.j6.DesktopHelper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Main class of the Swing application.
 * 
 * @author Olivier Wehner at 26.02.2008 <!--
 *  FAR - Find And Replace
 *  Copyright (C) 2009,  Olivier Wehner
    
 *  This program 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.
    
 *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *  -->
 */
public class FindAndReplace extends JFrame {

    private SwingConfig config;

    private ComponentRepository componentRepository;

    private FARConfigurationFactory configFactory;

    private FileImporter fileImporter;

    private Log logger = LogFactory.getLog(this.getClass());

    /**
     * Default constructor. Defines the application title and initialises the
     * logging for this component.
     */
    private FindAndReplace() {
        super(SwingConfig.APPLICATION_TITLE);
        String message = "Starting FAR - Find And Replace " + getClass().getPackage().getSpecificationVersion()
                + " (" + getClass().getPackage().getImplementationVersion() + ")";
        logger.info(message);
    }

    /**
     * The main method. Expects no arguments.
     * 
     * @param args
     *            not evaluated
     */
    public static void main(String[] args) {
        if (FARConfig.getEffectiveJavaVersion() == 0) { // obscure jvm
            LogFactory.getLog(FindAndReplace.class)
                    .warn("Java version could not be read. This may very well lead to unexpected crashes");
        } else if (FARConfig.getEffectiveJavaVersion() < 5) { // won't work -
            // exit
            LogFactory.getLog(FindAndReplace.class)
                    .error("FAR requires java 5 (1.5.x) or higher. Found 1." + FARConfig.getEffectiveJavaVersion());
            System.exit(1);
        } else {
            LogFactory.getLog(FindAndReplace.class).debug("Running on java " + FARConfig.getEffectiveJavaVersion());
        }
        JFrame.setDefaultLookAndFeelDecorated(SwingConfig.isMacOSX());
        UIManager.put("Button.defaultButtonFollowsFocus", Boolean.TRUE);
        FindAndReplace far = new FindAndReplace();
        far.configure();
        far.init();
        far.pack();
        far.setVisible(true);
        // First time initialisation - speeds up the loading of the help views
        HelpView helpView = new HelpView(far, "About", "about.html", new Point(100, 100));
        helpView.pack();
        helpView.setVisible(false);

        if (args.length > 0 && SwingConfig.getEffectiveJavaVersion() > 5) {
            List<File> fileList = new ArrayList<File>();
            for (String arg : args) {
                File file = new File(arg);
                if (file.exists())
                    fileList.add(file);
            }
            if (fileList.size() > 0) {
                far.fileImporter.importFiles(fileList);
            }
        }

        if (far.config.versionHasChanged()) {
            UpdateDialog updateWizzard = new UpdateDialog(far, far.config, far.componentRepository);
            if (updateWizzard.isUserInteractionRequired()) {
                updateWizzard.pack();
                updateWizzard.setVisible(true);
            } else {
                updateWizzard.dispose();
            }
        }
    }

    /**
     * User preferences.
     */
    private void configure() {
        logger.debug("Configuration...");
        try {
            config = new SwingConfig();
            configFactory = new FARConfigurationFactory();
            configFactory.loadConfig(config);
            // localizer
            File localizerProperties = new File(
                    this.getClass().getClassLoader().getResource("fartext.properties").toURI());
            Localizer loco = new DefaultLocalizer(localizerProperties, Locale.ENGLISH);
            JComponent.setDefaultLocale(loco.getLocale());
            config.setLocalizer(loco);
        } catch (Exception x) {
            logger.error(x.getClass().getName() + ": " + x.getMessage(), x);
            throw new ConfigurationException(x.getClass().getName() + ": " + x.getMessage());
        }

        // standard component hight
        JButton testButton = new JButton("TEST");
        config.setStandardComponentHight(testButton.getPreferredSize().height);

        // screen center
        Rectangle screen = getGraphicsConfiguration().getBounds();
        config.setScreenCenter(new Point((screen.width - screen.x) / 2, (screen.height - screen.y) / 2));

    }

    /**
     * Pannels and other swing settings
     */
    private void init() {
        logger.debug("Setting up FAR Swing GUI");

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        ExitListener closeFARlistener = new ExitListener();
        addWindowListener(closeFARlistener);

        setIconImage(new ImageIcon(this.getClass().getClassLoader().getResource("icons/far.gif")).getImage());

        setLocation(config.getScreenCenter().x / 3, config.getScreenCenter().y / 3);

        this.setLayout(new BorderLayout());
        InfoLine infoLine = new InfoLine(config);
        componentRepository = new ComponentRepository(config, infoLine, closeFARlistener, this);
        componentRepository.getOperationCallBackListener().addComponentStartReseted(infoLine,
                OperationType.REPLACE);
        componentRepository.getResetDispatcher().addResetable(infoLine);
        componentRepository.getSearchBaseListener().addResetable(infoLine);

        // menu
        MenuFactory menuFactory = new MenuFactory(config, componentRepository);
        this.setJMenuBar(menuFactory.createMenu());
        closeFARlistener.registerCloseApplicationKeyListener(this.getJMenuBar());

        this.add(infoLine, BorderLayout.NORTH);

        //
        // sub components
        //

        OperationTabPane tabbedPane = componentRepository.getTabPane();
        closeFARlistener.registerCloseApplicationKeyListener(tabbedPane);

        // find tab
        FindFilePanel findFilePanel = new FindFilePanel(config, componentRepository);
        ButtonPanel findFileBasePanel = new ButtonPanel(OperationType.FIND, config, componentRepository);
        findFileBasePanel.setMainPanel(findFilePanel);
        tabbedPane.addTab(config.getLocalizer().localize("button.find"), findFileBasePanel);
        tabbedPane.setMnemonicAt(0, config.getAccessKey("menu.find"));
        // replace tab
        ReplaceContentPanel replacePanel = new ReplaceContentPanel(config, componentRepository);
        ButtonPanel replaceBasePanel = new ButtonPanel(OperationType.REPLACE, config, componentRepository);
        replaceBasePanel.setMainPanel(replacePanel);
        tabbedPane.addTab(config.getLocalizer().localize("button.replace"), replaceBasePanel);
        tabbedPane.setMnemonicAt(1, config.getAccessKey("menu.replace"));
        // rename tab
        RenameFilesPanel renamePanel = new RenameFilesPanel(config, componentRepository);
        ButtonPanel renameBasePanel = new ButtonPanel(OperationType.RENAME, config, componentRepository);
        renameBasePanel.setMainPanel(renamePanel);
        tabbedPane.addTab(config.getLocalizer().localize("button.rename"), renameBasePanel);
        tabbedPane.setMnemonicAt(2, config.getAccessKey("menu.rename"));
        // listener
        componentRepository.getOperationCallBackListener().addComponentTerminationEnabled(tabbedPane,
                OperationType.FIND);
        componentRepository.getResetDispatcher().addResetable(tabbedPane);
        componentRepository.getSearchBaseListener().addResetable(tabbedPane);
        tabbedPane.reset();
        this.add(tabbedPane, BorderLayout.WEST);

        FileListPanel fileListPanel = new FileListPanel(config, componentRepository);
        this.add(fileListPanel, BorderLayout.CENTER);
        closeFARlistener.registerCloseApplicationKeyListener(fileListPanel);

        // drag and drop
        if (SwingConfig.getEffectiveJavaVersion() > 5) {

            fileImporter = new FileImporter(componentRepository);

            DesktopHelper.installTransferHandler(this, fileImporter);
        } else {
            infoLine.info(config.getLocalizer().localize("message.please-update-java"));
        }

    }

    class ExitListener extends AbstractAction implements WindowListener {

        public void actionPerformed(ActionEvent e) {
            dispose();
        }

        public void windowClosed(WindowEvent wen) {
            logger.debug("Exit");
            backupBeforeExit();
        }

        public void windowClosing(WindowEvent wen) {
            logger.debug("Closing...");
            backupBeforeExit();
        }

        public void windowActivated(WindowEvent e) {
        }

        public void windowDeactivated(WindowEvent e) {
        }

        public void windowDeiconified(WindowEvent e) {
        }

        public void windowIconified(WindowEvent e) {
        }

        public void windowOpened(WindowEvent e) {
        }

        public void registerCloseApplicationKeyListener(JComponent component) {
            component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
                    .put(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK), "exitAction");
            component.getActionMap().put("exitAction", this);
        }

        private void backupBeforeExit() {
            if (!configFactory.saveConfig(config))
                logger.warn("Preferences not properly saved, exit though.");
            logger.info(" - End -");
        }
    }

    class FileImporter implements FileImportNotifier, Runnable {
        private Localizer localizer;
        private ProgressListener findProgressListener;
        private OperationCallBackListener callbackLister;
        private MessageBox errorSink;
        private FindForm findForm;
        private FileSetTableModel tableModel;

        // should be externalized
        private int fileCount;
        private List<File> fileList;

        public FileImporter(ComponentRepository repository) {
            localizer = config.getLocalizer();
            findProgressListener = repository.getOperationCallBackListener();
            errorSink = repository.getMessageBox();
            findForm = repository.getFindForm();
            tableModel = repository.getTableModel();
            callbackLister = repository.getOperationCallBackListener();
        }

        public void importFiles(List<File> fileList) {
            this.fileList = fileList;
            Thread thread = new Thread(this);
            thread.start();
        }

        public void run() {
            fileCount = 0;
            findProgressListener.operationStarted(OperationType.FIND);
            callbackLister.operationStarted(OperationType.FIND);
            List<File> expanded = new ArrayList<File>();
            for (File file : fileList) {
                if (file.isFile()) {
                    // possibly relative path through command line
                    expanded.add(file.getAbsoluteFile());
                    findProgressListener.operationProgressed(fileCount++, 0, OperationType.FIND);
                } else if (file.isDirectory()) {
                    expanded.addAll(resolve(file));
                }
            }
            if (expanded.size() == 0)
                return;
            // build the target file list
            logger.info("Importing " + expanded.size() + " files from external source");
            List<TargetFile> importList = new ArrayList<TargetFile>();
            File basedir = null;
            for (int i = 0; i < expanded.size(); i++) {
                File nextFile = expanded.get(i);
                if (basedir == null) {
                    basedir = nextFile.getParentFile();
                } else {
                    String path = nextFile.getPath();
                    while (basedir != null && !path.startsWith(basedir.getPath())) {
                        basedir = basedir.getParentFile();
                    }
                    if (basedir == null)
                        basedir = File.listRoots()[0];
                }
                importList.add(new TargetFile(nextFile));
                findProgressListener.operationProgressed(i, expanded.size(), OperationType.FIND);
            }
            // import
            FindForm inferedForm = config.getDefaultFindForm();
            inferedForm.setBaseDirectory(basedir);
            String fileNamePattern = "";
            if (fileList.size() == 1) {
                if (fileList.get(0).isFile()) {
                    fileNamePattern = fileList.get(0).getName();
                } else {
                    fileNamePattern = "*";
                }
            }
            inferedForm.setFileNamePattern(new FileNamePattern(fileNamePattern));
            findForm.update(inferedForm);
            findProgressListener.operationTerminated(OperationType.FIND);
            callbackLister.operationTerminated(OperationType.FIND);
            tableModel.setFileList(importList, basedir);
            // write to message sink AFTER updating the model to avoid clear() erasing the message
            errorSink.info(localizer.localize("message.drop-import-ok",
                    new Object[] { Integer.valueOf(importList.size()) }));
            logger.debug(importList.size() + " files imported.");

        }

        private List<File> resolve(File directory) {
            List<File> result = new ArrayList<File>();
            File[] raw = directory.listFiles();
            for (File file : raw) {
                if (file.isFile()) {
                    // possibly relative path through command line
                    result.add(file.getAbsoluteFile());
                    findProgressListener.operationProgressed(fileCount++, 0, OperationType.FIND);
                } else if (file.isDirectory()) {
                    result.addAll(resolve(file));
                }
            }
            return result;
        }
    }
}