Difference between revisions of "Scripts collection"

From Freeplane - free mind mapping and knowledge management software
m (Find changed nodes)
(add missing defs)
Line 29: Line 29:
  
 
def getLastModifiedAtRecursive(NodeProxy node, List nodeIdsToOmit) {
 
def getLastModifiedAtRecursive(NodeProxy node, List nodeIdsToOmit) {
     thisLastModifiedAt = getLastModifiedAt(node, nodeIdsToOmit)
+
     def thisLastModifiedAt = getLastModifiedAt(node, nodeIdsToOmit)
 
     if (node.children.isEmpty())
 
     if (node.children.isEmpty())
 
       return thisLastModifiedAt
 
       return thisLastModifiedAt
     lastModifiedAt = node.children.collect{getLastModifiedAtRecursive(it, nodeIdsToOmit)}.max()
+
     def lastModifiedAt = node.children.collect{getLastModifiedAtRecursive(it, nodeIdsToOmit)}.max()
 
     return thisLastModifiedAt.after(lastModifiedAt) ? thisLastModifiedAt : lastModifiedAt;
 
     return thisLastModifiedAt.after(lastModifiedAt) ? thisLastModifiedAt : lastModifiedAt;
 
}
 
}
Line 39: Line 39:
 
// modification should not count
 
// modification should not count
 
// note: before Freeplane 1.0.39 it has to be node.rootNode instead of node.map.rootNode
 
// 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})
+
def lastModifiedAt = getLastModifiedAtRecursive(node.map.rootNode, c.selecteds.collect{it.nodeID})
f = new java.text.SimpleDateFormat("yyyy-MM-dd hh-mm-ss")
+
def f = new java.text.SimpleDateFormat("yyyy-MM-dd hh-mm-ss")
 
node.setText("The map was last modified at: " + f.format(lastModifiedAt));
 
node.setText("The map was last modified at: " + f.format(lastModifiedAt));
 
</groovy>
 
</groovy>
Line 63: Line 63:
 
import java.text.NumberFormat;
 
import java.text.NumberFormat;
  
