Java tutorial
/** * Copyright (C) 2005 - 2012 Eric Van Dewoestine * * 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/>. */ package org.eclim.installer.step; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Properties; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.filechooser.FileFilter; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.taskdefs.Delete; import org.apache.tools.ant.taskdefs.condition.Os; import org.apache.tools.ant.types.FileSet; import org.formic.InstallContext; import org.formic.Installer; import org.formic.util.CommandExecutor; import org.formic.util.File; import org.formic.util.dialog.gui.GuiDialogs; import org.formic.wizard.form.GuiForm; import org.formic.wizard.form.Validator; import org.formic.wizard.form.gui.component.FileChooser; import org.formic.wizard.form.validator.ValidatorBuilder; import org.formic.wizard.step.AbstractGuiStep; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import foxtrot.Task; import foxtrot.Worker; import net.miginfocom.swing.MigLayout; /** * Step for choosing the vimfiles directory to install vim scripts in. * * @author Eric Van Dewoestine */ public class VimStep extends AbstractGuiStep { private static final Logger logger = LoggerFactory.getLogger(VimStep.class); private static final String[] WINDOWS_VIMS = { "vim.bat", "gvim.bat", "vim.exe", "gvim.exe", "C:/Program Files (x86)/Vim/vim73/vim.exe", "C:/Program Files (x86)/Vim/vim73/gvim.exe", "C:/Program Files (x86)/Vim/vim72/vim.exe", "C:/Program Files (x86)/Vim/vim72/gvim.exe", "C:/Program Files/Vim/vim73/vim.exe", "C:/Program Files/Vim/vim73/gvim.exe", "C:/Program Files/Vim/vim72/vim.exe", "C:/Program Files/Vim/vim72/gvim.exe", "C:/Program Files/Vim/vim71/vim.exe", "C:/Program Files/Vim/vim71/gvim.exe", "C:/Program Files/Vim/vim70/vim.exe", "C:/Program Files/Vim/vim70/gvim.exe", }; private static final String[] WINDOWS_GVIMS = { "C:/Program Files (x86)/Vim/vim73/gvim.exe", "C:/Program Files (x86)/Vim/vim72/gvim.exe", "C:/Program Files/Vim/vim73/gvim.exe", "C:/Program Files/Vim/vim72/gvim.exe", "C:/Program Files/Vim/vim71/gvim.exe", "C:/Program Files/Vim/vim70/gvim.exe", }; private static final String[] UNIX_VIMS = { "vim", "gvim" }; private static final String COMMAND = "redir! > <file> | silent! echo &rtp | quit"; private JPanel panel; private FileChooser fileChooser; private JList dirList; private JCheckBox skipCheckBox; private boolean rtpAttempted; private boolean homeVimCreatePrompted; private String[] runtimePath; /** * Constructs the step. */ public VimStep(String name, Properties properties) { super(name, properties); } /** * {@inheritDoc} * @see org.formic.wizard.step.GuiStep#init() */ public Component init() { GuiForm form = createForm(); String files = fieldName("files"); fileChooser = new FileChooser(JFileChooser.DIRECTORIES_ONLY); // allow just .vim dirs to not be hidden fileChooser.getFileChooser().setFileHidingEnabled(false); fileChooser.getFileChooser().addChoosableFileFilter(new FileFilter() { public boolean accept(java.io.File f) { String path = f.getAbsolutePath(); return f.isDirectory() && (path.matches(".*/\\.vim(/.*|$)") || !path.matches(".*/\\..*")); } public String getDescription() { return null; } }); String skip = fieldName("skip"); skipCheckBox = new JCheckBox(Installer.getString(skip)); skipCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { boolean selected = ((JCheckBox) e.getSource()).isSelected(); JTextField fileField = fileChooser.getTextField(); fileField.setEnabled(!selected); fileChooser.getButton().setEnabled(!selected); if (dirList != null) { dirList.setEnabled(!selected); } // hacky Validator validator = (Validator) fileField.getClientProperty("validator"); setValid(selected || validator.isValid(fileField.getText())); } }); panel = new JPanel(new MigLayout("wrap 2", "[fill]", "[] [] [] [fill, grow]")); panel.add(form.createMessagePanel(), "span"); panel.add(new JLabel(Installer.getString(files)), "split"); panel.add(fileChooser, "skip"); panel.add(skipCheckBox, "span"); form.bind(files, fileChooser.getTextField(), new ValidatorBuilder().required().isDirectory().fileExists().isWritable().validator()); return panel; } /** * {@inheritDoc} * @see org.formic.wizard.WizardStep#displayed() */ public void displayed() { if (!rtpAttempted) { rtpAttempted = true; setBusy(true); try { runtimePath = (String[]) Worker.post(new Task() { public Object run() throws Exception { setGvimProperty(); return getVimRuntimePath(); } }); // filter out dirs the user doesn't have permission write to. ArrayList<String> filtered = new ArrayList<String>(); if (runtimePath != null) { for (String path : runtimePath) { if (new File(path).canWrite()) { if (Installer.isUninstall()) { File eclimDir = new File(path + "/eclim"); if (eclimDir.exists()) { if (eclimDir.canWrite()) { filtered.add(path); } else { logger.warn(path + "/eclim is not writable by the current user"); } } } else { filtered.add(path); } } } } String[] rtp = filtered.toArray(new String[filtered.size()]); if (rtp == null || rtp.length == 0) { if (!Installer.isUninstall()) { if (!homeVimCreatePrompted) { createUserVimFiles("No suitable vim files directory found."); } else { GuiDialogs.showWarning( "Your vim install is still reporting no\n" + "suitable vim files directories.\n" + "You will need to manually specify one."); } } } else { if (rtp.length == 1) { fileChooser.getTextField().setText(rtp[0]); // try to discourage windows users from installing eclim files in // their vim installation. if (new File(rtp[0] + "/gvim.exe").exists()) { createUserVimFiles("No user vim files directory found."); } } else { dirList = new JList(rtp); dirList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); JScrollPane scrollPane = new JScrollPane(dirList); panel.add(scrollPane, "span, grow"); dirList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent event) { if (!event.getValueIsAdjusting()) { fileChooser.getTextField().setText((String) dirList.getSelectedValue()); } } }); dirList.setSelectedIndex(0); } } } catch (Exception e) { e.printStackTrace(); } setBusy(false); fileChooser.getTextField().grabFocus(); } } /** * {@inheritDoc} * @see org.formic.wizard.WizardStep#proceed() */ public boolean proceed() { boolean proceed = super.proceed(); if (proceed) { InstallContext context = Installer.getContext(); context.setValue("vim.skip", Boolean.valueOf(skipCheckBox.isSelected())); String vimfiles = (String) context.getValue("vim.files"); if (vimfiles != null) { vimfiles = vimfiles.replace('\\', '/'); context.setValue("vim.files", vimfiles); // Check if the user has the eclim vim files already installed in // another directory in their vim's runtime path. // on windows, since case is insensitive, lower the path. if (Os.isFamily(Os.FAMILY_WINDOWS)) { vimfiles = vimfiles.toLowerCase(); } if (runtimePath != null && runtimePath.length > 0) { for (String rpath : runtimePath) { String path = rpath; if (Os.isFamily(Os.FAMILY_WINDOWS)) { path = path.toLowerCase(); } if (vimfiles.equals(path)) { continue; } File fpath = new File(path + "/plugin/eclim.vim"); if (!fpath.exists()) { continue; } if (fpath.canWrite()) { boolean remove = GuiDialogs .showConfirm("You appear to have one or more of the eclim vim files\n" + "installed in another directory:\n" + " " + rpath + "\n" + "Would you like the installer to remove those files now?"); if (remove) { Delete delete = new Delete(); delete.setProject(Installer.getProject()); delete.setTaskName("delete"); delete.setIncludeEmptyDirs(true); delete.setFailOnError(true); FileSet set = new FileSet(); set.setDir(new File(path + "/eclim")); set.createInclude().setName("**/*"); set.createExclude().setName("after/**/*"); set.createExclude().setName("resources/**/*"); delete.addFileset(set); try { boolean deleted = fpath.delete(); if (!deleted) { throw new BuildException("Failed to delete file: plugin/eclim.vim"); } delete.execute(); } catch (BuildException be) { GuiDialogs.showError("Failed to delete old eclim vim files:\n" + " " + be.getMessage() + "\n" + "You may continue with the installation, but if old eclim\n" + "vim files remain, chances are that you will receive\n" + "errors upon starting (g)vim and the older version of\n" + "the files may take precedence over the ones you are\n" + "installing now, leading to indeterminate behavior."); } } proceed = remove; } else { GuiDialogs.showWarning("You appear to have one or more of the eclim vim files\n" + "installed in another directory:\n" + " " + rpath + "\n" + "Unfortunately it seems you do not have write access to\n" + "that directory. You may continue with the installation,\n" + "but chances are that you will receive errors upon starting\n" + "(g)vim and the older version of the files may take precedence\n" + "over the ones you are installing now, leading to indeterminate\n" + "behavior."); } } } } } return proceed; } /** * Attempt to find where gvim is installed. */ private void setGvimProperty() { try { String[] gvims = null; if (Os.isFamily(Os.FAMILY_WINDOWS)) { gvims = WINDOWS_GVIMS; for (String gvim : gvims) { if (new File(gvim).isFile()) { Installer.getProject().setProperty("eclim.gvim", gvim); break; } } } else { String vim = Os.isFamily(Os.FAMILY_MAC) ? "mvim" : "gvim"; CommandExecutor executor = CommandExecutor.execute(new String[] { "which", vim }, 1000); if (executor.getReturnCode() == 0) { String result = executor.getResult().trim(); logger.info("which " + vim + ": " + result); Installer.getProject().setProperty("eclim.gvim", result); } else { logger.info("which " + vim + ':' + " out=" + executor.getResult() + " err=" + executor.getErrorMessage()); } } } catch (Exception e) { e.printStackTrace(); } } /** * Prompt the user to create the standard user local vim files directory. * * @param message The message indicating the primary reason we're asking them * if they want to create the user local directory. */ private void createUserVimFiles(String message) { homeVimCreatePrompted = true; File vimfiles = new File( System.getProperty("user.home") + '/' + (Os.isFamily(Os.FAMILY_WINDOWS) ? "vimfiles" : ".vim")); System.out.println("Checking for user vim files directory: " + vimfiles); if (!vimfiles.exists()) { boolean create = GuiDialogs.showConfirm(message + "\n" + "Would you like to create the standard\n" + "directory for your system?\n" + vimfiles); if (create) { boolean created = vimfiles.mkdir(); if (created) { rtpAttempted = false; displayed(); } else { GuiDialogs.showError("Unable to create directory: " + vimfiles); } } } else { fileChooser.getTextField().setText(vimfiles.getAbsolutePath().replace('\\', '/')); } } /** * Attempts to determine available paths in vim's runtime path. * * @return Array of paths or null if unable to determine any. */ private String[] getVimRuntimePath() { try { java.io.File tempFile = File.createTempFile("eclim_installer", null); String command = COMMAND.replaceFirst("<file>", tempFile.getAbsolutePath().replace('\\', '/').replaceAll(" ", "\\ ")); String[] vims = null; if (Os.isFamily(Os.FAMILY_WINDOWS)) { vims = WINDOWS_VIMS; } else { vims = UNIX_VIMS; } String[] args = { null, "-f", "-X", "-u", "NONE", "-U", "NONE", "--cmd", command, }; for (int ii = 0; ii < vims.length; ii++) { args[0] = vims[ii]; CommandExecutor executor = CommandExecutor.execute(args, 5000); if (executor.getReturnCode() == 0) { return parseVimRuntimePathResults(tempFile); } if (executor.isShutdown()) { return null; } executor.destroy(); } } catch (Exception e) { GuiDialogs.showError("Error determining your vim runtime path.", e); } return null; } /** * Parses the results of echoing vim runtime path to a file. * * @param file The file containing the results. * @return The results. */ private String[] parseVimRuntimePathResults(java.io.File file) { FileInputStream in = null; try { String contents = IOUtils.toString(in = new FileInputStream(file)); String[] paths = StringUtils.stripAll(StringUtils.split(contents, ',')); ArrayList<String> results = new ArrayList<String>(); for (String path : paths) { if (new File(path).isDirectory()) { results.add(path.replace('\\', '/')); } } return results.toArray(new String[results.size()]); } catch (Exception e) { e.printStackTrace(); } finally { IOUtils.closeQuietly(in); file.deleteOnExit(); file.delete(); } return null; } }