com.intellij.execution.ui.JrePathEditor.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.execution.ui.JrePathEditor.java

Source

/*
 * Copyright 2000-2015 JetBrains s.r.o.
 *
 * 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 com.intellij.execution.ui;

import com.intellij.execution.ExecutionBundle;
import com.intellij.icons.AllIcons;
import com.intellij.ide.util.BrowseFilesListener;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ui.OrderEntryAppearanceService;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.ui.StatusText;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import java.io.File;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;

/**
 * @author nik
 */
public class JrePathEditor extends JPanel implements PanelWithAnchor {
    private static final String DEFAULT_JRE_TEXT = "Default";
    private final ComboboxWithBrowseButton myPathField;
    private final JBLabel myLabel;
    private final JreComboboxEditor myComboboxEditor;
    private final DefaultJreItem myDefaultJreItem;
    private DefaultJreSelector myDefaultJreSelector;
    private JComponent myAnchor;
    private final SortedComboBoxModel<JreComboBoxItem> myComboBoxModel;
    private String myPreviousCustomJrePath;

    public JrePathEditor(DefaultJreSelector defaultJreSelector) {
        this();
        setDefaultJreSelector(defaultJreSelector);
    }

    /**
     * This constructor can be used in UI forms. <strong>Don't forget to call {@link #setDefaultJreSelector(DefaultJreSelector)}!</strong>
     */
    public JrePathEditor() {
        myLabel = new JBLabel(ExecutionBundle.message("run.configuration.jre.label"));

        myComboBoxModel = new SortedComboBoxModel<JreComboBoxItem>((o1, o2) -> {
            int result = Comparing.compare(o1.getOrder(), o2.getOrder());
            if (result != 0) {
                return result;
            }
            return o1.getPresentableText().compareToIgnoreCase(o2.getPresentableText());
        });
        myDefaultJreItem = new DefaultJreItem();
        myComboBoxModel.add(myDefaultJreItem);
        final Sdk[] allJDKs = ProjectJdkTable.getInstance().getAllJdks();
        for (Sdk sdk : allJDKs) {
            myComboBoxModel.add(new SdkAsJreItem(sdk));
        }

        final Set<String> jrePaths = new HashSet<String>();
        for (JreProvider provider : JreProvider.EP_NAME.getExtensions()) {
            String path = provider.getJrePath();
            if (!StringUtil.isEmpty(path)) {
                jrePaths.add(path);
                myComboBoxModel.add(new CustomJreItem(path));
            }
        }

        for (Sdk jdk : allJDKs) {
            String homePath = jdk.getHomePath();

            if (!SystemInfo.isMac) {
                final File jre = new File(jdk.getHomePath(), "jre");
                if (jre.isDirectory()) {
                    homePath = jre.getPath();
                }
            }
            if (jrePaths.add(homePath)) {
                myComboBoxModel.add(new CustomJreItem(homePath));
            }
        }
        ComboBox comboBox = new ComboBox(myComboBoxModel, 100);
        comboBox.setEditable(true);
        comboBox.setRenderer(new ColoredListCellRendererWrapper<JreComboBoxItem>() {
            @Override
            protected void doCustomize(JList list, JreComboBoxItem value, int index, boolean selected,
                    boolean hasFocus) {
                if (value != null) {
                    value.render(this, selected);
                }
            }
        });
        myComboboxEditor = new JreComboboxEditor(myComboBoxModel);
        myComboboxEditor.getEditorComponent().setTextToTriggerEmptyTextStatus(DEFAULT_JRE_TEXT);
        comboBox.setEditor(myComboboxEditor);
        myPathField = new ComboboxWithBrowseButton(comboBox);
        myPathField.addBrowseFolderListener(ExecutionBundle.message("run.configuration.select.alternate.jre.label"),
                ExecutionBundle.message("run.configuration.select.jre.dir.label"), null,
                BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR, JreComboboxEditor.TEXT_COMPONENT_ACCESSOR);

        setLayout(new MigLayout("ins 0, gap 10, fill, flowx"));
        add(myLabel, "shrinkx");
        add(myPathField, "growx, pushx");

        InsertPathAction.addTo(myComboboxEditor.getEditorComponent());

        setAnchor(myLabel);

        updateUI();
    }

    @Nullable
    public String getJrePathOrName() {
        JreComboBoxItem jre = getSelectedJre();
        if (jre instanceof DefaultJreItem) {
            return myPreviousCustomJrePath;
        }
        return jre.getPathOrName();
    }

