This commit is contained in:
Alexander Lobas
2012-02-19 21:05:13 +04:00
parent 7b688fe314
commit 26cc0683f9
17 changed files with 370 additions and 93 deletions
@@ -29,6 +29,8 @@ import com.intellij.designer.designSurface.*;
import com.intellij.designer.designSurface.selection.DirectionResizePoint;
import com.intellij.designer.designSurface.selection.NonResizeSelectionDecorator;
import com.intellij.designer.designSurface.selection.ResizeSelectionDecorator;
import com.intellij.designer.designSurface.tools.ComponentCreationFactory;
import com.intellij.designer.designSurface.tools.CreationTool;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.utils.Position;
import com.intellij.openapi.module.Module;
@@ -45,6 +47,8 @@ import javax.swing.*;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.util.List;
@@ -60,6 +64,21 @@ public final class AndroidDesignerEditorPanel extends DesignerEditorPanel {
public AndroidDesignerEditorPanel(@NotNull Module module, @NotNull VirtualFile file) {
super(module, file);
myGlassLayer.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent event) {
if (event.getKeyCode() == KeyEvent.VK_F2) {
myToolProvider.setActiveTool(new CreationTool(true, new ComponentCreationFactory() {
@Override
@NotNull
public RadComponent create() throws Exception {
return new RadViewComponent(null, event.isControlDown() ? "swing" : "android");
}
}));
}
}
});
// TODO: (profile|device|target|...|theme) panel
// TODO: use platform DOM
@@ -0,0 +1,81 @@
/*
* 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.android.designer.designSurface;
import com.intellij.android.designer.model.RadViewComponent;
import com.intellij.designer.designSurface.EditOperation;
import com.intellij.designer.designSurface.FeedbackLayer;
import com.intellij.designer.designSurface.OperationContext;
import com.intellij.designer.designSurface.feedbacks.AlphaComponent;
import com.intellij.designer.model.RadComponent;
import javax.swing.*;
import java.awt.*;
import java.util.List;
/**
* @author Alexander Lobas
*/
public class CreateOperation implements EditOperation {
private final OperationContext myContext;
private final RadViewComponent myContainer;
private JComponent myFeedback;
public CreateOperation(RadViewComponent container, OperationContext context) {
myContainer = container;
myContext = context;
}
@Override
public void setComponent(RadComponent component) {
}
@Override
public void setComponents(List<RadComponent> components) {
}
@Override
public void showFeedback() {
FeedbackLayer layer = myContext.getArea().getFeedbackLayer();
if (myFeedback == null) {
myFeedback = new AlphaComponent(Color.GREEN, Color.LIGHT_GRAY);
layer.add(myFeedback);
}
myFeedback.setBounds(myContainer.getBounds(layer));
layer.repaint();
}
@Override
public void eraseFeedback() {
if (myFeedback != null) {
FeedbackLayer layer = myContext.getArea().getFeedbackLayer();
layer.remove(myFeedback);
layer.repaint();
myFeedback = null;
}
}
@Override
public boolean canExecute() {
return true;
}
@Override
public void execute() throws Exception {
}
}
@@ -39,7 +39,7 @@ public class RadViewComponent extends RadComponent {
if (parent != null) {
parent.getChildren().add(this);
}
setLayout(new RadViewLayout());
setLayout(new RadViewLayout(this));
}
@Override
@@ -15,6 +15,7 @@
*/
package com.intellij.android.designer.model;
import com.intellij.android.designer.designSurface.CreateOperation;
import com.intellij.android.designer.designSurface.MoveOperation;
import com.intellij.designer.designSurface.ComponentDecorator;
import com.intellij.designer.designSurface.EditOperation;
@@ -29,6 +30,12 @@ import java.awt.*;
* @author Alexander Lobas
*/
public class RadViewLayout extends RadLayout {
private final RadViewComponent myContainer;
public RadViewLayout(RadViewComponent container) {
myContainer = container;
}
@Override
public ComponentDecorator getChildSelectionDecorator(RadComponent component) {
return new NonResizeSelectionDecorator(Color.RED, 1);
@@ -39,6 +46,12 @@ public class RadViewLayout extends RadLayout {
if (context.isMove()) {
return new MoveOperation(context);
}
if (context.isCreate()) {
RadViewComponent component = (RadViewComponent)context.getComponents().get(0);
if ("android".equals(component.getTitle())) {
return new CreateOperation(myContainer, context);
}
}
return null;
}
}
@@ -38,7 +38,7 @@ import java.awt.*;
/**
* @author Alexander Lobas
*/
public abstract class DesignerEditorPanel extends JPanel implements ToolProvider, DataProvider {
public abstract class DesignerEditorPanel extends JPanel implements DataProvider {
private final CardLayout myLayout = new CardLayout();
protected static final Integer LAYER_COMPONENT = JLayeredPane.DEFAULT_LAYER;
@@ -55,10 +55,10 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
private CaptionPanel myVerticalCaption;
private JScrollPane myScrollPane;
protected JLayeredPane myLayeredPane;
private GlassLayer myGlassLayer;
protected GlassLayer myGlassLayer;
private DecorationLayer myDecorationLayer;
private FeedbackLayer myFeedbackLayer;
private InputTool myTool;
protected ToolProvider myToolProvider;
protected EditableArea mySurfaceArea;
@NonNls private final static String ERROR_CARD = "error";
@@ -70,7 +70,7 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
setLayout(myLayout);
createDesignerCard();
createErrorCard();
loadDefaultTool();
myToolProvider.loadDefaultTool();
}
private void createDesignerCard() {
@@ -147,7 +147,19 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
}
};
myGlassLayer = new GlassLayer(this, mySurfaceArea);
myToolProvider = new ToolProvider() {
@Override
public void loadDefaultTool() {
setActiveTool(new SelectionTool());
}
@Override
public void showError(@NonNls String message, Throwable e) {
DesignerEditorPanel.this.showError(message, e);
}
};
myGlassLayer = new GlassLayer(myToolProvider, mySurfaceArea);
myLayeredPane.add(myGlassLayer, LAYER_GLASS);
myDecorationLayer = new DecorationLayer(mySurfaceArea);
@@ -184,29 +196,6 @@ public abstract class DesignerEditorPanel extends JPanel implements ToolProvider
@Nullable
protected abstract EditOperation processRootOperation(OperationContext context);
public InputTool getActiveTool() {
return myTool;
}
@Override
public void setActiveTool(InputTool tool) {
if (myTool != null) {
myTool.deactivate();
}
myTool = tool;
if (myTool != null) {
myTool.setToolProvider(this);
myTool.activate();
}
}
@Override
public void loadDefaultTool() {
setActiveTool(new SelectionTool());
}
public final void showError(@NonNls String message, Throwable e) {
myRootComponent = null;
myErrorLabel.setText(message + e.toString());
@@ -27,7 +27,10 @@ import java.awt.event.MouseEvent;
* @author Alexander Lobas
*/
public abstract class AbstractCreationTool extends TargetingTool {
protected AbstractCreationTool() {
private boolean myCanUnload;
protected AbstractCreationTool(boolean canUnload) {
myCanUnload = canUnload;
setDefaultCursor(Cursors.getCopyCursor());
setDisabledCursor(Cursors.getNoCursor());
}
@@ -62,14 +65,7 @@ public abstract class AbstractCreationTool extends TargetingTool {
updateContext();
updateTargetUnderMouse();
showFeedback();
setCommand();
}
@Override
protected void handleDragStarted() {
if (myState == STATE_DRAG) {
myState = STATE_DRAG_IN_PROGRESS;
}
updateCommand();
}
@Override
@@ -77,28 +73,58 @@ public abstract class AbstractCreationTool extends TargetingTool {
if (myState == STATE_DRAG_IN_PROGRESS) {
updateContext();
showFeedback();
setCommand();
updateCommand();
}
}
protected abstract void selectAddedObjects();
private void selectAddedObjects() {
myArea.setSelection(myContext.getComponents());
}
@Override
protected void resetState() {
// hack: update cursor
if (myCanUnload || myArea == null) {
super.resetState();
}
}
private void handleFinished() {
if (myCanUnload) {
myToolProvider.loadDefaultTool();
}
else {
deactivate();
activate();
// hack: update cursor
if (myArea != null) {
handleMove();
}
}
}
private void updateTargetUnderMouse() {
ContainerTargetFilter filter = new ContainerTargetFilter();
RadComponent target = myArea.findTarget(myCurrentScreenX, myCurrentScreenY, filter);
setTarget(target, filter);
// TODO
if (target != null) {
updateTarget();
}
}
protected abstract void updateTarget();
@Override
protected void updateContext() {
super.updateContext();
if (myState == STATE_DRAG_IN_PROGRESS) {
myContext.setSizeDelta(new Dimension(myCurrentScreenX - myStartScreenX, myCurrentScreenY - myStartScreenY));
myContext.setSizeDelta(new Dimension(moveDeltaWidth(), moveDeltaHeight()));
}
myContext.setLocation(new Point(myCurrentScreenX, myCurrentScreenY));
myContext.setLocation(getLocation());
}
@Override
@@ -0,0 +1,27 @@
/*
* 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.tools;
import com.intellij.designer.model.RadComponent;
import org.jetbrains.annotations.NotNull;
/**
* @author Alexander Lobas
*/
public interface ComponentCreationFactory {
@NotNull
RadComponent create() throws Exception;
}
@@ -0,0 +1,29 @@
/*
* 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.tools;
import com.intellij.designer.model.RadComponent;
import org.jetbrains.annotations.NotNull;
import java.util.List;
/**
* @author Alexander Lobas
*/
public interface ComponentPasteFactory {
@NotNull
List<RadComponent> create() throws Exception;
}
@@ -15,12 +15,36 @@
*/
package com.intellij.designer.designSurface.tools;
import com.intellij.designer.designSurface.OperationContext;
import java.util.Collections;
/**
* @author Alexander Lobas
*/
public class CreationTool extends AbstractCreationTool {
private final ComponentCreationFactory myFactory;
public CreationTool(boolean canUnload, ComponentCreationFactory factory) {
super(canUnload);
myFactory = factory;
}
@Override
protected void selectAddedObjects() {
// TODO: Auto-generated method stub
public void activate() {
super.activate();
myContext.setType(OperationContext.CREATE);
try {
myContext.setComponents(Collections.singletonList(myFactory.create()));
}
catch (Throwable e) {
myToolProvider.loadDefaultTool();
}
}
@Override
protected void updateTarget() {
myTargetOperation.setComponent(myContext.getComponents().get(0));
}
}
@@ -59,12 +59,12 @@ public class DragTracker extends SelectionTracker {
updateContext();
updateTargetUnderMouse();
showFeedback();
setCommand();
updateCommand();
}
}
@Override
protected void setCommand() {
protected void updateCommand() {
if (myTargetOperation != null) {
if (myContext.isMove()) {
setExecuteEnabled(myContext.isMoveEnabled() && myTargetOperation.canExecute());
@@ -117,9 +117,9 @@ public class DragTracker extends SelectionTracker {
protected void updateContext() {
super.updateContext();
myContext.setMoveDelta(new Point(myCurrentScreenX - myStartScreenX, myCurrentScreenY - myStartScreenY));
myContext.setMoveDelta(new Point(moveDeltaWidth(), moveDeltaHeight()));
myContext.setSizeDelta(new Dimension());
myContext.setLocation(new Point(myCurrentScreenX, myCurrentScreenY));
myContext.setLocation(getLocation());
if (myContext.getComponents() == null) {
List<RadComponent> components = new ArrayList<RadComponent>();
@@ -40,7 +40,6 @@ public abstract class InputTool {
protected boolean myExecuteEnabled;
private boolean myActive;
private boolean myCanUnload = true;
protected int myState;
@@ -53,6 +52,9 @@ public abstract class InputTool {
private boolean myCanPastThreshold;
private Cursor myDefaultCursor;
private Cursor myDisabledCursor;
//////////////////////////////////////////////////////////////////////////////////////////
//
// State
@@ -60,6 +62,7 @@ public abstract class InputTool {
//////////////////////////////////////////////////////////////////////////////////////////
public void activate() {
myCanPastThreshold = false;
resetState();
myState = STATE_INIT;
myActive = true;
@@ -77,7 +80,6 @@ public abstract class InputTool {
myButton = 0;
myStartScreenX = 0;
myStartScreenY = 0;
myCanPastThreshold = false;
}
public final void setToolProvider(ToolProvider provider) {
@@ -100,10 +102,6 @@ public abstract class InputTool {
}
}
public final void setUnloadWhenFinished(boolean value) {
myCanUnload = value;
}
protected final void setExecuteEnabled(boolean enabled) {
myExecuteEnabled = enabled;
refreshCursor();
@@ -114,8 +112,6 @@ public abstract class InputTool {
// Cursor
//
//////////////////////////////////////////////////////////////////////////////////////////
private Cursor myDefaultCursor;
private Cursor myDisabledCursor;
protected final void setCursor(@Nullable Cursor cursor) {
if (myArea != null) {
@@ -186,17 +182,30 @@ public abstract class InputTool {
myCurrentScreenY = event.getY();
myButton = event.getButton();
myInputEvent = event;
myToolProvider.setEvent(event);
}
private boolean movedPastThreshold() {
if (!myCanPastThreshold) {
myCanPastThreshold =
Math.abs(myStartScreenX - myCurrentScreenX) > DRAG_THRESHOLD
|| Math.abs(myStartScreenY - myCurrentScreenY) > DRAG_THRESHOLD;
Math.abs(moveDeltaWidth()) > DRAG_THRESHOLD
|| Math.abs(moveDeltaHeight()) > DRAG_THRESHOLD;
}
return myCanPastThreshold;
}
protected final int moveDeltaWidth() {
return myCurrentScreenX - myStartScreenX;
}
protected final int moveDeltaHeight() {
return myCurrentScreenY - myStartScreenY;
}
protected final Point getLocation() {
return new Point(myCurrentScreenX, myCurrentScreenY);
}
protected void handleButtonDown(int button) {
}
@@ -221,16 +230,6 @@ public abstract class InputTool {
protected void handleAreaExited() {
}
protected final void handleFinished() {
if (myCanUnload) {
myToolProvider.loadDefaultTool();
}
else {
deactivate();
activate();
}
}
public void mouseDown(MouseEvent event, EditableArea area) throws Exception {
setArea(area);
setEvent(event);
@@ -285,6 +284,7 @@ public abstract class InputTool {
}
setArea(area);
myToolProvider.setArea(area);
}
public void mouseExited(MouseEvent event, EditableArea area) throws Exception {
@@ -292,6 +292,7 @@ public abstract class InputTool {
setEvent(event);
handleAreaExited();
setArea(null);
myToolProvider.setArea(null);
}
}
}
@@ -15,12 +15,36 @@
*/
package com.intellij.designer.designSurface.tools;
import com.intellij.designer.designSurface.OperationContext;
import java.util.Collections;
/**
* @author Alexander Lobas
*/
public class PasteTool extends AbstractCreationTool {
private final ComponentPasteFactory myFactory;
public PasteTool(boolean canUnload, ComponentPasteFactory factory) {
super(canUnload);
myFactory = factory;
}
@Override
protected void selectAddedObjects() {
// TODO: Auto-generated method stub
public void activate() {
super.activate();
myContext.setType(OperationContext.PASTE);
try {
myContext.setComponents(myFactory.create());
}
catch (Throwable e) {
myToolProvider.loadDefaultTool();
}
}
@Override
protected void updateTarget() {
myTargetOperation.setComponents(myContext.getComponents());
}
}
@@ -94,7 +94,7 @@ public class ResizeTracker extends InputTool {
if (myState == STATE_DRAG_IN_PROGRESS) {
updateContext();
showFeedback();
setCommand();
updateCommand();
}
}
@@ -129,7 +129,7 @@ public class ResizeTracker extends InputTool {
}
}
private void setCommand() {
private void updateCommand() {
for (EditOperation operation : getOperations()) {
if (operation.canExecute()) {
setExecuteEnabled(true);
@@ -146,7 +146,7 @@ public class ResizeTracker extends InputTool {
Point move = new Point();
Dimension size = new Dimension();
int moveDeltaWidth = myCurrentScreenX - myStartScreenX;
int moveDeltaWidth = moveDeltaWidth();
if ((myDirection & Position.WEST) != 0) {
move.x += moveDeltaWidth;
size.width -= moveDeltaWidth;
@@ -155,7 +155,7 @@ public class ResizeTracker extends InputTool {
size.width += moveDeltaWidth;
}
int moveDeltaHeight = myCurrentScreenY - myStartScreenY;
int moveDeltaHeight = moveDeltaHeight();
if ((myDirection & Position.NORTH) != 0) {
move.y += moveDeltaHeight;
size.height -= moveDeltaHeight;
@@ -166,7 +166,7 @@ public class ResizeTracker extends InputTool {
myContext.setMoveDelta(move);
myContext.setSizeDelta(size);
myContext.setLocation(new Point(myCurrentScreenX, myCurrentScreenY));
myContext.setLocation(getLocation());
}
private List<EditOperation> getOperations() {
@@ -80,6 +80,7 @@ public class SelectionTool extends InputTool {
protected void handleButtonUp(int button) {
myState = STATE_INIT;
setTracker(null);
handleMove(); // hack: update cursor
}
@Override
@@ -74,13 +74,6 @@ public class SelectionTracker extends TargetingTool {
}
}
@Override
protected void handleDragStarted() {
if (myState == STATE_DRAG) {
myState = STATE_DRAG_IN_PROGRESS;
}
}
private void performSelection() {
if (mySelected) {
return;
@@ -20,6 +20,7 @@ import com.intellij.designer.designSurface.EditOperation;
import com.intellij.designer.designSurface.OperationContext;
import com.intellij.designer.model.RadComponent;
import com.intellij.designer.model.RadLayout;
import org.jetbrains.annotations.Nullable;
/**
* @author Alexander Lobas
@@ -44,9 +45,17 @@ public abstract class TargetingTool extends InputTool {
setExecuteEnabled(false);
}
@Override
protected void handleDragStarted() {
if (myState == STATE_DRAG) {
myState = STATE_DRAG_IN_PROGRESS;
}
}
@Override
protected void handleAreaExited() {
setTarget(null, null);
setExecuteEnabled(false);
}
protected void showFeedback() {
@@ -76,16 +85,16 @@ public abstract class TargetingTool extends InputTool {
}
}
protected void updateCommand() {
setExecuteEnabled(myTargetOperation != null && myTargetOperation.canExecute());
}
protected void updateContext() {
myContext.setArea(myArea);
myContext.setInputEvent(myInputEvent);
}
protected void setCommand() {
setExecuteEnabled(myTargetOperation != null && myTargetOperation.canExecute());
}
protected void setTarget(RadComponent target, ContainerTargetFilter filter) {
protected void setTarget(@Nullable RadComponent target, @Nullable ContainerTargetFilter filter) {
if (target != myTarget) {
if (myTargetOperation != null) {
eraseFeedback();
@@ -15,17 +15,58 @@
*/
package com.intellij.designer.designSurface.tools;
import com.intellij.designer.designSurface.EditableArea;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.awt.event.MouseEvent;
/**
* @author Alexander Lobas
*/
public interface ToolProvider {
InputTool getActiveTool();
public abstract class ToolProvider {
private InputTool myTool;
private EditableArea myArea;
private MouseEvent myEvent;
void setActiveTool(InputTool tool);
public InputTool getActiveTool() {
return myTool;
}
void loadDefaultTool();
public void setActiveTool(InputTool tool) {
if (myTool != null) {
myTool.deactivate();
}
void showError(@NonNls String message, Throwable e);
myTool = tool;
if (myTool != null) {
myTool.setToolProvider(this);
myTool.activate();
// hack: update cursor
if (myArea != null) {
myTool.setArea(myArea);
myTool.refreshCursor();
try {
myTool.mouseMove(myEvent, myArea);
}
catch (Exception e) {
showError("Edit error: ", e);
}
}
}
}
public abstract void loadDefaultTool();
public void setArea(@Nullable EditableArea area) {
myArea = area;
}
public void setEvent(MouseEvent event) {
myEvent = event;
}
public abstract void showError(@NonNls String message, Throwable e);
}