IDEA-19061 Integrate the Rearranger-plugin into core-IDEA

Providing ability to add new conditions
This commit is contained in:
Denis.Zhdanov
2012-08-13 17:12:23 +04:00
parent 5b73b79823
commit e5bedbf36d
22 changed files with 559 additions and 337 deletions
@@ -20,10 +20,11 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettings;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
@@ -48,25 +49,25 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
}
@Override
public boolean isNameFilterEnabled(@NotNull ArrangementSettings settings) {
public boolean isNameFilterEnabled(@NotNull ArrangementMatcherSettings settings) {
// TODO den implement
return true;
}
@Override
public boolean isSupported(@NotNull ArrangementEntryType type) {
public boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings settings) {
// TODO den implement
return true;
}
@Override
public boolean isSupported(@NotNull ArrangementModifier modifier) {
public boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings settings) {
// TODO den implement
return true;
}
@Override
public boolean isSupported(@NotNull ArrangementEntrySortType type) {
public boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings settings) {
// TODO den implement
return true;
}
@@ -15,6 +15,7 @@
*/
package com.intellij.psi.codeStyle.arrangement.settings;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
import org.jetbrains.annotations.NotNull;
@@ -24,12 +25,14 @@ import java.util.EnumSet;
import java.util.Set;
/**
* // TODO den add doc
* Encapsulates information about {@link ArrangementEntryMatcher standard arrangement match rule settings}.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 8/6/12 2:30 PM
*/
public class ArrangementSettings implements Cloneable {
public class ArrangementMatcherSettings implements Cloneable {
@NotNull private final Set<ArrangementModifier> myModifiers = EnumSet.noneOf(ArrangementModifier.class);
@@ -58,8 +61,8 @@ public class ArrangementSettings implements Cloneable {
}
@Override
protected ArrangementSettings clone() {
ArrangementSettings result = new ArrangementSettings();
protected ArrangementMatcherSettings clone() {
ArrangementMatcherSettings result = new ArrangementMatcherSettings();
result.setType(myType);
result.myModifiers.addAll(myModifiers);
return result;
@@ -19,6 +19,7 @@ import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* // TODO den add doc
@@ -30,14 +31,14 @@ import org.jetbrains.annotations.NotNull;
public interface ArrangementStandardSettingsAware {
// TODO den add doc
boolean isNameFilterEnabled(@NotNull ArrangementSettings settings);
boolean isNameFilterEnabled(@Nullable ArrangementMatcherSettings settings);
// TODO den add doc
boolean isSupported(@NotNull ArrangementEntryType type);
boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings settings);
// TODO den add doc
boolean isSupported(@NotNull ArrangementModifier modifier);
boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings settings);
// TODO den add doc
boolean isSupported(@NotNull ArrangementEntrySortType type);
boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings settings);
}
@@ -39,9 +39,12 @@ public class ArrangementAndNodeComponent extends JPanel implements ArrangementNo
private static final int BUBBLE_CONNECTOR_LENGTH = 10;
@NotNull private final List<ArrangementNodeComponent> myComponents = new ArrayList<ArrangementNodeComponent>();
@Nullable private Rectangle myScreenBounds;
@NotNull private final ArrangementSettingsCompositeNode mySettingsNode;
@Nullable private Rectangle myScreenBounds;
public ArrangementAndNodeComponent(@NotNull ArrangementSettingsCompositeNode node, @NotNull ArrangementNodeComponentFactory factory) {
mySettingsNode = node;
setLayout(null);
int x = 0;
for (ArrangementSettingsNode operand : node.getOperands()) {
@@ -55,6 +58,12 @@ public class ArrangementAndNodeComponent extends JPanel implements ArrangementNo
}
}
@NotNull
@Override
public ArrangementSettingsNode getSettingsNode() {
return mySettingsNode;
}
@NotNull
@Override
public JComponent getUiComponent() {
@@ -16,6 +16,7 @@
package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.ui.GridBag;
@@ -36,7 +37,6 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
private static final int PADDING = 2;
@Nullable private Rectangle myScreenBounds;
@NotNull private final JPanel myRenderer = new JPanel(new GridBagLayout()) {
@Override
public void paint(Graphics g) {
@@ -65,9 +65,14 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
return mySize == null ? super.getPreferredSize() : mySize;
}
};
@NotNull private final ArrangementSettingsAtomNode mySettingsNode;
@Nullable private Dimension mySize;
@Nullable private Rectangle myScreenBounds;
public ArrangementAtomNodeComponent(@NotNull ArrangementNodeDisplayManager manager, @NotNull ArrangementSettingsAtomNode node) {
mySettingsNode = node;
myLabel.setHorizontalAlignment(SwingConstants.CENTER);
myLabel.setText(manager.getDisplayValue(node));
mySize = new Dimension(manager.getMaxWidth(node.getType()), myLabel.getPreferredSize().height);
@@ -106,6 +111,12 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
myRenderer.setOpaque(false);
}
@NotNull
@Override
public ArrangementSettingsNode getSettingsNode() {
return mySettingsNode;
}
@NotNull
@Override
public JComponent getUiComponent() {
@@ -0,0 +1,31 @@
/*
* Copyright 2000-2012 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.application.options.codeStyle.arrangement;
import org.jetbrains.annotations.NonNls;
/**
* @author Denis Zhdanov
* @since 8/13/12 11:48 AM
*/
public class ArrangementConstants {
@NonNls public static final String ACTION_GROUP_RULE_EDITOR_CONTEXT_MENU = "Arrangement.RuleEditor.Context.Menu";
@NonNls public static final String RULE_EDITOR_PLACE = "Arrangement.RuleEditor.Place";
private ArrangementConstants() {
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
import com.intellij.ui.awt.RelativePoint;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,7 +30,10 @@ import java.awt.*;
* @since 8/10/12 11:22 AM
*/
public interface ArrangementNodeComponent {
@NotNull
ArrangementSettingsNode getSettingsNode();
// TODO den add doc
@NotNull
JComponent getUiComponent();
@@ -15,7 +15,6 @@
*/
package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.application.options.codeStyle.arrangement.ArrangementSettingsUtil;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
@@ -40,7 +39,7 @@ public class ArrangementNodeDisplayManager {
private final TObjectIntHashMap<ArrangementSettingType> myMaxWidths = new TObjectIntHashMap<ArrangementSettingType>();
public ArrangementNodeDisplayManager(@NotNull ArrangementStandardSettingsAware filter) {
Map<ArrangementSettingType, List<?>> map = ArrangementSettingsUtil.buildAvailableOptions(filter);
Map<ArrangementSettingType, List<?>> map = ArrangementSettingsUtil.buildAvailableOptions(filter, null);
for (Map.Entry<ArrangementSettingType, List<?>> entry : map.entrySet()) {
myMaxWidths.put(entry.getKey(), maxWidth(entry.getKey(), entry.getValue()));
}
@@ -63,6 +62,13 @@ public class ArrangementNodeDisplayManager {
return getDisplayValue(node.getType(), node.getValue());
}
@SuppressWarnings("MethodMayBeStatic")
@NotNull
public String getDisplayValue(@NotNull ArrangementSettingType type) {
return type.toString().toLowerCase();
}
@NotNull
private static String getDisplayValue(@NotNull ArrangementSettingType type, @NotNull Object value) {
return value.toString().toLowerCase();
}
@@ -15,6 +15,8 @@
*/
package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
import com.intellij.psi.codeStyle.arrangement.model.*;
@@ -22,6 +24,7 @@ import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettin
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.treeStructure.Tree;
import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,13 +47,15 @@ public class ArrangementRuleTree {
@NotNull private final DefaultTreeModel myTreeModel;
@NotNull private final ArrangementStandardSettingsAware myFilter;
@NotNull private final Tree myTree;
@NotNull private final ArrangementNodeDisplayManager myDisplayManager;
@NotNull private final ArrangementNodeComponentFactory myFactory;
@Nullable private ArrangementNodeComponent myPrevComponentUnderMouse;
public ArrangementRuleTree(@NotNull ArrangementStandardSettingsAware filter) {
myFilter = filter;
myFactory = new ArrangementNodeComponentFactory(new ArrangementNodeDisplayManager(filter));
myDisplayManager = new ArrangementNodeDisplayManager(filter);
myFactory = new ArrangementNodeComponentFactory(myDisplayManager);
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
myTreeModel = new DefaultTreeModel(root);
myTree = new Tree(myTreeModel) {
@@ -61,12 +66,9 @@ public class ArrangementRuleTree {
super.setExpandedState(path, state);
}
}
@Override
public void setSelectionPath(TreePath path) {
// Don't allow selection in order to avoid standard selection background drawing.
}
};
// Don't allow row selection as we're interested in particular row nodes.
myTree.setSelectionModel(null);
myTree.addMouseMotionListener(new MouseAdapter() {
@Override
@@ -74,6 +76,24 @@ public class ArrangementRuleTree {
onMouseMoved(e);
}
});
myTree.putClientProperty(DataManager.CLIENT_PROPERTY_DATA_PROVIDER, new DataProvider() {
@Override
public Object getData(@NonNls String dataId) {
if (ArrangementSettingsUtil.NODE_COMPONENT.is(dataId)) {
return myPrevComponentUnderMouse;
}
else if (ArrangementSettingsUtil.DISPLAY_MANAGER.is(dataId)) {
return myDisplayManager;
}
else if (ArrangementSettingsUtil.FILTER.is(dataId)) {
return myFilter;
}
else if (ArrangementSettingsUtil.TREE.is(dataId)) {
return myTree;
}
return null;
}
});
// TODO den remove
List<ArrangementSettingsNode> children = new ArrayList<ArrangementSettingsNode>();
@@ -116,7 +136,7 @@ public class ArrangementRuleTree {
}
private static void map(@NotNull DefaultMutableTreeNode parentTreeNode, @NotNull HierarchicalArrangementSettingsNode settingsNode) {
DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(settingsNode);
DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(settingsNode.getCurrent());
parentTreeNode.add(childTreeNode);
for (HierarchicalArrangementSettingsNode node : settingsNode.getChildren()) {
map(childTreeNode, node);
@@ -129,10 +149,10 @@ public class ArrangementRuleTree {
}
@NotNull
private ArrangementNodeComponent getComponent(int row, @NotNull HierarchicalArrangementSettingsNode node) {
private ArrangementNodeComponent getComponent(int row, @NotNull ArrangementSettingsNode node) {
ArrangementNodeComponent result = myRenderers.get(row);
if (result == null) {
myRenderers.put(row, result = myFactory.getComponent(node.getCurrent()));
myRenderers.put(row, result = myFactory.getComponent(node));
}
return result;
}
@@ -201,7 +221,7 @@ public class ArrangementRuleTree {
int row,
boolean hasFocus)
{
HierarchicalArrangementSettingsNode node = (HierarchicalArrangementSettingsNode)((DefaultMutableTreeNode)value).getUserObject();
ArrangementSettingsNode node = (ArrangementSettingsNode)((DefaultMutableTreeNode)value).getUserObject();
return getComponent(row, node).getUiComponent();
}
}
@@ -16,11 +16,13 @@
package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.application.options.CodeStyleAbstractPanel;
import com.intellij.ide.ui.customization.CustomizationUtil;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.ui.GridBag;
import org.jetbrains.annotations.NotNull;
@@ -39,7 +41,11 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel {
public ArrangementSettingsPanel(@NotNull CodeStyleSettings settings, @NotNull ArrangementStandardSettingsAware filter) {
super(settings);
myContent.add(new ArrangementRuleTree(filter).getTreeComponent(), new GridBag().weightx(1).weighty(1).fillCell());
Tree component = new ArrangementRuleTree(filter).getTreeComponent();
myContent.add(component, new GridBag().weightx(1).weighty(1).fillCell());
CustomizationUtil.installPopupHandler(
component, ArrangementConstants.ACTION_GROUP_RULE_EDITOR_CONTEXT_MENU, ArrangementConstants.RULE_EDITOR_PLACE
);
}
@Override
@@ -15,21 +15,22 @@
*/
package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.*;
import java.util.List;
import java.util.Map;
/**
* // TODO den add doc
@@ -39,34 +40,73 @@ import java.util.Map;
*/
public class ArrangementSettingsUtil {
public static final DataKey<ArrangementNodeComponent> NODE_COMPONENT = DataKey.create("Arrangement.Rule.Editor.Node.Component");
public static final DataKey<ArrangementStandardSettingsAware> FILTER = DataKey.create("Arrangement.Rule.Editor.Settings.Filter");
public static final DataKey<ArrangementNodeDisplayManager> DISPLAY_MANAGER = DataKey.create("Arrangement.Rule.Editor.Display.Manager");
public static final DataKey<ArrangementMatcherSettings> SETTINGS = DataKey.create("Arrangement.Rule.Editor.Matcher.Settings");
public static final DataKey<JComponent> TREE = DataKey.create("Arrangement.Rule.Editor.Tree");
private static final EntryTypeHelper ENTRY_TYPE_HELPER = new EntryTypeHelper();
private static final ModifierHelper MODIFIER_HELPER = new ModifierHelper();
private ArrangementSettingsUtil() {
}
@Nullable
public static ArrangementSettingsNode getSettingsNode(@NotNull DataContext context) {
ArrangementNodeComponent nodeComponent = NODE_COMPONENT.getData(context);
return nodeComponent == null ? null : nodeComponent.getSettingsNode();
}
@Nullable
public static HierarchicalArrangementSettingsNode buildTreeStructure(@NotNull ArrangementSettingsNode modelNode) {
// TODO den implement
return new HierarchicalArrangementSettingsNode(modelNode);
}
/**
* Serves for the same purposes as {@link #buildAvailableOptions(ArrangementStandardSettingsAware, ArrangementMatcherSettings)} but
* retrieves necessary information from the given context.
*
* @param context target information holder
* @return map which contains information on what new new settings are available at the current situation
*/
@NotNull
public static Map<ArrangementSettingType, List<?>> buildAvailableOptions(@NotNull ArrangementStandardSettingsAware filter) {
public static Map<ArrangementSettingType, List<?>> buildAvailableOptions(@NotNull DataContext context) {
ArrangementStandardSettingsAware filter = FILTER.getData(context);
if (filter == null) {
return Collections.emptyMap();
}
return buildAvailableOptions(filter, SETTINGS.getData(context));
}
/**
* Allows to answer what new settings are available for a particular {@link ArrangementMatcherSettings arrangement matcher rules}.
*
* @param filter filter to use
* @param settings object that encapsulates information about current arrangement matcher settings
* @return map which contains information on what new new settings are available at the current situation
*/
@NotNull
public static Map<ArrangementSettingType, List<?>> buildAvailableOptions(@NotNull ArrangementStandardSettingsAware filter,
@Nullable ArrangementMatcherSettings settings)
{
Map<ArrangementSettingType, List<?>> result = new EnumMap<ArrangementSettingType, List<?>>(ArrangementSettingType.class);
processData(filter, result, ArrangementEntryType.values(), ENTRY_TYPE_HELPER);
processData(filter, result, ArrangementModifier.values(), MODIFIER_HELPER);
processData(filter, settings, result, ArrangementEntryType.values(), ENTRY_TYPE_HELPER);
processData(filter, settings, result, ArrangementModifier.values(), MODIFIER_HELPER);
return result;
}
private static <T> void processData(@NotNull ArrangementStandardSettingsAware filter,
@Nullable ArrangementMatcherSettings settings,
Map<ArrangementSettingType, List<?>> result,
@NotNull T[] values,
@NotNull Helper<T> helper)
{
List<T> data = null;
for (T v : values) {
if (!helper.isSupported(v, filter)) {
if (!helper.isEnabled(v, filter, settings)) {
continue;
}
if (data == null) {
@@ -100,7 +140,7 @@ public class ArrangementSettingsUtil {
private interface Helper<T> {
@NotNull ArrangementSettingType getType();
boolean isSupported(@NotNull T data, @NotNull ArrangementStandardSettingsAware filter);
boolean isEnabled(@NotNull T data, @NotNull ArrangementStandardSettingsAware filter, @Nullable ArrangementMatcherSettings settings);
}
private static class EntryTypeHelper implements Helper<ArrangementEntryType> {
@@ -111,8 +151,11 @@ public class ArrangementSettingsUtil {
}
@Override
public boolean isSupported(@NotNull ArrangementEntryType data, @NotNull ArrangementStandardSettingsAware filter) {
return filter.isSupported(data);
public boolean isEnabled(@NotNull ArrangementEntryType data,
@NotNull ArrangementStandardSettingsAware filter,
@Nullable ArrangementMatcherSettings settings)
{
return filter.isEnabled(data, settings);
}
}
@@ -124,8 +167,11 @@ public class ArrangementSettingsUtil {
}
@Override
public boolean isSupported(@NotNull ArrangementModifier data, @NotNull ArrangementStandardSettingsAware filter) {
return filter.isSupported(data);
public boolean isEnabled(@NotNull ArrangementModifier data,
@NotNull ArrangementStandardSettingsAware filter,
@Nullable ArrangementMatcherSettings settings)
{
return filter.isEnabled(data, settings);
}
}
}
@@ -0,0 +1,84 @@
/*
* Copyright 2000-2012 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.application.options.codeStyle.arrangement.action;
import com.intellij.application.options.codeStyle.arrangement.ArrangementNodeDisplayManager;
import com.intellij.application.options.codeStyle.arrangement.ArrangementSettingsUtil;
import com.intellij.application.options.codeStyle.arrangement.editor.ArrangementNodeEditor;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
import com.intellij.ui.awt.RelativePoint;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Map;
/**
* @author Denis Zhdanov
* @since 8/13/12 11:52 AM
*/
public class ArrangementAddAndConditionAction extends AnAction {
public ArrangementAddAndConditionAction() {
getTemplatePresentation().setText(ApplicationBundle.message("arrangement.action.add.and.node.text"));
getTemplatePresentation().setDescription(ApplicationBundle.message("arrangement.action.add.and.node.description"));
}
@Override
public void actionPerformed(AnActionEvent e) {
Map<ArrangementSettingType, List<?>> availableSettings = ArrangementSettingsUtil.buildAvailableOptions(e.getDataContext());
if (availableSettings.isEmpty()) {
return;
}
ArrangementNodeDisplayManager displayManager = ArrangementSettingsUtil.DISPLAY_MANAGER.getData(e.getDataContext());
if (displayManager == null) {
return;
}
Project project = PlatformDataKeys.PROJECT.getData(e.getDataContext());
if (project == null) {
return;
}
JComponent tree = ArrangementSettingsUtil.TREE.getData(e.getDataContext());
if (tree == null) {
return;
}
ArrangementSettingsNode node = ArrangementSettingsUtil.getSettingsNode(e.getDataContext());
if (node == null) {
// TODO den implement
}
else {
ArrangementNodeEditor editor = new ArrangementNodeEditor(displayManager, availableSettings);
editor.applyColorsFrom(tree);
Balloon balloon = JBPopupFactory.getInstance().createBalloonBuilder(editor).setDisposable(project).setHideOnClickOutside(true)
.setFillColor(tree.getBackground()).createBalloon();
Point point = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen(point, tree);
balloon.show(new RelativePoint(tree, point), Balloon.Position.below);
}
}
}
@@ -0,0 +1,87 @@
/*
* Copyright 2000-2012 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.application.options.codeStyle.arrangement.editor;
import com.intellij.util.Consumer;
import com.intellij.util.ui.GridBag;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.List;
/**
* Editor for choosing a single value from a set of predefined values.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 8/13/12 4:15 PM
*/
public class ArrangementAtomEditor extends JPanel {
@NotNull private final Dimension myPrefSize;
public ArrangementAtomEditor(@NotNull String[] values, @NotNull final Consumer<String> callback) {
JComboBox box = new JComboBox(values);
box.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
callback.consume((String)e.getItem());
}
}
});
setLayout(new GridBagLayout());
add(box, new GridBag().anchor(GridBagConstraints.CENTER));
FontMetrics metrics = box.getFontMetrics(box.getFont());
int maxWidth = 0;
String widestText = null;
for (String value : values) {
int width = metrics.stringWidth(value);
if (width > maxWidth) {
widestText = value;
maxWidth = width;
}
}
if (widestText != null) {
box.setSelectedItem(widestText);
}
myPrefSize = getPreferredSize();
if (values.length > 0) {
box.setSelectedItem(values[0]);
}
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
@Override
public Dimension getMaximumSize() {
return getPreferredSize();
}
@Override
public Dimension getPreferredSize() {
return myPrefSize;
}
}
@@ -0,0 +1,92 @@
/*
* Copyright 2000-2012 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.application.options.codeStyle.arrangement.editor;
import com.intellij.application.options.codeStyle.arrangement.ArrangementNodeDisplayManager;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
import com.intellij.util.ui.GridBag;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* // TODO den add doc
*
* @author Denis Zhdanov
* @since 8/13/12 12:33 PM
*/
public class ArrangementNodeEditor extends JPanel {
@NotNull private final CardLayout myCardLayout = new CardLayout();
@NotNull private final JPanel myValuePanel = new JPanel(myCardLayout);
@NotNull private final ArrangementNodeDisplayManager myDisplayManager;
@NotNull private final Map<ArrangementSettingType, List<?>> myAvailableSettings;
@NotNull private final JComboBox myTypeComboBox;
@NotNull private final Dimension myPrefSize;
public ArrangementNodeEditor(@NotNull ArrangementNodeDisplayManager manager,
@NotNull Map<ArrangementSettingType, List<?>> settings)
{
myDisplayManager = manager;
myAvailableSettings = settings;
setOpaque(false);
myTypeComboBox = new JComboBox();
ArrangementSettingType[] types = myAvailableSettings.keySet().toArray(new ArrangementSettingType[myAvailableSettings.size()]);
Arrays.sort(types, new Comparator<ArrangementSettingType>() {
@Override
public int compare(ArrangementSettingType o1, ArrangementSettingType o2) {
return myDisplayManager.getDisplayValue(o1).compareTo(myDisplayManager.getDisplayValue(o2));
}
});
for (ArrangementSettingType type : types) {
myTypeComboBox.addItem(myDisplayManager.getDisplayValue(type));
}
setLayout(new GridBagLayout());
add(myTypeComboBox, new GridBag());
// TODO den remove
myPrefSize = getPreferredSize();
}
public void applyColorsFrom(@NotNull JComponent component) {
myTypeComboBox.setBackground(component.getBackground());
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
@Override
public Dimension getMaximumSize() {
return getPreferredSize();
}
@Override
public Dimension getPreferredSize() {
return myPrefSize;
}
}
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.ui.popup;
import com.intellij.openapi.Disposable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -96,4 +97,16 @@ public interface BalloonBuilder {
@NotNull
BalloonBuilder setBlockClicksThroughBalloon(boolean block);
/**
* Links target balloon life cycle to the given object. I.e. current balloon will be auto-hide and collected as soon
* as given anchor is disposed.
* <p/>
* <b>Note:</b> given disposable anchor is assumed to correctly implement {@link #hashCode()} and {@link #equals(Object)}.
*
* @param anchor target anchor to link to
* @return balloon builder which produces balloon linked to the given object life cycle
*/
@NotNull
BalloonBuilder setDisposable(@NotNull Disposable anchor);
}
@@ -15,8 +15,12 @@
*/
package com.intellij.ui.popup;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.BalloonImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -24,15 +28,20 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
public class BalloonPopupBuilderImpl implements BalloonBuilder {
@Nullable private final Map<Disposable, List<Balloon>> myStorage;
@Nullable private Disposable myAnchor;
JComponent myContent;
Color myBorder = Color.gray;
Color myFill = new Color(186, 238, 186, 230);
Color myBorder = Color.gray;
Color myFill = new Color(186, 238, 186, 230);
boolean myHideOnMouseOutside = true;
boolean myHideOnKeyOutside = true;
long myFadeoutTime = -1;
boolean myHideOnKeyOutside = true;
long myFadeoutTime = -1;
private Balloon.Position myPrefferedPosition = Balloon.Position.below;
@@ -41,7 +50,7 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
private boolean myHideOnFrameResize = true;
private ActionListener myClickHandler;
private boolean myCloseOnClick;
private boolean myCloseOnClick;
private int myAnimationCycle = 500;
private int myCalloutShift;
@@ -49,15 +58,16 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
private int myPositionChangeYShift;
private boolean myHideOnAction = true;
private boolean myDialogMode;
private String myTitle;
private Insets myContentInsets = new Insets(2, 2, 2, 2);
private boolean myShadow = false;
private boolean mySmallVariant = false;
private String myTitle;
private Insets myContentInsets = new Insets(2, 2, 2, 2);
private boolean myShadow = false;
private boolean mySmallVariant = false;
private Balloon.Layer myLayer;
private boolean myBlockClicks = false;
public BalloonPopupBuilderImpl(@NotNull final JComponent content) {
public BalloonPopupBuilderImpl(@Nullable Map<Disposable, List<Balloon>> storage, @NotNull final JComponent content) {
myStorage = storage;
myContent = content;
}
@@ -157,8 +167,41 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
@NotNull
public Balloon createBalloon() {
return new BalloonImpl(myContent, myBorder, myFill, myHideOnMouseOutside, myHideOnKeyOutside, myHideOnAction, myShowCalllout, myCloseButtonEnabled, myFadeoutTime, myHideOnFrameResize, myClickHandler, myCloseOnClick, myAnimationCycle,
myCalloutShift, myPositionChangeXShift, myPositionChangeYShift, myDialogMode, myTitle, myContentInsets, myShadow, mySmallVariant, myBlockClicks, myLayer);
final BalloonImpl result =
new BalloonImpl(myContent, myBorder, myFill, myHideOnMouseOutside, myHideOnKeyOutside, myHideOnAction, myShowCalllout,
myCloseButtonEnabled, myFadeoutTime, myHideOnFrameResize, myClickHandler, myCloseOnClick, myAnimationCycle,
myCalloutShift, myPositionChangeXShift, myPositionChangeYShift, myDialogMode, myTitle, myContentInsets, myShadow,
mySmallVariant, myBlockClicks, myLayer);
if (myAnchor != null) {
List<Balloon> balloons = myStorage.get(myAnchor);
if (balloons == null) {
myStorage.put(myAnchor, balloons = new ArrayList<Balloon>());
Disposer.register(myAnchor, new Disposable() {
@Override
public void dispose() {
List<Balloon> toDispose = myStorage.remove(myAnchor);
if (toDispose != null) {
for (Balloon balloon : toDispose) {
if (!balloon.isDisposed()) {
Disposer.dispose(balloon);
}
}
}
}
});
}
balloons.add(result);
result.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
if (!result.isDisposed()) {
Disposer.dispose(result);
}
myStorage.remove(result);
}
});
}
return result;
}
@NotNull
@@ -215,4 +258,11 @@ public class BalloonPopupBuilderImpl implements BalloonBuilder {
myLayer = layer;
return this;
}
@NotNull
@Override
public BalloonBuilder setDisposable(@NotNull Disposable anchor) {
myAnchor = anchor;
return this;
}
}
@@ -20,6 +20,7 @@ import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.IdeTooltipManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.actionSystem.impl.ActionMenu;
@@ -48,6 +49,8 @@ import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.ui.popup.mock.MockConfirmation;
import com.intellij.ui.popup.tree.TreePopupImpl;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.WeakHashMap;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
@@ -62,8 +65,8 @@ import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PopupFactoryImpl extends JBPopupFactory {
@@ -78,6 +81,8 @@ public class PopupFactoryImpl extends JBPopupFactory {
private static final Icon QUICK_LIST_ICON = AllIcons.Actions.QuickList;
private final Map<Disposable, List<Balloon>> myStorage = new WeakHashMap<Disposable, List<Balloon>>();
public ListPopup createConfirmation(String title, final Runnable onYes, int defaultOptionIndex) {
return createConfirmation(title, CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText(), onYes, defaultOptionIndex);
}
@@ -706,23 +711,24 @@ public class PopupFactoryImpl extends JBPopupFactory {
}
private static class ActionStepBuilder {
private final List<ActionItem> myListModel;
private final DataContext myDataContext;
private final boolean myShowNumbers;
private final boolean myUseAlphaAsNumbers;
private final boolean myShowDisabled;
private final List<ActionItem> myListModel;
private final DataContext myDataContext;
private final boolean myShowNumbers;
private final boolean myUseAlphaAsNumbers;
private final boolean myShowDisabled;
private final HashMap<AnAction, Presentation> myAction2presentation;
private int myCurrentNumber;
private boolean myPrependWithSeparator;
private String mySeparatorText;
private final boolean myHonorActionMnemonics;
private Icon myEmptyIcon;
private int myMaxIconWidth = -1;
private int myCurrentNumber;
private boolean myPrependWithSeparator;
private String mySeparatorText;
private final boolean myHonorActionMnemonics;
private Icon myEmptyIcon;
private int myMaxIconWidth = -1;
private int myMaxIconHeight = -1;
@NotNull private String myActionPlace;
private ActionStepBuilder(@NotNull DataContext dataContext, final boolean showNumbers, final boolean useAlphaAsNumbers,
final boolean showDisabled, final boolean honorActionMnemonics) {
final boolean showDisabled, final boolean honorActionMnemonics)
{
myUseAlphaAsNumbers = useAlphaAsNumbers;
myListModel = new ArrayList<ActionItem>();
myDataContext = dataContext;
@@ -888,12 +894,12 @@ public class PopupFactoryImpl extends JBPopupFactory {
}
public BalloonBuilder createBalloonBuilder(@NotNull final JComponent content) {
return new BalloonPopupBuilderImpl(content);
return new BalloonPopupBuilderImpl(myStorage, content);
}
@Override
public BalloonBuilder createDialogBalloonBuilder(@NotNull JComponent content, String title) {
final BalloonPopupBuilderImpl builder = new BalloonPopupBuilderImpl(content);
final BalloonPopupBuilderImpl builder = new BalloonPopupBuilderImpl(myStorage, content);
final Color bg = UIManager.getColor("Panel.background");
final Color borderOriginal = Color.darkGray;
final Color border = ColorUtil.toAlpha(borderOriginal, 75);
@@ -913,7 +919,8 @@ public class PopupFactoryImpl extends JBPopupFactory {
}
public BalloonBuilder createHtmlTextBalloonBuilder(@NotNull final String htmlContent, @Nullable final Icon icon, final Color fillColor,
@Nullable final HyperlinkListener listener) {
@Nullable final HyperlinkListener listener)
{
JEditorPane text = IdeTooltipManager.initPane(htmlContent, new HintHint().setAwtTooltip(true), null);
@@ -954,7 +961,8 @@ public class PopupFactoryImpl extends JBPopupFactory {
@Override
public BalloonBuilder createHtmlTextBalloonBuilder(@NotNull String htmlContent,
MessageType messageType,
@Nullable HyperlinkListener listener) {
@Nullable HyperlinkListener listener)
{
return createHtmlTextBalloonBuilder(htmlContent, messageType.getDefaultIcon(), messageType.getPopupBackground(), listener);
}
}
@@ -551,3 +551,6 @@ title.tabs.and.indents=Tabs and Indents
# Arrangement
tab.title.arrangement=Arrangement
arrangement.action.add.and.node.text=And
arrangement.action.add.and.node.description=Add 'and' condition
arrangement.label.type=Type
@@ -807,6 +807,12 @@
<action id="DumpLookupElementWeights" internal="true" class="com.intellij.internal.DumpLookupElementWeights" text="Dump lookup element weights"/>
<add-to-group group-id="Internal" anchor="last"/>
</group>
<group id="Arrangement.RuleEditor.Context.Menu">
<action id="Arrangement.AddNode"
class="com.intellij.application.options.codeStyle.arrangement.action.ArrangementAddAndConditionAction"
icon="AllIcons.General.Add"/>
</group>
</actions>
</component>
@@ -5,6 +5,7 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.treeStructure.Tree;
@@ -72,7 +73,8 @@ public class GradleShowConflictDetailsAction extends AbstractGradleSyncTreeNodeA
if (hintPosition == null) {
return;
}
final Balloon balloon = GradleUtil.getBalloonBuilder(control, project).setFillColor(tree.getBackground()).createBalloon();
final Balloon balloon = JBPopupFactory.getInstance().createBalloonBuilder(control).setDisposable(project)
.setFillColor(tree.getBackground()).createBalloon();
final GradleUiListener publisher = project.getMessageBus().syncPublisher(GradleUiListener.TOPIC);
publisher.beforeConflictUiShown();
balloon.addListener(new JBPopupAdapter() {
@@ -1,204 +0,0 @@
package org.jetbrains.plugins.gradle.util;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.List;
/**
* @author Denis Zhdanov
* @since 3/17/12 3:18 PM
*/
class GradleBalloonBuilder implements BalloonBuilder {
@NotNull private final BalloonBuilder myDelegate;
@NotNull private final List<Balloon> myStorage;
GradleBalloonBuilder(@NotNull BalloonBuilder delegate, @NotNull List<Balloon> storage) {
myDelegate = delegate;
myStorage = storage;
}
@Override
@NotNull
public Balloon createBalloon() {
final Balloon result = myDelegate.createBalloon();
myStorage.add(result);
result.addListener(new JBPopupAdapter() {
@Override
public void onClosed(LightweightWindowEvent event) {
if (!result.isDisposed()) {
Disposer.dispose(result);
}
myStorage.remove(result);
}
});
return result;
}
@Override
@NotNull
public BalloonBuilder setPreferredPosition(Balloon.Position position) {
myDelegate.setPreferredPosition(position);
return this;
}
@Override
@NotNull
public BalloonBuilder setBorderColor(@NotNull Color color) {
myDelegate.setBorderColor(color);
return this;
}
@Override
@NotNull
public BalloonBuilder setFillColor(@NotNull Color color) {
myDelegate.setFillColor(color);
return this;
}
@Override
@NotNull
public BalloonBuilder setHideOnClickOutside(boolean hide) {
myDelegate.setHideOnClickOutside(hide);
return this;
}
@Override
@NotNull
public BalloonBuilder setHideOnKeyOutside(boolean hide) {
myDelegate.setHideOnKeyOutside(hide);
return this;
}
@Override
@NotNull
public BalloonBuilder setShowCallout(boolean show) {
myDelegate.setShowCallout(show);
return this;
}
@Override
@NotNull
public BalloonBuilder setCloseButtonEnabled(boolean enabled) {
myDelegate.setCloseButtonEnabled(enabled);
return this;
}
@Override
@NotNull
public BalloonBuilder setFadeoutTime(long fadeoutTime) {
myDelegate.setFadeoutTime(fadeoutTime);
return this;
}
@Override
@NotNull
public BalloonBuilder setAnimationCycle(int time) {
myDelegate.setAnimationCycle(time);
return this;
}
@Override
@NotNull
public BalloonBuilder setHideOnFrameResize(boolean hide) {
myDelegate.setHideOnFrameResize(hide);
return this;
}
@Override
@NotNull
public BalloonBuilder setClickHandler(ActionListener listener, boolean closeOnClick) {
myDelegate.setClickHandler(listener, closeOnClick);
return this;
}
@Override
@NotNull
public BalloonBuilder setCalloutShift(int length) {
myDelegate.setCalloutShift(length);
return this;
}
@Override
@NotNull
public BalloonBuilder setPositionChangeXShift(int positionChangeXShift) {
myDelegate.setPositionChangeXShift(positionChangeXShift);
return this;
}
@Override
@NotNull
public BalloonBuilder setPositionChangeYShift(int positionChangeYShift) {
myDelegate.setPositionChangeYShift(positionChangeYShift);
return this;
}
@Override
public boolean isHideOnAction() {
return myDelegate.isHideOnAction();
}
@Override
@NotNull
public BalloonBuilder setHideOnAction(boolean hideOnAction) {
myDelegate.setHideOnAction(hideOnAction);
return this;
}
@Override
@NotNull
public BalloonBuilder setDialogMode(boolean dialogMode) {
myDelegate.setDialogMode(dialogMode);
return this;
}
@Override
@NotNull
public BalloonBuilder setTitle(@Nullable String title) {
myDelegate.setTitle(title);
return this;
}
@Override
@NotNull
public BalloonBuilder setContentInsets(Insets insets) {
myDelegate.setContentInsets(insets);
return this;
}
@Override
@NotNull
public BalloonBuilder setShadow(boolean shadow) {
myDelegate.setShadow(shadow);
return this;
}
@Override
@NotNull
public BalloonBuilder setSmallVariant(boolean smallVariant) {
myDelegate.setSmallVariant(smallVariant);
return this;
}
@Override
@NotNull
public BalloonBuilder setLayer(Balloon.Layer layer) {
myDelegate.setLayer(layer);
return this;
}
@NotNull
@Override
public BalloonBuilder setBlockClicksThroughBalloon(boolean block) {
myDelegate.setBlockClicksThroughBalloon(block);
return this;
}
}
@@ -2,7 +2,6 @@ package org.jetbrains.plugins.gradle.util;
import com.intellij.execution.rmi.RemoteUtil;
import com.intellij.ide.actions.OpenProjectFileChooserDescriptor;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
@@ -25,7 +24,6 @@ import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.BalloonBuilder;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
@@ -38,7 +36,6 @@ import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.WeakHashMap;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -59,9 +56,6 @@ import java.awt.*;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
/**
@@ -74,8 +68,6 @@ public class GradleUtil {
public static final String PATH_SEPARATOR = "/";
private static final Map<Project, List<Balloon>> PROJECT_BALLOONS = new WeakHashMap<Project, List<Balloon>>();
private static final List<Balloon> APPLICATION_BALLOONS = new CopyOnWriteArrayList<Balloon>();
private static final NotNullLazyValue<GradleLibraryManager> LIBRARY_MANAGER = new NotNullLazyValue<GradleLibraryManager>() {
@NotNull
@Override
@@ -116,10 +108,9 @@ public class GradleUtil {
* @param message message to show
*/
public static void showBalloon(@NotNull JComponent component, @NotNull MessageType messageType, @NotNull String message) {
final BalloonBuilder delegate = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(message, messageType, null);
BalloonBuilder balloonBuilder = new GradleBalloonBuilder(delegate, APPLICATION_BALLOONS);
ApplicationBalloonsDisposeActivator.ensureActivated();
Balloon balloon = balloonBuilder.setFadeoutTime(TimeUnit.SECONDS.toMillis(1)).createBalloon();
final BalloonBuilder builder = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(message, messageType, null)
.setDisposable(ApplicationManager.getApplication()).setFadeoutTime(TimeUnit.SECONDS.toMillis(1));
Balloon balloon = builder.createBalloon();
Dimension size = component.getSize();
Balloon.Position position;
int x;
@@ -429,35 +420,6 @@ public class GradleUtil {
return new MatrixControlBuilder(gradle, intellij);
}
/**
* Wraps {@link JBPopupFactory#createBalloonBuilder(JComponent) default api} in order to take care of automatic balloon disposing
* on project close.
*
* @param content target balloon content
* @param project project that should be used to bound target balloon's lifecycle to
* @return balloon builder to use.
*/
@NotNull
public static BalloonBuilder getBalloonBuilder(@NotNull JComponent content, @NotNull final Project project) {
List<Balloon> balloons = PROJECT_BALLOONS.get(project);
if (balloons == null) {
PROJECT_BALLOONS.put(project, balloons = new CopyOnWriteArrayList<Balloon>());
final List<Balloon> b = balloons;
Disposer.register(project, new Disposable() {
@Override
public void dispose() {
for (Balloon balloon : b) {
if (!balloon.isDisposed()) {
Disposer.dispose(balloon);
}
}
PROJECT_BALLOONS.remove(project);
}
});
}
return new GradleBalloonBuilder(JBPopupFactory.getInstance().createBalloonBuilder(content), balloons);
}
public static boolean isGradleAvailable() {
final Project[] projects = ProjectManager.getInstance().getOpenProjects();
final Project project;
@@ -498,23 +460,4 @@ public class GradleUtil {
}
};
}
/**
* Serves the same purpose as the {@link DescriptorHolder} but for application-level balloons releasing.
*/
private static class ApplicationBalloonsDisposeActivator {
static {
Disposer.register(ApplicationManager.getApplication(), new Disposable() {
@Override
public void dispose() {
for (Balloon balloon : APPLICATION_BALLOONS) {
if (!balloon.isDisposed()) {
Disposer.dispose(balloon);
}
}
}
});
}
static void ensureActivated() { /* the real job is at the static init block. */ }
}
}