/*
* Copyright 2013-2016 Sergey Ignatov, Alexander Zolotov, Florin Patan
*
* 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.goide.configuration;
import com.goide.project.GoApplicationLibrariesService;
import com.goide.project.GoLibrariesService;
import com.intellij.openapi.fileChooser.FileChooserDialog;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.ui.CollectionListModel;
import com.intellij.ui.ColoredListCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBList;
import com.intellij.util.IconUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import static com.intellij.openapi.fileChooser.FileChooserDescriptorFactory.createMultipleFoldersDescriptor;
public class GoLibrariesConfigurable implements SearchableConfigurable, Configurable.NoScroll {
@NotNull private final String myDisplayName;
private final GoLibrariesService<?> myLibrariesService;
private final String[] myReadOnlyPaths;
private final JBCheckBox myUseEnvGoPathCheckBox = new JBCheckBox("Use GOPATH that's defined in system environment");
private final JPanel myPanel = new JPanel(new BorderLayout());
private final CollectionListModel<ListItem> myListModel = new CollectionListModel<>();
public GoLibrariesConfigurable(@NotNull String displayName, @NotNull GoLibrariesService librariesService, String... urls) {
myDisplayName = displayName;
myLibrariesService = librariesService;
myReadOnlyPaths = urls;
JBList filesList = new JBList(myListModel);
filesList.setCellRenderer(new ColoredListCellRenderer() {
@Override
protected void customizeCellRenderer(@NotNull JList list, Object value, int index, boolean selected, boolean hasFocus) {
ListItem item = (ListItem)value;
String url = item.url;
if (item.readOnly) {
append("[GOPATH] ", SimpleTextAttributes.GRAY_ATTRIBUTES);
}
VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url);
if (file != null) {
append(file.getPresentableUrl(), item.readOnly ? SimpleTextAttributes.GRAY_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES);
setIcon(IconUtil.getIcon(file, Iconable.ICON_FLAG_READ_STATUS, null));
}
else {
append(VfsUtilCore.urlToPath(url), SimpleTextAttributes.ERROR_ATTRIBUTES);
}
}
});
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(filesList)
.setAddAction(button -> {
FileChooserDialog fileChooser = FileChooserFactory.getInstance()
.createFileChooser(createMultipleFoldersDescriptor(), null, filesList);
VirtualFile fileToSelect = null;
ListItem lastItem = ContainerUtil.getLastItem(myListModel.getItems());
if (lastItem != null) {
fileToSelect = VirtualFileManager.getInstance().findFileByUrl(lastItem.url);
}
VirtualFile[] newDirectories = fileChooser.choose(null, fileToSelect);
if (newDirectories.length > 0) {
for (VirtualFile newDirectory : newDirectories) {
String newDirectoryUrl = newDirectory.getUrl();
boolean alreadyAdded = false;
for (ListItem item : myListModel.getItems()) {
if (newDirectoryUrl.equals(item.url) && !item.readOnly) {
filesList.clearSelection();
filesList.setSelectedValue(item, true);
scrollToSelection(filesList);
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
myListModel.add(new ListItem(newDirectoryUrl, false));
}
}
}
})
.setRemoveActionUpdater(event -> {
for (Object selectedValue : filesList.getSelectedValuesList()) {
if (((ListItem)selectedValue).readOnly) {
return false;
}
}
return true;
})
.setRemoveAction(button -> {
for (Object selectedValue : filesList.getSelectedValuesList()) {
myListModel.remove((ListItem)selectedValue);
}
});
myPanel.add(decorator.createPanel(), BorderLayout.CENTER);
if (librariesService instanceof GoApplicationLibrariesService) {
myUseEnvGoPathCheckBox.addActionListener(event -> {
if (myUseEnvGoPathCheckBox.isSelected()) {
addReadOnlyPaths();
}
else {
removeReadOnlyPaths();
}
});
myPanel.add(myUseEnvGoPathCheckBox, BorderLayout.SOUTH);
}
}
private static void scrollToSelection(JList list) {
int selectedRow = list.getSelectedIndex();
if (selectedRow >= 0) {
list.scrollRectToVisible(list.getCellBounds(selectedRow, 0));
}
}
@Nullable
@Override
public JComponent createComponent() {
return myPanel;
}
@Override
public boolean isModified() {
return !getUserDefinedUrls().equals(myLibrariesService.getLibraryRootUrls()) ||
myLibrariesService instanceof GoApplicationLibrariesService &&
((GoApplicationLibrariesService)myLibrariesService).isUseGoPathFromSystemEnvironment() !=
myUseEnvGoPathCheckBox.isSelected();
}
@Override
public void apply() throws ConfigurationException {
myLibrariesService.setLibraryRootUrls(getUserDefinedUrls());
if (myLibrariesService instanceof GoApplicationLibrariesService) {
((GoApplicationLibrariesService)myLibrariesService).setUseGoPathFromSystemEnvironment(myUseEnvGoPathCheckBox.isSelected());
}
}
@Override
public void reset() {
myListModel.removeAll();
resetLibrariesFromEnvironment();
for (String url : myLibrariesService.getLibraryRootUrls()) {
myListModel.add(new ListItem(url, false));
}
}
private void resetLibrariesFromEnvironment() {
if (myLibrariesService instanceof GoApplicationLibrariesService) {
myUseEnvGoPathCheckBox.setSelected(((GoApplicationLibrariesService)myLibrariesService).isUseGoPathFromSystemEnvironment());
if (((GoApplicationLibrariesService)myLibrariesService).isUseGoPathFromSystemEnvironment()) {
addReadOnlyPaths();
}
else {
removeReadOnlyPaths();
}
}
}
private void addReadOnlyPaths() {
for (String url : myReadOnlyPaths) {
myListModel.add(new ListItem(url, true));
}
}
private void removeReadOnlyPaths() {
List<ListItem> toRemove = myListModel.getItems().stream().filter(item -> item.readOnly).collect(Collectors.toList());
for (ListItem item : toRemove) {
myListModel.remove(item);
}
}
@Override
public void disposeUIResources() {
UIUtil.dispose(myUseEnvGoPathCheckBox);
UIUtil.dispose(myPanel);
myListModel.removeAll();
}
@NotNull
@Nls
@Override
public String getDisplayName() {
return myDisplayName;
}
@Nullable
@Override
public String getHelpTopic() {
return null;
}
@NotNull
private Collection<String> getUserDefinedUrls() {
Collection<String> libraryUrls = ContainerUtil.newArrayList();
for (ListItem item : myListModel.getItems()) {
if (!item.readOnly) {
libraryUrls.add(item.url);
}
}
return libraryUrls;
}
@NotNull
@Override
public String getId() {
return "go.libraries";
}
@Nullable
@Override
public Runnable enableSearch(String option) {
return null;
}
private static class ListItem {
final boolean readOnly;
final String url;
public ListItem(String url, boolean readOnly) {
this.readOnly = readOnly;
this.url = url;
}
}
}