attrib = "AMOUNT"
+
def attrib = "AMOUNT"
  
 
def get(node) {
 
def get(node) {
     text = node.getAttributes().get(attrib)
+
     def text = node.getAttributes().get(attrib)
 
     if (text != null && text.isDouble())
 
     if (text != null && text.isDouble())
 
         return text.toDouble()
 
         return text.toDouble()
Line 83: Line 83:
  
 
def get(node) {
 
def get(node) {
     text = node.getAttributes().get(attrib)
+
     def text = node.getAttributes().get(attrib)
 
     if (text != null && text.isDouble())
 
     if (text != null && text.isDouble())
 
         return text.toDouble()
 
         return text.toDouble()
Line 98: Line 98:
 
     }
 
     }
 
     else {
 
     else {
         total = node.children.sum{ setAndReturnSum(it) }
+
         def total = node.children.sum{ setAndReturnSum(it) }
 
         set(node, total)
 
         set(node, total)
 
         return total
 
         return total
Line 124: Line 124:
  
 
<groovy>
 
<groovy>
sorted = new java.util.ArrayList(node.children).sort{ it.text }
+
def sorted = new java.util.ArrayList(node.children).sort{ it.text }
i = 0
+
def i = 0
 
sorted.each {
 
sorted.each {
 
     it.moveTo(node, i++)
 
     it.moveTo(node, i++)
Line 160: Line 160:
 
// for cut 'n paste:
 
// for cut 'n paste:
 
def showDialog(String text) {
 
def showDialog(String text) {
     dialog = new JDialog(UITools.getFrame())
+
     def dialog = new JDialog(UITools.getFrame())
 
     dialog.setSize(350, 450)
 
     dialog.setSize(350, 450)
 
     dialog.setLocationRelativeTo(UITools.getFrame())
 
     dialog.setLocationRelativeTo(UITools.getFrame())
Line 169: Line 169:
 
}
 
}
  
all_tags = ['address', 'author', 'booktitle', 'chapter', 'edition', 'editor',
+
def all_tags = ['address', 'author', 'booktitle', 'chapter', 'edition', 'editor',
 
     'howpublished', 'institution', 'isbn', 'journal', 'month', 'note', 'number',
 
     'howpublished', 'institution', 'isbn', 'journal', 'month', 'note', 'number',
 
     'organization', 'pages', 'publisher', 'school', 'series', 'title', 'type',
 
     'organization', 'pages', 'publisher', 'school', 'series', 'title', 'type',
Line 185: Line 185:
 
     //  - we can not match case insensitive
 
     //  - we can not match case insensitive
 
     // -> should be fixed ASAP
 
     // -> should be fixed ASAP
     tags = all_tags.collect { processAttribute(attr, it) }
+
     def tags = all_tags.collect { processAttribute(attr, it) }
 
     // compact: erase nulls
 
     // compact: erase nulls
 
     return "@" + type + "{${index.toString()}, \n  " +
 
     return "@" + type + "{${index.toString()}, \n  " +
Line 202: Line 202:
 
}
 
}
  
index = 1;
+
def index = 1;
 
// merge everything into one string
 
// merge everything into one string
result = getChildrenRecursive(node).sum {
+
def result = getChildrenRecursive(node).sum {
     attr = it.attributes;
+
     def attr = it.attributes;
 
     // valid values would be: article, book, booklet, conference, inbook,
 
     // valid values would be: article, book, booklet, conference, inbook,
 
     // incollection, inproceedings, manual, mastersthesis, misc, phdthesis,
 
     // incollection, inproceedings, manual, mastersthesis, misc, phdthesis,
Line 222: Line 222:
 
Use the following script to create a map for testing purposes. It adds some "BibTeX nodes" to selected nodes:
 
Use the following script to create a map for testing purposes. It adds some "BibTeX nodes" to selected nodes:
 
<groovy>
 
<groovy>
i = 1
+
def i = 1
 
def makeBibEntry(node, type, tags) {
 
def makeBibEntry(node, type, tags) {
     child = node.createChild()
+
     def child = node.createChild()
 
     child.attributes.set('bibtex', type);
 
     child.attributes.set('bibtex', type);
 
     tags.each {
 
     tags.each {
Line 252: Line 252:
 
// for cut 'n paste:
 
// for cut 'n paste:
 
def showDialog(String text) {
 
def showDialog(String text) {
     dialog = new JDialog(UITools.getFrame())
+
     def dialog = new JDialog(UITools.getFrame())
 
     dialog.setSize(350, 450)
 
     dialog.setSize(350, 450)
 
     dialog.setLocationRelativeTo(UITools.getFrame())
 
     dialog.setLocationRelativeTo(UITools.getFrame())
Line 262: Line 262:
  
 
def process(thisNode, childPosition) {
 
def process(thisNode, childPosition) {
     result = [[childPosition, thisNode.text]]
+
     def result = [[childPosition, thisNode.text]]
 
     thisNode.children.each {
 
     thisNode.children.each {
 
         result += process(it, childPosition + 1)
 
         result += process(it, childPosition + 1)
Line 269: Line 269:
 
}
 
}
  
result = process(node, 0);
+
def result = process(node, 0);
 
showDialog(result.collect{ "," * it[0] + it[1] }.join("\n"))
 
showDialog(result.collect{ "," * it[0] + it[1] }.join("\n"))
 
</groovy>
 
</groovy>
Line 370: Line 370:
 
<groovy>
 
<groovy>
 
def lastSection(Str){
 
def lastSection(Str){
     String[] p;
+
     String[] p = Str.split("\\.");
    p = Str.split("\\.");
 
 
     return p[p.size()-1];
 
     return p[p.size()-1];
 
}
 
}
  
 
def newChildNode(node, method){
 
def newChildNode(node, method){
     apiNode    = node.createChild(0);
+
     def apiNode    = node.createChild(0);
     returnType = apiNode.createChild(0);
+
     def returnType = apiNode.createChild(0);
     iProto    = apiNode.createChild(1);
+
     def iProto    = apiNode.createChild(1);
  
 
     def text = method.toString();
 
     def text = method.toString();
     String[] parts;
+
     String[] parts = text.split(" ");
    parts = text.split(" ");
 
  
 
     StringBuilder sb = new StringBuilder();
 
     StringBuilder sb = new StringBuilder();
Line 397: Line 395:
  
 
     def Class[] parms;
 
     def Class[] parms;
     parms = method.getParameterTypes();
+
     def parms = method.getParameterTypes();
     protoTxt = new StringBuffer();
+
     def protoTxt = new StringBuffer();
 
     if(parms.size() >0){
 
     if(parms.size() >0){
 
         for(i in 0..parms.size()-1){
 
         for(i in 0..parms.size()-1){
Line 419: Line 417:
  
 
def makeApi(node, object) {
 
def makeApi(node, object) {
     node = node.createChild()
+
     def node = node.createChild()
 
     node.text = object.class.name
 
     node.text = object.class.name
     methods = object.getClass().getMethods()
+
     def methods = object.getClass().getMethods()
 
     for(i in 0..<methods.size()){
 
     for(i in 0..<methods.size()){
 
         newChildNode(node, methods[i]);
 
         newChildNode(node, methods[i]);
Line 445: Line 443:
 
<groovy>
 
<groovy>
 
// @CacheScriptContent(true)
 
// @CacheScriptContent(true)
 +
def bookmarksNode
 
if((dummyList = c.find{ it.text.equals("Bookmarks")}).isEmpty()) {
 
if((dummyList = c.find{ it.text.equals("Bookmarks")}).isEmpty()) {
(bookmarksNode = node.getMap().getRootNode().createChild()).setText("Bookmarks")
+
    (bookmarksNode = node.getMap().getRootNode().createChild()).setText("Bookmarks")
}
+
}
else {
+
else {
bookmarksNode=dummyList.get(0)
+
    bookmarksNode=dummyList.get(0)
}
+
}
  
 
if((dummyList = bookmarksNode.find{ it.text.equals("recent")}).isEmpty()) {
 
if((dummyList = bookmarksNode.find{ it.text.equals("recent")}).isEmpty()) {
(recentBookmarkNode = bookmarksNode.createChild()).setText("recent")
+
    (recentBookmarkNode = bookmarksNode.createChild()).setText("recent")
}
+
}
else {
+
else {
recentBookmarkNode=dummyList.get(0)
+
    recentBookmarkNode=dummyList.get(0)
}
+
}
  
 
recentBookmarkNode.getLink().set("#"+c.getSelected().getNodeID())
 
recentBookmarkNode.getLink().set("#"+c.getSelected().getNodeID())
Line 465: Line 464:
 
<groovy>
 
<groovy>
 
// @CacheScriptContent(true)
 
// @CacheScriptContent(true)
 +
def dummyList1
 +
def dummyList2
 
if(!(dummyList1 = c.find{ it.text.equals("Bookmarks")}).isEmpty()) {
 
if(!(dummyList1 = c.find{ it.text.equals("Bookmarks")}).isEmpty()) {
 
if(!(dummyList2 = dummyList1.get(0).find{ it.text.equals("recent")}).isEmpty()) {
 
if(!(dummyList2 = dummyList1.get(0).find{ it.text.equals("recent")}).isEmpty()) {
Line 477: Line 478:
 
<groovy>
 
<groovy>
 
// @CacheScriptContent(true)
 
// @CacheScriptContent(true)
 +
def dummyList1
 +
def dummyList2
 
if(!(dummyList1 = c.find{ it.text.equals("Bookmarks")}).isEmpty()) {
 
if(!(dummyList1 = c.find{ it.text.equals("Bookmarks")}).isEmpty()) {
 
if(!(dummyList2=dummyList1.get(0).getChildren()).isEmpty()){
 
if(!(dummyList2=dummyList1.get(0).getChildren()).isEmpty()){
Line 510: Line 513:
 
   
 
   
 
def iterateDown(thisNode, childPosition) {
 
def iterateDown(thisNode, childPosition) {
     result = thisNode.getPlainTextContent().split(" ").length
+
     def result = thisNode.getPlainTextContent().split(" ").length
 
     thisNode.children.each {
 
     thisNode.children.each {
 
         result += iterateDown(it, childPosition + 1)
 
         result += iterateDown(it, childPosition + 1)
Line 517: Line 520:
 
}
 
}
  
result = c.getSelecteds().sum {
+
def result = c.getSelecteds().sum {
 
iterateDown(it, 0)
 
iterateDown(it, 0)
 
}
 
}
  
sumFormatted = NumberFormat.getInstance().format(result)
+
def sumFormatted = NumberFormat.getInstance().format(result)
 
UITools.informationMessage(UITools.getFrame(), sumFormatted, "Plain Text Word Count")
 
UITools.informationMessage(UITools.getFrame(), sumFormatted, "Plain Text Word Count")
 
</groovy>
 
</groovy>
Line 536: Line 539:
  
 
// @ExecutionModes({ON_SELECTED_NODE})
 
// @ExecutionModes({ON_SELECTED_NODE})
 
 
def createNewNode (node, text)
 
def createNewNode (node, text)
 
{
 
{
Child = node.createChild()
+
    def child = node.createChild()
Child.text = text
+
    child.text = text
return Child
+
    return child
 
}
 
}
 
   
 
   
def getTargetNodes (connectors)  
+
def getTargetNodes (connectors) {
{
+
     connectors.each {
     connectors.each
+
         def targetNode = it.getTarget()
      {
+
         def sourceNode = it.getSource()
         targetNode = it.getTarget()
+
         result = createNewNode(resultNode, sourceNode.text + " --> " + targetNode.text)
         sourceNode = it.getSource()
+
    }
         result = createNewNode(resultNode,sourceNode.text + " --> " + targetNode.text)
+
}
        }
 
}
 
 
   
 
   
def getChildrenRecursive(node) {
+
def getChildrenRecursive(node) {
 
     if (node.isLeaf()) {
 
     if (node.isLeaf()) {
 
         return [node];
 
         return [node];
Line 569: Line 569:
 
resultNode = createNewNode(thisNode,"Connected Nodes")
 
resultNode = createNewNode(thisNode,"Connected Nodes")
 
nodeList = getChildrenRecursive(thisNode)
 
nodeList = getChildrenRecursive(thisNode)
nodeList.each
+
nodeList.each {
{
+
     if (it.getConnectorsOut().isEmpty()) {
     if (it.getConnectorsOut().isEmpty())  
 
      {
 
 
         // do nothing
 
         // do nothing
          }  
+
    }
     else
+
     else {
        {
+
         def targets =  it.getConnectorsOut()
         Targets =  it.getConnectorsOut()
+
         getTargetNodes(targets)
         getTargetNodes(Targets)
+
    }
        }
 
 
}
 
}
  
Line 609: Line 606:
 
def matches = new ArrayList(c.find{ it.lastModifiedAt.after(changedSince) }).sort{ -it.lastModifiedAt.time }
 
def matches = new ArrayList(c.find{ it.lastModifiedAt.after(changedSince) }).sort{ -it.lastModifiedAt.time }
  
historyNode = node.map.root.createChild()
+
def historyNode = node.map.root.createChild()
 
historyNode.text = matches.size() + " nodes were changed since " + changedSince
 
historyNode.text = matches.size() + " nodes were changed since " + changedSince
 
c.statusInfo = historyNode.text
 
c.statusInfo = historyNode.text

Revision as of 23:41, 4 January 2011

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]


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) {

   def thisLastModifiedAt = getLastModifiedAt(node, nodeIdsToOmit)
   if (node.children.isEmpty())
      return thisLastModifiedAt
   def 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 def lastModifiedAt = getLastModifiedAtRecursive(node.map.rootNode, c.selecteds.collect{it.nodeID}) def 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;

def attrib = "AMOUNT"

def get(node) {

   def 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) {

   def 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 {
       def 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> def sorted = new java.util.ArrayList(node.children).sort{ it.text } def 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) {

   def 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 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
   def 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();
   }

}

def index = 1; // merge everything into one string def result = getChildrenRecursive(node).sum {

   def 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> def i = 1 def makeBibEntry(node, type, tags) {

   def 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) {

   def 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) {

   def result = childPosition, thisNode.text
   thisNode.children.each {
       result += process(it, childPosition + 1)
   }
   return result

}

def 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 = Str.split("\\.");
   return p[p.size()-1];

}

def newChildNode(node, method){

   def apiNode    = node.createChild(0);
   def returnType = apiNode.createChild(0);
   def iProto     = apiNode.createChild(1);
   def text = method.toString();
   String[] 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;
   def parms = method.getParameterTypes();
   def 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) {

   def node = node.createChild()
   node.text = object.class.name
   def 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 bookmarks. 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. A third key combination takes you to the subtree containing the recently stored bookmark and allows you to rename it. This is the basis of managing and accessing multiple named bookmarks.

Step 1: put these three scripts in your ~/.freeplane/scripts directory (or whereever you tell freeplane to look for groovy scripts)

setBookmark.groovy <groovy> // @CacheScriptContent(true) def bookmarksNode if((dummyList = c.find{ it.text.equals("Bookmarks")}).isEmpty()) {

   (bookmarksNode = node.getMap().getRootNode().createChild()).setText("Bookmarks")

} else {

   bookmarksNode=dummyList.get(0)

}

if((dummyList = bookmarksNode.find{ it.text.equals("recent")}).isEmpty()) {

   (recentBookmarkNode = bookmarksNode.createChild()).setText("recent")

} else {

   recentBookmarkNode=dummyList.get(0)

}

recentBookmarkNode.getLink().set("#"+c.getSelected().getNodeID()) </groovy>

gotoRecentBookmark.groovy <groovy> // @CacheScriptContent(true) def dummyList1 def dummyList2 if(!(dummyList1 = c.find{ it.text.equals("Bookmarks")}).isEmpty()) { if(!(dummyList2 = dummyList1.get(0).find{ it.text.equals("recent")}).isEmpty()) { if((linkString=dummyList2.get(0).getLink().get())!=null){ c.select(node.getMap().node(linkString.substring(1))) } } } </groovy>

gotoBookmarks.groovy <groovy> // @CacheScriptContent(true) def dummyList1 def dummyList2 if(!(dummyList1 = c.find{ it.text.equals("Bookmarks")}).isEmpty()) { if(!(dummyList2=dummyList1.get(0).getChildren()).isEmpty()){ c.select(dummyList2.get(0)) } } </groovy>

Step 2: (Re)start freeplane. Choose menu Tools/Scripts/SetBookmark and Ctrl-click on "Execute SetBookmark on one selected node". You are asked to choose a new shortcut key (combination). Do similar for the gotoRecentBookmark.groovy and gotoBookmarks.groovy scripts. Voilà.

Once setBookmark.groovy is executed, a child node named "Bookmark" will be added to the map root node. In the beginning it has one child named "recent". The latter has a local hyperlink pointing to the currently selected node. Executing gotoRecentBookmark.groovy simply follows this link. Everytime you execute setBookmark.groovy this link will be overwritten. You can rename the "recent" node to conserve the link. This is the basis of managing multiple bookmarks. For convenience, executing gotoBookmarks.groovy will take you to the first child of the "Bookmarks" node to quickly access your "Bookmark manager" subtree. From here you can manually follow the links as usual, pressing 'Ctrl-Enter' or klicking the arrow icon. Please feel free to improve the scripts and post improvements here!

Author: User:philshvarcz

Simple plain text word count using scripts

This script will take the selected node(s), iterate down through subnodes, and count plain text. Notes, attributes, icons are not counted.

<groovy> // @ExecutionModes({ON_SINGLE_NODE}) // wordCount.groovy by User:cybaker // Adapted from "Output A Map to CSV" by User:Boercher // This script goes through all selected nodes and their subnodes and counts the number of // plain text words, not including notes. Words are simply delimited by a space character. // Usage: Select desired node(s). Run script once.

import java.text.NumberFormat; import org.freeplane.core.ui.components.UITools;

def iterateDown(thisNode, childPosition) {

   def result = thisNode.getPlainTextContent().split(" ").length
   thisNode.children.each {
       result += iterateDown(it, childPosition + 1)
   }
   return result

}

def result = c.getSelecteds().sum { iterateDown(it, 0) }

def sumFormatted = NumberFormat.getInstance().format(result) UITools.informationMessage(UITools.getFrame(), sumFormatted, "Plain Text Word Count") </groovy>

Author: User:cybaker

Find all connected nodes

This script will find all nodes below the current node that have connections and list them under a new node created to hold the results called "connected nodes". I found this extremely useful when I have multiple connections reaching across subtrees in a large map. <groovy> import java.text.NumberFormat; import org.freeplane.plugin.script.proxy.NodeProxy;

// @ExecutionModes({ON_SELECTED_NODE}) def createNewNode (node, text) {

   def child = node.createChild()
   child.text = text
   return child

}

def getTargetNodes (connectors) {

   connectors.each {
       def targetNode = it.getTarget()
       def sourceNode = it.getSource()
       result = createNewNode(resultNode, sourceNode.text + " --> " + targetNode.text)
   }

}

def getChildrenRecursive(node) {

   if (node.isLeaf()) {
       return [node];
   }
   else {
       // father and sons
       return [node] + node.children.collect{ getChildrenRecursive(it) }.flatten();
   }

}

//******************************************************

thisNode = node resultNode = createNewNode(thisNode,"Connected Nodes") nodeList = getChildrenRecursive(thisNode) nodeList.each {

   if (it.getConnectorsOut().isEmpty()) {
        // do nothing
   }
   else {
       def targets =  it.getConnectorsOut()
       getTargetNodes(targets)
   }

}

</groovy> Author: User:ccrick

Find changed nodes

This script was suggested by Tobias Brown. It creates a new child node of the root node with shallow copies of the first maxCount changed nodes, ordered by modification time starting with the most recently changed node. Note that the values in the first lines are meant for adjustment to your own preferences. <groovy> // @ExecutionModes({ON_SINGLE_NODE}) // == Config BEGIN // find all nodes changed since 1970-01-01. Limit the search to the last 48 hours by: new Date() - 2 def changedSince = new Date(0L) // maximum number of displayed nodes def maxCount = 50 // maximum length of cited text def maxLength = 50 // add modification time to the node reference? def addTimestamp = true // add connector to the changed node? def addConnector = false // == Config END

def df = new java.text.SimpleDateFormat("yyyy-MM-dd hh:mm")

// find() returns a unmodifiable list so we have to copy it in order to copy it. // The minus sign reverts the order. def matches = new ArrayList(c.find{ it.lastModifiedAt.after(changedSince) }).sort{ -it.lastModifiedAt.time }

def historyNode = node.map.root.createChild() historyNode.text = matches.size() + " nodes were changed since " + changedSince c.statusInfo = historyNode.text

if (matches.size() > maxCount)

   matches = matches[0..maxCount-1]

matches.each{ node ->

   def child = historyNode.createChild()
   def text = (addTimestamp ? df.format(node.lastModifiedAt) + " " : "") + node.plainTextContent
   child.text = text.length() > maxLength ? text.substring(0, maxLength-1) : text
   if(addConnector)
       child.addConnectorTo(node)
   child.link.set('#' + node.nodeID)

} c.select(historyNode) </groovy> Author: User:boercher