package jetbrains.mps.nodeEditor.cells.jetpad;
/*Generated by MPS */
import jetbrains.mps.nodeEditor.EditorCell_WithComponent;
import jetbrains.jetpad.mapper.MapperFactory;
import org.jetbrains.mps.openapi.model.SNode;
import jetbrains.jetpad.projectional.diagram.view.DiagramView;
import java.awt.event.FocusListener;
import jetbrains.mps.nodeEditor.cells.SelectCellOnFocusGainedFocusListener;
import jetbrains.jetpad.mapper.Mapper;
import jetbrains.jetpad.projectional.view.ViewContainer;
import jetbrains.jetpad.projectional.view.awt.ViewContainerComponent;
import jetbrains.jetpad.model.collections.list.ObservableList;
import jetbrains.jetpad.model.collections.list.ObservableArrayList;
import jetbrains.jetpad.model.property.Property;
import jetbrains.jetpad.model.property.ValueProperty;
import jetbrains.jetpad.projectional.diagram.view.PolyLineConnection;
import jetbrains.jetpad.projectional.view.ViewTrait;
import jetbrains.mps.lang.editor.diagram.runtime.jetpad.palette.ui.DiagramPalette;
import javax.swing.JPanel;
import jetbrains.jetpad.base.Registration;
import jetbrains.mps.openapi.editor.EditorContext;
import org.jetbrains.annotations.NotNull;
import javax.swing.JComponent;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.event.FocusEvent;
import jetbrains.mps.nodeEditor.cellMenu.SubstituteInfoPartExt;
import jetbrains.jetpad.projectional.view.ViewTraitBuilder;
import jetbrains.jetpad.projectional.view.ViewEvents;
import jetbrains.jetpad.projectional.view.ViewEventHandler;
import jetbrains.jetpad.event.MouseEvent;
import jetbrains.jetpad.projectional.view.View;
import jetbrains.jetpad.event.KeyEvent;
import jetbrains.jetpad.event.Key;
import jetbrains.mps.editor.runtime.selection.SelectionUtil;
import java.util.List;
import jetbrains.mps.openapi.editor.cells.SubstituteAction;
import jetbrains.mps.editor.runtime.commands.EditorCommand;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import jetbrains.mps.nodeEditor.cellMenu.CellContext;
import java.util.ArrayList;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import jetbrains.mps.smodel.action.ModelActions;
import jetbrains.mps.smodel.action.DefaultSChildSetter;
import org.jetbrains.annotations.Nullable;
import jetbrains.mps.smodel.action.AbstractNodeSubstituteAction;
import jetbrains.mps.smodel.action.NodeFactoryManager;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import java.util.Collections;
import jetbrains.mps.nodeEditor.cellMenu.NodeSubstitutePatternEditor;
import java.awt.Window;
import java.awt.Point;
import java.awt.Dimension;
import jetbrains.jetpad.event.ModifierKey;
import jetbrains.jetpad.mapper.Synchronizers;
import jetbrains.jetpad.model.property.WritableProperty;
import jetbrains.mps.lang.editor.diagram.runtime.jetpad.views.DiagramDecoratorView;
import jetbrains.jetpad.model.event.EventHandler;
import jetbrains.jetpad.model.property.PropertyChangeEvent;
import jetbrains.jetpad.projectional.diagram.view.RootTrait;
import jetbrains.jetpad.geometry.Vector;
import java.util.ListIterator;
import java.util.Set;
import jetbrains.mps.internal.collections.runtime.Sequence;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.smodel.action.NodeSubstituteActionWrapper;
public abstract class DiagramCell extends AbstractJetpadCell implements EditorCell_WithComponent, MapperFactory<SNode, DiagramView> {
private final FocusListener mySelectCellOnFocusGained = new SelectCellOnFocusGainedFocusListener(this);
private Mapper<SNode, ViewContainer> myRootMapper;
private Mapper<SNode, ViewContainer> myDecorationRootMapper;
private ViewContainerComponent myComponent;
private boolean mySubstituteEditorVisible = false;
private int myPatternEditorX;
private int myPatternEditorY;
protected ObservableList<SNode> myBlocks = new ObservableArrayList<SNode>();
protected ObservableList<SNode> myConnectors = new ObservableArrayList<SNode>();
protected Property<Boolean> myIsShowingDragFeedBack = new ValueProperty<Boolean>(false);
protected PolyLineConnection myDragConnection = new PolyLineConnection();
private ViewTrait myHandlingTrait;
private DiagramPalette myPalettePanel;
private JPanel myPanel;
protected Registration myRegistration;
protected Property<ViewTrait> myTraitProperty = new ValueProperty<ViewTrait>(null);
public DiagramCell(EditorContext editorContext, SNode node) {
super(editorContext, node);
myTraitProperty.set(getEventHandlingTrait());
}
@NotNull
@Override
public JComponent getComponent() {
if (myPanel == null) {
int columnCount = (myPalettePanel == null ? 1 : 2);
myPanel = new JPanel();
myPanel.setLayout(new GridBagLayout());
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridheight = 1;
gridBagConstraints.gridwidth = columnCount;
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.anchor = GridBagConstraints.NORTHEAST;
if (myPalettePanel != null) {
myPanel.add(myPalettePanel, gridBagConstraints);
}
gridBagConstraints.gridx = columnCount - 1;
myPanel.add(getContainerComponent());
}
return myPanel;
}
private ViewContainerComponent getContainerComponent() {
if (myComponent == null) {
myComponent = new ViewContainerComponent();
getRootMapper().attachRoot();
myComponent.container(getRootMapper().getTarget());
getDecorationRootMapper().attachRoot();
myComponent.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent event) {
}
public void focusLost(FocusEvent focusEvent) {
hidePatternEditor();
}
});
}
return myComponent;
}
@Override
protected void relayoutImpl() {
super.relayoutImpl();
setWidth(getComponent().getWidth() + myGapLeft + myGapRight);
setHeight(getComponent().getHeight());
}
@Override
public void onAdd() {
super.onAdd();
getEditor().getCellTracker().addComponentCell(this);
getComponent().addFocusListener(mySelectCellOnFocusGained);
}
@Override
public void onRemove() {
getComponent().removeFocusListener(mySelectCellOnFocusGained);
getEditor().getCellTracker().removeComponentCell(this);
super.onRemove();
}
@Override
public void setX(int x) {
getComponent().setLocation(x, getComponent().getY());
super.setX(x);
}
@Override
public void setY(int y) {
getComponent().setLocation(getComponent().getX(), y);
super.setY(y);
}
@Override
public void moveTo(int x, int y) {
super.moveTo(x, y);
getComponent().setLocation(myX, myY);
}
/*package*/ void setPatternEditorX(int x) {
myPatternEditorX = x;
}
/*package*/ void setPatternEditorY(int y) {
myPatternEditorY = y;
}
public void setExternalTrait(ViewTrait trait) {
check_xnhqai_a0a82(myRegistration);
if (trait == null) {
myTraitProperty.set(getEventHandlingTrait());
} else {
myTraitProperty.set(trait);
}
}
@Override
public boolean isDrawBorder() {
return false;
}
public void setPalette(DiagramPalette palette) {
myPalettePanel = palette;
}
protected abstract SubstituteInfoPartExt[] createPaletteBlockSubstituteInfoPartExts();
protected abstract SubstituteInfoPartExt[] createPaletteConnectorSubstituteInfoPartExts();
private ViewTrait getEventHandlingTrait() {
if (myHandlingTrait == null) {
this.myHandlingTrait = new ViewTraitBuilder().on(ViewEvents.MOUSE_PRESSED, new ViewEventHandler<MouseEvent>() {
public void handle(View view, MouseEvent event) {
if (view.viewAt(event.location()) != view) {
return;
}
if (!(view.focused().get())) {
view.container().focusedView().set(view);
} else {
hidePatternEditor();
createNewDiagramElement(event.x(), event.y());
}
event.consume();
}
}).on(ViewEvents.KEY_PRESSED, new ViewEventHandler<KeyEvent>() {
public void handle(View view, KeyEvent event) {
if (mySubstituteEditorVisible) {
getEditor().processKeyPressed(getAWTKeyEvent(event, false));
event.consume();
return;
}
if (event.key() == Key.ESCAPE) {
SelectionUtil.selectCell(getContext(), getSNode(), getCellId());
event.consume();
}
}
}).on(ViewEvents.KEY_TYPED, new ViewEventHandler<KeyEvent>() {
public void handle(View view, KeyEvent event) {
if (!(mySubstituteEditorVisible)) {
return;
}
getEditor().processKeyTyped(getAWTKeyEvent(event, false));
event.consume();
}
}).on(ViewEvents.MOUSE_DRAGGED, new ViewEventHandler<MouseEvent>() {
@Override
public void handle(View view, MouseEvent event) {
if (!(hasConnectionDragFeedback())) {
View sourceView = view.viewAt(event.location());
if (sourceView == null || !(check_xnhqai_a0a1a0a0a0b0a0a0a0a0hb(sourceView.prop(JetpadUtils.CONNECTION_SOURCE).get()))) {
return;
}
showConnectionDragFeedback(sourceView);
}
updateConnectionDragFeedback(event.location());
requestRelayout();
getEditor().relayout();
}
}).on(ViewEvents.MOUSE_RELEASED, new ViewEventHandler<MouseEvent>() {
@Override
public void handle(View view, MouseEvent event) {
if (!(hasConnectionDragFeedback())) {
return;
}
updateConnectionDragFeedback(event.location());
createNewDiagramElement(event.location().x, event.location().y);
}
}).build();
}
return this.myHandlingTrait;
}
public void createNewDiagramElement(int x, int y) {
myPatternEditorX = x;
myPatternEditorY = y;
if (trySubstituteImmediately()) {
return;
}
getEditor().activateNodeSubstituteChooser(this, false);
}
private boolean trySubstituteImmediately() {
List<SubstituteAction> matchingActions = getSubstituteInfo().getMatchingActions("", false);
if (matchingActions.size() == 0) {
hideConnectionDragFeedback();
return true;
}
if (matchingActions.size() > 1) {
return false;
}
final SubstituteAction theAction = matchingActions.get(0);
final boolean[] result = new boolean[]{false};
getContext().getRepository().getModelAccess().runReadAction(new Runnable() {
public void run() {
result[0] = theAction.canSubstitute("");
}
});
if (!(result[0])) {
return false;
}
getContext().getRepository().getModelAccess().executeCommand(new EditorCommand(getContext()) {
protected void doExecute() {
theAction.substitute(getContext(), "");
}
});
hideConnectionDragFeedback();
return true;
}
private void hidePatternEditor() {
getEditor().getNodeSubstituteChooser().setVisible(false);
}
public SubstituteInfoPartExt createNewDiagramNodeActions(final SNode container, SAbstractConcept childNodeConcept, final SContainmentLink containingLink, final _FunctionTypes._void_P3_E0<? super SNode, ? super Integer, ? super Integer> setNodePositionCallback) {
return new SubstituteInfoPartExt() {
public List<SubstituteAction> createActions(CellContext cellContext, EditorContext editorContext) {
List<SubstituteAction> result = new ArrayList<SubstituteAction>();
for (SubstituteAction action : ListSequence.fromList(ModelActions.createChildNodeSubstituteActions(container, null, containingLink, null, new DefaultSChildSetter(containingLink) {
@Override
public SNode doExecute(SNode parentNode, SNode oldChild, SNode newChild, @Nullable EditorContext editorContext) {
super.doExecute(parentNode, oldChild, newChild, editorContext);
setNodePositionCallback.invoke(newChild, myPatternEditorX, myPatternEditorY);
return newChild;
}
}, editorContext))) {
result.add(new DiagramCell.DiagramSubstituteActionWraper(action) {
@Override
public boolean canSubstitute(String string) {
return !(hasConnectionDragFeedback()) && super.canSubstitute(string);
}
});
}
return result;
}
};
}
public SubstituteInfoPartExt createNewDiagramConnectorActions(final SNode container, final SAbstractConcept childNodeConcept, final SContainmentLink containingLink, final _FunctionTypes._return_P4_E0<? extends Boolean, ? super SNode, ? super Object, ? super SNode, ? super Object> canCreateConnector, final _FunctionTypes._void_P5_E0<? super SNode, ? super SNode, ? super Object, ? super SNode, ? super Object> setConnectorCallback) {
// TMP solution: manually creating instance of connection instead of using
// ModelActions.createChildNodeSubstituteActions() because of mbeddr reqirements:
// hiding text-specific connection substitute actions from the diagram
return new SubstituteInfoPartExt() {
public List<SubstituteAction> createActions(CellContext cellContext, final EditorContext editorContext) {
AbstractNodeSubstituteAction action = new AbstractNodeSubstituteAction(childNodeConcept.getDeclarationNode(), childNodeConcept, container) {
@Override
public boolean canSubstitute(String string) {
if (!(hasConnectionDragFeedback()) || !(super.canSubstitute(string))) {
return false;
}
DiagramCell.ConnectionInfo connectionInfo = getConnectionInfo();
return connectionInfo.isValid() && canCreateConnector.invoke(connectionInfo.getFromNode(), connectionInfo.getFromId(), connectionInfo.getToNode(), connectionInfo.getToId());
}
@Override
protected SNode doSubstitute(@Nullable EditorContext context, String string) {
SNode result = NodeFactoryManager.createNode(childNodeConcept, null, container, SNodeOperations.getModel(container));
ListSequence.fromList(SNodeOperations.getChildren(container, containingLink)).addElement(result);
DiagramCell.ConnectionInfo connectionInfo = getConnectionInfo();
setConnectorCallback.invoke(result, connectionInfo.getFromNode(), connectionInfo.getFromId(), connectionInfo.getToNode(), connectionInfo.getToId());
return result;
}
};
return Collections.<SubstituteAction>singletonList(new DiagramCell.DiagramSubstituteActionWraper(action));
}
};
}
public DiagramCell.ConnectionInfo getConnectionInfo() {
return new DiagramCell.ConnectionInfo();
}
@Override
public NodeSubstitutePatternEditor createSubstitutePatternEditor() {
return new NodeSubstitutePatternEditor() {
@Override
public void activate(Window window, Point point, Dimension dimension, boolean show) {
Dimension actualDimension = new Dimension(100, 0);
point.translate(myPatternEditorX + getContainerComponent().getX(), myPatternEditorY + getContainerComponent().getY());
super.activate(window, point, actualDimension, show);
mySubstituteEditorVisible = true;
}
@Override
public void done() {
super.done();
hideConnectionDragFeedback();
mySubstituteEditorVisible = false;
}
};
}
private java.awt.event.KeyEvent getAWTKeyEvent(KeyEvent jetPadKeyEvent, boolean isTyped) {
// TODO: better integration with MPS substitute editor is required here
int id = (isTyped ? java.awt.event.KeyEvent.KEY_TYPED : java.awt.event.KeyEvent.KEY_PRESSED);
long when = System.currentTimeMillis();
int modifiers = 0;
if (jetPadKeyEvent.has(ModifierKey.ALT)) {
modifiers |= java.awt.event.KeyEvent.ALT_MASK;
}
if (jetPadKeyEvent.has(ModifierKey.CONTROL)) {
modifiers |= java.awt.event.KeyEvent.CTRL_MASK;
}
if (jetPadKeyEvent.has(ModifierKey.META)) {
modifiers |= java.awt.event.KeyEvent.META_MASK;
}
if (jetPadKeyEvent.has(ModifierKey.SHIFT)) {
modifiers |= java.awt.event.KeyEvent.SHIFT_MASK;
}
int keyCode;
switch (jetPadKeyEvent.key()) {
case ESCAPE:
keyCode = java.awt.event.KeyEvent.VK_ESCAPE;
break;
case SPACE:
keyCode = java.awt.event.KeyEvent.VK_SPACE;
break;
case BACKSPACE:
keyCode = java.awt.event.KeyEvent.VK_BACK_SPACE;
break;
case DELETE:
keyCode = java.awt.event.KeyEvent.VK_DELETE;
break;
case LEFT:
keyCode = java.awt.event.KeyEvent.VK_LEFT;
break;
case RIGHT:
keyCode = java.awt.event.KeyEvent.VK_RIGHT;
break;
case UP:
keyCode = java.awt.event.KeyEvent.VK_UP;
break;
case DOWN:
keyCode = java.awt.event.KeyEvent.VK_DOWN;
break;
case ENTER:
keyCode = java.awt.event.KeyEvent.VK_ENTER;
break;
default:
keyCode = 0;
}
return new java.awt.event.KeyEvent(getComponent(), id, when, modifiers, keyCode, jetPadKeyEvent.keyChar());
}
public Mapper<SNode, ViewContainer> getRootMapper() {
if (myRootMapper == null) {
myRootMapper = new Mapper<SNode, ViewContainer>(getSNode(), createViewContainer()) {
@Override
protected void registerSynchronizers(Mapper.SynchronizersConfiguration configuration) {
super.registerSynchronizers(configuration);
configuration.add(Synchronizers.forConstantRole(this, getSource(), getTarget().contentRoot().children(), DiagramCell.this));
configuration.add(Synchronizers.forProperty(myTraitProperty, new WritableProperty<ViewTrait>() {
public void set(ViewTrait trait) {
myRegistration = getTarget().root().addTrait(trait);
}
}));
}
};
}
return myRootMapper;
}
public Mapper<SNode, ViewContainer> getDecorationRootMapper() {
if (myDecorationRootMapper == null) {
myDecorationRootMapper = new Mapper<SNode, ViewContainer>(getSNode(), getRootMapper().getTarget()) {
@Override
protected void registerSynchronizers(Mapper.SynchronizersConfiguration configuration) {
super.registerSynchronizers(configuration);
configuration.add(Synchronizers.forConstantRole(this, getSource(), getTarget().decorationRoot().children(), new MapperFactory<SNode, View>() {
public Mapper<? extends SNode, ? extends View> createMapper(SNode source) {
return createDecorationMapper(source);
}
}));
}
};
}
return myDecorationRootMapper;
}
public abstract Mapper<SNode, DiagramDecoratorView> createDecorationMapper(SNode node);
private ViewContainer createViewContainer() {
ViewContainer result = new ViewContainer();
result.root().focusable().set(true);
result.root().focused().addHandler(new EventHandler<PropertyChangeEvent<Boolean>>() {
public void onEvent(PropertyChangeEvent<Boolean> focused) {
if (!(focused.getNewValue())) {
hidePatternEditor();
} else if (!(isSelected())) {
SelectionUtil.selectCell(getContext(), getSNode(), getCellId());
}
}
});
result.root().addTrait(RootTrait.ROOT_TRAIT);
return result;
}
public boolean hasConnectionDragFeedback() {
return myIsShowingDragFeedBack.get();
}
public PolyLineConnection showConnectionDragFeedback(View fromView) {
assert !(myIsShowingDragFeedBack.get());
PolyLineConnection connection = new PolyLineConnection();
connection.fromView().set(fromView);
myDragConnection = connection;
myIsShowingDragFeedBack.set(true);
return connection;
}
public void updateConnectionDragFeedback(Vector toLocation) {
View targetView = getRootMapper().getTarget().contentRoot().viewAt(toLocation);
while (targetView != null && targetView.prop(JetpadUtils.CONNECTABLE).get() == null) {
targetView = targetView.parent().get();
}
if (targetView != null && targetView.prop(JetpadUtils.CONNECTABLE).get()) {
myDragConnection.toView().set(targetView);
} else {
myDragConnection.toView().set(null);
}
myDragConnection.toLocation().set(toLocation);
}
public void hideConnectionDragFeedback() {
myIsShowingDragFeedBack.set(false);
}
protected void syncDiagramElements(Iterable<SNode> elements, ListIterator<SNode> blocksIterator, Set<SNode> existingBlocks, ListIterator<SNode> connectorsIterator, Set<SNode> existingConnectors) {
for (SNode nextElement : Sequence.fromIterable(elements)) {
EditorCell cell = getContext().getEditorComponent().getUpdater().getCurrentUpdateSession().updateChildNodeCell(nextElement);
if (!(cell instanceof BlockCell) && !(cell instanceof ConnectorCell)) {
continue;
}
syncToNextNode((cell instanceof BlockCell ? blocksIterator : connectorsIterator), (cell instanceof BlockCell ? existingBlocks : existingConnectors), nextElement, cell);
}
}
/*package*/ static class DiagramSubstituteActionWraper extends NodeSubstituteActionWrapper {
private DiagramSubstituteActionWraper(SubstituteAction action) {
super(action);
}
}
public class ConnectionInfo {
public ConnectionInfo() {
if (myDragConnection == null) {
return;
}
View fromView = myDragConnection.fromView().get();
View toView = myDragConnection.toView().get();
if (fromView == null || toView == null) {
return;
}
setFromNode(fromView.prop(JetpadUtils.SOURCE).get());
setFromId(fromView.prop(JetpadUtils.ID).get());
setToNode(toView.prop(JetpadUtils.SOURCE).get());
setToId(toView.prop(JetpadUtils.ID).get());
}
public boolean isValid() {
return getFromNode() != null && getToNode() != null;
}
private SNode myFromNode;
public SNode getFromNode() {
return this.myFromNode;
}
private void setFromNode(SNode value) {
this.myFromNode = value;
}
private Object myFromId;
public Object getFromId() {
return this.myFromId;
}
private void setFromId(Object value) {
this.myFromId = value;
}
private SNode myToNode;
public SNode getToNode() {
return this.myToNode;
}
private void setToNode(SNode value) {
this.myToNode = value;
}
private Object myToId;
public Object getToId() {
return this.myToId;
}
private void setToId(Object value) {
this.myToId = value;
}
}
private static void check_xnhqai_a0a82(Registration checkedDotOperand) {
if (null != checkedDotOperand) {
checkedDotOperand.remove();
}
}
private static boolean check_xnhqai_a0a1a0a0a0b0a0a0a0a0hb(Boolean checkedDotOperand) {
if (null != checkedDotOperand) {
return checkedDotOperand.booleanValue();
}
return false;
}
}