package jetbrains.mps.vcs.diff.ui.common; /*Generated by MPS */ import jetbrains.mps.nodeEditor.messageTargets.EditorMessageWithTarget; import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import jetbrains.mps.vcs.diff.changes.ModelChange; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.errors.messageTargets.MessageTarget; import jetbrains.mps.openapi.editor.message.EditorMessageOwner; import jetbrains.mps.errors.MessageStatus; import java.awt.Color; import jetbrains.mps.vcs.diff.changes.ChangeType; import jetbrains.mps.openapi.editor.cells.EditorCell; import jetbrains.mps.errors.messageTargets.MessageTargetEnum; import jetbrains.mps.openapi.editor.cells.EditorCell_Collection; import java.awt.Graphics; import jetbrains.mps.nodeEditor.EditorComponent; import java.awt.Rectangle; import jetbrains.mps.nodeEditor.cells.GeometryUtil; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.nodeEditor.messageTargets.CellFinder; import jetbrains.mps.nodeEditor.cells.PropertyAccessor; import jetbrains.mps.nodeEditor.cells.EditorCell_Property; import jetbrains.mps.openapi.editor.message.SimpleEditorMessage; import jetbrains.mps.internal.collections.runtime.Sequence; import jetbrains.mps.openapi.editor.cells.CellMessagesUtil; import jetbrains.mps.internal.collections.runtime.IWhereFilter; import jetbrains.mps.errors.messageTargets.DeletedNodeMessageTarget; import jetbrains.mps.ide.util.ColorAndGraphicsUtil; import jetbrains.mps.baseLanguage.closures.runtime.Wrappers; import jetbrains.mps.smodel.ModelAccess; import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes; import jetbrains.mps.nodeEditor.inspector.InspectorEditorComponent; import java.util.Iterator; import jetbrains.mps.baseLanguage.closures.runtime.YieldingIterator; import jetbrains.mps.util.Computable; import jetbrains.mps.nodeEditor.cellLayout.CellLayout_Vertical; import jetbrains.mps.editor.runtime.style.StyleAttributes; import org.jetbrains.annotations.NotNull; import org.apache.log4j.Level; import jetbrains.mps.nodeEditor.cells.ModelAccessor; public class ChangeEditorMessage extends EditorMessageWithTarget { private static final Logger LOG = LogManager.getLogger(ChangeEditorMessage.class); private static final String NAME_PROPERTY = "name"; private ModelChange myChange; private ChangeEditorMessage.ConflictChecker myConflictsChecker; private boolean myHighlighted; protected ChangeEditorMessage(SNode node, MessageTarget target, EditorMessageOwner owner, ModelChange change, ChangeEditorMessage.ConflictChecker conflictChecker, boolean highlighted) { super(node, MessageStatus.OK, target, null, "", owner); myChange = change; myConflictsChecker = conflictChecker; myHighlighted = highlighted; } public boolean isConflicted() { return myConflictsChecker != null && myConflictsChecker.isChangeConflicted(myChange); } @Override public boolean showInGutter() { return false; } @Override public Color getColor() { return ChangeColors.get((isConflicted() ? ChangeType.CONFLICTED : myChange.getType())); } public ModelChange getChange() { return myChange; } @Override public boolean isBackground() { return true; } private boolean isDirectCell(EditorCell cell) { // Return true if and only if this cell should be painted, not only set in frame if (cell == null) { return false; } if (myMessageTarget.getTarget() == MessageTargetEnum.NODE) { return getNode() == cell.getSNode(); } else { return !(cell instanceof EditorCell_Collection) && isNameCell(cell) == (myMessageTarget.getTarget() == MessageTargetEnum.PROPERTY && NAME_PROPERTY.equals(myMessageTarget.getRole())); } } @Override public boolean showInEditor() { return myHighlighted; } @Override public void paint(Graphics graphics, EditorComponent editor, EditorCell cell) { if (!(myHighlighted)) { return; } if (isDirectCell(cell)) { ((jetbrains.mps.nodeEditor.cells.EditorCell) cell).paintSelection(graphics, getColor(), false); repaintConflictedMessages(graphics, cell); } else { if (myMessageTarget.getTarget() == MessageTargetEnum.DELETED_CHILD) { drawDeletedChild(graphics, cell); } else { Rectangle bounds = (isIndirectRoot(editor) ? getFirstPseudoLineBounds(editor) : GeometryUtil.getBounds(cell)); graphics.setColor(ChangeColors.get((isConflicted() ? ChangeType.CONFLICTED : ChangeType.CHANGE))); graphics.drawRect(bounds.x + 1, bounds.y + 1, bounds.width - 2, bounds.height - 2); } } } @Override public EditorCell getCell(EditorComponent editor) { EditorCell cell = super.getCell(editor); if (cell != null && cell.isBig() && !(isDirectCell(cell))) { SNode node = getNode(); if (SNodeOperations.isInstanceOf(node, MetaAdapterFactory.getInterfaceConcept(0xceab519525ea4f22L, 0x9b92103b95ca8c0cL, 0x110396eaaa4L, "jetbrains.mps.lang.core.structure.INamedConcept"))) { cell = CellFinder.getCellForProperty(editor, node, NAME_PROPERTY); } } return cell; } @Override public boolean acceptCell(EditorCell cell, EditorComponent component) { EditorCell superCell = super.getCell(component); return isNameCell(cell) && !(isDirectCell(cell)) && superCell != null && cell.isBig() || super.acceptCell(cell, component); } private boolean isNameCell(EditorCell cell) { PropertyAccessor pa = as_myu41h_a0a0a81(check_myu41h_a0a0a71((as_myu41h_a0a0a0a0a81(cell, EditorCell_Property.class))), PropertyAccessor.class); return getNode() == check_myu41h_a0a1a71(pa) && NAME_PROPERTY.equals(check_myu41h_a0a0b0r(pa)); } private void repaintConflictedMessages(Graphics graphics, EditorCell cell) { // This is a workaround for case when any change message is going to be painted over // "conflicted" red frame. In this case, we repaint conflicted red frame again EditorCell_Collection parent = cell.getParent(); if (parent != null && parent.getCellsCount() == 1) { SimpleEditorMessage messageToRepaint = Sequence.fromIterable(((Iterable<ChangeEditorMessage>) CellMessagesUtil.getMessages(parent, ChangeEditorMessage.class))).findFirst(new IWhereFilter<ChangeEditorMessage>() { public boolean accept(ChangeEditorMessage m) { return m.isConflicted(); } }); if (messageToRepaint != null) { ((ChangeEditorMessage) messageToRepaint).paint(graphics, (EditorComponent) cell.getEditorComponent(), parent); } } } private void drawDeletedChild(Graphics graphics, EditorCell cell) { if (myMessageTarget.getRole().equals(cell.getRole())) { int index = ((DeletedNodeMessageTarget) myMessageTarget).getNextChildIndex(); if (index != -1) { EditorCell_Collection collectionCell = (EditorCell_Collection) cell; if (hasChildrenWithDifferentNode(cell)) { EditorCell childCell = getChildCell(collectionCell, index); if (isVertical(collectionCell)) { drawHorizontalLine(graphics, collectionCell, childCell); } else { drawVerticalLineWithArrows(graphics, collectionCell, childCell); } } else { ((jetbrains.mps.nodeEditor.cells.EditorCell) cell).paintSelection(graphics, getColor(), false); } } } } private void drawHorizontalLine(Graphics graphics, EditorCell_Collection collectionCell, EditorCell childCell) { int y; if (childCell != null) { y = childCell.getY(); } else { y = collectionCell.lastCell().getBottom(); } graphics.setColor(getColor()); graphics.drawLine(collectionCell.getX(), y, collectionCell.getRight(), y); } private void drawVerticalLineWithArrows(Graphics graphics, EditorCell_Collection collectionCell, EditorCell cell) { int x; EditorCell childCell; if (cell != null) { childCell = cell; x = cell.getX(); } else { childCell = collectionCell.lastCell(); x = childCell.getRight(); } int y1 = childCell.getY(); int y2 = childCell.getBottom(); graphics.setColor(getColor()); graphics.drawLine(x, y1, x, y2); graphics.fillPolygon(new int[]{x, x - 3, x + 3}, new int[]{y1 - 2, y1 - 5, y1 - 5}, 3); graphics.fillPolygon(new int[]{x, x - 3, x + 3}, new int[]{y2 + 2, y2 + 5, y2 + 5}, 3); graphics.setColor(ColorAndGraphicsUtil.brightenColor(getColor(), 0.8f)); graphics.drawPolygon(new int[]{x, x - 3, x + 3}, new int[]{y1 - 2, y1 - 5, y1 - 5}, 3); graphics.drawPolygon(new int[]{x, x - 3, x + 3}, new int[]{y2 + 2, y2 + 5, y2 + 5}, 3); } private boolean isIndirectRoot(final EditorComponent editor) { final Wrappers._boolean res = new Wrappers._boolean(); ModelAccess.instance().runReadAction(new _Adapters._return_P0_E0_to_Runnable_adapter(new _FunctionTypes._return_P0_E0<Boolean>() { public Boolean invoke() { return res.value = !(isDirectCell(getCell(editor))) && check_myu41h_a0a0a0a0a0b0w(getNode(), ChangeEditorMessage.this) == null && !(editor instanceof InspectorEditorComponent); } })); return res.value; } private Rectangle getFirstPseudoLineBounds(EditorComponent editor) { Iterable<EditorCell> leafCells = new _FunctionTypes._return_P1_E0<Iterable<EditorCell>, EditorCell>() { public Iterable<EditorCell> invoke(final EditorCell cell) { return new Iterable<EditorCell>() { public Iterator<EditorCell> iterator() { return new YieldingIterator<EditorCell>() { private int __CP__ = 0; protected boolean moveToNext() { __loop__: do { __switch__: switch (this.__CP__) { case -1: assert false : "Internal error"; return false; case 4: this._4_child_it = Sequence.fromIterable((EditorCell_Collection) cell).iterator(); case 5: if (!(this._4_child_it.hasNext())) { this.__CP__ = 1; break; } this._4_child = this._4_child_it.next(); this.__CP__ = 6; break; case 7: this._7__yield_myu41h_a0a0a0a0a0a32_it = Sequence.fromIterable(invoke(_4_child)).iterator(); case 8: if (!(this._7__yield_myu41h_a0a0a0a0a0a32_it.hasNext())) { this.__CP__ = 5; break; } this._7__yield_myu41h_a0a0a0a0a0a32 = this._7__yield_myu41h_a0a0a0a0a0a32_it.next(); this.__CP__ = 9; break; case 2: if (cell instanceof EditorCell_Collection) { this.__CP__ = 3; break; } this.__CP__ = 11; break; case 10: this.__CP__ = 8; this.yield(_7__yield_myu41h_a0a0a0a0a0a32); return true; case 12: this.__CP__ = 1; this.yield(cell); return true; case 0: this.__CP__ = 2; break; case 3: this.__CP__ = 4; break; case 6: this.__CP__ = 7; break; case 9: this.__CP__ = 10; break; case 11: this.__CP__ = 12; break; default: break __loop__; } } while (true); return false; } private EditorCell _4_child; private Iterator<EditorCell> _4_child_it; private EditorCell _7__yield_myu41h_a0a0a0a0a0a32; private Iterator<EditorCell> _7__yield_myu41h_a0a0a0a0a0a32_it; }; } }; } }.invoke(editor.getRootCell()); if (Sequence.fromIterable(leafCells).first() == null) { return new Rectangle(); } final int firstCellY = Sequence.fromIterable(leafCells).first().getY(); return GeometryUtil.getBounds(Sequence.fromIterable(leafCells).where(new IWhereFilter<EditorCell>() { public boolean accept(EditorCell it) { return it.getY() == firstCellY; } }).toGenericArray(EditorCell.class)); } public Bounds getBounds(final EditorComponent editor) { if (myMessageTarget.getTarget() != MessageTargetEnum.DELETED_CHILD) { if (isIndirectRoot(editor)) { Rectangle r = getFirstPseudoLineBounds(editor); return new Bounds(r.y, r.y + r.height); } else { return getBoundsSuper(editor); } } else { DeletedNodeMessageTarget cmt = ((DeletedNodeMessageTarget) myMessageTarget); EditorCell cell = ModelAccess.instance().runReadAction(new Computable<EditorCell>() { public EditorCell compute() { return getCell(editor); } }); if (cell == null) { return new Bounds(-1, -1); } if (cmt.getRole().equals(cell.getRole())) { if (hasChildrenWithDifferentNode(cell)) { return getBoundsForChild((EditorCell_Collection) cell, cmt.getNextChildIndex()); } else { return getBoundsSuper(editor); } } else { int y = cell.getY(); return new Bounds(y, y + 1); } } } private Bounds getBoundsForChild(EditorCell_Collection cell, int index) { EditorCell childCell = getChildCell(cell, index); int minY; int maxY; if (childCell == null) { EditorCell lastCell = cell.lastCell(); minY = (isVertical(cell) ? lastCell.getBottom() : lastCell.getY()); maxY = Math.max(lastCell.getBottom(), minY + 1); } else { minY = childCell.getY(); maxY = (isVertical(cell) ? minY + 1 : childCell.getBottom()); } return new Bounds(minY, maxY); } private Bounds getBoundsSuper(EditorComponent component) { return new Bounds(super.getStart(component), super.getStart(component) + super.getHeight(component)); } @Override public int getStart(jetbrains.mps.openapi.editor.EditorComponent component) { return (int) getBounds(((EditorComponent) component)).start(); } @Override public int getHeight(jetbrains.mps.openapi.editor.EditorComponent component) { return getBounds(((EditorComponent) component)).length(); } public void setHighlighted(boolean highlighted) { myHighlighted = highlighted; } private static boolean hasChildrenWithDifferentNode(EditorCell cell) { if (cell instanceof EditorCell_Collection) { final EditorCell_Collection collectionCell = (EditorCell_Collection) cell; return Sequence.fromIterable(((Iterable<EditorCell>) collectionCell)).any(new IWhereFilter<EditorCell>() { public boolean accept(EditorCell child) { return child.getSNode() != collectionCell.getSNode(); } }); } else { return false; } } private static boolean isVertical(EditorCell cell) { return cell instanceof EditorCell_Collection && (((EditorCell_Collection) cell).getCellLayout() instanceof CellLayout_Vertical || cell.getStyle().get(StyleAttributes.INDENT_LAYOUT_CHILDREN_NEWLINE)); } private static EditorCell getChildCell(@NotNull EditorCell_Collection collectionCell, int nodeIndex) { if (nodeIndex == -1) { return null; } int currentNodeIndex = -1; for (EditorCell childCell : collectionCell) { if (childCell.getSNode() != collectionCell.getSNode()) { currentNodeIndex++; } if (currentNodeIndex == nodeIndex) { return childCell; } } if (currentNodeIndex == nodeIndex - 1) { return null; } if (LOG.isEnabledFor(Level.WARN)) { LOG.warn("Could not find child cell index for deleted child: currentNodeIndex=" + currentNodeIndex + ", total cells=" + collectionCell.getCellsCount() + ", requested nodeIndex=" + nodeIndex); } return null; } public interface ConflictChecker { boolean isChangeConflicted(ModelChange change); } private static ModelAccessor check_myu41h_a0a0a71(EditorCell_Property checkedDotOperand) { if (null != checkedDotOperand) { return checkedDotOperand.getModelAccessor(); } return null; } private static SNode check_myu41h_a0a1a71(PropertyAccessor checkedDotOperand) { if (null != checkedDotOperand) { return checkedDotOperand.getNode(); } return null; } private static String check_myu41h_a0a0b0r(PropertyAccessor checkedDotOperand) { if (null != checkedDotOperand) { return checkedDotOperand.getPropertyName(); } return null; } private static SNode check_myu41h_a0a0a0a0a0b0w(SNode checkedDotOperand, ChangeEditorMessage checkedDotThisExpression) { if (null != checkedDotOperand) { return checkedDotOperand.getParent(); } return null; } private static <T> T as_myu41h_a0a0a81(Object o, Class<T> type) { return (type.isInstance(o) ? (T) o : null); } private static <T> T as_myu41h_a0a0a0a0a81(Object o, Class<T> type) { return (type.isInstance(o) ? (T) o : null); } }