| /* |
| * Copyright 2000-2014 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.openapi.roots.libraries.ui.impl; |
| |
| import com.intellij.openapi.application.ApplicationNamesInfo; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.ui.ComboBoxTableRenderer; |
| import com.intellij.openapi.ui.DialogWrapper; |
| import com.intellij.openapi.ui.TitlePanel; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.openapi.vfs.VfsUtilCore; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.ui.*; |
| import com.intellij.ui.treeStructure.treetable.TreeColumnInfo; |
| import com.intellij.util.PlatformIcons; |
| import com.intellij.util.containers.Convertor; |
| import com.intellij.util.ui.ColumnInfo; |
| import com.intellij.util.ui.ComboBoxCellEditor; |
| import com.intellij.util.ui.tree.TreeUtil; |
| import com.intellij.xml.util.XmlStringUtil; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import javax.swing.table.DefaultTableCellRenderer; |
| import javax.swing.table.TableCellEditor; |
| import javax.swing.table.TableCellRenderer; |
| import javax.swing.table.TableColumn; |
| import javax.swing.tree.TreePath; |
| import java.awt.*; |
| import java.io.File; |
| import java.util.*; |
| import java.util.List; |
| |
| /** |
| * This dialog allows selecting paths inside selected archives or directories. |
| * The tree is three-level: |
| * <ul> |
| * <li>The root is a fake node that just holds child nodes.</li> |
| * <li>The second level is archives or directories selected on the previous selection step.</li> |
| * <li>The third level are detected roots inside previous selection.</li> |
| * </ul> |
| * |
| * @author max |
| * @author Constantine.Plotnikov |
| */ |
| public class DetectedRootsChooserDialog extends DialogWrapper { |
| private static final ColumnInfo ROOT_COLUMN = new TreeColumnInfo(""); |
| private static final ColumnInfo<VirtualFileCheckedTreeNode, String> ROOT_TYPE_COLUMN = new ColumnInfo<VirtualFileCheckedTreeNode, String>("") { |
| @Override |
| public String valueOf(VirtualFileCheckedTreeNode node) { |
| final SuggestedChildRootInfo rootInfo = node.getRootInfo(); |
| return rootInfo != null ? rootInfo.getRootTypeName(rootInfo.getSelectedRootType()) : ""; |
| } |
| |
| @Override |
| public TableCellRenderer getRenderer(VirtualFileCheckedTreeNode node) { |
| final SuggestedChildRootInfo rootInfo = node.getRootInfo(); |
| if (rootInfo != null && isCellEditable(node)) { |
| return new ComboBoxTableRenderer<String>(rootInfo.getRootTypeNames()); |
| } |
| return new DefaultTableCellRenderer(); |
| } |
| |
| @Override |
| public TableCellEditor getEditor(VirtualFileCheckedTreeNode o) { |
| final SuggestedChildRootInfo rootInfo = o.getRootInfo(); |
| if (rootInfo == null) return null; |
| final ComboBoxCellEditor editor = new ComboBoxCellEditor() { |
| @Override |
| protected List<String> getComboBoxItems() { |
| return Arrays.asList(rootInfo.getRootTypeNames()); |
| } |
| }; |
| editor.setClickCountToStart(1); |
| return editor; |
| } |
| |
| @Override |
| public boolean isCellEditable(VirtualFileCheckedTreeNode node) { |
| final SuggestedChildRootInfo rootInfo = node.getRootInfo(); |
| return rootInfo != null && rootInfo.getDetectedRoot().getTypes().size() > 1; |
| } |
| |
| @Override |
| public void setValue(VirtualFileCheckedTreeNode node, String value) { |
| final SuggestedChildRootInfo rootInfo = node.getRootInfo(); |
| if (rootInfo != null) { |
| rootInfo.setSelectedRootType(value); |
| } |
| } |
| }; |
| |
| private CheckboxTreeTable myTreeTable; |
| private JScrollPane myPane; |
| private String myDescription; |
| |
| public DetectedRootsChooserDialog(Component component, Collection<SuggestedChildRootInfo> suggestedRoots) { |
| super(component, true); |
| init(suggestedRoots); |
| } |
| |
| public DetectedRootsChooserDialog(Project project, Collection<SuggestedChildRootInfo> suggestedRoots) { |
| super(project, true); |
| init(suggestedRoots); |
| } |
| |
| private void init(Collection<SuggestedChildRootInfo> suggestedRoots) { |
| myDescription = XmlStringUtil.wrapInHtml(ApplicationNamesInfo.getInstance().getFullProductName() + |
| " just scanned files and detected the following " + StringUtil.pluralize("root", suggestedRoots.size()) + ".<br>" + |
| "Select items in the tree below or press Cancel to cancel operation."); |
| myTreeTable = createTreeTable(suggestedRoots); |
| myPane = ScrollPaneFactory.createScrollPane(myTreeTable); |
| setTitle("Detected Roots"); |
| init(); |
| } |
| |
| private static CheckboxTreeTable createTreeTable(Collection<SuggestedChildRootInfo> suggestedRoots) { |
| final CheckedTreeNode root = createRoot(suggestedRoots); |
| CheckboxTreeTable treeTable = new CheckboxTreeTable(root, new CheckboxTree.CheckboxTreeCellRenderer(true) { |
| @Override |
| public void customizeRenderer(JTree tree, |
| Object value, |
| boolean selected, |
| boolean expanded, |
| boolean leaf, |
| int row, |
| boolean hasFocus) { |
| if (!(value instanceof VirtualFileCheckedTreeNode)) return; |
| VirtualFileCheckedTreeNode node = (VirtualFileCheckedTreeNode)value; |
| VirtualFile file = node.getFile(); |
| String text; |
| SimpleTextAttributes attributes; |
| Icon icon; |
| boolean isValid = true; |
| if (leaf) { |
| VirtualFile ancestor = ((VirtualFileCheckedTreeNode)node.getParent()).getFile(); |
| if (ancestor != null) { |
| text = VfsUtilCore.getRelativePath(file, ancestor, File.separatorChar); |
| if (StringUtil.isEmpty(text)) { |
| text = File.separator; |
| } |
| } |
| else { |
| text = file.getPresentableUrl(); |
| } |
| if (text == null) { |
| isValid = false; |
| text = file.getPresentableUrl(); |
| } |
| attributes = SimpleTextAttributes.REGULAR_ATTRIBUTES; |
| icon = PlatformIcons.DIRECTORY_CLOSED_ICON; |
| } |
| else { |
| text = file.getPresentableUrl(); |
| attributes = SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES; |
| icon = PlatformIcons.DIRECTORY_CLOSED_ICON; |
| } |
| final ColoredTreeCellRenderer textRenderer = getTextRenderer(); |
| textRenderer.setIcon(icon); |
| if (!isValid) { |
| textRenderer.append("[INVALID] ", SimpleTextAttributes.ERROR_ATTRIBUTES); |
| } |
| textRenderer.append(text, attributes); |
| } |
| }, new ColumnInfo[]{ROOT_COLUMN, ROOT_TYPE_COLUMN}); |
| |
| int max = 0; |
| for (SuggestedChildRootInfo info : suggestedRoots) { |
| for (String s : info.getRootTypeNames()) { |
| max = Math.max(max, treeTable.getFontMetrics(treeTable.getFont()).stringWidth(s)); |
| } |
| } |
| final TableColumn column = treeTable.getColumnModel().getColumn(1); |
| int width = max + 20;//add space for combobox button |
| column.setPreferredWidth(width); |
| column.setMaxWidth(width); |
| treeTable.setRootVisible(false); |
| new TreeTableSpeedSearch(treeTable, new Convertor<TreePath, String>() { |
| @Override |
| public String convert(TreePath o) { |
| Object node = o.getLastPathComponent(); |
| if (!(node instanceof VirtualFileCheckedTreeNode)) return ""; |
| return ((VirtualFileCheckedTreeNode)node).getFile().getPresentableUrl(); |
| } |
| }); |
| TreeUtil.expandAll(treeTable.getTree()); |
| return treeTable; |
| } |
| |
| private static CheckedTreeNode createRoot(Collection<SuggestedChildRootInfo> suggestedRoots) { |
| SuggestedChildRootInfo[] sortedRoots = suggestedRoots.toArray(new SuggestedChildRootInfo[suggestedRoots.size()]); |
| Arrays.sort(sortedRoots, new Comparator<SuggestedChildRootInfo>() { |
| @Override |
| public int compare(@NotNull SuggestedChildRootInfo o1, @NotNull SuggestedChildRootInfo o2) { |
| return o1.getDetectedRoot().getFile().getPresentableUrl().compareTo(o2.getDetectedRoot().getFile().getPresentableUrl()); |
| } |
| }); |
| |
| CheckedTreeNode root = new CheckedTreeNode(null); |
| Map<VirtualFile, CheckedTreeNode> rootCandidateNodes = new HashMap<VirtualFile, CheckedTreeNode>(); |
| for (SuggestedChildRootInfo rootInfo : sortedRoots) { |
| final VirtualFile rootCandidate = rootInfo.getRootCandidate(); |
| CheckedTreeNode parent = rootCandidateNodes.get(rootCandidate); |
| if (parent == null) { |
| parent = new VirtualFileCheckedTreeNode(rootCandidate); |
| rootCandidateNodes.put(rootCandidate, parent); |
| root.add(parent); |
| } |
| parent.add(new VirtualFileCheckedTreeNode(rootInfo)); |
| } |
| return root; |
| } |
| |
| @Override |
| protected JComponent createTitlePane() { |
| return new TitlePanel("Choose Roots", myDescription); |
| } |
| |
| @Nullable |
| @Override |
| protected JComponent createCenterPanel() { |
| return myPane; |
| } |
| |
| public SuggestedChildRootInfo[] getChosenRoots() { |
| return myTreeTable.getCheckedNodes(SuggestedChildRootInfo.class); |
| } |
| |
| @NonNls |
| @Override |
| protected String getDimensionServiceKey() { |
| return "DetectedRootsChooserDialog"; |
| } |
| |
| @Nullable |
| @Override |
| public JComponent getPreferredFocusedComponent() { |
| return myTreeTable; |
| } |
| |
| private static class VirtualFileCheckedTreeNode extends CheckedTreeNode { |
| private final VirtualFile myFile; |
| |
| private VirtualFileCheckedTreeNode(VirtualFile file) { |
| super(file); |
| myFile = file; |
| } |
| |
| public VirtualFileCheckedTreeNode(SuggestedChildRootInfo rootInfo) { |
| super(rootInfo); |
| myFile = rootInfo.getDetectedRoot().getFile(); |
| } |
| |
| public VirtualFile getFile() { |
| return myFile; |
| } |
| |
| @Nullable |
| private SuggestedChildRootInfo getRootInfo() { |
| return userObject instanceof SuggestedChildRootInfo ? (SuggestedChildRootInfo)userObject : null; |
| } |
| } |
| } |