/*
* Copyright 2003-2011 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 jetbrains.mps.nodeEditor.cellActions;
import jetbrains.mps.baseLanguage.tuples.runtime.MultiTuple;
import jetbrains.mps.baseLanguage.tuples.runtime.Tuples._4;
import jetbrains.mps.editor.runtime.cells.AbstractCellAction;
import jetbrains.mps.ide.datatransfer.CopyPasteUtil;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.AttributeOperations;
import jetbrains.mps.nodeEditor.EditorComponent;
import jetbrains.mps.nodeEditor.text.TextRenderUtil;
import jetbrains.mps.openapi.editor.EditorContext;
import jetbrains.mps.openapi.editor.TextBuilder;
import jetbrains.mps.openapi.editor.cells.CellTraversalUtil;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.openapi.editor.cells.EditorCell_Collection;
import jetbrains.mps.openapi.editor.selection.SelectionManager;
import jetbrains.mps.util.SNodeOperations;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.util.Condition;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Author: Sergey Dmitriev.
* Time: Nov 26, 2003 2:06:41 PM
*/
public class CellAction_CopyNode extends AbstractCellAction {
private static final Logger LOG = LogManager.getLogger(CellAction_CopyNode.class);
@Override
public boolean canExecute(EditorContext context) {
return context.getEditorComponent().getSelectionManager().getSelection() != null;
}
@Override
public void execute(EditorContext context) {
_4<List<SNode>, List<SNode>, Map<SNode, Set<SNode>>, String> tuple = extractSelection(context);
if (tuple == null) return;
CopyPasteUtil.copyNodesAndTextToClipboard(tuple._0(), tuple._2(), tuple._3());
}
/**
* Returns two collection of nodes (among other things) - nodes to copy and nodes to remove.
* These collections may differ slightly - when a Copy/Cut action is invoked on a Attribute node, its parent node (the one annotated with the attribute) must be copied,
* but only the attribute should be deleted from the source (in case of Cut).
*
* @param context The EditorContext
* @return A four-element tuple - nodes to pass through clipboard, nodes to remove from the source, map of attributes per copied node, text representation of the copied nodes
*/
protected _4<List<SNode>, List<SNode>, Map<SNode, Set<SNode>>, String> extractSelection (EditorContext context) {
EditorComponent editorComponent = (EditorComponent) context.getEditorComponent();
TextBuilder textBuilder = TextRenderUtil.getTextBuilderForSelectedCellsOfEditor(editorComponent);
SelectionManager selectionManager = editorComponent.getSelectionManager();
List<EditorCell> selectedCells = selectionManager.getSelection().getSelectedCells();
if (selectedCells.size() == 0) {
return null;
}
if (selectedCells.size() > 1) {
LOG.debug("Copy " + selectedCells.size() + " nodes : ");
for (EditorCell aCell : selectedCells) {
LOG.debug(" " + SNodeOperations.getDebugText(aCell.getSNode()));
}
} else {
LOG.debug("Copy node : " + SNodeOperations.getDebugText(selectedCells.get(0).getSNode()));
}
List<SNode> copyNodeList = new ArrayList<SNode>();
List<SNode> deleteNodeList = new ArrayList<SNode>();
Map<SNode, Set<SNode>> nodesAndAttributes = new HashMap<SNode, Set<SNode>>();
for (EditorCell selectedCell : selectedCells) {
SNode node = selectedCell.getSNode();
final SNode parent = node.getParent();
if (parent != null && AttributeOperations.isAttribute(node)) {
Condition<EditorCell> condition = new Condition<EditorCell>() {
@Override
public boolean met(EditorCell object) {
SNode selectedNode = object.getSNode();
return selectedNode != null &&
selectedNode.getParent() == parent && AttributeOperations.isAttribute(selectedNode);
}
};
//Store the attribute by default. Store the parent only of it is also part of the selection.
SNode nodeToDelete = node;
Set<SNode> selectedAttributes = new HashSet<SNode>();
selectedAttributes.add(node);
if (selectedCell instanceof EditorCell_Collection) {
for (EditorCell cell : CellTraversalUtil.iterateTree(selectedCell, selectedCell, true)) {
if (condition.met(cell)) {
selectedAttributes.add(cell.getSNode());
}
if (cell.getSNode() == parent) { //Is the parent part of the selection
nodeToDelete = parent;
}
}
}
copyNodeList.add(parent);
deleteNodeList.add(nodeToDelete);
nodesAndAttributes.put(parent, selectedAttributes);
} else {
copyNodeList.add(node);
deleteNodeList.add(node);
}
}
return new MultiTuple._4<List<SNode>, List<SNode>, Map<SNode, Set<SNode>>, String> (copyNodeList, deleteNodeList, nodesAndAttributes, textBuilder.getText());
}
}