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

Showing 'close' icon for the condition nodes
This commit is contained in:
Denis.Zhdanov
2012-08-23 13:21:21 +04:00
parent ef5e419012
commit 8b60941b28
8 changed files with 195 additions and 14 deletions
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -194,6 +195,18 @@ public class ArrangementAndNodeComponent extends JPanel implements ArrangementNo
}
}
@Override
public Rectangle handleMouseMove(@NotNull MouseEvent event) {
Point location = event.getLocationOnScreen();
for (ArrangementNodeComponent component : myComponents) {
Rectangle bounds = component.getScreenBounds();
if (bounds != null && bounds.contains(location)) {
return component.handleMouseMove(event);
}
}
return null;
}
@Override
public String toString() {
return String.format("(%s)", StringUtil.join(myComponents, " and "));
@@ -15,9 +15,11 @@
*/
package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.openapi.actionSystem.impl.ActionButton;
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.Consumer;
import com.intellij.util.ui.GridBag;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
@@ -25,9 +27,12 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
/**
* // TODO den add doc
* {@link ArrangementNodeComponent} for {@link ArrangementSettingsAtomNode} representation.
* <p/>
* Not thread-safe.
*
* @author Denis Zhdanov
* @since 8/8/12 10:06 AM
@@ -68,7 +73,8 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
}
};
@NotNull private final ArrangementSettingsAtomNode mySettingsNode;
@NotNull private final ArrangementSettingsAtomNode mySettingsNode;
@Nullable private final ActionButton myCloseButton;
@Nullable private Dimension mySize;
@Nullable private Rectangle myScreenBounds;
@@ -76,18 +82,60 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
private boolean myEnabled = true;
private boolean mySelected;
private boolean myInverted;
private boolean myCloseButtonHovered;
public ArrangementAtomNodeComponent(@NotNull ArrangementNodeDisplayManager manager, @NotNull ArrangementSettingsAtomNode node) {
public ArrangementAtomNodeComponent(@NotNull ArrangementNodeDisplayManager manager,
@NotNull ArrangementSettingsAtomNode node,
@Nullable Consumer<ArrangementSettingsAtomNode> closeCallback)
{
mySettingsNode = node;
myLabel.setHorizontalAlignment(SwingConstants.CENTER);
myLabel.setText(manager.getDisplayValue(node));
mySize = new Dimension(manager.getMaxWidth(node.getType()), myLabel.getPreferredSize().height);
int width = manager.getMaxWidth(node.getType());
int height = myLabel.getPreferredSize().height;
final ArrangementRemoveConditionAction action;
if (closeCallback == null) {
myCloseButton = null;
action = null;
}
else {
action = new ArrangementRemoveConditionAction();
Icon buttonIcon = action.getTemplatePresentation().getIcon();
Dimension buttonSize = new Dimension(buttonIcon.getIconWidth(), buttonIcon.getIconHeight());
myCloseButton = new ActionButton(action, action.getTemplatePresentation().clone(), ArrangementConstants.RULE_TREE_PLACE, buttonSize) {
@Override
protected Icon getIcon() {
return myCloseButtonHovered ? action.getTemplatePresentation().getHoveredIcon() : action.getTemplatePresentation().getIcon();
}
};
Dimension preferredButtonSize = myCloseButton.getPreferredSize();
width += preferredButtonSize.width;
height = Math.max(height, preferredButtonSize.height);
}
mySize = new Dimension(width, height);
GridBagConstraints constraints = new GridBag().anchor(GridBagConstraints.CENTER).insets(0, 0, 0, 0);
JPanel labelPanel = new JPanel(new GridBagLayout());
JPanel labelPanel = new JPanel(new GridBagLayout()) {
@Override
public void paint(Graphics g) {
Rectangle buttonBounds = getCloseButtonScreenLocation();
if (buttonBounds != null && action != null) {
Point mouseScreenLocation = MouseInfo.getPointerInfo().getLocation();
myCloseButtonHovered = buttonBounds.contains(mouseScreenLocation);
}
super.paint(g);
}
};
myLabel.setBackground(Color.red);
labelPanel.add(myLabel, constraints);
if (myCloseButton != null) {
labelPanel.add(myCloseButton, new GridBag().anchor(GridBagConstraints.EAST).insets(0, 0, 0, 0));
}
labelPanel.setBorder(IdeBorderFactory.createEmptyBorder(PADDING));
labelPanel.setOpaque(false);
@@ -168,6 +216,30 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
myInverted = inverted;
}
@Nullable
@Override
public Rectangle handleMouseMove(@NotNull MouseEvent event) {
Rectangle buttonBounds = getCloseButtonScreenLocation();
if (buttonBounds == null) {
return null;
}
boolean mouseOverButton = buttonBounds.contains(event.getLocationOnScreen());
return (mouseOverButton ^ myCloseButtonHovered) ? buttonBounds : null;
}
@Nullable
private Rectangle getCloseButtonScreenLocation() {
if (myCloseButton == null || myScreenBounds == null) {
return null;
}
Rectangle buttonBounds = myCloseButton.getBounds();
buttonBounds = SwingUtilities.convertRectangle(myCloseButton.getParent(), buttonBounds, myRenderer);
buttonBounds.x += myScreenBounds.x;
buttonBounds.y += myScreenBounds.y;
return buttonBounds;
}
@Override
public String toString() {
return myLabel.getText();
@@ -25,6 +25,7 @@ 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";
@NonNls public static final String RULE_TREE_PLACE = "Arrangement.RuleTree.Place";
private ArrangementConstants() {
}
@@ -80,7 +80,7 @@ public class ArrangementMatcherRuleEditor extends JPanel {
JPanel valuesPanel = new MultiRowFlowPanel(FlowLayout.LEFT, 8, 5);
for (Object value : manager.sort(values)) {
ArrangementAtomNodeComponent component = new ArrangementAtomNodeComponent(manager, new ArrangementSettingsAtomNode(key, value));
ArrangementAtomNodeComponent component = new ArrangementAtomNodeComponent(manager, new ArrangementSettingsAtomNode(key, value), null);
myComponents.put(value, component);
valuesPanel.add(component.getUiComponent());
}
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
/**
* // TODO den add doc
@@ -54,4 +55,17 @@ public interface ArrangementNodeComponent {
* @param selected flag that indicates if current component should be drawn as 'selected'
*/
void setSelected(boolean selected);
/**
* Instructs current component about mose move event.
* <p/>
* Primary intention is to allow to react on event like 'on mouse hover' etc. We can't do that by subscribing to the
* mouse events at the {@link #getUiComponent() corresponding UI control} because it's used only as a renderer and is not put
* to the containers hierarchy, hence, doesn't receive mouse events.
*
* @param event target mouse move event
* @return bounds to be repainted (in screen coordinates) if any; <code>null</code> otherwise
*/
@Nullable
Rectangle handleMouseMove(@NotNull MouseEvent event);
}
@@ -17,6 +17,7 @@ package com.intellij.application.options.codeStyle.arrangement;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.codeStyle.arrangement.model.*;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
/**
@@ -26,9 +27,13 @@ import org.jetbrains.annotations.NotNull;
public class ArrangementNodeComponentFactory {
@NotNull private final ArrangementNodeDisplayManager myDisplayManager;
private Consumer<ArrangementSettingsAtomNode> myRemoveConditionCallback;
public ArrangementNodeComponentFactory(@NotNull ArrangementNodeDisplayManager manager) {
public ArrangementNodeComponentFactory(@NotNull ArrangementNodeDisplayManager manager,
@NotNull Consumer<ArrangementSettingsAtomNode> removeConditionCallback)
{
myDisplayManager = manager;
myRemoveConditionCallback = removeConditionCallback;
}
@NotNull
@@ -37,13 +42,14 @@ public class ArrangementNodeComponentFactory {
node.invite(new ArrangementSettingsNodeVisitor() {
@Override
public void visit(@NotNull ArrangementSettingsAtomNode node) {
ref.set(new ArrangementAtomNodeComponent(myDisplayManager, node));
ref.set(new ArrangementAtomNodeComponent(myDisplayManager, node, myRemoveConditionCallback));
}
@Override
public void visit(@NotNull ArrangementSettingsCompositeNode node) {
switch (node.getOperator()) {
case AND: ref.set(new ArrangementAndNodeComponent(node, ArrangementNodeComponentFactory.this, myDisplayManager)); break;
case AND:
ref.set(new ArrangementAndNodeComponent(node, ArrangementNodeComponentFactory.this, myDisplayManager)); break;
case OR: // TODO den implement
}
}
@@ -0,0 +1,43 @@
/*
* 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 com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import javax.swing.*;
/**
* @author Denis Zhdanov
* @since 8/23/12 11:41 AM
*/
public class ArrangementRemoveConditionAction extends AnAction {
private static final Icon ICON = AllIcons.Actions.CloseNew;
private static final Icon HOVER_ICON = AllIcons.Actions.CloseNewHovered;
public ArrangementRemoveConditionAction() {
getTemplatePresentation().setIcon(ICON);
getTemplatePresentation().setHoveredIcon(HOVER_ICON);
}
@Override
public void actionPerformed(AnActionEvent e) {
// TODO den implement
System.out.println("ArrangementRemoveConditionAction.actionPerformed()");
}
}
@@ -24,6 +24,7 @@ import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettingsGrouper;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.Consumer;
import gnu.trove.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -67,7 +68,12 @@ public class ArrangementRuleTree {
private boolean mySkipSelectionChange;
public ArrangementRuleTree(@NotNull ArrangementSettingsGrouper grouper, @NotNull ArrangementNodeDisplayManager displayManager) {
myFactory = new ArrangementNodeComponentFactory(displayManager);
myFactory = new ArrangementNodeComponentFactory(displayManager, new Consumer<ArrangementSettingsAtomNode>() {
@Override
public void consume(@NotNull ArrangementSettingsAtomNode node) {
removeConditionFromActiveModel(node);
}
});
myRoot = new ArrangementTreeNode(null);
myTreeModel = new DefaultTreeModel(myRoot);
myTree = new Tree(myTreeModel) {
@@ -117,6 +123,12 @@ public class ArrangementRuleTree {
}
}
});
myTree.addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
onMouseMoved(e);
}
});
myTree.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
@@ -159,7 +171,7 @@ public class ArrangementRuleTree {
myTree.setShowsRootHandles(false);
myTree.setCellRenderer(new MyCellRenderer());
}
private void selectPreviousRule() {
ArrangementTreeNode currentSelectionBottom = getCurrentSelectionBottom();
@@ -338,6 +350,22 @@ public class ArrangementRuleTree {
return result;
}
private void removeConditionFromActiveModel(@NotNull ArrangementSettingsAtomNode condition) {
// TODO den implement
System.out.println("Remove condition " + condition);
}
private void onMouseMoved(@NotNull MouseEvent e) {
ArrangementNodeComponent component = getNodeComponentAt(e.getLocationOnScreen());
if (component == null) {
return;
}
Rectangle changedScreenRectangle = component.handleMouseMove(e);
if (changedScreenRectangle != null) {
repaintScreenBounds(changedScreenRectangle);
}
}
private void onMouseClicked(@NotNull MouseEvent e) {
ArrangementNodeComponent component = getNodeComponentAt(e.getLocationOnScreen());
if (component != null) {
@@ -381,12 +409,16 @@ public class ArrangementRuleTree {
private void repaintComponent(@NotNull ArrangementNodeComponent component) {
Rectangle bounds = component.getScreenBounds();
if (bounds != null) {
Point location = bounds.getLocation();
SwingUtilities.convertPointFromScreen(location, myTree);
myTree.repaint(location.x, location.y, bounds.width, bounds.height);
repaintScreenBounds(bounds);
}
}
private void repaintScreenBounds(@NotNull Rectangle bounds) {
Point location = bounds.getLocation();
SwingUtilities.convertPointFromScreen(location, myTree);
myTree.repaint(location.x, location.y, bounds.width, bounds.height);
}
private void notifySelectionListeners(@Nullable ArrangementRuleEditingModel model) {
for (ArrangementRuleSelectionListener listener : myListeners) {
if (model == null) {