CaptionPanel

This commit is contained in:
Alexander Lobas
2012-04-13 18:09:21 +04:00
parent 6d2b3095f0
commit 372b49e629
9 changed files with 402 additions and 104 deletions
@@ -17,6 +17,7 @@ package com.intellij.android.designer.model;
import com.android.ide.common.rendering.api.ViewInfo;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.model.RadVisualComponent;
import com.intellij.designer.propertyTable.Property;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.psi.xml.XmlAttribute;
@@ -24,20 +25,15 @@ import com.intellij.psi.xml.XmlTag;
import com.intellij.util.containers.hash.HashMap;
import org.jdom.Element;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author Alexander Lobas
*/
public class RadViewComponent extends RadComponent {
private final List<RadComponent> myChildren = new ArrayList<RadComponent>();
public class RadViewComponent extends RadVisualComponent {
protected ViewInfo myViewInfo;
private Component myNativeComponent;
private final Rectangle myBounds = new Rectangle();
private Rectangle myMargins;
private XmlTag myTag;
private List<Property> myProperties;
@@ -50,11 +46,6 @@ public class RadViewComponent extends RadComponent {
myTag = tag;
}
@Override
public List<RadComponent> getChildren() {
return myChildren;
}
public ViewInfo getViewInfo() {
return myViewInfo;
}
@@ -83,33 +74,6 @@ public class RadViewComponent extends RadComponent {
return myMargins;
}
@Override
public Rectangle getBounds() {
return myBounds;
}
@Override
public Rectangle getBounds(Component relativeTo) {
return SwingUtilities.convertRectangle(myNativeComponent, myBounds, relativeTo);
}
public void setBounds(int x, int y, int width, int height) {
myBounds.setBounds(x, y, width, height);
}
public Component getNativeComponent() {
return myNativeComponent;
}
public void setNativeComponent(Component nativeComponent) {
myNativeComponent = nativeComponent;
}
@Override
public Point convertPoint(Component component, int x, int y) {
return SwingUtilities.convertPoint(component, x, y, myNativeComponent);
}
@Override
public void delete() throws Exception {
getParent().getChildren().remove(this);
@@ -51,6 +51,11 @@ public class CommonEditActionsProvider implements DeleteProvider, CopyProvider,
public CommonEditActionsProvider(DesignerEditorPanel designer) {
myDesigner = designer;
}
protected EditableArea getArea() {
return myDesigner.getActionsArea();
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Delete
@@ -60,7 +65,7 @@ public class CommonEditActionsProvider implements DeleteProvider, CopyProvider,
@Override
public boolean canDeleteElement(@NotNull DataContext dataContext) {
// TODO: InplaceEditing
List<RadComponent> selection = myDesigner.getActionsArea().getSelection();
List<RadComponent> selection = getArea().getSelection();
if (selection.isEmpty()) {
return false;
}
@@ -77,7 +82,7 @@ public class CommonEditActionsProvider implements DeleteProvider, CopyProvider,
myDesigner.getToolProvider().execute(new ThrowableRunnable<Exception>() {
@Override
public void run() throws Exception {
EditableArea area = myDesigner.getActionsArea();
EditableArea area = getArea();
List<RadComponent> selection = area.getSelection();
List<RadComponent> components = RadComponent.getPureSelection(selection);
RadComponent newSelection = getNewSelection(components.get(0), selection);
@@ -128,7 +133,7 @@ public class CommonEditActionsProvider implements DeleteProvider, CopyProvider,
@Override
public boolean isCopyEnabled(@NotNull DataContext dataContext) {
// TODO: InplaceEditing
return !myDesigner.getActionsArea().getSelection().isEmpty();
return !getArea().getSelection().isEmpty();
}
@Override
@@ -141,7 +146,7 @@ public class CommonEditActionsProvider implements DeleteProvider, CopyProvider,
Element root = new Element("designer");
root.setAttribute("target", myDesigner.getPlatformTarget());
List<RadComponent> components = RadComponent.getPureSelection(myDesigner.getActionsArea().getSelection());
List<RadComponent> components = RadComponent.getPureSelection(getArea().getSelection());
for (RadComponent component : components) {
component.copyTo(root);
}
@@ -15,22 +15,130 @@
*/
package com.intellij.designer.designSurface;
import com.intellij.designer.actions.CommonEditActionsProvider;
import com.intellij.designer.designSurface.tools.InputTool;
import com.intellij.designer.model.FindComponentVisitor;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.model.RadVisualComponent;
import com.intellij.ide.DeleteProvider;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.SideBorder;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.util.List;
/**
* @author Alexander Lobas
*/
public class CaptionPanel extends JComponent implements DataProvider {
public class CaptionPanel extends JLayeredPane implements DataProvider, DeleteProvider, ComponentSelectionListener {
private final boolean myHorizontal;
private final EditableArea myArea;
private final DecorationLayer myDecorationLayer;
private final FeedbackLayer myFeedbackLayer;
private final CommonEditActionsProvider myActionsProvider;
private final RadVisualComponent myRootComponent;
public CaptionPanel(DesignerEditorPanel designer, boolean horizontal) {
setBorder(IdeBorderFactory.createBorder(horizontal ? SideBorder.BOTTOM : SideBorder.RIGHT));
setFocusable(true);
myHorizontal = horizontal;
myRootComponent = new RadVisualComponent() {
@Override
public boolean canDelete() {
return false;
}
};
myRootComponent.setNativeComponent(this);
myRootComponent.setBounds(0, 0, 100000, 100000);
myArea = new ComponentEditableArea(this) {
@Override
protected void fireSelectionChanged() {
super.fireSelectionChanged();
revalidate();
repaint();
}
@Override
public RadComponent findTarget(int x, int y, @Nullable ComponentTargetFilter filter) {
FindComponentVisitor visitor = new FindComponentVisitor(CaptionPanel.this, filter, x, y);
myRootComponent.accept(visitor, false);
return visitor.getResult();
}
@Override
public InputTool findTargetTool(int x, int y) {
return myDecorationLayer.findTargetTool(x, y);
}
@Override
public void showSelection(boolean value) {
myDecorationLayer.showSelection(value);
}
@Override
public ComponentDecorator getRootSelectionDecorator() {
return EmptyComponentDecorator.INSTANCE;
}
@Override
public EditOperation processRootOperation(OperationContext context) {
return null;
}
@Override
public FeedbackLayer getFeedbackLayer() {
return myFeedbackLayer;
}
@Override
public RadComponent getRootComponent() {
return myRootComponent;
}
};
add(new GlassLayer(designer.getToolProvider(), myArea), DesignerEditorPanel.LAYER_GLASS);
myDecorationLayer = new DecorationLayer(myArea);
add(myDecorationLayer, DesignerEditorPanel.LAYER_DECORATION);
myFeedbackLayer = new FeedbackLayer();
add(myFeedbackLayer, DesignerEditorPanel.LAYER_FEEDBACK);
myActionsProvider = new CommonEditActionsProvider(designer) {
@Override
protected EditableArea getArea() {
return myArea;
}
};
designer.getSurfaceArea().addSelectionListener(this);
}
public void attachToScrollPane(JScrollPane scrollPane) {
scrollPane.getViewport().addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
repaint();
}
});
}
public void doLayout() {
for (int i = getComponentCount() - 1; i >= 0; i--) {
Component component = getComponent(i);
component.setBounds(0, 0, getWidth(), getHeight());
}
}
@Override
@@ -45,6 +153,56 @@ public class CaptionPanel extends JComponent implements DataProvider {
@Override
public Object getData(@NonNls String dataId) {
return null; // TODO: Auto-generated method stub
if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) {
return this;
}
return null;
}
@Override
public boolean canDeleteElement(@NotNull DataContext dataContext) {
return myActionsProvider.canDeleteElement(dataContext);
}
@Override
public void deleteElement(@NotNull DataContext dataContext) {
myActionsProvider.deleteElement(dataContext);
}
@Override
public void selectionChanged(EditableArea area) {
List<RadComponent> selection = area.getSelection();
if (selection.size() != 1) {
return;
}
List<RadComponent> children = myRootComponent.getChildren();
boolean update = !children.isEmpty();
children.clear();
myRootComponent.setLayout(null);
ICaption caption = null;
RadComponent component = selection.get(0);
RadComponent parent = component.getParent();
if (parent != null && parent.getLayout() instanceof ICaption) {
caption = (ICaption)parent.getLayout();
}
if (caption == null && component instanceof ICaption) {
caption = (ICaption)component;
}
if (caption != null) {
myRootComponent.setLayout(caption.getCaptionLayout(area, myHorizontal));
caption.addCaptionChildren(area, myHorizontal, children);
update = true;
}
if (update) {
revalidate();
repaint();
}
}
}
@@ -21,8 +21,8 @@ import com.intellij.designer.actions.DesignerActionPanel;
import com.intellij.designer.componentTree.TreeComponentDecorator;
import com.intellij.designer.componentTree.TreeEditableArea;
import com.intellij.designer.designSurface.tools.*;
import com.intellij.designer.model.FindComponentVisitor;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.model.RadComponentVisitor;
import com.intellij.designer.palette.Item;
import com.intellij.designer.propertyTable.Property;
import com.intellij.diagnostic.LogMessageEx;
@@ -70,12 +70,10 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
private static final Logger LOG = Logger.getInstance("#com.intellij.designer.designSurface.DesignerEditorPanel");
protected static final Integer LAYER_COMPONENT = JLayeredPane.DEFAULT_LAYER;
protected static final Integer LAYER_STATIC_DECORATION = JLayeredPane.POPUP_LAYER;
protected static final Integer LAYER_DECORATION = JLayeredPane.DRAG_LAYER;
protected static final Integer LAYER_FEEDBACK = LAYER_DECORATION + 100;
protected static final Integer LAYER_DECORATION = JLayeredPane.POPUP_LAYER;
protected static final Integer LAYER_FEEDBACK = JLayeredPane.DRAG_LAYER;
protected static final Integer LAYER_GLASS = LAYER_FEEDBACK + 100;
protected static final Integer LAYER_BUTTONS = LAYER_GLASS + 100;
protected static final Integer LAYER_INPLACE_EDITING = LAYER_BUTTONS + 100;
protected static final Integer LAYER_INPLACE_EDITING = LAYER_GLASS + 100;
private static final Integer LAYER_PROGRESS = LAYER_INPLACE_EDITING + 100;
private final static String DESIGNER_CARD = "designer";
@@ -134,24 +132,6 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
}
private void createDesignerCard() {
JPanel content = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.VERTICAL;
myVerticalCaption = new CaptionPanel(this, false);
content.add(myVerticalCaption, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
myHorizontalCaption = new CaptionPanel(this, true);
content.add(myHorizontalCaption, gbc);
myLayeredPane = new MyLayeredPane();
mySurfaceArea = new ComponentEditableArea(myLayeredPane) {
@@ -165,7 +145,7 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
@Override
public RadComponent findTarget(int x, int y, @Nullable ComponentTargetFilter filter) {
if (myRootComponent != null) {
FindComponentVisitor visitor = new FindComponentVisitor(filter, x, y);
FindComponentVisitor visitor = new FindComponentVisitor(myLayeredPane, filter, x, y);
myRootComponent.accept(visitor, false);
return visitor.getResult();
}
@@ -267,6 +247,24 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
myFeedbackLayer = new FeedbackLayer();
myLayeredPane.add(myFeedbackLayer, LAYER_FEEDBACK);
JPanel content = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.fill = GridBagConstraints.VERTICAL;
myVerticalCaption = new CaptionPanel(this, false);
content.add(myVerticalCaption, gbc);
gbc.gridx = 1;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
myHorizontalCaption = new CaptionPanel(this, true);
content.add(myHorizontalCaption, gbc);
gbc.gridx = 1;
gbc.gridy = 1;
gbc.weightx = 1;
@@ -277,6 +275,9 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
myScrollPane.setBackground(Color.WHITE);
content.add(myScrollPane, gbc);
myHorizontalCaption.attachToScrollPane(myScrollPane);
myVerticalCaption.attachToScrollPane(myScrollPane);
myActionPanel = new DesignerActionPanel(this, myGlassLayer);
myDesignerCard = new JPanel(new FillLayout());
@@ -768,37 +769,6 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
}
}
private class FindComponentVisitor extends RadComponentVisitor {
@Nullable private final ComponentTargetFilter myFilter;
private RadComponent myResult;
private final int myX;
private final int myY;
public FindComponentVisitor(@Nullable ComponentTargetFilter filter, int x, int y) {
myFilter = filter;
myX = x;
myY = y;
}
public RadComponent getResult() {
return myResult;
}
@Override
public boolean visit(RadComponent component) {
return myResult == null &&
component.getBounds(myLayeredPane).contains(myX, myY) &&
(myFilter == null || myFilter.preFilter(component));
}
@Override
public void endVisit(RadComponent component) {
if (myResult == null && (myFilter == null || myFilter.resultFilter(component))) {
myResult = component;
}
}
}
public static final class ErrorInfo {
public String myMessage;
public String myDisplayMessage;
@@ -0,0 +1,44 @@
/*
* 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.designer.designSurface;
import com.intellij.designer.designSurface.tools.InputTool;
import com.intellij.designer.model.RadComponent;
import java.awt.*;
/**
* @author Alexander Lobas
*/
public final class EmptyComponentDecorator extends ComponentDecorator {
public static final ComponentDecorator INSTANCE = new EmptyComponentDecorator();
private EmptyComponentDecorator() {
}
@Override
public InputTool findTargetTool(DecorationLayer layer, RadComponent component, int x, int y) {
return null;
}
@Override
public void decorate(DecorationLayer layer, Graphics2D host, RadComponent component) {
}
@Override
protected void paint(DecorationLayer layer, Graphics2D g, RadComponent component) {
}
}
@@ -0,0 +1,30 @@
/*
* 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.designer.designSurface;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.model.RadLayout;
import java.util.List;
/**
* @author Alexander Lobas
*/
public interface ICaption {
RadLayout getCaptionLayout(EditableArea mainArea, boolean horizontal);
void addCaptionChildren(EditableArea mainArea, boolean horizontal, List<RadComponent> children);
}
@@ -0,0 +1,58 @@
/*
* 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.designer.model;
import com.intellij.designer.designSurface.ComponentTargetFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* @author Alexander Lobas
*/
public class FindComponentVisitor extends RadComponentVisitor {
private final JComponent myComponent;
private final ComponentTargetFilter myFilter;
private RadComponent myResult;
private final int myX;
private final int myY;
public FindComponentVisitor(@NotNull JComponent component, @Nullable ComponentTargetFilter filter, int x, int y) {
myComponent = component;
myFilter = filter;
myX = x;
myY = y;
}
public RadComponent getResult() {
return myResult;
}
@Override
public boolean visit(RadComponent component) {
return myResult == null &&
component.getBounds(myComponent).contains(myX, myY) &&
(myFilter == null || myFilter.preFilter(component));
}
@Override
public void endVisit(RadComponent component) {
if (myResult == null && (myFilter == null || myFilter.resultFilter(component))) {
myResult = component;
}
}
}
@@ -115,7 +115,7 @@ public abstract class RadComponent {
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// layout
// Layout
//
//////////////////////////////////////////////////////////////////////////////////////////
@@ -123,9 +123,11 @@ public abstract class RadComponent {
return myLayout;
}
public void setLayout(RadLayout layout) {
public void setLayout(@Nullable RadLayout layout) {
myLayout = layout;
myLayout.setContainer(this);
if (myLayout != null) {
myLayout.setContainer(this);
}
}
@Nullable
@@ -0,0 +1,67 @@
/*
* 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.designer.model;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author Alexander Lobas
*/
public abstract class RadVisualComponent extends RadComponent {
protected final List<RadComponent> myChildren = new ArrayList<RadComponent>();
private Component myNativeComponent;
private final Rectangle myBounds = new Rectangle();
@Override
public List<RadComponent> getChildren() {
return myChildren;
}
@Override
public Rectangle getBounds() {
return myBounds;
}
@Override
public Rectangle getBounds(Component relativeTo) {
return myNativeComponent == relativeTo
? new Rectangle(myBounds) :
SwingUtilities.convertRectangle(myNativeComponent, myBounds, relativeTo);
}
public void setBounds(int x, int y, int width, int height) {
myBounds.setBounds(x, y, width, height);
}
@Override
public Point convertPoint(Component relativeFrom, int x, int y) {
return myNativeComponent == relativeFrom
? myBounds.getLocation() :
SwingUtilities.convertPoint(relativeFrom, x, y, myNativeComponent);
}
public Component getNativeComponent() {
return myNativeComponent;
}
public void setNativeComponent(Component nativeComponent) {
myNativeComponent = nativeComponent;
}
}