/*
* Copyright 2013 The authors
* 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.struts2.facet.ui;
import com.intellij.facet.ui.FacetEditorContext;
import com.intellij.facet.ui.FacetEditorTab;
import com.intellij.icons.AllIcons;
import com.intellij.ide.BrowserUtil;
import com.intellij.ide.CommonActionsManager;
import com.intellij.ide.DefaultTreeExpander;
import com.intellij.ide.TreeExpander;
import com.intellij.ide.projectView.PresentationData;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.struts2.StrutsBundle;
import com.intellij.struts2.StrutsIcons;
import com.intellij.struts2.dom.struts.model.StrutsManager;
import com.intellij.struts2.facet.StrutsFacetConfiguration;
import com.intellij.ui.AnActionButton;
import com.intellij.ui.AnActionButtonRunnable;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.treeStructure.*;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultTreeModel;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* Struts2 facet tab "File Sets".
*
* @author Yann Cébron
*/
public class FileSetConfigurationTab extends FacetEditorTab implements Disposable {
// GUI components -----------------------
private JPanel myPanel;
private SimpleTree myTree;
private AnActionButton myRemoveButton;
private AnActionButton myEditButton;
private JPanel myTreePanel;
// GUI helpers
private final SimpleTreeBuilder myBuilder;
private final SimpleNode myRootNode = new SimpleNode() {
public SimpleNode[] getChildren() {
final List<SimpleNode> nodes = new ArrayList<>(myBuffer.size());
for (final StrutsFileSet entry : myBuffer) {
if (!entry.isRemoved()) {
final FileSetNode setNode = new FileSetNode(entry);
nodes.add(setNode);
}
}
return ArrayUtil.toObjectArray(nodes, SimpleNode.class);
}
public boolean isAutoExpandNode() {
return true;
}
};
private final TreeExpander myTreeExpander;
private final StrutsConfigsSearcher myConfigsSearcher;
// original config
private final StrutsFacetConfiguration originalConfiguration;
private final Module module;
// local config
private final Set<StrutsFileSet> myBuffer = new LinkedHashSet<>();
private boolean myModified;
public FileSetConfigurationTab(@NotNull final StrutsFacetConfiguration strutsFacetConfiguration,
@NotNull final FacetEditorContext facetEditorContext) {
originalConfiguration = strutsFacetConfiguration;
module = facetEditorContext.getModule();
myConfigsSearcher = new StrutsConfigsSearcher(module);
// init tree
final SimpleTreeStructure structure = new SimpleTreeStructure() {
public Object getRootElement() {
return myRootNode;
}
};
myTree = new SimpleTree();
myTree.setRootVisible(false);
myTree.setShowsRootHandles(true); // show expand/collapse handles
myTree.getEmptyText().setText(StrutsBundle.message("facet.fileset.no.filesets.defined"), SimpleTextAttributes.ERROR_ATTRIBUTES);
myTreeExpander = new DefaultTreeExpander(myTree);
myBuilder = new SimpleTreeBuilder(myTree, (DefaultTreeModel)myTree.getModel(), structure, null);
myBuilder.initRoot();
final DumbService dumbService = DumbService.getInstance(facetEditorContext.getProject());
myTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(final TreeSelectionEvent e) {
final StrutsFileSet fileSet = getCurrentFileSet();
myEditButton.setEnabled(fileSet != null && !dumbService.isDumb());
myRemoveButton.setEnabled(fileSet != null);
}
});
final CommonActionsManager actionManager = CommonActionsManager.getInstance();
myTreePanel.add(
ToolbarDecorator.createDecorator(myTree)
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
final StrutsFileSet fileSet =
new StrutsFileSet(StrutsFileSet.getUniqueId(myBuffer),
StrutsFileSet.getUniqueName(StrutsBundle.message("facet.fileset.my.fileset"), myBuffer),
originalConfiguration) {
public boolean isNew() {
return true;
}
};
final FileSetEditor editor = new FileSetEditor(myPanel,
fileSet,
facetEditorContext,
myConfigsSearcher);
editor.show();
if (editor.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
final StrutsFileSet editedFileSet = editor.getEditedFileSet();
Disposer.register(strutsFacetConfiguration, editedFileSet);
myBuffer.add(editedFileSet);
myModified = true;
myBuilder.updateFromRoot();
selectFileSet(fileSet);
}
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
IdeFocusManager.getGlobalInstance().requestFocus(myTree, true);
});
}
})
.setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
remove();
myModified = true;
myBuilder.updateFromRoot();
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
IdeFocusManager.getGlobalInstance().requestFocus(myTree, true);
});
}
})
.setEditAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
final StrutsFileSet fileSet = getCurrentFileSet();
if (fileSet != null) {
final FileSetEditor editor = new FileSetEditor(myPanel,
fileSet,
facetEditorContext,
myConfigsSearcher);
editor.show();
if (editor.getExitCode() == DialogWrapper.OK_EXIT_CODE) {
myModified = true;
myBuffer.remove(fileSet);
final StrutsFileSet edited = editor.getEditedFileSet();
Disposer.register(strutsFacetConfiguration, edited);
myBuffer.add(edited);
edited.setAutodetected(false);
myBuilder.updateFromRoot();
selectFileSet(edited);
}
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
IdeFocusManager.getGlobalInstance().requestFocus(myTree, true);
});
}
}
})
.addExtraAction(AnActionButton.fromAction(actionManager.createExpandAllAction(myTreeExpander, myTree)))
.addExtraAction(AnActionButton.fromAction(actionManager.createCollapseAllAction(myTreeExpander, myTree)))
.addExtraAction(new AnActionButton("Open Struts 2 plugin documentation…", AllIcons.Actions.Help) {
@Override
public void actionPerformed(AnActionEvent e) {
BrowserUtil.browse("https://confluence.jetbrains.com/pages/viewpage.action?pageId=35367");
}
})
.disableUpDownActions()
.createPanel());
myEditButton = ToolbarDecorator.findEditButton(myTreePanel);
myRemoveButton = ToolbarDecorator.findRemoveButton(myTreePanel);
AnActionButton addButton = ToolbarDecorator.findAddButton(myTreePanel);
assert addButton != null;
dumbService.makeDumbAware(addButton.getContextComponent(), this);
dumbService.makeDumbAware(myEditButton.getContextComponent(), this);
}
@Nullable
private StrutsFileSet getCurrentFileSet() {
final FileSetNode currentFileSetNode = getCurrentFileSetNode();
return currentFileSetNode == null ? null : currentFileSetNode.mySet;
}
@Nullable
private FileSetNode getCurrentFileSetNode() {
final SimpleNode selectedNode = myTree.getSelectedNode();
if (selectedNode == null) {
return null;
}
if (selectedNode instanceof FileSetNode) {
return (FileSetNode)selectedNode;
}
else if (selectedNode.getParent() instanceof FileSetNode) {
return (FileSetNode)selectedNode.getParent();
}
else {
final SimpleNode parent = selectedNode.getParent();
if (parent != null && parent.getParent() instanceof FileSetNode) {
return (FileSetNode)selectedNode.getParent().getParent();
}
}
return null;
}
private void selectFileSet(final StrutsFileSet fileSet) {
myTree.select(myBuilder, new SimpleNodeVisitor() {
public boolean accept(final SimpleNode simpleNode) {
if (simpleNode instanceof FileSetNode) {
if (((FileSetNode)simpleNode).mySet.equals(fileSet)) {
return true;
}
}
return false;
}
}, false);
}
private void remove() {
final SimpleNode[] nodes = myTree.getSelectedNodesIfUniform();
for (final SimpleNode node : nodes) {
if (node instanceof FileSetNode) {
final StrutsFileSet fileSet = ((FileSetNode)node).mySet;
if (fileSet.getFiles().isEmpty()) {
myBuffer.remove(fileSet);
return;
}
final int result = Messages.showYesNoDialog(myPanel,
StrutsBundle.message("facet.fileset.remove.fileset.question",
fileSet.getName()),
StrutsBundle.message("facet.fileset.remove.fileset.title"),
Messages.getQuestionIcon());
if (result == Messages.YES) {
if (fileSet.isAutodetected()) {
fileSet.setRemoved(true);
myBuffer.add(fileSet);
}
else {
myBuffer.remove(fileSet);
}
}
}
else if (node instanceof ConfigFileNode) {
final VirtualFilePointer filePointer = ((ConfigFileNode)node).myFilePointer;
final StrutsFileSet fileSet = ((FileSetNode)node.getParent()).mySet;
fileSet.removeFile(filePointer);
}
}
}
@Nls
public String getDisplayName() {
return StrutsBundle.message("facet.fileset.title");
}
@NotNull
public JComponent createComponent() {
return myPanel;
}
public boolean isModified() {
return myModified;
}
public void apply() {
final Set<StrutsFileSet> fileSets = originalConfiguration.getFileSets();
fileSets.clear();
for (final StrutsFileSet fileSet : myBuffer) {
if (!fileSet.isAutodetected() || fileSet.isRemoved()) {
fileSets.add(fileSet);
}
}
originalConfiguration.setModified();
myModified = false;
}
public void reset() {
myBuffer.clear();
final Set<StrutsFileSet> sets = StrutsManager.getInstance(module.getProject()).getAllConfigFileSets(module);
for (final StrutsFileSet fileSet : sets) {
myBuffer.add(/*new StrutsFileSet(fileSet)*/fileSet);
}
myBuilder.updateFromRoot();
myTree.setSelectionRow(0);
}
public void disposeUIResources() {
Disposer.dispose(myBuilder);
Disposer.dispose(this);
}
public void dispose() {
}
private static class FileSetNode extends SimpleNode {
protected final StrutsFileSet mySet;
FileSetNode(final StrutsFileSet fileSet) {
mySet = fileSet;
final PresentationData presentationData = getPresentation();
final String name = mySet.getName();
if (fileSet.getFiles().isEmpty()) {
presentationData.addText(name, getErrorAttributes());
presentationData.setTooltip(StrutsBundle.message("facet.fileset.no.files.attached"));
}
else {
presentationData.addText(name, getPlainAttributes());
presentationData.setLocationString(Integer.toString(fileSet.getFiles().size()));
}
}
public SimpleNode[] getChildren() {
final List<SimpleNode> nodes = new ArrayList<>();
for (final VirtualFilePointer file : mySet.getFiles()) {
nodes.add(new ConfigFileNode(file, this));
}
return ArrayUtil.toObjectArray(nodes, SimpleNode.class);
}
public boolean isAutoExpandNode() {
return true;
}
@NotNull
public Object[] getEqualityObjects() {
return new Object[]{mySet, mySet.getName(), mySet.getFiles()};
}
}
private static final class ConfigFileNode extends SimpleNode {
private final VirtualFilePointer myFilePointer;
ConfigFileNode(final VirtualFilePointer name, final SimpleNode parent) {
super(parent);
myFilePointer = name;
setUniformIcon(StrutsIcons.STRUTS_CONFIG_FILE);
}
@Override
public boolean isAlwaysLeaf() {
return true;
}
protected void doUpdate() {
final VirtualFile file = myFilePointer.getFile();
if (file != null) {
renderFile(file, getPlainAttributes(), null);
}
else {
renderFile(file, getErrorAttributes(), StrutsBundle.message("facet.fileset.file.not.found"));
}
}
private void renderFile(final VirtualFile file,
final SimpleTextAttributes textAttributes,
@Nullable final String toolTip) {
final PresentationData presentation = getPresentation();
presentation.setTooltip(toolTip);
presentation.addText(myFilePointer.getFileName(), textAttributes);
if (file != null) {
presentation.setLocationString(file.getPath());
}
}
public SimpleNode[] getChildren() {
return NO_CHILDREN;
}
}
@Override
public String getHelpTopic() {
return "reference.settings.project.structure.facets.struts2.facet";
}
}