/**
* 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.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.Properties;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.tools.ant.taskdefs.condition.Os;
import org.formic.Installer;
import org.formic.util.CommandExecutor;
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 specifying location of eclipse installation.
*
* @author Eric Van Dewoestine
*/
public class EclipseStep
extends AbstractGuiStep
{
private static final Logger logger = LoggerFactory.getLogger(EclipseStep.class);
private static final String[] WINDOWS_ECLIPSES = {
"C:/eclipse",
"C:/Program Files/eclipse",
"C:/Program Files (x86)/eclipse",
};
private static final String[] UNIX_ECLIPSES = {
"/opt/eclipse",
"/usr/lib/eclipse",
"/usr/lib/eclipse-3.3",
"/usr/local/eclipse",
"/usr/share/eclipse",
SystemUtils.USER_HOME + "/eclipse",
"/Applications/eclipse",
};
private boolean initializePanelAdded = false;
private JCheckBox overridePluginsCheckBox;
/**
* Constructs the welcome step.
*/
public EclipseStep(String name, Properties properties)
{
super(name, properties);
}
/**
* {@inheritDoc}
* @see org.formic.wizard.step.GuiStep#init()
*/
public Component init()
{
final JPanel panel =
new JPanel(new MigLayout("wrap 2, fillx", "[growprio 0] [fill]"));
GuiForm form = createForm();
String home = fieldName("home");
final FileChooser eclipseHomeChooser =
new FileChooser(JFileChooser.DIRECTORIES_ONLY);
panel.add(form.createMessagePanel(), "span");
panel.add(new JLabel(Installer.getString(home)));
panel.add(eclipseHomeChooser);
Validator validator = new ValidatorBuilder()
.required()
.isDirectory()
.validator(new EclipseHomeValidator())
.validator();
form.bind(home, eclipseHomeChooser.getTextField(),
new ValidatorBuilder()
.validator(validator)
.validator(new EclipseHomeWritableValidator())
.validator());
String eclipseHomeDefault = getDefaultEclipseHome();
// On systems where eclispe was installed via a package manger, the user may
// need to install the plugins in an alternate location.
if(!Os.isFamily(Os.FAMILY_WINDOWS)){
String local = fieldName("local");
String eclipseLocalDefault = eclipseHomeDefault;
final FileChooser eclipseLocalChooser =
new FileChooser(JFileChooser.DIRECTORIES_ONLY);
form.bind(local, eclipseLocalChooser.getTextField(),
new ValidatorBuilder().required().isDirectory().isWritable().validator());
final JTextField eclipseHomeField = eclipseHomeChooser.getTextField();
final JTextField eclipseLocalField = eclipseLocalChooser.getTextField();
eclipseLocalField.setText(eclipseLocalDefault);
eclipseLocalChooser.getButton().setEnabled(false);
String hasLocal = fieldName("hasLocal");
overridePluginsCheckBox = new JCheckBox(Installer.getString(hasLocal));
// button to initialize user local eclipse config.
final JPanel initializePanel = new JPanel(new FlowLayout());
final JButton initializeButton =
new JButton(new InitializeAction(eclipseHomeField, eclipseLocalField));
initializePanel.add(
new JLabel(Installer.getString("eclipse.initialize")));
initializePanel.add(initializeButton);
eclipseLocalField.setEnabled(false);
overridePluginsCheckBox.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
boolean selected = ((JCheckBox)e.getSource()).isSelected();
JTextField eclipseLocalField = eclipseLocalChooser.getTextField();
eclipseLocalField.setEnabled(selected);
eclipseLocalChooser.getButton().setEnabled(selected);
// force home field to re-validate
JTextField eclipseHomeField = eclipseHomeChooser.getTextField();
eclipseHomeField.setText(eclipseHomeField.getText());
if(!selected){
// force eclipse local text field to update itself
eclipseHomeField = eclipseHomeChooser.getTextField();
eclipseHomeField.setText(eclipseHomeField.getText());
initializeButton.setEnabled(false);
}else{
eclipseLocalField.grabFocus();
final File eclipseLocalPath = getDefaultEclipseLocalPath();
if(eclipseLocalPath != null){
setEclipseLocalPath(eclipseLocalField, eclipseLocalPath);
}else{
if(!initializePanelAdded){
initializePanelAdded = true;
panel.add(initializePanel, "span");
}
initializeButton.setEnabled(true);
}
}
}
});
eclipseHomeField.getDocument().addDocumentListener(
new EclipseHomeListener(
eclipseHomeField,
eclipseLocalField,
overridePluginsCheckBox,
validator));
panel.add(overridePluginsCheckBox, "span");
panel.add(new JLabel(Installer.getString(local)));
panel.add(eclipseLocalChooser);
// see if plugins are installed in user's home directory instead.
File eclipseLocalPath = getDefaultEclipseLocalPath();
if(eclipseLocalPath != null){
overridePluginsCheckBox.doClick();
}
}
eclipseHomeChooser.getTextField().setText(eclipseHomeDefault);
return panel;
}
/**
* {@inheritDoc}
* @see org.formic.wizard.WizardStep#proceed()
*/
public boolean proceed()
{
boolean proceed = super.proceed();
String home = (String)Installer.getContext().getValue("eclipse.home");
home = FilenameUtils.normalizeNoEndSeparator(home).replace('\\', '/');
Installer.getContext().setValue("eclipse.home", home);
if (Os.isFamily(Os.FAMILY_WINDOWS)){
Installer.getContext().setValue("eclipse.local", home);
}else{
String local = (String)Installer.getContext().getValue("eclipse.local");
local = FilenameUtils.normalizeNoEndSeparator(local);
Installer.getContext().setValue("eclipse.local", local);
if (!new org.formic.util.File(local).canWrite()){
proceed = false;
GuiDialogs.showWarning(
"You do not have write permissions on the directory:\n" +
" " + local + "");
}
}
return proceed;
}
/**
* Gets the default value to use for the eclipse home if any.
*
* @return The default value or null if none could be determined.
*/
private String getDefaultEclipseHome()
{
String home = Installer.getEnvironmentVariable("ECLIPSE_HOME");
if(home == null || home.trim().length() == 0){
if(Os.isFamily(Os.FAMILY_WINDOWS)){
for (int ii = 0; ii < WINDOWS_ECLIPSES.length; ii++){
if(new File(WINDOWS_ECLIPSES[ii]).exists()){
home = WINDOWS_ECLIPSES[ii];
break;
}
}
}else{
for (int ii = 0; ii < UNIX_ECLIPSES.length; ii++){
if(new File(UNIX_ECLIPSES[ii]).exists()){
home = UNIX_ECLIPSES[ii];
break;
}
}
}
}
return home;
}
/**
* Gets the default default user local eclipse path if one can be found.
*
* @return The default user local eclipse path (~/.eclipse/org.eclipse...).
*/
private File getDefaultEclipseLocalPath()
{
final File dotEclipse = new File(
Installer.getProject().replaceProperties("${user.home}/.eclipse"));
if(dotEclipse.exists()){
File[] contents = dotEclipse.listFiles(new FilenameFilter(){
public boolean accept(File dir, String name){
File configuration = new File(dir + "/" + name + "/configuration");
if (configuration.exists() && configuration.isDirectory()){
return true;
}
return false;
}
});
if(contents.length > 0){
if(contents.length > 1){
logger.warn(
"Found more than one possible local eclipse dir: " +
Arrays.toString(contents));
}
Arrays.sort(contents);
File dir = contents[contents.length - 1];
return dir;
}
}
return null;
}
private void setEclipseLocalPath(JTextField eclipseLocalField, File path)
{
eclipseLocalField.setText(path.getAbsolutePath());
eclipseLocalField.setCaretPosition(0);
}
private class EclipseHomeValidator
implements Validator
{
public boolean isValid(Object value)
{
String folder = (String)value;
if(folder != null && folder.trim().length() > 0){
File plugins = new File(FilenameUtils.concat(folder, "plugins"));
return plugins.exists() && plugins.isDirectory();
}
return true;
}
public String getErrorMessage()
{
return getName() + ".home.invalid";
}
}
private class EclipseHomeWritableValidator
implements Validator
{
public boolean isValid(Object value)
{
String folder = (String)value;
if(folder != null && folder.trim().length() > 0){
File plugins =
new org.formic.util.File(FilenameUtils.concat(folder, "plugins"));
return (overridePluginsCheckBox != null &&
overridePluginsCheckBox.isSelected()) ||
plugins.canWrite();
}
return true;
}
public String getErrorMessage()
{
return getName() + ".home.writable";
}
}
private class EclipseHomeListener
implements DocumentListener
{
private JTextField eclipseHome;
private JTextField eclipseLocal;
private JCheckBox hasLocal;
private final Validator eclipseHomeValidator;
public EclipseHomeListener(
JTextField eclipseHome,
JTextField eclipseLocal,
JCheckBox hasLocal,
Validator eclipseHomeValidator)
{
this.eclipseHome = eclipseHome;
this.eclipseLocal = eclipseLocal;
this.hasLocal = hasLocal;
this.eclipseHomeValidator = eclipseHomeValidator;
}
public void insertUpdate(DocumentEvent e)
{
pathUpdated(e);
}
public void removeUpdate(DocumentEvent e)
{
pathUpdated(e);
}
public void changedUpdate(DocumentEvent e)
{
pathUpdated(e);
}
private void pathUpdated(DocumentEvent e)
{
final String path = eclipseHome.getText();
if(!hasLocal.isSelected()){
eclipseLocal.setText(path);
}
if (path.length() > 0){
final File plugins =
new org.formic.util.File(FilenameUtils.concat(path, "plugins"));
SwingUtilities.invokeLater(new Runnable(){
public void run(){
if (eclipseHomeValidator.isValid(path) && !plugins.canWrite()){
if (!hasLocal.isSelected()){
hasLocal.doClick();
}
hasLocal.setEnabled(false);
}else{
hasLocal.setEnabled(true);
}
}
});
}
}
}
private class InitializeAction
extends AbstractAction
{
private static final long serialVersionUID = 1L;
private JTextField eclipseHomeField;
private JTextField eclipseLocalField;
public InitializeAction(
JTextField eclipseHomeField, JTextField eclipseLocalField)
{
super("Initialize");
this.eclipseHomeField = eclipseHomeField;
this.eclipseLocalField = eclipseLocalField;
}
public void actionPerformed(ActionEvent e)
{
setBusy(true);
try{
Worker.post(new Task(){
public Object run() throws Exception {
String eclipseHome = eclipseHomeField.getText();
String launcher = EclipseUtils.findEclipseLauncherJar(eclipseHome);
if (launcher == null){
throw new RuntimeException(
"Could not find the eclipse launcher jar for path: " + eclipseHome);
}
CommandExecutor executor = CommandExecutor.execute(
new String[]{"java", "-jar", launcher, "-initialize"}, 60000);
if(executor.getReturnCode() != 0){
throw new RuntimeException(
"error: " + executor.getErrorMessage() +
" out: " + executor.getResult());
}
return null;
}
});
((JButton)e.getSource()).setEnabled(false);
final File path = getDefaultEclipseLocalPath();
if (path != null){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
setEclipseLocalPath(eclipseLocalField, path);
new File(eclipseLocalField.getText()).mkdirs();
// force re-validation
eclipseLocalField.grabFocus();
}
});
}else{
GuiDialogs.showError(
"Unable to locate initialized user local eclipse dir.");
}
}catch(Exception ex){
GuiDialogs.showError(
"Error initializing user local eclipse configuration.", ex);
}finally{
setBusy(false);
}
}
}
}