org.intellij.erlang.settings.ErlangExternalToolsConfigurable.java Source code

Java tutorial

Introduction

Here is the source code for org.intellij.erlang.settings.ErlangExternalToolsConfigurable.java

Source

/*
 * Copyright 2012-2013 Sergey Ignatov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.intellij.erlang.settings;

import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.TitledSeparator;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.intellij.erlang.dialyzer.DialyzerSettings;
import org.intellij.erlang.emacs.EmacsSettings;
import org.intellij.erlang.rebar.settings.RebarConfigurationForm;
import org.intellij.erlang.rebar.settings.RebarSettings;
import org.intellij.erlang.sdk.ErlangSystemUtil;
import org.intellij.erlang.utils.ExtProcessUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.io.File;

/**
 * @author Maxim Vladimirsky, ignatov
 */
public class ErlangExternalToolsConfigurable implements SearchableConfigurable, Configurable.NoScroll {
    public static final String ERLANG_RELATED_TOOLS = "Erlang External Tools";
    public static final String ERLANG_LIBRARY_NAME = "Erlang SDK";
    private final Project myProject;
    private JPanel myPanel;
    private TextFieldWithBrowseButton myEmacsPathSelector;
    private JTextField myEmacsVersionText;
    private RebarConfigurationForm myRebarConfigurationForm;
    private TextFieldWithBrowseButton myPltPathSelector;
    private String myPrevEmacsPath;
    private EmacsSettings myEmacsSettings;
    private RebarSettings myRebarSettings;
    private DialyzerSettings myDialyzerSettings;
    private TextFieldWithBrowseButton mySdkPathSelector;
    private TitledSeparator mySdkTitledSeparator;
    private JLabel mySdkPathLabel;

    public ErlangExternalToolsConfigurable(@NotNull Project project) {
        myProject = project;
        myRebarSettings = RebarSettings.getInstance(project);
        myEmacsSettings = EmacsSettings.getInstance(project);
        myDialyzerSettings = DialyzerSettings.getInstance(project);
        myEmacsPathSelector.addBrowseFolderListener("Select Emacs executable", "", null,
                FileChooserDescriptorFactory.createSingleLocalFileDescriptor());
        myPltPathSelector.addBrowseFolderListener("Select dialyzer PLT", "", null,
                FileChooserDescriptorFactory.createSingleLocalFileDescriptor());
        mySdkPathSelector.addBrowseFolderListener("Select Erlang SDK path", "", null,
                FileChooserDescriptorFactory.getDirectoryChooserDescriptor("Erlang SDK root"));
        myPrevEmacsPath = myEmacsSettings.getEmacsPath();

        if (StringUtil.isEmpty(myRebarSettings.getRebarPath())) {
            VirtualFile baseDir = project.getBaseDir();
            if (baseDir != null) {
                VirtualFile rebar = baseDir.findChild("rebar");
                if (rebar != null) {
                    String canonicalPath = rebar.getCanonicalPath();
                    if (canonicalPath != null) {
                        myRebarSettings.setRebarPath(canonicalPath);
                    }
                }
            }
        }

        if (StringUtils.isEmpty(myEmacsSettings.getEmacsPath()) && (SystemInfo.isLinux || SystemInfo.isMac)) {
            String suggestedPath = "/usr/bin/emacs";
            File file = new File(suggestedPath);
            if (file.exists() && FileUtil.canExecute(file)) {
                myEmacsSettings.setEmacsPath(suggestedPath);
            }
        }

        if (!ErlangSystemUtil.isSmallIde()) {
            mySdkPathSelector.setVisible(false);
            mySdkTitledSeparator.setVisible(false);
            mySdkPathLabel.setVisible(false);
        }

        reset();
    }

    @NotNull
    @Override
    public String getId() {
        return ERLANG_RELATED_TOOLS;
    }

    @Nullable
    @Override
    public Runnable enableSearch(String option) {
        return null;
    }

    @NonNls
    @Override
    public String getDisplayName() {
        return ERLANG_RELATED_TOOLS;
    }

    @Nullable
    @Override
    public String getHelpTopic() {
        return null;
    }

    @Nullable
    @Override
    public JComponent createComponent() {
        myRebarConfigurationForm.createComponent();
        return myPanel;
    }

