blob: 0512bb051bf7e5e302a36df0b289a5f7cc0880fc [file] [log] [blame]
/*
* Copyright 2000-2013 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.jetbrains.python.configuration;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.projectRoots.ui.SdkPathEditor;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.ListCellRendererWrapper;
import com.intellij.ui.ListUtil;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBList;
import com.intellij.util.ArrayUtil;
import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Set;
/**
* @author traff
*/
public class PythonPathEditor extends SdkPathEditor {
private final PathListModel myPathListModel;
public PythonPathEditor(final String displayName,
final OrderRootType orderRootType,
final FileChooserDescriptor descriptor) {
super(displayName, orderRootType, descriptor);
myPathListModel = new PathListModel(orderRootType, getListModel());
}
public void reset(@Nullable SdkModificator modificator) {
if (modificator != null) {
List<VirtualFile> list = Lists.newArrayList(modificator.getRoots(getOrderRootType()));
resetPath(myPathListModel.reset(list, modificator));
}
else {
setEnabled(false);
}
}
public void reload(@Nullable SdkModificator sdkModificator) {
if (sdkModificator != null) {
List<VirtualFile> list = Lists.newArrayList(sdkModificator.getRoots(getOrderRootType()));
resetPath(myPathListModel.reload(list));
setModified(true);
}
else {
setEnabled(false);
}
}
@Override
public void apply(SdkModificator sdkModificator) {
sdkModificator.removeRoots(getOrderRootType());
// add all items
for (int i = 0; i < myPathListModel.getRowCount(); i++) {
VirtualFile path = myPathListModel.getValueAt(i);
if (!myPathListModel.isExcluded(path)) {
sdkModificator.addRoot(path, getOrderRootType());
}
}
setModified(false);
myPathListModel.apply(sdkModificator);
}
@Override
protected VirtualFile[] adjustAddedFileSet(Component component, VirtualFile[] files) {
for (int i = 0, filesLength = files.length; i < filesLength; i++) {
if (files[i].getFileType() == FileTypes.ARCHIVE) {
files[i] = JarFileSystem.getInstance().getJarRootForLocalFile(files[i]);
}
}
if (myPathListModel.add(Lists.newArrayList(files))) {
setModified(true);
}
return files;
}
@Override
protected void doRemoveItems(int[] idxs, JList list) {
List<Pair<VirtualFile, Integer>> removed = Lists.newArrayList();
for (int i : idxs) {
removed.add(Pair.create((VirtualFile)getListModel().get(i), i));
}
ListUtil.removeIndices(list, myPathListModel.remove(removed));
list.updateUI();
setModified(true);
}
@Override
protected ListCellRenderer createListCellRenderer(JBList list) {
return new PythonPathListCellRenderer(super.createListCellRenderer(list), myPathListModel);
}
@Override
protected void addToolbarButtons(ToolbarDecorator toolbarDecorator) {
AnActionButton reloadButton = new AnActionButton("Reload list of paths", AllIcons.Actions.Refresh) {
@Override
public void actionPerformed(AnActionEvent e) {
onReloadButtonClicked();
}
};
toolbarDecorator.addExtraAction(reloadButton);
}
protected void onReloadButtonClicked() {
}
private static class PathListModel {
private Set<VirtualFile> myAdded = Sets.newHashSet();
private Set<VirtualFile> myExcluded = Sets.newHashSet();
private Set<VirtualFile> myFoundFiles = Sets.newHashSet();
private List<VirtualFile> myFilteredOut = Lists.newArrayList();
private final DefaultListModel myListModel;
private final OrderRootType myOrderRootType;
private Set<VirtualFile> myUserAddedToRemove = Sets.newHashSet();
public PathListModel(OrderRootType orderRootType, DefaultListModel listModel) {
myOrderRootType = orderRootType;
myListModel = listModel;
}
private int getRowCount() {
return myListModel.getSize();
}
private VirtualFile getValueAt(int row) {
return (VirtualFile)myListModel.get(row);
}
public boolean add(List<VirtualFile> files) {
for (VirtualFile file : files) {
if (!myFoundFiles.contains(file)) {
if (!myExcluded.remove(file)) { //if it was excluded we only delete exclusion mark
myAdded.add(file);
myUserAddedToRemove.remove(file);
}
else {
myFoundFiles.add(file);
return true;
}
} else {
myExcluded.remove(file);
}
}
return false;
}
public int[] remove(List<Pair<VirtualFile, Integer>> files) {
List<Integer> toRemove = Lists.newArrayList();
for (Pair<VirtualFile, Integer> e : files) {
if (myAdded.contains(e.first)) {
toRemove.add(e.second);
myAdded.remove(e.first);
myUserAddedToRemove.add(e.first);
}
else if (myExcluded.contains(e.first)) {
myExcluded.remove(e.first);
}
else {
myExcluded.add(e.first);
}
}
return ArrayUtil.toIntArray(toRemove);
}
public void apply(SdkModificator sdkModificator) {
sdkModificator.setSdkAdditionalData(collectSdkAdditionalData(sdkModificator));
addFilteredOutRoots(sdkModificator);
}
private void addFilteredOutRoots(SdkModificator sdkModificator) {
for (VirtualFile file : myFilteredOut) {
sdkModificator.addRoot(file, myOrderRootType);
}
}
private SdkAdditionalData collectSdkAdditionalData(SdkModificator sdkModificator) {
PythonSdkAdditionalData data = (PythonSdkAdditionalData)sdkModificator.getSdkAdditionalData();
if (data == null) {
data = new PythonSdkAdditionalData(null);
}
data.setAddedPathsFromVirtualFiles(myAdded);
data.setExcludedPathsFromVirtualFiles(myExcluded);
return data;
}
public void setAdded(Set<VirtualFile> added) {
myAdded = Sets.newHashSet(added);
}
public void setExcluded(Set<VirtualFile> excluded) {
myExcluded = Sets.newHashSet(excluded);
}
public String getPresentationSuffix(VirtualFile file) {
if (myAdded.contains(file)) {
return "(added by user)";
}
if (myExcluded.contains(file)) {
return "(removed by user)";
}
return "";
}
public List<VirtualFile> reload(List<VirtualFile> list) {
myFoundFiles.clear();
myFoundFiles.addAll(list);
List<VirtualFile> result = filterOutStubs(list, myFilteredOut);
result.removeAll(myUserAddedToRemove);
result.addAll(myAdded);
return result;
}
public List<VirtualFile> reset(List<VirtualFile> list, SdkModificator modificator) {
myFilteredOut.clear();
List<VirtualFile> result = filterOutStubs(list, myFilteredOut);
myFoundFiles.clear();
myFoundFiles.addAll(list);
myUserAddedToRemove.clear();
if (modificator.getSdkAdditionalData() instanceof PythonSdkAdditionalData) {
PythonSdkAdditionalData data = (PythonSdkAdditionalData)modificator.getSdkAdditionalData();
setAdded(data.getAddedPathFiles());
setExcluded(data.getExcludedPathFiles());
result.addAll(myExcluded);
}
else if (modificator.getSdkAdditionalData() == null) {
myAdded.clear();
myExcluded.clear();
}
return result;
}
private static List<VirtualFile> filterOutStubs(List<VirtualFile> list, List<VirtualFile> filteredOut) {
List<VirtualFile> result = Lists.newArrayList();
filteredOut.clear();
for (VirtualFile file : list) {
if (!isStubPath(file)) {
result.add(file);
}
else {
filteredOut.add(file);
}
}
return result;
}
private static boolean isStubPath(@NotNull VirtualFile file) {
final String path = PythonSdkType.getSkeletonsRootPath(PathManager.getSystemPath());
final VirtualFile skeletonRoot = LocalFileSystem.getInstance().findFileByPath(path);
if (skeletonRoot != null && file.getPath().startsWith(skeletonRoot.getPath())) {
return true;
}
else if (file.equals(PyUserSkeletonsUtil.getUserSkeletonsDirectory())) {
return true;
}
else {
return false;
}
}
public boolean isExcluded(VirtualFile path) {
return myExcluded.contains(path);
}
}
private class PythonPathListCellRenderer extends ListCellRendererWrapper<VirtualFile> {
private final PathListModel model;
public PythonPathListCellRenderer(final ListCellRenderer listCellRenderer, PathListModel model) {
super();
this.model = model;
}
@Override
public void customize(JList list, VirtualFile value, int index, boolean selected, boolean hasFocus) {
String suffix = model.getPresentationSuffix(value);
if (suffix.length() > 0) {
suffix = " " + suffix;
}
setText(value != null ? getPresentablePath(value) + suffix : "");
}
}
protected String getPresentablePath(VirtualFile value) {
return value.getPresentableUrl();
}
}