    public boolean isAlternativeJreSelected() {
        return !(getSelectedJre() instanceof DefaultJreItem);
    }

    private JreComboBoxItem getSelectedJre() {
        return (JreComboBoxItem) myPathField.getComboBox().getEditor().getItem();
    }

    public void setDefaultJreSelector(DefaultJreSelector defaultJreSelector) {
        myDefaultJreSelector = defaultJreSelector;
        myDefaultJreSelector.addChangeListener(() -> updateDefaultJrePresentation());
    }

    public void setPathOrName(@Nullable String pathOrName, boolean useAlternativeJre) {
        JreComboBoxItem toSelect = myDefaultJreItem;
        if (!StringUtil.isEmpty(pathOrName)) {
            myPreviousCustomJrePath = pathOrName;
            JreComboBoxItem alternative = findOrAddCustomJre(pathOrName);
            if (useAlternativeJre) {
                toSelect = alternative;
            }
        }
        myPathField.getChildComponent().setSelectedItem(toSelect);
        updateDefaultJrePresentation();
    }

    private void updateDefaultJrePresentation() {
        StatusText text = myComboboxEditor.getEmptyText();
        text.clear();
        text.appendText(DEFAULT_JRE_TEXT, SimpleTextAttributes.REGULAR_ATTRIBUTES);
        text.appendText(myDefaultJreSelector.getDescriptionString(), SimpleTextAttributes.GRAY_ATTRIBUTES);
    }

    private JreComboBoxItem findOrAddCustomJre(@NotNull String pathOrName) {
        for (JreComboBoxItem item : myComboBoxModel.getItems()) {
            if (item instanceof CustomJreItem && FileUtil.pathsEqual(pathOrName, ((CustomJreItem) item).myPath)
                    || pathOrName.equals(item.getPathOrName())) {
                return item;
            }
        }
        CustomJreItem item = new CustomJreItem(pathOrName);
        myComboBoxModel.add(item);
        return item;
    }

    @Override
    public JComponent getAnchor() {
        return myAnchor;
    }

    @Override
    public void setAnchor(JComponent anchor) {
        myAnchor = anchor;
        myLabel.setAnchor(anchor);
    }

    interface JreComboBoxItem {
        void render(SimpleColoredComponent component, boolean selected);

        String getPresentableText();

        @Nullable
        String getPathOrName();

        int getOrder();
    }

    private static class SdkAsJreItem implements JreComboBoxItem {
        private final Sdk mySdk;

        public SdkAsJreItem(Sdk sdk) {
            mySdk = sdk;
        }

        @Override
        public void render(SimpleColoredComponent component, boolean selected) {
            OrderEntryAppearanceService.getInstance().forJdk(mySdk, false, selected, true).customize(component);
        }

        @Override
        public String getPresentableText() {
            return mySdk.getName();
        }

        @Override
        public String getPathOrName() {
            return mySdk.getName();
        }

        @Override
        public int getOrder() {
            return 1;
        }
    }

    static class CustomJreItem implements JreComboBoxItem {
        private final String myPath;

        public CustomJreItem(String path) {
            myPath = path;
        }

        @Override
        public void render(SimpleColoredComponent component, boolean selected) {
            component.append(getPresentableText());
            component.setIcon(AllIcons.Nodes.Folder);
        }

        @Override
        public String getPresentableText() {
            return FileUtil.toSystemDependentName(myPath);
        }

        @Override
        public String getPathOrName() {
            return myPath;
        }

        @Override
        public int getOrder() {
            return 2;
        }
    }

    private class DefaultJreItem implements JreComboBoxItem {
        @Override
        public void render(SimpleColoredComponent component, boolean selected) {
            component.append(DEFAULT_JRE_TEXT);
            //may be null if JrePathEditor is added to a GUI Form where the default constructor is used and setDefaultJreSelector isn't called
            if (myDefaultJreSelector != null) {
                component.append(myDefaultJreSelector.getDescriptionString(), SimpleTextAttributes.GRAY_ATTRIBUTES);
            }
        }

        @Override
        public String getPresentableText() {
            return DEFAULT_JRE_TEXT;
        }

        @Override
        public String getPathOrName() {
            return null;
        }

        @Override
        public int getOrder() {
            return 0;
        }
    }
}