    @Override
    public boolean isModified() {
        String emacsSelectedPath = myEmacsPathSelector.getText();
        if (!myPrevEmacsPath.equals(emacsSelectedPath))
            validateEmacsPath();

        return !myRebarSettings.getRebarPath().equals(myRebarConfigurationForm.getPath())
                || !myEmacsSettings.getEmacsPath().equals(emacsSelectedPath)
                || !myDialyzerSettings.getCurrentPltPath().equals(myPltPathSelector.getText())
                || !getErlangSdkPath().equals(mySdkPathSelector.getText());
    }

    @Override
    public void apply() throws ConfigurationException {
        myRebarSettings.setRebarPath(myRebarConfigurationForm.getPath());
        myEmacsSettings.setEmacsPath(myEmacsPathSelector.getText());
        myDialyzerSettings.setCurrentPltPath(myPltPathSelector.getText());
        setUpOrUpdateSdk(mySdkPathSelector.getText());
    }

    @Override
    public void reset() {
        myRebarConfigurationForm.setPath(myRebarSettings.getRebarPath());
        myEmacsPathSelector.setText(myEmacsSettings.getEmacsPath());
        myPltPathSelector.setText(myDialyzerSettings.getCurrentPltPath());
        mySdkPathSelector.setText(getErlangSdkPath());
        validateEmacsPath();
    }

    @Override
    public void disposeUIResources() {
    }

    private void validateEmacsPath() {
        String version = ExtProcessUtil.restrictedTimeExec(myEmacsPathSelector.getText() + " --version", 3000);
        String[] split = StringUtils.split(version, "\n");
        if (StringUtils.containsIgnoreCase(version, "emacs") && split.length > 0) {
            myEmacsVersionText.setText(ArrayUtil.getFirstElement(split));
        } else {
            myEmacsVersionText.setText("N/A");
        }
    }

    @NotNull
    public String getErlangSdkPath() {
        return getErlangSdkPath(myProject);
    }

    @NotNull
    public static String getErlangSdkPath(@NotNull Project project) {
        AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
        try {
            LibraryTable table = LibraryTablesRegistrar.getInstance().getLibraryTable(project);
            Library lib = table.getLibraryByName(ERLANG_LIBRARY_NAME);
            String[] urls = lib == null ? ArrayUtil.EMPTY_STRING_ARRAY : lib.getUrls(OrderRootType.CLASSES);
            return VfsUtilCore.urlToPath(ObjectUtils.notNull(ArrayUtil.getFirstElement(urls), ""));
        } finally {
            token.finish();
        }
    }

    private void setUpOrUpdateSdk(@NotNull final String path) {
        ApplicationManager.getApplication().runWriteAction(new Runnable() {
            @Override
            public void run() {
                LibraryTable table = LibraryTablesRegistrar.getInstance().getLibraryTable(myProject);
                Library get = table.getLibraryByName(ERLANG_LIBRARY_NAME);
                Library lib = get != null ? get : table.createLibrary(ERLANG_LIBRARY_NAME);

                Library.ModifiableModel libraryModel = lib.getModifiableModel();
                String libUrl = ArrayUtil.getFirstElement(lib.getUrls(OrderRootType.CLASSES));
                if (libUrl != null) {
                    libraryModel.removeRoot(libUrl, OrderRootType.CLASSES);
                }

                String url = VfsUtilCore.pathToUrl(path);
                libraryModel.addRoot(url, OrderRootType.CLASSES);
                libraryModel.commit();

                boolean remove = path.isEmpty();
                if (remove) {
                    updateModules(lib, true);
                    table.removeLibrary(lib);
                }

                table.getModifiableModel().commit();

                if (!remove) {
                    updateModules(lib, false);
                }
            }
        });
    }

    private void updateModules(@NotNull Library lib, boolean remove) {
        Module[] modules = ModuleManager.getInstance(myProject).getModules();
        for (Module module : modules) {
            ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
            if (!remove) {
                if (model.findLibraryOrderEntry(lib) == null) {
                    LibraryOrderEntry entry = model.addLibraryEntry(lib);
                    entry.setScope(DependencyScope.PROVIDED);
                }
            } else {
                LibraryOrderEntry entry = model.findLibraryOrderEntry(lib);
                if (entry != null) {
                    model.removeOrderEntry(entry);
                }
            }
            model.commit();
        }
    }
}