- Add support for copy and paste.

This commit is contained in:
Paulo Gustavo Veiga 2012-07-08 18:41:35 -03:00
parent a5acdc7bb7
commit 8175eea928
25 changed files with 446 additions and 326 deletions

View File

@ -27,7 +27,7 @@ mindplot.ActionDispatcher = new Class({
throw "method must be implemented."; throw "method must be implemented.";
}, },
addTopic: function(nodeModel, parentTopicId, animated) { addTopics: function(models, parentTopicId) {
throw "method must be implemented."; throw "method must be implemented.";
}, },

View File

@ -61,7 +61,7 @@ mindplot.BrixActionDispatcher = new Class({
return mindplot.collaboration.CollaborationManager.getInstance().getCollaborativeFramework(); return mindplot.collaboration.CollaborationManager.getInstance().getCollaborativeFramework();
}, },
addTopic : function(nodeModel, parentTopicId, animated) { addTopics : function(nodeModel, parentTopicId) {
var framework = this._getFramework(); var framework = this._getFramework();
var cmindmap = framework.getModel(); var cmindmap = framework.getModel();

View File

@ -65,6 +65,7 @@ mindplot.Designer = new Class({
this.setViewPort(options.viewPort); this.setViewPort(options.viewPort);
mindplot.TopicEventDispatcher.configure(this.isReadOnly()); mindplot.TopicEventDispatcher.configure(this.isReadOnly());
this._clipboard = [];
}, },
/** /**
@ -131,7 +132,7 @@ mindplot.Designer = new Class({
var centralTopic = this.getModel().getCentralTopic(); var centralTopic = this.getModel().getCentralTopic();
var model = this._createChildModel(centralTopic, mousePos); var model = this._createChildModel(centralTopic, mousePos);
this._actionDispatcher.addTopic(model, centralTopic.getId()); this._actionDispatcher.addTopics([model], [centralTopic.getId()]);
} }
}.bind(this)); }.bind(this));
@ -347,6 +348,41 @@ mindplot.Designer = new Class({
} }
}, },
copyToClipboard:function () {
var topics = this.getModel().filterSelectedTopics();
if (topics.length <= 0) {
// If there are more than one node selected,
$notify($msg('AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED'));
return;
}
// Exclude central topic ..
topics = topics.filter(function (topic) {
return topic.getTopicType() != mindplot.model.INodeModel.CENTRAL_TOPIC_TYPE
});
this._clipboard = topics.map(function (topic) {
var nodeModel = topic.getModel().deepCopy();
// Change position to make the new topic evident...
var pos = nodeModel.getPosition();
nodeModel.setPosition(pos.x + (60 * Math.sign(pos.x)), pos.y + 30);
return nodeModel;
});
$notify($msg('SELECTION_COPIED_TO_CLIPBOARD'));
},
pasteClipboard:function () {
if (this._clipboard.length == 0) {
$notify($msg('CLIPBOARD_IS_EMPTY'));
return;
}
this._actionDispatcher.addTopics(this._clipboard);
this._clipboard = [];
},
getModel:function () { getModel:function () {
return this._model; return this._model;
}, },
@ -387,7 +423,7 @@ mindplot.Designer = new Class({
var childModel = this._createChildModel(parentTopic); var childModel = this._createChildModel(parentTopic);
// Execute event ... // Execute event ...
this._actionDispatcher.addTopic(childModel, parentTopicId, true); this._actionDispatcher.addTopics([childModel], [parentTopicId]);
}, },
@ -415,7 +451,7 @@ mindplot.Designer = new Class({
// Position far from the visual area ... // Position far from the visual area ...
model.setPosition(1000, 1000); model.setPosition(1000, 1000);
this._actionDispatcher.addTopic(model, null, false); this._actionDispatcher.addTopics([model]);
var topic = this.getModel().findTopicById(model.getId()); var topic = this.getModel().findTopicById(model.getId());
// Simulate a mouse down event to start the dragging ... // Simulate a mouse down event to start the dragging ...
@ -452,7 +488,7 @@ mindplot.Designer = new Class({
} }
var parentTopicId = parentTopic.getId(); var parentTopicId = parentTopic.getId();
this._actionDispatcher.addTopic(siblingModel, parentTopicId, true); this._actionDispatcher.addTopics([siblingModel], [parentTopicId]);
} }
}, },

View File

@ -93,6 +93,35 @@ mindplot.DesignerKeyboard = new Class({
}.bind(this), }.bind(this),
'ctrl+c':function () {
event.preventDefault(event);
event.stopPropagation();
designer.copyToClipboard();
}.bind(this),
'meta+c':function (event) {
event.preventDefault();
event.stopPropagation();
designer.copyToClipboard();
}.bind(this),
'ctrl+v':function () {
event.preventDefault(event);
event.stopPropagation();
designer.pasteClipboard();
}.bind(this),
'meta+v':function (event) {
event.preventDefault();
event.stopPropagation();
designer.pasteClipboard();
}.bind(this),
'ctrl+z+shift':function (event) { 'ctrl+z+shift':function (event) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();

View File

@ -86,8 +86,12 @@ mindplot.Messages.BUNDLES = {
CENTRAL_TOPIC:'Central Topic', CENTRAL_TOPIC:'Central Topic',
ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE:'Children can not be collapsed. One topic must be selected.', ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE:'Children can not be collapsed. One topic must be selected.',
SHORTCUTS:'Keyboard Shortcuts', SHORTCUTS:'Keyboard Shortcuts',
// @Todo: pending ...
ENTITIES_COULD_NOT_BE_DELETED:'Could not delete topic or relation. At least one map entity must be selected.', ENTITIES_COULD_NOT_BE_DELETED:'Could not delete topic or relation. At least one map entity must be selected.',
CENTRAL_TOPIC_CAN_NOT_BE_DELETED: 'Central topic can not be deleted.' CENTRAL_TOPIC_CAN_NOT_BE_DELETED:'Central topic can not be deleted.',
SELECTION_COPIED_TO_CLIPBOARD:'Topics copied to the clipboard',
CLIPBOARD_IS_EMPTY:'Nothing to copy. Clipboard is empty'
}, },
'es':{ 'es':{
DISCARD_CHANGES:'Descartar Cambios', DISCARD_CHANGES:'Descartar Cambios',

View File

@ -29,8 +29,8 @@ mindplot.StandaloneActionDispatcher = new Class({
}, },
addTopic:function (nodeModel, parentTopicId, animated) { addTopics:function (models, parentTopicsId) {
var command = new mindplot.commands.AddTopicCommand(nodeModel, parentTopicId, animated); var command = new mindplot.commands.AddTopicCommand(models, parentTopicsId);
this.execute(command); this.execute(command);
}, },

View File

@ -41,15 +41,14 @@ mindplot.TopicFeature = {
}); });
}, },
createModel : function(id, topic, attributes) { createModel : function(id, attributes) {
$assert(id, 'type can not be null'); $assert(id, 'type can not be null');
$assert(topic, 'topic can not be null');
$assert(attributes, 'attributes can not be null'); $assert(attributes, 'attributes can not be null');
var model = mindplot.TopicFeature._featuresMetadataById.filter(function(elem) { var model = mindplot.TopicFeature._featuresMetadataById.filter(function(elem) {
return elem.id == id; return elem.id == id;
})[0].model; })[0].model;
return new model(topic, attributes); return new model(attributes);
}, },
createIcon : function(topic, model) { createIcon : function(topic, model) {

View File

@ -62,7 +62,7 @@ mindplot.collaboration.framework.brix.model.NodeModel = new Class({
var model = new mindplot.model.NodeModel(cmodel.getType(), designer.getMindmap(), this.getId()); var model = new mindplot.model.NodeModel(cmodel.getType(), designer.getMindmap(), this.getId());
cmodel.copyTo(model); cmodel.copyTo(model);
actionDispatcher.addTopic(model, this.getId(), true); actionDispatcher.addTopics([model], [this.getId()]);
} }
} catch(e) { } catch(e) {
console.trace(); console.trace();

View File

@ -18,24 +18,30 @@
mindplot.commands.AddTopicCommand = new Class({ mindplot.commands.AddTopicCommand = new Class({
Extends:mindplot.Command, Extends:mindplot.Command,
initialize: function(model, parentTopicId) { initialize:function (models, parentTopicsId) {
$assert(model, 'Model can not be null'); $assert(models, 'models can not be null');
$assert(parentTopicsId == null || parentTopicsId.length == models.length, 'parents and models must have the same size');
this.parent(); this.parent();
this._model = model; this._models = models;
this._parentId = parentTopicId; this._parentsIds = parentTopicsId;
}, },
execute:function (commandContext) { execute:function (commandContext) {
this._models.forEach(function (model, index) {
// Add a new topic ... // Add a new topic ...
var topic = commandContext.createTopic(this._model, false); var topic = commandContext.createTopic(model, false);
// Connect to topic ... // Connect to topic ...
if ($defined(this._parentId)) { if (this._parentsIds) {
var parentTopic = commandContext.findTopics(this._parentId)[0]; var parentId = this._parentsIds[index];
if ($defined(parentId)) {
var parentTopic = commandContext.findTopics(parentId)[0];
commandContext.connect(topic, parentTopic); commandContext.connect(topic, parentTopic);
} }
}
// Finally, focus ... // Finally, focus ...
var designer = commandContext._designer; var designer = commandContext._designer;
@ -45,12 +51,16 @@ mindplot.commands.AddTopicCommand = new Class({
topic.setOnFocus(true); topic.setOnFocus(true);
}); });
fade.start(); fade.start();
}.bind(this));
}, },
undoExecute:function (commandContext) { undoExecute:function (commandContext) {
// Finally, delete the topic from the workspace ... // Finally, delete the topic from the workspace ...
var topicId = this._model.getId(); this._models.forEach(function (model) {
var topicId = model.getId();
var topic = commandContext.findTopics(topicId)[0]; var topic = commandContext.findTopics(topicId)[0];
commandContext.deleteTopic(topic); commandContext.deleteTopic(topic);
}.bind(this));
} }
}); });

View File

@ -17,13 +17,11 @@
*/ */
mindplot.model.FeatureModel = new Class({ mindplot.model.FeatureModel = new Class({
initialize:function(type, topic) { initialize:function(type) {
$assert(type, 'type can not be null'); $assert(type, 'type can not be null');
$assert(topic, 'topic can not be null');
this._id = mindplot.model.FeatureModel._nextUUID(); this._id = mindplot.model.FeatureModel._nextUUID();
this._type = type; this._type = type;
this._topic = topic;
this._attributes = {}; this._attributes = {};
// Create type method ... // Create type method ...
@ -53,10 +51,6 @@ mindplot.model.FeatureModel = new Class({
return this._attributes[key]; return this._attributes[key];
}, },
getTopic : function() {
return this._topic;
},
getId : function() { getId : function() {
return this._id; return this._id;
}, },

View File

@ -56,7 +56,7 @@ mindplot.model.INodeModel = new Class({
setPosition : function(x, y) { setPosition : function(x, y) {
$assert(!isNaN(parseInt(x)), "x position is not valid:" + x); $assert(!isNaN(parseInt(x)), "x position is not valid:" + x);
$assert(!isNaN(parseInt(y)), "x position is not valid:" + y); $assert(!isNaN(parseInt(y)), "y position is not valid:" + y);
this.putProperty('position', '{x:' + parseInt(x) + ',y:' + parseInt(y) + '}'); this.putProperty('position', '{x:' + parseInt(x) + ',y:' + parseInt(y) + '}');
}, },

View File

@ -18,8 +18,8 @@
mindplot.model.IconModel = new Class({ mindplot.model.IconModel = new Class({
Extends: mindplot.model.FeatureModel, Extends: mindplot.model.FeatureModel,
initialize:function(topic, attributes) { initialize:function(attributes) {
this.parent(mindplot.model.IconModel.FEATURE_TYPE, topic); this.parent(mindplot.model.IconModel.FEATURE_TYPE);
this.setIconType(attributes.id); this.setIconType(attributes.id);
}, },

View File

@ -18,8 +18,8 @@
mindplot.model.LinkModel = new Class({ mindplot.model.LinkModel = new Class({
Extends: mindplot.model.FeatureModel, Extends: mindplot.model.FeatureModel,
initialize : function(topic, attributes) { initialize : function(attributes) {
this.parent(mindplot.model.LinkModel.FEATURE_TYPE, topic); this.parent(mindplot.model.LinkModel.FEATURE_TYPE);
this.setUrl(attributes.url); this.setUrl(attributes.url);
}, },

View File

@ -33,7 +33,7 @@ mindplot.model.NodeModel = new Class({
}, },
createFeature:function (type, attributes) { createFeature:function (type, attributes) {
return mindplot.TopicFeature.createModel(type, this, attributes); return mindplot.TopicFeature.createModel(type, attributes);
}, },
addFeature:function (feature) { addFeature:function (feature) {
@ -97,6 +97,26 @@ mindplot.model.NodeModel = new Class({
return result; return result;
}, },
/**
* Similar to clone, assign new id to the elements ...
* @return {mindplot.model.NodeModel}
*/
deepCopy:function () {
var result = new mindplot.model.NodeModel(this.getType(), this._mindmap);
result._children = this._children.map(function (node) {
var cnode = node.deepCopy();
cnode._parent = result;
return cnode;
});
var id = result.getId();
result._properties = Object.clone(this._properties);
result.setId(id);
result._feature = this._feature.clone();
return result;
},
appendChild:function (child) { appendChild:function (child) {
$assert(child && child.isNodeModel(), 'Only NodeModel can be appended to Mindmap object'); $assert(child && child.isNodeModel(), 'Only NodeModel can be appended to Mindmap object');
this._children.push(child); this._children.push(child);

View File

@ -18,8 +18,8 @@
mindplot.model.NoteModel = new Class({ mindplot.model.NoteModel = new Class({
Extends: mindplot.model.FeatureModel, Extends: mindplot.model.FeatureModel,
initialize : function(topic, attributes) { initialize : function(attributes) {
this.parent(mindplot.model.NoteModel.FEATURE_TYPE, topic); this.parent(mindplot.model.NoteModel.FEATURE_TYPE);
this.setText(attributes.text); this.setText(attributes.text);
}, },

View File

@ -351,7 +351,7 @@ mindplot.persistence.XMLSerializer_Pela = new Class({
// Create a new element .... // Create a new element ....
var featureType = child.tagName; var featureType = child.tagName;
var feature = mindplot.TopicFeature.createModel(featureType, topic, attributes); var feature = mindplot.TopicFeature.createModel(featureType, attributes);
topic.addFeature(feature); topic.addFeature(feature);
} else if (child.tagName == "text") { } else if (child.tagName == "text") {

View File

@ -251,10 +251,10 @@ mindplot.widget.Menu = new Class({
this._registerTooltip('redoEdition', $msg('REDO'), "meta+shift+Z"); this._registerTooltip('redoEdition', $msg('REDO'), "meta+shift+Z");
this._addButton('addTopic', true, false, function () { this._addButton('addTopics', true, false, function () {
designer.createChildForSelectedNode(); designer.createChildForSelectedNode();
}); });
this._registerTooltip('addTopic', $msg('ADD_TOPIC'), "Enter"); this._registerTooltip('addTopics', $msg('ADD_TOPIC'), "Enter");
this._addButton('deleteTopic', true, true, function () { this._addButton('deleteTopic', true, true, function () {

View File

@ -43,5 +43,10 @@ SUB_TOPIC=Sub Topic
ISOLATED_TOPIC=Isolated Topic ISOLATED_TOPIC=Isolated Topic
CENTRAL_TOPIC=Central Topic CENTRAL_TOPIC=Central Topic
SHORTCUTS=Keyboard Shortcuts SHORTCUTS=Keyboard Shortcuts
ENTITIES_COULD_NOT_BE_DELETED=Could not delete topic or relation. At least one map entity must be selected. ENTITIES_COULD_NOT_BE_DELETED=Could not delete topic or relation. At least one map entity must be selected.
AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED=At least one topic must be selected.
CLIPBOARD_IS_EMPTY=Nothing to copy. Clipboard is empty.
CENTRAL_TOPIC_CAN_NOT_BE_DELETED=Central topic can not be deleted. CENTRAL_TOPIC_CAN_NOT_BE_DELETED=Central topic can not be deleted.
MULTIPLE_LINES=Add multiple text lines.
COPY_AND_PASTE_TOPICS=Copy and Paste Topics

View File

@ -44,3 +44,5 @@ ISOLATED_TOPIC=Tópico Aislado
CENTRAL_TOPIC=Tópico Central CENTRAL_TOPIC=Tópico Central
ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE=Tópicos hijos no pueden ser colapsados. Solo un topic debe ser seleccionado. ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE=Tópicos hijos no pueden ser colapsados. Solo un topic debe ser seleccionado.
SHORTCUTS=Accesos directos SHORTCUTS=Accesos directos
MULTIPLE_LINES=Add multilines text node
COPY_AND_PASTE_TOPICS=Copy Topics

View File

@ -43,3 +43,5 @@ SUB_TOPIC=子节点
ISOLATED_TOPIC=独立节点 ISOLATED_TOPIC=独立节点
CENTRAL_TOPIC=中心节点 CENTRAL_TOPIC=中心节点
SHORTCUTS=快捷键 SHORTCUTS=快捷键
MULTIPLE_LINES=Add multilines text node
COPY_AND_PASTE_TOPICS=Copy Topics

View File

@ -43,3 +43,5 @@ SUB_TOPIC=子節點
ISOLATED_TOPIC=獨立節點 ISOLATED_TOPIC=獨立節點
CENTRAL_TOPIC=中心節點 CENTRAL_TOPIC=中心節點
SHORTCUTS=快捷鍵 SHORTCUTS=快捷鍵
MULTIPLE_LINES=Add multilines text node
COPY_AND_PASTE_TOPICS=Copy Topics

View File

@ -1,46 +1,52 @@
<map name="3" version="pela"> <map name="welcome" version="tango">
<topic central="true" text="Welcome To WiseMapping" id="1" fontStyle=";;#dfcfe6;;;" bgColor="#0a0a08"> <topic central="true" text="Welcome To WiseMapping" id="1" fontStyle=";;#dfcfe6;;;" bgColor="#0a0a08">
<topic position="-326,50" order="2" text="Productivity" id="2" fontStyle=";;#104f11;;;" bgColor="#d9b518"> <topic position="178,-130" order="0" text="Try it Now!" id="11" fontStyle=";;#ffffff;;;" bgColor="#250be3"
brColor="#080559">
<topic position="272,-156" order="0" text="Double Click" id="12" fontStyle=";;#001be6;;italic;"/>
<topic position="274,-130" order="1" text=" INS to insert" id="13" fontStyle=";;#001be6;;italic;"/>
<topic position="285,-104" order="2" text="Drag map to move" id="14" fontStyle=";;#001be6;;italic;"/>
</topic>
<topic position="-189,-52" order="1" text="Productivity" id="2" fontStyle=";;#104f11;;;" bgColor="#d9b518">
<icon id="chart_bar"/> <icon id="chart_bar"/>
<topic position="-443,17" order="0" text="Share your ideas" id="3"> <topic position="-310,-78" order="0" text="Share your ideas" id="3">
<icon id="bulb_light_on"/> <icon id="bulb_light_on"/>
</topic> </topic>
<topic position="-429,41" order="1" text="Brainstorming" id="4"/> <topic position="-299,-52" order="1" text="Brainstorming" id="4"/>
<topic position="-413,65" order="2" text="Visual " id="5"/> <topic position="-283,-26" order="2" text="Visual " id="5"/>
</topic> </topic>
<topic position="257,150" order="6" text="Features" id="15"> <topic position="185,-39" order="2" text="Mind Mapping" id="6" fontStyle=";;#602378;;;" bgColor="#edabff">
<topic position="350,81" order="0" text="Links to Sites" id="16" fontStyle=";6;;;;"> <topic position="303,-78" order="0" text="Share with Collegues" id="7"/>
<link url="www.digg.com"/> <topic position="275,-52" order="1" text="Online" id="8"/>
<topic position="299,-26" order="2" text="Anyplace, Anytime" id="9"/>
<topic position="277,0" order="3" text="Free!!!" id="10"/>
</topic> </topic>
<topic position="328,105" order="1" text="Fonts" id="17"/> <topic position="-183,39" order="3" text="Web 2.0 Tool" id="22" fontStyle=";;#0c1d6b;;;" bgColor="#add1f7">
<topic position="339,129" order="2" text="Topic Color" id="18"/> <topic position="-281,0" order="0" text="Collaborate" id="23"/>
<topic position="343,153" order="3" text="Topic Shapes" shape="line" id="19"/> <topic position="-302,26" order="1" text="No plugin required" id="24">
<topic position="334,177" order="4" text="Icons" id="20"> <icon id="conn_disconnect"/>
</topic>
<topic position="-271,52" order="2" text="Share" id="25"/>
<topic position="-282,78" order="3" text="Easy to use" id="26"/>
</topic>
<topic position="171,91" order="4" text="Features" id="15">
<topic position="266,26" order="0" text="Links to Sites" id="16" fontStyle=";6;;;;">
<link url="http://www.digg.com" type="url"/>
</topic>
<topic position="245,52" order="1" text="Fonts" id="17"/>
<topic position="255,78" order="2" text="Topic Color" id="18"/>
<topic position="260,104" order="3" text="Topic Shapes" shape="line" id="19"/>
<topic position="252,130" order="4" text="Icons" id="20">
<icon id="object_rainbow"/> <icon id="object_rainbow"/>
</topic> </topic>
<topic position="357,201" order="5" text="History Changes" id="21"> <topic position="272,156" order="5" text="History Changes" id="21">
<icon id="arrowc_turn_left"/> <icon id="arrowc_turn_left"/>
</topic> </topic>
</topic> </topic>
<topic position="-336,-100" order="3" text="Web 2.0 Tool" id="22" fontStyle=";;#0c1d6b;;;" bgColor="#add1f7">
<topic position="-433,-145" order="0" text="Collaborate" id="23"/>
<topic position="-453,-121" order="1" text="No plugin required" id="24">
<icon id="conn_disconnect"/>
</topic>
<topic position="-420,-97" order="2" text="Share" id="25"/>
<topic position="-432,-73" order="3" text="Easy to use" id="26"/>
</topic>
<topic position="266,0" order="0" text="Try it Now!" id="11" fontStyle=";;#ffffff;;;" bgColor="#250be3"
brColor="#080559">
<topic position="358,-33" order="0" text="Double Click" id="12" fontStyle=";;#001be6;;italic;"/>
<topic position="362,-9" order="1" text=" INS to insert" id="13" fontStyle=";;#001be6;;italic;"/>
<topic position="371,15" order="2" text="Drag map to move" id="14" fontStyle=";;#001be6;;italic;"/>
</topic>
<topic position="299,-100" order="3" text="Mind Mapping" id="6" fontStyle=";;#602378;;;" bgColor="#edabff">
<topic position="415,-145" order="0" text="Share with Collegues" id="7"/>
<topic position="385,-121" order="1" text="Online" id="8"/>
<topic position="410,-97" order="2" text="Anyplace, Anytime" id="9"/>
<topic position="386,-73" order="3" text="Free!!!" id="10"/>
</topic>
</topic> </topic>
<relationship srcTopicId="1" destTopicId="3" lineType="3" endArrow="true" startArrow="false"/>
<relationship srcTopicId="3" destTopicId="1" lineType="3" srcCtrlPoint="-10,-37" destCtrlPoint="-212,-107"
endArrow="true" startArrow="false"/>
<relationship srcTopicId="6" destTopicId="14" lineType="3" endArrow="true" startArrow="false"/>
<relationship srcTopicId="12" destTopicId="18" lineType="3" srcCtrlPoint="184,86" destCtrlPoint="166,2"
endArrow="true" startArrow="false"/>
</map> </map>

View File

@ -66,6 +66,17 @@
<td><spring:message code="JUST_START_TYPING"/> | F2</td> <td><spring:message code="JUST_START_TYPING"/> | F2</td>
<td><spring:message code="JUST_START_TYPING"/> | F2</td> <td><spring:message code="JUST_START_TYPING"/> | F2</td>
</tr> </tr>
<tr>
<td><spring:message code="MULTIPLE_LINES"/></td>
<td>Ctrl + Enter</td>
<td>⌘ + Enter</td>
</tr>
<tr>
<td><spring:message code="COPY_AND_PASTE_TOPICS"/></td>
<td>Ctrl + c/Ctrl + v</td>
<td>⌘ + c/⌘ + c</td>
</tr>
<tr> <tr>
<td><spring:message code="COLLAPSE_CHILDREN"/></td> <td><spring:message code="COLLAPSE_CHILDREN"/></td>
<td>Space bar</td> <td>Space bar</td>