Scripts collection
The first version of the article mainly consists/consisted of a port of the FreeMind script collection. Some of those scripts got a general rewrite; - escpecially those that were marked buggy or even broken. But I took the freedom to (hopefully) improve every script were it made sense. With one exception ("Sum up all subnodes...", a very long script) I have ported all scripts from the FreeMind page, no matter how useful I found them since I believe that you will be able to learn from all of them.
Unfortunately I do not know some authors of the scripts, so I can't give them proper reference. Please help identify them.
-Volker
Feel free to add your own scripts to this page. For larger scripts there is a special Bazaar repository. Inspect it at contrib/groovy or get it via
bzr branch bzr://freeplane.bzr.sourceforge.net/bzrroot/freeplane/contrib/groovy [read only] bzr+ssh://USERNAME@freeplane.bzr.sourceforge.net/bzrroot/freeplane/contrib/groovy/ [developers only]
Contents
- 1 A node with the last modification date of the map
- 2 Prepend the modified date at the beginning of the node text
- 3 Add up attribute values of subnodes.
- 4 Set the color for all children
- 5 Sort child nodes alphabetically or by length
- 6 Set up a logger
- 7 Export to BibTeX
- 8 Sum up all subnodes recursively for attributes
- 9 Output A Map to CSV
- 10 Output A Map to CSV Part 2
- 11 Daves massivly cheezy Api Generator
- 12 Simple bookmark implementation using scripts
A node with the last modification date of the map
This script sets the text of the selected node to the last modification timestamp of the whole map, not counting selected node. (So that executing the script multiple times will not change the text.)
<groovy> // @ExecutionModes({ON_SELECTED_NODE}) import java.text.SimpleDateFormat; import java.util.Date; import org.freeplane.plugin.script.proxy.NodeProxy;
// node.lastModifiedAt requires Freeplane 1.0.40 or later def getLastModifiedAt(NodeProxy node, List nodeIdsToOmit) {
return nodeIdsToOmit.contains(node.nodeID) ? new Date(0) : node.lastModifiedAt
}
def getLastModifiedAtRecursive(NodeProxy node, List nodeIdsToOmit) {
thisLastModifiedAt = getLastModifiedAt(node, nodeIdsToOmit) if (node.children.isEmpty()) return thisLastModifiedAt lastModifiedAt = node.children.collect{getLastModifiedAtRecursive(it, nodeIdsToOmit)}.max() return thisLastModifiedAt.after(lastModifiedAt) ? thisLastModifiedAt : lastModifiedAt;
}
// exclude all selected (timestamp) nodes from the search since their // modification should not count // note: before Freeplane 1.0.39 it has to be node.rootNode instead of node.map.rootNode lastModifiedAt = getLastModifiedAtRecursive(node.map.rootNode, c.selecteds.collect{it.nodeID}) f = new java.text.SimpleDateFormat("yyyy-MM-dd hh-mm-ss") node.setText("The map was last modified at: " + f.format(lastModifiedAt)); </groovy>
Author: User:Boercher
Prepend the modified date at the beginning of the node text
This is a port of the respective script on the FreemindPage. Note that node.lastModifiedAt requires Freeplane 1.0.40 or later
<groovy> =new java.text.SimpleDateFormat("M/d/yyyy").format(node.lastModifiedAt) +
" " + node.text
// @ExecutionModes({ON_SELECTED_NODE}) </groovy>
Add up attribute values of subnodes.
This script adds up the "AMOUNT" attributes of all child nodes of a node and sets the "AMOUNT" attribute of the selected node to the sum.
<groovy> import java.text.NumberFormat;
attrib = "AMOUNT"
def get(node) {
text = node.getAttributes().get(attrib) if (text != null && text.isDouble()) return text.toDouble() return 0
} node.getAttributes().set(attrib, NumberFormat.getInstance().format(node.children.sum{get(it)})) // @ExecutionModes({ON_SELECTED_NODE}) </groovy>
The following script does the same, but recursively, i.e. called for the root node it updates the complete map so that each parent node has the "AMOUNT" attribute set to the sum of all children, grandchildren and so on.
<groovy> import java.text.NumberFormat;
attrib = "AMOUNT"
def get(node) {
text = node.getAttributes().get(attrib) if (text != null && text.isDouble()) return text.toDouble() return 0
}
def set(node, amount) {
node.getAttributes().set(attrib, NumberFormat.getInstance().format(amount))
}
def setAndReturnSum(node) {
if (node.isLeaf()) { return get(node) } else { total = node.children.sum{ setAndReturnSum(it) } set(node, total) return total }
}
setAndReturnSum(node) // @ExecutionModes({ON_SELECTED_NODE}) </groovy>
Author: User:yubrshen, general rewrite by User:Boercher for Freeplane
Set the color for all children
This is an example of iteration over child nodes.
<groovy> node.children.each{ it.style.nodeTextColor = java.awt.Color.BLUE } // @ExecutionModes({ON_SELECTED_NODE, ON_SELECTED_NODE_RECURSIVELY}) </groovy>
Sort child nodes alphabetically or by length
<groovy> sorted = new java.util.ArrayList(node.children).sort{ it.text } i = 0 sorted.each {
it.moveTo(node, i++)
} // @ExecutionModes({ON_SELECTED_NODE, ON_SELECTED_NODE_RECURSIVELY}) </groovy>
To sort by length: Change "it.text" to "it.text.length()".
To reverse either of these sorts: Add a minus sign before "it", i.e. "-it.text.length()".
Author: User:Boercher
Set up a logger
The following code makes use of the application logger, provided by LogTool.
<groovy> import org.freeplane.core.util.LogTool; LogTool.info(" ******* Logger set up for script"); </groovy>
Export to BibTeX
A working script for creating BibTeX files from a special formatted mindmap. A BibTeX node has an attribute "bibtex" with the kind of article as value (e.g. "article", "note"). Bibtex entry properties are given as attributes as well. Unfortunately it's currently not possible to write the attribute names other than in lower case.
The resulting BibTeX file is shown in a popup window that supports scrolling and cut 'n paste.
<groovy> import javax.swing.*; import org.freeplane.core.ui.components.UITools;
// for cut 'n paste: def showDialog(String text) {
dialog = new JDialog(UITools.getFrame()) dialog.setSize(350, 450) dialog.setLocationRelativeTo(UITools.getFrame()) dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE) dialog.add(new JScrollPane(new JTextArea(text))) UITools.addEscapeActionToDialog(dialog) dialog.setVisible(true)
}
all_tags = ['address', 'author', 'booktitle', 'chapter', 'edition', 'editor',
'howpublished', 'institution', 'isbn', 'journal', 'month', 'note', 'number', 'organization', 'pages', 'publisher', 'school', 'series', 'title', 'type', 'volume', 'year']
def processAttribute(attr, attr_name) {
return (attr.findAttribute(attr_name) != -1) ? attr_name + " = \"" + attr.get(attr_name) + "\"" : null
}
def process(type, attr, index) {
// note: there's no getAttributeNames() yet so // - we can not iterate over *existing* attributes // - we can not match case insensitive // -> should be fixed ASAP tags = all_tags.collect { processAttribute(attr, it) } // compact: erase nulls return "@" + type + "{${index.toString()}, \n " + tags.grep { !it.is(null) }.join(",\n ") + '\n}\n\n'
}
def getChildrenRecursive(node) {
if (node.isLeaf()) { return [node]; } else { // father and sons return [node] + node.children.collect{ getChildrenRecursive(it) }.flatten(); }
}
index = 1; // merge everything into one string result = getChildrenRecursive(node).sum {
attr = it.attributes; // valid values would be: article, book, booklet, conference, inbook, // incollection, inproceedings, manual, mastersthesis, misc, phdthesis, // proceedings, techreport, unpublished if (attr.get('bibtex')) return process(attr.get('bibtex'), attr, index++); else return ;
}; showDialog(result) </groovy>
Author: User:Leonardo, general rewrite for Freeplane by User:Boercher
Use the following script to create a map for testing purposes. It adds some "BibTeX nodes" to selected nodes:
<groovy>
i = 1
def makeBibEntry(node, type, tags) {
child = node.createChild() child.attributes.set('bibtex', type); tags.each { child.attributes.set(it, it + "_" + i++) }
}
makeBibEntry(node, 'article', ['author', 'title', 'journal', 'year', 'url']) makeBibEntry(node, 'techreport', ['author', 'title', 'institution', 'year']) makeBibEntry(node, 'misc', ['author', 'url']) makeBibEntry(node, 'proceedings', ['author', 'title', 'year', 'url']) </groovy>
Sum up all subnodes recursively for attributes
Did not try to port this script due to its length. Tell me if you would like to see it here.
Output A Map to CSV
For export to a spreadsheet for inclusion in a larger project plan. The following script creates CSV output from a mindmap and shows it in a dialog window for cut 'n paste. <groovy> import javax.swing.*; import org.freeplane.core.ui.components.UITools;
// for cut 'n paste: def showDialog(String text) {
dialog = new JDialog(UITools.getFrame()) dialog.setSize(350, 450) dialog.setLocationRelativeTo(UITools.getFrame()) dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE) dialog.add(new JScrollPane(new JTextArea(text))) UITools.addEscapeActionToDialog(dialog) dialog.setVisible(true)
}
def process(thisNode, childPosition) {
result = childPosition, thisNode.text thisNode.children.each { result += process(it, childPosition + 1) } return result
}
result = process(node, 0); showDialog(result.collect{ "," * it[0] + it[1] }.join("\n")) </groovy>
Author: User:Boercher
Output A Map to CSV Part 2
The second iteration of the estimate to CSV script allows different item types to be denoted by icons (here the number icons ("1", "2", ...) which then get mapped to attribute values. That way I can do things like estimate the complexity of a task by adding a number icon and then have that mapped to text like "Very Complex" in my CSV file. Here is the code:
<groovy> import org.freeplane.core.util.HtmlTools
class TreeWalker {
def rootNode; def minFontSize; private iconMappings = [:] private attributeMappings = [:] private attributeNames = []
def visit(thisNode, childPosition) { def attributes = [:] def nodeName = HtmlTools.htmlToPlain(thisNode.getPlainTextContent()) def nodeLevel = thisNode.getNodeLevel(true) thisNode.icons.icons.each { iconName -> if (iconMappings[iconName]) { def attributeName = iconMappings[iconName] def attributeValue = attributeMappings[attributeName][iconName] attributes[attributeName] = attributeValue } } def attributeString = "" attributeNames.each { attributeString += ",${attributes[it]?attributes[it]:}" } def nodeType = "" if (new Integer(thisNode.style.font.size) < minFontSize) { nodeType = "Note" } else { if (attributes.Complexity) { nodeType = "Widget" } else { nodeType = "Heading" } }
println "$nodeType,$nodeLevel,$childPosition$attributeString,\"$nodeName\"" def i = 0 if (thisNode.children) { thisNode.children.each { i++ visit(it, i) } } }
def walk() { visit(rootNode, 0) }
/** * Add a set of mappings from icon names to values for a given attribute */ def addAttributeMapping(attributeName, mappings) { attributeMappings[attributeName] = mappings; mappings.each { iconMappings[it.key] = attributeName; } attributeNames << attributeName; }
}
def walker = new TreeWalker(rootNode:node, minFontSize:12); walker.addAttributeMapping("Complexity",
[ "full-1":"Very Simple", "full-2":"Simple", "full-3":"Medium", "full-4":"Complex", "full-5":"Very Complex", "full-6":"Extremely Complex"]);
walker.addAttributeMapping("Type",
[ "connect":"Interface", "page_white_cup":"Java Code", "html":"Screen", "report":"Report", "page_white_text":"Document", "cog":"Configuration/Infrastructure Setup"]);
walker.walk(); </groovy>
Author: User:Yellek, prepared for Freeplane by User:Boercher
Daves massivly cheezy Api Generator
If you are lazy (like me) and dont wan't to look through the source code to find the api for the node and c variables, use this to make a somewhat cheezy mindmap/api
<groovy> def lastSection(Str){
String[] p; p = Str.split("\\."); return p[p.size()-1];
}
def newChildNode(node, method){
apiNode = node.createChild(0); returnType = apiNode.createChild(0); iProto = apiNode.createChild(1);
def text = method.toString(); String[] parts; parts = text.split(" ");
StringBuilder sb = new StringBuilder(); sb.append(parts[0]); sb.append(" ");
sb.append(lastSection(parts[1]));
returnType.setText(parts[1]);
sb.append(" "); sb.append(method.getName()); sb.append("(");
def Class[] parms; parms = method.getParameterTypes(); protoTxt = new StringBuffer(); if(parms.size() >0){ for(i in 0..parms.size()-1){ protoTxt.append(parms[i].toString()); sb.append(lastSection(parms[i].toString())); if(i<parms.size()-1){ protoTxt.append("\n"); sb.append(","); } } } else{ protoTxt.append("*none*"); } sb.append(")"); apiNode.setText(sb.toString()); apiNode.setFolded(true); iProto.setText(protoTxt.toString());
}
def makeApi(node, object) {
node = node.createChild() node.text = object.class.name methods = object.getClass().getMethods() for(i in 0..<methods.size()){ newChildNode(node, methods[i]); }
}
makeApi(node, node) makeApi(node, c) </groovy>
Author: User:Dke211 (Dave), prepared for Freeplane by User:Boercher
Simple bookmark implementation using scripts
This is a rudimentary implementation of a bookmark. If set up as described below you can use a self chosen key combination to memorize the currently selected node and return to it at any later time using another key combination.
Step 1: put these two scripts in your ~/.freeplane/scripts directory (or whereever you tell freeplane to look for groovy scripts)
setBookmark.groovy <groovy> // @CacheScriptContent(true) def root=node.getMap().getRootNode()
if((dummyList = c.find{ it.text.equals("Bookmark")}).isEmpty()) { (bookmarkNode = root.createChild()).setText("Bookmark") } else { bookmarkNode=dummyList.get(0) }
selectedID=c.getSelected().getNodeID()
bookmarkNode.getLink().set("#"+selectedID) </groovy>
gotoBookmark.groovy <groovy> // @CacheScriptContent(true) def root=node.getMap().getRootNode()
if(!(dummyList = c.find{ it.text.equals("Bookmark") }).isEmpty()) { bookmarkNode=dummyList.get(0) c.select(node.getMap().node(bookmarkNode.getLink().get().substring(1))) } </groovy>
Step 2: (Re)start freeplane. Choose menu Tools/Scripts/GotoBookmark and Ctrl-click on "Execute GotoBookmark on one selected node". You are asked to choose a new shortcut key (combination). Do similar for the gotoBookmark script. Voilà.
Once setBookmark.groovy is executed, a child node named "Bookmark" will be added to the map root node. It has a local hyperlink pointing to the currently selected node. Executing gotoBookmark.groovy simply follows this link. Of course this implementation is a hack. Feel free to improve it!
Author: User:philshvarcz