Freeplane

Freeplane is a free and open source software application that supports thinking, sharing information, getting things done at work, in school and at home. It provides you a set of tools for mind mapping (also known as concept mapping or information mapping) and navigating the mapped information. Freeplane's capabilities will appeal to power users, but for the typical user is also a more robust alternative to Xmind, Mindmeister, and similar mind mapping software.

Freeplane is written in Java using OSGi and Java Swing. It runs on any operating system that has a current version of Java installed. It can be run locally or portably from removable storage like a USB drive.

Download and install the latest version over at Sourceforge. The change log is available here.

If you would like to report a bug, you can go report it over at Issues

Hop on to our Discussions if you have any questions, ideas, or thoughts you'd like to share. Contributors are very much welcome, of course!

Features rundown

student


slides


formatting


UI


addons


command search


styling


formulas


discussions


Thanks

Freeplane team uses:

How to get help

Freeplane is a non-commercial project. It lives by our active and vibrant community, where we try to support each other in order to develop and provide an outstanding knowledge management application. Please, feel free to discuss Freeplane and its features with other interested Freeplane users. For this purpose, we provided two forums (see structure picture on the right):

We invite you to do the following things:

in our DISCUSSIONS FORUM

  • discuss the usage of existing features
  • discuss the suitability of new features
  • discuss the development of [existing scripts](scripting/Scripting showcase and examples/Scripts_collection.md) and new ones

New bug reports go into the bug reports

New feature requests go into the feature requests

Freeplane's old user forums are archived here and here.

Getting started

Install

Download Freeplane

Download Freeplane now!
(this downloads the stable version 1.12.4u1)
change log
Download last development versions ( preview )

Find out which distribution better fits your requirements.

Extend with add-ons.

Freeplane is available for differents Operating Systems. All Freeplane setup files are available for download here.

Please find below recommendations to choose which file to download before installing Freeplane on your computer.

Distributions for Microsoft Windows

  • Freeplane-Setup-with-Java-xxx.exe: Windows installer with embedded Java.
  • Freeplane-Setup-xxx.exe: Windows installer which requires Java 11 to 17 to be installed independently. To use this version set environment variable path FREEPLANE_JAVA_HOME.
  • FreeplanePortable-xxx.paf.exe: runs on Windows using Portable Apps launcher. Requires Open JDK JRE64 portable java version 15 to be installed on your portable app device. It saves user configuration files on the same device.
  • freeplane_bin-xxx.zip: archive without installer. It requires Java 11 to 17 to be installed. To use this version set environment variable path FREEPLANE_JAVA_HOME.

Distributions for Apple macOS

  • Freeplane-xxx-intel.dmg: distribution with embedded java for macOS with intel or m1 processor. This distribution includes adaptive Look and Feel VAqua.
  • Freeplane-xxx-apple.dmg: distribution with embedded java for macOS with m1 processor. This distribution does not include adaptive Look and Feel VAqua.

Distributions for Linux

  • freeplane_xxx~upstream-1_all.deb: Debian installer compliant with differents Linux derivatives.
  • freeplane_bin-xxx.zip: archive without installer.

They both requires Java 11 to 17 to be installed. To use them, set environment variable path FREEPLANE_JAVA_HOME.

Command-line options

Call freeplane like this:

freeplane [options] [file1 [file2 ...]]
OptionDescription
-h or --helplist available options
-X<menukey>execute menu item with key . Use devtools add-on to find the menu keys
-Sstop after executing menu items
-Nset the 'nonInteractive' system property to 'true'
-U<userdir>set the freeplane user config directory (only since version 1.3.3!!!)

Batch execution of menu items (e.g. scripts) is described in a special wiki article.

Debug start script under Linux

Start Freeplane in debug mode (if you have problems starting):

DEBUG=true freeplane.sh

Environment variables

Select Java installation used to run Freeplane

The following variables are tried in order:

  • FREEPLANE_JAVA_HOME
  • JAVA_HOME (not on Windows OS)

For windows, set one of these variables and run freeplane.exe or freeplaneConsole.exe:

FREEPLANE_JAVA_HOME=C:\Program Files\Zulu\zulu-11-jre

or, under Linux/UNIX:

FREEPLANE_JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ ./freeplane.sh

Java version

Freeeplane 1.11.x requires Java between Java 11 and Java 21 on Windows and Mac, Java 8 and Java 21 on Linux

Freeeplane 1.10.x requires Java between Java 8 and Java 17.

Freeplane 1.9.x requires Java between Java 8 and Java 15, because Java 16 is not compatible with current Groovy Engine.
Use of Java 16 can be permitted only on Linux by setting variable FREEPLANE_USE_UNSUPPORTED_JAVA_VERSION to 1.

JAVA_OPTS

Set Java Properties, e.g. set the freeplane user config directory in Freeplane < 1.3.3:

JAVA_OPTS=-Dorg.freeplane.userfpdir=$HOME/blabla freeplane.sh

What is an Add-on?

Add-ons are a way to extend and customize Freeplane similar to how plug-ins and extensions can be used to extend and customize well-known applications like Firefox or LibreOffice. Freeplane add-ons can be used to provide a single function, a bundle of multiple functions, bind those functions to a menu item, and much more.

Anybody can write an add-on! (see the add-on developer documentation)

note: add-ons are not necessarily provided by the Freeplane core developers.

Installing an add-on

An add-on is a Freeplane mind map with the special additional suffix .addon.mm. Add-ons can be installed with a single click with Freeplane version v1.2.10_05 or later.

If Freeplane is not the designated program to open '.mm' files and for Freeplane versions before v1.2.10_05, follow this procedure:

  1. In Freeplane, select Tools > Add-ons > Search add-ons > Visit add-on page
  2. Search for your add-on and choose download
  3. Save the add-on on your computer (for example, on your desktop)
  4. Select Tools > Addons > Search and install
  5. Select directory icon
  6. Find and select the file you just downloaded (for example, on your desktop)
  7. Select Install
  8. Restart Freeplane

You will now find the new command in the menu. For example, "Insert Inline Image" can be found under Edit->Node extensions with the shortcut Ctrl+Shift+i.)

Add-ons are listed below.


Edit

wikdNode

by L. C. Rees, maintainer Volker Börchers

Node wrangling features for Freeplane:

  • Case
    • capitalize first word in node core text
    • capitalize all words in node core text
    • upper case node core text
    • lower case node core text
  • Delete
    • delete first chosen characters from node core text
    • delete first characters matching a regular expression from node core text
    • delete last chosen character from node core text
    • delete last characters matching a regular expression from node core text
    • delete links on multiple nodes
  • Split
    • split node core tex into multiple nodes on periods
    • split node core text into multiple nodes on commas
    • split node core text into multiple nodes on spaces
    • split node core text into multiple nodes on one or more chosen characters...
    • split node core text into multiple nodes before one or more chosen characters...
    • split node core text into multiple nodes on characters that match a regular expression...
    • split node core text into multiple nodes before characters that match a regular expression...
    • splits node core text after one or more chosen characters
    • splits node core text after characters matching a regular expression
  • Join
    • join node core text of multiple nodes with spaces
    • join node core text of multiple nodes with commas
    • join node core text of multiple nodes with periods
    • join node core text of multiple nodes with one or more chosen characters
  • Other
    • copy node core text as a new child of the node
    • replace parent node core text with the core node text of one of its children
    • convert parent node attributes to node children
    • convert node children to parent node attributes

Download v0.8.0 from Github (with Java speedups)

Note: previous version of widkNode needed addition of 'scripts' to the script classpath in Freeplane's preferences. Please undo that before installing 0.8 and later

Source: Github


Navigate

MapInsight

by ADXSoft (Allan)

Freeplane Add-on for exploring maps and connecting idea

MapInsight addon provides a simple UI for walking around a map and optionally creating connectors

Using a lot of connectors, a map can get very confusing. This simple UI gives the view from a selected node showings its parent, children, connectors in and out. Hovering over a node in the UI reveals the notes and details.

Connection Candidates tool finds possible connections through link words, phrases or regular expressions and allows you to create the connector

Connection Manager shows all connectors in the map in a sortable table with edit/delete options

Video demonstration https://www.youtube.com/watch?v=cSyhkcsB2-M (made before the script was converted to an add-on but demonstrates the functionality of the import)

Add-on is located at https://github.com/adxsoft/MapInsight-Addon

Note that the latest version is this one: https://github.com/adxsoft/MapInsight-Addon/issues/4#issuecomment-715262901

'''by Jodi D. Krol

Scroll leaves to visible

Performs two actions:

  • Folds/unfolds the selected node
  • On unfolding moves (grand)children into the screen area.

Does not (un)fold (grand)children. The action is performed recursively for al children. As a result the last child may cause the previous child to be moved outside the screen area. This behaviour may be influenced by folding the (other) children.

video demonstration

Demote to upper sibling

Moves each selected node to upper sibling and appends as child.

Download navigation 0.3

Installing the addon adds method Scroll leaves to visible and method Demote to upper sibling to menu Tools>scripts.

Jumper

by lilive

A fully keyboard driven search box for quick navigation in maps. It filters the nodes on-the-fly as the user types the search terms, and allows to jump to one of the results.

Jumper, the Jumping Filter, provides an easy and quick way to search for nodes in Freeplane maps. Press Jumper keyboard shortcut, type some text snippets, and you will instantly see all the nodes (or branches !) that contain them in the Jumper window. Select one of these nodes to select it in the map.

1 minute demonstration video.

Some features:

  • Search results updated as you type
  • Matching text is highlighted in the results list
  • Regular search or transversal search (find words or text snippets across a branch)
  • Words or text snippets can be searched in any order
  • Search in any part of the nodes (core text, details, notes, attributes)
  • Plain text or regular expressions search, case sensitive or insensitive

Find all Jumper features, usage instructions and download here.

Bookmarks

by lilive

This add-on allows to bookmark some nodes in a Freeplane map, and to easily navigate between them.

Available in french and english. Le module Marque-pages est disponible en français et en anglais.

You can download it from its github page.


Problem solving

FreeIBIS

by L. C. Rees, maintainer Henk van den Akker

Issue-Based Information System for Freeplane, supporting coordination and planning of political decision processes, sensemaking and collaborative problem solving in a variety of social and technical contexts.

In the README file on the FreeIBIS Github page you can find information about the usage of this add-on.

Download v0.1.1


Plan and organize

Freeplane|GTD

This add-on enables using a mind map as a 'trusted system' in the Getting Things Done (GTD) methodology.

The hierarchical nature of a mind map is ideal for tracking projects, their associated tasks, and next actions.

Features:

  • Extracts Next Action lists from nodes marked with a next action icon
  • Displays lists sorted by Project, Context, Waiting-For, or Due Dates
  • Accepts a simple, natural shorthand notation for entering Next Actions
  • Next Actions in lists are hyperlinked back to the GTD mind map for easy editing

See here for more details.

Download latest version

Freeplane|GTD+

A generic task management add-on, with a special focus in supporting the Getting Things Done (GTD) methodology.

The hierarchical nature of a mind map is ideal for tracking projects, their associated tasks, and next actions.

Based on the original Freplane|GTD add-on, this add-on takes working with your tasks to the next level.

Features:

  • Extracts Next Action lists from nodes marked with a next action icon
  • Displays lists sorted by Project, Context, Waiting-For, or Due Dates
  • Accepts a simple, natural shorthand notation for entering Next Actions
  • Next Actions in lists are hyperlinked back to the GTD mind map for easy editing

New features:

  • Allow marking tasks as done, and optionally hiding them from the task list
  • Automatic Icon to Context transformation, based on your preferences
  • Allow setting task priorities from shorthand, or the number icons
  • Advanced copy to clipboard function to copy all or or grouped (Project/Context/Responsible/Duedate) actions as simple text, formatted text/HTML and as freeplane nodes
  • Select function to select all or grouped (Project/Context/Responsible/Duedate) tasks in the mindmap

See here for more details.

Download latest version

GTD Sync

by Henk van den Akker

Groovy script to synchronise a Freeplane|GTD mind map with todo.txt. The catch is that you can make your Next Action list available to other applications and systems. For example, you can use Dropbox to distribute todo.txt and use SimpleTask for Android to consult and maintain todo.txt. What does GTD sync do?

  • It imports new next actions from todo.txt to your GTD mind map under node 'New'.
  • It updates existing next actions in your GTD mind map with the changes made in todo.txt since last synchronisation. This includes changing the status to completed.
  • In case a next action is changed in both todo.txt and the GTD mind map, the attributes changed in todo.txt are logged, so after the synchronisation you are able to check whether any manual update is necessary.
  • After the GTD mind map is updated with all new and changed next actions in todo.txt, all its next actions will be exported to todo.txt. The export does not include completed next actions.

For further information consult the wiki or the Quick Start mind map (Shift+F1) provided with the add-on.

For Freeplane 1.8.9 and higher: download the latest version of GTD Sync.

For upgrade information and Freeplane version compatibility read the README file

Freeplane|WBS

It aggregates the costs and durations for a task tree. It also assigns codes to each task in a doted form for later reference.

You should consider the root of the map as the project root, and each node as a task.

Project page

Download latest version

Study Planner

by Predrag Cuklin

Study Planner will help in better organization of learning.

It is designed for pupils and students in planning everyday school extracurricular activities and obligations.

Important functions of Study Planner are:

  • organization of subjects and activities by day
  • organization of activities by time of learning
  • the ability to determine the type of activities
  • countdown learning
  • creating lists of activity by Day, by Subject, by Type of activity, by Period of learning
  • copying list
  • print list
  • more icons

For more information see this page

Download v1.2.1


Images and icons

Insert Inline Image

by Volker Börchers, Rickenbroc

This add-on is a convenient way to add images on the fly in your maps. The images can come from :

  • a file from your computer,
  • the clipboard : file path or a copy (like a screenshot),
  • an url from the internet

You can resize the display (with a preview pane) and put it in :

  • node core
  • node details
  • note
  • node extension

You can even decorate the image inserted with a link which point wherever you would want.

Download v1.1 for Freeplane v1.8.0 and higher

Download v1.0 for Freeplane v1.2.10 to v1.7.x

Old Icons Theme

This little theme add-on installs the old (pre 1.2.9) link icons (Link.png and LinkLocal.png).

Download v0.9.5

Palm Icons

by Steve Kunkel

Free Palm Os Icons categorized by groups Office, Home.... for Freeplane.

Compiled by Steve Kunkel and converted to an Add-on by Predrag. For artist information, see this forum post.

Download v1.0

User Icons

by Predrag Cuklin

This add-on adds standard Freeplane icons under User icons in bigger size (24 px) and adds other icons (computer, more office icons...).

Download v1.1


Collaborate

Roan-Presentation

by Jodi D. Krol

RoAn-Presentation provides a combination of mind mapping with Powerpoint- and Prezi like presentation, using automatic filtering and zooming.

Stepping the presentation not only unfolds nodes, but also displays hidden details, centers the current node, executes the named filters which may be connected to each node and more. In short it supports traversing a mind map, taking over abundant clicking from the user.

Besides traversing the mindmap depth first, it is possible to define scenes and scenario's for traversing in any order.

The included Help file which itself is an example which can be played or stepped as well. The Help file also contains links to example maps and videos which can be downloaded.

Besides functionality for presenting, RoAn may automatically add nodes with links to all folders and files in the directory of the mind map (indexing). As a choice image files may be displayed as inline images. This functionality is more basic than in addon diView(indexfile), but more easy to use.

Installing the add-on results in a new menu Tools> RoAn-Presentation. This menu contains a submenu "Menu" which opens a window with presentation and edit buttons. One of the buttons will open the Help file. Once menu RoAn is used on a mind map, a little button is added to the root to open RoAn's menu with a click next time.

Download roan-presentation 0.2.1 for Freeplane 1.5.

Download roan-presentation 0.1.3 for Freeplane 1.3.

Translation

by Volker Börchers

Utilities for automatic translation of maps and language resources that use the mymemory translation service. Of most interest for Freeplane translators.

The scripts still have some limitations:

  • Text size per node/text is limited to 1000 characters.
  • Translation time growths mainly with the number of texts/nodes. No optimization for the case of many small texts.

Download v0.6

Collaborative tools

This add-on is no longer maintened (not tested under freeplane 1.5).

by Sébastien Georget

Collaborative tools provides some scripts to ease team working on a single map.

It requires a working versionning system, CVS, SVN and GIT are supported.

Once installed, you can execute the following commands inside freeplane

  • diff your mindmap (F10)
  • update your mindmap (F11)
  • publish your mindmap (F12)

Download the latest version

Feedback and contributions are welcome.


Import and export

Pack & Go

by Volker Börchers

Pack and Go provides a function to pack a map with all its dependencies into one zip file.

All files have to be loaded into the RAM so be prepared to increase Java heap space if you get a "Out Of Memory" Error.

Download v0.5

Pack and Go-Go

by macmarrum

Originally Pack And Go by Volker Börchers - no longer maintained

Pack and Go-Go adds a menu item to create a ZIP file with the mindmap, packing also its images and linked mindmaps (without dependencies).

Note: All files are loaded into RAM. If you get an Out Of Memory Error, see Troubleshooting

Works with Freeplane version 1.9.1 and above.

PackAndGoGo.addon.mm releases

Import OPML to selected node

by ADXSoft (Allan)

Freeplane Add-on for importing OPML files

OPML is a popular export format for mind maps and OPML has nodes recorded in outline tags.

Within each outline tag is

  • a text attribute which is the node title
  • a _note attribute which is the note related to the node. This may or may not be present
  • optionally, a richcontent tag with html content

This script will import the nodes and their related notes and richcontent into Freeplane as follows

  • an outline tag's text attribute will import into a node core's text
  • a _note attribute (not always present) will import into the nodes note text
  • a richcontent tag's contents, if present, will import as html into the node details text

Video demonstration https://youtu.be/hUagckdoeNATo (made before the script was converted to an add-on but demonstrates the functionality of the import)

Add-on is located at https://github.com/adxsoft/ImportOPMLtoselectednode.addon

Map Obfuscator

by macmarrum

Duplicates the current mindmap and obfuscates its content so that it can be shared without exposing private information.

Works with Freeplane version 1.8.0 and above.

Download Map Obfuscator


Others

SmartLocker

by Jodi D. Krol

SmartLocker provides a secure repository integrated within a freeplane mind map.

Besides it can generate a secure password, automatically login to a website and open multiple sites in one click.

Its typical use is illustrated in the video's below.

After downloading and installing SmatLocker's menu appears in menu Tools > SmartLocker. This menu contains extensive help, both local and online, and in addition to the local help provided in tooltips. It contains documentation describing all system nodes and preferences which can be set for these nodes through menu Tools > Preferences > SmartLocker. It describes how you can translate SmatLocker's menu and help files, and share them through the freeplane wiki with other users. The Help file also contains a link to a map with predefined nodes for logging in to email providers, facefook etc. And it contains a node Illustration which contains documented nodes explaining the global architecture of SmartLocker (don't forget to to look inside the locker nodes). Finally, if you want to write your own scripts, the documentation contains a number of scripts you can simply import and use.

Video 1. Repository

Video 2. Automatic login

Download preview Smart Locker v0.2

IMPORTANT

After downloading, in Tools > Preferences > Plugins set:

  • classpath: lib
  • permit file/ read operation: true

dView(indexfile)

by Jodi D. Krol

The add-on dView(indexfile) supports adding annotations, hyperlinks and reminders to file names in a folder structure. For this a specialized dashboard mindmap must be put into the folder to index. When this dashboard is opened and button Index is pressed, a hierarchy of nodes with hyperlinks to the subfolders and files of the indexed folder is generated. Next one can add annotations, add hyperlinks to other files or websites, and add reminders (clock) for file related actions. If email adresses are registered, with one click all users of a particular dashboard can be sent a group-email. In case of image files, a preview can be displayed. The resulting mindmap can be shared with other users, which can navigate it without having to install the add-on. Hyperlinks to indexed files can be copied and pasted into an email. With special options set the add-on can be used with MS Sharepoint or on the internet, and/or be used to generate NATO-compliant file names.

Installing add-on dView(indexfile) results in a new menu Tools> dView(indexfile) with different dashboard types to choose from: basic, dossier, meeting, theme, organisation, person and folders, see the descriptions below. Besides it has an extensive Help.

The following functions can be used on any map:

  • Copy selected hyperlinks to clipboard (F12), to paste with Ctrl-V in email, Word document, other html-based document
  • Copy adresses of links in selected nodes to clipboard (F11), to paste with Ctrl-V
  • Copy location of node in map (F10), to paste as link in node of different map (F9) See Help for details.

For a video and examples seeInformation management with add-on dView(indexfile).

'''Download dView(indexfile) 0.3.1

When opening and instaling the add-on:

  • jar files scriptlib and indexfile are added to /lib
  • template files are added to /templates/indexfile
  • help files are added to /doc
  • submenu IndexFile is added to menu Tools

See video with instructions for installation.

Map Saving Options

by EdoFro

'Map Saving Options' is a Freeplane AddOn that gives you the possibility to add saving preferences to each of your maps.

This Add-on can be useful when working with Github or when comparing different versions of a mindmap file.

Find MapSavingOptions features, example images and usage instructions here

With this AddOn you can define if a map have to save the information of any of these:

  • folded and unfolded nodes
  • selected node when saving
  • Creation and Modification times of each node

This way, you can define for each map if it will use the central Freeplane preferences, its own or a mix of both.

Download the latest release here

Script Execution On Mindmap Open

by macmarrum

Freeplane has the functionality to execute Groovy scripts when the application starts. It's known as "init scripts" → https://docs.freeplane.org/?search=init

This add-on extends the functionality with the ability to execute scripts when a mindmap is opened, i.e. individually for each mindmap.

To execute a script for a mindmap, in your root node add an attribute named "scriptOnMapOpen", then use Tools->Edit script... to enter the Groovy code.

Note: The attribute name must start with "scriptOnMapOpen" but can have any suffix

Works with Freeplane version 1.7.10 and above.

Download Script Execution On Mindmap Open


For developers

Developer Tools

by Volker Börchers

This add-on collects some utilities that script and/or add-on developers will find useful.

  • Build add-on: adds all standard nodes, attributes and notes to the current map. Can be used with an empty Map to create a basic add-on.
  • Package add-on for release: It copies the .mm to -.mm and updates the script node's context from the files lying around.
  • Generate add-on documentation: Creates a snippet for the Freeplane add-ons wiki page.
  • Insert binary: Asks for a file to insert as text of the current node (BASE64 encoded).
  • Extract binary: Asks for a file to extract the BASE64 encoded binary in the current node to.
  • Encode translation: Encode non-ASCII characters so that they don't get scrambled while packaging or installation. This function is included in Package add-on for release so you don't need this function.
  • Menu item info: Shows technical details about a selected menu item.
  • freeplane.dsld: Adds Eclipse editor support for predefined script bindings such as node, c, ui, textUtils, ...

The functions are available under Tools -> Developer Tools

For Freeplane 1.7.4 and higher: Download v0.9.28

For Freeplane 1.6.15 and higher: Download v0.9.23

For Freeplane 1.3.x and 1.5.x: Download v0.9.22

For Freeplane 1.2.x: Download v0.9.14

wikdShell

by L. C. Rees, maintainer Volker Börchers

Groovy console for interacting with a running Freeplane instance.

Scripts inside the console have the same variables that every script has assigned to, like node (the selected node when launching the shell) and c (the Controller). See the groovyconsole description for usage instructions.

Source: Github

For Freeplane 1.5.x: Download 0.3.0

For Freeplane 1.3.x and 1.2.x: Download 0.2.3

scriptlib

by Jodi D. Krol

This add-on is aimed at starting developers. It:

  • Provides a number of generic ready to use scripts (play audio, set bubble, set cloud etc.);
  • Shows how to define local and online Help for add-ons (including translations);
  • Shows how to share both binary and groovy code by means of an add-on;
  • Shows how add-on scriptlib is defined, including defining menu items, preferences, default properties and translation; scripts and zips; and how the source of the add-on can itself be included in an add-on.

Download scriptlib v0.0.5

IMPORTANT: In Tools >Preferences > Plugins classpath must be set to: lib.

After installing the a menu Tools > Defining scripts is added. It opens two submenu's: Help and Help online. The former contains the help as provided when downloading scriptlib. The latter may contain a newer version of the help file, which is available without having to download a new version of scriptlib.

User Documentation

First steps

  • To create a new node, press enter.
  • To add text to the new node, start typing and press enter when you are done.
  • To navigate between nodes, use the arrow keys.
  • To fold/unfold a selected node, press space.
  • To move nodes, drag and drop them with the mouse.
  • For more details, see the rest of this documentation.
  • For any questions related to documentation ask at Freeplane docs forum.
  • For any questions related to freeplane software ask in Freeplane forum.

Working with mind-map files

Create a new map

Create a new map with File->New map (Ctrl+N). This creates a new map using the default template.

Create a new map from a different template with File->New map from template…. This opens a file picker that lets you choose a template to use to create a new map.

Create a new password-protected map with File->New protected (encrypted) map…. This opens a password dialog used to encrypt a new map created using the default template. Encrypted maps cannot be opened or read without the password.

Open maps

Open an existing map with File->Open mind map… (Ctrl+O). This opens a file picker to let you chose a Freeplane .mm map file to open. In this dialogue you can also choose standard or user-defined template mind maps from the drop-down menu at the bottom (see Templates).

Open an existing map from a list of recently opened maps with File->Open recent map.... Hovering over this Menu action shows a list of recently opened maps. Click on any map on this list to open it.

If you have Autosave enabled, you can open an autosaved version of an existing map with File->Open older version. See Autosave for more information.

Close maps

Close the active map with File->Close current map (Ctrl+W).

Close all inactive maps (open maps that are not the active map) with File->Close all other maps.

Close all open maps, both active and inactive, with File->Close all maps.

If you have made any changes to a map after opening it, including changes to a node's folded/unfolded state, and you attempt to close the map, Freeplane will ask you if you want to save the map first.

Save maps

Save an active map with File->Save map (Ctrl+S).

Save all open maps with File->Save all maps.

Save an active map under a new filename with File->Save map as… (Ctrl+Shift+S).

In the saving-dialogue you can choose standard or user-defined template mind maps from the drop-down menu at the bottom (see Templates).

Autosave

Enable and customize Autosave with settings in Tools -> Preferences in section Environment->Automatic save.

Preferences

There you can set the following preferences:

SettingNotes
Time for automatic saveSets the time in milliseconds between autosaves. To disable autosave set this number to 2000000000.
Use single directory for backup filesIf filled, Freeplane will autosave backup files to a single directory. If cleared, Freeplane will autosave backup files for each map to that map's directory
Backup directoryIf Use single directory for backup files is filled, this sets the directory where autosave files are saved. By default, it is set to .backup in the Freeplane user directory.
Delete automatic saves at exitIf filled, autosave files are deleted automatically when Freeplane is shutdown normally.
Number of different files for automatic saveSets the number of different autosave files to keep when Freeplane is open before the autosave files begin to be overwritten.
Number of kept backup filesSets the number of different autosave files that are kept after Freeplane is shut down normally.

Import

The File->Import menu has two types of functions. One is importing map branches from other Freeplane maps into an active map. The other is importing content from non-Freeplane maps into an active map.

Importing Freeplane map branches into an active map

(to be added)

Importing non-Freeplane map content into an active map

(to be added)

Export

Mindmaps can be exported to the following formats:

  • Documentation formats - Asciidoc,Mediawiki, Markdown, xbel, Twiki, pdf,opml
  • Latex - Beamer,book,document,input
  • Image formats - Jpeg, png, svg
  • XML formats - Raw XML with node formatting, xml
  • XHTML - xhtml(clickable html and javascript versions)
  • HTML - htm and html
  • Microsoft office 2003 formats - Microsoft Excel 2003,Word 2003, Project 2003
  • Open office format
  • Tasks from Tasks node to TaskJuggler file
  • Freeplane 1.1 format(old format)

Export map

To export the mindmap you can select File->Export map from the menu.

Export branches

To export a specific branch in mindmap you can select the node you want to export and then from menu you select File->Export branches.

Other resources

Change Freeplane settings

Freeplane settings can be customized from Tools -> Preferences menu option.

Preferences

Hot Keys

Freeplane allows to assign hot keys (aka keyboard shortcuts) to any action available in the menu, as well as to icons.

It is most apparent in View->Controls->F-Bar.

By default Preferences…->Keystrokes->Commands for the program->Ignore unassigned F-Keys is off, therefore a click on (usage of) an unassigned F-Bar key will display a prompt to "click on the desired command in the menu" to "create a new keyboard shortcut".

Hot Keys for Actions

Let's say that you want to use INSERT to add new child nodes, instead of the default TAB.

Method 1
You can go to Tools->Assign hot key, a pop-up window will appear with the message "To create a new keyboard shortcut, click on the desired command in the menu". Once you click on Insert->New node->New child node, a pop-up will prompt you to use your new hot key and click OK.

Method 2
Go to Insert->New node->New child node, hold Ctrl and click.
Alternatively, hover your mouse cursor over the menu item New child node and press Ctrl+Return.
A pop-up will prompt you to use your new hot key and click OK.

Method 3
You can launch the Command Search via Help->Command Search or its hot key Ctrl+F1.

  1. Make sure Menu items is checked.
  2. Type new child in the search bar.
  3. Select (using the arrow keys) Insert->New node->New child node (Tab) and press Ctlr+Enter.
    Alternatively, hold down Ctrl and double-click Insert->New node->New child node (Tab).
    A pop-up will appear, where the new hot key can be assigned.

Bonus
In step 3, when you select Insert->New node->New child node (Tab) and press Ctrl+C, the visible text is copied to the clipboard. It can be pasted e.g. in a Discussions post.

Hot Key Reassignment

It's possible to reassign an already used hot key to a different action or icon. The procedure is as described above, with the addition of a confirmation window.

Let's say you want to change the hot key for Command Search from the default Ctrl+F1 to Ctrl+Shift+A. Once you follow one of the three methods, you'll be presented with the confirmation pop-up

Hot Key Unassignment

You can clear a hot key, unassigning it from an action/icon. Just follow any of the methods in Hot Keys for Actions, and in the "Enter new key" pop-up window choose the button Clear and confirm OK.

Hot Keys for Icons

Similarly, a hot key can be assigned to an icon. It can be done using one of the methods described in Hot Keys for Actions, i.e. (for the "Home" icon):

  1. Tools->Assign hot key then Insert->Icons->Icon by category...->Miscellaneous->Home
  2. Insert->Icons->Icon by category...->Miscellaneous->Home then Ctrl+click
  3. Help->Command Search and checkbox Icons and type "home" then Ctrl+double-click

Additionally, in Insert->Icons->Icon from table… (Ctrl+F2) you can Ctrl+click on an icon to assign it a ctrl key, i.e. a hot key which works only in this window and uses Ctrl as its (first) modifier. Shift can be used as the second one.

Keyboard Shortcuts

Ctrl+C

Beyond the usual functionality of copying selected text or copying a node (branch), Ctrl+C copies the selected item's text in the following places:

  • Command Search - Help->Command Search
  • Filter composer - Filter->Compose filter
  • Attributes table - Edit->Node properties->Edit attribute in-line (Alt+F9)
  • Find and replace - Edit->Find->Find and replace… (Ctrl+Shift+F)
  • FInd and replace in all maps - Edit->Find->Find and replace in all maps
  • Mange reminders - Tools->Manage tasks and reminders…
  • Past reminders - Tools->Show past reminders…

Mouse Actions with Keyboard Modifiers

Alt

  • You can change the width of a node under the cursor (or several selected nodes) by Alt+scroll

Ctrl

  • You can create a copy of a node (branch) by Ctrl+drag of a node onto another node
  • You can change Distance between children (in View->Controls->Tool panel > Node layout) by Ctrl+drag of a node handle away or towards the center of node's stack of siblings
  • You can follow a link by Ctrl+click, if Preferences…->Behaviour->Open node link on simple mouse click is off

Shift

Ctrl+Shift

  • You can create a connector to another node by Ctrl+Shift+drag of a node onto another node

Formatting maps and nodes

Map background

There are several options to change the map background: Format->Map background

  • Background color
  • Background image (with the option "fit to window")

Formatting nodes

The most straightforward way to format a node is to use the formatting toolbar or hot keys, like Ctrl+B for bold.

There's also Tool panel (right-hand-side panel), which lists all formatting properties that can be set on a node. It can be opened by right-clicking on the mind map background and selecting Tool panel.

In addition to formatting an entire node, it is possible to format each character/word in the node. It can be done by using the editor dialog Edit->Node core->Edit node core in dialog (Alt+Enter).

Note: It's also possible to use the hot keys in the in-line editor (e.g. Ctrl+L for blue).

Using Format

Format allows to apply a special data format, e.g. a special or number date format. If for instance a date has the standard format 28/12/2012 it can be reformatted as 12/28/2012 by applying the format mm/dd/yyyy to the node. See Data recognition and data formats for details.

Another application of the format is to define text templates, such as a prefix like "Beware: ". In text templates "%s" represent the original node text like in "Beware: %s".

By setting Format to Text you switch all formatting off. Text also disables formula evaluation.

Format can be set to LaTeX or Unparsed LaTeXLaTeX in Freeplane

Styles

Finally, a node can be formatted by applying a style to the node → styles

If you set the text of a node to a number or date in Freeplane it will likely be recognized specially. If you don't like that advance to How to switch data recognition off.

Numbers

If a number is recognized

  • a "123" symbol is displayed in the left corner of the status bar,
  • a standard format is applied to the number, so "0.123456" is displayed as "0.1235" by default (due to rounding).

Number formats

The default ("Standard") number format is "#0.####", i.e. at least one digit before and at most four digits after the decimal separator.

You can change the "Format" in the format panel (View -> Properties panel). There are two types of format patterns for numbers. You will probably use the Excel style formats like these (for a given input number 0.12345):

  • .## -> .12
  • 0.000000 -> 0.123450 (zero-padded)

An alternative formatter ("printf") style uses the percent sign specially, see Formatter documentation (again for a given input number 0.12345):

  • %f -> 0.123450 (standard decimal format)
  • %.07f -> 0.1234500
  • %d -> 0 (integer)

Language dependency of parsing and formatting

It depends on your language setting which character is used as decimal and grouping sign: In German setting "12.123" will be recognized as 12123 since in Germany "." groups Thousands while "," is used as decimal separator. In an English setting it's vice versa: "12,123" is 12123.

The number formats will automatically acknowledge a change in the language setting too: If a number is displayed as "0,1234" in German setting it will be displayed as "0.1234" after switching to English.

Dates

If a date is recognized

  • a calendar symbol is displayed in the left corner of the status bar,
  • a standard format is applied to the date which is dependent on the language setting, e.g. 12/28/12 or 28.12.12.

Simple input of dates

Input of dates is greatly simplified in Freeplane. Depending on your language setting try 28/12, 12/28 or 28.12 to insert a standard formatted date -12-28. For date-times just add the year and the time like "12/28/13 12:30" to get "2013-12-28 12:30".

Date formats

The default ("Standard") date format is "SHORT", that is a language setting dependent short date representation, e.g. 12/28/12 or 28.12.12. The default date-time format is "SHORT,SHORT" (short date, no seconds).

You can change the "Format" in the format panel (View -> Properties panel). The Excel style formats for dates use symbols y/M/d/H/m/s for year/month/day/hour/minute/second:

  • yyyy-MM-dd HH:mm -> 2012-12-28 12:31
  • MM/dd/yy -> 12/28/12

A "printf" style is also available for dates but more useful are the language setting depending shortcuts

  • SHORT
  • MEDIUM
  • LONG which unfortunately are currently only available in the configuration but not in the format panel. (This is considered a bug.)

Configuration

Configuration of formats

The personal standard formats are defined in Tools -> Preferences -> Behavior -> Data formatting and parsing. In the same place you can also choose a language setting for formats that differs from the standard language setting. That way you can e.g. enter English style numbers with '.' as the decimal separator while still having Dutch or German menus.

The predefined formats are defined in the file /formats.xml. Ask in the forum if you like to change them and need help on it.

Configuration of the parser

After editing a node text several parsers are tried in a defined sequence. When a parser succeeds to parse the text as a number or date the node set to the parsed value. Note that the whole text is matched. If for instance a number is followed by a word it's not considered a number.

Unlike formatting the parsing has no normal user configuration (beside the possibility to switch parsing on/off). The predefined parsers are defined in the file /scanner.xml. Ask in the forum if you like to change them and need help on it.

How to switch data recognition off

Sometime data recognition can lead to unwanted results. For instance if you have text that you want to make sure that it is entered verbatim without converting "2/3" into "2013-02-03" or "0228" into "228". In this case you have several, more or less drastic possibilities:

  • You can turn data recognition off completely under Preferences->Behavior->Data formatting and parsing.
  • You can change the node format from "Text" to switch data recognition off for one node.
  • If you start typing with a single quote, ', then the text format is changed to "Text" too.
  • You can change the map template "standard.mm". Set the format to "Text". Then all new maps have "Text" as the standard format.

Styles

A style is a bundle of formatting properties and icons, saved under a style name. Styles are saved in the map itself.

Note: Styles' properties can be viewed and changed in Format->Manage Styles->Edit stles (Ctrl+F11)style editing

Freeplane has several predefined styles, like Default, Floating node or Important, as well as Automatic level styles like Level 1, Level 2. A template might have additional styles, and any mind map created from such a template will inherit the template styles. Moreover, any mind map can have its own additional styles and/or delete some of the inherited ones.

A style can be applied to a selected node by choosing the style in Toolbar on in Tool panel.

By default, a node has no style assigned and Freeplane uses Default to format the node.

It's worth to note that there can be several styles active for a node. The most common scenario is that Automatic level styles are enabled in a map, usually painting each level a different color. Still, each node can be explicitly assigned a style, e.g. Important. Then formatting properties from both Level and Important will blend.

To better understand how formatting using styles works, one needs to know that Freeplane uses a concept of layered Styles.

Here's the order of precedence in applying the different layers.

  1. Character/word-level formatting
  2. Selected style
  3. Node individual formatting, including "automatic edge color: on branch creation"
  4. Explicitly applied style
  5. Node conditional styles
  6. Map conditional styles
  7. Automatic edge color: for branches / levels / columns
  8. Automatic level style
  9. Default style

Note: Selected style is only in effect if Preferences->Defaits->Selection colors->Display selected nodes in bubbles is off.

Default is the base layer. Whatever property is set on that layer will either shine through or be overwritten by the next layer put on top of Default. If Apply level styles is enabled, any formatting property (e.g. background color) set on an Automatic leve style (e.g. Level 1), will override properties set on Default. An explicitly applied style will overwrite the former two, and will be overwritten by node individual formatting, if set.

Style editing

To manage styles you need first to open the styles editor: Styles->Edit styles.
Result: a map containing all styles is displayed.

There you can modify all defined styles: either styles provided by default with Freeplane, or add/change your own styles. Note that's its allowed to remove default freeplane's styles.

To add your own style:

  • in the styles editor, choose the style with the nearest format of the style you want to create, right click on this style, select in the contextual menu Save as new style..., enter new style name.
    Result: a new style is added and appears in the user's styles branch.

You can now fully define the style with the formatting panel. Close the style editor. Your new style is available for immediate use in toolbar's style list. Tip: you can also create a new style from a main map's node with the command Styles->New style from selection.

To rename a user style:

  • in the styles editor, select you style, right click, select in the contextual menu Save as new style..., enter the new name you want, remove the old style entry.

To change the display order of styles in the main toolbar styles list:

  • in the styles editor, move up / down branchs or styles.

Pre-defined styles

Some predefined styles are available in Freeplane. You can either use them "as they are" or change them as it's convient for you. Two pre-defined styles named "Details" and "Notes" have a particular behaviour because they are used to format Node Details and Node Notes:

  • Font and colors of node details is controlled by style "Details"
  • Font of notes (not the color) is controlled by style "Notes".

Other style features

  • menu Styles->Copy styles... imports, in the current map, styles from an other mindmap.
  • menu Styles->Redefine style redefine node style based on current node formats. It changes formats of all nodes using this style.

Making styles available to other mind maps

For a style to be available in other mind maps, it needs to be saved in a template → templates

Templates

For a style to be available in other mind maps, it needs to be saved in a template. Once this is done, the style will be available in each new mind map created from that template.

There are 2 ways to do it

  1. Open the template mind map and add your new style there
  2. Add a new style to your regular mind map
    • In Tool panelMake current formatting default, after setting the properties of your new style, choose for all maps based on template: and click Apply
    • Use Choose template to change the association beforehand, if needed

File Paths for Templates

Depending on your OS, you can find template folders in different directories. However, on every OS, there is a subfolder in the Freeplane installation-folder, where you can store user-defined template files.

Note: You can also change the default directory containing the user configuration. This means, the file path for templates might be different in your Freeplane (see The user directory).

Windows

TODO

Linux

System-wide templates (when Freeplane is installed via the package manager of your distribution) are located in:

/usr/share/freeplane/resources/templates

User-defined templates can be found in:

~/.config/freeplane/VERSION/templates

MacOS

TODO

Set a default template file

The default template file will be used for every newly generated mind map. You can set the default template file in the preferences:

Tools > Preferences > Environment, Files > 'Standard template file'

The template files shown here as an option are those located in the system-wide path for template files.

Create a new map from a template

You can create a new mind map from a template file at File > New map from template…. In the dialogue you have different options, depending on which Files of Type you choose from the drop-down menu at the bottom of the dialogue:

Menu New map from template…

OptionDescription
All filesall filetypes (also non-mind-map files, which might give you an error)
Maps (*.mm)your mind maps, whose styling you want to use (see Styles)
Standard Templates (*.mm)the templates Freeplane comes with → system-wide path for template files
User templates (*.mm)your template mind maps → user-defined path for template files

Note: Depending on your current choice in the drop-down menu at the bottom of this dialogue, the path in the upper part changes accordingly:
If you click on Standard template (*.mm) it will show you the system-wide path for templates, if you click on User templates (*.mm) it will change to the user-defined path.

CSS For HTML/Markdown

Since 1.9.12 (Dec 2021)

HTML or Markdown content can be formatted using CSS.

Quick Start by Example

To get you started quickly, here's a simple CSS example for Markdown content.

  1. Insert a new node, adding the following text
# My Heading 1

Some text in my paragraph

> A sample quote
  1. Set the node's format to Markdown – View->Controls->Tool panel->Format->Core Text->Format = Markdown
  2. Add the following CSS – View->Controls->Tool panel->Format->Node Font->CSS->Edit CSS...
h1 {
  color: blue;
  font-weight: normal;
}
blockquote {
  color: green;
  font-style: italic;
}
  1. As a result, in your node you should see a blue heading, a regular paragraph and a green italic quote.

Sample Mind Map

Requires Freeplane 1.9.12 or higher

Node_CSS_Functionality.mm

CSS For Core Text

A node is formatted by CSS instructions in 2 cases:

  1. When CSS is added to the node – View->Controls->Tool panel->Format->Node Font->CSS->Edit CSS...
  2. When CSS is added to the Style applied to the node – Format->Manage styles->Edit styles | a Style | Node Font->CSS->Edit CSS...

When CSS is added to a node, CSS added to a Style (applied to the node) is ignored.

The following formatting properties can coexist with CSS-defined formatting:

  • Node Color -> Text
  • Node Color -> Background
  • Node Font -> Font family
  • Node Font -> Font size
  • Node Font -> Bold
  • Node Font -> Strike through
  • Node Font -> Italic
  • Node Font -> Text Alignment

Under the hood, these formatting properties are converted to CSS for body and applied alongside the CSS added to a Style or to a node.

More about CSS

  • https://www.w3schools.com/css/
  • https://peterxjang.com/blog/modern-css-explained-for-dinosaurs.html

Order Of CSS Application

Just like any web browser (Chrome, Firefox, Safari, etc), the Java library used by Freeplane has its own default CSS: https://github.com/openjdk/jdk/blob/master/src/java.desktop/share/classes/javax/swing/text/html/default.css

In addition to that, Freeplane adds its own CSS, overriding the formatting instructions from the Java default CSS:

p { margin-top:0; }
table { border: 0; border-spacing: 0; }
th, td { border: 1px solid; }

Next, the CSS created based on formatting properties is used, overriding any previous instructions for body, and finally the CSS added to the Style or to the node is applied, overriding any other CSS instructions.

When CSS is added to Default, it affects node-core HTML/Markdown of all nodes where Default is applied.

When CSS is added to a Style, CSS added to Default is ignored for that Style.

When CSS is added to a node, CSS added to a Style (applied to the node) is ignored.

CSS For Details And Note

CSS can be added to Details and to Note, making it possible to specify detailed formatting for their HTML/Markdown content.

  • Format->Manage Styles->Edit styles | Details | Node Font->CSS->Edit CSS...
  • Format->Manage Styles->Edit styles | Note | Node Font->CSS->Edit CSS...

CSS added to Details will affect node-details HTML/Markdown of all nodes in the map.
Similarly, CSS added to Note will affect note HTML/Markdown of all nodes in the map.

Note that when CSS is added to Default, it is also applied to Details and Note. To make Details or Note ignore CSS added to Default and use only its formatting properties, add "empty" CSS (e.g. a space) to Details or Note respectively. This is because when CSS is added to a Style (here to Details or to Note), CSS added to Default is ignored for that Style.

Example Of Markdown With CSS

Given the following Markdown document:

# Heading 1
Regular text.
**Bold text.** *Italic text.* ***Both: bold and italic.***

A line (horizontal ruler) using underscores:
___

<s>Strike through</s> NB. using `~~deleted text~~` doesn't work in Freeplane (Java html/css renderer)

E.g. ~~deleted text~~

<u>Underlined text</u>

## Heading 2
> A quote, line 1.
> Line 2 of the quote (will be joined with line 1).
>> A quote within a quote

### Heading 3
Sample text with `an in-line piece of code`.

```groovy
// a Groovy code example - as a block of code
def name = 'Freeplane User'
"Hello, ${name}!"
```

    Another example of a block of code
    introduced as indented Markdown (with a tab or 4 spaces)

>     An example of a quote
>     containing a block of code
>     At least 5 spaces need to be used
> And it continues as a regular quote

#### Heading 4
A table

| # | Language | [Pangram](https://en.wikipedia.org/wiki/Pangram) |
|--|--|--|
| 1 | English | The quick brown fox jumps over the lazy dog |
| 2 | French | Portez ce vieux whisky au juge blond qui fume |
| 3 | German | Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich |
| 4 | Italian | Pranzo d'acqua fa volti sghembi |
| 5 | Spanish | Benjamín pidió una bebida de kiwi y fresa. Noé, sin vergüenza, la más exquisita champaña del menú |

##### Heading 5
A list of items

* Item 1
* Item 2
* Item 3

###### Heading 6
A numbered list

1. Item A
2. Item B
3. Item C

and keeping in mind that it will be converted to the following HTML:

<html>
<head></head>
<body>
    <h1 id="heading-1">Heading 1</h1>
    <p>Regular text. <strong>Bold text.</strong> <em>Italic text.</em> <strong><em>Both: bold and italic.</em></strong>
    </p>
    <p>A line (horizontal ruler) using underscores:</p>
    <hr>
    <p><s>Strike through</s> NB. using <code>~~deleted text~~</code> doesn&#39;t work in Freeplane (Java html/css
        renderer)</p>
    <p>E.g. <del>deleted text</del></p>
    <p><u>Underlined text</u></p>
    <h2 id="heading-2">Heading 2</h2>
    <blockquote>
        <p>A quote, line 1.
            Line 2 of the quote (will be joined with line 1).</p>
        <blockquote>
            <p>A quote within a quote</p>
        </blockquote>
    </blockquote>
    <h3 id="heading-3">Heading 3</h3>
    <p>Sample text with <code>an in-line piece of code</code>.</p>
    <pre><code class="lang-groovy">// a Groovy code example - as a block of code
def name = &#39;Freeplane User&#39;
&quot;Hello, ${name}!&quot;
</code></pre>
    <pre><code>Another example of a block of code
introduced as indented Markdown (with a tab or 4 spaces)
</code></pre>
    <blockquote>
        <pre><code>An example of a quote
containing a block of code
At least 5 spaces need to be used
</code></pre>
        <p>And it continues as a regular quote</p>
    </blockquote>
    <h4 id="heading-4">Heading 4</h4>
    <p>A table</p>
    <table>
        <thead>
            <tr>
                <th>#</th>
                <th>Language</th>
                <th><a href="https://en.wikipedia.org/wiki/Pangram">Pangram</a></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>1</td>
                <td>English</td>
                <td>The quick brown fox jumps over the lazy dog</td>
            </tr>
            <tr>
                <td>2</td>
                <td>French</td>
                <td>Portez ce vieux whisky au juge blond qui fume</td>
            </tr>
            <tr>
                <td>3</td>
                <td>German</td>
                <td>Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich</td>
            </tr>
            <tr>
                <td>4</td>
                <td>Italian</td>
                <td>Pranzo d&#39;acqua fa volti sghembi</td>
            </tr>
            <tr>
                <td>5</td>
                <td>Spanish</td>
                <td>Benjamín pidió una bebida de kiwi y fresa. Noé, sin vergüenza, la más exquisita champaña del menú
                </td>
            </tr>
        </tbody>
    </table>
    <h5 id="heading-5">Heading 5</h5>
    <p>A list of items</p>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
    <h6 id="heading-6">Heading 6</h6>
    <p>A numbered list</p>
    <ol>
        <li>Item A</li>
        <li>Item B</li>
        <li>Item C</li>
    </ol>
</body>
</html>

the following CSS can be applied to the node to format the Markdown content:

h1, h2, h3, h4, h5, h6 {
  background: #D4D4D4;
  border-top: 1px solid gray;
  border-bottom: 1px solid gray;
  font-weight: normal;
  padding-left: 2px;
  padding-right: 2px;
}
blockquote {
  background: #E6F2E6;
  border-left: 3px solid #408040;
  font-style: italic;
  padding-left: 5px;
  margin-left: 2px;
}
pre {
  background: #E0F0FF;
  border-left: 5px solid #55AAFF;
  padding: 5px;
  margin-left: 2px;
}
code {
  background: #E0F0FF;
  font-family: JetBrains Mono NL, Courier New, Monospaced;
  font-size: 0.9em;
}
table {
  border-spacing: 0px;
  border-right: 1px solid gray;
  border-bottom: 1px solid gray;
}
th, td {
  border-left: 1px solid gray;
  border-top: 1px solid gray;
}
th {
  background: #D4D4D4;
  font-weight: 600;
}
ul {
  margin-left-ltr: 20px;
  margin-right-rtl: 20px;
}
ol {
  margin-left-ltr: 25px;
  margin-right-rtl: 25px;
}

Nodes have several characteristics (colors, shapes, text content, icons, etc). The users of FreePlane can create rules to automatically associate a certain characteristic with a certain style. So this kind of rule works like this: if the node has this characteristic, then apply that style on it.

The rules for automatic node formatting consist of a condition like the conditions used for filters and a style name. Thus, node formatting can depend on its content, attributes, icons or level. They can be set using Format->Manage Styles->Manage conditional styles for map/node.

Multiple styles simultaneously applied to one node

Because each style may set only some of the formatting attributes, the resulting node formatting is a sum of formats defined by explicitly set format, explicitly assigned style and all matching conditional styles.

So if there is more than one conditional style, all those styles that satisfy given conditions are applied resulting each node to be formatted by a composition of multiple styles. Here, if different styles set different properties, all of them are applied to a node; otherwise the upper style has higher priority.

Read more about the layering of styles in the page styles of the documentation.

The Stop button

image

The list in the Conditional Styles list can be thought of as a list of tasks that the user gives to FreePlane. FreePlane goes through each node of the map and executes all the tasks of the list on the node.

Each task is like this: if the node has this characteristic, then apply that style on it.

When Freeplane does the task on a node, this is what happens:

  • if the node doesn't have the characteristic, Freeplane interprets condition to be : false and proceeds with the next task
  • if the node has the characteristic, it interprets condition to be true, then applies the style and proceeds with the next task

So, in both cases, Freeplane continues for the next task.

What the Stop button does is it creates a rule: if, in this task, you conclude true, then don't continue to the next task. So, if that happens, FreePlane stops in the middle of the list of tasks, instead of going through all of it, as usual. Notice that it only happens if there is a true conclusion in the task where the Stop option is activated.

Video and Diagram explanation

You can have a look at demo video of Conditional Styles (with and without the STOP option), and a resume diagram.

FreeplaneConditionalStyle_161113_222746.png}}

Freeplane 1.2.x supports LaTeX formulae in boxes underneath nodes while Freeplane 1.3.x deprecates those boxes and adds LaTeX directly to node contents. Please see the relevant subsections below.

Thanks to the excellent JLaTeXMath!

LaTeX Text+Formulae in Freeplane >1.3.x =

  • LaTeX text is displayed inline in node content (as opposed to underneath nodes in 1.2.x)
  • You can tell Freeplane to treat a node as LaTeX text by either:
    • using a "\latex " ("\latex" + ) prefix
    • View->Controls->Tool panel (previously View->Properties panel), then Core text->Format->LaTeX
  • By default the LaTeX interpreter is in text mode, so you need to use $...$ for (inline) formulae
  • Automatic linebreaks are supported
  • The editor supports LaTeX syntax highlighting

Example:

\latex my formula: $x_2=\frac{1}{2}$

Common/global LaTeX Macros

Freeplane has a textbox in preferences->Plugins->LaTeX that allows you to enter code (usually macros) that will be inserted into every LaTeX node before the actual node content. Be aware though, that using this means that your map will only be readable by someone else if he/she also includes the macros in his/her config!

"Unparsed LaTex" (LaTeX for Export)

JLaTeXMath, the component used by Freeplane for rendering LaTeX, is focused on math and thus does not support i.e. itemize or enumerate and more. However, some people want to export complete LaTeX documents, including code not supported by JLaTeXMath, and if you try to use unsupported LaTeX in LaTeX nodes (Format=LaTeX or node prefix "\latex"), then this will be correctly exported but you will get ugly error boxes in Freeplane.

In order to solve this, we have added Format="Unparsed LaTeX" (translation may be different) and the node prefix "\unparsedlatex" (for symmetry, will not be translated). Nodes designated like this will use LaTeX syntax highlighting and will be exported correctly, but will not be rendered with JLaTeXMath.

Including LaTeX content from file system

If your node matches the pattern

\latexinput{<file>}

then Freeplane will include the given file at the given position in the LaTeX export. Note that the export will fail if the document cannot be read.

Caveat: The file must be a well-formed XML document, so you must have a root tag and escape <, > and & (<, >, &), like this:

<doc>
\begin{tabular}{cc}
1 &amp;amp; 2 \\
3 &amp;amp; 4 \\
\end{tabular}
</doc>

Combination of LaTeX and Groovy formulas

Here's how to format formula results as LaTeX:

  1. Set node format to LaTeX.
  2. Let your formula generate LaTeX code.

Example (copy 'n paste it into a map)

="\\LaTeX: \$\\sum_{children} = ${children.sum(0)}\$"
2
3
4

Note that LaTeX symbol \ has to be doubled in a double quoted string and that a $ have to be escaped with a single \ to prevent Groovy from interpreting it as the prefix of a variable.

Known Problems

  • Array environments are maximized on the maximum node width
  • align=right and align=center does not work well
  • The syntax highlighting editor has problems with some unicode/chinese characters. If you experience this, turn off the editor in prefs->Plugins->LaTeX (Freeplane will then use the normal editor for LaTeX).

Customizing LaTeX Export

  • Copy <installation_dir>/resources/xslt/mm2latex*.xsl to /xslt (you can find with Tools->Open user directory)
  • You need all three because mm2latexartcl.xsl and mm2latexbook.xsl include mm2latexinput.xsl
  • Adapt your export script (usually document: mm2latexartcl.xsl, book: mm2latexbook.xsl, or input: mm2latexinput.xsl)
  • Restart freeplane --> the new export scripts will be used

Other Export solutions

There are many XSLT scripts out there; here is one from Igor Gartzia Olaizola that integrates well with Freeplane and also allows to export to LaTeX Beamer presentations: https://sites.google.com/site/freemind2beamer/. The source code is on github.

LaTeX Formulae in Freeplane 1.2.x

This type of LaTeX formulae in Freeplane is deprecated in Freeplane 1.3.x (the formula boxes will still be displayed and can be edited but you can't add new boxes)! Please see the 1.3.x section above if you're using Freeplane 1.3.x.

  • you can add a LaTeX formula to a node by running Edit->Node Extensions->Add LaTeX formula...
  • you can edit a LaTeX formula related to a node by running Edit->Node Extensions->Edit LaTeX formula...
  • you can remove a LaTeX formula by selecting Edit->Node Extensions->Remove LaTeX formula OR by using Edit->Node Extensions->Edit LaTeX formula... and specifying an empty text.
  • by default the LaTeX interpreter is in math mode
  • does not support automatic linebreaks

Example:

x_2=\frac{1}{2}

Spell checker how-to

To enable spell checking, select one of the supported languages using pop-up menu→languages→[your language]. from any editor.

Some spell checker options can be configured from Preferences->Behavior->Spell checker options.

User can add his personal words for a particular language from the context menu on word selection. The first time user adds a custom word, a user dictionary file is automatically generated in UserDictionary_XX.txt (where XX is the language code, for instance UserDictionary_en.txt stores english custom words). This text file can be created or edited with any text editor for instance to add new words in a bulk way or to remove a custom word added by error.

You can install another dictionaries copying them into <freeplane-install>/resources/ortho. The dictionary files dictionary_XX.ortho converted from aspell are available on http://sourceforge.net/projects/freeplane/files/spell_check_dictionaries/ .

Introduction

In the following the origin of Freeplane is described. Since then Freeplane has got and is still is getting new functionality at a rapid speed, while keeping the easy way of working which is known from Freemind, see Freeplane's home page. The power of this new functionality is shown by the Quick reference and Documentation, which are themselves mind maps. In addition there is a growing base of didactic maps in the wiki Tutorial Freeplane.

Why fork?

There was much discussion and reflection before the decision was made to fork a project as popular as FreeMind. There were two main areas where no internal agreement could be reached after years of discussion:

Software Architecture

Freeplane's code has been refactored considerably to create a highly modular, clear and logical design, to ease entrance into development and to provide a solid foundation for long term development. As there was disagreement on this, it was decided that Dimitry would start work on a fork, while Chris develops the existing codebase, to see where this would lead. It is possible the two projects will merge in the future, no one knows. At the moment we feel that Freeplane offers an exciting opportunity for developers to help create a lean and extensible open source framework for mind mapping.

Development Process

(i) release cycle

It was felt that the FreeMind release cycle was too slow, and that this was holding the project back. Freeplane aims for regular releases, this will probably mean a stable release every six months.

(ii) community driven development

It was felt that the current FreeMind set up was not doing enough both to promote and integrate community contributions. Freeplane aims to create a contribution friendly climate. We hope to ensure that contributions do not go to waste. If you can contribute, and your ideas are not wildly out of sync with the vision of the developers, then your contribution will be rapidly integrated and included in the new release.

Relationship to FreeMind

We are not aiming to divide sentiment or users. Freeplane is not positioning itself against FreeMind. We understand that FreeMind has many loyal users, and that this is because it is such as good product. Many of the team members contribute in some capacity to both projects, though the lead developers obviously concentrate their energies more on one project. If Freeplane's approach turns out to have advantages, then this will be of benefit to users, and create a more satisfying project for developers.

References to other known documentation/tutorial sites

Documentation mind maps distributed with Freeplane

  • Tutorial mind map
  • Documentation mind map
  • What's new in Freeplane 1.5 mind map

Videos

Forums

Freeplane Discussions > Category: shared-mind-maps

Freeplane Code Explorer Mode Documentation

Introduction

The Code Explorer mode in Freeplane is designed for analyzing the structure and dependencies of code compiled to JVM class files.

Code map

Accessing Code Explorer Mode

  1. Launch Freeplane version 1.11.12 or later.
  2. Navigate to the menu bar at the top of the application.
  3. Click on Maps.
  4. Select Modes.
  5. Choose Code Explorer to enter the code explorer mode.

Video Tutorials

Video tutorials are available to help users familiarize themselves with the Code Explorer mode. To access the tutorial, click here or navigate to the Help menu within Freeplane and select Help -> Code Explorer Introduction Video.

Configurations Panel

Configurations Tab

The Configurations tab allows users to manage their configurations and consists of three parts: configurations, locations, and rules.

Configurations

  • Add Configuration: Click this button to create a new configuration.
  • Delete Configuration: Use this button to remove the currently selected configuration.
  • Run Analysis: Initiates the analysis process, loading and importing class files.
  • Apply Changes: Attempts to apply only rule changes without reloading class files, if there are no location changes.
  • Cancel: Allows users to cancel an analysis that has started but not yet finished.

Locations

  • Add JARs and Folders: This button allows you to add new JAR files or folders to your configuration.
  • Remove Selected Locations: This button will remove the currently selected locations from your configuration.
  • Ordering Buttons: Adjust the priority order of locations, affecting which classes are imported when duplicates exist.
Location Details in Code Explorer

When adding locations for analysis in the Code Explorer mode, Freeplane processes directories differently based on their contents:

  • Maven Projects: If the location is a directory containing a pom.xml file, Freeplane recognizes it as a Maven project. It will then look for class files specifically in the target/classes/** directory structure.

  • Gradle Projects: If the location is a directory containing a build.gradle file, Freeplane identifies it as a Gradle project. It will search for class files within the build/classes/** directory structure.

  • Other Cases: If the directory does not contain pom.xml or build.gradle, Freeplane will search for any .class files contained within any subdirectories.

This behavior allows Freeplane to adapt to different project structures and build systems, ensuring that only the relevant class files are included in the analysis.

Rules

Rules in the Code Explorer mode are used to specify allowed and forbidden dependencies, among other settings. Rules are defined in the following formats:

[command] [originPattern] [direction] [targetPattern]
classpath [path]
ignore class [classPattern]
import interface [classPattern]
import annotation [classPattern].[methodName]()
group [classPattern]
group [classPattern] as [group name]
ignore group [classPattern]
  • Revert: Undoes the last change made to the rule configuration.
  • Help: Provides documentation related to creating and managing rules.

Analysis Results

After running an analysis with the "Run Analysis" button, the result is represented as an interactive mind map that visualizes all packages and classes.

Mind Map Structure

  • Packages and Classes: Displayed in a hierarchical format, with packages expanding to reveal classes contained within them.
  • Dependencies: Represented as connectors between nodes on the mind map. All mind map nodes are automatically sorted to ensure that as many dependencies as possible are visualized as going down in the mind map. This sorting strategy aims to minimize the visual complexity and enhance the readability of the dependency graph. Dependencies that are depicted as going up in the mind map are significant as they always indicate the presence of dependency cycles. This visual cue helps in quickly identifying areas in the codebase that might require refactoring to eliminate circular dependencies.
  • Forbidden Dependencies: Illustrated with red lines, these dependencies are configured in the rules to be disallowed.

Dependencies Tab

Dependencies

The Dependencies tab dynamically updates with information as the selection within the mind map changes. It provides a detailed list of dependencies including verdict, origin, target, and the specific details about the nature of the dependency.

Filtering Dependencies

  • The filter input field allows users to filter the list of dependencies by entering keywords or by specifying a column for searching using the format column:keyword.

Rules Configuration in Code Explorer

Rules in the Code Explorer mode are pivotal for controlling how the application interprets the dependencies and structure within a JVM-compiled codebase. These rules are versatile, catering to a broad spectrum of analysis needs, from dependency management to enhancing the visibility of specific code elements within the mind map.

Rule Definition Format

Rules are articulated on a per-line basis, conforming to formats that accommodate various directives, such as managing dependencies, augmenting the classpath, and more nuanced configurations like ignoring or grouping classes:

  • Dependency directives: [command] [originPattern] [direction] [targetPattern]
  • Augmenting classpath: classpath [path]
  • Class-specific directives: ignore class [classPattern], import interface [classPattern], import annotation [classPattern], import annotation [classPattern].[methodName]()
  • Grouping directives: group [classPattern], group [classPattern] as [group name]
  • Ignoring groups: ignore group [classPattern]

Commands for Dependency Management

Specific commands within the rules are designed to directly influence how dependencies are managed:

  • allow, forbid, ignore, group: These commands serve as the foundation for defining allowed and forbidden dependencies, excluding specific dependencies from analysis, and organizing Java classes into logical groupings, respectively.

Direction Indicators

Dependency directions are denoted by symbols that indicate the nature of the dependency flow:

  • ->: Represents a dependency that can go up or down in the mind map, aligning with the automatic sorting of nodes to optimize the visualization of dependencies.
  • ->^: Indicates a dependency going up in the mind map, highlighting dependency cycles.
  • ->v: Signifies a dependency going down in the mind map, following the natural flow of most dependencies after nodes are automatically sorted.

Pattern Syntax

The syntax for patterns in rules utilizes an AspectJ-like formulation, enabling precise matching against package and class names for a targeted analysis.

Group Commands

  • ignore group [classPattern]: Excludes all classes matching the class pattern from dependency analysis. This command is useful for omitting specific groups of classes, such as test classes, from cluttering the analysis results.
  • group [classPattern] as [group name]: Groups all classes matching the class pattern under a custom name. This name appears in the mind map, enhancing the organization of the analysis results. When parts of the class pattern are enclosed in round brackets, they are captured and appended to the group name, separated by a colon if there is more than one part. This feature allows for a dynamic and descriptive naming of groups based on the matched class structure.

For example, with the rules:

group (hudson|jenkins).(triggers|views)..
group .. as rest

Classes within the hudson or jenkins package trees and belonging to either the triggers or views subtrees will be grouped accordingly. Unmatched classes will be grouped under the name rest. In the mind map, this results in groups named hudson:triggers, hudson:views, jenkins:triggers, and jenkins:views, clarifying the organization of the codebase at a glance.

Jenkins Example

Utilizing Classpath

Multiple classpath directives can be declared to specify the directories to be scanned for classes, superseding the default directories (target/classes, build/classes, .), thus offering flexibility in accommodating various project structures.

Usage Notes

  • Comments: Lines prefixed with # or // are treated as comments and ignored, allowing for annotations within the rules file.
  • The AspectJ-like pattern matching system underpins the flexibility in specifying classes, interfaces, annotations, and groups, ensuring that the rules can be finely tuned to the project’s specific requirements.

By addressing these aspects, the documentation now comprehensively covers the functionalities related to rules within the Code Explorer mode, including the previously omitted details about group management and pattern usage.

Class Filters and Dependency Exploration Options

Available in both the toolbar and the "Explore" menu, Freeplane's Code Explorer mode offers a comprehensive set of actions for quickly applying special filters related to dependency analysis. These actions can be used in combination with the general filter tools on the toolbar and within the filter menu for an in-depth analysis. The "Explore" menu extends these capabilities, providing additional actions for more advanced analysis and allowing for a more detailed exploration of the code's structure and dependencies.

"Show Dependencies Going Outside" Toggle

The "Show dependencies going outside" function in the Code Explorer mode is a toggle button that changes the scope of the dependency analysis:

  • When selected: Freeplane will analyze dependencies that extend beyond the currently selected nodes. This includes any external dependencies that classes, packages, or package trees have with nodes outside of the selected scope.

  • When not selected: The analysis will focus on the dependencies between the selected nodes only, ignoring any external connections.

Users can activate or deactivate this toggle at any time to adjust the analysis to either include or exclude external dependencies based on their current requirements.

Filtering by External Dependencies

The "Filter by external dependencies" action, available in both the toolbar and the Explore menu, is influenced by the "Show dependencies going outside" toggle:

  • With the toggle selected: Applying the filter will cause Freeplane to display only the classes that have dependencies going outside the selected nodes. All other classes and their corresponding packages that do not have external dependencies will be hidden from view.

  • With the toggle not selected: When this filter is applied, it will only keep visible the classes that have dependencies between them within the selected scope. Classes that do not have internal dependencies within the selected nodes will be hidden.

This feature allows users to concentrate on the classes that interact with external components or those that interact within a defined scope, depending on the analysis requirement.

Actions for Revealing Classes

In the Code Explorer mode, a suite of actions is available to reveal dependencies of nodes. These actions become helpful after applying a filter, enabling a focused analysis on specific classes.

Toolbar Actions

On the toolbar, there are actions to reveal dependencies for the selected nodes:

  • Show Direct Subclasses and Subinterfaces of the Selected Nodes: Reveals nodes that are subclasses or subinterfaces directly extending or implementing the selected nodes, providing a focused, immediate view of the inheritance structure.
  • Show Subclasse and Subinterface Hierarchy of the Selected Nodes: Reveals nodes that represent the full subclass and subinterface hierarchy of the selected nodes, displaying both direct and indirect descendants in the inheritance chain.
  • Show Direct Superclasses and Superinterfaces of the Selected Nodes: Reveals nodes that are superclasses or superinterfaces from which the selected nodes directly inherit or extend, offering a direct view of parent classes or interfaces.
  • Show Superclass and Superinterface Hierarchy of the Selected Nodes: Reveals nodes that encompass the complete superclass and superinterface hierarchy above the selected nodes, tracing all hierarchical layers back to the top-level ancestors.
  • Show Incoming Dependencies of the Selected Nodes: Reveals nodes that are direct or recursive dependencies entering the selected nodes.
  • Show Outgoing Dependencies of the Selected Nodes: Reveals nodes that are direct or recursive dependencies exiting the selected nodes.
  • Show Connected Dependencies of the Selected Nodes: Reveals nodes that have direct or recursive dependencies connected to the selected nodes.

These actions on the toolbar allow users to visualize the dependencies in a more targeted manner.

Explore Menu Actions

The Explore menu offers additional actions that include the capabilities of the toolbar and further:

  • Actions to reveal dependencies for all visible nodes, not just the selected ones. This provides a broader view of the codebase's architecture.
  • Options to reveal both direct and recursive dependencies, offering a detailed exploration of the code structure.

These menu actions are helpful for expanding the analysis to understand the broader context of the dependencies within the entire visible code structure. By leveraging these tools, users can deepen their understanding of the interdependencies within their codebase.

Cyclic Dependencies Analysis

In the Code Explorer mode, Freeplane includes actions to analyze and visualize cyclic dependencies involving the selected classes or packages.

Toolbar and Explore Menu Actions

  • Filter selected nodes by selected element cycles: When this action is triggered, Freeplane checks for cyclic dependencies that include the selected class or package. If a cycle is found, the view is updated to hide all classes and packages that are not part of the cycle, making the cycle's structure clear and focused.
  • Select nodes by selected element cycles: This action also checks for cyclic dependencies. If it identifies a cycle, it selects all classes and packages that are part of the cycle within the mind map. If no cycles are found, there will be no change to the selection or visibility of the nodes.

These actions are useful for pinpointing and resolving cyclic dependencies, which are often indicators of potential design issues that can complicate the maintainability of a codebase. By utilizing these features, developers can ensure their code's architecture adheres to best practices and remains clean and manageable.

Arch Unit Test Result Viewer

Introduction

The Architecture Violations feature in Freeplane's Code Explorer mode is used to capture and display rule violations that are identified during the code analysis process. This is specifically related to the integration with the Freeplane ArchUnit extension.

Architecture Violations Tab

Architecture Violations

Overview

The Architecture Violations tab provides a mechanism to record and display violations reported by the ArchUnit tests.

Buttons and Their Functions

  • Record ArchUnit Test Results: This button starts a listener that receives test results from the Freeplane ArchUnit Extension.
  • Delete Configuration: Removes the currently selected violation configuration.
  • Run Analysis: Performs the analysis again to detect architecture violations. Double-click on the configuration has the same result.
  • Cancel: Halts any ongoing analysis process.

Violations Reporting

  • Violated rules are reported and can be visualized as maps within the Architecture Violations tab.
  • These violations are not saved across Freeplane restarts and are only available during the current session.

Additional Information

  • For persistent records of violations, users should manually save or document the information prior to exiting Freeplane.
  • Detailed setup and usage guidelines for the Freeplane ArchUnit Extension are available on its GitHub repository.

Note

Please ensure that the Freeplane ArchUnit Extension is correctly installed and configured to utilize the Architecture Violations feature effectively.

Freeplane does not start

  • Check that the java runtime environment is installed. Sun JRE 1.6 or later is recommended.
  • Run freeplane.bat (under linux run freeplane.sh) from a shell and look at the output printed there. If you can not understand the reasons for failure yourself, open a bug request and post there the output.

Freeplane throws out-of-memory exception

You can increase memory available to Freeplane by setting Java VM option -Xmx to higher values

Examples: -Xmx1024M (1024 MB) -Xmx2G (2 GB) -Xmx8G (8 GB)

Depending on your OS the configuration can be changed at different places.

Windows

Add line

-Xmx4G

to files freeplane.l4j.ini and freeplaneConsole.l4j.ini which are used when you start freeplane.exe or freeplaneConsole.exe.

If you use freeplane.bat you need to configure this option there.

Mac OS

Go to Application==> Left click on specific application (like Weka)==> Show Package Content==> Contents==>app

Edit file Freeplane.cfg ane replace any of lines

java-options=-XX:MaxRAM=...
java-options=-XX:MaxRAMPercentage=...
java-options=-Xmx...

by line

java-options=-Xmx4G

Save the changes.

Linux

Edit freeplane.sh and replace -Xmx... by whatever value you need.

Graphics Issues with the UI

Try disabling the DirectDraw pipeline by adding the following flag to your Freeplane options (freeplane.l4j.ini and freeplaneConsole.l4j.ini on Windows, freeplane.sh on Linux):

-Dsun.java2d.noddraw=true

For explanations and other configuration options you can try, see this documentation.

Performance issues when scrolling/selecting nodes

Try to use OpenGL rendering instead of Direct3D by adding the following flag into your Freeplane options (freeplane.l4j.ini and freeplaneConsole.l4j.ini on Windows, freeplane.sh on Linux)

-Dsun.java2d.d3d=false

Html text and images can not be pasted from Web pages in nodes and notes on Linux

It is a java issue on linux. Use Firefox for Windows with Wine.

Nodes are not displayed properly on linux if the map is zoomed

Install the latest sun java from http://www.java.com/de/download/. The open jdk behaves buggy and is also significantly slower.

I cannot find the spell check function

The spell checker has to be enabled, see the Spell checker how-to.

The editor freezes

Create an entry in Bugs and provide as much information as possible about the conditions under which the behavior occurs:

  • Does it happen always if you do ...?
  • Is there a dependency on the size of the loaded map(s)?
  • Post the output of "java -version" (it contains the build number)
  • Do you have something special in your environment?
  • Is Freeplane consuming computation power when it freezes or not?
  • Before the freeze, was there any activity in the logfile? At least if there is anything suspicious, please post the logfile.
  • Can you stop it with normal means (close window, send SIGTERM, ...)?
  • Try a downgrade to an older Freeplane version - does that help?

It would be of great help in any case if you would provide a listing ("stacktrace") of what Freeplane is currently doing when it freezes by using the jstack tool. Find out the process id (PID) of the Freeplane Java process instance via Taskmanager, top, ps or whatever tool. Let's assume that the PID is 2345. Please post the output of

jstack -l 2345

(You have to replace "2345" with the real PID.) For comparison also post the jstack output of Freeplane before the freeze (if possible). As you can easily check by inspecting the output it's pure technical stuff, nothing of your private mindmap is contained in it. Unfortunately you have to have the JDK installed to use jstack (the JRE wouldn't suffice). Please tell us, if you cannot install the JDK for some reason. - We might be able to help.

For more on jstack see its Sun documentation.

How to Start Contributing

Freeplane is developed and maintained by volunteers who want to share their passion and skills with the world. The project was launched by its current lead Dimitry Polivaev in 2007.

You can participate not only as user and community member but maybe as a

  • developer (coder and designer)
  • tester (writer of tutorials, screencasts and help texts)
  • translator (various languages)
  • forum moderator (care for a specific subject)

We're currently looking for contributors for developing the documentation. If you can write simple step-by-step guides, translate existing text into English, transfer text from our old documentation into the new one, then we could use your help. You can start a discussion post (in the docs project) saying you want to contribute to the documentation and the Freeplane team will respond and assist you.

If you have other ways of contributing: developing an addon, sharing your pre-configured mindmap, or suggestions about future development, please feel free to join us in the Discussions

Every contributor or team member freely decides what task they are going to work on. However, for making the best decision regarding development, it's advised that we first propose and suggest the idea to the community through a discussion post as to enable early discussion and community feedback.

This page will give you all the information you need to translate Freeplane into your own language.

Freeplane GUI translation and improvement

This How-To section describes the tools and (alternative) processes for Freeplane GUI translation. This concerns the translation of all the English source strings displayed in the Freeplane interface, especially in menus and dialogs.

English is the source language for all translations, so you need to know English to be a translator.

UI designers need to be able to improve the UI by improving the existing English source strings and by adding new tool tips. Since they use the same tools and almost the same processes, these processes are also described here.

This How-To uses the following conventions and terms:

  • Language code: 'xx' in any file name or URL means the two letter language code of the language you are translating to. So you have to replace it by that language code to make it work.

  • Your language page: https://hosted.weblate.org/projects/freeplane/translation/xx/, Weblate page that gives an overview of the translation of Freeplane to your language. For details see Weblate

  • Your translation item: An untranslated English source string that you would like to translate or an existing translation that you would like to improve.

  • Translate page: Weblate page where you can edit your translation item, see How to translate

  • Translation key: This is a unique text string that links a certain English source string to all its translations and defines the location where the source string or its translation is displayed in the user interface.

  • File separator: '/' (forward slash) is used as file separator in the display of paths in order to be compatible with all relevant operating systems. '' (backward slash) is the default in Windows, but '/' will work as well.

  • Freeplane user directory: preceding any file name is the path to the Freeplane user directory. This path ends in /Freeplane/1.5.x/ where the last subdirectory varies between major releases. You can open this directory in your file manager via the Freeplane menu Tools > Open user directory.

If you have any questions or suggestions with regard to this part of the How-To, post them at the thread Questions about translating Freeplane via the Weblate tool

Tools: Weblate and Freeplane translation editor

Weblate

Since version 1.3.x Freeplane uses a collaborative web based translation tool developed by Michal Čihař. For all described processes the translations are entered or imported in Weblate (except for new tool tips which are merged directly into git). From Weblate all new and changed are committed to the Freeplane git release branch. Weblate stays in sync with the Freeplane git release branche, so any committed new tool tip or other new translation key and its English source string are immediately available for translation in Weblate. With every new Freeplane release the current state of the Freeplane translation in Weblate is also released.

In order to get started as a Freeplane translator or UI designer in Weblate you need to know and do a few things:

  • You can find the Freeplane Weblate project page here: http://hosted.weblate.org/projects/freeplane.

  • If you have not registered for Weblate yet, you need to do so by clicking 'Register' in the top-right corner and following the instructions.

  • It is important that you know how to find your language page, i.e. the Freeplane Weblate page that gives an overview of the translation to your language, has some handy filters for strings to check and has the menu items Search and Files that we are going to use in this How-To:

    • On the Freeplane Weblate project page, click component Translation and then on your language
    • If in your Weblate profile you specify your translated language and subscribe to the Freeplane project, a link to this page appears in your Weblate Dashboard
    • The web address of this page is https://hosted.weblate.org/projects/freeplane/translation/xx/ where 'xx' is the 2-letter code for your language.
  • You need to get yourself familiar with Weblate functionality, so take a look at the Weblate translator guide and keep it as a reference next to this How-To.

If you find bugs on the Weblate tool, you can report them here.

Freeplane translation editor

The Freeplane translation editor is a tool for translators and UI designers that is available in the Freeplane GUI. It is included in Freeplane v1.5.16 or higher and is enabled by installing the User Translation Support add-on.

The translation editor appears when you press Crtr+Shift+F10 while your mouse is hovering above the text of your translation item. It shows a translation window for the text string and, if applicable, for the tool tip associated with the text string. You can choose to do one of 2 things:

  • You can choose to translate in the translation window itself (i.e. offline translation). When you close Freeplane, all translated items are stored in a local file: UserResources_xx.properties, that can be uploaded to Weblate.
  • Or you can choose to press the Weblate button. This takes you straight to the correct translate page, the Weblate page where you can edit your translation item.

The translation editor does not work for all GUI text strings. In that case the message "No translatable string found" appears in the bottom-left corner of the Freeplane Window.

For some tool tip items you might notice that offline editing is disabled and that the translate page cannot be found. In that case it is a new tool tips.

If you would like to change the standard hot key for the translation editor, you can do so by selecting Tools > Set text change hot key from the menu.

Online or offline translation?

In the following 2 paragraphs it is explained in detail how these 2 tools work together in online or offline translation. Both ways have advantages over the other.

Online translationOffline translation
Easy to collaborateFast
Automatically work on the most current translationYou immediately can check the result of your translation in the Freeplane UI
More information and tools to support translation: glossary, machine translation, review flags, comments, historyYou do not need Internet during translation

When to use online or offline translation depends on what you have to do, your circumstances, your translation skills and the preferences of you and your co-translators. Here are a few examples

Online translationOffline translation
When you have to improve existing translationsWhen you have to translate untranslated items
When you translate a few items from time to timeWhen you want to and are able to translate a lot of items in a short time
When you need to collaborate with other translators for your languageWhen you are the only translator for a language
When machine translation and a secondary language can help you translateWhen you are able to translate without any aids
When the quality of translation is more importantWhen the speed of translation is more important
When you always have access to InternetWhen you need to be able to do part of the work offline

Online translation

Online translation has basically 3 steps:

  1. You need to find, filter and/or review translation items
  2. Translate an item
  3. Test your Weblate translation

How to find, filter and/or review translation items

The following 4 scenarios can help you to get from no translation to a complete and improved translation. You could use a combination of scenario 1 and 2 to go through all menu's and screens systematically followed by scenario 3. Scenario 1 is the only scenario that can be replaced with offline translation. Scenario 4 can take place at any time. In case of a largely completed translation that needs maintenance, the scenarios can be used in any order. New tool tips and other new English source strings and translation keys that are added during development are probably easiest found through scenario 3, though it might be difficult to find the location of these strings in the user interface.

Scenario 1: In the Freeplane user interface you see a string you would like to translate or improve and you can use the Freeplane translation editor. You can recognise untranslated strings as the English source string with the token [Translate me] attached to it. Otherwise you could see a string that needs better formulation or correction of a language error. Hold your mouse above the intended string and press Ctrl+Shift+F10 to invoke the Freeplane translation editor. It will show the string and, if applicable, its tool tip. Press the Weblate button of the string you would like to translate or improve. That will directly open your web browser with the Weblate page for your translation item. In a few cases this scenario does not work or stops here:

  • When you press Ctrl+Shift+F10 the translation editor does not appear and the message "No translatable string found" appears in the bottom-left corner of the Freeplane Window. The translation editor cannot handle this type of string and you should use scenario 2 to find and translate this string.
  • After you press the Weblate button, the translation item cannot be found in Weblate. This concerns a new tool tip, see new tool tips
  • You may find that the string is already translated or improved. This is because Weblate can be ahead of the translation that came with the Freeplane release you are using.

Scenario 2: As scenario 1 but without the Freeplane translation editor. Once you have identified your translation item you go to your language page (https://hosted.weblate.org/projects/freeplane/translation/xx/) and press Search. In case of translation you enter the English source string in Query and enable option "Search in source strings" In case of an improvement you enter the current translation in Query and enable option "Search in target strings". After pressing the Search button you might directly find the page for your translation item. If you find more than one item, you can browse through them to find your translation item. If you find nothing or the wrong item the English source text or the translated text has been changed in Weblate since the moment of the Freeplane release you are using. You can try to find them by reducing the number of keywords in the search.

Scenario 3: Finding remaining or new untranslated items in Weblate. In Weblate you can easily find all untranslated items by clicking 'Not translated strings' on your language page. Disadvantage over scenario 1 and 2 is that you might have difficulties to find the location of these translation items in the Freeplane interface, so you miss the context that helps you to translate or improve it. After having gone systematically through all menu's and screens with scenario 1 and 2, this is the only way to find the remaining untranslated items.

Scenario 4: Reviewing translations. In scenario 1 and 2 you review the translations directly in the Freeplane interface. In Weblate there are many additional ways to select translations for review:

  • Review all translation items marked for review: Click the link 'Strings marked for review' from your language page. You can now browse through all translations that are marked for review by other translators or automatically by Weblate if the English source string has changed. If necessary you can improve the translation. If your are satisfied with the translation, remove the tick "Needs review" and save.
  • Review all translations done by other translators since a certain date: From your language page click Search, in the Review pane specify the date and click "Start review".
  • Review consistent translation of a certain keyword: From your language page click search, enter the keyword, only enable "Search in source strings" and hit the Search button.
  • Review translations with failed checks: From your language page click the link "Strings with failed checks". On the search page you can use "Search filter" to filter on specific failed checks.

How to translate

The basis of the translate page is the English source string and the translation field. For an untranslated item you can enter the translation. An existing translation you can review and change. You can also enable or disable 'Needs review' if necessary. Then you can save your changes.

If the English source string has changed, the change is shown as well. If you have another secondary language that you know better than English, you can specify that in your Weblate profile and the translation to this secondary language is also shown on the translate page.

If you do not know the location of your translation item in the Freeplane user interface (scenario 3 and 4), the context string (which is in fact the translation key) and the Nearby messages might give a clue.

You can check what Machine translation suggests and how translators have changed the translation in History. Comments and Glossary are discussed in How to collaborate to translate Freeplane to your language

How to test your Weblate translations:

  • Open your language page: https://hosted.weblate.org/projects/freeplane/translation/xx/
  • Choose Files
  • Click "Download", save freeplane-translation-xx.properties
  • Copy freeplane-translation-xx.properties to resources/translations/Resources_xx.properties
  • Restart Freeplane
  • Test your translations
  • Close Freeplane
  • Remove resources/translations/Resources_xx.properties, otherwise it will overrule newer translations that will come with new Freeplane releases.

Offline translation

The basic steps of offline translation are simple: you translate your translation items with the translation editor and then you upload your translation to Weblate. The use of the translation editor has already been explained. The first paragraph explains how to upload your translation.

When you plan to translate offline you need to realise that there are 3 risks that could upset you and your peer translators compared to the situation where you and the other translators use online translation exclusively:

  1. Your local Freeplane translation files are not automatically up to date with the most current translation to your language. There is a risk that you translate items that already have been translated.
  2. You and other translators for your language are not automatically aware of reach others work. There is a risk that you and your co-translators work on the same translation items.
  3. You do not automatically compare your translation with an existing translation that is added after the local outdated translation (risk 1) or while you were working on your offline translation (risk 2). There is a risk that you accidentally overwrite a preferable translation. In the best case scenario there is no translation to your language yet and you are able to ensure that you are the only translator. In other scenarios these unwanted results could occur and might upset you and/or your co-translators. So it is better to prevent these risks from happening by the measures explained in the third paragraph. Part of these measures concern updating the local language files and it helps to understand their hierarchy as explained in the second paragraph.

How to upload your translation

When you have finished your offline translation and would like to upload your translation to Weblate, you can take steps 5 to 10 in the procedure described in How to prevent offline translation risks. In step 9 you can choose from the following settings:

The standard recommended settings are: : Merge method: Add as a translation : Processing of strings needing review: Do not import : Merge file header: Disabled : Merge translation comments: Disabled : Overwrite existing translations: Enabled You apply these settings if you are sure there are no existing translations, if you have an alternative for reviewing translations that are going to be overwritten or if you are intentionally overwriting existing translations with improved translations.

If there is a chance that you are going to overwrite other translations unintentionally, the following alternative settings allows you or you co-translator to review whether you have accidentally overwritten a preferable translation. : Merge method: Add as a translation needing review : Processing of strings needing review: Import as string needing review See also the procedure in How to prevent offline translation risks for a smarter way to review for preferable translations that are accidentally overwritten.

If you want to prevent that your import overwrites existing translations, you can change the last setting as follows : Overwrite existing translations: Disabled

Other variations are not relevant, since the type of translation file we use does not have a file header and does not support marking individual strings needing review or adding translations comments.

How to keep your local translation files up to date

If you understand Freeplane's translation file hierarchy, you can figure out how to keep the local Freeplane translation up to date. Freeplane looks for a translation of a certain translation key in the following order:

  1. in UserResources_xx.properties (where translation editor stores translations)
  2. in resources/translations/Resources_xx.properties (that you can use to save the most recent translation from Weblate)
  3. in the file Resources_xx.properties that came with the release (in the installation directory)
  4. in the file with the English resource strings, displaying it as <English text> [translate me]

With this file hierarchy in mind you can easily grasp the following situations:

  • Suppose you download the translation file in your language from Weblate and save it as resources/translations/Resources_xx.properties. Then the updated translations from Weblate will overrule the outdated translations that came with your current Freeplane version.
  • The previous bullet is not true if you kept an UserResources_xx.properties with some outdated translation strings that overrule the strings with the same translation keys in resources/translations/Resources_xx.properties. So it is good practise to remove UserResources_xx.properties after you have uploaded your translationThat will also prevent you from uploading the same translation strings twice.
  • Suppose you have finished your translation work, you keep resources/translations/Resources_xx.properties without updating it and you update Freeplane to a new version. At that moment outdated translations in resources/translations/Resources_xx.properties overrule updated translations that come with the Freeplane releases. So if you want to benefit from automatic translation updates that come worth Freeplane releases you should remove resources/translations/Resources_xx.properties.

How to prevent offline translation risks

When you start offline translation you need to assess to what extent the risks of outdated translation files and hidden translation work do apply. Here are some suggested measures and a procedure, just check what applies to your situation. If you work with a group of translators, you can agree on your measures and procedures.

Measures

  • Announce on the Freeplane forum that you are going to do an offline translation. You can do this in an existing or new thread as explained in Discussion in a topic on the Freeplane forum
  • Keep the moment between starting the offline translation and uploading it to Weblate as short as possible. For example, if you can work on the translation fulltime for 2 days, upload it immediately after you have finished. If you can work on it one hour now and then, upload it after each hour.

Procedure

This is an example procedure that updates your local translation before you start offline translation and allows you to review whether your upload overwrites any new or changed translations that other translators have added to Weblate while you were working offline. Some steps might not apply to all situations, e.g. if Weblate does not contain any translations in your language yet, there is no need to download a translation file to update the translation in Freeplane (step 2).

  1. Remove the file UserResources_xx.properties if you have uploaded offline translations previously and forgot to remove it.

  2. In Weblate go to your language page and click Files > Download original translation file (Java Properties (ISO-8859-1)). Save the file as resources/translations/Resources_xx.properties. Restart Freeplane. The Freeplane translation for your language is now up to date with Weblate.

  3. If you have not done so, change the language of the Freeplane user interface to your language in Tools > Preferences > Environment > Language and restart Freeplane.

  4. Carry out your offline translation.

  5. Close Freeplane to make sure that all your translations are stored in UserResources_xx.properties

  6. Open your language page (https://hosted.weblate.org/projects/freeplane/translation/xx/)

  7. Click Files > Upload translation

  8. Choose the file UserResources_xx.properties

  9. Choose the options as recommended in these instructions. You can use the standard settings or, if you do not want to spent time on reviewing in the next step, you can choose not to overwrite existing translations.

  10. Click the upload button

  11. From your language page, click history and check that your translations have been imported. Click on every item with action'Translation changed' and check in the history tab of the displayed translate page whether you unintentionally have overwritten something. If you find the previous translation better than yours, you can restore the previous one.

  12. Remove UserResources_xx.properties to prevent that you upload the same translations again and to enable you to see updates through the other language files, see the previous paragraph.

New tool tips

The translator editor has also functionality for UI Designers to add new tool tips in order to improve the user interface. Translators can recognise these new tool tips by the fact that the entry field in translator editor is disabled or by the fact the Weblate button does not find the translation item. A translator can enable the translation of a tool tip by taking over the role of the UI designer. It requires the translator to submit an English source string before the actual translation can start. It also requires an developer to add the new translation key and source string to Weblate, so enabling is not an instant action. The next paragraphs describe in detail the different processes with regard to new tool tips.

UI designer process

This process is for new tool tips only. If you want to improve the source string of existing tool tips follow the regular process to change source strings.

  1. Check if there is any open "New tool tips" bug report. If so, wait till they are all closed and Weblate is up to date. If not, you might repeat your own work or overwrite your co-designers work.
  2. If the Freeplane language is other than English, change it to English in Preferences
  3. Close Freeplane
  4. Remove UserResources_en.properties to prevent submitting the same new tool tips
  5. Download the English source through menu "Files > Download original translation file (Java Properties(ISO-8859-1))" from https://hosted.weblate.org/projects/freeplane/translation/en/. Save it as viewer-resources/translations/Resources_en.properties. In this way your local source strings are up to date.
  6. Start Freeplane
  7. Hover over the item that you would like to add a tool tip to. If there is already a tool tip, skip the item. If not, press Ctrl+Shift+F10
  8. Enter the text for the tool tip (the bottom field) and press OK.
  9. Repeat the last 2 steps till you have finished what you had planned
  10. Close Freeplane
  11. Create a new bug report titled "New tool tips" and attach <fpuserdir>UserResources_en.properties
  12. If necessary, change Freeplane back to the original language.

Translator process

If you want to enable translation for a certain tool tip, you should follow the following steps.

  1. Hover over the item with the disabled tool tip and press Ctrl+Shift+F10.
  2. Press the Weblate button. If the translation key is present in Weblate, you can continue with normal online translation. For the offline translation process continue with that section below. If no translation key is present, continue with the next step
  3. Follow the steps of the UI designer process
  4. When the "New tool tips" bug report is closed, continue with online translation. For offline translation process continue with that section below.

Offline translation process for new tool tips

This is the same as the normal offline translation process, except that you need to update the English source strings to enable the new tool tip fields:

  • Download the English source through menu "Files > Download original translation file (Java Properties(ISO-8859-1))" from https://hosted.weblate.org/projects/freeplane/translation/en/. Save it as viewer-resources/translations/Resources_en.properties. In this way your local source strings are up to date.

Change English source strings

It is possible to change the English source strings with the same tools as used for translation. You should do this with the utmost care. If you see a spelling error in the source text you can correct it just like that. Other improvements you should discuss in the Improvement of Freeplane usability thread. In addition can go to the English translate page of the item you would like to improve, check 'Needs review' and leave your suggestions as a comment at the translation level.

I recommend you to change English source strings only online because you will make a few changes at a time and you will prevent a mix up with new tool tips.

You can follow the instructions for online and offline translation with a few adjustments:

  • In order to use the Freeplane translation editor for English source text, you need to change the interface language to English in Freeplane's preferences.
  • Where it says 'your language page' you can start off from the Freeplane English source page: https://hosted.weblate.org/projects/freeplane/translation/en/
  • Obviously on the translate page for English there is no source string, in the translation field you can change the source string
  • While you are on a translate page for a language other than English, there is a icon of a pencil next to the label 'Source'. This icon links to the translate page for the English source string.
  • If you want to test or update the English source strings in your local Freeplane, you can download them from Weblate in the same way as for translations, but you should save it as: viewer-resources/translations/Resources_en.properties.

How to collaborate to translate Freeplane to your language

Weblate makes it very easy to collaborate on translating Freeplane to your language. If you or another translator add a new translation, the other translators immediately see this new translation in Weblate. If something unexpected has happened to a translation item you can check in the history tab of the translate page who has done what. The following paragraphs highlight some other Weblate collaboration features and the fact that you also can communicate through the Freeplane forum.

Communication by comments and review flags in Weblate

If you are not sure about your or somebody else's translation you can check 'Needs review' and add a translation comment with your question or concern. Be sure to choose 'Translation comment' as a scope so that it is only visible to other translators in your language. This means you can write the comment in your language.

If you have a remark that can help translators of all languages, e.g. "Clone and copy should be translated to different words, because they are functionally different.", you can choose 'Source string comment' as a scope. Of course you should write this comment in English.

If you have a suggestion to improve an English source string, ignore the Weblate advice and see Change English source strings about how to communicate this.

Consistent translation by using a glossary

A Weblate glossary is a great way to agree on a consistent translation of certain keywords. If we repeat the example of the terms clone and copy, that are functionally different in Freeplane: in the glossary you can actually suggest how both words should be translated in your language. Once a keyword in the glossary appears in the source string on the translate page, suggested translations appear in the Glossary window in the right top corner of the translate page. You can also add a new keyword with translation to the glossary through this window.

If you want to review and edit your glossary, you can click the 'Manage glossary' icon in the top right corner of the glossary window. Alternatively, you can go to the page https://hosted.weblate.org/dictionaries/freeplane/ and select the glossary for your language from the overview.

Discussion in a topic on the Freeplane forum

If you feel the need to have a discussion with your fellow translators you can check if there is an existing thread for your language on Discussions. If not, you can start a new topic for translation to your language. Since such topic is for people having the same primary language, you are allowed to write in your mother tongue. If you subscribe to this thread, e-mail messages will notify you of new posts.

Here is an incomplete list of forum threads and pages related to the translation to different languages. If any existing translation thread is missing from this list or if you started a new translation topic for your language, report it in the thread: Questions about translating Freeplane via the Weblate tool

French / Français

You can have a look at:

Flemish/Dutch / Nederlands/Vlaams

Frequently Asked Questions / Tips for translators

While running Freeplane, why are some strings ending with `[translate me]`? 
As long as a key is missing in a translation, Freeplane automatically uses ` [translate me]` as translation. Translators should translate these strings in priority and then remove `[translate me]`.
Why are strings ending with `[auto]`? 
Translation files can be submitted to an automatic translation tool, then strings of type ` [translate me]` becomes strings of type `<local language text> [auto]`. Translators should search and review these strings and then remove `[auto]`.
Why is there sometimes space before values? 
spaces before values are ignored, don't care.
Why is there & character before some values (sometimes "in" the words)? 
The ampersand (&) is used to mark keys in the menu (i.e. open the menu, press the key/letter to activate the menu entry) - It is not necessary to add the & character to your translation, because Freeplane will automatically mark keys in the menu. I you do want to have full control over which keys are marked, you can add the & character to your translation strings and you need to make sure that each letter is only used once per menu. The easiest way to do this is to finalize your translation and than quickly add the & characters in offline translation because then you can immediately check the result in the Freeplane interface.
Some values begins by <html> with no </html> at the end? 
Java accepts unclosed tags - don't care.
Some keys are not used / displayed in the software 
you should stay aligned with the English version to be on the safe side, but if keys are not used, it's a bug you can report it here.
When testing Freeplane with my translation file, some menus are missing or some buttons have no label, why? 
If you leave any empty keys in the file, Freeplane assumes they are valid translations and displays nothing. There are differences between "empty key in the translation file" which displays nothing and "missing key in the translation file" which displays ` [translate me]` (see above).
Your translation is truncated 
If your translation is truncated when displayed, it may contains a ' (apostrophe) character (e.g. Freeplane displays "Copier l" instead of "Copier l'identifiant"), you may simply enter the ' character twice (ie "Copier l"identifiant") as translation, where " is twice the character '. Most of the time, ' apostrophe characters should be handled as in the English version (for some strings which are used in format statements put them twice, for other strings put them once).

Translation of Freeplane add-ons

Add-ons manage their translations on their own, i.e. the translations are integrated into the add-on sources. Nevertheless, it's simple to translate an add-on by editing the add-on installation package in Freeplane and modifying the translations therein. If the translations contain non-ASCII characters you have to encode the text using a script, either from the Developer Tools (since version 0.9.16) or from here.

Translation of third party tool used in Freeplane

JOrtho spell checker

For spell check Freeplane relies on JOrtho project. JOrtho translation file contains very few strings and only 5 are used in Freeplane but if you want to translate this file too, you can get it at its current location.

Translation of Tutorial or Documentation maps

These are the mind maps you get when you press Help → Tutorial (freeplaneTutorial.mm) and Help → Documentation (freeplane.mm).

Basic steps

  1. Create a working directory myTranslations.
  2. Copy the most recent English documentation from https://www.freeplane.org/mapsOnline. For this choose Help > Documentation Maps Online and select the map of your choice; or copy your last translation.
  3. make a subdirecory structure for images: myTranslations/doc; (if you use these, also myTranslations/mouse and myTranslations/key).
  4. Copy images you reuse or put new images you use in myTranslations.doc (possibly also myTranslations/mouse and myTranslations/key).
  5. Edit your translation. Drag your images from the defined subdirectories into your translation (assuming URI's are relative).
  6. Test the translation, in particular the images.
  7. Zip directory myTranslations.
  8. Select Help > report a bug, select new report of type translation and upload the zip file.

Note Check Help > Documentation Maps Online > indexMap > Images/doc for the images used in the present doc mind maps.

Old

  1. Download the latest version of freeplane.mm and FP_MenuReference.mm (or an already existing versions in your language) from the repository.
    • The current link is https://github.com/freeplane/freeplane/tree/master/freeplane/resources/translations/ (but check if it's not an outdated link)
  2. Visit pages https://www.freeplane.org/doc/freeplane_all_languages.html and https://www.freeplane.org/doc/FP_MenuReference_all_languages.html to see how the documentation is automaticly translated by Google Translate.
  3. Using the latest development version of Freeplane, just create a map in your language (or complete the one already existing).
    • As it's almost impossible to track differences between maps and ensure an exact one to one relationship between the languages, we don't expect this from translators.
    • To track changes of freeplane.mm filters can be useful: Open the file in normal mindmap mode (not via F1) and apply a "Date filter" with the modification time set to the last time you have edited the translated map.
    • Just make sure that the map is consistent with the current version of Freeplane, as complete as possible and helpful to users.
  4. Go to the tracker (requires Sourceforge log-in) and upload your map (the Project should be set to Translations).

Keys Mapping translation

TBD

Java Help translation

TBD (the current version doesn't allow for localization). Hint for later: http://jhelpdev.sourceforge.net/

Scripts? Start here 🤖

This page can be used as an overview guide for the Scripting section of this Documentation.

💡Tip: If you got a script in the forum, and just want to know how to use it, you can read the first sections of this Tutorial, until the section The first script: HelloWorld.groovy.

💡Tip: If you are interested in just finding useful scripts, go to the Finding Scripts page.

For a quick introduction to what Scripts are, and what they can do, go to this page

If you are interested in building your own scripts, then you may want to consider the following suggestions.

Learn the basics 👨‍🏫

If you want to learn the basics about how to create scripts, even if you are a complete beginner in coding, you can follow our Learning Guide.

Get Advanced 🚀

If you already know the basics of how to create Freeplane scripts, you may want to:

  • Find a comfortable setup to create your scripts: Scripting setup

  • In the References and Cheatsheet section, get some handy references to be used while creating scripts

  • Read the Advanced Topics section

  • Using AI to build scripts. AI is already very capable of creating Freeplane scripts.

  • Learn how to use internal methods (there are still no guides about it)

If you want to learn the basics about how to create scripts, even if you are a complete beginner in coding, you can follow this suggested learning path:

  • Start with this gentle tutorial that uses many practical examples: Tutorial
  • Now that you are more familiar with the general idea of how scripts work, you can use this concise guide for revision and reference of the important points: Scripting concise guide

Scripts are a set of instructions that tell a computer program how to perform specific tasks. Think of a script like a recipe for a computer. Just as a recipe guides you through the steps to make a dish, a script guides the computer through the steps to complete an action.

When you're using a software program like Freeplane, which helps you organize information visually, you might find that there are certain tasks you do repeatedly. Maybe you always format text the same way, or you combine pieces of information in a specific pattern. Doing this manually each time can be tedious and time-consuming. That’s where scripts come in handy.

Scripts automate these repetitive tasks. Someone who knows how to write scripts can set up a sequence of actions, like changing text color or moving information from one place to another. Once the script is written, you can run it with a simple command, and the script will do all the steps for you quickly and accurately.

More advanced scripts allow the user to customize the Interface and behavior of Freeplane, in order to make it fit exactly to the user needs. Advanced scripts are usually transformed in Add-ons, but they are essentially the same thing.

As an example of what an advanced script can do, you can watch this detailed video presentation of MapInsight, which expands the Freeplane capabilities in order to fulfill very specific needs from the user.

The beauty of scripts is that they can be shared. If someone creates a useful script, they can give it to other Freeplane users, who can then use it without having to know anything about programming. It’s a way to customize and enhance the functionality of the program to better suit your individual needs or the needs of a group.

This page is best viewed in the Ayu theme

Part 1

If you are new to scripting and/or Groovy, it might be easier to start with something you already know.

Formula - spreadsheet

Many people are familiar with spreadsheet formulas, so let's start there.
In e.g. LibreOffice Calc or in MS Office Excel, to have in cell A5 the value of cell A1, you can write the formula =A1.

Once confirmed with Enter, in A5 you can see the value of A1.

Formula - node

Similarly, in Freplane you can reference another node by using a formula. When you write = in the 5th node, Edit Formula window appears.
Here ID_1736361150 is the equivalent of A1 in a spreadsheet, in the sense that it uniquely identifies a node, just like A1 uniquely identifies a cell.

Note: In Freeplane, node ID is generated automatically for each new node. In your mind map you'll find a different ID than ID_1736361150.

Once confirmed with OK, you can see (Node) Freeplane.

Why not just Freeplane?
It's because, from the scripting perspective, a node is an object. It has many attributes, e.g. details, note or text, to name a few.

Where are these attributes described?
They are described in the Scripting API.

By now you might already have guessed how to correct the formula in the 5th node to display the value of the 1st node, i.e. by accessing the text attribute. It's done by using a dot notation, i.e. =ID_1736361150.text.

Before we have a look at the relevant section in the Scripting API, it's time to introduce Groovy.

Groovy - intro

Groovy is a programming language, like Java, C#, Python, Visual Basic, etc.
Whereas in MS Office macros are written in VBA (Visual Basic for Applications), Freeplane scripts (macros) are written in Groovy. Unlike in a spreadsheet, where formulas can use only predefined "functions", formulas in Freeplane are free to use all that Groovy has to offer.

You know that Freeplane requires JRE (Java Runtime Environment) to run. This is because Freeplane is written in the Java programming language, which itself requires JRE to be executed. Java and JRE is mentioned here because Groovy can be perceived as simplified Java. Groovy also runs on JRE and is quite similar to Java. So much that code written in Java can be executed as Groovy (with some minor exceptions).

So why use Groovy if one can use Java?
Because Groovy is simpler than Java.

OK, but why are we talking so much about Java? This tutorial is about API/Groovy.
It's because the Scripting API is part of Freeplane's code base, which is written in Java. Therefore, you'll see Java code at https://docs.freeplane.org/api/.

Scripting API - example

Let's look at our formula =ID_1736361150.text and find its Scripting API page. You know that =ID_1736361150 points to Node, and that it is an object. The object is NodeROhttps://docs.freeplane.org/api/org/freeplane/api/NodeRO.html.
The text is getText() method of NodeRO object.

Click to expand getText()
java.lang.String getText()
Raw text of this node which might be plain or HTML text. Possible transformations (formula evaluation, formatting, ...) are not applied.

See

Since:
1.2

So why =ID_1736361150.text and not =ID_1736361150.getText()?
Actually both will work. The first one is Groovy-style, the second is Java-style, but equally valid in Groovy.

Note: When you see a method starting with get and ending with (), you can use its stripped-down version in Groovy, i.e. without get and ().

Java-styleGroovy-style
getText()text
getPlainText()plainText
getTransformedText()transformedText

Formula - node details

Let's go back to our formula example and add details to the 1st node, e.g. API/Groovy tutorial, then display it in the 5th node using a formula. You can search the Scripting API to find a suitable method – use the search box in the top right.

The revised formula is =ID_1736361150.details (or =ID_1736361150.getDetails()).

Formula - Convertible

The page https://docs.freeplane.org/api/org/freeplane/api/NodeRO.html#getDetails() informs that getDetails() "returns the text of the details as a Convertible". So what is a Convertible?
It's another object. You can see its page at https://docs.freeplane.org/api/org/freeplane/api/Convertible.html.

Convertible: Utility wrapper class around a String that is used to convert node texts to different types. It's especially important for Formulas.

Convertible has several methods available, in particular:

  • getText()
  • getDate()
  • getNum()
  • getNum0()

This means that we can rewrite our formula to =ID_1736361150.details.text (or =ID_1736361150.getDetails().getText()).

Formula - node children

So far you've been using =ID_1736361150 to point to the 1st node. Let's use another approach, i.e. parent / child. When you have a look at https://docs.freeplane.org/api/org/freeplane/api/NodeRO.html, you'll notice getParent() and getChildren() methods. Let's rewrite our formula to get the first (top) sibling, i.e. the first child of node's parent.

How to refer to self (the node in which the formula is written)?
In Freeplane it is done by using node.

Therefore =node points to itself, =node.details points to node's details, and =node.parent points to the parent. And since the parent is also a NodeRO, you can call getChildren() on it, or simply =node.parent.children.

It's time to select the first child. In Groovy it's done by using square brackets → https://groovy-lang.org/operators.html#subscript-operator
The trick is to start counting from 0, i.e. =node.parent.children[0].

Having the first sibling, you can get its details.

Script - set details

Let's write and execute a script on the root node. The easiest way is via Tools->Edit script… > Action > New Script.

Let's change the root node's details.

Earlier, in Formula - node details, the search results contained "setDetails(Object)". You can find it again and read the API docs now.

Based on the description, node.setDetails(details) should do the job. Why not =node.setDetails(details)?
Because only a formula starts with =. A script does not.

Let's try it then.

And run it via the menu Actions > Run.

Why nothing changed, except for the output Result:null?
Because details is null, therefore the script is equivalent to node.setDetails(null).

What is null?
In Groovy, null has the meaning of "nothing".

Let's set "something", then: node.setDetails('I am Groot').

And just like with getDetails(), also with setDetails(details) there is a Java-style and a Groovy-style way.

node.details = 'I am Groot'
Java-styleGroovy-style
node.setText(value)node.text = value
node.setDetails(value)node.details = value
node.setNote(value)node.note = value

It worked OK, but why does the output still say Result:null?
It's because it is the result of the last expression. In this case it returned nothing, because it was a set operation. This is in contrast to a get operation, which usually returns something. In other words, node.getDetails() or node.details would have returned the value of details.
Let's try it: Actions > Run.

Note: Freeplane allows even shorter expressions for get operations, where node. is implied if omitted.

How to remove details from the root node?
Based on the API docs, "Use null to unset the details."

Let's try to read details now.

Note: node.getDetails() or node.details or getDetails() or details, all of them will work the same.

Yes, there's nothing, thus Result:null.

Script - set details for each child

How to set details for each child of the node?

In Groovy, there is a more-often-used way of iterating over a collection of elements.

It's possible, in Groovy, to omit def child -> and instead use the default variable name inside .each { ... }, i.e. it.

Let's use this knowledge to set each child's details to contain its position among siblings (counted from 0), i.e. 0, 1, 2, 3, 4.
https://docs.freeplane.org/api/org/freeplane/api/NodeRO.html#getChildPosition(org.freeplane.api.Node)

node.children.each {
    it.details = node.getChildPosition(it)
}

This version might be easier to understand.

node.children.each { def child ->
    child.details = node.getChildPosition(child)
}

Note: child is a variable. It points to a different node with every iteration of each.
To define a variable, the keyword def is used.

Let's make it even more readable.

node.children.each { def child ->
    def position = node.getChildPosition(child)
    child.details = position
}

After the script is run, you should see numbers in details.

Formula - working with numbers

Let's edit the formula in the 5th node, so that it sums up the numbers in siblings' details.

=node.parent.children[0..3]*.details*.num.sum()

You already know that node.parent.children[0] points to the first sibling.
You also know by now that node.parent.children[0].details gets the text of details (details usually means details.text).
Earlier, we looked at ConvertibleFormula - convertible, therefore you can guess what details.num will get you.

New Groovy concepts:

In a script, to sum up the numbers in details and place the total into the node's text, you would write

def total = 0
node.parent.children[0..3].each { child ->
    total = total + child.details.num
}
node.text = total

Note: It's customary to omit def before a variable and -> inside { ... }, i.e. in a Closure

In a formula, to make it more concise, you can use a Groovy shorthand *., which does much of what .each {} does → https://groovy-lang.org/operators.html#_spread_operator
In other words children[0..3]*.details*.num iterates over each of the child nodes in the range 0..3 and gets details from each child, then iterates over the resulting list of details and gets num from each one:

  • Step 1 results in [details of child 0, details of child 1, details of child 2, details of child 3]
  • Step 2 results in [num of details of child 0, num of details of child 1, num of details of child 2, num of details of child 3]

Finally, .sum() calculates the sum of numbers in the list.

NodeRO vs Node

You might have noticed that some node-related methods are described in https://docs.freeplane.org/api/org/freeplane/api/NodeRO.html, while other in https://docs.freeplane.org/api/org/freeplane/api/Node.html. RO in NodeRO stands for read-only. The idea behind this segregation is to indicate methods safe for formulas, i.e. the read-only ones. While Freeplane won't stop you from including a non-RO method, such a formula might produce unexpected effects. Therefore, it's best to avoid using non-RO methods in formulas and script filters.

Filter by script and more

Let's add a filter to show nodes whose details is an even number. Using the GUI, you can do that via Filter->Compose filter. In a script, you can... search for filter at https://docs.freeplane.org/api/ or when you open the same page locally via Help->Freeplane API….

Once you read about MindMap.filter(...), you'll learn that it's a method of MindMap.

So how to get MindMap in a script if all you have is node?
The answer is one search away...

Let's create a script Tools->Edit script… and run it Actions > Run.

def showAncestors = true
def showDescendants = false
def condition = { n -> 
    if (n.details.num % 2 == 0) {
        true
    } else {
        false
    }
}
node.mindMap.filter(showAncestors, showDescendants, condition)

New Groovy concepts:

You might notice that a Closure {...} is used in another context than .each {...}. But the structure is already familiar, with a variable at the begining, followed by an arrow, etc.

What happens when the script is run?

Here's why. The script instructs Freeplane to add a filter which is executed on each node in the mind map. The script (captured in the variable condition) receives the node as its first (and only) argument (variable n) and accesses the node's details as number. But hold on. The root node has no details. This means n.details will return null. And null.num makes no sense. Hence, "Cannot get property 'num' on null object".

So how to fix it?
By checking first if details exist, i.e. n.details != null or even simpler n.detailshttps://groovy-lang.org/semantics.html#the-groovy-truth

def showAncestors = true
def showDescendants = false
def condition = { n -> 
    if (n.details && n.details.num % 2 == 0) {
        true
    } else {
        false
    }
}
node.mindMap.filter(showAncestors, showDescendants, condition)

New Groovy concepts:

Can the script be made shorter?

def showAncestors = true
def showDescendants = false
def condition = { n -> n.details && n.details.num % 2 == 0 }
node.mindMap.filter(showAncestors, showDescendants, condition)

A bit more, please?

def showAncestors = true
def showDescendants = false
def condition = { it.details && it.details.num % 2 == 0 }
node.mindMap.filter(showAncestors, showDescendants, condition)

How about a one-liner?

node.mindMap.filter(true, false) { it.details && it.details.num % 2 == 0 }

New Groovy concepts:

  • a Closure outside of parentheses is allowed in Groovy, but only if it's the last parameter of the method

Actually the concept isn't quite as new. You've seen it already with .each, which is a method taking a Closure as its last parameter → https://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html#each(groovy.lang.Closure)

So one of the earlier scripts could be written with .each( {...} ) instead of .each {...}, i.e.

node.children.each( { child -> child.details = node.getChildPosition(child) } )

Let's go back to our script filter. What happens when you change the 1st sibling's details from "0" to "API/Groovy tutorial" and run the "filter" script again?

org.freeplane.plugin.script.ExecuteScriptException: 
org.freeplane.plugin.script.proxy.ConversionException: not a number: 'API/Groovy tutorial'

Aha, "API/Groovy tutorial" is not a number. So let's make sure to take only numbers in details → https://docs.freeplane.org/api/org/freeplane/api/Convertible.html#isNum()

node.mindMap.filter(true, false) { it.details && it.details.isNum() && it.details.num % 2 == 0 }

Great. The filter was accepted. But now the formula in the 5th node suffers from the same "not a number" error. Let's fix that too by considering only the nodes whose details contain a number. We need to "filter" the list of children, i.e. node.parent.children[0..3]. In Groovy, it can be done with .findAll {...}https://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html#findAll(groovy.lang.Closure)

=node.parent.children[0..3].findAll{ it.details.isNum() }*.details*.num.sum()

Let's remove "API/Groovy totorial" from the 1st node's details – Edit->Node properties->Remove node details. This causes an error in our formula: "Cannot invoke method isNum() on null object".

But of course; it.details is null for the 1st node. You can add the same check as in the filter, i.e. it.details && it.details.isNum(), but you can also use a Groovy shorthand: it.details?.isNum()https://groovy-lang.org/operators.html#_safe_navigation_operator

=node.parent.children[0..3].findAll{ it.details?.isNum() }*.details*.num.sum()

Note: .isNum() works also when details is null, because .isNum() checks for null and returns false in such case.

All fine and dandy, but why the result of the formula says "6", when there is only one sibling with "2" in its details?

It's because the formula considers all siblings, rather than only the visible ones.

Let's fix that too.

=node.parent.children[0..3].findAll{ it.isVisible() && it.details?.isNum() }*.details*.num.sum()

Conditional Styles with Script Filters

Let's change the way formula nodes look like by adding a Map Conditional Style.

How to tell if a node has a formula?
By checking if it starts with =.

First, let's remove any filters Filter->No filtering, make sure to disable Preferences…->Plugins->Formulas->Highlight formulas and add a custom style to be used:

  • Format->Manage Styles->Edit styles
  • Manage styles->New user style
  • Name: "Formula"
  • Insert->Icons->Nature->Nice (or any icon that you like)
  • Confirm with OK

You can search for "conditional" in the Scripting API.

Great. There is a method to get ConditionalStyles for a mind map.

As you can see in the page for MindMap#getConditionalStyles, ConditionalStyles is another object, which has its own methods. You can read its API docs now → https://docs.freeplane.org/api/org/freeplane/api/ConditionalStyles.html

You already know how to get from the current node to the mind map object → https://docs.freeplane.org/api/org/freeplane/api/NodeRO.html#getMindMap()
so the code to get map conditional styles should come as no surprise.

def mcs = node.mindMap.conditionalStyles
// or node.getMindMap().getConditionalStyles()

New Groovy concepts:

ConditionalStyles#add(...) method is of interest for our task. As you can see in the API docs, it resembles the GUI layout at Format->Manage Styles->Manage conditional styles for map.

Let's create our script and run it.

def mcs = node.mindMap.conditionalStyles
def isActive = true
def script = '''
node.text.startsWith('=')
'''
def styleName = 'Formula'
def isLast = false
mcs.add(isActive, script, styleName, isLast)

New Groovy concepts:

Note: the following comes from the Java API:

Groovy itself is built on top of Java. Many of the methods available in Groovy are therefore documented in the Java API docs.

Once the script is run, this is what you'll see.

You can also see a new entry in Format->Manage Styles->Manage conditional styles for map.

Let's add a formula to the 1st node. Earlier you used its node ID to refer to the node. How about displaying its ID in details?

How to get a node's ID using scripting API?
Let's search https://docs.freeplane.org/api/ for "ID".

Great. There is NodeRO#getNodeID()https://docs.freeplane.org/api/org/freeplane/api/NodeRO.html#getNodeID()

Uh-oh, its page says it's deprecated and to "use Node.getId() instead". That's fine. It happens from time to time that the design of API changes and new ideas are introduced.

Let's type the formula in the 1st node's details.

=node.id

Cool. But wait. Wasn't a formula node supposed to be conditionally assigned the "Formula" style? The 1st node isn't. WTF?

Let's have a look at the script variable, which has the logic to find formula nodes.

def script = '''
node.text.startsWith('=')
'''

Ah, yes. It only checks node core (node.text). Let's add a check for node details, too. And keep in mind to use the Safe Navigation operator with details.

def script = '''
node.text.startsWith('=') || node.details?.startsWith('=')
'''

New Groovy concepts:

How to change the script in an existing Conditional Style?
So far you've been dealing with ConditionalStyles (plural). It's time to look at ConditionalStyle (singular) → https://docs.freeplane.org/api/org/freeplane/api/ConditionalStyle.html.

To get a list of ConditionalStyle items from a mind-map ConditionalStyles, execute the following script in Tools->Edit script….

New Groovy concepts:

Now, using square brackets, you can get the 1st element (keep in mind to count from 0), which is a ConditionalStyle object. As you can see in its API page, there is a setScript method available.
Let's use it.

def script = '''
node.text.startsWith('=') || node.details?.startsWith('=')
'''
def mcs = node.mindMap.conditionalStyles
def cs = mcs.collect()[0]
cs.script = script

Hmm, this is unexpected. The code was executed without errors, but the 1st node still has Default style.

Let's see what node.details gets you.

Well, it's the effect of the formula evaluation, not the formula itself. So there is no '=' at the beginning.

How to get "raw" details?
Let's search the API docs. Actually, the search bar isn't that much helpful. Let's go to NodeRO and use Ctrl+F to search the page itself for "raw".

Found it: getDetailsText() "returns the raw HTML text of the details if there is any or null otherwise".

Let's see it in action.

Note: Node Details is (usually) represented in Freeplane as HTML.
Since NodeRO#getDetails() returns Convertible, details' content is auto-converted from HTML. node.details.text returns plain text (HTML converted to plain text).

How to convert HTML to plain text?
Let's search the API docs for "html".

Great. There is HtmlUtils and HtmlUtils#htmlToPlain. And at the top of its page, there's a tip: "Utilities for conversion from/to HTML and XML used in Freeplane: In scripts available as "global variable" htmlUtils".

This is useful! htmlUtils is made available to scripts as a "global variable"; you can use htmlUtils.htmlToPlain(...) in your script.

Note: Prior to v1.11.5, HtmlUtils#htmlToPlain(String text) expects non-null text. You can use the Elvis operator ?: to comply with this requirement.

def script = '''
node.text.startsWith('=') || htmlUtils.htmlToPlain(node.detailsText ?: '').startsWith('=')
'''
def mcs = node.mindMap.conditionalStyles
def cs = mcs.collect()[0]
cs.script = script

New Groovy concepts:

Success!

Part 2

Coming soon

Freeplane's builtin functionality can be extended by Groovy and JavaScript scripts. Starting with Freeplane 1.3.5_05 you can use many other languages, e.g Python. This page gives a first impression what you can do with Groovy scripting and helps to get started.

With Freeplane scripting you can

  • write your own functions and use them from the menu or via keyboard shortcuts,
  • use formulas in your map to compute stuff like in Excel, and
  • create add-ons to share it with other users,
  • have init scripts executed on startup that changes Freeplane's behavior (since Freeplane 1.5).

Most people use scripting to automate otherwise tedious procedures like creating a node with a special style and some standard attributes. But much more is possible with scripting.

External Groovy scripts can be integrated simply by placing them in the scripts subdirectory of the Freeplane homedir. Such scripts can be used like any other built-in function of Freeplane.

After some preparation we'll create the first script.

Preparation

A newly installed Freeplane installation is almost ready for scripting:

  • The scripts directory is created in the User Configuration Folder which you can open via Tools > Open user directory.

  • The scripts directory is empty, initially. On startup, the directory is automatically searched for ".groovy" files.

  • Scripting is disabled by default, but before enabling it, let's take security into consideration.

  • After having reflected on security, navigate the menu to Tools > Preferences > Plugins> Scripting and:

    • set ''Script execution enabled'' to ''Yes''
    • enable ''Permit File/Read Operations (NOT recommended)'' - despite the warning.
    • These changes take effect without restarting Freeplane and only need to be done once.

Select an editor

You will need a text editor. For the first steps presented on this page any editor will do, such as Notepad on Windows (though the free Notepad++is much better), Sublime Text or TextEdit on Mac OS X. You can find an overview of editors with Groovy support on Stackoverflow and on the Groovy website.

Freeplane also has a small script editor built into it. It is reached through Tools->Edit Script. You can run the scripts directly in the editor and store them as attributes of the node you are working in. But such map local scripts are most useful for quick tests since you can not write the scripts directly to ".groovy" files.

For ambitious scripting projects or if you have Java/Eclipse know-how you should have a look at the page on Scripting environment setup.

The first script: HelloWorld.groovy

"Hello World" is the traditional first program when taking up a programming language. Let's create a Groovy Freeplane version of it:

  • Create an empty Groovy script file named HelloWorld.groovy in your scripts directory (remember that you can get there via Tools > Open user directory). The suffix .groovy is mandatory.
  • Open HelloWorld.groovy in an appropriate editor as detailed above.
  • Copy the following script into the file and save it.
node.text = "Hello World!"
  • Execute the script by selecting Tools->Scripts->Hello World->Execute on one selected node. (Never mind the difference between the Execute ... variants; we'll come to that later.)
  • The text of the selected node will be changed to "Hello World!".
  • To restore the original, press Ctrl-Z.
  • If you like try the other "Execute..." menu items. Test the influence of selecting multiple nodes. Always press Ctrl-Z to revert the changes.

Hello Controller

Every script is given the variables

**node** set to the currently selected node
**c** tool box for various tasks relating to the map or Freeplane altogether

These give access to the two most important bits of a map. In HelloWorld we used node, which gave access to the selected node.

Now we'll change HelloWorld.groovy to use the second, the Controller variable c:

  • Copy the following script into the file and save it:
c.statusInfo = "Hello World!"
  • Execute the script by selecting Tools->Scripts->Hello World->Execute on one selected node.

The "Controller" manages the status bar. By assigning "Hello World!" to the Controller attribute "statusInfo" we are able to print text to the status bar.

The scripting API

The variables node and c are "objects" with a list of attributes (like "text", "details" or "style") and methods that operate on the object, like "addConnector()", "createChild()" or "moveTo()". The "type" of the object decides on the list of attribute of attributes and methods an object has. "node" is of type Proxy.Node while "c" has the type Proxy.Controller.

To get started with Freeplane scripting you have to get slowly accustomed to the Groovy syntax and the Freeplane specialities too. The types and objects that Freeplane supports are defined by Freeplane's scripting API. You can learn it step by step: Very little is required to write useful scripts.

An important resource is the built-in scripting documentation that is available via Help->Scripting API. Open it now and search for the statusInfo attribute at Scripting API->Proxy->Controller->statusInfo: String (w). The text means: The Controller has an attribute statusInfo that only can be written to (w), that is you can't find out what is currently displayed on the status bar. The attribute has type String (either use "double quotes" or 'single quotes'). If you unfold the node you see void setStatusInfo(String). That means that

c.statusInfo = 'Hello World!'

and

c.setStatusInfo('Hello World!')

are equivalent. But the first "attribute" style is preferable since it is clearer. The clickable links in the "Scripting API" map carry to the respective location in the detailed API description which might be a bit overwhelming at this point.

In the "Scripting API" map, near to statusInfo you find the userDirectory attribute. You can use it to add a link to this directory to your map. Create a new script file addLink.groovy in the script directory with the following content:

node.link.file = c.userDirectory

Here an slightly extended version that adds an external link to the selected node(s) and creates a node with a local link back to its parent node:

node.link.text = 'http://freeplane.org/wiki/index.php?title=Scripting'

This script creates a local link back to its parent node:

node.link.node = node.parent

In the next section we'll see what the "@ExecutionModes" line is about.

Execution modes

For each script we had three submenu entries of "Hello World". These entries are different with respect to multiple selected nodes:

*In the case of Execute on one selected node a script is executed only once no matter how many nodes are selected. It's best to be used when only a single node is selected since in this case the node variable of the script is set to the selected node. If multiple nodes are selected then node is set to one of the nodes arbitrarily. That is, you shouldn't count on the selection if multiple nodes are selected. *With Execute on all selected nodes it is called once for each selected node (with node set to the respective node) and with *Execute on all selected nodes, recursively the selection will be implicitly extended by all child trees of the selected nodes.

If we chose Execute on all selected nodes for the first version of "Hello World" then the text of all selected nodes changed. - Probably what you expect. By adding the line

// @ExecutionModes({ON_SELECTED_NODE})

all other choices would be suppressed.

The second "Hello World" version printed to the status bar. This only has to happen once so here Execute on one selected node is the right choice and we have to add the line

// @ExecutionModes({ON_SINGLE_NODE})

It's a good idea to put the "annotations" at the beginning of the script. (In section Simple text replacement we will see an exception.) ON_SELECTED_NODE_RECURSIVELY applies a script on any node in the branch that has a selected node as root. You can also enable more than one mode by concatening them with commas:

// @ExecutionModes({ON_SELECTED_NODE, ON_SELECTED_NODE_RECURSIVELY})

Note that for Groovy this is a comment. This line is only interpreted by Freeplane. Omitting the // will result in a Groovy compilation error. Additionally, while changes to script's code are picked up immediately, Freeplane needs to be restarted for @ExecutionModes changes to take effect.

Scripts can determine to which menu or submenu a script will be added. Even the menu title can be set (although the standard file name to menu title translation should be enough in most cases):

// @ExecutionModes({on_single_node="/menu_bar/help[scripting_api_generator_title]"})

You can find out about the internal menu keys using the Developer Tools > Menu item info.

Per node execution: addIcon.groovy

Now let's use the node variable again in our next script, addIcon.groovy (restart Freeplane to see it in the menu). This script will add the "button_ok" icon to any selected node:

node.icons.add("button_ok")
// @ExecutionModes({ON_SELECTED_NODE})

This will add the "check" icon to each selected node. Hopefully it's clear that the execution mode Execute on one selected node makes no sense in this case. So let's remove this from the "Extra" menu:

// @ExecutionModes({ON_SELECTED_NODE, ON_SELECTED_NODE_RECURSIVELY})
node.icons.add("button_ok")

(To see the change in the menu you have to restart Freeplane.)

We will extend this script now a little further to only set the icon if the node text contains the words "yes" or "OK" (case insensitively):

// @ExecutionModes({ON_SELECTED_NODE, ON_SELECTED_NODE_RECURSIVELY})
if (node.text.toLowerCase().matches(".*\\b(yes|ok)\\b.*"))
    node.icons.add("button_ok")

Note that node.text makes use of the special (compared to Java) attribute handling - see section On Groovy properties and the Scripting API.


The status bar again: getIconName.groovy

Finding the proper name of an icon may be a bit difficult. One way is to use the wanted icon in some map and to look it up in the sources. The XML for a node with an icon might look like that:

<node TEXT="done" ID="ID_789648746" CREATED="1239285242562" MODIFIED="1242658193277">
<icon BUILTIN="button_ok"/>
</node>

This script writes the icon names of the selected node to the status bar:

c.statusInfo = "Icons: " + node.icons.icons

Note: For built-in icons, the icon name is the same as the corresponding graphic file name, that may be found here.

Formulas

Starting with Freeplane 1.2 one use scripts as Formulas directly in the node core like in Excel. Type this formula in the node core:

= "Icons: " + node.icons.icons

This will display the result of the formula instead of the formula itself.

Notes:

  • The equal sign has to be the very first character in the script.
  • On typing the equal sign as the first character a special script editor pops up which supports syntax highlighting.

Data parsing and formatting

TODO: add text

node.object = 40
def answer = node.to.num0 + 2
node.text = '2013-02-15'
c.statusInfo = node.to.date + 1
node.object = 42
node.format = '#.00'
c.statusInfo = format(42, '#.00').toString()

Many useful scripts operate only on the current/selected node. But most scripts need to access multiple nodes. The scripting API provides methods for accessing special nodes:

  • node.parent - parent node
  • node.map.root - root of the map

For example this script prints the text of the parent node to the status bar:

c.statusInfo = node.parent.text

Other methods return node lists:

  • children - list of all children of a node, maybe empty
  • c.findAll() - all nodes of the map in breath first order
  • c.findDepthFirst() - all nodes of the map in depth first order
  • c.find() - all nodes for which returns true.

The use of this methods requires some knowledge of Groovy collections.

Filtering

The most important concept is that of "closures", small code blocks that are used for filtering and modification of the element currently being iterated over. Let's start with filtering:

def matches = c.find{ it.text.contains('ok') }
c.statusInfo = matches.size() + " nodes contain 'ok'"

The method find has a closure argument which is applied to all nodes in the map. All nodes for which the closure returns true are returned as a new list which is assigned to the matches variable. In the closure the "current item" has a default name it. As c.find iterates over nodes it is a Node that has the attribute text which is a String that has a method contains() returning true if OK is contained somewhere in the text, like in "grok" or "it's ok".

Transformation

Many Groovy methods transform lists/collections into others:

def squares = children.collect{ it.to.num0 * it.to.num0 }

and others transform lists into single values:

def sumOfSquares = children.sum(0){ it.to.num0 * it.to.num0 }

When using sum() it's always a good idea to give it a start value since if the node had no children sumOfSquares would be null instead of 0.

Clones (since 1.5.5)

There are several methods to create clones of nodes and to act on the clones of a node. Note that cloning works symmetrically so we could better speak of shared nodes instead of clone and cloned since none of both is privileged. However each clone or shared node has a unique nodeId and may or not (depending on the share mode) have its own child nodes.

Add two clones of this node to the root node, one as single node, one including the branch starting at this node. Warning: before beta-1.5.5-pre03 appendAsCloneWithSubtree and appendAsCloneWithoutSubtree have reversed meaning!

def root = node.map.root
def lonelyClone = root.appendAsCloneWithoutSubtree(node)
def childWithSubtree = root.appendAsCloneWithSubtree(node)
// add nodes to the clones
lonelyClone.createChild('a child not shared')
childWithSubtree.createChild('a shared child')

Mark a node with yellow background color if it has any clone:

if (node.getCountNodesSharingContent() > 0)
    node.backgroundColorCode = '#ffff00'

Mark all nodes of a map having any clone:

c.find{ it.getCountNodesSharingContent() > 0 }.each {
    it.backgroundColorCode = '#ffff00'
}

If you should be interested in clones that share also the subtree (and not only the core properties) filter for countNodesSharingContentAndSubtree instead of countNodesSharingContent.

Add a connector from node to all of its clones using property-access instead of method (nodesSharingContent instead of getNodesSharingContent()):

node.nodesSharingContent.each { node.addConnectorTo(it) }

TODO: Tutorial ends here...

Appendix

Using external libraries

Some libraries are already included, but almost all other available Java libraries can be used. Place them in the lib directory in the <freeplane_userdir> which is already included in the "Script classpath" (see also Tools->Preferences->Plugins). All .class files and the content of all .jar files are automatically available in scripts and formulas.

Starting with Freeplane 1.3 utility scripts on the script classpath are compiled automatically.

You can also create your own utility script library.

The add-on scriptlib contains some libraries you can load and install. They include some node operations missing in the scripting API, file operations and a method to play audio with a hidden player.

On Groovy

Although Groovy is more or less a superset of Java it would be a shame not to use the new opportunities Groovy provides. On the other hand there are notable differences between Groovy and Ruby. In this section some of the differences between Java, Groovy and Ruby will be listed.

Using external libraries from groovy scripts and formulas

Freeplane 1.7.4 and later also support groovy annotation @grab to add required libraries to your scripts. It means you do not need to place your libraries in lib folder and they are downloaded and managed by groovy itself. The whole dependency management in Groovy scripts is documented at http://docs.groovy-lang.org/latest/html/documentation/grape.html .

The following example shows using a cvs parsing library from https://github.com/xlson/groovycsv available at maven central repository

@Grab('com.xlson.groovycsv:groovycsv:1.3')
import static com.xlson.groovycsv.CsvParser.parseCsv

def csv = '''Name,Lastname
Mark,Andersson
Pete,Hansen'''

def data = parseCsv(csv)
for(line in data) {
    node.createChild("$line.Name $line.Lastname")
}

On iteration

Groovy provides much improved ways to work on collections of data. This helps a lot in Freeplane scripting since most of the time you are working with collection of Node instances. From Java you might be used to this pattern:

  // NEVER do that in Freeplane scripting!!!
  for (i = 0; i < c.selecteds.size()-1; i++) {
    aNode = c.selecteds[i]
    aNode.text = "Do it groovy instead!"
  }

But this code is not even ineffective in Freeplane scripting (since every "c.selecteds" call creates a new list with new wrapped Node instances!) but it might even lead to errors since the list might change on the way. The following is better...

  // better, but still NOT GOOD
  def selected = c.selecteds
  for (i = 0; i < selected.size()-1; i++) {
    def aNode = selected[i]
    aNode.text = "Do it groovy instead!"
  }

Do yourself a favor and read this short article on Groovy Collections. Then you will see that the best way to do the same is

// Good!
c.selecteds.each {
  it.text = "That's groovy!"
}

c.selecteds is only evaluated once and there are no redundant variables and method calls.

On Groovy properties and the Scripting API

If an object, e.g. Node node, has a method getXyz() then groovy allows to use node.xyz. If it also has a proper setXyz() method (proper in the sense of the JavaBeans specification) then the property is writable.

Example of a read-only property: assert node.getId() == node.id println("ok")

This will print "ok" into the logfile since the assertion is valid.

Example of a read-write property: println(node.text) node.text = "please note!" println(node.text)

The second println will print the changed node text.

It's considered better style in Groovy if you use the properties instead of getters and setters. So better use

c.statusInfo = "Icons: " + node.icons.icons

instead of

c.setStatusInfo("Icons: " + node.getIcons().getIcons())

The menu item Help -> Scripting API shows the attributes instead of get/set methods where possible and indicates if the attributes are read-only, read-write or write-only.

The operator == means equals()

In Groovy the operator == is overridden to mean equals(). To check for identity use the method is()

Integer i = new Integer(3)
Integer j = new Integer(3)
assert i == j
assert ! i.is(j)

Caveat

Note that - unlike in Ruby - it's not allowed to omit the parens of a function without parameters in Groovy. So to get the number of children a node has, use node.children.size(), not node.children.size. The latter would be OK if java.util.List had a method getSize().


Wanted: Your participation!

It's very likely that scripting support lacking some functionality that would be useful for a large number of users. For this reason you are strongly encouraged to give feedback on issues you are having with scripting and on things you are missing.

  • For discussions use https://github.com/freeplane/freeplane/discussions
  • Submit bugs and feature requests at https://github.com/freeplane/freeplane/issues
  • Please share useful scripts at https://github.com/freeplane/freeplane/discussions

What users say

Further reading

This guide should have given you a quick overview over what can be done with scripts in Freeplane. Of course we have only scratched the surface. Here are some suggestions to dig further into Groovy / Freeplane scripting:

This page will present a couple of different setups that can be used for creating scripts.

A good setup can make the activity more comfortable and efficient. On the other hand, if you are still creating just simple scripts, an advanced setup will be overkill, and a basic setup will offer all you need.

The setups will be divided in 3 levels, for mere didactic reasons: Basic; Intermediate; and Advanced.

Basic

"Edit Script"

Inside FreePlane you will find the "Edit Script" tool. It was used in some examples at this Tutorial, where you can learn how it works. An advantage of this setup is that it offers a console, which can be useful to understand how your script interacts with FreePlane.

Text editor

This setup was mentioned in this introductory guide.

Intermediate

Groovy Console

The Groovy Console Add-on looks similar to the "Edit Script" tool, but it's more powerful. There are some useful tools, like the inspector of variables.

IDE (simple version, without debugging)

Creating the script inside an integrated development environment (IDE) is helpful because it has many tools dedicated to writing code, like autocompletion. This guide shows how to set the IDE for that purpose.

Complementary resources, if you get stuck in the guide:

This forum discussion may help

This is another approach

Advanced (debugging)

With debugging tools, you can very clearly see how your script interacts with Freeplane, which allows spotting the exact lines of code that are not working correctly.

This page has the most recent and easiest steps to set the IDE.

Complementary resources:

This forum discussion may help clarify the guide and bring different ways to achieve the same things.

If you want to read more about using Gradle in Freeplane and in Add-ons, take a look at this, this and this.

This page will present a couple of different setups that can be used for creating scripts.

A good setup can make the activity more comfortable and efficient. On the other hand, if you are still creating just simple scripts, an advanced setup will be overkill, and a basic setup will offer all you need.

The setups will be divided in 3 levels, for mere didactic reasons: Basic; Intermediate; and Advanced.

Basic

"Edit Script"

Inside FreePlane you will find the "Edit Script" tool. It was used in some examples at this Tutorial, where you can learn how it works. An advantage of this setup is that it offers a console, which can be useful to understand how your script interacts with FreePlane.

Text editor

This setup was mentioned in this introductory guide.

Intermediate

Groovy Console

The Groovy Console Add-on looks similar to the "Edit Script" tool, but it's more powerful. There are some useful tools, like the inspector of variables.

IDE (simple version, without debugging)

Creating the script inside an integrated development environment (IDE) is helpful because it has many tools dedicated to writing code, like autocompletion. This guide shows how to set the IDE for that purpose.

Complementary resources, if you get stuck in the guide:

This forum discussion may help

This is another approach

Advanced (debugging)

With debugging tools, you can very clearly see how your script interacts with Freeplane, which allows spotting the exact lines of code that are not working correctly.

This page has the most recent and easiest steps to set the IDE.

Complementary resources:

This forum discussion may help clarify the guide and bring different ways to achieve the same things.

If you want to read more about using Gradle in Freeplane and in Add-ons, take a look at this, this and this.

After the installation of the [Scripting environment](../scripting/Scripting_environment_setup .md) you can start editing scripts. You might also be interested in debugging scripts

This is what it looks like after opening a script via Ctrl+Shift+R:

border

Code completion and quickfixes

Eclipse helps you quite a lot in avoiding and fixing errors. Here are some examples.

Let's assume that you have created a class in a file Hello.groovy that you want to use in another script:

package hellopackage

class Hello {
    def hello() {
        c.statusInfo = "Hello world!"
    }
}

When we want to use class Hello we have to consider that it is defined in the package "hellopackage". Let's use Eclipse' editing aids to use it: After entering def hello = new hell hit Ctrl+Space

border

You will see that there is an error since the required "import hellopackage" is unfortunately not added automatically (as it is for imported Java classes). But the small red "x" indicates that a "Quick fix" is available which you can select either by clicking on the "x" or by hitting Ctrl+1

border

After selecting the first suggestion by hitting Enter you will be done:

border

My tip: Test what happens if you type Ctrl+Space whenever you think that Eclipse might have an idea what you are about to type. The idea is: You do the creative work and and Eclipse cares for the tedious details of exact naming and locating objects.

Magic keys

  • Ctrl+Space
    • Initiates content assist, completes typed texts.
    • Import declarations for completed types are automatically added.
    • Example: type "str" (without the quotes) and hit ALT space.
  • F3
    • Navigates to the definition of the variable/class under the cursor.
    • This also works for Java and Freeplane classes - allowes to lookup details of the class.
  • ALT+Cursor_Left
    • Navigates to the last remembered location.
  • Shift+Ctrl+T
    • Open a type (e.g. a class or interface).
    • Try entering "proxy" and select the Proxy from org.freeplane.plugin.script.proxy
    • Proxy is the API definition.
  • Shift+Ctrl+R
    • Use this to open a script
  • Ctrl+1

Making available groovy classes to your mind map

If in Eclipse you define and run Hello.groovy, Eclipse compiles and saves it as Hello.class in the build output folder you specified above. If you supplied a package name in the script e.g. package hellopackage, this name is used as a subdirectory, hellopackage/Hello.class. If you used the default (which it advised for scripts), it is just Hello.class.

  • Open Freeplane and open Tools > Preferences > Plugins. On the last row add the path to Eclipse' build output folder.
  • If you followed the procedure above the build output folder is scripts/bin in the Freeplane user directory. In this case simply enter scripts/bin.
  • If you have chosen some other directory (e.g. one in the Eclipse workspace) you have to specify the full path.

In Windows 7 with non-English localization this has the following complication: Suppose the full path of the build output folder is shown in a Dutch Windows 7 as C:/Gebruikers/Beheerder/workspaceFP/scripts/bin then the script class path must be C:\Users\Beheerder\workspaceFP\scripts\bin since Windows 7 translates the real path C:\Users to Dutch C:\Beheerder. Furthermore note that all slashes MUST BE backslashes on Windows. You could avoid these complications by using the Freeplane script directory directly in Eclipse as described above.

  • To take effect, restart Freeplane. (In case of problems, check the log file if Freeplane did could install the path).

Script debugging

See debugging scripts.

Here's a procedure for setting up IntelliJ IDEA.
See IDE setup for an alternative, using Gradle.

Installation and configuration

  1. Go to https://www.jetbrains.com/idea/download/
  2. Choose Community (direct download link for Windows: https://www.jetbrains.com/idea/download/download-thanks.html?platform=windows&code=IIC)
  3. Install IntelliJ IDEA (Next, Next, Next; the default options are fine)
  4. Launch IntelliJ IDEA
  5. On the Welcome screen, choose New Project
  6. Name: freeplane-scripting
  7. Language: Groovy
  8. Build system: IntelliJ
  9. JDK: if none detected, select Download JDK and choose version 17. Any Vendor: will do, e.g. Eclipse Temurin ...
  10. Groovy JDK: choose Specify Groovy SDK home and navigate to your Freeplane installation directory then to plugins and select org.freeplane.plugin.script; confirm with OK (e.g. C:\Program Files\Freeplane\plugins\org.freeplane.plugin.script - you can copy-paste)
  11. Click Create
  12. Once created, go to File->Project structure (Ctrl+Alt+Shift+S)
  13. Then to Libraries, and in the middle pane (above groovy-#.#.#) click + > Java
  14. Navigate to your Freeplane installation directory and select freeplanelauncher.jar (e.g. C:\Program Files\Freeplane\freeplanelauncher.jar - you can copy-paste)
  15. Confirm with OK the message "Library 'freeplanelauncher' will be added to the selected modules."
  16. In the far-right pane click + (above freeplanelauncher.jar)
  17. Navigate to your Freeplane installation directory > core > org.freeplane.core, select lib and confirm with OK (e.g. C:\Program Files\Freeplane\core\org.freeplane.core\lib - you can copy-paste)
  18. And again + > Freeplane installation > plugins > org.freeplane.plugin.script, select lib and confirm with OK (e.g. C:\Program Files\Freeplane\plugins\org.freeplane.plugin.script\lib)
  19. Close the Project Structure window with OK at the bottom

The installation is done. You are ready to start creating your first script.

Script example

In IntelliJ IDEA, right-click on the (blue) folder src > New->Groovy Script and in the dialog write the name hello.

  • In the file (right-hand pane), start writing def c = ScriptUtils. A drop-down will appear
  • Choose the (first) entry pointing to org.freeplane.plugin.script.proxy. It will add a line at the top import org.freeplane.plugin.script.proxy.ScriptUtils
  • Continue writing in line 3. Put a dot after ScriptUtils and wait for a drop-down to appear. Select c() (with Down) and confirm with Enter
  • Enter to the next line, then write def node = ScriptUtils.n and wait for a drop-dwonto appear with node() as the first item - confirm it with Enter
  • In a new line type c.stat and select statusInfo. You can use Down Enter or your mouse
  • Then type = "Hello. Current node id: ${node.id}
  • Finally, copy the path to your src folder, by selecting it (in the left-hand pane) and pressing Ctrl+Shift+C

Verification in Freeplane

  • In Freeplane, open Tools->Preferences… (Ctrl+Comma) and go to Preferences…->Plugins->Scripting->Script search path (see tooltip)
  • Paste your path to src (something like C:\Users\<User>\IdeaProjects\freeplane-scritping\src) and confirm with OK
  • Restart Freeplane
  • Go to Tools->Script->Hello to run it
  • Verify in the status bar that you can see Hello. Current node id: ID_#######

Bonus - non-Freeplane Groovy script

In Intellij IDEA, you can also write and execute regular Groovy scripts, not only scripts meant for Freeplane. Here's an example.

  • Right-click on your (blue) src > New->Groovy Script and give it a name, e.g. currentWeather
  • Copy and paste the code
import groovy.json.JsonSlurper

// set your location
float latitude = 50.0
float longitude = 20.0

// get the text from the web
def link = "https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current_weather=true"
// print it so that you can click on the link to be opened in your web browser
println(link)

// query OpenMeteo for the current weather information
def urlCurrentWeatherInLocation = new URL(link)
def textReturnedFromOpenMeteo = urlCurrentWeatherInLocation.text

// uncomment the next line (and add an import for JsonOutput) to print the returned text
//println(JsonOutput.prettyPrint(textReturnedFromOpenMeteo))

// convert text to a HashMap
def mapFromJson = new JsonSlurper().parseText(textReturnedFromOpenMeteo)

// print the interesting bits
println('-' * 45)
println("  Current temperature (at ${mapFromJson['latitude']} ${mapFromJson['longitude']}): ${mapFromJson['current_weather']['temperature']}")
println('-' * 45)
  • Run it with Ctrl+Shift+F10

In the Scripting API you will find all public methods that can be used in scripts.

If you are not sure about how a method needs to be written, you can see examples of each method at this reference page.

For a quick reference, use the Cheatsheet.


Other pages, that are planned:

Scripting Reference (work in progress)

To test the example codes you can use the Freeplane's script editor:

  • select the test node
  • open the script editor ( Menu->Tools->Edit script… )
  • create a new script ( Actions->New script )
  • paste the example code in the editor
  • test the code ( Actions->Run )
  • if you want, you can select other nodes and repeat the test
// This file contains Freeplane API reference for Groovy scripting.

/*
  AttributesRO
*/

/*
For the following code examples you can paste the following branch in Freeplane.
Select and copy the following lines and paste as a branch from the selected node in your mind map.

Sample Branch 01
	item A: Attributes
		item A1
		+	myAttribute	my text value
		+	aaa	v_aaa
		item A2
		+	otherAttribute	aaa
		item A3
		item A4
		+	aaa	first
		+	bbb	second
		+	aaa	third
		+	aaa	fourth
	item B
	item C

 */

// Returns "true", if the selected node contains an attribute key that is equal to "aaa". Returns "false", otherwise.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns true
        node "item A2" returns false
        node "item A3" returns false
        node "item A4" returns true
 */
node.attributes.containsKey("aaa")

// Returns the index of the first attribute with the name "aaa" if one exists or -1 otherwise.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns 1 (it's the second attribute)
        node "item A2" returns -1
        node "item A3" returns -1
        node "item A4" returns 0 (the first one is in the first attribute's position)
 */
node.attributes.findFirst("aaa")

// Returns the attribute value at the index 1.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns 'v_aaa'
        node "item A2" returns exception: "org.freeplane.plugin.script.ExecuteScriptException: Array index out of range: 1, Array index out of range: 1"
        node "item A3" returns exception: "org.freeplane.plugin.script.ExecuteScriptException: Array index out of range: 1, Array index out of range: 1"
        node "item A4" returns 'second'
 */
node.attributes.get(1)

//  Returns the values of all the attributes that has the key equal to "aaa".
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns [v_aaa]
        node "item A2" returns []
        node "item A3" returns []
        node "item A4" returns [first, third, fourth]
 */
node.attributes.getAll("aaa")

// Returns the first value of an attribute with the name "aaa" or null otherwise.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns v_aaa
        node "item A2" returns null
        node "item A3" returns null
        node "item A4" returns first
 */
node.attributes.getFirst("aaa")

// Returns the attribute key at the index 1.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns aaa
        node "item A2" returns exception: "org.freeplane.plugin.script.ExecuteScriptException: Array index out of range: 1, Array index out of range: 1"
        node "item A3" returns exception: "org.freeplane.plugin.script.ExecuteScriptException: Array index out of range: 1, Array index out of range: 1"
        node "item A4" returns bbb
 */
node.attributes.getKey(1)

// Returns all attributes as a map.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns {myAttribute=my text value, aaa=v_aaa}
        node "item A2" returns {otherAttribute=aaa}
        node "item A3" returns {}
        node "item A4" returns {aaa=fourth, bbb=second}  // (note that it takes for aaa the value of the last attribute)
 */
node.attributes.map

// Returns all attribute names in the proper sequence.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns [myAttribute, aaa]
        node "item A2" returns [otherAttribute]
        node "item A3" returns []
        node "item A4" returns [aaa, bbb, aaa, aaa]
 */
node.attributes.names

// Returns "true", if the selected node has no attributes. Returns "false", otherwise.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns false
        node "item A2" returns false
        node "item A3" returns true
        node "item A4" returns false
*/
 node.attributes.empty

// Returns the number of attributes.
/*
    using "Sample Branch 01":
    selecting
        node "item A1" returns 2
        node "item A2" returns 1
        node "item A3" returns 0
        node "item A4" returns 4
*/
node.attributes.size()

/*
  Attributes
*/

// Adds an attribute with key "aaa" and value "xxx", no matter if an attribute with the given name already exists.

node.attributes.add("aaa", "xxx")

// Adds an attribute with key "aaa", value "8", with formatting pattern "0.0", no matter if an attribute with the given name already exists.

node.attributes.add("aaa", "8", "0.0")

// Removes all attributes of the selected node.

node.attributes.clear()

// Optimizes widths of attribute view columns according to contents.

node.attributes.optimizeWidths()

// Removes the attribute at the index 1.

node.attributes.remove(1)

// Removes all attributes with name "aaa".

node.attributes.removeAll("aaa")

// Sets "xxx" as the value of the attribute at index 1.

node.attributes.set(1,"xxx")

// Sets "aaa" as the key, and "xxx" as the value of the attribute at index 1.

node.attributes.set(1, "aaa", "xxx")

// Sets "aaa" as the key, "8" as the value, and "0.0" as the format pattern of the attribute at index 1.

node.attributes.set(1, "aaa", "8", "0.0")

// Adds an attribute with key "aaa" and value "xxx" if there is no attribute with the given key or changes the value of the first attribute with the given key.

node.attributes.set("aaa", "xxx")

// Sets "0.0" as the format pattern to the attribute at index 1.

node.attributes.setFormat(1, "0.0")

/*
  BorderRO
*/

// Retrieves the color of the border.

node.style.border.color

// Retrieves the color code of the border.

node.style.border.colorCode

// Retrieves the dash pattern of the border.

node.style.border.dash

// Checks if the border uses the edge color. Returns true if it does, false otherwise.

node.style.border.usesEdgeColor

// Checks if the border uses the edge dash pattern. Returns true if it does, false otherwise.

node.style.border.usesEdgeDash

// Checks if the border uses the edge width. Returns true if it does, false otherwise.

node.style.border.usesEdgeWidth

// Retrieves the width of the border.

node.style.border.width

// Checks if the border color is set. Returns true if it is, false otherwise.

node.style.border.colorSet

// Checks if the dash pattern of the border is set. Returns true if it is, false otherwise.

node.style.border.dashSet

// Checks if the use of edge color for the border is set. Returns true if it is, false otherwise.

node.style.border.usesEdgeColorSet

// Checks if the use of edge dash for the border is set. Returns true if it is, false otherwise.

node.style.border.usesEdgeDashSet

// Checks if the use of edge width for the border is set. Returns true if it is, false otherwise.

node.style.border.usesEdgeWidthSet

// Checks if the width of the border is set. Returns true if it is, false otherwise.

node.style.border.widthSet

/*
  Border
*/

// Sets the color of the border to java.awt.Color.YELLOW.

node.style.border.color = java.awt.Color.YELLOW

// Sets the color of the border using an RGB string.

node.style.border.colorCode = "#ffff00ff"

// Sets the dash pattern of the border to "CLOSE_DOTS".

node.style.border.dash = "CLOSE_DOTS"

// Sets whether the border color matches the edge color.

node.style.border.usesEdgeColor = true

// Sets whether the border dash pattern matches the edge dash pattern.

node.style.border.usesEdgeDash = true

// Sets whether the border width matches the edge width.

node.style.border.usesEdgeWidth = true

// Sets the width of the border in integer format.

node.style.border.width = 8

// Sets the width of the border as a string.

node.style.border.width = "8"

// Sets the width of the border as a Quantity object with LengthUnit.

node.style.border.width = "8pt"

/*
  Cloud
*/

// Returns the color of the cloud set to the selected node.

node.cloud.color

// Returns the color code of the cloud set to the selected node.

node.cloud.colorCode

// Returns "true" if the selected node has a cloud enabled.

node.cloud.enabled

// Returns the shape of the cloud set to the selected node.

node.cloud.shape

// Sets "YELLOW" as the color of the selected node cloud.

node.cloud.color = java.awt.Color.YELLOW

// Sets "#ffff00ff" as the color code of the selected node cloud.

node.cloud.colorCode = "#ffff00ff"

// Enables a cloud in the selected node.

node.cloud.enabled = true

// Sets "STAR" as the shape of the selected node cloud.

node.cloud.shape = "STAR"

/*
  FreeplaneVersion
*/

// Returns the Maj number of the Freeplane version.

c.freeplaneVersion.maj

// Returns the Mid number of the Freeplane version.

c.freeplaneVersion.mid

// Returns the Min number of the Freeplane version.

c.freeplaneVersion.min

// Returns the Freeplane version.

c.freeplaneVersion.num

// Returns the Freeplane revision number.

c.freeplaneVersion.revision

// Returns "true" if the Freeplane version is final.

c.freeplaneVersion.final

// Returns the Freeplane version number as a string.

c.freeplaneVersion.numberToString()

/*
  ConditionalStyleRO
*/

// Retrieves the simple name of the condition class of the conditional style applied to the map and located at index 0.

map.conditionalStyles.findAll().conditionClassSimpleName[0]

// Retrieves the script associated with  the conditional style applied to the map and located at index 0.

map.conditionalStyles.findAll().script[0]

// Retrieves the name of the conditional style applied to the map and located at index 0.

map.conditionalStyles.findAll().styleName[0]

// Checks if there is a script condition associated with the conditional style applied to the map and located at index 0.

map.conditionalStyles.findAll().get(0).hasScriptCondition()

// Checks if the conditional style applied to the map and located at index 0 is active. Returns true if it is, false otherwise.

map.conditionalStyles.findAll().active[0]

// Checks if the conditional style applied to the map and located at index 0 is always applied. Returns true if it is, false otherwise.

map.conditionalStyles.findAll().always[0]

// Checks if the conditional style applied to the map and located at index 0 is the last one in the sequence. Returns true if it is, false otherwise.

map.conditionalStyles.findAll().last[0]

/*
  ConditionalStyle
*/

// Moves the conditional style of position 0 to position 1.

map.conditionalStyles.findAll().get(0).moveTo(1)

// Removes the conditional style of position 0.

map.conditionalStyles.findAll().get(0).remove()

// Sets the active state of the conditional style of position 0.

map.conditionalStyles.findAll().active[0] = true

// Sets whether the conditional style currently in position 0 gets as the last one in the sequence.

map.conditionalStyles.findAll().last[0] = true

// Sets the script for the conditional style of position 0.

map.conditionalStyles.findAll().script[0] = "script example"

// Sets "aaa" as the name of the style for the conditional style of position 0.

map.conditionalStyles.findAll().styleName[0] = "aaa"

/*
  ConnectorRO
  
  The examples refer to the connectors that leave the currently selected node, so they use connectorsOut. In order to reference the connectors that are reaching the node, use connectorsIn instead of connectorsOut. 
*/

// Returns the color of the connectors.

node.connectorsOut.color

// Returns the color code of the connectors.

node.connectorsOut.colorCode

// Returns the end inclination of the connectors.

node.connectorsOut.endInclination

// Returns the font family of the label of the connectors.

node.connectorsOut.labelFontFamily

// Returns the font size of the label of the connectors.

node.connectorsOut.labelFontSize

// Returns the middle label of the connectors.

node.connectorsOut.middleLabel

// Returns the opacity of the connectors.

node.connectorsOut.opacity

// Returns the shape of the connectors.

node.connectorsOut.shape

// Returns the source node of the connectors.

node.connectorsOut.source

// Returns the label of the source node of the connectors.

node.connectorsOut.sourceLabel

// Returns the start inclination of the connectors.

node.connectorsOut.startInclination

// Returns the target node of the connectors.

node.connectorsOut.target

// Returns the label of the target node of the connectors.

node.connectorsOut.targetLabel

// Returns the width of the connectors.

node.connectorsOut.width

/*
  Connector
*/

// Sets to java.awt.Color.YELLOW the color of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].color = java.awt.Color.YELLOW

// Sets "#ffff00ff" as the color of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].colorCode = "#ffff00ff"

// Sets the dash array pattern of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].dashArray = "CLOSE_DOTS"

// Sets whether to show an arrow at the end of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].endArrow = true

// Sets the inclination points of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].setInclination([5,6], [7,8])

// Sets the font family for the label of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].labelFontFamily = "Arial"

// Sets the font size for the label of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].labelFontSize = 8

// Sets the middle label of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].middleLabel = "aaa"

// Sets to 8 the opacity of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].opacity = 8

// Sets to "LINEAR_PATH" the shape of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].shape = "LINEAR_PATH"

// Sets whether the outside connector located at index 0 of the selected node simulates an edge.

node.connectorsOut[0].simulatesEdge = true

// Sets the label at the source of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].sourceLabel = "aaa"

// Sets whether to show an arrow at the start of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].startArrow = true

// Sets the label at the target of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].targetLabel = "aaa"

// Sets the width of the outside connector located at index 0 of the selected node.

node.connectorsOut[0].width = 8

/*
  ControllerRO
*/

// Exports the specified mind map to a file 'C:/t.png' in the PNG format, with an option to overwrite existing files.

boolean overwriteExistingFile = true
c.export(node.map, new File('C:/t.png'), 'Portable Network Graphic (PNG) (.png)', overwriteExistingFile)

// Finds nodes matching the condition node core is equal to "aaa", with options to include ancestors and descendants in the search set to true.

c.find(true, true, { it.text == "aaa" })

// Finds nodes matching the condition node core is equal to "aaa".

c.find{ it.text == "aaa" }

// Finds all nodes.

c.findAll()

// Finds all nodes in a depth-first manner.

c.findAllDepthFirst()

// Retrieves descriptions of all available export types.

c.exportTypeDescriptions

// Retrieves the version of Freeplane being used.

c.freeplaneVersion

// Retrieves the currently selected node.

c.selected

// Retrieves all selected nodes, as a List.

c.selecteds

// Retrieves the sorted selection of nodes, excluding the nodes that are descendants of other selected nodes.

c.getSortedSelection(true)

// Retrieves the user directory path.

c.userDirectory

// Retrieves the root node of the current view.

c.viewRoot

// Retrieves the current zoom level.

c.zoom

// Checks if the current mode is interactive. Returns true if it is, false otherwise.

c.interactive

/*
  Controller
*/

// Centers the view on the specified node. In the example, the node of ID ID_313704791.

c.centerOnNode(ID_313704791)

// Deactivates the undo functionality.

c.deactivateUndo()

// Opens the specified node for editing. In the example, the node of ID ID_313704791.

c.edit(ID_313704791)

// Opens the specified node for editing in a popup window. In the example, the node of ID ID_313704791.

c.editInPopup(ID_313704791)

// Retrieves the main thread executor service.

c.mainThreadExecutorService

// Retrieves a list of currently open mind maps.

c.openMindMaps

// Creates a new mind map from the template file "Example Template.mm", located at "C:/Example Template.mm".

c.newMapFromTemplate(new File("C:/Example Template.mm"))

// Creates a new mind map.

c.newMindMap()

// Performs a redo action.

c.redo()

// Selects the collection of nodes "someNodes".

someNodes = [] + ID_313704791 + ID_1260664080
c.select(someNodes)

// Selects the node with ID ID_313704791.

c.select(ID_313704791)

// Selects all nodes in the branch of the node with ID ID_313704791.

c.selectBranch(ID_313704791)

// Selects multiple nodes from the collection someNodes.

someNodes = [] + ID_313704791 + ID_1260664080
c.select(someNodes)

// Sets status information to be displayed.

c.setStatusInfo("hi there!")

// Sets status information to the standard info panel.

c.setStatusInfo("standard", "hi there!")

// Sets status information to the standard info panel and an icon "button_ok".

c.setStatusInfo("standard", "hi there!", "button_ok")

// Sets the zoom level to the specified ratio.

c.setZoom(8)

// Performs an undo action.

c.undo()

/*
  EdgeRO
*/

// Returns the color of the edge.

node.style.edge.color

// Returns the color code of the edge.

node.style.edge.colorCode

// Returns the line type of the edge.

node.style.edge.dash

// Returns the style (type) of the edge.

node.style.edge.type

// Returns the width of the edge.

node.style.edge.width

// Returns "true" if the edge color is set.

node.style.edge.colorSet

// Returns "true" if the edge line type is set.

node.style.edge.dashSet

// Returns "true" if the edge style (type) is set.

node.style.edge.typeSet

// Returns "true" if the edge width is set.

node.style.edge.widthSet

/*
  Edge
*/

// Sets "java.awt.Color.YELLOW" as the edge color.

node.style.edge.color = java.awt.Color.YELLOW

// Sets "#ffff00ff" as the edge color code.

node.style.edge.colorCode = "#ffff00ff"

// Sets "CLOSE_DOTS" as the edge line type.

node.style.edge.dash = "CLOSE_DOTS"

// Sets "linear" as the edge style.

node.style.edge.type = "linear"

// Sets 2 as the edge width.

node.style.edge.width = 2

/*
  FontRO
*/

// Returns the name of the font of the currently selected node.

node.style.font.name

// Returns the size of the font of the currently selected node.

node.style.font.size

// Returns "true" if the font of the currently selected node is bold.

node.style.font.bold

// Returns "true" if the font of the currently selected node is set to bold.

node.style.font.boldSet

// Returns "true" if the font of the currently selected node is italic.

node.style.font.italic

// Returns "true" if the font of the currently selected node is set to italic.

node.style.font.italicSet

// Returns "true" if the name of the font of the currently selected node is set.

node.style.font.nameSet

// Returns "true" if the size of the font of the currently selected node is set.

node.style.font.sizeSet

// Returns "true" if the font of the currently selected node is striked through.

node.style.font.strikedThrough

// Returns "true" if the font of the currently selected node is set to strike through.

node.style.font.strikedThroughSet

/*
  Font
*/

// Resets the "bold" property of font the selected node.

node.style.font.resetBold()

// Resets the "italic" property of font the selected node.

node.style.font.resetItalic()

// Resets the "name" property (i.e., the name of the font) of the font of the selected node.

node.style.font.resetName()

// Resets the "size" property of the font ogf the selected node.

node.style.font.resetSize()

// Resets the "Strike Through" property of the of the selected node.

node.style.font.resetStrikedThrough()

// Sets the font of the selected node to bold.

node.style.font.bold = true

// Sets the font of the selected node to italic.

node.style.font.italic = true

// Sets the name of the font of the selected node to "Arial".

node.style.font.name = "Arial"

// Sets the font of the selected node to size 20.

node.style.font.size = 20

// Sets the font of the selected node to strike through.

node.style.font.strikedThrough = true

/*
  IconsRO
*/

// Returns "true" if the selected node contains the icon "button_ok".

node.icons.contains("button_ok")

// Returns the icon located at the index 1 in the selected node.

node.icons[1]

// Returns the first icon that exists in the selected node.

node.icons.first

// Returns all the icons that exist in the selected node.

node.icons.icons

// Returns the urls of all the icons that exist in the selected node.

node.icons.urls

// Returns the number of icons that exist in the selected node.

node.icons.size()

/*
  Icons
*/

// Adds the icon "button_ok" to the node.

node.icons.add("button_ok")

// Removes all the icon that currently exist in the node.

node.icons.clear()

// Removes the icon at index 1.

node.icons.remove(1)

// Removes the first "button_ok" icon at that exists in the node.

node.icons.remove("button_ok")

/*
  ConditionalStyles
*/

// add a node conditional style to the end of the table
node.conditionalStyles.add(
        true, // isActive
        "node.text == 'Sunday'", // script
        'important', // styleName
        false) // isLast (aka stop)

// Adds an existing ConditionalStyleRO object. In the example, the ConditionalStyleRO object from the parent node.

node.conditionalStyles.add(node.parent.conditionalStyles.findAll())

// insert a node conditional style at the beginning of the table, with the condition "always"

node.conditionalStyles.insert(0, true, null, 'defaultstyle.floating', false)

// Inserts a copy of conditionalStyle at the specified position. It can be used to copy a conditional style between nodes or between maps. In the example, the conditional style located at index 0 of the parent of the selected node is inserted.

parentConditionalStyle = node.parent.conditionalStyles[0]
conditionalStyles.insert(0, parentConditionalStyle)

// move the third map conditional style to the top of the table

map.conditionalStyles.move(2, 0)

// remove the first map conditional style from the table

map.conditionalStyles.remove(0)

/*
  LinkRO
*/

// Retrieves the file associated with the link.

node.link.file

// Retrieves the node associated with the link.

link.node

// Retrieves the text of the link.

link.text

// Retrieves the URI of the link.

link.uri

/*
  Link
*/

// Removes the link.

link.remove()

// Sets the file associated with the link.

link.file = new File("C:/aaa.png")

// Sets the node associated with the link.

link.node = ID_1943538647

// Sets the text (stringified URI) for the link.

link.text = "http://www.google.com"

// Sets the URI for the link.

node.link.uri = new URI('http://www.google.com')

/*
  MindMapRO
*/

// Returns the background color of the map.

node.map.backgroundColor

// Returns HTML color spec like #ff0000 (red) or #222222 (darkgray).

node.map.backgroundColorCode

// Returns the filename of the map as a java.io.File object if available or null otherwise.

node.map.file

// Returns the title of the map.

node.map.name

// Returns the node that is the root of the map.

node.map.root

// Returns a list with the user defined styles names of the map.

node.map.userDefinedStylesNames

// Returns "true" if the map is saved.

node.map.saved

/*
  MindMap
*/

// Closes the mind map, with options to force close and allow interaction.

mindMap.close(true, false)

// Evaluates all formulas in the mind map.

mindMap.evaluateAllFormulas()

// Evaluates only the outdated formulas in the mind map.

mindMap.evaluateOutdatedFormulas()

// Filters nodes in the mind map with text core "aaa", don't show ancestors and show descendants.

node.map.filter(true, false){ it.text.contains("aaa") }

// Retrieves the list of listeners attached to the mind map.

mindMap.listeners

// Retrieves the storage mechanism of the mind map.

mindMap.storage

// Hides nodes in the mind map with text core "aaa", don't hide ancestors and hide descendants.

mindMap.hide(false, true){ it.text.contains("aaa") }

// Redoes the last filter applied to the mind map.

mindMap.redoFilter()

// Saves the mind map, and allow interaction during saving.

mindMap.save(allowInteraction)

// Saves the mind map as a new file.

mindMap.saveAs(new File('C:/new mindmap.mm'))

// Sets the background color of the mind map.

mindMap.backgroundColor = java.awt.Color.YELLOW

// Sets the background color of the mind map using an RGB string.

mindMap.backgroundColorCode = "#ffff00ff"

// Sets "aaa" as the name (title) of the mind map.

mindMap.name = "aaa"

// Sets the saved state of the mind map.

mindMap.saved = true

// Undoes the last filter applied to the mind map.

mindMap.undoFilter()

/*
  NodeGeometryRO
*/

// Returns the horizontal margin of the selected node.

node.geometry.horizontalMargin

// Returns "true" if the selected node has the property "uniform" activated.

node.geometry.isUniform

// Returns the shape of the selected node.

node.geometry.shape

// Returns the vertical margin of the selected node.

node.geometry.verticalMargin

/*
  NodeGeometry
*/

// Sets the node geometry as uniform.

node.geometry.isUniform = true

// Sets the shape of the node as "OVAL".

node.geometry.shape = "OVAL"

/*
  NodeRO
*/

// Retrieves all descendants of the selected node.

node.allAt("**")

// Retrieves the parent node.

node.at("..")

// Finds nodes matching the condition node core is equal to "aaa", with options to include ancestors and descendants in the search set to true.

node.find(true, true, { it.text == "aaa" })

// Finds nodes matching the condition node core is equal to "aaa".

node.find{ it.text == "aaa" }

// Finds all descendant nodes.

node.findAll()

// Finds all descendant nodes in a depth-first manner.

node.findAllDepthFirst()

// Retrieves the alias of the node.

node.alias

// Retrieves the value of the attribute with the specified name.

node.getAt("aaa")

// Retrieves a map of all attributes of the node.

node.attributes

// Retrieves the base distance to children as a Length object.

node.baseDistanceToChildrenAsLength

// Returns a BASE64 encoded node text as a binary object

node.binary

// Retrieves the branch as a text outline.

node.branchAsTextOutline

// Retrieves the layout of the child nodes.

node.childNodesLayout

// Retrieves the position of the child node ID_1725317136.

node.getChildPosition(ID_1725317136)

// Retrieves a list of child nodes.

node.children

// Retrieves the cloud of the node.

node.cloud

// Retrieves a list of conditional styles applied to the node.

node.conditionalStyles

// Retrieves a list of connectors incoming to this node.

node.connectorsIn

// Retrieves a list of connectors outgoing from this node.

node.connectorsOut

// Retrieves the count of nodes sharing the same content (i.e., clones).

node.countNodesSharingContent

// Retrieves the count of nodes sharing the same content and subtree (i.e., clones).

node.countNodesSharingContentAndSubtree

// Returns the date that the node was created.

node.createdAt

// Returns the text of the details as a Convertible.

node.details

// Returns details content type.

node.detailsContentType

// Returns the raw HTML text of the details if there is any or null otherwise.

node.detailsText

// Plain or HTML text of this node after possible transformation (formula evaluation, formatting, ...)

node.displayedText

// Returns the format string of the formatter if available and null otherwise.

node.format

// Returns true if node details are hidden.

node.hideDetails

// Returns the horizontal shift of the node.

node.horizontalShift

// Returns the horizontal shift of the node, as length.

node.horizontalShiftAsLength

// Returns the horizontal shift of the node, in screen pixels.

node.horizontalShiftInScreenPixels

// Returns the node text as HTML markup.

node.htmlText

// Returns a reference to an accessor object for icons of this node.

node.icons

// Returns the node id.

node.id

// Returns true if the node can be accessed using global accessor

node.isGlobal

// Returns time that the node was last modified.

node.lastModifiedAt

// Returns the layout orientation of the node.

node.layoutOrientation

// Returns a reference to an accessor object for link properties of this node.

node.link

// Returns the mind map this node belongs to.

node.mindMap

// Returns the minimal distance between children.

node.minimalDistanceBetweenChildren

// Returns the minimal distance between children, as length.

node.minimalDistanceBetweenChildrenAsLength

// Returns the minimal distance between children, in screen pixels.

node.minimalDistanceBetweenChildrenInScreenPixels

// Returns the next node with respect to this node in depth-first order. Returns null if this node is the only one in the map.

node.next

// Returns the node level. As it's set to false, then only nodes that are matched by the current filter are counted.

node.getNodeLevel(false)

// Returns the count of nodes sharing their content (i.e., clones) with this node.

node.nodesSharingContent

// Returns the nodes sharing their content and subtree (i.e., clones) with this node.

node.nodesSharingContentAndSubtree

// Returns the text of the note as a Convertible.

node.note

// Returns note content type.

node.noteContentType

// Returns the HTML text of the node.

node.noteText

// Returns the object that's displayed as the node text - normally the raw text of this node (then this method is equivalent to getText())

node.object

// Returns the parent node.

node.parent

// Returns a list of all nodes starting from this node upto (and including) the root node.

node.pathToRoot

// Returns the plain text content of the node. Plain text after removal of possible HTML markup.

node.plainText

// Gets the previous sibling of the current node in the tree structure. I.e., returns the previous node with respect to this node in depth-first order.

node.previous

// Retrieves the reminder associated with the node, if any.

node.reminder

// Returns plain text of this node after possible transformation and forced text shortening (e.g., a minimized node).

node.shortText

// Returns the side of the root node where the node is located.

node.sideAtRoot

// Retrieves the style of the node.

node.style

// Returns the text of the node core. Raw text of this node which might be plain or HTML text. Possible transformations (formula evaluation, formatting, ...) are not applied.

node.text

// Returns a conversion of the node to a num, if possible.

node.to.num

// Returns a conversion of the node to a date, if possible.

node.to.date

// Returns a conversion of the node to a string.

node.to.string

// Returns a conversion of the node to a text.

node.to.text

// Returns a conversion of the node to the kind of object that fits best. Uses the following priority ranking to determine the type of the text: null; Long; Double; Date; String

node.to.object

// Returns the text of the node after applying any transformations like scripts or formulas. Plain or HTML text of this node after possible transformation (formula evaluation, formatting, ...).

node.transformedText

// Retrieves the value of the node.

node.value

// Returns the vertical shift of the node.

node.verticalShift

// Returns the vertical shift of the node as Length.

node.verticalShiftAsLength

// Returns the vertical shift of the node in screen pixels.

node.verticalShiftInScreenPixels

// Returns if the node has style "ex1".

node.hasStyle("ex1")

// Returns true if p is a parent, or grandparent, ... of this node, or if it is equal to this node; returns false otherwise.

node.isDescendantOf(p)

// Checks if the node is folded. Returns true if it is, false otherwise.

node.folded

// Checks if the node is a free node. Returns true if it is, false otherwise.

node.free

// Checks if the node is a leaf node (has no children). Returns true if it is, false otherwise.

node.leaf

// Checks if the node is minimized. Returns true if it is, false otherwise.

node.minimized

// Checks if the node is the root of the map. Returns true if it is, false otherwise.

node.root

// Checks if the node is at the top or position. Returns true if it is, false otherwise.

node.topOrLeft

// Checks if the node is at the top or left position when the parent is the Root in a map view. Returns true if it is, false otherwise.

node.isTopOrLeftOnViewsWithRoot(node.parent)

// Checks if the node is visible. Returns true if it is, false otherwise.

node.visible

// Checks if the node is visible in views that have the specified root node. In the example, returns true, because the specified node is the parent.

node.isVisibleOnViewsWithRoot(node.parent)

/*
  Node
*/

node.addConnectorTo(ID_1429940931)

// Adds a connector to another node specified as a Node object. In the example, the parent of the selected node.

node.addConnectorTo(node.parent)

// Appends a clone of the specified node (without its subtree) to this node. In the example, the cloned node is ID_1429940931.

node.appendAsCloneWithoutSubtree(ID_1429940931)

// Appends a clone of the specified node (including its subtree) to this node. In the example, the cloned node is ID_1429940931.

node.appendAsCloneWithSubtree(ID_1429940931)

// Appends the branch of the specified node (in the example, node ID_1429940931) as a copy to this node.

node.appendBranch(ID_1429940931)

// Appends a copy of the specified node (in the example, node ID_1429940931) as a child to this node.

node.appendChild(ID_1429940931)

// Appends an outline text as a branch to this node. The example has a first node "aaa" and a child node "bbb".

node.appendTextOutlineAsBranch(
        """
        aaa
            bbb
        """
)

// Creates a new child node under the current node.

node.createChild()

// Creates a new child node at the index position 1 under the current node.

node.createChild(1)

// Creates a new child node with the given value under the current node. In the example, the string "aaa".

node.createChild("aaa")

// Decrypts the content of the node using the password "acb123".

node.decrypt("acb123")

// Deletes the current node.

node.delete()

// Encrypts the content of the node using the password "acb123".

node.encrypt("acb123")

// Retrieves the geometry information of the node.

node.geometry

// Checks if the node has encryption enabled. Returns true if it does, false otherwise.

node.hasEncryption()

// Checks if the node is currently encrypted. Returns true if it is, false otherwise.

node.encrypted

// Moves the node to become a child of the specified node (in the example, node ID_1429940931).

node.moveTo(ID_1429940931)

// Moves the node to a specific position (in the example, position index 1) under the specified parent node (in the example, node ID_1429940931).

node.moveTo(ID_1429940931, 1)

// Inserts the node(s) copied from clipboard as clone(s).

node.pasteAsClone()

// Sets or updates the value (in the example, value "xxx") of an attribute with the specified name (in the example, attribute "aaa") for this node.

node.putAt("aaa", "xxx")

// Removes the specified connector from the node. In the example, first is created a list of the ConnectorsOut, then the connector at index 1 of this list is removed.

listOfConnectorsOut = []
listOfConnectorsOut += node.connectorsOut
node.removeConnector(a[1])

// Removes encryption from the node using the specified password.

node.removeEncryption("abc123")

// Sets an alias for the node.

node.alias = "aaa"

// Clear all attributes and sets attributes for the node using a map of key-value pairs. In the example, sets attribute "aaa", with value "xxx", and attribute "bbb", with value "yyy".

node.attributes = ["aaa" : "xxx", "bbb" : "yyy"]

// Sets the base distance to children nodes in integer format. In the example, 8.

node.baseDistanceToChildren = 8

// Sets the base distance to children nodes as a string. In the example, 8.

node.baseDistanceToChildren = "8"

// Sets the base distance to children nodes as a Quantity object with LengthUnit. In the example, 8pt.

node.baseDistanceToChildren = "8pt"

// Sets binary data for the node. Converts data to a BASE64 encoded string and sets it as this node's text. In the example, "aaa".

node.binary = "aaa"

// Sets the layout for the child nodes as "TOPTOBOTTOM_LEFT_BOTTOM".

node.childNodesLayout = "TOPTOBOTTOM_LEFT_BOTTOM"

// Sets the creation date of the node to "2010-12-20".

node.createdAt = Date.parse("yyyy-MM-dd","2010-12-20")

// Sets the node text to a default formatted datetime object. In the example, the current date and time.

node.dateTime = new Date()

// Sets the details of the node to "aaa".

node.details = "aaa"

// Sets the content type of the node's details to "latex".

node.detailsContentType = "latex"

// Sets the details text of the node, in HTML format, to "aaa".

node.detailsText = "aaa"

// Sets the folded state of the node as true.

node.folded = true

// Sets the format of the node as 'STANDARD_FORMAT'.

node.format = 'STANDARD_FORMAT'

// Sets whether the node is free (not attached to the main map).

node.free = true

// Sets whether to hide the details of the node.

node.hideDetails = true

// Sets the horizontal shift of the node in integer format.

node.horizontalShift = 8

// Sets the horizontal shift of the node as a string.

node.horizontalShift = "8"

// Sets the horizontal shift of the node as a Quantity object with LengthUnit.

node.horizontalShift = "8pt"

// Sets the global status of the node to true.

node.isGlobal = true

// Sets the last modified date of the node to "2010-12-20".

node.lastModifiedAt = Date.parse("yyyy-MM-dd","2010-12-20")

// Sets the minimal distance between children nodes in integer format.

node.minimalDistanceBetweenChildren = 8

// Sets the minimal distance between children nodes as a string.

node.minimalDistanceBetweenChildren = "8"

// Sets the minimal distance between children nodes as a Quantity object with LengthUnit.

node.minimalDistanceBetweenChildren = "8pt"

// Sets whether the node is minimized.

node.minimized = true

// Sets the note of the node as "aaa".

node.note = "aaa"

// Sets the content type of the node's note as "latex".

node.noteContentType = "latex"

// Sets the note text of the node, in HTML format, to "aaa".

node.noteText = "aaa"

// Sets an object associated with the node. In the example, the integer 8.

node.object = 8

// Sets the side of the node at the root as "TOP_OR_LEFT".

node.sideAtRoot = "TOP_OR_LEFT"

// Sets the text of the node to "aaa".

node.text = "aaa"

// Sets the vertical shift of the node in integer format.

node.verticalShift = 8

// Sets the vertical shift of the node as a string.

node.verticalShift = "8"

// Sets the vertical shift of the node as a Quantity object with LengthUnit.

node.verticalShift = "8pt"

// Sorts the children of the node according to the specified comparator. In the example, creation date.

node.sortChildrenBy{ it.getCreatedAt() }

/*
  NodeStyleRO
*/

// Returns all style names/translation keys active for the node.

node.style.allActiveStyles

// Returns the name of the background color of the selected node.

node.style.backgroundColor

// Returns HTML color spec like #ff0000 (red) or #222222 (darkgray).

node.style.backgroundColorCode

// Returns the CSS code set to the selected node.

node.style.css

// Returns the horizontal text alignment of the selected node.

node.style.horizontalTextAlignment

// Returns max node width set to the selected node.

node.style.maxNodeWidth

// Returns min node width set to the selected node.

node.style.minNodeWidth

// Returns the name of the node's style if set or null otherwise.

node.style.name

// Returns the style node of the style set to the selected node.

node.style.styleNode

// Returns the text color of the selected node.

node.style.textColor

// Returns code of the text color of the selected node.

node.style.textColorCode

// Returns "true" if the background color of the selected node is set.

node.style.backgroundColorSet

// Returns "true" if CSS of the selected node is set.

node.style.cssSet

// Returns "true" if the "floating" property of the selected node is set.

node.style.floating

// Returns "true" if the "Horizontal Text Alignment" property of the selected node is set.

node.style.horizontalTextAlignmentSet

// Returns "true" if the "Max Node Width" property of the selected node is set.

node.style.maxNodeWidthSet

// Returns "true" if the "Min Node Width" property of the selected node is set.

node.style.minNodeWidthSet

// Returns "true" if the "Numbering" property of the selected node is enabled.

node.style.numberingEnabled

// Returns "true" if the "Text Color" property of the selected node is set.

node.style.textColorSet

/*
  NodeStyle
*/

// Sets "YELLOW" as the background color of the selected node.

node.style.backgroundColor = java.awt.Color.YELLOW

// Sets "#ffff00ff" as the background color of the selected node.

node.style.backgroundColorCode = "#ffff00ff"

// Sets "aaa" as the CSS of the selected node.

node.style.css = "aaa"

// Sets the "floating" property of the selected node as true.

node.style.floating = "true"

// Sets the "Horizontal Text Alignment" property of the selected node as "LEFT".

node.style.horizontalTextAlignment = "LEFT"

// Sets the "Max Node Width" property of the selected node as 3 px.

node.style.maxNodeWidth = 3

// Sets the "Max Node Width" property of the selected node as 2 cm.

node.style.maxNodeWidth = "2 cm"

// Sets the "Min Node Width" property of the selected node as 3 px.

node.style.minNodeWidth = 3

// Sets the "Min Node Width" property of the selected node as 2 cm.

node.style.minNodeWidth = "2 cm"

// Sets the style "aaa" as the style of the selected node.

node.style.name = "aaa"

// Sets the "numbering" property of the selected node as true.

node.style.numberingEnabled = true

// Sets "YELLOW" as the text color of the selected node.

node.style.textColor = java.awt.Color.YELLOW

// Sets "#ffff00ff" as the text color of the selected node.

node.style.textColorCode = "#ffff00ff"

/*
  ReminderRO
*/

// Retrieves the period of the reminder.

node.reminder.period

// Retrieves the unit of the period of the reminder.

node.reminder.periodUnit

// Retrieves the datetime at which the reminder is set to alert.

node.reminder.remindAt

// Retrieves the script associated with the reminder.

node.reminder.script

/*
  Reminder
*/

// Creates a periodic reminder. To make the reminder fire every second week:

node.reminder.createOrReplace(new Date() + 1, "WEEK", 2)

// Removes the reminder.

node.reminder.remove()

// Sets a script to execute when the reminder fires.

node.reminder.setScript("aaa")

/*
  Script
*/

// Grants the script permission to access the network.

c.script(new File("C:/example script.groovy")).accessingNetwork().executeOn(node.map.root)

// Executes the script on the specified node.

c.script(new File("C:/example script.groovy")).executeOn(node.map.root)

// Grants the script permission to read files.

c.script(new File("C:/example script.groovy")).readingFiles().executeOn(node.map.root)

// Grants the script permission to start applications.

c.script(new File("C:/example script.groovy")).startingApplications().executeOn(node.map.root)

// Grants the script all permissions.

c.script(new File("C:/example script.groovy")).withAllPermissions().executeOn(node.map.root)

// Grants the script permission to write files.

c.script(new File("C:/example script.groovy")).writingFiles().executeOn(node.map.root)

How to reference a node

In all the examples, the text of the referenced node is changed to this.

NodeExample
Rootnode.mindMap.root.text = "this"
Parentnode.parent.text = "this"
Selected Nodenode.text = "this"
All selected Nodesnode.text = "this"
First childnode.children[0] = "this"
All childrennode.children.each {it.text = "this"}
The whole branchnode.findAll().each {it.text = "this"}

Inspector

textUtils.copyToClipboard(node.icons.getAt(0)) //copy the name of the first icon to the clipboard
c.statusInfo = node.icons.getAt(0) 

Condition tester

Another option is to use the Filter Toolbar, with the option Filter->Highlight all matching nodes, and compose a Script Filter directly in the toolbar

if (node.text == "this") {
	c.statusInfo = "yes"
}

else {
	c.statusInfo = "no"
}

Scripting Basics (work in progress)

// This file contains tutorial examples for Freeplane Groovy scripting.

For the Scripting API see its Javadoc documentation.

The Scripting API is in some sense extended by Freeplane's utility classes and by the Libraries included in Freeplane.

Changes to the scripting API

The Scripting API will evolve over time but Freeplane's developers will do whatever possible to keep new API versions downward compatible. On the other hand there might be changes in parts of the Freeplane code that are not part of the official API but on which some scripts might depend nevertheless. This mostly applies to the utility classes.

Changes to the API are indicated per method by version numbers in the JavaDoc of the Proxy class.

Add-ons:

Batch Jobs

Debugging scripts

External script file execution

Formulas

Init scripts

Map local scripts

Libraries and utility classes:

Script filter

UpdateFreeplane's Groovyversion Security considerations

About using other languages besides Java and Groovy:


Old pages that are not relevant anymore:

This page gives instructions for developing Freeplane add-ons.

Freeplane is built from modules called "plugins" like the Scripting, Formula or LaTeX plugin, ... Add-ons are a more light-weight extension mechanism than plugins. There are several add-ons that don't need any programming know-how, but depending on the purpose of your add-on you might have to write scripts. Scripts can be organized in a special lib where they are compiled automatically when Freeplane is run, see wiki.

Add-ons are installed in the Freeplane user directory (see Tools > Open user directory). They may contain any number of scripts and Zip archives which are unpacked on installation. Combinations of scripts and Zips are especially interesting since they enable you to package scripts with required libraries/JARs/class files. For instance it's possible to bundle some Groovy scripts for creating diagrams with the JFreechart library - so there's no need to download and install the JFreechart libraries anymore. Another applications are custom Java libraries that provide additional functionality for use in formulas. See Adding JARs and class files on how to handle these cases.

Note: You will find th most current documentation of the add-on file format as comments in the add-on map itself after it has been updated by the "Check Add-on" tool.

Preparations

Install developer tools

Update to the most recent Freeplane version and install the Developer Tools from the Add-ons page (follow the installation instructions there). The add-on provides scripts that relieves you from most of the tedious work. If you experience any problems with it in the future first check if you actually have the most recent add-on version installed.

The add-on functions are available in: Tools > Developer tools

Editors, build tools, IDEs

If you are considering to create scripts as part of your add-on you it's advisable to set up an integrated scripting environment. If you have 250 MB spare disk space do it. - It will pay-off soon. There is a gradle plug-in which makes development and IDE integration easier. You find it at https://github.com/freeplane/gradle-plugin.

Steps towards your own add-on

The goal of the example add-on is to put:

  1. an existing script myCoolScript.groovy in /script/myCoolScript.groovy; and
  2. an icon mycoolicon.png in /icons/mycoolicon.png.

The steps to follow are:

  1. In Freeplane create a new empty map by Ctrl+n.
  2. Invoke Tools > Developer Tools > Build add-on. You will be asked for the name of your add-on. Answer My Cool Add-on
  3. Look through the messages in the info box that is shown if everything looks alright. The name attribute of the root node will be myCoolAddOn. This is the identifying technical name of the add-on that is usually used as a file name, for menu locations and translation keys and so on. The node text My Cool Add-on is the English name/translation of the add-on.
  4. Set the version attribute of the root node to v0.1 and fill the other attributes of the root node (only freeplaneVersionTo is optional).
  5. Write an initial description of the add-on as a child node of the description node.
  6. Create a new directory somewhere with the technical name of the add-on, myCoolAddOn.
  7. Save the new map to myCoolAddOn/myCoolAddOn.mm.
  8. Copy or move myCoolScript.groovy to myCoolAddOn/scripts/myCoolScript.groovy.
  9. In the map create a new subnode of the scripts node with name myCoolScript.groovy.
  10. Copy mycoolicon.png to zips/icons/mycoolicon.png.
  11. In the map create a new subnode of the zips node with name icons.
  12. Invoke Tools > Developer Tools > Build add-on again. This will add the required attributes of the script node and proposes proper deinstall rules (just accept them when you are asked for it).
  13. Fill the attributes of the myCoolScript.groovy node. The notes on the scripts node will help you to find the right attribute values. See also the section about menuLocation below.
  14. Save the map.
  15. Invoke Tools > Developer Tools > Package add-on for publication. This will create the file myCoolAddOn-v0.1.mm which can be installed via Tools > Scripts > Install Add-on (or via Tools > Add-ons).

Before publishing your add-on read all notes in the add-on map. (They are meant for add-on developers, not for users since users are not expected to read an add-on package.) The notes should guide you to add all missing information. Carefully revise the defaults that the Build add-on script has entered.

Script configuration

This is a bit tricky since the script configuration consists of quite a lot attributes, some of them with a strong relation to translations and to menu configuration. For most questions the notes on the scripts node will be sufficient as a documentation.

A menu location is the menu or submenu into which the new menu item for the script will be put into.

The Freeplane menus (main menu, context menu, menu for applets and file browser) are configured via XML files. It helps a lot if you get an understanding how the structure in this file relates to the actual menu. The most relevant menus for scripts are configured through mindmapmodemenu.xml. To inspect it select Download file and load the file in your web browser. To get an overview over its structure fold/unfold the nodes. You see that the "file" submenu is a sub node of the "menu_bar" menu_category which defines the main menu. (There're also definitions for context menus: "map_popup", "node_popup" and the "main_toolbar"). A menu location is a path that starts with a root menu_category, e.g.

/menu_bar/file/import

For some paths there are aliases/shortcuts. These are defined as "menu_key" attribute of a menu_submenu node, e.g.

main_menu_scripting

which is an alias for

/menu_bar/extras/first/scripting

Note that you can define menuLocations that do not exist in the menu already. If you do that you have to make sure that for every submenu level there's a translation for its name. Here's an example from the Edit Goodies add-on:

/menu_bar/edit/editGoodies

This creates a new submenu below the Edit menu. From Freeplane v1.2.10_5 on this only requires the definition of a translation for

addons.editGoodies

("addons." could have been omitted but leave it there to avoid naming collisions.)

More about the configuration of menus can be found on the wiki page Menus and commands.

Adding JARs and class files

An add-on map may contain any number of nodes containing binary files (normally .jar files) which are automatically added to the add-on's classpath if you place them under the "lib" node.

  • The immediate child nodes contain the name of the file, e.g. 'mysql-connector-java-5.1.25.jar'). Put the file into a 'lib' subdirectory of the add-on base directory.
  • The child nodes of these nodes contain the actual files.
  • Any lib file will be extracted in //lib.
  • The files will be processed in the sequence as seen in the map.

Creating Libraries

Libraries (JARs) can not only be used to include external software. Often the scripts of an add-on can be improved by extracting common functions into a library created from one or more aditional Groovy or Java files.

To create such libraries you should use a builder like Gradle:

  • Place your source files in the right subdirectory:
    • for .groovy files: src/main/groovy
    • for .java files: src/main/java
  • create a build.gradle file like one of wikdshell or roan-presentation.
  • run gradle to create the jar

Translations

Add-ons can be translated. If you used the "Build add-on" script from the "Developer tools" add-on to create your add-on, it created a "translations" branch and an "en" node for your add-on. The following keys are mandatory:

  • 'addons.${name}' for the add-on's name
  • 'addons.${name}.description' for the description, e.g. in the add-on overview dialog (not necessary for English)
  • 'addons.${name}.' for the menuTitleKey attribute of each script which is used as the menu title.

Add-on developers can define more messages at their will and use them via textUtils.getText("addons.myAddon.someAdditionalMessageKey"). Include the add-on name to avoid clashes with keys that Freeplane uses for itself.

Adding new languages

  • Duplicate the "en" node under "translations" and rename it to your locale (e.g. "fr", "de", "ru", ...).
  • Edit the translations.
  • Don't forget to send the file/translation node to the add-on author!

Note that if the translations contain non-ASCII characters you should upgrade to minimally Developer Tools v0.9.24 and Freeplane v1.7.4. With older versions your will see java escape codes instead of non-ASCII characters in your menus and other translations. Despite the fact that Freeplane can only work with java-encoded non-ASCII characters in translation strings, there is no need java-encode them before installation: this is automatically done during installation. On the other hand it is not a problem if non-ASCII characters in your translations already have been java-encoded.

Add-ons may have their own preferences

If you have properties/variables that should be configurable by the user you can extend the option panel under Tools->Preferences. Let's assume the plugin needs the variables

  • my_addon_server_url
  • my_addon_timeout_sec

You have to consider the following nodes in the add-on source map:

preferences.xml

This is a complete, syntactically correct XML string that is constructed like the preferences.xml files that are part of Freeplane. (There is one main file, one of the Scripting plugin and one of the Formula plugin.) For our purpose we need (see the previous links for extensive examples):

<?xml version="1.0" encoding="UTF-8"?>
<preferences_structure>
	<tabbed_pane>
		<tab name="plugins">
			<separator name="myaddon">
				<string name="my_addon_server_url" />
				<number name="my_addon_timeout_sec" min="0" />
			</separator>
		</tab>
	</tabbed_pane>
</preferences_structure>

This will place a new block for the new add-on in the "Plugins" tab.

Some other types to use are:

    <number name="my_addon_timeout_sec" min="0" max="1000" />
    <number name="my_addon_timeout_sec" />
    <boolean name="myAddon_myBoolean"/>

default.properties

All preference variables should have a default value so the "default.properties" node needs two attributes:

default.properties
my_addon_server_urlhttp://server.org/my_addon
my_addon_timeout_sec15

Unfortunately it leads to an error during the creation of the add-on if you enter an URL up to Freeplane version 1.2.20. Workaround: Add a single quote in front the URL to avoid it being parsed and remove the space by manually editing the .mm file.

Translation of preference entries

You have to add translations for the preferences block ("separator") and for each variable. For preferences the key is the variable name prefixed by "OptionPanel." For messages which are not preferences the variable is the key only:

en
OptionPanel.separator.myaddonMy add-on
OptionPanel.my_addon_server_urlServer URL
OptionPanel.my_addon_timeout_secTimeout[seconds]
my_addon_message_textERROR: some message text

Access the variables

Here's how you access the variables set in the OptionPanel in scripts (second parameter are default values if the value should be null):

def timeout = config.getIntProperty('my_addon_timeout_sec', 15)
def url = config.getProperty('my_addon_server_url', 'http://server.org/default')

See FreeplaneScriptBaseClass.ConfigProperties in the scripting API documentation for details.

Variables which hold a translation of e.g. a message text can be accessed in a similar way:

def static textUtils= new org.freeplane.core.util.TextUtils()
def myMessage=textUtils.getText('my_addon_message_text', 'ERROR: example message')

In scripts textUltils is a global parameter, hence the first rule is redundant. myMessage returns its text in the current language (translation).

Publish

Once you are done with a new add-on you can create a package for publication via Tools > Developer Tools > Package add-on for publication. If this succeeds you can actually publish it, see the How to publish add-ons page. - Don't miss the information on the add-on updater there!

Worked out example

See scriptlib for a worked out example. It also contains some generic scripts and illustrates adding Help to your script.

Freeplane is a program with a graphical user interface. - That's smart since it would be hard to create mindmaps otherwise...

But there are some cases where you might want to let Freeplane do something for you unattended especially if you have appropriate scripts. So here's what Freeplane supports in this respect:

  • Open the GUI, execute one or more functions and exit afterwards,
  • Execute one or more function and keep the Freeplane window opened.

All is build on two building blocks:

  • All functions in the menu (e.g. scripts) are available for batch execution.
  • The functions are submitted to Freeplane on the command line.

Howto

Preparation

Install Freeplane stable and a recent Developer Tools add-on. Then restart Freeplane.

Run a function on startup

Let's assume that you want to launch the "Open saved map..." function whenever you start Freeplane. This is how it works:

  • Start Freeplane and invoke Tools > Developer Tools > Menu item info

  • In the dialog select File > Open saved map... and click OK.

  • The necessary command line argument that is printed after "Command line option:" has been copied to the clipboard.

  • Open a command line window. If the Freeplane executables are not in the path variable you have to cd to the directory where freeplane.bat (on Windows) or freeplane.sh (on Linux) reside.

  • On Windows type

    freeplane.bat -XOpenAction

  • on Linux type (note that the dollar signs have to be quoted)

    ./freeplane.sh -XOpenAction

  • before Freeplane 1.5 menu action keys contained dollar signs and on Linux you had to protect these via single quotation marks:

    ./freeplane.sh -X'$OpenAction$0'

Run a script and terminate

Scripts have their menu items too so most of the steps also hold for scripts.

  • Find the command line option as written above. Let's assume the command line parameter is -XMyScript_on_single_node

  • On Windows type

    freeplane.bat -S -N -XMyScript_on_single_node

  • on Linux type

    ./freeplane.sh -S -N -XMyScript_on_single_node

  • Option -S makes Freeplane stop/shutdown after executing the script.

  • Option -N let's Freeplane set the system variable nonInteractive variable to true. It's upto the script to evaluate this variable like this:

    boolean isInteractive() { return !Boolean.parseBoolean(System.getProperty("nonInteractive")) }

Notes

  • Options without an argument can be combined with others like -SNX'MyScript_on_single_node'

  • If you want to execute more than one menu item use the -X option multiple times. Each item will be executed in the order given on the command line.

  • The "single instance" preferences (Environment->Single program instance) are ignored for batch jobs since the other instance may not be able to handle all commands properly. If you for instance have given the command to exit after executing the options you might not be aware that you would terminate the single instance.

Example: Exporting to file

Exporting to files requires writing a script. The type of export has to be copied verbatim from the export dialog. These strings are unfortunately internationalized so the scripts depend on the configured interface language. You can use this script to write the available descriptions to the logfile:

println c.exportTypeDescriptions.join('\n')

And this script exports the map to a file:

boolean overwriteExistingFile = true
def filename = '/tmp/' + node.map.file.name.replaceFirst('.mm$', '.pdf')
// English localization
c.export(node.map, new File(filename), 'Portable Document Format (PDF) (.pdf)', overwriteExistingFile)
// German localization
//c.export(node.map, new File(filename), 'Portables Dokumentenformat (PDF) (.pdf)', overwriteExistingFile)

Debugging allows to run scripts step by step, to inspect the content of script variables and to view the interaction between Freeplane and scripts. Debugging of scripts is a bit complicated at first but once you have mastered the first steps it will be easy.

Almost all your scripts will access properties from Freeplane - the selected node (node), the controller (c), ... Such scripts need a running Freeplane instance of course. That's why debugging of scripts starts with starting Freeplane. This must happen from Eclipse and in a special way since otherwise Eclipse will neither know about the Freeplane instance nor about your script you want to test.

  1. Open the file freeplane-osgi.launch via the Open resource command (Ctrl+Shift+R):

border

  1. The file describes how a Freeplane instance can be launched from Eclipse. Use it this way:

border

  1. Let's assume you want to debug a script called test.groovy. The script execution should be stopped before executing the second line of code. Therefore we have to set a "Breakpoint" at this line. Open the context menu over the line with a right mouse click.

(By the way: In the lower part of the image below you can see the "Console" window. It contains Freeplane's log output - very helpful in case of errors. - You don't have to visit to logfile to inspect error traces.)

border

A faster way to add breakpoints is to double click in the left bar before the line. The breakpoint is visualized as a small blue point:

border

  1. Then start the script in Freeplane. After some seconds Eclipse will get activated since the breakpoint in the script is hit. A dialog may appear in Eclipse:

border

  1. Eclipse doesn't know yet where to look for the sources of the script. Click on "Edit Source Lookup Path"

border

  1. In the following dialog click on Add then follow the screen shots

border

border

border

  1. Finally the code line is displayed! In the "Variable" view in the upper right side corner you can inspect variables. For further instructions on how to use the Debugging perspective see the Eclipse debugging perspective.

border

Enjoy!

Here's how to set up Freeplane in IntelliJ IDEA:

Importing into IDEA

  1. File->New->Project from Existing Sources and point to your cloned repo. Pay attention to point to the correct folder. For example, if the repo folder is a folder called freeplane-1.11.x that you placed in a folder called FPsource, then make sure to point to the folder freeplane-1.11.x, and not the parent folder FPsource.
  2. In "Import Project" window that appears, choose "Import project from external model" -> "Gradle"
  3. Click "Trust Project"

This should import and run Gradle for the project, downloading all dependencies.

Building

First, make sure that you are using a Gradle version that is able to build Freeplane. When this guide was written, the user had to choose a Gradle JVM lower than 20. It can be set at the IDEA Settings: File | Settings | Build, Execution, Deployment | Build Tools | Gradle.

To build the freeplane binaries, open Terminal (at the bottom, in IDEA) and run (make sure that you are at the root folder):

.\gradlew.bat build

If it complains about JAVA_HOME not being set, you need to set the variable, preferably for the system, or for this session only:

$Env:JAVA_HOME="C:\Users\<user-name>\.jdks\temurin-<version>"
.\gradlew.bat build

Change C:\Users\<user-name>\.jdks\temurin-<version> for the path of your Java JDK. It may also be, for example, at your Program files folder, like this: C:\Program Files\Java\jdk-18.0.2.

How to launch Freeplane

  • copy freeplane_debughelper/idea/runConfigurations (the whole runConfigurations directory!) containing run configuration files into .idea created by IntelliJ in project root
  • Restart IntelliJ afterwards.

Now, in the top right corner you will see the "Run/Debug configuration" options, including two called "freeplane" and "freeplane dist". You will be able to run Freeplane by choosing any of them.

Configuring the launcher for your needs

The "run configuration" is also the place to pass parameter to the launcher, like pointing to a different user folder to be used by Freeplane. Writing like this creates a new APPDATA folder inside the BIN folder, and will be used as the user directory: -U "%APPDATA%\FreeplaneTests"

Where to create the scripts

The easiest way to make the scripts be detected by the debugger is placing them inside this same project. But, there is no need to place them inside this same folder that is located Freeplane. You can create a different Module, to be dedicated for developing the scripts.

To learn how to make the debugging, see this page.

Setting the External Script Directories Search Path

There is a mechanism to load and execute scripts from script directories matching a given name scheme (hardcoded: ".*.groovy").

Starting with Freeplane 1.2 you do not have to configure the script search path since 'scripts' is the default (see below where that is).

  1. The list of script directories is configurable by selecting tools->Preferences ... from the menu, and then in the resulting Preferences window, click the Scripting button.
  2. In the Script search path (separate entries by ;;) text box, you can specify additional pathes where Freeplane can search for Groovy Scripts.

Windows

Specify your path as you would normally in windows, just be sure to add a ;; at the end of the path you add to the existing script path.

Example

If you wanted the default %USERPROFILE%.freeplane\scripts directory, and also wanted to use C:\temp you would set : scripts;;C:\temp;;

Linux, MacOS X

(todo)

(default: scripts, i.e. directory scripts in the freeplane user home).

Adding external libraries

If your script needs external libraries (.jar or .class files) add the directory containing them to the "Script classpath", see example scripts.

Executing Scripts

  • Matching scripts are listed in the menu Extra->Scripts.

Hot Key Assignment to Execution of Scripts

  • Due to the flexible standard hotkey assignment it's possible to create hotkeys for these scripts.

For each script there is a submenu with three menu entries (see Scripting for instructions how this can be controlled by the script writer).:

  • Execute for one selected node: This will invoke the script for one selected node (arbitrarily choosen), i.e. if three nodes are selected, it will be executed once, with the node variable set to one of the selected nodes. Since setting of node is not really predictable this variable should not be used.
  • Execute for all selected nodes: This will invoke the script on every selected node, i.e. if three nodes are selected, it will be executed three times, once for each node with the node variable set to the respective node.
  • Execute for all selected nodes, recursively: This will invoke the script on every selected node and recursively on all of its children.
    • Note: If a node and a child node are both selected, then the script is invoked on the child node twice.
  • To execute a script on all nodes in a map one has to select the root node and execute the script recursively.

Script Error Logging

  • Errors while loading or while execution of scripts are handled by error message popups. (See resources ExecuteScriptError.text and ReadScriptError.text.)

Formulas are very similar to formulas in spreadsheet processors like Excel or OpenOffice Calc:

 =2 + 3

Formulas, which are identified by the leading '=', are expressions that are evaluated for display. That is their result is displayed instead of the formula text. In case of =2 + 3 this would be 5. The formula itself (=2 + 3) is only visible in the editor.

Overview

Formulas can be defined in

  • node texts
  • attribute values
  • notes

Formulas are evaluated as Groovy scripts. This fact defines the basic syntax of formulas. But although Groovy is a full-blown programming language simple things are very simple in Groovy like this:

  = 3 * 2

gives 6,

  = (3 * 2) + " times"

gives 6 times. Note that the space after the '=' is optional.

Now something more complex:

  = children.sum(""){ it.text }

gives the concatenation of all child node texts. By using sum("") instead of sum we set the start value to "" and ensure that the formula also works if the node has no children at all.

  = children.sum(0){ it.to.num }

sums over the numerical values of the child nodes.

The following statement sums over the numerical values of the attribute item of all childrens. If one child does not have that attribute or if it isn't convertible to a number num0 (or getNum0()) uses 0 instead (since 1.2.1_17).

  = children.sum(0){ it['item'].num0 }

Formulas have access to a read-only variant of the Scripting API, i.e. formulas may not change anything in a map. There are some minor extensions to the Groovy language for formulas to improve the ease of use, e.g. for simpler data type conversion. Note that properties and methods of a formula node (like children or text) are directly available to the formula, i.e. the leading "node." can be left out.

References

Formulas have access to all nodes in the map by

  • navigating the hierarchy for instance via =node.children, =node.parent or =node.map.root
  • searching the map via find, e.g. =node.find{ it.text == 'sum'}.
  • direct references to a specific node by id like ID_172581364.to.num. To enter the id of a node double-click on the node while the formula editor is opened or use the function Copy Node ID in the context menu of a node.

Note that like in Excel you can easily create circular references if a node references itself (either directly or indirectly).

  = parent.children.sum{ it.to.text }

The circular reference is obviously due to navigating back and forth in the hierarchy. Now an Example that more likely may occur to you (paste the next lines into a map):

  = "count nodes above 10: " + node.find { it.to.num > 10 }.size()
    = 10
    = 11

The result should be count nodes above 10: 1 but the find tries to evaluate itself since it.to involves a formula evaluation. This leads to this error:

Circular reference: The formula in node '= count nodes....' references itself.

To prevent that you should avoid formula evaluation in the argument to find like this:

  = "count nodes matching '11': " + node.find { it.text == '11' }.size()

For analysis of complicated cases you will have to look up the logfile. Search for messages like this:

WARNING: Circular reference detected! Traceback (innermost last):
* ID_1323597872 = "count nodes above 10: " ... ->  "count nodes above 10: " + node.find { it.to.num > 10 }....
-> * ID_1323597872 = "count nodes above 10: " ... ->  "count nodes above 10: " + node.find { it.to.num > 10 }....

The node that is causing the circular reference is highlighted by an asterisk. We see that the cycle is a direct one, i.e. the node is directly referencing itself. But it doesn't need to be so simple and there might be more nodes involved when you happen to see this kind of error.

Note that many problems with circular references arise from using find. So here's one advice: Avoid find if you don't need it.

Also note that references between texts, notes and attributes of the same node do not result in a "circular reference" warning. On the other hand it doesn't matter which attribute, text or note is referenced by another node: cycles are detected only on the (coarse) node level.

When formulas get too big: Build your own utility classes

Starting with Freeplane 1.3.2 all .groovy files in the script classpath directories are automatically compiled when Freeplane starts. See Scripting! Your own utility library.

Plus operator for nodes

Given the following map:

 = children.sum()
   1
   2

This will result in "3" since the plus operator for nodes is defined as Node.to.num0 + Node.to.num0. While this is simple and nice in most cases you have to keep in mind that "+" is numeric only and will never concatenate strings.

When the map is changed...

Formulas are immediately updated when necessary. (Otherwise it's a bug that you should report.)

Formula evaluation is significantly more costly than many other things that will happen during normal operation. To reduce the overhead of formula evaluation Freeplane implements a dependency tracking mechanism that takes care to only update those formulas that reference a changed node.

But this mechanism could theoretically get fooled by complex Groovy expressions. I can't give you an example currently but it's definitely possible.

So just in case the formula processor got confused somehow there's a function Tools > Formulas > Evaluate all that re-evaluate the whole map.

Caching formula evaluation results

For continuous node visualization the properties of a node are queried much more often than they are changed. To avoid recalculation in this cases all evaluation results are stored/cached internally. This cache is initially filled on opening a map and emptied on unload of it.

For debugging purposes it is possible to switch off caching completely via the preferences page of the formula plugin. But keep in mind that this might severely impair application's performance, so don't switch caching off unless you really, really need that.

Editor support for formulas

For editing of nodes containing a formula a special editor is used that provides the following features:

  • Syntax highlighting: Support for standard Groovy expressions and node references.
  • GUI-Support for referencing other nodes: Double click a node to insert a reference to it into the formula.
  • GUI-Support for visualization of node references: If the cursor is in a node id the referenced node will be selected in the map. The tooltip of the editor will show the (transformed) text of the node in this case.

Note that the special editor will only be used if the node text already starts with an equal sign. The editor support will be further extended in the future, especially with code completion.

Formatting

Formatting of numbers and dates in node core is available as an element of styles, that means that they are not formula specific. Formatting of attribute values, details and notes must be handled by setting the value to a formatted object via format(Object, formatString). For more on data and formatting see this page.

Security

Formulas will have strict security limitations that can not be disabled via configuration. From formulas it's impossible to write to the file system or the network and you can not execute external programs. Read access is granted to Formulas only if you have enabled that for all scripts.

Miscelleneous

Richtext nodes (in node texts and notes) are supported by stripping all HTML clutter from the text before evaluation but using plaintext is definitely preferable for formulas.

Borders: Formula nodes are marked with a green border. This can be changed at View->View settings->Highlight formulas.

Attribute Access: Formulas provide simplified attribute access via the ['name'] operator:

  = children.sum(0){ it['attrib_name'].num0 }

Open issues

Please help to fix some open issues. Please leave your opinion on the discussion page or in the discussion forum.

Named nodes

Node references by node id are effective and the referenced node can be easily inspected if viewed in the formula editor. But without the editor support the node ids don't make any sense for themselves.

Named nodes would allow to make references more readable. If for instance one "parameter node" with ID ID_241399282 is used in many formulas in a map, then it would be good to give it a name, e.g. scale and to use N("scale").to.num instead of using ID_241399282.to.num.

Do you have an idea how such names should be defined? Is it enough to have named nodes or do we need named collections of nodes, too?

Implementation of functions available in spreadsheet processors?

Spreadsheet processors have a large number of functions that are not directly supported by Freeplane (see ODF specification). Of course many of these functions are not easily translatable from tabulars to mindmaps but one might strive to provide as many as possible to increase portability of existing formulas to Freeplane.

What do you think, do we need implementations for functions like NOW(), SECOND(), PPMT(), RRI(), COLUMNS(), etc., even if Groovy equivalents exist? If you do you are encouraged to provide a Groovy class with appropriate static methods and we'll see how to integrate them into Freeplane.

Limitations

  • References to nodes in other maps.

Further reads

Example Maps

Videos

Description of Vulnerability

A malicious mind map containing scripts or formulas can be used to escape the JVM sandbox and take full control over the victim's computer by leveraging Groovy to violate Java's access modifiers and disable the Security Manager. We recommend all our users to upgrade to the latest version as soon as possible.

Reported on 2017/02/19

Fix released on 2017/04/15

Severity

The CVSS score of this vulnerability is 7.8, based on vector AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H.

Affected Versions

1.5.19 and prior

1.6.1_16 and prior

Fixed Versions

1.5.20

1.6.1_17

Acknowledgments

We would like to thank Adrián Bravo Navarro (@adrianbravon ) for his research and help throughout reporting and fixing this issue.

These are the steps to publish an add-on:

Put the source code under public version control

To facilitate collaboration and continuous improvement put the source-code under version control in a public Github, Bitbucket or SourceForge repository. If you want you could contribute to the central Freeplane add-on repository (either as a Freeplane developer or via pull requests ). In most cases you will have your own repository.

Hint: Check the license of your add-on. If you have chosen the GPL (as recommended) you have to provide the source code with the add-on. If you have no compiled .jar or .class files the packaged add-on contains all sources in principle - but you should rather make the whole directory structure accessible that makes up your add-on.

Provide your add-on for download

There are many places where you can publish your packaged add-ons:

  1. In opposite to Github Bitbucket and SourceForge provide download pages.
  2. Freeplane developers have access to the Freeplane webserver.
  3. Maybe you have your own web space somewhere
  4. As a last resort you can upload an packaged add-on as an attachment of a forum post.

Add-on updater support

Freeplane periodically checks for add-ons updates but you can also do that directly via Help -> Check for updates.

To enable update check for your add-on you have to

  1. create a downloadable file with versioning information in one of the two formats described below,
  2. Freeplane will find a "version.properties" or "version.txt" file if it located directly on the add-on's homepage like the one of the devtools add-on: devtools/version.properties.
  3. If the file has a different name or location you have to specify the URL as the updateUrl of the add-on map's root node, like http://my.addon.com/path/to/version.properties.

.properties file format

Informations are stored as key=value: version=x.y.z downloadUrl=http://direct.link.to/download changelogUrl=http://link.to/your/changelog

The version property is mandatory, changelogUrl is optional.

If the version number in this file is higher than the version installed by the user, he will be prompted to go to the downloadUrl (or the add-on homepage by default) if he wants to download the latest release.

.txt file format

This is the native Freeplane versioning format that is also used for Freeplane updates: ========= x.y.z ========= your changelog here

Where x, y and z are your version numbers (the '======' lines are mandatory).

If the version number in this file is higher than the version installed by the user, he will be prompted to go to your homepage if he wants to download the latest release.

Register your add-on on the Add-ons Wiki page

Add your add-on to the add-on wiki page. You can generate an appropriate text via Tools > Developer Tools > Generate add-on documentation. Check if all links are correct (download link, add-on' and author's homepage, image).

Announce the new add-on

Do not forget to post about your new add-on in the Freeplane Open Discussion forum. (As a temporary solution you could upload the add-on as an attachment to your post if you have no better download location yet.)

If you can't continue to maintain an add-on

  • please try to find somebody who likes to adopt your package in the forum.
  • If you haven't done so make the source code available now.

Starting with 1.5.8 Freeplane supports init scripts, i. e. scripts that are executed on startup. This is especially useful for scripts that change the behavior of Freeplane, e. g. via listeners that listen on events like opening maps, mouse or keyboard events.

So here are the rules (may change until 1.5 is declared stable):

  • Init scripts are all scripts in the directory /scripts/init/, inside the user directory (Tools->Open user directory)
  • After startup (Freeplane window is up) all init scripts are run in lexicographical order of script names.
  • In an init script you can't rely on the variable node since it is not bound. You also should not assume that any script map is opened.

If you need map specific behavior encode this in your scripts by checking the name of the current map.

Examples

  • [Register a Markdown IContentTransformer](../scripting/Scripts_collection .md)
  • An extended script can be found in this forum article.

Back to scripting overview

Map local scripts are a legacy from FreeMind that most experienced script developers don't use. But some people like them to test some bit of code quickly.

Map local scripts can be defined within a map as attributes of some node. These scripts are embedded within a map and can be easily shipped with a map. A special, builtin editor is used for script editing.

In preparation for a quick intro on map local scripts create a new map with two nodes, "test 1" and "test 2", e.g. by pasting the following two lines onto the root of a new map:

test 1
test 2

Define a map local script

  • Select the node "test 1". Let's attach a script to it.
  • From the menu select Tools->Scripts->Script Editor.
  • In the script editor's menus select Actions/New Script. An entry script1 will be added to the upper left panel.
  • Write the following script in the upper right panel:
println("1st script: " + node.text)
  • Save and exit the script editor via the menu Actions/Save and Exit.
  • To check what happened make the attributes visible via menu View/Attributes/Show All Attributes (if necessary). You see that the script has been added to the map as an attribute with name script1 and the script as its value. If you would add further scripts to the same node then these will be named script2 and so forth.

Note that you may not rename the attribute. The script lookup relies on the attribute name: It has to start with "script".

Execute the script in the script editor

In the script editor's menus select Actions/Run. The following output will be printed in the lower (script output) panel:

1st script: test 1
Result:null

That way you can test your scripts very easily.

Execute the script via the menu

  • Save and exit the script editor via the menu Actions/Save and Exit if you haven't done it already.

  • Ensure that the node with the attached script is selected.

  • In the menu select Tools/Scripts/Execute selected node scripts. In the logfile (normally ~/.freeplane/log.0) you will find two new lines:

    1st script: test 1 Result:null

The Execute selected node scripts action requires you to have the script node selected.

To circumvent this use the menu entry Tools->Scripts->Execute all scripts. This executes all map local scripts.

To test how this works for multiple scripts let's create another map local script:

  • Select node "test 2"
  • Open the script editor again and create a script with a slightly different print message:
println("2nd script: " + node.text)
  • Save and exit the script editor.

  • Select Tools/Scripts/Execute all scripts. The result should something like this:

    STDOUT: 2nd script: test 2 STDOUT: Result:null STDOUT: 1st script: test 1 STDOUT: Result:null

Both scripts are executed.

Note: Map local scripts will ever have their "node" variable set to the node the respective script is attached to. If you don't want that you have to use external scripts, see Scripting or External script file execution. External scripts allow to tune the way scripts are executed on which node.

Signed scripts

Scripts may be signed for security considerations.

TODO: please fill out this gap

The Scripting API, which is defined by the org.freeplane.plugin.script.proxy.Proxy interface and is documented as JavaDoc, will evolve over time but Freeplane's developers will do whatever possible to keep new API versions downward compatible. On the other hand there might be changes in parts of the Freeplane code that are not part of the official API but on which some scripts might depend nevertheless. This mostly applies to the utility classes.

Changes to the API are indicated per method by version numbers in the JavaDoc of the Proxy class.

Here a possibly incomplete list of changes from 1.3 to 1.5:

  • node.attributes.containsKey(String)
  • node.attributes.optimizeWidths()
  • node.icons.addAll(Collection)
  • node.icons.addAll(otherNode.icons)
  • node.link.remove()
  • node.sortChildrenBy{ Closure }
  • support units like mm, cm, pt for lengths and dimensions
  • c.select(Collection)
  • c.getOpenMaps()
  • textUtils.setClipboardContentsToHtml()

Clones

  • c.pasteAsClone()
  • node.appendAsCloneWithSubtree(NodeRO toBeCloned)
  • node.appendAsCloneWithoutSubtree(NodeRO toBeCloned)
  • node.getCountNodesSharingContent()
  • node.getCountNodesSharingContentAndSubtree()
  • node.getNodesSharingContent()
  • node.getNodesSharingContentAndSubtree()

Back to Scripting overview

There are a few utility classes in Freeplane that are of special use for scripting. Look up their API in the Freeplane scripting API docs, for example coming from the menu - Help -> Scripting API. Here are the direct links:

UITools

Available via the shortcut ui, e.h. ui.frame instead of UITools.getFrame(). See it's API.

TextUtils

Mainly gives acces to available translations. Use the shortcut textUtils, e.h. textUtils.getText('invalid_url', 'The URL is invalid'). See it's API.

HtmlTools

Available via the shortcut htmlUtils, e.h. htmlUtils.toHtml("bla\nbla"). See it's API.

LogUtils

Gives access to Freeplane's standard logging facility, see it's API.

FreeplaneVersion

FreeplaneVersion.version is the full current version (like "1.2.20") but FreeplaneVersion has also accessors for major, minor versions etc. See it's API.

Back to Scripting overview

OSGI allows to control exactly which packages should be exported by a library. By this means only a few of the libraries included in the Freeplane distribution are accessible by scripts:

Accessible libraries

Inaccessible libraries that are part of the distribution

Accessing the following libraries requires repackaging of Freeplane (the libraries are grouped by their project). If there there should be a common need to add certain packages/libraries, please file a feature request here.

freeplane

  • SimplyHTML
  • forms
  • gnu-regexp

freeplane_plugin_help

  • jhall

freeplane_plugin_latex

  • jlatexmath

freeplane_plugin_svg

  • batik-anim
  • batik-awt-util
  • batik-bridge
  • batik-codec
  • batik-css
  • batik-dom
  • batik-ext
  • batik-extension
  • batik-gui-util
  • batik-gvt
  • batik-parser
  • batik-script
  • batik-svg-dom
  • batik-svggen
  • batik-swing
  • batik-transcoder
  • batik-util
  • batik-xml
  • js
  • pdf-transcoder
  • xerces_2_5_0
  • xml-apis-ext
  • xml-apis

Hints for scripting Freeplane in Python/Jython

You may want to have this url http://docs.freeplane.org/api/ at hand.

Attributes

node.attributes.get(name) # no default value, returns None if non-existant
node.attributes.set(name, value)
if 'myAttrib' in node.attributes.names:
...

Node Text, Details and Notes

txt = node.text          # also available via node.getText()
node.setText("new text") # can not assign to node.text

details = node.getDetailsText()     # Question: would node.getDetails() be better?
node.setDetails('new details text')

note = node.getNoteText()           # Question: would node.getNote() be better?
node.setNote('new note text')

Starting with Freeplane 1.3.5_05 Groovy isn't your only choice for doing scripting in Freeplane. You can use all languages that (a) build on the Java Virtual Machine (JVM) and (b) provide a JSR 223 adapter. These include most of the large list of JVM-languages , e.g. JavaScript, Jython, Scala, Clojure, ...

Built-in: JavaScript

JavaScript can be used without any further installation. To use it just create a .js file in /scripts, e.g. Test.js, and start to code. (Freeplane looks up the right script engine based on the file extension.) Here is an example:

var children = node.children;
print("children: " + children);
for (var i = 0; i < children.size(); i++) {
  print('child ' + i + ' is ' + children.get(i).plainText);
}
node.detailsText = children.size() + " children";
node.style.textColor = Java.type("java.awt.Color").RED;
c.statusInfo = "JavaScript script done!";

You see that the convenient property access known from Groovy is also supported for JavaScript.

Installation of other languages

To install a new language you only have to install all required JAR (.jar) files in /lib. Alternatively include JARs from other local folders by extending Freeplane's script classpath. Which JARs you need should be mentioned in the documentation of the language or in documentation of the JSR 223 adapter if is not part of the standard language distribution. Depending on the implementation/quality of the existing JSR 223 adpters problems might occur. If you get another language working please add a section here with a description what you had to do.

Jython

Here a step-by-step instruction to install Jython, the Python implementation that runs on the JVM:

  1. Download the all-in-one Jython-JAR, e.g. from maven central. It contains not only the language and all necessary libraries but also the JSR 223 adapter.
  2. Copy jython-standalone-.jar to /lib/.
  3. Create the following test script as /scripts/testJython.py (suffix ".py" is mandatory)
  4. Restart Freeplane, so the script appears in the menu.
  5. run it via Tools -> Scripts -> Test Jython -> Execute...one selected node. Note that the same code is also valid in Groovy and JavaScript: c.statusInfo = "Jython's here: Node's text is " + node.text

Hints for scripting Freeplane in Python/Jython can be found on page Scripting! Jython.

Drawbacks

Groovy is the distinguished scripting language for Freeplane and will be most probably always be better supported than other languages. Here are the differences:

  • Since most Freeplane scripting happens in Groovy, you will more likely find one to help you with problems in the Freeplane forum.

  • Groovy is (so far) the only language to write formulas and filters with.

  • The Groovy scripting API is extended by some methods and tweaks (see a separate page ):

    • Shortcut methods
    • Simple references to other nodes like ''ID_1723255651.text''
  • The script editor only supports Groovy scripts.

A part of this drawbacks could be worked around in the future. It could be made possible for instance to change the language for formulas per map. (If you would like to implement that show up in the Developers forum.)

For special search and filtering tasks scripting can be employed. The rich scripting API gives access to all relevant properties of nodes and the Groovy language provides all measures to express every filtering condition you may think of.

Script filters are selected either via Filter->Compose filter or via the filtering toolbar in the following way:

  • Select "Script filter" in the field that shows "Core, details or note" by default.
  • Click on "Edit script"
  • In the dialog enter some Groovy expression that returns a boolean value like true, 1 > 0, node.text.contains('bla')
  • Click on OK to close the editor.
  • In the filter composer you have to "Add" the new filter and so on (not very intuitive but you'll find your way).

Here after some samples will show you what you can do.

Node modification date

Some of us are using Freeplane to follow project's tasks. To easily follow evolution of them, we can filter nodes having a ModifyDate < last week. Meaning all nodes for which I've not made any updates since 1 week. The script filter for that is

node.lastModifiedAt <= new Date() - 7

Now, to filter for all nodes that have changed within the last 2 hours (see Groovy dates and times )

use (groovy.time.TimeCategory) {
node.lastModifiedAt <= 2.hours.ago
}

Freeplane comes with it's own version of the Groovy library. If you want up update it to a more recent one you can do that quite easily. It just takes the following steps:

  1. Download Groovy binary distribution package (e.g. groovy-binary-1.8.0.zip) from http://groovy.codehaus.org/Download.
  2. Extract the groovy-all Jar from the package
  3. Replace the old groovy-all Jar with the new one.

For Linux (non-deb version)

We assume that Freeplane is installed to /opt/freeplane:

$ unzip groovy-binary-1.8.0.zip groovy-1.8.0/embeddable/groovy-all-1.8.0.jar
inflating: groovy-1.8.0/embeddable/groovy-all-1.8.0.jar

$ sudo mv /opt/freeplane/plugins/org.freeplane.plugin.script/lib/groovy-all.jar \
/opt/freeplane/plugins/org.freeplane.plugin.script/lib/groovy-all.jar.orig

$ sudo cp groovy-1.8.0/embeddable/groovy-all-1.8.0.jar \
/opt/freeplane/plugins/org.freeplane.plugin.script/lib/groovy-all.jar

Security considerations

Scripting

Groovy, the scripting language of choice in Freeplane is a full-fledged programming language which can nearly do everything with your computer if it's unconstrained. For this reason Freeplane severely restricts script execution after installation. For script development and for using scripts most of the restrictions should be disabled.

Disabling these restriction doesn't cause a threat by its own although you should be very careful:

  • with scripts from persons that you don't know
  • with maps that contain scripts (see Map local scripts )
  • when writing your own scripts

That said normal scripts in Freeplane are less dangerous than macros contained in Office documents since there are no hooks that may start scripts on load of a map or on start of Freeplane. Every script invocation is triggered by you alone so the best advice might be this:

  • think twice before installing a script
  • think twice before executing a script

Then everything should be safe - even if you disable most of the restrictions.

Script developers and regular script users will certainly check the following options in the Preferences under Tools->Preferences->Scripting:

  • Scripts should be carried out without confirmation?
  • Permit file/read Operations (NOT recommended)
  • Trust signed scripts (recommended)

It's a bit unfortunate that you need file/read for many operations but the Java implementation requires file/read access even for mere creation of a File object, e.g. in this case:

node.link.file = c.userDirectory

Since Java checks if the file is a directory ahead of it's usage it accesses the file system.

The other options may not be necessary to check:

  • Permit file/write Operations (NOT recommended)
  • Permit Network Operations (NOT recommended)
  • Permit to Execute other Applications (NOT recommended)

A lot of very useful scripts need one or another of those but you can defer enabling them to the moment you need them.

Formulas

Formulas are somewhat similar to Office macros in that they are evaluated on loading of a map. But formulas are restricted without anyone having the possibility to override this restrictions manually. The worst a formula can do is to read and display local files if you have given scripts the "read file" permission. (That is needed if you have extended the classpath of scripts.) So be careful but not anxious.

Add-ons

Scripts that are part of add-ons have their own, independent rights management so you don't have to loosen your scripting permissions just if a certain add-on needs special permissions.

Starting with Freeplane preview version 1.3.2_02 all .groovy files in the script classpath directories are automatically compiled when Freeplane starts. The .class files are generated besides their .groovy source files in the classpath directories. Keep in mind that package declarations in the script files determine the location of the class files. See scriptlib for some generic scripts and adding Help to your script.

Extract often used functionality

This feature allows to keep your scripts and formulas more concise since you can define functionality that you often use in your scripts in a utility script/class. Let's assume that you want to create a map with a lot of formulas that compute sums over child nodes:

=node.children.sum(0){ it['total'].num0 }

and that 50 times in a map as in this map. Put that into a utility script named FP.groovy and put it into the scripts classpath (see below):

def static childAttribSum(parentNode, attributeName) {
    parentNode.children.sum(0){ it[attributeName].num0 }
}

Then your formula will look nicer:

=FP.childAttribSum(node, 'total')

Please Note:

  • in order for the library functions to be used within your scripts, the library (file) name MUST start with a capital letter
  • for utility functions you should think twice to find good function names to make it easier to remember what they do

Notes

Why 'static'?

If you forget the static in the function declaration then the simple rule Classname.method(...) won't work since non-static functions need an instance of the class in which they are defined, which is 'FP' in case of FP.groovy. In certain cases that might be what you want and it could work:

def nonStatic() {
    'blablabla'
}

Then you had to create a FP instance first and use that:

def fp = new FP()
println fp.nonStatic()

or more concise:

println new FP().nonStatic()

will print "blablabla".

No 'node', no 'c'?

Unfortunately functions (static or not) have no access to the two central scripting entry points, node (for the currently selected node) and c (the 'Controller'). You can get around these restrictions by using the ScriptUtils, new in 1.3.2_03:

import org.freeplane.plugin.script.proxy.ScriptUtils

def static test() {
    def node = ScriptUtils.node()
    def c = ScriptUtils.c()
    c.statusInfo = 'text of selected node is ' + node.text
}

Make yourself at home

Let's assume you don't like the groovy way to sum over child values. Let's also assume that you like functions with UPPERCASE LETTERS. Then you will like the following function (>= 1.3.2_03):

// use: println 'sum over children is ' + SUMC()
import org.freeplane.plugin.script.proxy.ScriptUtils

def static SUMC() {
    def node = ScriptUtils.node()
    node.children.sum(0)
}

Define constants

You can also define constants that you often use. If you define them in one place it will be easier to change them if you like. For example in a Const.groovy file :

import groovy.transform.Field
@Field final static String company = 'Scripting Geeks Inc.'
@Field final static String stdDateFormat = 'yyyy/MM/dd_hhmm'

Or for the same result :

class Const {
    final static String company = 'Scripting Geeks Inc.'
    final static String stdDateFormat = 'yyyy/MM/dd_hhmm'
}

Use it like this:

node['started'] = format(new Date(), Const.stdDateFormat)

Enable utility script compilation

Under Tools->Preferences->Plugins->Script classpath enter lib. - Relative paths will be interpreted as starting from the Freeplane user directory. So open that via Tools->Open user directory and create a directory lib in it. Put your scripts into this directory.

You can add multiple directories to the classpath. See the tooltip of the option in the preferences how to do that.

How to name the script files

If you use lowercase names for your script, like fp, then Groovy will not find this class since it "thinks" that you are referring to a variable that it doesn't know and issue an error that it doesn't have matching attribute or method.

There are many scripts and Add-ons spread over the internet. Here are some suggestions of how to search for those scripts:

Inside this documentation:

Repositories

The forums. There are many scripts spread over the two forums. Searching for the word "script" will return many of them.

  • Github forum (current forum)
  • Sourceforge forum (old forum)

These are scripts which deal mostly with editing the text of nodes.

Some of them are also available in the editgoodies addon.

Feel free to add your own scripts here. If you give script a name using wiki text like

<syntaxhighlight lang="Groovy" name="yourScriptName"> your script </syntaxhighlight>

an extra download button is created for it, and it can be downloaded directly from this page.

For larger scripts there is a special git repository [https://github.com/freeplane/addons].

Transpose the two characters around the cursor (for bad typists)

Once this script is downloaded and placed in the script directory, it should be bound to a keystroke so that it can be called without moving from the keyboard. It is now also available as part of the Edit Goodies addon, as is the script below, to change case. That's much the easiest way to install it. This version should be considered a purely instructional example.



  // @ExecutionModes({ON_SINGLE_NODE}) 
  // first we import the Java libraries needed 
  // to access and manipulate the text of a node
  import java.awt.KeyboardFocusManager 
  import javax.swing.JEditorPane 
  // Then wrap the action in a "try/catch" block so that it fails gracefully
  // though the record is written to a largely inaccessible log file, and should be displayed better
  try { 
     def focusOwner = KeyboardFocusManager.currentKeyboardFocusManager.focusOwner 
     // these two lines check that the cursor is inside a node being actively edited
     if (focusOwner instanceof JEditorPane) { 
         JEditorPane editor = focusOwner 
         // next, find the cursor position and save it in a variable
         cursor = editor.caretPosition - 1 
         // Get a copy of the node text with all the html markup stripped out
         def oldstr = htmlUtils.htmlToPlain(editor.text)
        // Make a new string with the letters around the cursor changed
         def newstr = oldstr.substring(0, cursor-1) + oldstr[cursor] + oldstr[cursor-1] + oldstr.substring(cursor+1) 
         // And write it back into the node
         editor.text = newstr 
         // finally, put the cursor back where it was
         editor.caretPosition = cursor + 1 
     } 
     else { 
         c.statusInfo = 'cannot transpose: inline editor not active' 
     } 
  } 
  catch (Exception e) { 
    logger.severe('cannot transpose', e) 
  }

Author: seatrout with polish and editing by boercher

Change case of words, and sort bAD CApitalisation

This script, like the one above, is part of the edit goodies addon, available from the support site. If used from here, it should be bound to a key

<syntaxhighlight lang="Groovy" name="caseChanger">
// @ExecutionModes({ON_SINGLE_NODE}) 
//import java.awt.Color
import java.awt.KeyboardFocusManager 
import javax.swing.JEditorPane 
import java.text.BreakIterator
// annotated a bit extra for instructional purposes
// starts with wrapping everything in a "try" block so that it crashes gracefully 

try { 
// first find the node we are working in
def focusOwner = KeyboardFocusManager.currentKeyboardFocusManager.focusOwner 
if (focusOwner instanceof JEditorPane) { 
JEditorPane editor = focusOwner 
cursor = editor.caretPosition-1 //Here we find the cursor
oldWord=editor.getSelectedText()
plaintext=htmlUtils.htmlToPlain(editor.text) // and here strip out the html for manipulating the text
isBigSelection=0
selectionStart=cursor //belt and braces to initialise this, but still
// first, select the word the cursor is in, or merely hanging around
// if there is no text presently selected
if (oldWord==null){
BreakIterator bi=BreakIterator.getWordInstance()
bi.setText(plaintext)
// this next bit should be simple, but is complicated by the need
// to do the right thing if the cursor is at either end of a word.
// the next block captures the case if it is at the beginning of a word
if (bi.isBoundary(cursor) && (bi.isBoundary(cursor-1))){
if (plaintext.substring(cursor-1,cursor) ==~/[A-z]/) {
//Problem! It could be a single-letter word, in which case
oldWord=plaintext.substring(cursor-1,cursor)
selectionStart=cursor-2
}
else {
oldWord=plaintext.substring(cursor,bi.next(2))
}
}
else {
oldWord=plaintext.substring(bi.preceding(cursor),bi.next())
selectionStart=bi.preceding(cursor)
}    
}
// or there may be text selected, perhaps several words. in that case ... 
else { 
selectionStart=editor.getSelectionStart()
selectionEnd=editor.getSelectionEnd()
oldWord=plaintext.substring(selectionStart-1,selectionEnd)
isBigSelection=1
//ui.informationMessage(ui.frame, oldWord, "The selection is")
}
// either way, now we have a selection
// and the next line does all the real work
    
newWord=cycleCase(oldWord)

// this next change changed to ensure that only one instance of a word is affected
//(bug found in v 0.2)

editor.text=changeSelectedWordOnly(plaintext,selectionStart,oldWord,newWord)
    
// now clean everything up and put the cursor back where it was 

if(isBigSelection==0){
editor.caretPosition = cursor+1
}
else {
editor.setCaretPosition(selectionStart)
editor.moveCaretPosition(selectionEnd)
}
    
} 
else { 
c.statusInfo = 'cannot change case: inline editor not active' 
} 
} 
catch (Exception e) { 
logger.severe('cannot change case', e) 
}

// acb routine to ensure only the selection is changed
// could no doubt be more elegant but life is short

def changeSelectedWordOnly(text,start,oldWord,newWord){
firsthalf=text.substring(0,start)
secondhalf=text.substring(start)
firsthalf+secondhalf.replaceFirst(oldWord,newWord)
}

// And the actual cycle case routine

def cycleCase(oldWord){
if (oldWord.toUpperCase()==oldWord){
oldWord.toLowerCase()
}
else if (oldWord.toLowerCase()==oldWord) {
oldWord[0].toUpperCase()+oldWord.substring(1).toLowerCase()
}
else {
oldWord.toUpperCase()
}
}
</syntaxhighlight>

Author: seatrout with polish and editing by boercher

Clean screen editor

A toggle script for when you want to concentrate: will either centre the selected node, hide all others, and darken the background, or switch back to the normal bright, and possibly cluttered, view.

  // @ExecutionModes({ON_SINGLE_NODE})
  import java.awt.Color
  import org.freeplane.core.resources.ResourceController
  import org.freeplane.core.ui.ColorTracker
  import org.freeplane.core.util.ColorUtils
  import org.freeplane.core.util.TextUtils
  import org.freeplane.features.mode.Controller;
  import org.freeplane.features.styles.MapStyle
  import org.freeplane.features.styles.MapStyleModel
  def setBackgroundColor(Color actionColor) {
    Controller controller = Controller.getCurrentController();
    MapStyle mapStyle = (MapStyle) controller.getModeController().getExtension(MapStyle.class);
    MapStyleModel model = (MapStyleModel) mapStyle.getMapHook(node.map.delegate);
    mapStyle.setBackgroundColor(model, actionColor);
  }
 
  def setBackgroundColorCode(String rgbString) {
    setBackgroundColor(ColorUtils.stringToColor(rgbString));
  }
 
  // note Groovy gotcha in the next line -- if "paleblue" 
  // is defined as a colour explicitly, as in
  // "Color paleblue=new Color(218,230,239)"
  // the script breaks, because variables defined in this way are not accessible inside blocks
  // they must instead be defined "naked" as below.
  // see http://groovy.codehaus.org/Scoping+and+the+Semantics+of+%22def%22
  
  paleblue=new Color(218,230,239)
  
  
  if (this.node.style.edge.getColor()==paleblue){
      clutterscreen()
  }
  else {
      clearscreen()
  }
  
  
  def clearscreen(){
    setBackgroundColor(paleblue)
    myname=this.node.getId()
    node.map.filter = { it.getId()==myname }
    this.node.style.edge.setColor(paleblue)
    c.centerOnNode(this.node)
  }
  
  def clutterscreen(){
      this.node.style.edge.setColor(Color.lightGray)
      setBackgroundColor(Color.white)
      node.map.undoFilter()
  }

Author: seatrout with the hard bits by boercher

Inserts an inline image into node text or details

This script asks for an image file for inclusion as an inline graphics either into node details or node text. Plain texts will be converted to HTML. Thanks to Q for asking for this feature.

Note: This script is here just as an example for coding. If you just want to use it use the Insert Inline Image Add-On instead.

Requires at least Freeplane 1.2.7

// @ExecutionModes({ON_SINGLE_NODE})
import groovy.swing.SwingBuilder
import java.awt.FlowLayout as FL
import javax.swing.BoxLayout as BXL
import javax.swing.ImageIcon
import javax.swing.JFileChooser
import javax.swing.JTextField
import org.freeplane.core.resources.ResourceController

def ImageIcon getIcon(String path) {
    new ImageIcon(ResourceController.getResourceController().getResource(path))
}

def builder = new SwingBuilder()
def dial = builder.dialog(title:'Insert Image', id:'insertImage', modal:true,
               locationRelativeTo:ui.frame, owner:ui.frame, pack:true, show:true) {
    panel() {
        JTextField urlField
        boxLayout(axis:BXL.Y_AXIS)
        panel(alignmentX:0f) {
            flowLayout(alignment:FL.LEFT)
            label('URL')
            urlField = textField(id:'url', columns:30)
            button(action:action(closure:{
                def chooser = fileChooser(fileSelectionMode:JFileChooser.FILES_ONLY)
                if (chooser.showOpenDialog() == JFileChooser.APPROVE_OPTION)
                    urlField.text = chooser.selectedFile.toURL()
                }), icon:getIcon("/images/fileopen.png"))
        }
        panel(alignmentX:0f) {
            flowLayout(alignment:FL.LEFT)
            label('Width:')
            textField(id:'width', columns:3)
            glue()
            label('Height:')
            textField(id:'height', columns:3)
        }
        panel(alignmentX:0f) {
            flowLayout(alignment:FL.LEFT)
            label('Target:')
            buttonGroup().with { group ->  
                radioButton(id:'text', text:'Node Text', selected:true, buttonGroup:group)  
                radioButton(id:'details', text:'Node Details', buttonGroup:group)  
            }  
        }
        panel(alignmentX:0f) {
            flowLayout(alignment:FL.RIGHT)
            button(action:action(name:'OK', defaultButton:true, mnemonic:'O',
                                 enabled:bind(source:urlField, sourceProperty:'text',
                                              converter:{ it ? true : false }),
                                 closure:{variables.ok = true; dispose()}))
            button(action:action(name:'Cancel', mnemonic:'C', closure:{dispose()}))
        }
    }
}

def String insertTag(String text, String htmlTag) {
    if (text == null)
        text = ""
    if ( ! text.startsWith("<html>"))
        text = "<html><head/><body>${text}</body></html>"
    return text.replace("</body>", htmlTag + "</body>")
}

def String imageTag(url, width, height) {
    def attribs = [ "src='${url}'" ]
    if (width)
        attribs << "width='${width}'"
    if (height)
        attribs << "height='${height}'"
    "<img ${attribs.join(' ')} />"
}

def vars = builder.variables
if (vars.ok) {
    def imageTag = imageTag(vars.url.text, vars.width.text, vars.height.text)
    if (vars.details.selected)
        node.details = insertTag(node.detailsText, imageTag)
    else
        node.text = insertTag(node.text, imageTag)
}

Author: boercher

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.

  // @ExecutionModes({ON_SINGLE_NODE})
  // Initial version: wordCount.groovy by User:cybaker
  // Adapted for Freeplane 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 delimited by a any white space character.
  // Message box for reporting added by User:seatrout
  //
  // Usage: Select node(s). Run script once.

  import java.text.NumberFormat;

  def nodes = new HashSet()
  c.selecteds.each{ nodes.addAll(it.find{true}) }

  def result = nodes.sum(0){ it.plainTextContent.split("\\s+").length }
  ui.informationMessage(ui.frame, NumberFormat.getInstance().format(result)+ " Words in selected node and children", "Word Count")

Author: cybaker

Delete line breaks

Replace line breaks in the node text by space characters.

<syntaxhighlight lang="Groovy" name="deleteLineBreaks">

// @ExecutionModes({ON_SELECTED_NODE})
node.text = node.text.replaceAll('\\s*\n\\s*', ' ')

Author: boercher

Note statistics

This script prints note statistics to the status bar no matter if the note editor panel is opened or not. Although not strictly an editing script this one shows how to access the note editor panel.

// @ExecutionModes({ON_SINGLE_NODE}) 

import org.freeplane.features.note.NoteController

def noteTextFromViewer = NoteController.controller.noteViewerComponent?.documentText
def noteText = noteTextFromViewer ? htmlUtils.htmlToPlain(noteTextFromViewer) : node.note?.to?.plain
if (noteText) {
	def wordCount = noteText.split('\\W+').length
	c.statusInfo = "note: ${wordCount} words, ${noteText.length()} characters"
}
else {
	c.statusInfo = "no note"
}

Author: boercher

With external Java libraries you can explore completely new application fields with Freeplane and accomplish amazing things. Remember: Groovy is fully Java compatible, i.e. you can use any available Java library.

General installation instructions for external Java libraries

Java libraries normally come in form of .jar files which you have to make known to the application that wants to use them. Here's the way to do that in Freeplane:

  1. only before 1.4: Create a folder lib in your Freeplane user directory

  2. Copy the .jar file to that directory.

  3. only before 1.4: Start Freeplane and add lib to Preferences -> Plugins -> Scripting -> Script -> Script classpath, and save.

  4. Restart Freeplane

To install further .jar files in the future you just have to copy the .jar files to that lib directory and restart Freeplane.

Database access: Oracle

Test script that shows how to connect to an Oracle database. Thanks to Pascal for asking.

Installation instructions:

  1. Save the script to the scripts folder in your Freeplane user directory and edit USERNAME/PASSWORD and the rest of the database url appropriately.

  2. Follow the instructions at the beginning of this chapter to install ojdbc14-10.1.0.4.0.jar (or later) to the lib directory in your Freeplane user directory

Required permissions: Execute script, read file, network access. Requires Freeplane 1.2.

// @ExecutionModes({ON_SINGLE_NODE})
import java.sql.Connection
import groovy.sql.Sql
import oracle.jdbc.pool.OracleDataSource

// def driver = Class.forName("oracle.jdbc.driver.OracleDriver")
// println driver.name

OracleDataSource ds = new OracleDataSource();
ds.setURL("jdbc:oracle:thin:USERNAME/PASSWORD@//localhost:1521/xe")
def sql = new Sql(ds.getConnection())

def mviews = node.map.root.createChild("materialized views")
sql.eachRow("select * from user_tables where table_name like 'MVIEW%'", { mviews.createChild(it.table_name)} );

Author: boercher

Database access: MySQL

Test script that shows how to connect to a MySQL database. Thanks to Pascal and Michel.

Installation instructions:

  1. Save the script to the scripts folder in your Freeplane user directory and edit database access properties appropriately.

  2. Follow the instructions at the beginning of this chapter to install mysql-connector-java-5.1.17-bin.jar (or similar) to the lib directory in your Freeplane user directory

Required permissions: Execute script, read file, network access. Requires Freeplane 1.2.

// @ExecutionModes({ON_SINGLE_NODE})
import java.sql.Connection; 
import groovy.sql.Sql
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; 

MysqlDataSource ds = new MysqlDataSource(); 

ds.setServerName("localhost"); 
ds.setUser("root"); 
ds.setPassword(""); 
ds.setDatabaseName("cdcol"); 

def sql = new Sql(ds.getConnection())

def titles = node.map.root.createChild("Titles") 
sql.eachRow("select * from cds"){
    titles.createChild(it.title)
}

Author: megatop, boercher

Database access: SQLite

Test script that shows how to connect to a SQLite database.

Installation instructions:

  1. Save the script to the scripts folder in your Freeplane user directory and edit database access properties appropriately.

  2. Download sqlite-jdbc-(VERSION).jar to the lib directory in your Freeplane user directory

Required permissions: Execute script, read+write file, network access. Requires Freeplane 1.3.

import java.sql.*;
import org.sqlite.*

try {
  SQLiteDataSource dataSource = new SQLiteDataSource();
  dataSource.setUrl("jdbc:sqlite:test.db");
  def connection = dataSource.getConnection()
  c.statusInfo = "Opened database successfully"
  // ...
} catch (Exception e) {
  e.printStackTrace()
} finally {
  if (connection != null)
    connection.close()
}

Author: boercher

JFreeChart: Diagrams and Charts

Example how to use JFreeChart in Freeplane. Thanks to Michel for asking. See also Gantt chart example.

Installation instructions:

Follow the instructions at the beginning of this chapter to install jfreechart-.jar and jcommon-.jar (download) to the lib directory in your Freeplane user directory

Required permissions: Execute script, read file. Requires Freeplane 1.2.

// @ExecutionModes({ON_SINGLE_NODE})
import org.jfree.chart.ChartFactory
import org.jfree.chart.ChartPanel
import org.jfree.data.general.DefaultPieDataset
import groovy.swing.SwingBuilder
import java.awt.*
import javax.swing.WindowConstants as WC

def piedataset = new DefaultPieDataset();
piedataset.with {
     setValue "Apr", 10
     setValue "May", 30
     setValue "June", 40
}

def options = [true, true, true]
def chart = ChartFactory.createPieChart("Pie Chart Sample",
    piedataset, *options)
chart.backgroundPaint = Color.white
def swing = new SwingBuilder()
def frame = swing.frame(title:'Groovy PieChart',
        defaultCloseOperation:WC.EXIT_ON_CLOSE) {
    panel(id:'canvas') { widget(new ChartPanel(chart)) }
}
frame.pack()
frame.show()

Author: boercher

And here the script for Gantt chart generation

// @ExecutionModes({ON_SINGLE_NODE})
import groovy.swing.SwingBuilder

import javax.swing.WindowConstants as WC

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.data.category.IntervalCategoryDataset;
import org.jfree.data.gantt.Task;
import org.jfree.data.gantt.TaskSeries;
import org.jfree.data.gantt.TaskSeriesCollection;
import org.jfree.data.time.SimpleTimePeriod;

// adapted from http://www.java2s.com/Code/Java/Chart/JFreeChartGanttDemo1.htm

// - - - Test Map: remove leading "// " and copy/paste it into an empty map - -
// Iteration 1
//   Design
//     2011-07-01
//     2011-07-08
//   Implement
//     2011-07-07
//     2011-07-15
//   Test
//     2011-07-12
//     2011-07-22
// Iteration 2
//   Design
//     2011-07-25
//     2011-08-01
//   Implement
//     2011-07-25
//     2011-08-10
//   Test
//     2011-08-01
//     2011-08-12
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

//
// main
//
final IntervalCategoryDataset dataset = createDataset();
final JFreeChart chart = createChart(dataset);

def swing = new SwingBuilder()
def dialog = swing.dialog(title:'Groovy Gantt', locationRelativeTo:ui.frame, owner:ui.frame
        , defaultCloseOperation:WC.DISPOSE_ON_CLOSE) {
    panel(id:'canvas') { widget(new ChartPanel(chart)) }
}
ui.addEscapeActionToDialog(dialog)
dialog.pack()
dialog.show()

// create task data from the map. Note the use of inject
// (see http://insidethemachine.wordpress.com/2009/01/25/injectgroovy/)
def IntervalCategoryDataset createDataset() {
    return node.map.root.children.inject(new TaskSeriesCollection()) { seriesCollection, seriesNode ->
        seriesCollection.add(seriesNode.children.inject(new TaskSeries(seriesNode.to.plain)) { series, taskNode ->
            // real live software will be a bit more permissive
            def dates = taskNode.children.collect{ dateNode -> dateNode.to.date }
            if (dates.size() != 2)
                throw new RuntimeException(taskNode + " does not have exactly 2 date children as expected")
            series.add(new Task(taskNode.to.plain, new SimpleTimePeriod(dates[0], dates[1])))
            series // this is a "return"
        })
        seriesCollection // this is a "return"
    }
}

def JFreeChart createChart(final IntervalCategoryDataset dataset) {
    return ChartFactory.createGanttChart(
        "Gantt Chart Demo"  // chart title
        , "Task"            // domain axis label
        , "Date"            // range axis label
        , dataset           // data
        , true              // include legend
        , true              // tooltips
        , false             // urls
    );
    return chart;
}

The first version of this Scripting article mainly consists/consisted of a port of the FreeMind script collection. Some of those scripts got a general rewrite; - especially those that were marked buggy or even broken. But I took the freedom to improve every script where it made sense. With one exception ("Sum up all subnodes...", a very long script) I have ported all scripts from the FreeMind page, regardless of how useful I found them since I believe that you will be able to learn from all of them.

Unfortunately scripts might get old over time, i.e. when scripting idioms evolve over time old scripts should be upgraded. If you find such scripts do a post in the forum.

  • Scripts for text editing have been hived off to a separate page
  • Scripts that use external libraries have their separate page, too.
  • Scripts that might need a review before they are added here can be found in the Script incubator.

For larger scripts there is a special git repository [https://github.com/freeplane/addons].

A node with the last modification date of the map

This script sets the text of the status bar to the last modification timestamp of the whole map. format() is a free method of the Groovy script base class FreeplaneScriptBaseClass.

// @ExecutionModes({ON_SELECTED_NODE})
// find all nodes, collect their lastModifiedAt date and get the latest
def lastModifiedAt = c.findAll().collect{ it.lastModifiedAt }.max()
c.statusInfo = "The map was last modified at: " + format(lastModifiedAt, "yyyy-MM-dd hh:mm:ss")

Author: Boercher

Add up attribute values of subnodes.

This script adds up the "AMOUNT" attributes of all child nodes of a node and sets the "SUM" attribute of the selected node to the sum. The start value ensures that the argument is created always, even if the node has no children. Note that node[] returns a Convertible.

def startValue = node['AMOUNT'].to.num0
node['SUM'] = node.children.sum(startValue){ it['AMOUNT'].to.num0 }
// @ExecutionModes({ON_SELECTED_NODE})

To set a special formatting use the format() method again:

def sum = node.children.sum(0){ it['AMOUNT'].to.num0 }
node['SUM'] = format(sum, '0.0')
// @ExecutionModes({ON_SELECTED_NODE})

The following script does the same for the whole map.

c.findAllDepthFirst() iterates the map in the right order, starting from the leaf nodes. Uncomment the lines containing "index".

You should study how to use Groovy Collections methods like collect(), each(), sum() since this is one of most important topics for scripting beginners.

//int index = 1
c.findAllDepthFirst().each { n ->
    def sum
    if (n.isLeaf()) {
        sum = n['AMOUNT'].to.num0
    } else {
        def startValue = n['AMOUNT'].to.num0
        sum = n.children.sum(startValue){ it['SUM'].to.num0 }
    }
    n['SUM'] = format(sum, '0.0')
    //n['index'] = index++
}
// @ExecutionModes({ON_SELECTED_NODE})

Original author: yubrshen, general rewrite by Boercher for Freeplane

Copies the hyperlink of a node to the clipboard. Print message to the status bar if the node contains no link.

// @ExecutionModes({ON_SINGLE_NODE})
def link = node.link.text
if (link)
	textUtils.copyToClipboard(node.link.text)
else
	c.statusInfo = "no link in ${node.text}"

Author: Boercher

Sort child nodes alphabetically, by length or by other properties

def sorted = new ArrayList(node.children).sort{ it.text }
sorted.eachWithIndex { it, i ->
    it.moveTo(node, i)
}
// @ExecutionModes({ON_SELECTED_NODE, ON_SELECTED_NODE_RECURSIVELY})

To sort

  • by length: Change "it.text" to "it.text.length()".
  • by last modification date: Change "it.text" to "it.lastModifiedAt".
  • by creation date: Change "it.text" to "it.createdAt".
  • by the numeric value of an attribute "some_attrib": Change "it.text" to "it['some_attrib'].num0"

You can use every node attribute that is sortable - numbers, strings, ...

To reverse either of these sorts: Replace "sorted.eachWithIndex" by "sorted.reverse().eachWithIndex"

Author: Boercher

Sort attributes by name

The following script may be adjusted by changing the variable caseInsensitive or the body of the comparator.

Note that everything would be easier if attribute names were unique. Then we could use node.attributes.map. But if an attribute name appears more than once the map has less entries than the node has attributes.

Note how we define comparator as a block of code (a "Closure").

// @ExecutionModes({ON_SELECTED_NODE})
def caseInsensitive = true
def comparator = {
    def string = it[0]
    if (caseInsensitive)
        string.toLowerCase()
    else
        string
}
def nodeAttributes = node.attributes
 
// save original attributes
def attribs = []
nodeAttributes.names.eachWithIndex { name, i ->
    attribs.add([name, nodeAttributes.get(i)])
}
 
// replace attributes
nodeAttributes.clear()
attribs.sort(comparator).each { k, v ->
    nodeAttributes.add(k, v)
}

Sort attributes by value

The following script is similar and may also be adjusted by changing the variable caseInsensitive or the body of the comparator.

// @ExecutionModes({ON_SELECTED_NODE})
def caseInsensitive = true
def comparator = {
    def string = it[1] == null ? '' : it[1].toString()
    if (caseInsensitive)
        string.toLowerCase()
    else
        string
}
def nodeAttributes = node.attributes
 
// save original attributes
def attribs = []
nodeAttributes.names.eachWithIndex { name, i ->
    attribs.add([name, nodeAttributes.get(i)])
}
 
// replace attributes
nodeAttributes.clear()
attribs.sort(comparator).each { k, v ->
    nodeAttributes.add(k, v)
}

Author: Boercher

Set up a logger

The following code makes use of the application logger which logs to the standard Freeplane logfile. (Note: no import, no static access):

logger.info("Hello world!");

Import the structure of a LaTeX document as a mind map

Resulted from discussion in this forum discussion.

Note: This script is not tested - please review it and remove this note if it works.

Author: Cyril Crassin, adapted for Freeplane by Boercher

import javax.swing.JFileChooser

import org.freeplane.plugin.script.proxy.Proxy

/**
 * @author Cyril Crassin
 * adapted from http://www.icare3d.org/Blogger/Files/FreeMindLatexImportScript.groovy
 * by Volker Boerchers
 */
JFileChooser chooser = new JFileChooser('.')
chooser.showOpenDialog()
File file = chooser.getSelectedFile()

if ( ! file)
	return

def sectionhierarchy = [
	"\\part",
	"\\chapter",
	"\\section",
	"\\subsection",
	"\\subsubsection",
	"\\paragraph",
	"\\subparagraph"
]

Proxy.Node prevNode = node.mindMap.root
prevLevel = 0
String curNoteText = ""
String lastNoteTextAdd = ""

prevNode.text = "PhDThesis"

file.eachLine{
	secFound = false
	for (i = 0; i<sectionhierarchy.size(); i++) {
		if (it.contains(sectionhierarchy[i])) {
			//Flush text
			if (curNoteText.length() > 0) {
				//curNoteText = curNoteText+lastNoteTextAdd
				curNoteText = curNoteText+"</body>\n</html>"

				prevNode.text = curNoteText
				//c.setXmlNoteText(prevNode, curNoteText)
			}
			lastNoteTextAdd = ""
			curNoteText = ""

			//Deal with new node
			openAcc = it.indexOf('{')
			closeAcc = it.indexOf('}')

			curLevel = i
			sectionName = it.substring(openAcc+1, closeAcc)

			while (prevLevel>=curLevel &&  prevNode != node.mindMap.root) {
				prevNode = prevNode.parent
				prevLevel--
			}
			def newNode = prevNode.createChild(sectionName)

			prevNode = newNode
			prevLevel = curLevel

			secFound = true
			break
		}
	}

	if (!secFound){
		if (it.length() > 0 || curNoteText.length() > 0 || lastNoteTextAdd.length() > 0){
			if (curNoteText.length() == 0){
				curNoteText += "<html>\n<head>\n<style type=\"text/css\">\n <!--\np { margin-top: 0 }\nbody { font-family: SansSerif; font-size: 12pt }\n-->\n</style>\n</head>\n<body>"
			}
			curNoteText += lastNoteTextAdd
			lastNoteTextAdd = "<p>" + it + "</p>\n"
		}
	}
}

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.

Tested with Freeplane 1.1 and 1.2.

import javax.swing.*;

// for cut 'n paste:
def showDialog(String text) {
    def dialog = new JDialog(ui.frame)
    dialog.setSize(350, 450)
    dialog.setLocationRelativeTo(ui.frame)
    dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
    dialog.add(new JScrollPane(new JTextArea(text)))
    ui.addEscapeActionToDialog(dialog)
    dialog.visible = true
}

def processAttribute(attr, attr_name) {
    return (attr.findAttribute(attr_name) != -1) ?
        attr_name + " = \"" + attr.get(attr_name) + "\"" :
        null
}

def process(type, attr, index) {
    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']
    // note for Freeplane version < 1.2: 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 }.join(",\n  ") +
        '\n}\n\n'
}

index = 1;
// merge everything into one string
def result = node.find{ true }.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)

Author: Leonardo, general rewrite for Freeplane by Boercher

Use the following script to create a map for testing purposes. It adds some "BibTeX nodes" to selected nodes:

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'])

Export Node children as table for latex import

Simple script to export node children organised as two column tabular environment in latex. First Column is filled by child text, second column by latex equation attached to each. I assume you use \import command like:

\begin{table}[H] \input{filename.tex} \end{table}

// @ExecutionModes({ON_SINGLE_NODE})

// we can't use LatexExtension.class directly since the class is not public

def buildLatexRow(node,latexExtension){
	def result = node.text	
	result = result + " & " + "\$" + latexExtension.equation + "\$" + "\\\\"
	return result
}
def findLatexExtension(node) {
	def result = null
	node.delegate.extensions.values().each{
		if (it.getClass().simpleName == 'LatexExtension')
			result = it
	}
	return result
}

def fos= new FileWriter(node.text+'.tex')
fos.write("\\begin{tabular}{ll}\n")
fos.write("\\hline\n")	
node.children.each {fos.write(buildLatexRow(it,findLatexExtension(it))+"\n")}
fos.write("\\hline\n")	
fos.write("\\end{tabular}")
fos.close()

Author: catamik,

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.

import javax.swing.*;

// for cut 'n paste:
def showDialog(String text) {
    def dialog = new JDialog(ui.frame)
    dialog.setSize(350, 450)
    dialog.setLocationRelativeTo(ui.frame)
    dialog.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE)
    dialog.add(new JScrollPane(new JTextArea(text)))
    ui.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"))

Author: Boercher

Output A Map to CSV Part 2

The second iteration of the export 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:

class TreeWalker {

    def rootNode;
    def minFontSize;
    private iconMappings = [:]
    private attributeMappings = [:]
    private attributeNames = []

    def visit(thisNode, childPosition) {
        def attributes = [:]
        def nodeName = thisNode.plainText
        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();

Author: Yellek, prepared for Freeplane by Boercher

Daves massivly cheezy Api Generator

An extended version of the original apiGenerator.groovy is part of the Freeplane standard installation and can be invoked via Help->Scripting API. For its source code see apiGenerator.groovy at github.

Author: Dke211 (Dave), prepared and extended for Freeplane by 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)

def findOrCreate(nodeTitle, parentNode) {
    def matches = c.find{ it.text.equals(nodeTitle)}
    return matches ? matches.getAt(0) : parentNode.createChild(nodeTitle)
}

def bookmarksNode = findOrCreate('Bookmarks', node.mindMap.root)
def recentBookmarkNode = findOrCreate('recent', bookmarksNode)

recentBookmarkNode.link.node = c.getSelected()
def recentBookmarkNodes = c.find { it.text == 'recent' && it.parent?.text == 'Bookmarks' }
if (recentBookmarkNodes) {
    def recentNode = recentBookmarkNodes.get(0).link.node
    if (recentNode) {
        c.select(recentNode)
    }
}
def bookmarkNodes = c.find { it.text == 'Bookmarks' }
if (bookmarkNodes) {
    def children = bookmarkNodes.get(0).children
    if (children) {
        c.select(children.get(0))
    }
}

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!

TODO: make an add-on out of this!

Author: philshvarcz

Create a map with Firefox bookmarks

This script asks for a Firefox bookmarks-.json file and presents its content as a new mindmap. Requires at least Freeplane 1.2.7

Update (2015-02-05): Firefox has changed the file format for bookmark backups. Manual backups are still JSON but you could also use HTML, see this Mozilla forum post.

// @ExecutionModes({ON_SINGLE_NODE})
import groovy.io.FileType
import groovy.json.JsonSlurper
import javax.swing.JFileChooser

def filename = ui.showInputDialog(node.delegate
   , "Provide a bookmark-<date>.json file" +
     "\n(see folder bookmarkbackups in Firefox profile directory)",
   , findBookmarkFile())
if (! filename)
    return
def file = new File(filename)
if (!file.exists()) {
    ui.errorMessage(filename + " does not exist." +
        "\nIn Firefox 'about:support' shows your profile directory")
    return
}
def json = new JsonSlurper().parse(file.newReader('UTF-8'))

def map = c.newMap()
map.root.text = file.name
def handleEntry(parentNode, Map m) {
    def title = m["title"]
    def children = m["children"]
    if (! title && ! children)
        return
    def child = parentNode.createChild(title ? title : "")
    m.each{ key, value ->
        if (key != "children") {
            child[key] = value
        }
    }
    def uri = m["uri"]
    try {
        // special URIs parts are not properly encoded in Firefox bookmarks
        if (uri != null)
            child.link.text = uri.replace("%s", "%25s").replace("|", "%7C")
    } catch (Exception e) {
        logger.warn("cannot convert " + uri, e)
    }
    if (children)
        children.each{ handleEntry(child, it) }
}

def children = json["children"]
if (children != null)
    children.each{ handleEntry(map.root, it) }


def findBookmarkFile() {
    def bookmarkFiles = new TreeSet<File>()
    def locations = [
        System.getenv("APPDATA") + "\\Mozilla\\Firefox\\Profiles"
        , System.getProperty('user.home') + "/.mozilla/firefox"
    ]
    locations.each{ dir ->
        def location = new File(dir)
        if (location.exists()) {
            location.eachFileRecurse{ f ->
                if (f.name.matches("bookmarks[\\d-]*.json"))
                    bookmarkFiles.add(f)
            }
        }
    }
    if (bookmarkFiles)
        return String.valueOf(bookmarkFiles.last()) // youngest
    return ""
}

Author: boercher

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.

// @ExecutionModes({ON_SELECTED_NODE})
 
def resultNode = node.createChild("Connected Nodes")
resultNode.style.backgroundColorCode = '#FFFF00'
resultNode.link.node = node
node.findAll().each {
    it.connectorsOut.each {
        def target = it.target
        def child = resultNode.createChild("${it.source.text} --> ${target.text}")
        child.link.setNode(target)
    }
}

Author: ccrick, adapted to Freeplane 1.2 by boercher

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.

// @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.mindMap.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)

Author: boercher

Pomodoro Timer

To encourage focusing on doing concrete tasks, and accumulate Pomodoro credits, this script provides a Pomodoro timer against a node in mind-map. When the time reaches the break time, plays sound of applause for encouragement, and when the time is up, add the time Pomodoro time credit to the current node's attribute with the name of 'Pomodoro', and add to the root node's attribute with name of today's date.

Need to customize the path to the audio file "APPLAUSE.WAV" in function playSound.

import groovy.swing.SwingBuilder
import java.awt.FlowLayout as FL
import javax.swing.BoxLayout as BXL
import javax.swing.JFrame
import groovy.beans.Bindable
import java.util.timer.*  
import java.applet.Applet;
import java.applet.AudioClip;
//import org.freeplane.plugin.script.proxy.Node

/*
 To encourage focusing on doing concrete tasks, and accumulate Pomodoro credits, this script provides a Pomodoro timer against a node in mind-map. 
 When the time reaches the break time, plays sound of applause for encouragement, 
 and when the time is up, add the time Pomodoro time credit to the current node's attribute with the name of 'Pomodoro', 
 and add to the root node's attribute with name of today's date. 

 Need to customize the path to the audio file "APPLAUSE.WAV" in function playSound

 Developed by Yu Shen based on examples of SwingBuilder in Freeplane Forum, and other examples of timer tasks, and @Bindable found in Internet
 2012-01-01
*/

class CountDown { // resolution: second
  int delay = 1 // seconds
  int period = 1 // seconds
  int countDownValue = 25*60 // seconds, the total value of the countDown, per Pomodoro Techniques: http://www.pomodorotechnique.com/
  int remainingTime = countDownValue // seconds, multiple of 60 (for minute)
  int breakTime = (int) (countDownValue/5) // seconds, time for break
  int countDownTime = remainingTime
  boolean running = true
  //Node node
  def node
  TimerTaskCountDown task
  Timer timer

  CountDown (// Node
    nodeIn) { 
    node = nodeIn
    task = new TimerTaskCountDown(this)
    timer =  new Timer()
    timer.scheduleAtFixedRate(task, delay*1000, period*1000)
  }
  
  // adaptive display for count down time, and available operation
  @Bindable String timeStr = "25:00"
  @Bindable String buttonName = 'Pause'

  public int getElapsedTime () {
    (int) ((countDownTime - remainingTime)/60) // convert to minutes
  }

  def getValue(node, attrib) {// get valid attribute value
    def value = node.getAttributes().get(attrib)
    (value != null) ? value : 0
  }

  void accumulateTime () { // add Pomodoro credit against current node and the root node for today's attribute
    int elapseTime =  getElapsedTime()
    if (elapseTime > 0) {
      node['Pomodoro'] = getValue(node, 'Pomodoro') + elapseTime ;
      def rootNode = node.getMap().getRootNode()
      def today = new Date()
      def formattedDate = today.format('yyyy-MM-dd')
      rootNode[formattedDate] = getValue(rootNode, formattedDate) + elapseTime
    }
  } 

  public String secondToString(x) {
    int seconds = x % 60 ;
    int minutes =(int) (x / 60);
    return String.format("%02d:%02d", minutes, seconds)
  }

  public start() {
    // println "Start"
    remainingTime = countDownValue
    countDownTime = remainingTime
    running = true
    // no cancel, thus no restart
    // timer =  new Timer()
    // task = new TimerTaskCountDown(this)
    // timer.scheduleAtFixedRate(task, delay*1000, period*1000)
    setButtonName('Pause')
  }

  void end () {
    accumulateTime ()
    // it would be more saving of CPU, slightly, to cancel the timer, and tasks. 
    // But my experiment didn't work. It caused the Swing Widget disappear. I'm not sure why. 
    //task.cancel()
    //timer.cancel()
    setButtonName('Start');
    running = false
  }

  private static void playSound () {
    // the clip is a bit too long, annoying.
    // TODO: wish to find a way to set the current directory to the script directory, so that the script can be applicable without modification 
    System.setProperty("user.dir", "d:\\yushen\\scripts");
    java.io.File file = new java.io.File("APPLAUSE.wav");
    AudioClip sound = Applet.newAudioClip(file.toURL());
    sound.play();
    println "Played sound."
  }
  
  public void update() {// for timer task
    if (running) {
      if (remainingTime >= period) {
        remainingTime -= period
      } else { 
        end()
      }
      setTimeStr(secondToString(remainingTime))
      // println "remainingTime: $remainingTime and breakTime: $breakTime"
      if (remainingTime == breakTime) {// play sound to congratulate
        playSound ()
      }
    }
  }

  public void react () {
    if (running) {// pause
      end ();
    } else {// start
      start()}}
}

class TimerTaskCountDown extends TimerTask {
  CountDown model

  public TimerTaskCountDown (CountDown model) {
    // super() // not neccessary
    this.model = model
  }

  public void run() {
    model.update()
  }  
}  

CountDown model = new CountDown(node)

def s = new SwingBuilder()
// s.setVariable('myDialog-properties',[:]) // seems not neccessary
def dial = s.dialog(title:'Pomodoro', id:'pormodoro', modal:false,  defaultCloseOperation:JFrame.DISPOSE_ON_CLOSE, pack:true, show:true) {
  panel() {
    boxLayout(axis:BXL.Y_AXIS)
    panel(alignmentX:0f) {
      flowLayout(alignment:FL.LEFT)
      label text: node.text + ': '
      label text: bind {model.timeStr }
    }

    panel(alignmentX:0f) {
      flowLayout(alignment:FL.RIGHT)
      button (text: bind {model.buttonName}, actionPerformed: {model.react(); }) 
    }
  }
}

Author: yubrshen

Kill Empty Nodes

When pasting text from clipboard, Freeplane would split the content by newline, thus it may produce some empty node without text at all for those multiple newlines. This script removes all those empty nodes.

You can execute the script at an empty node, or at a node and recursively for its sub-nodes.

// Test the current node if it's empty, and it does not have any sub-nodes, 
// then delete it.
// The node is empty, if it has no non-blank text.

def killEmptyNode (aNode){
    nonEmpty = /\w+/
    nodeText = aNode.getPlainText()
    // println nodeText
    if (aNode.children & !(nodeText =~ nonEmpty)) {
        // println "Found an empty node!"
        aNode.delete()
    }
}

killEmptyNode(node)

Author: yubrshen

Create a Today GTD simple framework

Discussion here : The Freeplane Task Time Tracker

// @ExecutionModes({ON_SINGLE_NODE})
//ui.informationMessage(ui.frame, temp)

//import java.awt.Color;
import org.freeplane.plugin.script.proxy.Proxy.Node

// ========================= Config BEGIN   =========================
// create as child of selected node or child of root node ? "true" = selected node / "false" = root node
def fromSelectedNode = "false"
// Name of containing node
def newNodeName = "Agenda"
// Number of days to create
def daysToCreate = 1
// Maximum number of nodes to remain unfolded
def unfoldedNodes = 1
// choose your prefered date format : (ex : "yyyy-MM-dd hh:mm")
def dateFormat = "dd/MM/yy"
// define edge color 
def String edgeColor = "#006699"
// define edge width
def edgeWidth = 2
// assign edge color like parent node ?  "true" / "false" 
parentEdgeColor = "false"
// assign edge width like parent node ?  "true" / "false" 
parentEdgeWidth = "true"
// define recurrent items within each day
def daysCategories = ["Todo" , "Delegated To", "Phone Calls", "Appointments", "Meetings", "Events", "New Inbox"]
// ========================= Config END =========================

// color information : http://chir.ag/projects/name-that-color/#6183ED
// Colors codes used:
clr = [   "BahamaBlue":"#006699"
        , "WildSand":"#f5f5f5"
        , "Gray":"#999999"
        , "VerdunGreen":"#336600"
        , "Orange":"#ff9933"
		, "Black":"#000000"
		, "Yellow":"#ffff00"
		, "White":"#ffffff"
		, "Red":"#ff0000"		
        , "Pink":"#ff9999"]

// Functions
def void formatNode(Node node, String nodeTextColor, String nodeBgColor, nodeFontSize, String edgeColor, edgeWidth) {
    node.style.font.bold = 0
    node.style.setTextColorCode(nodeTextColor)
    node.style.setBackgroundColorCode(nodeBgColor)
    node.style.font.size = nodeFontSize
    node.style.edge.setColorCode(edgeColor)
    node.style.edge.setWidth(edgeWidth)
}

def today = new Date()
def f = new java.text.SimpleDateFormat(dateFormat)
todaySimple = f.format(today)

def nextday = today

if ( parentEdgeColor == "true")
	edgeColor = c.selected.style.edge.getColorCode()
	
if ( parentEdgeWidth == "true")
	edgeWidth = c.selected.style.edge.getWidth()

def newNode	
if ( fromSelectedNode == "true"){
	newNode = c.selected.createChild()
} else {
	newNode = node.mindMap.root.createChild()
}

newNode.text = newNodeName
//newNode.style.name = "Step"

formatNode(newNode, clr.White, clr.Red, 14, edgeColor , edgeWidth)

i = 0
while ( i++ < daysToCreate ) {
	def child = newNode.createChild()
	child.text = f.format(nextday)
	child.attributes = [
		"totalJournee" : ""]
	daysCategories.each() { 
		def cat = child.createChild()
		cat.text = it
	}

	if (i > unfoldedNodes)
		child.setFolded(true)
	nextday++
}
def todayCats
c.find{
    it.text == todaySimple
}.each {
	formatNode(it, clr.Black, clr.Yellow, 13, edgeColor , edgeWidth)
	c.select (it)
	it.setFolded(false)
	todayCats = it.getChildren()
}

todayCats.each{
	if (it.text == "Todo")
		it.text = "ToDoNow"
}

Author: Megatop

The Freeplane Task Time Tracker

This script opens a form with

discussion here : The Freeplane Task Time Tracker

condition: you have to run the CreateTodayGTD.groovy script first (see above)

// @ExecutionModes({ON_SINGLE_NODE})

import groovy.time.*
import java.util.Timer;
import javax.swing.BorderFactory
import java.awt.Color
import groovy.swing.SwingBuilder
import java.awt.FlowLayout as FL
import javax.swing.BoxLayout as BXL
import javax.swing.JFrame
import javax.swing.JScrollPane
import javax.swing.JTabbedPane
import javax.swing.JOptionPane
import java.awt.Font
import javax.swing.ImageIcon

def colorWhite = new Color(255, 255, 255) // white
def colorBlack = new Color(0, 0, 0) // black
def colorRed = new Color(255, 0, 0) // red
def colorBlue = new Color(225, 235, 254) // light blue
def colorYellow = new Color(240, 250, 208) // light yellow
def colorRose = new Color(245, 230, 229) // light rose
def colorGreen = new Color(206, 253, 218) // light green
def colorOrange = new Color(253, 233, 206) // light orange
def colorPurple = new Color(246, 192, 251) // light purple
def colorGray = new Color(255,255,255) // gray 

def tabCenter = 28

def f = new java.text.SimpleDateFormat( "dd/MM/yy HH:mm:ss" )
def fDay = new java.text.SimpleDateFormat( "dd/MM/yy" )
def fTime = new java.text.SimpleDateFormat( "HH:mm:ss" )
def fDuree = new java.text.SimpleDateFormat( "HH:mm" )
def fMoisAnnee = new java.text.SimpleDateFormat( "MMMM yyyy", new Locale('FR'))

dateJour = fDay.format(new Date())

c.find{ it.text == dateJour }.each { today = it}
today.setFolded(false)

todayChillen = today.getChildren()
todayChillen.find{it.text == "ToDoNow"}.each {
	ToDoNow = it
	c.select(it)
	it.setFolded(false)
	}

listeNextActions = ToDoNow.getChildren()

listeNextActions.each {	

	it['debut'] = ""
	it['arret'] = ""
	it['fin'] =  ""
	it['total'] = ""
	it['totalJour'] = ""
	
}

def totalJournee = today['totalJournee']
def tempsTotalJournee = elapsedToMillis(totalJournee)

c.find{ it.text == "ToDos"}.each{inbox = it}

def elapsedTime(diff, precision, format){

	def time
	
	long secondInMillis = 1000;
	long minuteInMillis = secondInMillis * 60;
	long hourInMillis = minuteInMillis * 60;
	long dayInMillis = hourInMillis * 24;
	long yearInMillis = dayInMillis * 365;

	long elapsedYears = diff / yearInMillis;
	diff = diff % yearInMillis;
	long elapsedDays = diff / dayInMillis;
	diff = diff % dayInMillis;
	long elapsedHours = diff / hourInMillis;
	diff = diff % hourInMillis;
	long elapsedMinutes = diff / minuteInMillis;
	diff = diff % minuteInMillis;
	long elapsedSeconds = diff / secondInMillis;
	diff = diff % secondInMillis;
	
	elapsedSecondsString = String.format("%02d", elapsedSeconds)
	elapsedMinutesString = String.format("%02d", elapsedMinutes)
	elapsedHoursString = String.format("%02d", elapsedHours)
	
	if (precision == "sec" && format == "long")
		time = elapsedHoursString + " heures, " + elapsedMinutesString + " minutes, " + elapsedSecondsString +  " secondes"
	if (precision == "sec" && format == "court")
		time = elapsedHoursString + " h " + elapsedMinutesString + " m " + elapsedSecondsString +  " s"
		
	if (precision== "min" && format == "long")
		time = elapsedHours + " heures, " + elapsedMinutes + " minutes" 
	if (precision== "min" && format == "court")
		time = elapsedHours + " h " + elapsedMinutes + " m" 		

	if (precision== "pomodoro" && format == "court")
		time = elapsedMinutesString + " m " + elapsedSecondsString +  " s"
	return time
}
def elapsedToMillis(elapsed){

	def elapsedInMillis 
	if (elapsed == ""){
		elapsedInMillis = 0
	}else{
		def elapsedHours = Integer.parseInt(elapsed[0..1])
		def elapsedMinutes = Integer.parseInt(elapsed[5..6])
		def elapsedSeconds = Integer.parseInt(elapsed[10..11])
		elapsedInMillis = (elapsedSeconds * 1000) + (elapsedMinutes * 60 * 1000) + (elapsedHours * 60 * 60 * 1000)
	}
	return elapsedInMillis
}

Font font = new Font("Serif", Font.BOLD, 13) 
Font pom = new Font("Serif", Font.BOLD, 28) 

def s = new SwingBuilder() 
s.setVariable('myDialog-properties', [:]) 
def vars = s.variables 
def dial = s.dialog(title: 'Freeplane Task Time Tracker', id: 'myDialog', size: [930, 542], locationRelativeTo: ui.frame, owner: ui.frame,			
					defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE, visible:true, show: true ) {

	tabbedPane(id: 'tabs',  opaque : false, tabLayoutPolicy:JTabbedPane.SCROLL_TAB_LAYOUT) {
		tabs.setFont(font) 
		
		def actionsTabName = "Actions : " + listeNextActions.size().toString()
		panel(name:  actionsTabName.center(tabCenter) , background: colorWhite, foreground: colorBlue) {							  
			boxLayout(axis: BXL.Y_AXIS) 

			def totalTachesVal = "Total : " + listeNextActions.size().toString() + " actions"
			
			def totalJour
			def total

			def initNextActionID 
			def initPanelID		
			
			def lastAction = "Stop"

			j = -1
			while ( j++ < listeNextActions.size() -1 ) {
				initNextActionID = listeNextActions[j].getId()
				initPanelID = "panel$initNextActionID"

				c.find{
					it.getId() == initNextActionID
				}.each {
					totalJour = elapsedToMillis(it['totalJour'])						
					tempsTotalJournee += totalJour
				}
			}

			tempsTotalJourneeVal = (elapsedTime(tempsTotalJournee, "sec", "long")).toString()
				
			panel(id : 'summary', alignmentX: 0f, preferredSize: [900, 40]){
			boxLayout(axis: BXL.X_AXIS)
				panel(alignmentX: 0f,  background: colorWhite) {
					flowLayout(alignment: FL.LEFT) 
					label ( dateJour, preferredSize: [104, 24]).setFont(font) 
					totalTaches = label (totalTachesVal, preferredSize: [150, 24]).setFont(font) 
				}
				
				panel(alignmentX: 0f, background: colorWhite) {
					flowLayout(alignment: FL.RIGHT) 
					label (id :'totalTemps',text: "Temps total : $tempsTotalJourneeVal", preferredSize: [270, 24]).setFont(font) 
				}
			}		
			scrollPane( verticalScrollBarPolicy:JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED ,background: colorWhite) {
				vbox {		
					i = -1
					while ( i++ < listeNextActions.size() -1 ) {
						
						def nextAction = listeNextActions[i].text
						def nextActionID = listeNextActions[i].getId()
						def thisNode = listeNextActions[i]
						def panelID = "panel$nextActionID"
						def doneID = "donedone$nextActionID"
						
						def debutID 
						def finID	 
						def diffID	 

						c.find{
							it.getId() == nextActionID
						}.each {
							if( it['totalJour'] != "")
								diffID = it['totalJour'].toString()

							if( it['fin'] != "" ){						
								s."$doneID"  = "checked"
							}else{
								s."$doneID" = "unchecked" 
							}
						}

						thisActionOriginId = thisNode['ID']
						c.find{
							it.getId() == thisActionOriginId.toString()
						}.each {						
							def note = it.note
							def details = it.details.getPlain()
						}						

						def debutID_Val = "debut" + "$i" + "Val"
						def debutID_ValTime = "debut" + "$i" + "Time"

						def finID_Val = "fin" + "$i" + "Val"
						def finID_ValTime = "fin" + "$i" + "Time"
									
						panel( id: '$panelID' , alignmentX: 0f ) {
							boxLayout(axis: BXL.X_AXIS)

							def pane = panel(id: panelID , alignmentX: 0f , preferredSize: [100, 35], background: colorBlue , border: BorderFactory.createMatteBorder(0, 0, 1, 0, colorGray)) {
								flowLayout(alignment: FL.LEFT) 
								checkBox(id:'check$i', preferredSize: [20, 24], opaque: false, selected: (s."$doneID"  == "checked" ? true : false), actionPerformed: {
									
									c.find{
										it.getId() == nextActionID
									}.each {
										c.select(it)
										if (it['fin'] == ""){
											s."$doneID" = "checked"
											it['fin'] = it['arret']	
											s."$panelID".background = colorGreen
											}else{	
											it['fin'] = ""
											s."$doneID"  = "unchecked"
											s."$panelID".background = colorBlue
										}
									}
								})
								if (s."$doneID"  == "checked"){
									s."$panelID".background = colorGreen
								}else{
									s."$panelID".background = colorBlue
								}
								label(id :'todo$i', text: nextAction, preferredSize: [530, 24])
								button( id:'startButton$i', text:'Start', preferredSize: [60, 24], actionPerformed: {
									
									if (lastAction == "Stop" && s."$doneID"  == "unchecked"){
										
										lastAction = "Start"
										activeID = nextActionID
										
										s."$panelID".background = colorYellow

										debutID_Val = new Date()
										debutID.text =  fTime.format(debutID_Val)
										debutID_ValTime = debutID_Val.getTime()
										c.find{
											it.getId() == nextActionID
											
											
										}.each {
										c.select(it)
											if( it['debut'] == "")
												it['debut'] = f.format(debutID_Val)												
											finID.text = ""	
										}
									}
								})
								
								button( id:'stopButton$i', text:'Stop', visible: true,  preferredSize: [60, 24], actionPerformed: {
									
									if (lastAction == "Start" && activeID == nextActionID && s."$doneID"  == "unchecked"){

										lastAction = "Stop"
										currentActionID = nextActionID
										j = -1
										while ( j++ < listeNextActions.size() -1 ) {
											initNextActionID = listeNextActions[j].getId()
											initPanelID = "panel$initNextActionID"
											if (s."$doneID"  == "checked"){
												s."$panelID".background = colorGreen
											}else{
												s."$panelID".background = colorBlue
											}										
										}
										s."$panelID".background = colorRose
										
										finID_Val = new Date()
										finID.text =  fTime.format(finID_Val)
										finID_ValTime = finID_Val.getTime()	

										c.find{
											it.getId() == nextActionID
										}.each {
											c.select(it)
											difference = finID_ValTime - debutID_ValTime				
											it['arret'] = f.format(finID_Val)
											
											totalJour = elapsedToMillis(it['totalJour'])
											totalJour += difference
											it['totalJour'] = (elapsedTime(totalJour, "sec", "court")).toString()
											
											diffID.text = elapsedTime(totalJour, "sec", "court")

											total = elapsedToMillis(it['total'])
											total += difference										
											it['total'] = (elapsedTime(total, "sec", "court")).toString()
											
											tempsTotalJournee += difference						
											tempsTotalJourneeVal = (elapsedTime(tempsTotalJournee, "sec", "long")).toString()
											totalTemps.text = "Temps total : $tempsTotalJourneeVal"
										}
									}
								})

								debutID = label(debutID , preferredSize: [50, 24])
								finID = label(finID , preferredSize: [50, 24])
								diffID = label(diffID , preferredSize: [70, 24])
							}
						}
					}
				}
			}
		}
		panel(name: 'Delegated To'.center(tabCenter)) {
			borderLayout()
			splitPane() {
				panel(constraints: 'left') {
					label(text: 'Left')
				}
				panel(constraints: 'right') {
					label(text: 'Right')
				}
			}
		}		
		panel(name: 'Phone Calls'.center(tabCenter)) {
			textField(text: 'Some text', columns: 15)
			scrollPane() {
				textArea(text: 'Some text', columns: 15, rows: 4)
			}
		}
		panel(name: 'Appointments'.center(tabCenter)) {
			borderLayout()
			splitPane() {
				panel(constraints: 'left') {
					label(text: 'Left')
				}
				panel(constraints: 'right') {
					label(text: 'Right')
				}
			}
		}
		panel(name: 'Meetings'.center(tabCenter)) {
			borderLayout()
			splitPane() {
				panel(constraints: 'left') {
					label(text: 'Left')
				}
				panel(constraints: 'right') {
					label(text: 'Right')
				}
			}
		}
		panel(name: 'Events'.center(tabCenter)) {
			borderLayout()
			splitPane() {
				panel(constraints: 'left') {
					label(text: 'Left')
				}
				panel(constraints: 'right') {
					label(text: 'Right')
				}
			}
		}

		panel(name: 'Inbox'.center(tabCenter)) {
			boxLayout(axis: BXL.Y_AXIS) 
			panel( ){
				label('new entry').setFont(font) 
				button('ajout TodoNow', actionPerformed:{
					// deactivated
					})
				input = textField(columns:87,
					background: colorYellow,
					actionPerformed: { 
						output.text +=  input.text + "\n"
						input.text =""
					})
				}
			panel(alignmentY: 0f,){							
				scrollPane(verticalScrollBarPolicy:JScrollPane.VERTICAL_SCROLLBAR_ALWAYS) {
					output = textArea(id="liste", text: '', columns: 110, rows: 18)
				}
			}
		}	
	}
	def togglePomPanel
	def task 
	
	boxLayout(axis: BXL.Y_AXIS)		
	panel(id:'Pomodoro', background: colorWhite){                       

		togglePomPanel = "OFF"
		//button('Pomodoro',icon:new ImageIcon("pomodoro30x30-tr.png"),  actionPerformed:{
		
		button('Pomodoro', actionPerformed:{
			if (togglePomPanel == "OFF"){
				Pomodoro.background = colorRed
				pomodoroLabel.setForeground(colorWhite)
				togglePomPanel = "ON"
			
			
			def pomodoroVal = pomodor.selectedItem
			def pomodoro = pomodoroVal*60000

			use (TimerMethods) {
				def timer = new Timer()
				def fPomo = new java.text.SimpleDateFormat( "mm:ss" )

				pomodoroLabel.text = '   ' +(elapsedTime(pomodoro, "pomodoro", "court")).toString()
				pomodoro -= 1000

				task = timer.runEvery(1000, 1000) {

					while ( pomodoro > -1000 ){
						pomodoroLabel.text = '   ' + (elapsedTime(pomodoro, "pomodoro", "court")).toString()
						break							
					}
					pomodoro -= 1000

					if (pomodoro < 0 && togglePomPanel == "ON"){
							Pomodoro.background = colorWhite
							togglePomPanel = "OFF"
							pomodoroLabel.setForeground(colorBlack)
							task.cancel()
					}
				}
			}
			}
		})
		comboBox(
			id: 'pomodor', 
			items: [60,45,25,15,10,5,2,1], 
			selectedIndex: 2, 
			preferredSize: [50, 24]
		) 		
		label(id : 'pomodoroLabel' , '   00 m 00 s').setFont(pom)
		label(icon:new ImageIcon("Progress_quarter_03.svg"))	
	}
	
	panel(id:'secondPanel', background: colorWhite){                       
		button('End of session : update and quit', actionPerformed:{
			ui.informationMessage(ui.frame, "this should update each tasks duration attributes and manage archiving of past tasks"  )
			// dispose()
		})            	
	}			
}

// Mr Haki File: newtimer.groovy
// http://mrhaki.blogspot.com/2009/11/groovy-goodness-run-code-at-specified.html

class GroovyTimerTask extends TimerTask {
    Closure closure
    void run() {
        closure()
    }
}

class TimerMethods {
    static TimerTask runEvery(Timer timer, long delay, long period, Closure codeToRun) {
        TimerTask task = new GroovyTimerTask(closure: codeToRun)
        timer.schedule task, delay, period
        task
    }
}

Author: Megatop

Using map specific storage

This script shows how to use map specific storage, that is a key/value map attached to a Freeplane mindmap. The values are String based but the API gives you Convertibles to work with instead for easier conversion to other types like dates and numbers.

The script requires at least 1.3.6

def m = node.mindMap

// the basic storage is string valued but here a Convertible is returned (like for node.to)
def nodeIdAsConvertible = m.storage['last_visited_node_id']
if (nodeIdAsConvertible != null) {
    def lastVisitedNode = m.node(nodeIdAsConvertible.string)
    // select() does nothing if the node does not exist anymore
    c.select(lastVisitedNode)
}

// store the last location
m.storage['last_visited_node_id'] = node.id

// to remove key and value from map specific storage, uncomment the following line
// m.storage['last_visited_node_id'] = null

// toggle show_icon_for_attributes. The show_icon_for_attributes is one
// of the few map specific variables that Freeplane itself uses
// The "bool" conversion is the new explicit conversion to boolean
m.storage['show_icon_for_attributes'] = !m.storage['show_icon_for_attributes'].bool

Author: Boercher

Resize all external images

This script resizes all "external images" to their node's maximum width as requested in the forum.

This script may require 1.3

// @ExecutionModes({ON_SINGLE_NODE})
import java.awt.Dimension
import javax.swing.JComponent
import org.freeplane.view.swing.features.filepreview.IViewerFactory
import org.freeplane.view.swing.features.filepreview.ViewerController
import org.freeplane.view.swing.map.NodeView

def preferredWidth(NodeView nodeView) {
    JComponent content = nodeView.getContent(ViewerController.VIEWER_POSITION)
    IViewerFactory factory = content.getClientProperty(IViewerFactory.class)
    Dimension preferredSize = factory.getOriginalSize(content)
    return preferredSize.width
}

c.statusInfo = "setting image widths to maximumNodeWidth"
int sucesses = 0
int failures = 0
c.find { it.externalObject.asBoolean() }.each {
    try {
        it.delegate.viewers.each { v ->
            def width = preferredWidth(v)
            def newZoom = it.style.maxNodeWidth / width
            println "node $it.text, maxwidth: ${it.style.maxNodeWidth}, imagewidth: $width, current zoom: ${it.externalObject.zoom}, new zoom: ${newZoom}"
            if (newZoom > 0)
                it.externalObject.zoom = newZoom
            ++sucesses
        }
    } catch (Exception e) {
        logger.warn("can't resize $it.plainText", e)
        ++failures
    }
}
c.statusInfo = "set image widths to maximumNodeWidth: ${sucesses} success(es), ${failures} failure(s)"

Register a Markdown IContentTransformer

IContentTransformers are used for several tasks in Freeplane, e. g. for

Here we use a content transformer to render Markdown formatted links as HTML inline links like in this text: see the Scripts collection in the Freeplane wiki! to be rendered as see the [http://www.freeplane.org/wiki/index.php?title=Scripts_collection Scripts collection] in the [http://www.freeplane.org/wiki/index.php/Main_Page Freeplane wiki]!

This renderer implements full Markdown syntax. This script has to be executed once on startup so it's best to install it as a init script.

import org.freeplane.features.map.NodeModel
import org.freeplane.features.text.AbstractContentTransformer
import org.freeplane.features.text.TextController
import org.freeplane.features.text.TransformationException

import org.apache.commons.lang.StringUtils

@Grab(group='com.github.rjeschke', module='txtmark', version='0.13')
import com.github.rjeschke.txtmark.Processor

class MarkdownTransformer extends AbstractContentTransformer {
    MarkdownTransformer() {
        super(10)
    }

    @Override
    public Object transformContent(TextController textController, Object obj, NodeModel node, Object transformedExtension) {
        if (obj instanceof String) {
            String nodeText = (String) obj;
            while (nodeText.indexOf("<markdown>") >= 0) {
                String text = StringUtils.substringBetween(nodeText, "<markdown>", "</markdown>");
                text = Processor.process(text)
                nodeText = StringUtils.substringBefore(nodeText, "<markdown>") + "<html><body>" + text + "</html></body>" + StringUtils.substringAfter(nodeText, "</markdown>")
            }
            return nodeText;
        }
        return obj;
    }
}

// for development purposes: remove older instances of MarkdownTransformer first
TextController.controller.textTransformers
    .findAll{ it.getClass().simpleName.equals("MarkdownTransformer") }
    .each { TextController.controller.removeTextTransformer(it) }
// register our MarkdownTransformer
TextController.controller.addTextTransformer(new MarkdownTransformer()) 

How to use script? In node content write " here is markdown markup" and next your markdown markup.

Author: Bvfalcon

Base64-encoded image

With this script nodes can contains tag (Base64-encoded bynary image data).

Script's file base64image.groovy must be moved into folder init script.

Content of base64image.groovy:

import org.freeplane.features.map.NodeModel
import org.freeplane.features.text.AbstractContentTransformer
import org.freeplane.features.text.TextController
import org.freeplane.features.text.TransformationException
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;

import org.apache.commons.lang.StringUtils;

@Grab(group='commons-codec', module='commons-codec', version='1.8')
import org.apache.commons.codec.binary.Base64;

class Base64ImageTransformer extends AbstractContentTransformer {
    Base64ImageTransformer() {
        super(10)
    }

    @Override
    public Icon getIcon(TextController textController, Object nodeText, NodeModel node, Object transformedExtension) {
        if (nodeText.indexOf("<img") >= 0 && nodeText.indexOf("src=\"data:") >= 0) {
	        String base64String = StringUtils.substringBetween(nodeText, "base64,", "\"");
	        byte[] imageByte = Base64.decodeBase64(base64String);
	        ByteArrayInputStream inputStream = new ByteArrayInputStream(imageByte);
	        BufferedImage bufImage = ImageIO.read(inputStream);
	        ImageIcon icon = new ImageIcon(bufImage);
	        return icon;
        }
        return null;
    }

    public Object transformContent(TextController textController, Object content, NodeModel node, Object transformedExtension) {
        return content;
    }
}

// for development purposes: remove older instances of Base64ImageTransformer first
TextController.controller.textTransformers
    .findAll{ it.getClass().simpleName.equals("Base64ImageTransformer") }
    .each { TextController.controller.removeTextTransformer(it) }
// register our Base64ImageTransformer
TextController.controller.addTextTransformer(new Base64ImageTransformer())

Author: Bvfalcon

This script that checks that every link and every external image exists. All nodes with a broken link are linked to a newly created root child node named "broken".

Notes:

  • Links in attributes are not checked
  • Inline Hyperlinks in HTML core, details and notes are not checked
// @ExecutionModes({ON_SINGLE_NODE})
import org.freeplane.core.resources.ResourceController
import org.freeplane.features.mode.Controller
import org.freeplane.features.url.UrlManager
import org.freeplane.plugin.script.ScriptingPermissions
import org.freeplane.plugin.script.proxy.Proxy

private URL getAbsoluteUrl(uri) {
    UrlManager urlManager = Controller.currentModeController.getExtension(UrlManager.class)
    return urlManager.getAbsoluteUrl(node.mindMap.delegate, uri)
}

private boolean checkUri(uri) {
    try {
        def url = getAbsoluteUrl(uri instanceof URI ? uri : new URI(uri))
        println "checking ${uri}..."
        if (url.getProtocol() == 'https') {
            println "will not check ${uri}"
        } else {
            def urlConnection = url.openConnection()
            urlConnection.connect()
        }
        return true
    } catch (Exception e) {
        e.printStackTrace();
        println "broken link: ${uri}: ${e.message}"
        return false
    }
}

private boolean isExternalLink(Proxy.Link link) {
    link.uri != null && !link.toString().startsWith('#')
}

private void addBrokenLink(LinkedHashMap<Proxy.Node, List<URI>> brokenLinkMap, Proxy.Node node, URI uri) {
    def list = brokenLinkMap.get(node)
    if (list == null) {
        list = new ArrayList()
        brokenLinkMap.put(node, list)
    }
    list.add(uri)
}

def scriptingPermissions = new ScriptingPermissions(ResourceController.resourceController.properties)
if (!scriptingPermissions.get(scriptingPermissions.RESOURCES_EXECUTE_SCRIPTS_WITHOUT_READ_RESTRICTION)
    || !scriptingPermissions.get(scriptingPermissions.RESOURCES_EXECUTE_SCRIPTS_WITHOUT_NETWORK_RESTRICTION)) {
    throw new RuntimeException("this scripts needs file read and network access permissions")
}

def broken = new LinkedHashMap<Proxy.Node, List<URI>>()
def countGood = 0
c.find{ isExternalLink(it.link) || it.externalObject.uri != null }.each {
    if (isExternalLink(it.link) && !checkUri(it.link.uri))
        addBrokenLink(broken, it, it.link.uri)
    else if (it.externalObject.uri != null && !checkUri(it.externalObject.uri))
        addBrokenLink(broken, it, new URI(it.externalObject.uri))
    else
        ++countGood
}
if (broken) {
    def brokenLinksNode = node.mindMap.root.createChild("broken links")
    broken.each { n, uris ->
        def child = brokenLinksNode.createChild(n.text)
        child.link.node = n
        uris.each {
            def linkNode = child.createChild(it)
            linkNode.link.text = it
        }
    }
}
c.statusInfo = "found ${broken.size()} broken links and $countGood good links"

Author: seb4stien and boercher

Monitor Clipboard

This script monitors the clipboard for changes adds the copied text as a child of the current node. This can be useful for creating nodes for a mindmap while reading a main document

Notes:

  • The script runs in a endless loop (which effectively locks the freeplane interface). As there appears no 'break' or 'esc' key combo, the script expects a blank space copied to the clipboard to terminate running, after which everything returns to normal.
  • Possible extensions include inserting copied images to nodes. Recognising URIs and generating links. Watching for the window which has focus and automatically creating a reference/link to the original source document based on this.
//Script for freeplane to monitor the clipboard and create a new node containing text when it changes
// This script will loop endlessly until a single space (" ") is copied, at which point it will terminate
// David Mckenzie 2/2/14

import java.awt.Toolkit
import java.awt.datatransfer.Clipboard
import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection

// define static functions to get and set clipboard text
static void setClipboardContents(final String contents){    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(contents), null)    }
static String getClipboardContents(){    return Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null).getTransferData(DataFlavor.stringFlavor)    }

// @ExecutionModes({ON_SELECTED_NODE})
curNode = node
curClip = getClipboardContents()
oldClip = curClip
while (!curClip.equals(" ")) {                              // endless loop terminated if *only* a space is copied
    if (!(curClip.equals(oldClip))) {                       // check for change in the clipboard
        chldNode = node.createChild()                       // create new child
        chldNode.text = curClip                             // set the node text to the clipboard text
        Toolkit.getDefaultToolkit().beep()                  //beep when completed
        oldClip = curClip                                   // get text from the clipboard
    }
    Thread.sleep(1000)
    curClip = getClipboardContents()
}

Author: dgm5555

Copying files to sync directory

This script can be used to sync PDFs from Docear to a directory, e.g. on an e-book reader. It assumes that the literature that still has to be read is contained below the "Incoming" node, ordered by relevancy, and that the PDF nodes are moved somewhere else on the mind map after reading. On the e-book reader there has to be a directory dedicated only (!) to Docear syncing. When executed, that script ensures that the directory on the e-book reader contains exactly the first 10 PDFs from the "Incoming" node by copying new ones and deleting old ones. The source and target directories are currently hardcoded into the script and have to be adjusted before use. After being installed into Docear, the script can be started from the context menu of the root or "Incoming" node.


// @ExecutionModes({ON_SINGLE_NODE})
import org.freeplane.plugin.script.proxy.*
import javax.swing.*
import java.nio.file.*

def sourceDir = "C:\\Users\\mywindowsusername\\Documents\\literature\\repository"
def targetDir = "E:\\docearSync"

def incomingNode = null;
if (node.getDisplayedText().equals("Incoming")) {
    incomingNode = node;
} else {
    for (Proxy.NodeRO cur in node.children) {
        if (cur.displayedText.equals("Incoming")) {
	        incomingNode = cur;
		    break;
	    }
    }
}

if (incomingNode == null) {
    JOptionPane.showMessageDialog(null, "Incoming node not found!")
    return;
}

List<String> wantedNames = new ArrayList<>()
for (Proxy.NodeRO fileNode in incomingNode.children) {
    wantedNames.add(fileNode.displayedText)
	if (wantedNames.size() >= 10) {
	    break;
	}
}

File[] existingFiles = new File(targetDir).listFiles()
if (existingFiles == null) {
    JOptionPane.showMessageDialog(null, "Target dir does not exist: " + targetDir)
    return;
}

List<String> existingNames = existingFiles.collect({it.getName()})

List<String> toCopy = new ArrayList<>(wantedNames);
toCopy.removeAll(existingNames)

List<String> toDelete = new ArrayList<>(existingNames)
toDelete.removeAll(wantedNames)

for (String s in toCopy) {
    Files.copy(Paths.get(sourceDir, s), Paths.get(targetDir, s))
}

for (String s in toDelete) {
    Files.delete(Paths.get(targetDir, s))
}

JOptionPane.showMessageDialog(null,"Added " + toCopy.inject('', {s,f -> s.isEmpty() ? f : s + ',\n  ' + f}) + "\n\nDeleted " + toDelete.inject('', {s,f -> s.isEmpty() ? f : s + ',\n  ' + f}))

Author: Tobias Baum

Save Nodes of Style X to Text Files

This is a Groovy script that, when executed, saves particular nodes as text files. Only nodes with particular Styles (i.e. Student-Boy OR Student-Girl) are saved. They are saved in the form of Node Text = Name of .TXT file (rather, the first 30 characters of the node’s text). The body of the text file = the Notes of the node. The script checks the parent of the node, and puts the text file in the corresponding subfolder. The path C:\Users\<Your_Name>\CaseNotes\Complete is shown and corresponds to this http://i.imgur.com/BdgM3vQ.png screenshot, but please substitute your own file path. Please note that this is a one-way “archive,” not a “sync.”

def basedir
c.findAll().each {
 if (it.hasStyle('Student-Boy') | it.hasStyle('Student-Girl')) {
		if (it.parent!=null&&it.parent.text.contains('cBIP')) {  
			 basedir  = "C:\\Users\\<your_name>\\CaseNotes\\BIP" 
		}
		else if (it.parent!=null&&it.parent.text.contains('cComplete')) {  
			 basedir  = "C:\\Users\\<your_name>\\CaseNotes\\Complete" 
		}
		else if (it.parent!=null&&it.parent.text.contains('cEvaluations')) {  
			 basedir  = "C:\\Users\\<your_name>\\CaseNotes\\Evaluations" 
		}
		else if (it.parent!=null&&it.parent.text.contains('cMisc')) {  
			 basedir  = "C:\\Users\\<your_name>\\CaseNotes\\Misc" 
		}
		else if (it.parent!=null&&it.parent.text.contains('cReferrals')) {  
			 basedir  = "C:\\Users\\<your_name>\\CaseNotes\\Referrals" 
		}
		else if (it.parent!=null&&it.parent.text.contains('cTransfers')) {  
			 basedir  = "C:\\Users\\<your_name>\\CaseNotes\\Transfers" 
		}
		else if (it.parent!=null&&it.parent.text.contains('cUpcomming')) {  
			 basedir  = "C:\\Users\\<your_name>\\CaseNotes\\Upcomming" 
		}
		else {
			 basedir  = ""
		}
 def title = it.plainText
      def note = it.note
      if (note) {
		  def filename = title.substring(0, Math.min(30, title.length())) + '.txt'
          def file = new File (basedir, filename)
          file.text = note.plain
      } 
    } 
}

Idea: kunkel321, Most of the actual code: boercher. Also significant help from: jokro.

Remove Node and Log its Text in Parent Note

Version 1. This is a Groovy script that, when executed, removes the selected node and places its node text at the end of the parent node's note field, in the form of "On:

def beginHtml = '<html><body>\n'
def endHtml = '\n</body></html>'
if (!node.isRoot()) {
    def parent = node.parent
    def oldNote = parent.noteText ? parent.noteText.replaceFirst('(?s)</body>.*', '') : beginHtml
    // print oldNote
    parent.noteText = oldNote + '<p>Logged: ' + node.plainText + '<br>On: ' + format(new Date()) + '</p>' + endHtml
    node.delete()
}

Version 2. This script builds on the above one, but rather than logging the node text to the immediate parent, it "looks" back up the branch of ancestors for a node that has a style of either "Student-Boy" or "Student-Girl" and logs the text in that node's notes. It also has a pop-up message, if no such ancestor is found.

def beginHtml = '<html><body>\n'
def endHtml = '\n</body></html>'
def projectNode = node.pathToRoot.reverse().drop(1).find{ it.hasStyle('Student-Boy') || it.hasStyle('Student-Girl') }
if (!projectNode) {
	ui.errorMessage("No 'Student-Boy' or 'Student-Girl' ancestor node found.")
	}
else {
    def oldNote = projectNode.noteText ? projectNode.noteText.replaceFirst('(?s)</body>.*', '') : beginHtml
    projectNode.noteText = oldNote + '<p>On: ' + format(new Date()) + '<br>Logged: ' + node.plainText + '</p>' + endHtml
    node.delete()
    }

Idea: kunkel321, Actual code: boercher. See also related forum thread.

Set the color for all children

This is an example of iteration over child nodes.

node.children.each{ it.style.nodeTextColor = java.awt.Color.BLUE }
// @ExecutionModes({ON_SELECTED_NODE, ON_SELECTED_NODE_RECURSIVELY})

This script allows to create a link to a node in another map. Follow this procedure to insert a link:

  1. Open the target map and select the target node
  2. Execute this script (by default Tools -> Scripts -> Insert Link To Node In Other Map -> ...on one selected node. In the status line copied link will be printed
  3. Return to the node that should get the link (link source)
  4. Execute this script again. A dialog will appear asking if you want to insert the link - answer with Yes

This functionality was suggested by various people, most recently by Andrés and Paul in this discussion.

// @ExecutionModes({ON_SINGLE_NODE})
import java.awt.Toolkit
import java.awt.datatransfer.Clipboard
import java.awt.datatransfer.DataFlavor
import java.awt.datatransfer.StringSelection
import java.awt.datatransfer.Transferable

import javax.swing.JOptionPane

import org.freeplane.core.resources.ResourceController
import org.freeplane.features.link.LinkController

URI getNodeUriFromClipboardIfAvailable() {
    Transferable selection = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(this)
    if (selection == null || ! selection.isDataFlavorSupported(DataFlavor.stringFlavor))
        return null
    String selectionAsString = selection.getTransferData(DataFlavor.stringFlavor)
    try {
        def uri = new URI(selectionAsString)
        // only URIs with something after the '#' are proper links to nodes
        return uri.fragment && uri.path ? uri : null
    }
    catch (Exception e) {
        return null
    }
}

void copyLink() {
    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard()
    File file = node.mindMap.file
    if (file == null) {
        JOptionPane.showMessageDialog(ui.frame,
            'The map must be saved to be usable as a link target', "Freeplane", JOptionPane.WARNING_MESSAGE);
        return
    }
    URI mapUri = node.mindMap.file.absoluteFile.toURI();
    clipboard.setContents(new StringSelection('' + mapUri + '#' + node.id), null)
    c.statusInfo = 'copied link'
}

URI uri = getNodeUriFromClipboardIfAvailable()
if (uri != null && ! uri.path.contains(node.mindMap.name)) {
    def title = 'Insert link to node in other map?'
    def result = ui.showConfirmDialog(c.selected?.delegate, title, title, JOptionPane.YES_NO_CANCEL_OPTION)
    if (result == JOptionPane.YES_OPTION) {
        boolean useRelativeUri = ResourceController.getResourceController().getProperty("links").equals("relative");
        if (useRelativeUri && node.mindMap.file == null) {
            JOptionPane.showMessageDialog(ui.frame,
                'The map must be saved to be usable as a link source', "Freeplane", JOptionPane.WARNING_MESSAGE);
        }
        if (useRelativeUri)
            uri = new URI('' + LinkController.toRelativeURI(node.mindMap.file, new File(uri.path), LinkController.LINK_RELATIVE_TO_MINDMAP) + '#' + uri.fragment)
        node.link.text = uri
        c.statusInfo = 'link inserted'
    }
    else if (result == JOptionPane.NO_OPTION) {
        copyLink()
    }
}
else {
    copyLink()
}

Author: boercher

Inline linked maps into one single map

This script replaces recursively all nodes with links to a map file (link text ending on '.mm') with the content of the respective map. Check logfile for files that could not be found/inlined. Thanks to Dennis for asking for this feature.

Requires Freeplane after 1.2.8_02. With two minor adjustments also usable with older 1.2 versions (see script text).

// @ExecutionModes({ON_SINGLE_NODE})
def thisMap = node.mindMap
def newMap = cloneMap(thisMap.root)
inlineIncludes(newMap.root)

def cloneMap(rootNode) {
    def newMap = c.newMap()
    copyProperties(newMap.root, rootNode)
    rootNode.children.each{ newMap.root.appendBranch(it) }
    inlineIncludes(newMap.root)
    return newMap
}

// copies some of the various properties a node has from source to dest
def copyProperties(dest, source) {
    dest.text = source.text
    // only after 1.2.8_02
    dest.attributes = source.attributes.map
    dest.link.text = source.link.text
    if (source.note != null)
        dest.note = source.note
    dest.details = source.detailsText
}

// inserts linked maps into the node containing the link
def inlineIncludes(rootNode) {
    rootNode.find{ it.link.text && it.link.text.endsWith(".mm") }.each { include ->
        def url = getURL(include)
        if (url) {
            def childMap = c.newMap(url)
            copyProperties(include, childMap.root)
            include.link.text = null
            childMap.root.children.each{ child ->
                include.appendBranch(child)
            }
            // leads to an -ignorable- error upto 1.2.8_02
            childMap.close(true, false)
        }
    }
}

// handles relative paths and more
def getURL(node) {
    try {
        def uri = node.link.uri
        if (uri.scheme == null || uri.scheme == 'file') {
            def file = new File(uri.path)
            if (!file.isAbsolute())
                file = new File(node.mindMap.file.parent, uri.toString())
            if (!file.exists()) {
                logger.warn("invalid link " + file + " - cannot inline")
                return null
            }
            return file.toURL()
        }
        else {
            return uri.toURL()
        }
    } catch (Exception e) {
        logger.warn("invalid link " + node.link.text + " - cannot inline", e)
        return null
    }
}

Author: boercher

Play sound

It is possible to add a script to a reminder. The following script can be used to sound an audio alarm. In this way, if your mind map is open but covered by other windows,you can still know that a reminder is asking your attention.

Without audio dialog

This script plays sound "mySound.wav" which resides in subdirectory "scripts" of the Freeplane user directory. The script illustrates

  1. how to get the path to the user directory;
  2. how to concatenate this path with additional subdirectory "scrpts" and file "mySound.wav" to a full pathName;
  3. how to play a sound without showing an additional dialog for pausing and replay;

// Play sound mySound.wav which resides in subdirectory
// "scripts" of the Freeplane user directory
// IMPORTANT Tools > Preferences > Plugins "Permit to execute other applications" must be checked.
import java.applet.Applet;
import java.applet.AudioClip;
def fName ="mySound.wav";
def userDir=c.getUserDirectory();
// If Windows and user = "Beheerder", userDir == C:\Users\Beheerder\AppData\Roaming\Freeplane\1.2.x
pathName= "$userDir\\scripts\\$fName ";
// pathName == C:\Users\Beheerder\AppData\Roaming\Freeplane\1.2.x\scripts\mySound.wav
File file = new File(pathName);
AudioClip sound = Applet.newAudioClip(file.toURL());
sound.play();
println "played sound $pathName";
// e.g. played sound C:\Users\Beheerder\AppData\Roaming\Freeplane\1.2.x\scripts\mySound.wav 

Author: jokro Adapted from thePomodoro Timer script

Play sound with dialog

In the above example, if the .wav file resides in C:\Users\Beheerder\AppData\Roaming\Freeplane\1.2.x\scripts\mySound.wav, a dialog for playing the sound is opened and the sound is played in the following script;

// IMPORTANT Tools > Preferences > Plugins "Permit to execute other applications" must be checked.
loadUri(new URI('file:///C:/Users/Beheerder/Documents/My%20Dropbox/_MindMap/sound.wav'))
// or, starting from a file:
// loadUri(new File('C:\\Users\\Beheerder\\Documents\\My%20Dropbox\\_MindMap\\sound.wav').toURI())

class FreeplaneWindow

This example illustrates:

  1. defining a groovy class
  2. using an initalisation method for the class, with the same name of the class: FreeplaneWindow() {this.fp}. This method is called once and makes sure the global Freeplane object "ui" is known inside the class.
  3. instantiating the class and passing "ui" as a class parameter: w=new FreeplaneWindow(ui)
  4. setting & getting the position and size of the Freeplane main window without having to know the underlying specifics.
// class FreeplaneWindow
import java.awt.Frame;
import java.awt.Point; 
import java.awt.Dimension; 
import java.awt.Toolkit; 
 
class FreeplaneWindow {
    public FreeplaneWindow(Object fp) { this.fp = fp; }
    //use w= new FreeplaneWindow (ui) to pass global object ui from Freeplane)
    private fp
    private frame = fp.getFrame()
    private location = frame.getLocationOnScreen()
    private dimension = frame.getSize()
    public Object getFreeplaneWindow() {this.fp} //delivers ui
    public void setFullScreen() {
                frame.setSize(Toolkit.getDefaultToolkit().getScreenSize());
                frame.validate();                // Make sure layout is ok
                frame.setLocation(0,0)
                }
    public void setWindow(Integer left, top, width, height) {
                frame.setSize( new Dimension(width,height));
                frame.validate();                // Make sure layout is ok
                frame.setLocation(left,top)
                }
    public void setWindowForHD(){setWindow(0,0,1280,720)}
    public getTop()    {location.getX()}
    public getLeft()   {location.getY()}
    public getWidth()  {dimension.getWidth()} 
    public getHeight() {dimension.getHeight()}
}

//test it
    w=new FreeplaneWindow(ui)  // instantiate the class
    w.setWindowForHD()         // define a window of standard HD size
    println w.getTop()         // get the position on the screen
    println w.getLeft()
    println w.getWidth()
    println w.getHeight()

Author: jokro

open web page in external browser

THIS SCRIPT DOES

  • extract text contents from a node as part of a HTTP request
  • construct a valid URI to be understood from a browser
  • display the corresponding web page in an external browser

EXAMPLE APPLICATION

I use this script to easily jump into a help web page from within a programming language mindmap. When I describe function definitions like FileOpen() within a node, the script extracts the function name and combines it with a base URI which leads to a description WEB page. Combining the script execution with a keyboard shortcut e.g. , I can quickly lookup the detailed function documentation. In this example, it applies to the AutoIt scripting language.

example AutoIt

INSTRUCTIONS

In order for this script to operate properly, these conditions must be met:

  • the base URI for the HTTP request must be specified somewhere within the mindmap ** the appropriate string must be put into a node's core text ** the text string must end with a slash "/" ** a node's attribute "type" must be present with a value of "FunctionDocumentationBase"
  • the function name string within the selected node text must meet the following conditions ** the function name must end with opening braces "(" (no space inbetween) ** directly prior to the function name there may be one of the following: *** nothing, *** an equal sign "=" with further preceding characters *** an equal sign "=" with further preceding characters and following whitespaces
// @ExecutionModes({ON_SINGLE_NODE})

// INCLUDES
import java.awt.Desktop;
import java.net.URI;

//
// DEFINTIONS OF PRIVATE FUNCTIONS
//

private boolean showPageInBrowser( arg ){

    // check if desktop is supported
    if( !java.awt.Desktop.isDesktopSupported() ) {

        println "ERROR: Desktop is not supported."
        return false
        }

    // create desktop instance
    java.awt.Desktop desktop = java.awt.Desktop.getDesktop();

    // ensure that desktop is supported
    if( !desktop.isSupported( java.awt.Desktop.Action.BROWSE ) ) {
        println "ERROR: Desktop doesn't support browse action."
        return false
        }

    // now, show page in external browser
    try {
        java.net.URI uri = new java.net.URI( arg );
        desktop.browse( uri );
        }
    catch ( Exception e ) {
        println "ERROR: while trying to show [${arg}]: '${e.message}'."
        c.statusInfo = e.message;
        }

    // back with positive result
    return true
}


//
// EXTRACT FUNCTION NAME FROM NODE TEXT
//

// static definitions
def sKey = 'type'
def sValue = 'FunctionDocumentationBase'

// extract function keyword from node text
def sFunctionName = node.plainText.split( "\\(" )[0]

// document base directory in the WEB
def sWebDokuBase = ""

// reset pointer to first character of FunctionName
def iKeywordStart = 0

// strip off leading definitions if present
if( sFunctionName.matches( "^.*\\=.*" ) )
{
    // identify position of "="
    iKeywordStart = sFunctionName.indexOf( "=" ) +1

}

// strip off leading (and trailing) white spaces
sFunctionName = sFunctionName.substring( iKeywordStart ).trim()


//
// CONSTRUCT NODE HYPERLINK AND SHOW PAGE IN BROWSER
//

// find node with specific attribute setting
c.find{
    it.attributes.get( sKey ) == sValue
}.each{
    sWebDokuBase = it.getPlainTextContent()
}

// check if base hyperlink path was found
if( sWebDokuBase.equals( "" ) )
{
    // print error message
    c.statusInfo = "ERROR: no node attribute matching key '" + sKey + "' and value '" + sValue + "' found. Please create node first!"
}
else
{
    // print status info
    c.statusInfo = "INFO: opening [ " + sWebDokuBase + sFunctionName + ".htm ] with external browser."

    // jump to hyperlink using function
    showPageInBrowser( sWebDokuBase + sFunctionName + ".htm" )

}

Author: nnako

Paste clipboard

NOTE: this script stopped working after 1.10.4-pre07. To simply paste, an option is menuUtils.executeMenuItems(['PasteAction',]).

These scripts just pastes the clipboard content into the current node. Use "Execute Paste on all selected nodes" to paste into all selected nodes.

  1. This script is equivalent to the default Edit/Paste as.../ "HTML as node hierarchy" if there is text/html type in the clipboard, otherwise equivalent to "Plain text as node hierarchy":
import org.freeplane.features.map.mindmapmode.clipboard.MMapClipboardController

def clipboardController = MMapClipboardController.controller
def target = node.delegate
clipboardController.paste(clipboardController.clipboardContents, target, false, target.isNewChildLeft())
  1. This script is equivalent to the default Edit/Paste as.../ "HTML as single node":
import org.freeplane.features.map.mindmapmode.clipboard.MMapClipboardController
import org.freeplane.core.util.TextUtils;

def clipboardController = MMapClipboardController.controller
def target = node.delegate

/* Paste data as HTML single node */
//Check if html data is available in the clipboard
def isHtmlSupport = clipboardController.getSupportedHtmlFlavor(clipboardController.clipboardContents)

//Paste the data if DirectHtmlFlavorHandler is available, in other words, paste HTML as single node. 
if (isHtmlSupport != null) {

    //Generally when isHtmlSupport is True, the below line will return two flavor handlers: DirectHtmlFlavorHandler, which is for pasting HTML as single node, and StructuredHtmlFlavorHandler, which is the default handler. If StructuredHtmlFlavorHandler is used instead of DirectHtmlFlavorHandler, then the below script will do the same thing as script 1 above.
    def flavors = clipboardController.getFlavorHandlers()

    for (i = 0; i < flavors.size(); i++) { 
        if (TextUtils.getText(flavors.get(i).getClass().getSimpleName()).toString() == "HTML as single node") {
                clipboardController.paste(clipboardController.clipboardContents, flavors.get(i), target, false, target.isNewChildLeft())            
            break
        }     
    }    
}

Author: boercher Update:dreamofi

Access nodes from clipboard

This script isn't useful for itself but it shows how to access nodes that have been copied to the clipboard before. Once you have the node you can do everything you want with them: extract text, icons, links, ... However, in this script only the node count is echoed to the status bar and the nodes are printed to the log file.

import groovy.util.XmlParser
import java.awt.datatransfer.Transferable

import org.freeplane.features.clipboard.ClipboardController
import org.freeplane.features.clipboard.MindMapNodesSelection

private String getXml(Transferable t) {
    if (t.isDataFlavorSupported(MindMapNodesSelection.mindMapNodesFlavor)) {
        try {
            return t.getTransferData(MindMapNodesSelection.mindMapNodesFlavor).toString()
        }
        catch (final Exception e) {
        }
    }
    return null;
}

private List getNodesFromClipboard(String xml) {
    try {
        def parser = new XmlParser()
        return xml.split(ClipboardController.NODESEPARATOR).collect() {
            def xmlRootNode = parser.parseText(it)
            node.mindMap.node(xmlRootNode.@ID)
        }
    }
    catch (final Exception e) {
    }
    return [];
}

def copiedNodes = getNodesFromClipboard(getXml(ClipboardController.controller.clipboardContents))
c.statusInfo = "got ${copiedNodes.size()} nodes from clipboard"
copiedNodes.eachWithIndex { i, it ->
    // replace this with something more useful:
    println "node [${i}]: ${it}"
}

Author: boercher

toggle block view for all siblings

THIS SCRIPT DOES

a script to set (toggle) the MIN NODE WIDTH setting of all siblings of a node to a unified value. This value is based on the maximum node width of all the sibling nodes and can be adjusted using some script parameters (see options). Only those sibling nodes will be regarded which have the same style setting as the node selected when starting the script. When selecting multiple nodes the node styles are disregarded for this functionality but the identifier setting (if present still counts).

example toggle view

INSTRUCTIONS

In order for this script to operate according to your wishes, use the following options

  • strIdentifier - set necessary start string for nodes to be handled (e.g. '[')
  • width_grid - set grid for MIN NODE WIDTH operation
  • width_offset - set minimum offset to be added to maximum sibling node width
// @ExecutionModes({ON_SINGLE_NODE})
import org.freeplane.view.swing.map.NodeView

//
// configuration
//

// set default node identifier
def strIdentifier = "" // e.g. "[" for regarding only nodes with cores starting with "["

// width raster for the maximum width to get snatched
def width_grid = 20

// offset to be added to maximum node width
def width_offset = 10

//
// local variables
//

// get map zoom factor
def zoomfactor = c.getZoom()

// maximum width (with default value)
def maxwidth = 0

// node with maximum width (with default value)
def maxnode = node

// save current node object
def current_node_style = node.style.name

// node view
def nodeView = 0

// setting for regarding style setting
def bRegardStyleSetting = 1

// get parent node from selected node
def nodeParent = node.getParent()

// widthcompare
def widthcompare = 0

// get current width of component
def width = 0

// get list of siblings
lstSiblings = nodeParent.getChildren()

// if there are more than one nodes selected ...
if( c.selecteds.size() > 1 ) {

    // list of siblings will be all selected nodes
    lstSiblings = c.selecteds

    // don't regard the node's styles
    bRegardStyleSetting = 0

}

// set default for marker
def bLeaveFunctionHereafter = 0

//
// check if any relevant node has minimum width setting and reset setting
//

// take every sibling and ...
lstSiblings.each{

    // only regard nodes with fitting style ...
    if( it.style.name == current_node_style || bRegardStyleSetting == 0 ){

        // if any minimum width is set ...
        if( it.style.getMinNodeWidth() > 1 ){

            // if node start character specifics are fitting ...
            if( it.getPlainText().startsWith( strIdentifier ) ){

                // set marker
                bLeaveFunctionHereafter = 1

                // reset minimum node width
                it.style.setMinNodeWidth( -1 )

            }
        }
    }
}

// if marker was previously set ...
if( bLeaveFunctionHereafter == 0 ){

    //
    // determine maximum current node width of all siblings
    //

    // take every sibling and ...
    lstSiblings.each{

        // only regard nodes with fitting style ...
        if( it.style.name == current_node_style || bRegardStyleSetting == 0 ){

            // get nodeView
            nodeView = it.delegate.viewers.find() {it instanceof NodeView}

            // get current width of component
            width = nodeView?.mainView?.width

            // if its current width is the biggest so far ...
            if( width > maxwidth ){

                // if node start character specifics are fitting ...
                if( it.getPlainText().startsWith( strIdentifier ) ){

                    // update maximum width variable with current node width
                    maxwidth = width

                    // set max width node
                    maxnode = it

                }
            }
        }
    }

    // jump to node with maximum width
    //c.select( maxnode )

    //
    // set minimum width value for all siblibngs
    //

    // set starting width
    widthcompare = width_grid

    // fit maxwidth to raster
    while( maxwidth.div( zoomfactor ) + width_offset > widthcompare ){

        // increment width compare value
        widthcompare += width_grid
    }

    // take every sibling and ...
    lstSiblings.each{

        // only regard nodes with fitting style ...
        if( it.style.name == current_node_style || bRegardStyleSetting == 0 ){

            // if node start character specifics are fitting ...
            if( it.getPlainText().startsWith( strIdentifier ) ){

                // set its minimum width to the maximum current plus delta
                it.style.minNodeWidth = widthcompare

            }
        }
    }
}

// printout status
c.statusInfo = "zoom: $zoomfactor ; maxwidth: $maxwidth ; width: $width ; widthcompare: $widthcompare"

Author: nnako

Template Chooser - Create nodes from templates

A script to allow Freeplane users to define nodes as templates and then choose a template when creating a new node. Any node with the core text startgin with 'Template:' is considered a template. Script finds all template nodes and allows the user to choose a template and create a new node based on that template. Latest version and demo map available at https://github.com/adxsoft/TemplateChooser.

/* Template Chooser Script
A modification of the original script by Quinbus Flestrin, December 12, 2011
Modified by Allan at ADXSoft 20th Jan 2017

Purpose is to locate and copy pre-defined Templates as new branches to the selected node
The script uses a GUI swingbuilder combo box to capture user input as to which template
and then searches the map for any nodes with node text that commences with the string "Template:""
(these templates can be anywhere in the map).


Version 0.1

History
0.1 Original script

*/

import groovy.swing.SwingBuilder
import java.awt.FlowLayout as FL
import javax.swing.BoxLayout as BXL
import javax.swing.JFrame
import javax.swing.JOptionPane

template_prefix="Template:"

// scan map for Templates
templateList=[]
node.mindMap.root.find({it.text.startsWith(template_prefix)}).each{
    templateList+=it.text
}


def s = new SwingBuilder()
s.setVariable('myDialog-properties',[:])
def vars = s.variables
def dial = s.dialog(title:'Template Picker', id:'myDialog', minimumSize: [300,50], modal:true, locationRelativeTo:ui.frame, owner:ui.frame, defaultCloseOperation:JFrame.DISPOSE_ON_CLOSE, pack:true, show:true) {

    panel() {

        boxLayout(axis:BXL.Y_AXIS)

        panel(alignmentX:0f) {
            flowLayout(alignment:FL.LEFT)
            label('Choose Template')
            comboBox(id:'type', items:templateList)
        }

        panel(alignmentX:0f) {
            flowLayout(alignment:FL.RIGHT)
            button(action: action(name: 'OK', defaultButton: true, mnemonic: 'O',
                    closure: {vars.ok = true; dispose()}))
            button(action: action(name: 'Cancel', mnemonic: 'C', closure: {dispose()}))
        }
    }
}
if (vars.ok){

    c.find{
        it.text == vars.type.selectedItem
    }.each {
        def Copy = node.appendBranch(it)

        // create attributes in the new node (comment these lines out if not required)
        type=vars.type.selectedItem
        plen=template_prefix.length()
        type=type[plen+1..plen+type.length()-plen-1]
        Copy.text=type
        Copy.attributes.set("type", type)
        def today = new Date()
        def formattedDate = today.format('dd-MM-yy')
        Copy.attributes.set("created", formattedDate)
        // end of attributes creation
    }
}
//JOptionPane.showMessageDialog(ui.frame, 'REMINDER: Dates can be quickly inserted in each node with the Insert Date feature in property panel', "Template Picker" , JOptionPane.INFORMATION_MESSAGE);

Author: Adxsoft

Export nodes, notes and details to OPML

A script to export nodes, notes and details to opml. (Freeplane currently only exports node core text to OPML) This experimental script exports core text, notes and details for nodes. Node Notes and Details are exported as plain text rather than html The script 'Export OPML from selected node.groovy' creates opml 'outline tags' with 'text' and '_note' attributes

  • The 'text' attribute will contain the plain text of the node core text
  • The '_note' attribute will contain the node's note (if present) and also appends the node's details if present Latest version and demo map available at https://github.com/adxsoft/freeplaneOPMLExportWithNotes
/*
Freeplane Export nodes, notes and details to opml
Notes and Details are exported as plain text rather than html

Version History
V0.1 original script

Installation
1. Open the User Directory in Freeplane (Tools/Open User directory)
2. Open the scripts folder
3. Save this script as 'Export OPML from selected node.groovy' in the scripts folder
4. Restart Freeplane

To Use Script
1. Select the node you wish to export from (generally would be the root node of your map)
2. In Freeplane 'Tools' menu select 'Scripts'
3. Choose the script 'Export OPML from selected node'
4. Enter the saved file name when requested
5. OPML nodes, notes ande details will be exported from the selected node and its children
*/

import javax.swing.JFileChooser

class OPMLWriter {

    def rootNode;
    def output=''
    def outline_tag='<outline $$attributes$$>'
    
    def processNode(newNode, childPosition) {
        def nodeLevel = newNode.getNodeLevel(true)
        def outline_attribs='text="'+newNode.plainText+'"'
        def hasnote=false
        if (newNode.noteText) {
            outline_attribs+=' _note="'+removeHtmlTags(newNode.noteText)+'"'
            hasnote=true
        }
        if (newNode.detailsText) {
            if (hasnote) {
                def s=outline_attribs[0..-2]
                s+='\nDetails:\n'+
                        removeHtmlTags(newNode.detailsText)+'"\n'
                outline_attribs=s
            } else {
                outline_attribs+=' _note="Details:\n'+
                        removeHtmlTags(newNode.detailsText)+'"\n'

            }
        }
        output+="    "*(nodeLevel+1)+
                outline_tag.replace('$$attributes$$',outline_attribs)

        def i = 0
        if (newNode.children) {
            newNode.children.each {
                i++
                processNode(it, i)
            }
        }
        output+="    "*(nodeLevel+1)+'</outline>\n'
    }

    def removeHtmlTags(text) {
        def strippedText = text.replaceAll('\n\\s*','\n') // remove extra spaces after line breaks
        strippedText = strippedText.replaceAll('<.*?>', '') // remove anythiing in between < and >
        strippedText = strippedText.replaceAll('^\\s*', '') // remove whitespace
        strippedText = strippedText.replaceAll('\n\n\n','\n') // replace multiple line feed with single line feed
        return strippedText
    }

    def traverse() {
        processNode(rootNode, 0)
    }

}

//=================
// MAIN ENTRY POINT
//=================


// get saved file details
chooser = new JFileChooser()
chooser.setDialogTitle('Export to OPML from selected node')
returnVal = chooser.showSaveDialog();
if (returnVal == JFileChooser.APPROVE_OPTION) {

    // save file chosen so commence export

    c.statusInfo = 'User will save to file ' + chooser.selectedFile
    opmlfilename = chooser.selectedFile.toString()

    // instantiate the OPMLWriter class and set
    // starting node to selected node ('node')
    def opmlwriter = new OPMLWriter(rootNode:node);

    // walk through the selected node and its children
    opmlwriter.traverse()

    // build the opml file
    //
    // .. header
    opmldata="""
<opml version="1.0">
      <head>
        <title>$node.text</title>
    </head>
    <body>
"""
    // .. main body - outline tags
    opmldata+=opmlwriter.output

    // .. tail
    opmldata+="""
</body>
</opml>
"""

    // write the output opml file
    def outputfile = new File(opmlfilename)
    outputfile.write(opmldata.toString())

    c.statusInfo = 'Export to opml file ' + chooser.selectedFile+' completed.'

} else {
    c.statusInfo="Export OPML cancelled by user"
}

Author: Adxsoft

LIBRARY for creation and usage of global variables

Sometimes, a developer wants to share variables between scripts. For example, you want to remember a certain node id, a list of nodes a calculated text content, ... which can NOT be found within the currently selected node or map. And, you want to use this content by different scripts without having to calculate it within each of these subsequent scripts. Then you need "global variables" to store and retrieve these contents.

The following code is a "library". Its functions can be used within any of your scripts if you put this code into you scriptlib folder. Please see https://www.freeplane.org/wiki/index.php/Your_own_utility_script_library for instructions about utilization of script libraries.

/**
 *
 * DESCRIPTION
 *
 * static functions for management of global variables.
 * These variables have the following properties:
 *
 *  - choice of scope for each variable
 *    - global for local map
 *    - global for Freeplane instance
 *    - global for a different map [TODO]
 *  - persistent variable content (valid after restart and relocation)
 *  - content can be edited using any text editor (no Freeplane necessary)
 *  - ...
 *
 *
 * CAUTION
 *
 *  - library functions create a subdirectory '_global_vars'
 *    according to the choice of scope. If this folder name
 *    is already used, the code must be altered before function
 *    execution.
 *
 *    -> in case of scope='map' [DEFAULT]
 *       the folder will be created below the current map's location
 *
 *    -> in case of scope='global'
 *       the folder will be created below the user's application folder
 *
 *
 * AUTHOR
 *
 *   nnako, 2017
 *
 */


//
// INCLUDES
//

import org.freeplane.plugin.script.proxy.ScriptUtils
import groovy.json.JsonBuilder
import groovy.json.JsonSlurper


//
// STATIC FUNCTIONS
//

def static get( def strVarname, def strScope='map' ) {

    // get Freeplane objects
    def node = ScriptUtils.node()
    def c = ScriptUtils.c()
    def strSubfolder = '_global_vars'
    def infile = ''

    // check for scope
    if( strScope.equals( 'map' ) ) {

        // construct file name
        infile = new File( 
            node.mindMap.file.getParent() + File.separator
            + strSubfolder + File.separator
            + strVarname + '.json' )

    } else if( strScope.equals( 'global' ) ) {

        // construct file name
        infile = new File( 
            c.getUserDirectory().toString() + File.separator
            + strSubfolder + File.separator
            + strVarname + '.json' )

    }
    // ... to be continued for foreign-map-wide global variable access
    else {
        return
    }

    // check if file exists
    if( infile.exists() && !infile.isDirectory() ) {

        // return value to caller
        return new JsonSlurper().parseText( infile.text )[0]

    }

}

def static set( def strVarname, def objValue, def strScope='map' ) {

    // get Freeplane objects
    def node = ScriptUtils.node()
    def c = ScriptUtils.c()
    def strSubfolder = '_global_vars'
    def outfile = ''

    // check for scope
    if( strScope.equals( 'map' ) ) {

        // construct file name
        outfile = new File(
            node.mindMap.file.getParent() + File.separator
            + strSubfolder + File.separator
            + strVarname + '.json' )

    } else if( strScope.equals( 'global' ) ) {

        // construct file name
        outfile = new File(
            c.getUserDirectory().toString() + File.separator
            + strSubfolder + File.separator
            + strVarname + '.json' )
    }
    // ... to be continued for foreign-map-wide global variable access
    else {
        return
    }

    // create global's folder (if it doesn't exist)
    outfile.getParentFile().mkdirs()

    // write value into file
    outfile.write( new JsonBuilder( [ objValue ] ).toPrettyString() )

}

In order to use this library, your code (within any of your normal scripts) could look like this:

// save and retrieve map-global string
Global.set( 'strTest', 'dies ist ein Text-String, der map-global gespeichert wurde' )
ui.informationMessage( Global.get( 'strTest' ) )

// save and retrieve map-global list
Global.set( 'lstIntTest', [1, 2, 3, 4, 5] )
ui.informationMessage( String.valueOf( Global.get( 'lstIntTest' )[2] ) )

// save and retrieve Freeplane-global global string
Global.set( 'strTest', 'dies ist ein Text-String, der Freeplane-global gespeichert wurde', 'global' )
ui.informationMessage( Global.get( 'strTest', 'global' ) )

Author: nnako

Add/Remove integer indexes on nodes

These scripts add or remove integer indexes to nodes text. Nodes are consecutively numbered in depth-first order. Example: "some node text" becomes "some node text [42]" and vice-versa.

I'm using this script as a facilitator for cross-referencing nodes in another application.

Indexes are stored straight into the node's text. This is a very simple regex / parsing, thus one must be careful to adapt regex and avoid clashes.

Author: Laurentp13

Script to add indexes:

// add.groovy - add an index number to nodes
//   "some text" becomes "some text [42]"
//   adds index only to nodes that don't have one yet
// ! indexes are located using very simple regex : \[\d+\]
//   so ... do not use integers between square brackets in your nodes !
//   (or change the pattern)


import  java.util.regex.*
def allNodes = c.findAll()
int index = 0


// define pattern for extracting index from node
// for legibility, this is the pattern without the extra backslashes
// required by Java
//		raw pattern : "^.*\[\d+\]$"
//		with groups	:	"^(.*)\[(\d+)\]$"
String patternDef = "^(.*)\\[(\\d+)\\]\$"
Pattern pattern = Pattern.compile(patternDef)

// when new nodes are added, numbering must start from last index used

// do a first pass to find last indexes
int last = 0
int current = 0
Matcher matcher
allNodes.eachWithIndex{ it, i ->
	matcher = pattern.matcher(it.text)
	if (matcher.matches()) current = Integer.parseInt(matcher.group(2))
	if (current > last) last = current
}

// any new label to start from there
index = last

// second pass to add indexes to nodes not yet having one
allNodes.eachWithIndex{ it, i ->
	matcher = pattern.matcher(it.text)
	if (matcher.matches()) {
		// already labelled: do nothing
	} else {
		// move index and add label
		index++
		it.text = it.text + " [" + index + "]"
	}
}

Script to remove indexes:

// remove.groovy - remove index numbers from nodes
//   "some text [42]" becomes "some text"
// ! indexes are located using very simple regex
//   ==> do not use integers between square brackets in your nodes !
import  java.util.regex.*

// just iterate on nodes to find regex and delete
def allNodes = c.findAll()
allNodes.eachWithIndex{ it, i ->
	it.text = it.text.replaceAll(" \\[\\d+\\]\$","")
}

A collection of scripts that might need a review before adding them to the "official" [Scripts collection](../scripting/Scripts_collection .md).

Feel free to add your own scripts to this page. If you give script a name using wiki text like

<syntaxhighlight lang="Groovy" name="yourScriptName"> your script </syntaxhighlight>

an extra download button is created for it, and it can be downloaded directly from this page.

Pair of scripts to increase/decrease the node-width (can be used with shortcuts!)

Since freeplane 1.5.x we can adjust the node-width with ALT+mouse-wheel, but there is currently no way to make it with keyboard shortcuts.

So these scripts aim at increasing/decreasing the node-width (the same way that ALT-mout-wheel would do), but by being scripts they will have a menu entry in "Tools/Scripts/Node Width_Increase" and "Tools/Scripts/Node Width_Decrease", making possible to create a shortcut to these menu entries, and so, to adjust the node-width with keyboard shortcuts.

How to install the scripts

  1. Download the 2 scripts from https://www.freeplane.org/wiki/index.php/Script_incubator and put them inside the directory "/scripts" (you can open "" clicking in "Tools/Open user directory")
  2. Restart Freeplane - Verify that the 2 new scripts appear in these 2 new menu-entries "Tools/Scripts/Node Width_Increase" and "Tools/Scripts/Node Width_Decrease"
  3. optional Assign a shortcut-key to each of the 2 menu-entries (hold CTRL while clicking a menu-entry)

Hope it helps :)

// @ExecutionModes({ON_SELECTED_NODE})
 
// zipizap, Feb2016
// Trying to solve this thread discussion [1]
// Inspired by this node-width sample code [2]
// Published here: https://www.freeplane.org/wiki/index.php/Script_incubator#Pair_of_scripts_to_increase.2Fdecrease_the_node-width_.28can_be_used_with_shortcuts.21.29
// Dedicated to the great and friendly freeplane community :)
// UPDATE: 2016/08/16 - added improvements made by Ken Hill (see [3])
// UPDATE: 2017/01/13 - smaller code, only uses maxNodeWidth
//
//
// [1] https://sourceforge.net/p/freeplane/discussion/758437/thread/8f1d0faa/
// [2] https://sourceforge.net/p/freeplane/discussion/758437/thread/108a5c74/#2d6a
// [3] https://sourceforge.net/p/freeplane/discussion/758437/thread/8f1d0faa/#bf45
 
def step=10
node.style.maxNodeWidth+=step
// @ExecutionModes({ON_SELECTED_NODE})
 
// zipizap, Feb2016
// Trying to solve this thread discussion [1]
// Inspired by this node-width sample code [2]
// Published here: https://www.freeplane.org/wiki/index.php/Script_incubator#Pair_of_scripts_to_increase.2Fdecrease_the_node-width_.28can_be_used_with_shortcuts.21.29
// Dedicated to the great and friendly freeplane community :)
// UPDATE: 2016/08/16 - added improvements made by Ken Hill (see [3])
// UPDATE: 2017/01/13 - smaller code, only uses maxNodeWidth
//
//
// [1] https://sourceforge.net/p/freeplane/discussion/758437/thread/8f1d0faa/
// [2] https://sourceforge.net/p/freeplane/discussion/758437/thread/108a5c74/#2d6a
// [3] https://sourceforge.net/p/freeplane/discussion/758437/thread/8f1d0faa/#bf45
 
def step=10
(node.style.maxNodeWidth - step) > 0 ? node.style.maxNodeWidth-=step : null

Author: zipizap


Scripts to save/restore the folding of the current map, with 2 restore-points

Trying to help out with this request, to save different folding states [- see the thread for more info

[1] https://sourceforge.net/p/freeplane/discussion/758437/thread/10318019/?limit=25#879e

Use the save script to save the current folding of the map, and then later use the restore script to restore the saved-folding.

The folding-states are saved into the maps (.mm) file, and so are persistent across map loading. That is: you can save a folding state today, and next week when you open the same map restore the folding state

There are 2 pairs of files - save/restore_S0 and save/restore_S1 - that enable 2 restore-points.

If you need more restore points, then create more pairs of files (save/restore_S2, save/restore_S3, ...) where you will only need to change the last 2 lines of code save_restore_closure(...,"S9")

How to install the scripts

  1. Download the scripts from https://www.freeplane.org/wiki/index.php/Script_incubator and put them inside the directory "/scripts" (you can open "" clicking in "Tools/Open user directory")
  2. Restart Freeplane - Verify that the new scripts appear inside menu "Tools/Scripts"
  3. optional Assign a shortcut-key to each of the scripts new menu-entries (hold CTRL while clicking a menu-entry)

Hope it helps :)

// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
Closure save_restore_closure = 
  { String save_or_restore, String folding_state_name ->       
    // The save_or_restore variable should be given on of these two values: "save" or "restore"
    // The folding_state_name variable can be given any name without spaces or special characters. Ex: "S0" or "S1" or "S2"

    if ( save_or_restore == "save" ) {
      // save folding

      // get foldings
      def folded_nodes_ids_ary = c.findAll().findAll { it.isFolded() }.collect { it.id }
        // Array of Strings 
        // [ 'ID_xxx1',
        //   'ID,xxx2',
        //    ...
        //   'ID_xxxN'
        // ]
      //folded_nodes_ids_ary.each { N(it).style.backgroundColorCode = '#0000FF' }

      String stringified_ary_xml_escaped = htmlUtils.toXMLEscapedText( folded_nodes_ids_ary.inspect() )
        // String xml-escaped (ready to be stored in XML file)
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      // save to map stringified_ary_xml_escaped
      node.map.storage[folding_state_name]=stringified_ary_xml_escaped
    } else {
      // restore folding

      // load from map stringified_ary_xml_escaped
      def result_convertible = node.map.storage[folding_state_name]
        // Convertible (see org.freeplane.plugin.script.proxy.Convertible, use result_convertible.string to get String)
        // or null

      if (result_convertible == null) {
        return 
      }

      String stringified_ary_xml_escaped = result_convertible.string
      String stringified_ary = htmlUtils.toXMLUnescapedText( stringified_ary_xml_escaped )
        // String
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      def folded_nodes_ids_ary = Eval.me(stringified_ary)
        // Array of Strings
        //  [ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ] 

      // restore foldings
      c.findAll().each { n ->  n.setFolded( folded_nodes_ids_ary.contains(n.id) ? true : false ) }
    }
  }

// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
save_restore_closure("save", "S0")
//save_restore_closure("restore", "S0")



// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
Closure save_restore_closure = 
  { String save_or_restore, String folding_state_name ->       
    // The save_or_restore variable should be given on of these two values: "save" or "restore"
    // The folding_state_name variable can be given any name without spaces or special characters. Ex: "S0" or "S1" or "S2"

    if ( save_or_restore == "save" ) {
      // save folding

      // get foldings
      def folded_nodes_ids_ary = c.findAll().findAll { it.isFolded() }.collect { it.id }
        // Array of Strings 
        // [ 'ID_xxx1',
        //   'ID,xxx2',
        //    ...
        //   'ID_xxxN'
        // ]
      //folded_nodes_ids_ary.each { N(it).style.backgroundColorCode = '#0000FF' }

      String stringified_ary_xml_escaped = htmlUtils.toXMLEscapedText( folded_nodes_ids_ary.inspect() )
        // String xml-escaped (ready to be stored in XML file)
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      // save to map stringified_ary_xml_escaped
      node.map.storage[folding_state_name]=stringified_ary_xml_escaped
    } else {
      // restore folding

      // load from map stringified_ary_xml_escaped
      def result_convertible = node.map.storage[folding_state_name]
        // Convertible (see org.freeplane.plugin.script.proxy.Convertible, use result_convertible.string to get String)
        // or null

      if (result_convertible == null) {
        return 
      }

      String stringified_ary_xml_escaped = result_convertible.string
      String stringified_ary = htmlUtils.toXMLUnescapedText( stringified_ary_xml_escaped )
        // String
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      def folded_nodes_ids_ary = Eval.me(stringified_ary)
        // Array of Strings
        //  [ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ] 

      // restore foldings
      c.findAll().each { n ->  n.setFolded( folded_nodes_ids_ary.contains(n.id) ? true : false ) }
    }
  }

// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
//save_restore_closure("save", "S0")
save_restore_closure("restore", "S0")



// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
Closure save_restore_closure = 
  { String save_or_restore, String folding_state_name ->       
    // The save_or_restore variable should be given on of these two values: "save" or "restore"
    // The folding_state_name variable can be given any name without spaces or special characters. Ex: "S0" or "S1" or "S2"

    if ( save_or_restore == "save" ) {
      // save folding

      // get foldings
      def folded_nodes_ids_ary = c.findAll().findAll { it.isFolded() }.collect { it.id }
        // Array of Strings 
        // [ 'ID_xxx1',
        //   'ID,xxx2',
        //    ...
        //   'ID_xxxN'
        // ]
      //folded_nodes_ids_ary.each { N(it).style.backgroundColorCode = '#0000FF' }

      String stringified_ary_xml_escaped = htmlUtils.toXMLEscapedText( folded_nodes_ids_ary.inspect() )
        // String xml-escaped (ready to be stored in XML file)
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      // save to map stringified_ary_xml_escaped
      node.map.storage[folding_state_name]=stringified_ary_xml_escaped
    } else {
      // restore folding

      // load from map stringified_ary_xml_escaped
      def result_convertible = node.map.storage[folding_state_name]
        // Convertible (see org.freeplane.plugin.script.proxy.Convertible, use result_convertible.string to get String)
        // or null

      if (result_convertible == null) {
        return 
      }

      String stringified_ary_xml_escaped = result_convertible.string
      String stringified_ary = htmlUtils.toXMLUnescapedText( stringified_ary_xml_escaped )
        // String
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      def folded_nodes_ids_ary = Eval.me(stringified_ary)
        // Array of Strings
        //  [ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ] 

      // restore foldings
      c.findAll().each { n ->  n.setFolded( folded_nodes_ids_ary.contains(n.id) ? true : false ) }
    }
  }

// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
save_restore_closure("save", "S1")
//save_restore_closure("restore", "S1")



// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
Closure save_restore_closure = 
  { String save_or_restore, String folding_state_name ->       
    // The save_or_restore variable should be given on of these two values: "save" or "restore"
    // The folding_state_name variable can be given any name without spaces or special characters. Ex: "S0" or "S1" or "S2"

    if ( save_or_restore == "save" ) {
      // save folding

      // get foldings
      def folded_nodes_ids_ary = c.findAll().findAll { it.isFolded() }.collect { it.id }
        // Array of Strings 
        // [ 'ID_xxx1',
        //   'ID,xxx2',
        //    ...
        //   'ID_xxxN'
        // ]
      //folded_nodes_ids_ary.each { N(it).style.backgroundColorCode = '#0000FF' }

      String stringified_ary_xml_escaped = htmlUtils.toXMLEscapedText( folded_nodes_ids_ary.inspect() )
        // String xml-escaped (ready to be stored in XML file)
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      // save to map stringified_ary_xml_escaped
      node.map.storage[folding_state_name]=stringified_ary_xml_escaped
    } else {
      // restore folding

      // load from map stringified_ary_xml_escaped
      def result_convertible = node.map.storage[folding_state_name]
        // Convertible (see org.freeplane.plugin.script.proxy.Convertible, use result_convertible.string to get String)
        // or null

      if (result_convertible == null) {
        return 
      }

      String stringified_ary_xml_escaped = result_convertible.string
      String stringified_ary = htmlUtils.toXMLUnescapedText( stringified_ary_xml_escaped )
        // String
        // "[ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ]"
        
      def folded_nodes_ids_ary = Eval.me(stringified_ary)
        // Array of Strings
        //  [ 'ID_xxx1',
        //    'ID,xxx2',
        //     ...
        //    'ID_xxxN'
        //  ] 

      // restore foldings
      c.findAll().each { n ->  n.setFolded( folded_nodes_ids_ary.contains(n.id) ? true : false ) }
    }
  }

// USAGE: save_restore_closure("save"|"restore", "S0"|"S1"|"S2")
//save_restore_closure("save", "S1")
save_restore_closure("restore", "S1")



Author: zipizap

Helper methods to manipulate html-formatted text

In this forum thread, Alexandre shares groovy methods that help to manipulate an html-formatted text.

Copy/paste them into your groovy scripts, and enjoy.

Show your love and appreciation in the forum thread :)

:::: So use ReplaceWithFormat to replace text in the html and you can use FindWithFormat to search the html. FindWithFormat allows to use for example the caret (^) for the beginning of string which is not possible when there is the html header tags...I use it to check if some string exists at the beginning of a node. ReplaceWithFormat allows also to use the caret char to replace at the beginning of a string, which I use to insert text at the beginning of a node. I am not sure if it works for appending at the end ($) I didn't test for that as I don't need it for now. :::: :::: Thanks, :::: :::: Alexandre

def AddHtmlTags(text) { return '<html><head><body><p>' + text + '</p></body></head></html>' }

def RemoveHtmlTags(text) {
    def strippedText = text.replaceAll('<(html|head|body|p)>', '')
    strippedText = strippedText.replaceAll('</(html|head|body|p)>', '')
    strippedText = strippedText.replaceAll('\n', '')
    strippedText = strippedText.replaceAll('^\\s*', '')
    return strippedText
}

def ReplaceWithFormat(pNode, pattern, replacement) { 
    def strippedText = RemoveHtmlTags(pNode.text)
    def replacedText = strippedText.replaceAll(pattern, replacement)
    return AddHtmlTags(replacedText)
    }

def FindWithFormat(pNode, pattern) {
    def strippedText = RemoveHtmlTags(pNode.text)
    if (strippedText =~ /${pattern}/)
        return true
    else
        return false
}

How to call freeplane menu-items from groovy script

In this forum thread, Alexandre shares one possible way to call freeplane menu-items from groovy script, and a small function to make it easy to call them.

Latter Volker reminds there is already a more complete method: menuUtils.executeMenuItems() in the Freeplane Scritping API for calling menu items. To find out what is the menuItemKey of a menu item, there is a tool that ships with the Developer Tools Addon just for that.

Copy/paste them into your groovy scripts, and enjoy.

Show your love and appreciation in the forum thread :)

// In this example, 'SelectAllAction' is the <<menuItemKey>> corresponding to the Freeplane <<menu item>> clicable in "Navigate/Select all visible nodes". 
// This will select all nodes in the map.

menuUtils.executeMenuItems(['SelectAllAction'])

#REDIRECT Scripts collection

Scripting Examples

Scripting Examples by categories.

Scripts about Node Attributes

Every attribute that is related to one specific node.

Text, Details, Notes

How to change text and details:

node.text = "node text"
node.details = "node details"
node.note = "node notes"

Node Style

node.style.font.size = 20
node.style.font.name = "Arial"
node.style.setTextColorCode("#ff0000")
node.style.setBackgroundColorCode("#000000")
node.style.edge.setColorCode("#00ff00")

Result:

node style

Details & Notes Style

Can't be done with attributes? only html? Workaround

LINKS - TBD

content will be taken from here: setting-links

Add custom checkbox (switch between completed and not completed), with icons.

// @ExecutionModes({ON_SELECTED_NODE})
if (node.icons.icons.contains("unchecked")) {
    node.icons.remove("unchecked")
    node.icons.add("button_ok")
} else {
    node.icons.remove("button_ok")
    node.icons.add("unchecked")
}

Attributes

Set attributes:

node["attribute_text"]="hello"
node["attribute_num"]=123

Get attributes:

c.statusInfo = node["attribute_text"]

Get attributes properties:

c.statusInfo = node.attributes.size()

Clear attributes:

node.attributes = [:]

Scripts about the Entire Mind Map

Everything that has to do with multiple nodes.

Navigating nodes, selecting nodes etc'.

Created+ Modified HTML Table

Create an HTML Table of "created" and "modified" dates of all subnodes, from the selected node. Save the result to current node's note.

def date_format(date) {
    return date ? date.format('yyyy-MM-dd HH:mm:ss'): 'N/A'
}

def node_to_html_table(starting_node) {
    def table = "<html><body><table><tr><th>Node</th><th>Created</th><th>Modified</th></tr>"
    starting_node.findAll().each { n -> table += "<tr><td>${n.text}</td><td>${date_format(n.getCreatedAt())}</td><td>${date_format(n.getLastModifiedAt())}</td></tr>" }
    table += "</table></body></html>"
    return table
}

node.note = node_to_html_table(node)

Count number of nodes with the word "ok" in the entire map.

def matches = c.find{ it.text.contains('ok') }
c.statusInfo = matches.size() + " nodes contain 'ok'"

Create a child node with all icons of all subnodes

def usedIcons = node.findAll()*.icons*.icons.flatten().unique().sort()
node.createChild("<-- all icons'").icons.addAll(usedIcons)

Select children nodes

This scripts select the children nodes of the selected nodes.

// @ExecutionModes({ON_SINGLE_NODE})
def toSelect = c.selecteds.collect{ node -> node.find {it.parent == node} }.sum()
c.selectMultipleNodes(toSelect)

Alias

First, set an alias for a node. right click, choose "Set node alias" and type "alias1". Then, in another node, you can reference the first node using the following code:

node.details=node.at("/**/~alias1").text

Others

Miscellaneous examples. Not related to one node, or the mind map.

For example: calling external APIs, external libraries.

// @ExecutionModes({ON_SINGLE_NODE})
def link = node.link.text
if (link) {
	textUtils.copyToClipboard(node.link.text)
	c.statusInfo = "Hyperlink Copied."
} else {
	c.statusInfo = "no link in ${node.text}"
}

GUI

Using simple GUI to display information on the screen, integrated into freeplane.

Simple YES/NO Question

import org.freeplane.core.ui.components.UITools;
def result = UITools.showConfirmDialog(node.delegate, "Simple Yes/No Question", "window title",0)
c.statusInfo=result

Simple Msgbox

import org.freeplane.core.ui.components.UITools;
UITools.informationMessage('Simple Messagebox')

Display output in a window (+ copy button)

Code for displaying some output text in a window. Useful when running some function that returns an output.

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;

def copy_textarea_to_clipboard(JTextArea textArea) {
    textUtils.copyToClipboard(textArea.getText());
    textArea.requestFocusInWindow(); 
    textArea.selectAll();
}

def show_output_window(String txt, String title="", int width=600, int height=400) {
    JFrame frame = new JFrame(title);
    JTextArea textArea = new JTextArea();
    textArea.setText(txt);
    textArea.setLineWrap(false);
    textArea.setWrapStyleWord(false);
    JScrollPane scrollPane = new JScrollPane(textArea);
    scrollPane.setPreferredSize(new Dimension(width, height));
    JButton copyButton = new JButton("Copy to Clipboard");
    copyButton.addActionListener(e -> copy_textarea_to_clipboard(textArea));
    JPanel contentPane = new JPanel(new BorderLayout());
    contentPane.add(scrollPane, BorderLayout.CENTER);
    contentPane.add(copyButton, BorderLayout.SOUTH);
    frame.setContentPane(contentPane);
    frame.pack();
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
}

show_output_window("This is an example of an output text that will be displayed in a window.", "Output Window");

result:

output window

Freeplane uses a distributed revision control system named git. Use this instead of the source packages that are contained in the releases if you plan to take up coding.

This is a guide to Working with freeplane's git repository. The first part covers the commands you need the most, while the second part ("How to's") adds some commands for special tasks such as undoing commits or reverting files (currently there is some redundancy between the two which we will remove soon).

At least one Freeplane developer learned to use git with the help of an excellent German Open Source Press book on git.

You can (and probably want to) use eclipse for most operations. We try to explain this in each section, but it is a good idea to read the EGit documentation. Some operations, such as creating remote branches should be applied with the command line only (e.g. for publishing branches: in order to make sure that tracking branches are setup correctly).

There is a fun Google Tech Talk by Linus Torvalds on git and a excellent introductory Git talk by Jessica Kerr.

Quickstart Guide

This section is meant to be as brief as possible while still explaining the necessary commands a bit so that you understand what you are doing.

Installation / Configuration

Install git as described here.

You probably want to use the latest Eclipse (make sure to get Eclipse for RCP and RAP Developers) with the EGit (Eclipse-git) plugin that is part of recent Eclipse builds. Although EGit comes with its own pure java git implementation JGit, we rely on a native git for some commands, so please install git as described above, too.

After Git installation, you need to start Git Bash and run the following command line which first set the author details globally (which will be recorded for each changeset):

$ git config --global user.name "<Firstname> <Lastname>"
$ git config --global user.email "<email address>"

Initial checkout ("clone")

Solution 1: with Git Bash

Create a new directory named 'git' for git repositories:

$ cd $HOME
$ mkdir git
$ cd git

Create a local copy of the (whole!) git repository for Freeplane by cloning (git-speak for "checking out"):

$ git clone https://github.com/freeplane/freeplane.git

This will take 3-20 minutes depending on your network connection.

Now you can quit Git console:

$ exit

A local copy of the complete history and all branches has been created. Therefore it is possible to develop and make commits offline and only connect for the purpose of getting changes from other devs (pull) or sending your commits to a remote branch (push).

Continue with Post-checkout operations below!

Solution 2 : with Eclipse/EGit

you can clone the repository as follows

  • open the Java Perspective

  • open the Git Repositories View (Window>Show View->Other...->Git->Git Repositories)

  • select the Clone a Git repository option with the URL: https://github.com/freeplane/freeplane.git

  • enter credentials, choose all branches (!), accept the defaults or choose a different directory location (for the local copy of the repo), then check import all existing projects after clone finishes, hit Finish and be patient (should take <10 minutes)

  • NOTE:: import all existing projects after clone finishes is not needed when using gradle

  • If you already have cloned the repository just import the projects to eclipse and execute Team->Share project->Git->Use or create repository in parent folder of project

  • Enable following renames in history views. By default history view does not follow changes resulting from renaming of classes or packages and moving of java classes to other packages. These features should be activated as follows:

    • In Eclipse main menu: Window -> Preferences -> Team -> Git -> History, here you should enable option "Follow Renames"
    • Using the command line set git option diff.renameLimit to some big number so that commits with big number of changes are properly processed either for the cloned repository or as a global setting:
$ git config diff.renameLimit 100000

You can change the both settings also from git configuration dialog under eclipse preferences.

Enable Git keyboard shortcuts. Funnily enough you have to give Git shortcuts some blessing before they work, see this Stackoverflow answer.

Working with branches

Overview of structure and commands

Below, you see the a general structure of branches as they are proposed for any Freeplane developer to use. The remote branch origin/master is the global master branch for any development aiming a release in an official version. Each developer may fork his own origin/ (just once) by forking the sources from origin/master using the respective Git web site function button. On the local master, the developer works out his functions, pushes them up to his origin/ and updates from origin/master. Using the depicted structure, even some GIT commands take an easy form ("$ git push" and "$ git pull" could be executed without further parameters).

Nnako_UsageOfGit.gif

LEGEND
- locations of branches and persons are depicted in BLACK,
- possible activities are shown in BLUE text.
- Each activity marked wirh a "star" can be performed by the code developer,
- the "boxed" activities are performed by the admins.
- UNDERLINED activities accord to GIT commands,
- PLAIN activities describe ordinary tasks (e.g. for modification or building of code).

The main branch which was termed trunk in BAZAAR, is termed master in GIT. It holds all the Freeplane sources. For the Docear main branch, we use docear/trunk. New (feature) branches should always be named / or (if several devs are expected to work on a feature) just . Docear branches should accordingly be prefixed with docear/.

Command sequence and basic steps

Here are the basic commands for working with branches. The diagram is given just as an overview, read the step descriptions in the following sections before trying any git commands.

  1. The remote repository is cloned from origin (sourceforge). You now have a complete local copy of the repository including all branches and the complete history.
  2. The user creates (and checks out) a new local branch user/newdev1.
  3. This branch is created on the remote side too (pushed, with -u to setup the tracking correctly).
  4. After some development on that branch, you want to integrate this with changes in master. This is done by pulling from the remote master branch on origin.
  5. After having checked the merge (pull = fetch + merge), you push the integrated user/newdev1 branch to its remote counterpart.
  6. You are done with development on user/newdev1. In order to merge your changes into master, you switch to the master branch (git checkout master) and update it (git pull).
  7. The local user/newdev branch is merged into the local master branch.
  8. After having checked the result of the merge, it is pushed to the remote master branch.

In the following, development steps which roughly correspond to the commands above are described.

Step 1: checkout parent branch

Find and checkout original source branch 'branchname (the branch you want to base your work on, usually master) to the local work space.

If your parent branch is not the master you should select it first

  • Using command line git:
# fetches the remote (tracking) branch (not necessary if you just cloned the repo)
$ git pull 
# switch to **branchname**
$ git checkout <branchname>
  • Using Eclipse/EGit,
    • Team->fetch from upstream fetches all remote branches (may not be necessary)
    • Team->Switch To->New branch..., select Source ref = refs/remotes/origin/, merge and checkout new branch

Step 2: create your local branch

Create + check out your own local branch based on the original branch: Since branches are really really cheap in git, it makes sense to create a branch for most development tasks (especially if you want a review before you integrate into master!). The following command creates a new local branch and switches to it:

$ git checkout -b <devbranch>

Step 3: Work locally on your branch

Please read chapter 2.2 of the official git book in order to get started with working with git locally. You should understand how to stage and commit changes. Here are some basic steps:

  • modify/add files...
  • add the modifications to the index:
$ git add foo.java # (**Team->Add to index** in eclipse)
  • create a commit from the changes in the index:
$ git commit [-m message] # (**Team->Commit** in eclipse)

(if you omit -m then you will be prompted for a commit message)

  • create more commits, this is all done locally!
  • look at the commit graph:
$ git log # might want to use **gitk** as a graphical tool

Eclipse git is also able to do the local commits from the team menu

Step 4: First push from your new local branch to the repository

Setup git so that only the current "upstream" branch gets pulled/pushed (instead of pushing all branches that have an upstream tracking branch which can be confusing!):

$ git config push.default tracking

Note: this option is ignored by current EGit. On EGit you get the same behavior by selecting Team->Push To Upstream.

Publish ("push") your branch (including the commits you made) so that others can see (and review!) it.

NOTE: Run every push command with --dry-run first!!

Currently it's best to do this on the command line, because push -u sets up the tracking branch properly. Make sure you use the same name! Use --dry-run first.

$ <go to the local copy of the repo ("$ cd $HOME/git/freeplane")>
$ git push -u origin <devbranch> [--dry-run]

You should see a message like:

Branch user/dev1 set up to track remote branch user/dev1 from origin.

(When pushing from eclipse you have to configure the remote tracking branch manually!). In any case (tracking branch configured automatically or manually), Team->Push to Upstream will push the current branch to its (configured) remote branch on origin.

Step 5: Development cycles

Follow the cycle: Switch to the right branch (may not be necessary)

$ git checkout <devbranch> # **Team->Switch To->user/dev1** from EGit 

pull other people's changes on your devbranch (as a beginner you might want to do this on a copy of your repository first, it's all local!)

$ git pull # **Team->Pull** from EGit

(People recommend to use git fetch and git merge instead of git pull)

you might have to resolve conflicts: (might want to use 'git mergetool' or Eclipse/EGit ) git will place <<<<<<<<<< and >>>>>>>>>> comments to show the locations of the conflict(s)

for each conflict x:

  • resolve conflict in x, remove markers
  • git add x # mark x as resolved

to undo the merge you can use

$ git reset --hard # **Team->Reset...** in EGit

but this will throw away all uncommitted changes(!)

  • commit the conflict resolution(s):
$ git commit [-m message] # **Team->Commit** in EGit
  • create local commits (see "Step 3")
  • merge changes from master (to integrate the latest code into your feature and to make Step 6 easier)
$ git pull origin master
  • merge changes from master with EGit:
    • Team->Fetch from Upstream
    • Team->Merge..., select origin/master
  • push the result of the merge with master to your remote dev branch (always run git push with --dry-run first!)
$ git push [--dry-run] # EGit: **Team->Push to Upstream**
# (same as **git push origin <devbranch>** because tracking is set up)

Step 6: Merge your development into master

When you are done with your branch, and you have completed a code review of your dev branch, it should be merged into master (!) As a new developer, you must let a more experienced developer do this!

$ git checkout <devbranch> # Switch to <devbranch> in EGit
$ git pull # **Team->Pull** in EGit
$ git checkout master # Switch to **master** in EGit
$ git pull # **Team->Pull** in EGit
$ git merge <devbranch> # EGit: **Team->Merge...**, select **local** <devbranch>
$ git push [--dry-run] # EGit: **Team->Push to Upstream**
# (same as **git push origin master** because tracking is set up)

How to's

This section contains useful information for working with git, including stuff like checking that tracking branches are set up correctly, details about working with branches, undoing commits/reverting files, and a bit more.

Checkout in more detail

Checking out is termed cloning in git speak:

$ cd ~
$ mkdir git
$ cd git
$ git clone https://github.com/freeplane/freeplane.git freeplane

If you want/have read-only access, use this as the last command:

$ git clone git://github.com/freeplane/freeplane.git freeplane

However, this will only configure the master branch (named trunk in other VCS's such as svn) locally:

$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/docear/trunk
remotes/origin/master

In order to check out a branch (which is simply a reference to a commit) that currently only exists remotely (the remotes/origin/* references are called remote tracking branches), simply switch to that branch:

$ git checkout docear/trunk

This can be done more easily using Eclipse. This page also describes how to import a repository into eclipse.

Using Tags

Show all tags:

$ git tag

Search for a tag:

$ git tag -l "release-1.1*"

Show information about a tag:

$ git show release-1.1.2

Define a tag locally:

$ git tag -a <tagname>
# (an editor opens for you to add a description)

Tags are not automatically transferred when doing a git push, you have to push individually:

$ git push origin <tagname>

or push all tags:

$ git push --tags origin

You might need a

$ git pull --tags

to get all tags. See git-fetch(1) for situations when you will need this (rarely).

TODO: sign tags?

Working with branches

Branches are very central to git. Do not hesitate to create feature, team and (of course) maintenance branches.

You probably want set push.default to tracking or upstream which makes sure that only the current branch is pushed to its upstream branch (and NOT all configured branches): Note: this option is ignored by current EGit. On EGit you get the same behavior by selecting Team->Push To Upstream.

$ git config push.default tracking

(you can equivalently set this to upstream in recent git versions).

Switch to another branch

$ git checkout <branchname>

(Team->Switch To->... in Eclipse)

How to create a new branch

New (feature) branches should be named / or (if several devs work on a feature): .

# commit everything that should go into the new branch
$ git status
$ git add <file>
[...]
$ git commit -m "my changes"

# create new branch locally
$ git checkout -b <newbranch>

# check commit log to see that above commit is in there
$ git log

# new branch must be visible and selected:
$ git branch -a  

# (make sure that the name of the new branch is correct! it is diffcult/impossible
#  to rename published branches!)

# create branch remotely, use -u to automatically configure upstream location
$ git push -u origin <newbranch>
# this should output something like this:
**Branch <newbranch> set up to track remote branch <newbranch> from origin.**
# (**'Note**': -u is important if you want to use git pull/push without
specifying a remote/refspec)

# remote branch of <newbranch> must be visible:
$ git branch -a

So the short story is:

$ git checkout -b <newbranch>
$ git push -u origin <newbranch>

Rename a local branch

$ git branch -m <old-branch-name> <new-branch-name>

TODO: how to rename the remote tracking branch => difficult!!

How to merge local branches

$ git checkout <destination_branch>
$ git merge <source_branch>

If you want to abort a merge (revert the working directory to the state before the merge command), do this:

$ git reset --hard

(WARNING: this will remove all uncommitted changes!!)

In eclipse, this can be achieved by:

  • Team->Switch To and choose <destination_branch>
  • Team->Merge... and choose <source_branch>

In Eclipse, you may have to refresh all projects (F5) if a branch has been added/modified/deleted via the command line.

Fast-Forward Merges (merge-nodes)

Often the creation of a merge commit (merge node) is not necessary, and git merge uses a fast-forward merge, omitting the merge node:

$ git merge foo
Updating 9e9a63a..732b657
Fast-forward
testfoo.txt |    1 +
1 file changed, 1 insertion(+)
create mode 100644 testfoo.txt

results in:

* 732b657 commit in branch foo
* [...]

Using the option --no-ff you can force git to create a merge node even if isn't absolutely necessary (non-fast-forward merge):

$ git merge --no-ff foo2
Merge made by the 'recursive' strategy.
testfoo2.txt |    1 +
1 file changed, 1 insertion(+)
create mode 100644 testfoo2.txt

which will result in:

*   3890bc8 (HEAD, master) Merge branch 'foo2'
|\  
| * 6bc24c5 (foo2) commit on foo2
|/  
* 
* [...]

This is useful when merging feature branches because it clearly shows the integration of a new feature. On the other hand, many merge nodes make the commit graph less readable.

Merge master->dev-branch locally

$ git checkout <devbranch>
$ git merge master

Merge dev-branch->master locally

$ git checkout master
$ git merge <devbranch>

How to remove a branch

# remove branch locally
# (use -D instead if you want to delete a branch that is not fully merged into HEAD!)
$ git branch -d <branchname>

You can do this with EGit using Team->Advanced->Delete Branch....

If you accidentally deleted a (local) branch, you can recover it by starting a new branch from the location that git branch -d echoed (or by searching for the last commit on that branch in git reflog):

$ git branch -D foo
Deleted branch foo (was 732b657).
$ git branch foo 732b657

(remember that branches are simply pointers to commits)

Warning: this only works if the delete was quite recent as orphaned commits will be deleted after some time!

Delete a remote branch(!):

$ git push origin --delete <branchname>

Now the local and the remote tracking branch should be gone:

$ git branch -a
docear/trunk
* master
remotes/origin/docear/trunk
remotes/origin/master

NOTE: The stale branch will still exist in other checkouts, until you do a:

$ git remote prune origin

in that other checkout. TODO: but it still exists there as a local branch!

Check whether your branches are set up correctly

Make sure your branches are set up correctly for push/pull:

$ git remote show origin
* remote origin
Fetch URL: https://github.com/freeplane/freeplane.git
Push  URL: https://github.com/freeplane/freeplane.git
HEAD branch: master
Remote branches:
docear/trunk tracked
master       tracked
Local branches configured for 'git pull':
docear/trunk merges with remote docear/trunk
master       merges with remote master
Local refs configured for 'git push':
docear/trunk pushes to docear/trunk (up to date)
master       pushes to master       (up to date)

Importing a remote branch

Using command line git:

$ git pull # fetches the remote (tracking) branch
$ git checkout <branchname>

Using Eclipse/EGit:

  • Team->Pull fetches the remote (tracking) branch
  • Team->Switch To->New branch..., select Source ref = refs/remotes/origin/

General workflow

Create a dev branch (see section on creating branches above).

Work on your feature branch

# switch to feature branch
$ git checkout <feature>

# fetch and merge changes (in case another dev works on this)
$ git pull

# you might have to resolve conflicts: (might want to use 'git mergetool'
# or [http://wiki.eclipse.org/EGit/User_Guide#Resolving_a_merge_conflict Eclipse/EGit])
for each conflict x:
1. resolve conflict in x, remove markers
2. git add x # mark as resolved
# commit the conflict resolution(s)
$ git commit

$ git add ...
$ git commit
[...]

# This will push commits to the remote branch that is tracked
# make sure that push.default=tracking|upstream (see above),
# otherwise other branches will be pushed as well!
$ git push [--dry-run]

Merging

Merge master -> (see section on merging above) every once-in-a-while.

After a final code review (on your dev branch), merge -> master (see section on merging above).

Miscellaneous

Revert (reset) files

git checkout <filename>

In EGit do this: Right-click on file -> Replace With -> HEAD Revision

Revert all files in working copy (!):

git reset --hard

Undoing/editing commits

TODO: how to remove/edit a commit locally using rebase.

Undoing a commit that is already pushed

Use git revert , like this:

$ git revert b1e9b4c9755b091f95aaa3035aca04dcb02ec1fd

This will generate an inverse commit, it will not remove the original commit:

* 171881e (HEAD, master) Revert "a simple commit"
* b1e9b4c a simple commit

Avoid entering passwords on each commit

At least if you use the command line git interface you should consider to deposit your public ssh key at github. See the section about ssh configuration on github.

Freeplane uses a distributed revision control system named git. Use this instead of the source packages that are contained in the releases if you plan to take up coding.

This is a guide to Working with freeplane's git repository. The first part covers the commands you need the most, while the second part ("How to's") adds some commands for special tasks such as undoing commits or reverting files (currently there is some redundancy between the two which we will remove soon).

At least one Freeplane developer learned to use git with the help of an excellent German Open Source Press book on git.

You can (and probably want to) use eclipse for most operations. We try to explain this in each section, but it is a good idea to read the EGit documentation. Some operations, such as creating remote branches should be applied with the command line only (e.g. for publishing branches: in order to make sure that tracking branches are setup correctly).

There is a fun Google Tech Talk by Linus Torvalds on git and a excellent introductory Git talk by Jessica Kerr.

Quickstart Guide

This section is meant to be as brief as possible while still explaining the necessary commands a bit so that you understand what you are doing.

Installation / Configuration

Install git as described here.

You probably want to use the latest Eclipse (make sure to get Eclipse for RCP and RAP Developers) with the EGit (Eclipse-git) plugin that is part of recent Eclipse builds. Although EGit comes with its own pure java git implementation JGit, we rely on a native git for some commands, so please install git as described above, too.

After Git installation, you need to start Git Bash and run the following command line which first set the author details globally (which will be recorded for each changeset):

$ git config --global user.name "<Firstname> <Lastname>"
$ git config --global user.email "<email address>"

Initial checkout ("clone")

Solution 1: with Git Bash

Create a new directory named 'git' for git repositories:

$ cd $HOME
$ mkdir git
$ cd git

Create a local copy of the (whole!) git repository for Freeplane by cloning (git-speak for "checking out"):

$ git clone https://github.com/freeplane/freeplane.git

This will take 3-20 minutes depending on your network connection.

Now you can quit Git console:

$ exit

A local copy of the complete history and all branches has been created. Therefore it is possible to develop and make commits offline and only connect for the purpose of getting changes from other devs (pull) or sending your commits to a remote branch (push).

Continue with Post-checkout operations below!

Solution 2 : with Eclipse/EGit

you can clone the repository as follows

  • open the Java Perspective

  • open the Git Repositories View (Window>Show View->Other...->Git->Git Repositories)

  • select the Clone a Git repository option with the URL: https://github.com/freeplane/freeplane.git

  • enter credentials, choose all branches (!), accept the defaults or choose a different directory location (for the local copy of the repo), then check import all existing projects after clone finishes, hit Finish and be patient (should take <10 minutes)

  • NOTE:: import all existing projects after clone finishes is not needed when using gradle

  • If you already have cloned the repository just import the projects to eclipse and execute Team->Share project->Git->Use or create repository in parent folder of project

  • Enable following renames in history views. By default history view does not follow changes resulting from renaming of classes or packages and moving of java classes to other packages. These features should be activated as follows:

    • In Eclipse main menu: Window -> Preferences -> Team -> Git -> History, here you should enable option "Follow Renames"
    • Using the command line set git option diff.renameLimit to some big number so that commits with big number of changes are properly processed either for the cloned repository or as a global setting:
$ git config diff.renameLimit 100000

You can change the both settings also from git configuration dialog under eclipse preferences.

Enable Git keyboard shortcuts. Funnily enough you have to give Git shortcuts some blessing before they work, see this Stackoverflow answer.

Working with branches

Overview of structure and commands

Below, you see the a general structure of branches as they are proposed for any Freeplane developer to use. The remote branch origin/master is the global master branch for any development aiming a release in an official version. Each developer may fork his own origin/ (just once) by forking the sources from origin/master using the respective Git web site function button. On the local master, the developer works out his functions, pushes them up to his origin/ and updates from origin/master. Using the depicted structure, even some GIT commands take an easy form ("$ git push" and "$ git pull" could be executed without further parameters).

Nnako_UsageOfGit.gif

LEGEND
- locations of branches and persons are depicted in BLACK,
- possible activities are shown in BLUE text.
- Each activity marked wirh a "star" can be performed by the code developer,
- the "boxed" activities are performed by the admins.
- UNDERLINED activities accord to GIT commands,
- PLAIN activities describe ordinary tasks (e.g. for modification or building of code).

The main branch which was termed trunk in BAZAAR, is termed master in GIT. It holds all the Freeplane sources. For the Docear main branch, we use docear/trunk. New (feature) branches should always be named / or (if several devs are expected to work on a feature) just . Docear branches should accordingly be prefixed with docear/.

Command sequence and basic steps

Here are the basic commands for working with branches. The diagram is given just as an overview, read the step descriptions in the following sections before trying any git commands.

  1. The remote repository is cloned from origin (sourceforge). You now have a complete local copy of the repository including all branches and the complete history.
  2. The user creates (and checks out) a new local branch user/newdev1.
  3. This branch is created on the remote side too (pushed, with -u to setup the tracking correctly).
  4. After some development on that branch, you want to integrate this with changes in master. This is done by pulling from the remote master branch on origin.
  5. After having checked the merge (pull = fetch + merge), you push the integrated user/newdev1 branch to its remote counterpart.
  6. You are done with development on user/newdev1. In order to merge your changes into master, you switch to the master branch (git checkout master) and update it (git pull).
  7. The local user/newdev branch is merged into the local master branch.
  8. After having checked the result of the merge, it is pushed to the remote master branch.

In the following, development steps which roughly correspond to the commands above are described.

Step 1: checkout parent branch

Find and checkout original source branch 'branchname (the branch you want to base your work on, usually master) to the local work space.

If your parent branch is not the master you should select it first

  • Using command line git:
# fetches the remote (tracking) branch (not necessary if you just cloned the repo)
$ git pull 
# switch to **branchname**
$ git checkout <branchname>
  • Using Eclipse/EGit,
    • Team->fetch from upstream fetches all remote branches (may not be necessary)
    • Team->Switch To->New branch..., select Source ref = refs/remotes/origin/, merge and checkout new branch

Step 2: create your local branch

Create + check out your own local branch based on the original branch: Since branches are really really cheap in git, it makes sense to create a branch for most development tasks (especially if you want a review before you integrate into master!). The following command creates a new local branch and switches to it:

$ git checkout -b <devbranch>

Step 3: Work locally on your branch

Please read chapter 2.2 of the official git book in order to get started with working with git locally. You should understand how to stage and commit changes. Here are some basic steps:

  • modify/add files...
  • add the modifications to the index:
$ git add foo.java # (**Team->Add to index** in eclipse)
  • create a commit from the changes in the index:
$ git commit [-m message] # (**Team->Commit** in eclipse)

(if you omit -m then you will be prompted for a commit message)

  • create more commits, this is all done locally!
  • look at the commit graph:
$ git log # might want to use **gitk** as a graphical tool

Eclipse git is also able to do the local commits from the team menu

Step 4: First push from your new local branch to the repository

Setup git so that only the current "upstream" branch gets pulled/pushed (instead of pushing all branches that have an upstream tracking branch which can be confusing!):

$ git config push.default tracking

Note: this option is ignored by current EGit. On EGit you get the same behavior by selecting Team->Push To Upstream.

Publish ("push") your branch (including the commits you made) so that others can see (and review!) it.

NOTE: Run every push command with --dry-run first!!

Currently it's best to do this on the command line, because push -u sets up the tracking branch properly. Make sure you use the same name! Use --dry-run first.

$ <go to the local copy of the repo ("$ cd $HOME/git/freeplane")>
$ git push -u origin <devbranch> [--dry-run]

You should see a message like:

Branch user/dev1 set up to track remote branch user/dev1 from origin.

(When pushing from eclipse you have to configure the remote tracking branch manually!). In any case (tracking branch configured automatically or manually), Team->Push to Upstream will push the current branch to its (configured) remote branch on origin.

Step 5: Development cycles

Follow the cycle: Switch to the right branch (may not be necessary)

$ git checkout <devbranch> # **Team->Switch To->user/dev1** from EGit 

pull other people's changes on your devbranch (as a beginner you might want to do this on a copy of your repository first, it's all local!)

$ git pull # **Team->Pull** from EGit

(People recommend to use git fetch and git merge instead of git pull)

you might have to resolve conflicts: (might want to use 'git mergetool' or Eclipse/EGit ) git will place <<<<<<<<<< and >>>>>>>>>> comments to show the locations of the conflict(s)

for each conflict x:

  • resolve conflict in x, remove markers
  • git add x # mark x as resolved

to undo the merge you can use

$ git reset --hard # **Team->Reset...** in EGit

but this will throw away all uncommitted changes(!)

  • commit the conflict resolution(s):
$ git commit [-m message] # **Team->Commit** in EGit
  • create local commits (see "Step 3")
  • merge changes from master (to integrate the latest code into your feature and to make Step 6 easier)
$ git pull origin master
  • merge changes from master with EGit:
    • Team->Fetch from Upstream
    • Team->Merge..., select origin/master
  • push the result of the merge with master to your remote dev branch (always run git push with --dry-run first!)
$ git push [--dry-run] # EGit: **Team->Push to Upstream**
# (same as **git push origin <devbranch>** because tracking is set up)

Step 6: Merge your development into master

When you are done with your branch, and you have completed a code review of your dev branch, it should be merged into master (!) As a new developer, you must let a more experienced developer do this!

$ git checkout <devbranch> # Switch to <devbranch> in EGit
$ git pull # **Team->Pull** in EGit
$ git checkout master # Switch to **master** in EGit
$ git pull # **Team->Pull** in EGit
$ git merge <devbranch> # EGit: **Team->Merge...**, select **local** <devbranch>
$ git push [--dry-run] # EGit: **Team->Push to Upstream**
# (same as **git push origin master** because tracking is set up)

How to's

This section contains useful information for working with git, including stuff like checking that tracking branches are set up correctly, details about working with branches, undoing commits/reverting files, and a bit more.

Checkout in more detail

Checking out is termed cloning in git speak:

$ cd ~
$ mkdir git
$ cd git
$ git clone https://github.com/freeplane/freeplane.git freeplane

If you want/have read-only access, use this as the last command:

$ git clone git://github.com/freeplane/freeplane.git freeplane

However, this will only configure the master branch (named trunk in other VCS's such as svn) locally:

$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/docear/trunk
remotes/origin/master

In order to check out a branch (which is simply a reference to a commit) that currently only exists remotely (the remotes/origin/* references are called remote tracking branches), simply switch to that branch:

$ git checkout docear/trunk

This can be done more easily using Eclipse. This page also describes how to import a repository into eclipse.

Using Tags

Show all tags:

$ git tag

Search for a tag:

$ git tag -l "release-1.1*"

Show information about a tag:

$ git show release-1.1.2

Define a tag locally:

$ git tag -a <tagname>
# (an editor opens for you to add a description)

Tags are not automatically transferred when doing a git push, you have to push individually:

$ git push origin <tagname>

or push all tags:

$ git push --tags origin

You might need a

$ git pull --tags

to get all tags. See git-fetch(1) for situations when you will need this (rarely).

TODO: sign tags?

Working with branches

Branches are very central to git. Do not hesitate to create feature, team and (of course) maintenance branches.

You probably want set push.default to tracking or upstream which makes sure that only the current branch is pushed to its upstream branch (and NOT all configured branches): Note: this option is ignored by current EGit. On EGit you get the same behavior by selecting Team->Push To Upstream.

$ git config push.default tracking

(you can equivalently set this to upstream in recent git versions).

Switch to another branch

$ git checkout <branchname>

(Team->Switch To->... in Eclipse)

How to create a new branch

New (feature) branches should be named / or (if several devs work on a feature): .

# commit everything that should go into the new branch
$ git status
$ git add <file>
[...]
$ git commit -m "my changes"

# create new branch locally
$ git checkout -b <newbranch>

# check commit log to see that above commit is in there
$ git log

# new branch must be visible and selected:
$ git branch -a  

# (make sure that the name of the new branch is correct! it is diffcult/impossible
#  to rename published branches!)

# create branch remotely, use -u to automatically configure upstream location
$ git push -u origin <newbranch>
# this should output something like this:
**Branch <newbranch> set up to track remote branch <newbranch> from origin.**
# (**'Note**': -u is important if you want to use git pull/push without
specifying a remote/refspec)

# remote branch of <newbranch> must be visible:
$ git branch -a

So the short story is:

$ git checkout -b <newbranch>
$ git push -u origin <newbranch>

Rename a local branch

$ git branch -m <old-branch-name> <new-branch-name>

TODO: how to rename the remote tracking branch => difficult!!

How to merge local branches

$ git checkout <destination_branch>
$ git merge <source_branch>

If you want to abort a merge (revert the working directory to the state before the merge command), do this:

$ git reset --hard

(WARNING: this will remove all uncommitted changes!!)

In eclipse, this can be achieved by:

  • Team->Switch To and choose <destination_branch>
  • Team->Merge... and choose <source_branch>

In Eclipse, you may have to refresh all projects (F5) if a branch has been added/modified/deleted via the command line.

Fast-Forward Merges (merge-nodes)

Often the creation of a merge commit (merge node) is not necessary, and git merge uses a fast-forward merge, omitting the merge node:

$ git merge foo
Updating 9e9a63a..732b657
Fast-forward
testfoo.txt |    1 +
1 file changed, 1 insertion(+)
create mode 100644 testfoo.txt

results in:

* 732b657 commit in branch foo
* [...]

Using the option --no-ff you can force git to create a merge node even if isn't absolutely necessary (non-fast-forward merge):

$ git merge --no-ff foo2
Merge made by the 'recursive' strategy.
testfoo2.txt |    1 +
1 file changed, 1 insertion(+)
create mode 100644 testfoo2.txt

which will result in:

*   3890bc8 (HEAD, master) Merge branch 'foo2'
|\  
| * 6bc24c5 (foo2) commit on foo2
|/  
* 
* [...]

This is useful when merging feature branches because it clearly shows the integration of a new feature. On the other hand, many merge nodes make the commit graph less readable.

Merge master->dev-branch locally

$ git checkout <devbranch>
$ git merge master

Merge dev-branch->master locally

$ git checkout master
$ git merge <devbranch>

How to remove a branch

# remove branch locally
# (use -D instead if you want to delete a branch that is not fully merged into HEAD!)
$ git branch -d <branchname>

You can do this with EGit using Team->Advanced->Delete Branch....

If you accidentally deleted a (local) branch, you can recover it by starting a new branch from the location that git branch -d echoed (or by searching for the last commit on that branch in git reflog):

$ git branch -D foo
Deleted branch foo (was 732b657).
$ git branch foo 732b657

(remember that branches are simply pointers to commits)

Warning: this only works if the delete was quite recent as orphaned commits will be deleted after some time!

Delete a remote branch(!):

$ git push origin --delete <branchname>

Now the local and the remote tracking branch should be gone:

$ git branch -a
docear/trunk
* master
remotes/origin/docear/trunk
remotes/origin/master

NOTE: The stale branch will still exist in other checkouts, until you do a:

$ git remote prune origin

in that other checkout. TODO: but it still exists there as a local branch!

Check whether your branches are set up correctly

Make sure your branches are set up correctly for push/pull:

$ git remote show origin
* remote origin
Fetch URL: https://github.com/freeplane/freeplane.git
Push  URL: https://github.com/freeplane/freeplane.git
HEAD branch: master
Remote branches:
docear/trunk tracked
master       tracked
Local branches configured for 'git pull':
docear/trunk merges with remote docear/trunk
master       merges with remote master
Local refs configured for 'git push':
docear/trunk pushes to docear/trunk (up to date)
master       pushes to master       (up to date)

Importing a remote branch

Using command line git:

$ git pull # fetches the remote (tracking) branch
$ git checkout <branchname>

Using Eclipse/EGit:

  • Team->Pull fetches the remote (tracking) branch
  • Team->Switch To->New branch..., select Source ref = refs/remotes/origin/

General workflow

Create a dev branch (see section on creating branches above).

Work on your feature branch

# switch to feature branch
$ git checkout <feature>

# fetch and merge changes (in case another dev works on this)
$ git pull

# you might have to resolve conflicts: (might want to use 'git mergetool'
# or [http://wiki.eclipse.org/EGit/User_Guide#Resolving_a_merge_conflict Eclipse/EGit])
for each conflict x:
1. resolve conflict in x, remove markers
2. git add x # mark as resolved
# commit the conflict resolution(s)
$ git commit

$ git add ...
$ git commit
[...]

# This will push commits to the remote branch that is tracked
# make sure that push.default=tracking|upstream (see above),
# otherwise other branches will be pushed as well!
$ git push [--dry-run]

Merging

Merge master -> (see section on merging above) every once-in-a-while.

After a final code review (on your dev branch), merge -> master (see section on merging above).

Miscellaneous

Revert (reset) files

git checkout <filename>

In EGit do this: Right-click on file -> Replace With -> HEAD Revision

Revert all files in working copy (!):

git reset --hard

Undoing/editing commits

TODO: how to remove/edit a commit locally using rebase.

Undoing a commit that is already pushed

Use git revert , like this:

$ git revert b1e9b4c9755b091f95aaa3035aca04dcb02ec1fd

This will generate an inverse commit, it will not remove the original commit:

* 171881e (HEAD, master) Revert "a simple commit"
* b1e9b4c a simple commit

Avoid entering passwords on each commit

At least if you use the command line git interface you should consider to deposit your public ssh key at github. See the section about ssh configuration on github.

Requirements

  • You need java 11 or later and gradle >= 6.0

Download gradle

  • Download gradle: https://gradle.org/releases/
  • Unzip to your home directory

Clone the freeplane repository

git clone https://github.com/freeplane/freeplane.git
cd freeplane

Run gradle

  • Gradle wrapper files are intentionally not committed to the sources but git ignored so that you can add them yourself if you need them. $ ~/Downloads/gradle-6.0.1/bin/gradle build

Run freeplane

cd BIN
./freeplane.sh # linux
freeplane.bat

Create package

~/git2/freeplane(1.7.x u=)$ ~/Downloads/gradle-6.0.1/bin/gradle clean build dist
ls DIST

Configuring an IDE

Prerequisites

Freeplane's build system is based on GRADLE. So gradle can support concerning development processing and generation of configuration files.

Freeplane can be developed in basically any IDE (integrated development environment) like Eclipse, IntelliJ and Netbeans. These IDEs provide the UI (user interface) for the whole development process, including the support for code edit, search, debugging, testing,... At the same time, no developer is forced to use any of these IDEs, but can also use e.g. vim, as gradle is able to provides fitting configurations for any environment. If you use a proper IDE, configuration and manifest files are needed e.g. for debugging. They are created when executing gradle with the build parameter set.

If you executed gradle builds for previous Freeplane versions, you should manually delete all MANIFEST.MF files which were generated by build scripts, they are not needed any more.

IDE: Eclipse

Eclipse can directly import Gradle files using the buildship plugin. Please see the setup for scripting, with the difference that you can use your freeplane local repository directory in stead of the freeplane_root source directory. There is no need to use the Gradle cleanEclipse eclipse tasks that are explained in the next paragraph. If you do, it will remove the Gradle nature from the imported Freeplane projects.

Alternatively, if you want to configure Eclipse manually, all necessary eclipse project files can be generated by gradle using the eclipse parameter together with the gradle command. In effect, you should start a full and clean build using the following command:

gradle clean build cleanEclipse eclipse

This also creates an executable Freeplane application within the BIN folder below the current folder.

Now, you should start your Eclipse IDE and let it point to the base project folder (the folder where you just executed gradle). Up and running, you would now import the Freeplane project from the Eclipse top menu and choose ALL Freeplane project options from the import list. Now, please drop the '''freeplane_mac''' project when you don't work on a Mac. Otherwise it would cause you problems.

If you want to build and launch Freeplane for the first time in your newly configured IDE, you should look for the location of the launch configurations within Freeplane's source tree on the left side of the Eclipse window:

freeplane_debughelper / eclipse / freeplane.launch

would be the most useful one. But there are others like freeplane_debughelper/eclipse/freeplane dist.launch and freeplane_debughelper/eclipse/freeplane dist mac.launch, which are used to launch binary distributions created by gradle build.

As soon as you have once launched Freeplane as described, you will find appropriate menu items within the icons menu (RUN as well as DEBUG), from where you now can launch Freeplane for RUN or DEBUGGING purposes.

IDE: IntelliJ

This page has the instructions that may be the easiest, currently: Setting_IDE_for_debugging

Otherwise, you can try those steps:

The short story:
IntelliJ can directly import gradle files. After the import the directory freeplane_debughelper/idea/runConfigurations containing run configuration files should be copied into directory .idea created by IntelliJ in project root. Restart IntelliJ afterwards.

Detailed instructions:

Download and install IntelliJ Community Edition

  • https://www.jetbrains.com/idea/download

  • Extract in some directory

  • Run .../idea-IC-VERSION/bin/idea.sh (or similar on non-GNU platforms)

    • Do not import settings
    • Choose (any) UI theme
    • (optionally) Create desktop entry
    • (optionally) Create launcher script
    • Choose default plugins (you can disable some, like Android)
    • Do not download featured plugins
    • Click Start using IntelliJ IDEA

Open the freeplane checkout (IntelliJ 2021)

  • Click Open (when starting IntelliJ)
  • Point to the build.gradle in the checkout and click OK, then Open as Project
  • Trust project
  • change the project:
    • Enable Build with IntelliJ
    • You will get an error due to a proected package sun.awtshell ->
      File->Settings->Build->Compiler->Java Compiler->[ ] use Release
  • execute a toplevel gradle build for the command line (this is necessary for generating lexers etc.)
  • copy freeplane_debughelper/idea/runConfigurations (the whole runConfigurations directory!) containing run configuration files into .idea created by IntelliJ in project root
  • Restart IntelliJ afterwards.

Import the Freeplane build system (IntelliJ <= 2020)

  • Click Import Project (when starting IntelliJ)
  • Point to the settings.gradle in your checkout and click OK
    • Choose settings like these:
    • Make sure to use an unzipped gradle binary distribution (~/Downloads/gradle-5.1.1 in this case); a gradle linux distribution package did not work for me, not even with this information
  • Click OK and wait
  • copy freeplane_debughelper/idea/runConfigurations (the whole runConfigurations directory!) containing run configuration files into .idea created by IntelliJ in project root
  • Restart IntelliJ afterwards.

Start developing Freeplane

  • In order to run, choose Run->Run...->freeplane
    • If the field "Use classpath for module" is empty, put freeplane_root.freeplane_debughelper.main in there
  • In order to debug, choose Run->Debug...->freeplane

IDE: Netbeans

Netbeans can directly import gradle files using its Gradle support plug-in. Gradle tasks needed for running and debugging from the IDE are defined in freeplane_debughelper/build.gradle

Create a new Plugin

With the introduction of the gradle build system (Freeplane >= 1.4.1), the "create-plugin" ant task is deprecated because adding plugins "manually" has become very simple using gradle.

Steps

Here are the steps you need to perform:

  • choose a short name for your plugin (e.g. freeplane_plugin_foo, the name freeplane_plugin_* is mandatory)
  • include the plugin in settings.gradle
  • create freeplane_plugin_foo/build.gradle by copying the build.gradle from any other plugin (freeplane_plugin_latex freeplane_plugin_openmaps are quite simple)
  • add third-party dependencies (dependencies section) and OSGi imports (packages you need from core/other plugins) to your build.gradle
    • if your third-party dependencies are not available in maven.org, uses files() and commit them to version control (freeplane_plugin_foo/lib)
  • create freeplane_plugin_foo/src/main/java/org/freeplane/plugin/foo/Activator.java by copying from another plugin and then removing things you don't need
  • TODO: need to adapt eclipse launcher?
  • test your plugin by building and running freeplane
  • when committing, make sure not to commit .project / .classpath files as they are generated by gradle

Add options to the OptionPanel

The core plugins register their options via the configuration file freeplane/resources/xml/preferences.xml. Plugins can do it quite similar by defining their own preferences.xml (by convention in freeplane_plugin_/org/freeplane/plugin//preferences.xml); here from the script plugin (the latex plugin is also a good example):

<?xml version="1.0" encoding="UTF-8"?>
<preferences_structure>
   <tabbed_pane>
      <tab name="plugins">
         <separator name="scripting">
            <boolean name="execute_scripts_without_asking" />
            <boolean name="execute_scripts_without_file_restriction" />
            <boolean name="execute_scripts_without_network_restriction" />
            <boolean name="execute_scripts_without_exec_restriction" />
            <boolean name="signed_script_are_trusted" />
            <string name="script_user_key_name_for_signing" />
            <string name="script_directories" />
         </separator>
      </tab>
   </tabbed_pane>
</preferences_structure>

The option names have to be added to Resource_en.properties (excerpt):

OptionPanel.execute_scripts_without_asking = Scripts should be carried out without confirmation?
OptionPanel.execute_scripts_without_asking.tooltip = <html>Freeplane scripts are principally able...
OptionPanel.execute_scripts_without_exec_restriction = Permit to Execute other Applications (NOT recommended)

For an example of how options can be registered at the option panel see org.freeplane.plugin.script.ScriptingRegistration:

private void addPropertiesToOptionPanel() {
    final URL preferences = this.getClass().getResource("preferences.xml");
    if (preferences == null)
        throw new RuntimeException("cannot open preferences");
    modeController.getOptionPanelBuilder().load(preferences);
}

The options can be queried like this:

String executeWithoutAsking = ResourceController.getResourceController()
    .getProperty("execute_scripts_without_asking");

Register Actions

Please see OpenMapsRegistration.java in the freeplane_plugin_openmaps plugin.

Register Icon Mouse click listener

Please see OpenMapsRegistration.java in the freeplane_plugin_openmaps plugin.

Running export

This xslt exports are available together with all other exports through menu File -> Export...

The Export Using XSLT function applies an XSL Transformation to the Freeplane mindmap, to create a new file.

In the Freeplane Export using XSLT dialog box, the Files of type combo is populated with the list of supplied or user defined XSL files.

The files contained in the freeplane installation are located under freeplane installation directory in subdirectory resources/xslt.

Creating own XSLT transformations

You can define your own export as xslt table where you can implement all transformations. For instance you can generate your own xhtml and also attribute html elements with class attributes for css styling. XSL files must be stored in the xslt subfolder, either in the Freeplane system directory (e.g. C:\Program Files\Freeplane\resources\xslt) or in the Freeplane user directory (e.g. ~/.freeplane/xslt/).

XSL files must have the .xsl extension.

XSL files must contain within the 5 first lines a string matching the following pattern:

MINDMAPEXPORTFILTER extensions description

where the fields in italic are relative to the file format to which the mindmap will be exported to using this specific XSLT sheet:

  • extensions is a semi-colon separated list of acceptable file extensions without asterisk or dot (e.g. "htm;html")
  • description is a description of the file format (e.g. "Meeting Minutes in HTML")

Only the first unique combination of extensions and description will be kept, in such a way that users can "overwrite" an already existing XSLT sheet with their own version.

Viewing XML input for XSLT export transformation

The input xml for xslt transformations is different from the content of mm file. There is a special export sheet "Export raw xml with node formatting". XML produced by this sheet is the exact copy of the XML fed into xslt transformations.

The old wiki content is also available at the old MediaWiki site

Index wiki
IndexWiki.mm

You can navigate this wiki in different ways. The navigation menu on the left directs you to main support areas. Pages on detailed topics can be found in the mind map Index wiki on the right. Many pages of this wiki are tagged at the end of the page with Categories. You can click on the Category at the end of the page to display an index of all pages of the same Category.

You are invited to use and contribute to this wiki, to share information and tips about Freeplane and its features. NOTE: because of spammer attacks, editing of this wiki is now only allowed for registered wiki editors. If you want to become a wiki editor, write to the Freeplane team which user name and e-mail you want to use for the registration. So we can create a new user account and let the wiki generate password and send it to the mail address you provide.

We use forum https://www.freeplane.org/forum for discussions and issue tracker https://www.freeplane.org/tickets for bug reports and feature requests. The old forum content is available read only at https://www.freeplane.org/forum2012 .

Read more...

Free mind mapping and knowledge management software

Download Freeplane

Download Freeplane now!
(this downloads the stable version 1.10.2)
change log   •  fixed security issues
Download last development versions (preview )
Try it and give your opinion.

Freeplane is a free mind mapping program under the GNU General Public License (GPL) version 2 or later.
See Support for installation instructions, language support and special buttons and keys for Macintosh.

Freeplane is the Community Choice Source Forge Project of the Month for June 2014 and for November 2016 and the Staff Choice for July 2014 and December 2020.

What it is

What is mind mapping
WhatIsMindMapping.mm

Freeplane is a free and open source software application that supports thinking, sharing information and getting things done at work, in school and at home. The software can be used for mind mapping and analyzing the information contained in mind maps. Freeplane runs on any operating system that has a current version of Java installed. It can be run locally or portably from removable storage like a USB drive.

Freeplane basics

Application areas

Application areas
freeplaneApplications.mm

Freeplane supports much more than classic static mind mapping. This is illustrated by the mind map Application areas on the right, which summarizes the kind of tasks supported by Freeplane. Click on the hyperlink below the image to navigate the map. Read the node called Caption to learn how to navigate the map and unhide hidden information. Click the node Demonstration creating a map to see how easy it is to make a map.

In the center of the map, Application areas you see the central topic (root node) of the map. Extending from it are branches with subtopics (child nodes). At the border you see free topics (free nodes) which are independent of the root-tree. All topics can be formatted or styled and can contain text, hyperlinks, pictures and more; and can be connected with labelled lines or arrows. Also a topic (node) can represent hidden information which displays when the user wants it or can be automatically executed (formula). Content can also be password protected or connected to a particular time or filter.

Functions

Freeplane functions
freeplaneFunctions.mm

Freeplane supports the above application areas with the following functions:

  • Note taking with freely positionable, unconnected nodes (like post-it’s);
  • Ordering ideas (nodes) into a hierarchy connected by lines (edges);
  • Classifying nodes with metadata (attributes) and style types (system styles, user defined styles, level styles);
  • Grouping nodes with visual containers (clouds) and accolade (summary node);
  • Connecting nodes with dynamic links, free lines (connectors) and labels;
  • Automatically styling nodes (with a bubble, color, edge type, etc.) according to hierarchical level and content (conditional styles, automatic edge color, level styles);
  • Structuring nodes in terms of content (text, scientific formula, calculation, icon, image and hyperlink) and presentation area (core, details, notes, attributes, images and tooltip);
  • Changing views by hiding content (folding branches, filtering, roll-up of details and hiding extensions in tooltip), finding, scrolling and navigating;
  • Tasking with calendar and reminders;
  • Password protecting of whole map and of individual nodes with DES encryption;
  • Ease of use with inline- and dialog editors, object oriented main menu, context menu’s, multi-language support, spell checker, properties panel, drag& drop functionality, hot keys, options for batch execution, publishing, sharing and selectable preferences;
  • Approximate Search (similarity search) which allows to find search terms in a text, even if there is no exact match (e.g. "setup" = "set up" or "flie" = "file").
  • Support for LaTeX formulae underneath/in nodes
  • Easy extension of functionality with add-ons and home made scripts;
  • Integration with Docear academic literature suite;
  • Extensive support through Wiki and Forum; and tutorial and documentation in the form of a mind map.

The map called Freeplane functions illustrates the main functions of Freeplane. Besides it provides an index with hyperlinks to the tutorial an documentation where you can read more. The links are hidden at first, but become visible and can be clicked if you hover with the cursor over a function (node). This is another example of the power of Freeplane. (To experience these functions, open Help > Getting Started in the Freeplane program and select Index).

Add-ons and Scripts

It is possible to extend the functionality of Freeplane using Add-ons and scripts. You can make your own add-ons and scripts using the built in scripting language Groovy (based on JavaScript), and beginning with version 1.5 other languages, like python. Check page Add-ons_(install) for add-ons other users have made and shared. They can be downloaded and installed with a simple mouse click. Instructions are available if you want to make your own add-ons.

Presenting mind maps

Once you have a mind map you may want to use and present it. RoAn-Presentation provides a combination of mind mapping with Powerpoint- and Prezi like presentation, using automatic filtering and zooming. Stepping the presentation not only unfolds nodes, but also displays hidden details, centers the current node and more. In short it supports traversing a mind map, taking over abundant clicking from the user. You may download and install addon RoAn-presentation here.

Why you want it

Why Freeplane
WhyFreeplane.mm

Freeplane aims for maximum ease and speed of use. Occupying the middle ground between an editor and a diagramming tool, Freeplane allows the user to add content as quickly and naturally as they would in a text editor, yet producing structured content that can be manipulated as easily as a diagram. The workflow is unimpeded by the need to think about and manually place each piece of information; the user can intuitively input content as paragraphs and headings, and easily reorganise at a later stage. The width and other aspect of each topic (node) can be set independently and a node can be defined to behave indepently from the nodes in the tree structure, to be free positionable. The use of adaptable styles makes formatting an easy job and conditional styles make it automatic. A growing set of node extensions provide for details, metadata, scalable images, in-line hyperlinks and more which can be independently controlled to be visible or not. Freeplane maps can be easily integrated with Internet pages as in this wiki. And Freeplane is integrated with the Docear academic literature suite. Although Freeplane functionality is intended for non-programmers, the Freeplane project offers potential programmers a versatile [scripting](../scripting/Scripts_collection .md) language. Programmers may easily develop powerful extensions and students are stimulated to learn programming in a natural and stimulating environment. Freeplane also has a powerful mechanism to install packages of scripts, icons, images, language dictionaries for spell checking and other preferences including a different menu structure; and which can be used by non-programmers.

Freeplane was created because of short-comings in the design of the popular open source mind mapping program Freemind. Freeplane has been refactored from Freemind to make its code and packages more modular, make it easier for new software developers to contribute to Freeplane development, and to release new versions of Freeplane more often.

FreeMind users can have a look at the list of the most helpful features missed in FreeMind and available in Freeplane.

Documentation

Tutorial
freeplaneTutorial.mm

The versatility of Freeplane is demonstrated by the fact that the main user documentation is contained in mind maps. The mind map on the right shows the basic Tutorial for using Freeplane. The actual version of this map is contained in the Freeplane program in menu Help > Tutorial. This wiki contains a page Freeplane_Tutorial_Extensions with use cases which can be navigated or can be downloaded and extended. For some of the examples there are animations illustrating the making of the map. See Translated wiki pages if the page Freeplane Tutorial Extensions has been translated into your language. The advanced user is helped with detailed documentation in Freeplane'sHelp > Documentation and by many specific wiki pages explaining things like Scripting, Formulas and Add-ons. The mind map galleries provide a place for sharing mind maps in several languages. Online help is available at the open Forum, see below. It is possible to create a high quality animation or video of using Freeplane, see how to.

Freeplane books

  • German: "Freeplane 1.3 kompakt" by Holger Reibold, ISBN: 978-3-95444-177-4.

Community

community structure

Freeplane is a non-commercial project. It lives by our active and vibrant community, where we try to support each other in order to develop and provide an outstanding knowledge management application. Please, feel free to discuss Freeplane and its features with other interested Freeplane users. For this purpose, we provided two forums (see structure picture on the right):

We invite you to do the following things:

in our OPEN DISCUSSION FORUM

  • discuss the usage of existing features
  • discuss the suitability of new features
  • discuss the development of [existing scripts](../scripting/Scripts_collection .md) and new ones

New bug reports go into the bug reports

New feature requests go into the feature requests

Freeplane's old user forums are archived here and here.

News about new features coming in future releases of Freeplane can be found on our preview page.

To understand the Freeplane document structure (XML) and get it's XSD schema go to: Document Format

To understand the the project goal, see the Freeplane vision.

Join the Freeplane team not only as user but maybe as a

  • developer (coder and designer)
  • tester (writer of tutorials, screencasts and help texts)
  • translator (various languages)
  • forum moderator (care for a specific subject)

Artwork

Artwork for Freeplane since version 1.3 is created by Robert Gibson

Thanks

Freeplane team uses:

The old wiki content is also available at the old MediaWiki site

Index wiki
IndexWiki.mm

You can navigate this wiki in different ways. The navigation menu on the left directs you to main support areas. Pages on detailed topics can be found in the mind map Index wiki on the right. Many pages of this wiki are tagged at the end of the page with Categories. You can click on the Category at the end of the page to display an index of all pages of the same Category.

You are invited to use and contribute to this wiki, to share information and tips about Freeplane and its features. NOTE: because of spammer attacks, editing of this wiki is now only allowed for registered wiki editors. If you want to become a wiki editor, write to the Freeplane team which user name and e-mail you want to use for the registration. So we can create a new user account and let the wiki generate password and send it to the mail address you provide.

We use forum https://www.freeplane.org/forum for discussions and issue tracker https://www.freeplane.org/tickets for bug reports and feature requests. The old forum content is available read only at https://www.freeplane.org/forum2012 .

Read more...

Free mind mapping and knowledge management software

Download Freeplane

Download Freeplane now!
(this downloads the stable version 1.10.2)
change log   •  fixed security issues
Download last development versions (preview )
Try it and give your opinion.

Freeplane is a free mind mapping program under the GNU General Public License (GPL) version 2 or later.
See Support for installation instructions, language support and special buttons and keys for Macintosh.

Freeplane is the Community Choice Source Forge Project of the Month for June 2014 and for November 2016 and the Staff Choice for July 2014 and December 2020.

What it is

What is mind mapping
WhatIsMindMapping.mm

Freeplane is a free and open source software application that supports thinking, sharing information and getting things done at work, in school and at home. The software can be used for mind mapping and analyzing the information contained in mind maps. Freeplane runs on any operating system that has a current version of Java installed. It can be run locally or portably from removable storage like a USB drive.

Freeplane basics

Application areas

Application areas
freeplaneApplications.mm

Freeplane supports much more than classic static mind mapping. This is illustrated by the mind map Application areas on the right, which summarizes the kind of tasks supported by Freeplane. Click on the hyperlink below the image to navigate the map. Read the node called Caption to learn how to navigate the map and unhide hidden information. Click the node Demonstration creating a map to see how easy it is to make a map.

In the center of the map, Application areas you see the central topic (root node) of the map. Extending from it are branches with subtopics (child nodes). At the border you see free topics (free nodes) which are independent of the root-tree. All topics can be formatted or styled and can contain text, hyperlinks, pictures and more; and can be connected with labelled lines or arrows. Also a topic (node) can represent hidden information which displays when the user wants it or can be automatically executed (formula). Content can also be password protected or connected to a particular time or filter.

Functions

Freeplane functions
freeplaneFunctions.mm

Freeplane supports the above application areas with the following functions:

  • Note taking with freely positionable, unconnected nodes (like post-it’s);
  • Ordering ideas (nodes) into a hierarchy connected by lines (edges);
  • Classifying nodes with metadata (attributes) and style types (system styles, user defined styles, level styles);
  • Grouping nodes with visual containers (clouds) and accolade (summary node);
  • Connecting nodes with dynamic links, free lines (connectors) and labels;
  • Automatically styling nodes (with a bubble, color, edge type, etc.) according to hierarchical level and content (conditional styles, automatic edge color, level styles);
  • Structuring nodes in terms of content (text, scientific formula, calculation, icon, image and hyperlink) and presentation area (core, details, notes, attributes, images and tooltip);
  • Changing views by hiding content (folding branches, filtering, roll-up of details and hiding extensions in tooltip), finding, scrolling and navigating;
  • Tasking with calendar and reminders;
  • Password protecting of whole map and of individual nodes with DES encryption;
  • Ease of use with inline- and dialog editors, object oriented main menu, context menu’s, multi-language support, spell checker, properties panel, drag& drop functionality, hot keys, options for batch execution, publishing, sharing and selectable preferences;
  • Approximate Search (similarity search) which allows to find search terms in a text, even if there is no exact match (e.g. "setup" = "set up" or "flie" = "file").
  • Support for LaTeX formulae underneath/in nodes
  • Easy extension of functionality with add-ons and home made scripts;
  • Integration with Docear academic literature suite;
  • Extensive support through Wiki and Forum; and tutorial and documentation in the form of a mind map.

The map called Freeplane functions illustrates the main functions of Freeplane. Besides it provides an index with hyperlinks to the tutorial an documentation where you can read more. The links are hidden at first, but become visible and can be clicked if you hover with the cursor over a function (node). This is another example of the power of Freeplane. (To experience these functions, open Help > Getting Started in the Freeplane program and select Index).

Add-ons and Scripts

It is possible to extend the functionality of Freeplane using Add-ons and scripts. You can make your own add-ons and scripts using the built in scripting language Groovy (based on JavaScript), and beginning with version 1.5 other languages, like python. Check page Add-ons_(install) for add-ons other users have made and shared. They can be downloaded and installed with a simple mouse click. Instructions are available if you want to make your own add-ons.

Presenting mind maps

Once you have a mind map you may want to use and present it. RoAn-Presentation provides a combination of mind mapping with Powerpoint- and Prezi like presentation, using automatic filtering and zooming. Stepping the presentation not only unfolds nodes, but also displays hidden details, centers the current node and more. In short it supports traversing a mind map, taking over abundant clicking from the user. You may download and install addon RoAn-presentation here.

Why you want it

Why Freeplane
WhyFreeplane.mm

Freeplane aims for maximum ease and speed of use. Occupying the middle ground between an editor and a diagramming tool, Freeplane allows the user to add content as quickly and naturally as they would in a text editor, yet producing structured content that can be manipulated as easily as a diagram. The workflow is unimpeded by the need to think about and manually place each piece of information; the user can intuitively input content as paragraphs and headings, and easily reorganise at a later stage. The width and other aspect of each topic (node) can be set independently and a node can be defined to behave indepently from the nodes in the tree structure, to be free positionable. The use of adaptable styles makes formatting an easy job and conditional styles make it automatic. A growing set of node extensions provide for details, metadata, scalable images, in-line hyperlinks and more which can be independently controlled to be visible or not. Freeplane maps can be easily integrated with Internet pages as in this wiki. And Freeplane is integrated with the Docear academic literature suite. Although Freeplane functionality is intended for non-programmers, the Freeplane project offers potential programmers a versatile [scripting](../scripting/Scripts_collection .md) language. Programmers may easily develop powerful extensions and students are stimulated to learn programming in a natural and stimulating environment. Freeplane also has a powerful mechanism to install packages of scripts, icons, images, language dictionaries for spell checking and other preferences including a different menu structure; and which can be used by non-programmers.

Freeplane was created because of short-comings in the design of the popular open source mind mapping program Freemind. Freeplane has been refactored from Freemind to make its code and packages more modular, make it easier for new software developers to contribute to Freeplane development, and to release new versions of Freeplane more often.

FreeMind users can have a look at the list of the most helpful features missed in FreeMind and available in Freeplane.

Documentation

Tutorial
freeplaneTutorial.mm

The versatility of Freeplane is demonstrated by the fact that the main user documentation is contained in mind maps. The mind map on the right shows the basic Tutorial for using Freeplane. The actual version of this map is contained in the Freeplane program in menu Help > Tutorial. This wiki contains a page Freeplane_Tutorial_Extensions with use cases which can be navigated or can be downloaded and extended. For some of the examples there are animations illustrating the making of the map. See Translated wiki pages if the page Freeplane Tutorial Extensions has been translated into your language. The advanced user is helped with detailed documentation in Freeplane'sHelp > Documentation and by many specific wiki pages explaining things like Scripting, Formulas and Add-ons. The mind map galleries provide a place for sharing mind maps in several languages. Online help is available at the open Forum, see below. It is possible to create a high quality animation or video of using Freeplane, see how to.

Freeplane books

  • German: "Freeplane 1.3 kompakt" by Holger Reibold, ISBN: 978-3-95444-177-4.

Community

community structure

Freeplane is a non-commercial project. It lives by our active and vibrant community, where we try to support each other in order to develop and provide an outstanding knowledge management application. Please, feel free to discuss Freeplane and its features with other interested Freeplane users. For this purpose, we provided two forums (see structure picture on the right):

We invite you to do the following things:

in our OPEN DISCUSSION FORUM

  • discuss the usage of existing features
  • discuss the suitability of new features
  • discuss the development of [existing scripts](../scripting/Scripts_collection .md) and new ones

New bug reports go into the bug reports

New feature requests go into the feature requests

Freeplane's old user forums are archived here and here.

News about new features coming in future releases of Freeplane can be found on our preview page.

To understand the Freeplane document structure (XML) and get it's XSD schema go to: Document Format

To understand the the project goal, see the Freeplane vision.

Join the Freeplane team not only as user but maybe as a

  • developer (coder and designer)
  • tester (writer of tutorials, screencasts and help texts)
  • translator (various languages)
  • forum moderator (care for a specific subject)

Artwork

Artwork for Freeplane since version 1.3 is created by Robert Gibson

Thanks

Freeplane team uses:

Approximate Search in Freeplane

Starting with 1.2.13, Freeplane includes an 'Approximate Search' feature which allows to find content (nodes, notes, or whatever) that do not exactly match the search term, but allow some changes ("distance") between the search term and the content. See the section Search results below for some examples of approximate searching.

Press Ctrl-F or select View->Toolbars->Filter toolbar to show the "filter/search" toolbar and enable Approximate searching by enabling the "Approximate" checkbox in the filter toolbar (Alt+A). Then you can enter a search term in the search box (to the left of Match Case) and press Enter or click the Find next Button (icon with a blue right arrow in the filter toolbar) to start the search. If you want to check for equality (search term equals content as opposed to is contained in content), then you should change the default "Contains" in the search type combobox to "Is equal to". You can define more complex search rules by using the Filter->Compose filter dialog.

How to find (approximate) occurrences of the search term

This section only applies to freeplane >= 1.2.15.x. In order to search within the content (node text, note, ...), you need to start the Rich Text Editor (e.g. Alt+Enter for node content), click the Find&Replace icon or hit Ctrl+F which opens the Find & Replace Dialog. In the options panel at the bottom you will find Match case and Match approximately that correspond to the options in freeplane's filter toolbar. Enter the search term, select approximate matching and click Find next... to highlight the search occurrences incrementally.

Search results

Once you activate Approximate matching, all matching using the filter tool is done approximately, i.e.

  • you can search for "file" and it will find "flie" (typo)
  • you can search for "hobbies" and it will find "hobbys"
  • "setup" = "set up"
  • if you use Freeplane for program source code: you can search for "NumberFormat" and it will find "aNumber_Format"
  • "Bismark" = "Bismarck"
  • "188x" = "1886"
  • ...

Of course there are also limitations for this search feature! A search is considered a match depending on the edit distance between the search term and the content (see Threshold section below). That means that you get False Positives (i.e. "print"="pointer" for a 'Contains' match etc.) and False Negatives (i.e. "fitness center"!="fitness studio" or for an equality match: "RandomFileAccess"!="RandomAccessFolder", etc.).

The threshold

Matching is done based on edit distance (Damerau-Levenshtein algorithm, the popular library Lucene uses the same algorithm), i.e. a match beween search term x and content y is considered a hit (true positive) if (|x| - dist(x,y))/|x| > minProb. The Threshold for approximate matching minProb can be customized in the Tools->Preferences dialog, tab Behavior, section Search. The lower the value, the more variations of the search term will be found. minProb=0.15 will find almost anything, while minProb=1.0 will do exact string matching. The results above are observed using the default minProb=0.65.

Comparison to Regular Expressions

If you know exactly what variations of a search term you are looking for, and you know regular expressions, then the Regex search feature will probably be a better choice.

Implementation details

There are two EditDistanceStringMatchingStrategy implementations: Damerau-Levenshtein, and a Pseudo-Damerau-Levenshtein that is a simple modification of the Levenshtein algorithm (see Wikipedia page ). Both algorithms were enhanced by the semi-global option that allows the search-term to be shifted free-of-cost and is used by substring ("Contains") matching. Pseudo-Damerau-Levenshtein is the default because I understand the implementation and it can easily be adapted (for example punishing matches with spaces in content separately).

The occurrences are computed by calculating all pairwise Alignments from the DP matrix that have a score >= minProb, and then using a heuristic to filter overlapping alignments. For example, searching for "Bismark" in a text "... Bismarck lived...Bismarck reigned..." yields the following two alignments:

----Bismar-k----------------------------
... Bismarck lived...Bismarck reigned...

---------------------Bismar-k-----------
... Bismarck lived...Bismarck reigned...

Feedback

Please edit this section (if you have the privileges) or post in the Open Discussion Forum, your feedback is very much appreciated!

  • Should we replace the "Match case" and "Approximate" checkboxes with icons?
  • Should we increase the default threshold (find less) or decrease it (find more)?

Top level projects

Freeplane is a Java Swing application that has two major variants:

  • Standalone desktop application (full functionality)
    • This is the application most people know.
    • The distribution contains also a Portable version of the desktop application. It's just a different style of packaging the application to make it portable on USB sticks etc. but it's not another application.
  • Browser applet (limited functionality)

The desktop application architecture is based on the OSGi framework. It uses Knoplerfish version 2.3 as OSGi implementation.

The fact that Freeplane is build on OSGi has the following consequences:

  • All of Freeplane's components are packaged as OSGi bundles (aka "plugins").
  • Freeplane is launched in two steps:
  1. The OSGi kernel, which is an external library, is configured and launched by Launcher.
  2. The kernel initiates loading of all plugins.

The browser applet does not use functionality contributed by the plug-ins.

Projects

All major components have their own project (toplevel directory in the version control system and an Eclipse project) and they are build into separate JARs.

freeplane
freeplane_mac
freeplane_plugin_bugreport
freeplane_plugin_help
freeplane_plugin_latex
freeplane_plugin_script
freeplane_plugin_script_test
freeplane_plugin_svg

All Freeplane projects but freeplane build a single plugin.jar (freeplane builds one plugin consisting of four JARs):

$ cd "/Program Files/Freeplane"
$ find . -name [pf][rl]\*.jar -o -name \*.MF
core/org.freeplane.core/lib/freeplaneeditor.jar
core/org.freeplane.core/lib/freeplanemac.jar
core/org.freeplane.core/lib/freeplaneosgi.jar
core/org.freeplane.core/lib/freeplaneviewer.jar
core/org.freeplane.core/META-INF/MANIFEST.MF
framework.jar
plugins/org.freeplane.plugin.bugreport/lib/plugin.jar
plugins/org.freeplane.plugin.bugreport/META-INF/MANIFEST.MF
plugins/org.freeplane.plugin.latex/lib/plugin.jar
plugins/org.freeplane.plugin.latex/META-INF/MANIFEST.MF
plugins/org.freeplane.plugin.script/lib/plugin.jar
plugins/org.freeplane.plugin.script/META-INF/MANIFEST.MF
plugins/org.freeplane.plugin.svg/lib/plugin.jar
plugins/org.freeplane.plugin.svg/META-INF/MANIFEST.MF

Startup sequence

The startup sequence begins with essentially the following command (compare freeplane.sh):

cd "/Program Files/Freeplane"
java \
-jar ./framework.jar" \
-xargs ./init.xargs"

(The remaining arguments are mainly used for Knoplerfish configuration and memory settings.) The JAR is the Knoplerfish implementation JAR and init.xargs contains the directory where the plugin lookup should start:

$ cat init.xargs
-istart org.freeplane.core

This tells Knoplerfish to load the org.freeplane.core plugin first. Knoplerfish inspects core/org.freeplane.core/META-INF/MANIFEST.MF for the Activator class of this bundle org.freeplane.main.osgi.Activator.

Knoplerfish then runs org.freeplane.main.osgi.Activator.start() which then performs all the remaining startup steps:

  • It creates an instance of org.freeplane.main.application.Freeplane which is responsible for the creation of controllers, actions, menus - short the complete basic application.

  • Then it loads the other plugins from directory plugins, one after the other, by creating them from by loading their JARs and starting them (see ActivatorImpl.loadPlugins())

    // org.freeplane.main.osgi.ActivatorImpl.startFramework() starter = new FreeplaneStarter(); loadPlugins(context); final Controller controller = starter.createController();

Freeplane core design

Overview

Design aims for extendable set of packages with clear purposes and as few circular dependencies as possible.

Graphical overview over the package dependencies was created using structure analysis tool for Java stan4j. (Red lines show circular dependencies which are considered not good and demonstrate potential for improvement).

.freeplane.features

Features implement bits of functionality assigned to a node, like an icon a note, an attribute etc, see [[#Features and their dependencies | below]].

.freeplane.view.swing

Renderers, user interface listeners and renderer specific features, see [[#Features dependent on rendering components | below]].

.freeplane.core

Utilities, classes and components used from different feature packages.

.freeplane.n3.nanoxml

XML Parser derived from nanoxml.

.freeplane.main

Application builders which put all parts together and start the application:

  • .freeplane.main.application: application specific parts and main method for running freeplane without the osgi plug-ins.
  • .freeplane.main.applet: freeplane applet specific parts. Runs only browsemode in an applet.
  • .freeplane.main.osgi: osgi specific parts loading and starting the plug-ins.
  • .freeplane.main.mindmapmode, .freeplane.main.browsemode, .freeplane.main.filemode: mode factories.

Features and their dependencies

.features.map and .features.mode

The architecture aims for minimizing dependencies between features. For extensible architecture central classes (MapModel, NodeModel, ModeController, ReadManager, WriteManager) do not have to know about all the particular features. They serve as a container for their extensions (like in "The expension objects" pattern by Erich Gamma). This principle however is not satisfied by some old features representing e.g. node text, icons and map URL used for map loading.

Mode Controllers manage set of actions available to the user in each of the freeplane modes: *MindMapMode *BrowserMode *FileMode

Mode specific packages can depend on their common package, other dependencies are not permitted.

Freeplane modes

Also there is a Controller which manages mode controllers themselves and mode independent actions like printing.

Feature implementation patterns

Typical feature design

A feature usually consists of different parts, as in org.freeplane.features.cloud:

  • a contribution to the node model; it holds the actual data, like a text, a color etc. (CloudModel),
  • a controller class that integrates the feature into the application by registering actions and listeners (CloudController),
  • Position of actions in menu is specified in /freeplane/resources/xml/mindmapmodemenu.xml and other mode specific menu configuration files.
  • a builder class that is able to serialize and de-serialize the model into XML, i.e. to store the model within the map (CloudBuilder) which should register itself by >ReadManager and >WriteManager,
  • If a feature supplies own filter / find conditions it should register class implementing .features.filter.condition.IElementaryConditionController at ConditionFactory from the same package.
  • a view which displays the element in a map; it is often implemented in a separate java package e.g.org.freeplane.view.swing.map.cloud,
  • Editing operations are implemented in a sub package adding MCloudController with some actions. Mode independent feature packages must not depend on the mode specific parts.

Mode specific packages can depend on their common package, other dependencies are not permitted.

Framework class PersistentNodeHook

As an alternative to implementation of a feature as a package some easy extensions can be implemented as a class extending PersistentNodeHook which provides implementations of controller, builder and model. It creates an extension with xml compatible with FreeMind so that FreeMind can ignore it and load the map. The extension can be declared as related to a map or to a node.

Looks at classes from the type hierarchy given below for examples.

Features independent on rendering components

Features with models and controllers not depending on view components with their interdependencies. Features and their dependencies

Features dependent on rendering components

Some features depend on view elements. They are defined here. Rendering packages and rendering specific features

TODO: to be continued...

Plugins

Structure of a plugin

A plugin is defined by its MANIFEST.MF, here an extract from the org.freeplane.core plugin (core/org.freeplane.core/META-INF/MANIFEST.MF):

Bundle-Name: org.freeplane.core
Bundle-Version: 1.0.1
Bundle-ClassPath: lib/freeplaneviewer.jar,
lib/freeplaneeditor.jar,
lib/freeplanemac.jar,
lib/freeplaneosgi.jar,
lib/commons-lang-2.0.jar,
lib/forms-1.0.5.jar,
lib/gnu-regexp-1.1.4.jar,
lib/SimplyHTML.jar,
lib/jortho.jar
Bundle-Activator: org.freeplane.main.osgi.Activator
Import-Package: org.osgi.framework
Export-Package: org.apache.commons.lang,
org.freeplane.core.addins,
org.freeplane.core.controller,
[...]
org.freeplane.view.swing.ui.mindmapmode

This defines the class path that is available within the bundle (Bundle-ClassPath), its version (versioning support is an important feature of OSGI), the list of packages that this plugin exports to others (Export-Package) and the Activator class of the bundle (Bundle-Activator).

The simplest OSGi plugin just needs a single class, the Activator class. If it should do some work then it should define an action, hooks them into the menu. So most of the work of creating a plugin will be spent setting up the directory/project structure.

Freeplane plug-in registers its factories as services IModeControllerExtensionProvider or IControllerExtensionProvider . They are called by Freeplane and can be used for installing themselves.

Freeplane Plug-ins are organized like [[#Typical_feature_design | features]] or [[#Framework_class_PersistentNodeHook | hooks]]. They can add their actions to menus and install their options into preferences panel from xml resources using methods ModeController.updateMenus(URL), OptionPanelBuilder.load() and other Methods of OptionPanelBuilder and MenuBuilder.

Look at existing plug-ins and core for examples.

Create a new Plugin

A simple tool helps to get started with plugin development. It's an Ant Task named 'create-plugin' that is available from the freeplane_framework/ant directory. The task reads all required parameters from the command line. (If you want to do it non-interactively you have to create your own Ant task.)

See Plugin development for details.

Freeplane team and contributors

Freeplane 1.3 (2012 - 2014)

NameRoleContact
Dimitry PolivaevFounder, Lead Developerhttps://sourceforge.net/users/dpolivaev/
Volker BoerchersDeveloperhttps://sourceforge.net/users/boercher/
Felix NatterDeveloperhttps://sourceforge.net/users/fnatter/
Blair ArchibaldDeveloperhttps://sourceforge.net/users/blairarchibald/
Hartmut GoebelDeveloperhttps://sourceforge.net/users/htgoebel/
Robert ...Graphic designer...

Freeplane 1.2 (2010 - 2012)

NameRoleContact
Dimitry PolivaevFounder, Lead Developerhttps://sourceforge.net/users/dpolivaev/
Volker BoerchersLead Developerhttps://sourceforge.net/users/boercher/
Jodi KrolDocu writer, Menu developerhttps://sourceforge.net/users/jokro/
Stefan OttDeveloperhttps://sourceforge.net/users/storment74/
Felix NatterDeveloperhttps://sourceforge.net/users/fnatter/
PredragGraphic designerhttps://sourceforge.net/users/pegi7/

Translations were contributed by Source Forge users akopec, atarol, ccc57, hexit34, hokorobi, jokro, laktionovivan, ldmpub-nospam (fr), loz42, pegi7, rickenbroc (fr), salamandra001, samos29 (fr), sergist, ymym0mymy, Nnamdi Kohn (de), Giovanni Daldosso / gioita (it), Ivan Starčević / ozzii23 (sr)

Freeplane 1.1 (2008 - 2010)

NameRoleContact
Dimitry PolivaevFounder, Lead Developerhttps://sourceforge.net/users/dpolivaev/
Volker BoerchersDeveloperhttps://sourceforge.net/users/boercher/
Stefan OttDeveloperhttps://sourceforge.net/users/storment74/
Tamas EppelDeveloperhttps://sourceforge.net/users/peletomi/
PredragGraphic designerhttps://sourceforge.net/users/pegi7/
Eric LPackager
Ryan WDocu writer
Jodi Krol (Jokro)Docu writerhttps://sourceforge.net/users/jokro/
NamBloggerhttps://sourceforge.net/users/ldmpub-nospam/
Jayseye

Translations were contributed by Source Forge users aviret, ewl, gioita, haaihenkie, hokorobi, joeby58, jokro, ldmpub-nospam, leijp, loz42, pegi7, riyaah, sergist, storment74, ymym0mymy.

FreeMind (2000 - 2008)

NameRoleContact
Joerg MuellerFounder, Developer
Daniel PolanskyDeveloper, Director
Christian FoltinDeveloper, Director
Dimitry PolivaevDeveloper

This page tries to reflect changes of the Freeplane file format.

Original FreeMind File Format

The original FreeMind format was never described completely formally, but there is some documentation:

Note
the above documentation is outdated in regard to elements introduced by Freeplane, like connector labels, attributes, scripts, user icons and (scalable) images embedded in the map.

Freeplane's version of it

The following schema takes the schema pointed at in the previous chapter and completes it with Freeplane specific extensions (in bold for easy identification):

Attention: 
The file format was accurate as per version 1.1.x, new features in 1.2.x have not (yet) been documented.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">

<xs:element name='Parameters'> <xs:complexType> <!--Is the time management plugin.--> <xs:attribute name='REMINDUSERAT' type='xs:integer' use='optional'/> </xs:complexType> </xs:element>

<!--Used for node notes.--> <xs:element name='text'> <xs:complexType/> </xs:element>

<!-- BEGIN ATTRIBUTES -->

<xs:element name='attribute_value'> <xs:complexType> <xs:attribute name='VALUE' type='xs:string' use='required'/> <xs:attribute name='TYPE' type='xs:string' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='attribute_name'> <xs:complexType> <xs:choice minOccurs='0' maxOccurs='unbounded'> <xs:element ref='attribute_value'/> </xs:choice> <xs:attribute name='NAME' type='xs:string' use='required'/> <xs:attribute name='MANUAL' type='xs:boolean' use='optional' /> <xs:attribute name='RESTRICTED' type='xs:boolean' use='optional' /> <xs:attribute name='VISIBLE' type='xs:boolean' use='optional' /> </xs:complexType> </xs:element>

<xs:element name='attribute_registry'> <xs:complexType> <xs:choice minOccurs='0' maxOccurs='unbounded'> <xs:element ref='attribute_name'/> </xs:choice> <xs:attribute name='RESTRICTED' type='xs:boolean' use='optional' /> <xs:attribute name='SHOW_ATTRIBUTES' use='optional'> <xs:simpleType> <xs:restriction base='xs:string'> <xs:enumeration value='selected'/> <xs:enumeration value='hide'/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element>

<xs:element name='attribute_layout'> <xs:complexType> <xs:attribute name='NAME_WIDTH' type='xs:integer' use='optional'/> <xs:attribute name='VALUE_WIDTH' type='xs:integer' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='attribute'> <xs:complexType> <xs:attribute name='NAME' type='xs:string' use='required'/> <xs:attribute name='VALUE' type='xs:string' use='required'/> <xs:attribute name='TYPE' type='xs:string' use='optional'/> </xs:complexType> </xs:element>

<!-- END ATTRIBUTES -->

<xs:element name='arrowlink'> <xs:complexType> <xs:attribute name='COLOR' type='xs:string' use='optional'/> <xs:attribute name='DESTINATION' type='xs:string' use='required'/> <xs:attribute name='ENDARROW' type='xs:string' use='optional'/> <xs:attribute name='ENDINCLINATION' type='xs:string' use='optional'/> <xs:attribute name='ID' type='xs:string' use='optional'/> <xs:attribute name='STARTARROW' type='xs:string' use='optional'/> <xs:attribute name='STARTINCLINATION' type='xs:string' use='optional'/> <xs:attribute name='SOURCE_LABEL' type='xs:string' use='optional'/> <xs:attribute name='MIDDLE_LABEL' type='xs:string' use='optional'/> <xs:attribute name='TARGET_LABEL' type='xs:string' use='optional'/> <xs:attribute name='EDGE_LIKE' type='xs:boolean' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='cloud'> <xs:complexType> <xs:attribute name='COLOR' type='xs:string' use='optional'/> <xs:attribute name='WIDTH' type='xs:integer' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='edge'> <xs:complexType> <xs:attribute name='COLOR' type='xs:string' use='optional'/> <xs:attribute name='STYLE' type='xs:string' use='optional'/> <xs:attribute name='WIDTH' type='xs:string' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='font'> <xs:complexType> <xs:attribute name='BOLD' use='optional'> <xs:simpleType> <xs:restriction base='xs:string'> <xs:enumeration value='true'/> <xs:enumeration value='false'/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name='ITALIC' use='optional'> <xs:simpleType> <xs:restriction base='xs:string'> <xs:enumeration value='true'/> <xs:enumeration value='false'/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name='NAME' type='xs:string' use='optional'/> <xs:attribute name='SIZE' type='xs:integer' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='hook'> <xs:complexType> <xs:sequence> <xs:element ref='Parameters' minOccurs='0' maxOccurs='1'/> <xs:element ref='text' minOccurs='0' maxOccurs='1'/> </xs:sequence> <xs:attribute name='NAME' type='xs:string' use='required'/> <!-- for embedded images NAME="ExternalObject" --> <xs:attribute name='URI' type='xs:anyURI' use='optional'/> <xs:attribute name='SIZE' type='xs:decimal' use='optional'/> <!-- for map config info NAME="MapStyle" --> <xs:attribute name='max_node_width' type='xs:integer' use='optional'/> <xs:attribute name='zoom' type='xs:decimal' use='optional'/> <!-- for equations NAME="plugins/latex/LatexNodeHook.properties" --> <xs:attribute name='EQUATION' type='xs:string' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='icon'> <xs:complexType> <xs:attribute name='BUILTIN' type='xs:string' use='required'/> </xs:complexType> </xs:element>

<xs:element name='html'> <xs:complexType> <xs:sequence> <!--Anything that is valid XML, but should be http://www.w3.org/1999/xhtml --> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="skip"/> </xs:sequence> </xs:complexType> </xs:element>

<xs:element name='richcontent'> <xs:complexType> <!-- And contains XHTML as unique child:--> <xs:sequence> <xs:element ref='html' minOccurs='1' maxOccurs='1'/> </xs:sequence> <!--Currently, only NODE or NOTE is allowed.--> <xs:attribute name='TYPE' use='required'> <xs:simpleType> <xs:restriction base='xs:string'> <xs:enumeration value='NODE'/> <xs:enumeration value='NOTE'/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element>

<xs:element name='map'> <xs:complexType> <xs:sequence> <xs:element ref='attribute_registry' minOccurs='0' maxOccurs='1'/> <xs:element ref='node' minOccurs='1' maxOccurs='1' /> </xs:sequence> <xs:attribute name='version' type='xs:string' use='required'/> </xs:complexType> </xs:element>

<xs:element name='node'> <xs:complexType> <xs:choice minOccurs='0' maxOccurs='unbounded'> <xs:element ref='arrowlink'/> <xs:element ref='cloud'/> <xs:element ref='edge'/> <xs:element ref='font'/> <xs:element ref='hook'/> <xs:element ref='icon'/> <xs:element ref='node'/> <!-- For nodes with extended formatting content or for notes to nodes. --> <xs:element ref='richcontent'/> <xs:element ref='attribute_layout'/> <xs:element ref='attribute'/> </xs:choice> <xs:attribute name='BACKGROUND_COLOR' type='xs:string' use='optional'/> <xs:attribute name='COLOR' type='xs:string' use='optional'/> <xs:attribute name='FOLDED' use='optional'> <xs:simpleType> <xs:restriction base='xs:string'> <xs:enumeration value='true'/> <xs:enumeration value='false'/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name='ID' type='xs:ID' use='optional'/> <xs:attribute name='LINK' type='xs:string' use='optional'/> <xs:attribute name='POSITION' use='optional'> <xs:simpleType> <xs:restriction base='xs:string'> <xs:enumeration value='left'/> <xs:enumeration value='right'/> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name='STYLE' type='xs:string' use='optional'/> <xs:attribute name='TEXT' type='xs:string' use='optional'/> <xs:attribute name='LOCALIZED_TEXT' type='xs:string' use='optional'/> <xs:attribute name='TYPE' type='xs:string' use='optional'/> <xs:attribute name='CREATED' type='xs:integer' use='optional'/> <xs:attribute name='MODIFIED' type='xs:integer' use='optional'/> <xs:attribute name='HGAP' type='xs:integer' use='optional'/> <xs:attribute name='VGAP' type='xs:integer' use='optional'/> <xs:attribute name='VSHIFT' type='xs:integer' use='optional'/> <xs:attribute name='ENCRYPTED_CONTENT' type='xs:string' use='optional'/> </xs:complexType> </xs:element> </xs:schema>

Mapping between old and new format

Attention: 
This effort is on hold until further notice (perhaps after release of version 1.2/1.3).
Mapping between old and new format
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">
not relevant
 <xs:element name='Parameters'>
  <xs:complexType>
	  <!--Is the time management plugin.-->
   <xs:attribute name='REMINDUSERAT' type='xs:integer' use='optional'/>
  </xs:complexType>
 </xs:element>
Replaced by parameter node:reminder="dateTime" to node:node (this limits the number of reminders to one per node but Freeplane can't anyway handle more than one).
 <!--Used for node notes.-->
 <xs:element name='text'>
  <xs:complexType/>
 </xs:element>
Obsolete - all nodes are "rich"
 <!-- BEGIN ATTRIBUTES -->

<xs:element name='attribute_value'> <xs:complexType> <xs:attribute name='VALUE' type='xs:string' use='required'/> </xs:complexType> </xs:element>

<xs:element name='attribute_name'> <xs:complexType> <xs:choice minOccurs='0' maxOccurs='unbounded'> <xs:element ref='attribute_value'/> </xs:choice> <xs:attribute name='NAME' type='xs:string' use='required'/> <xs:attribute name='MANUAL' type='xs:boolean' use='optional' /> <xs:attribute name='RESTRICTED' type='xs:boolean' use='optional' /> <xs:attribute name='VISIBLE' type='xs:boolean' use='optional' /> </xs:complexType> </xs:element>

<xs:element name='attribute_registry'> <xs:complexType> <xs:choice minOccurs='0' maxOccurs='unbounded'> <xs:element ref='attribute_name'/> </xs:choice> <xs:attribute name='RESTRICTED' type='xs:boolean' use='optional' /> <xs:attribute name='SHOW_ATTRIBUTES' use='optional'> <xs:simpleType> <xs:restriction base='xs:string'> <xs:enumeration value='selected'/> <xs:enumeration value='hide'/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element>

<xs:element name='attribute_layout'> <xs:complexType> <xs:attribute name='NAME_WIDTH' type='xs:integer' use='optional'/> <xs:attribute name='VALUE_WIDTH' type='xs:integer' use='optional'/> </xs:complexType> </xs:element>

<xs:element name='attribute'> <xs:complexType> <xs:attribute name='NAME' type='xs:string' use='required'/> <xs:attribute name='VALUE' type='xs:string' use='required'/> </xs:complexType> </xs:element>

<!-- END ATTRIBUTES -->

The whole attribute will be replaced as follows. First define the sets of attributes at the map level:
<map:attributes attribute:restricted="false|true">
 <attribute:attribute meta:name="..."
                      attribute:restricted="false|true"
                      attribute:selected="false|true">
  <attribute:value>some value</attribute:value>
  ...
 </attribute:attribute>
 ...
</map:attributes>

And then assign the attributes at the node level:

<node:attributes attribute:name-width="..."
                 attribute:value-width="...">
 <attribute:attribute
           meta:name="...">some value</attribute:attribute>
 ...
</node:attributes>
 <xs:element name='arrowlink'>
  <xs:complexType>
   <xs:attribute name='COLOR' type='xs:string' use='optional'/>
   <xs:attribute name='DESTINATION' type='xs:string' use='required'/>
   <xs:attribute name='ENDARROW' type='xs:string' use='optional'/>
   <xs:attribute name='ENDINCLINATION' type='xs:string' use='optional'/>
   <xs:attribute name='ID' type='xs:string' use='optional'/>
   <xs:attribute name='STARTARROW' type='xs:string' use='optional'/>
   <xs:attribute name='STARTINCLINATION' type='xs:string' use='optional'/>
   <xs:attribute name='SOURCE_LABEL' type='xs:string' use='optional'/>
   <xs:attribute name='MIDDLE_LABEL' type='xs:string' use='optional'/>
   <xs:attribute name='TARGET_LABEL' type='xs:string' use='optional'/>
   <xs:attribute name='EDGE_LIKE' type='xs:boolean' use='optional'/>
  </xs:complexType>
 </xs:element>
Replaced by element <draw:connector ... /> with attributes
draw:start-shape="ID"
draw:color="#rrggbb"
draw:end-shape="ID"
map:start-arrow="true|false"
map:end-arrow="true|false"
xml:id="ID"
map:start-inclination="int;int;"
map:end-inclination="int;int;"
draw:style="normal|edge-like"

And with possible sub-nodes:

<map:start-label>...</map:start-label>
<svg:title>...</svg:title> (or svg:desc?!)
<map:end-label>...</map:end-label>
 <xs:element name='cloud'>
  <xs:complexType>
   <xs:attribute name='COLOR' type='xs:string' use='optional'/>
   <xs:attribute name='WIDTH' type='xs:integer' use='optional'/>
  </xs:complexType>
 </xs:element>
Replaced by element <node:cloud ... /> with attributes
draw:color="#rrggbb"

(WIDTH parameter isn't used currently and is always 0)

 <xs:element name='edge'>
  <xs:complexType>
   <xs:attribute name='COLOR' type='xs:string' use='optional'/>
   <xs:attribute name='STYLE' type='xs:string' use='optional'/>
   <xs:attribute name='WIDTH' type='xs:string' use='optional'/>
  </xs:complexType>
 </xs:element>
Replaced by element <node:edge ... /> with attributes
draw:color="#rrggbb"
draw:style="linear|sharp-linear|bezier|sharp-bezier|horizontal"
draw:stroke="solid|none"
svg:stroke-width="length" (Freeplane uses only integers)
Note
those attributes should be moved to a <style:style> element that defines a style with the family value of graphic, and referenced by name through the draw:style-name attribute.
 <xs:element name='font'>
  <xs:complexType>
   <xs:attribute name='BOLD' use='optional'>
    <xs:simpleType>
     <xs:restriction base='xs:string'>
      <xs:enumeration value='true'/>
      <xs:enumeration value='false'/>
     </xs:restriction>
    </xs:simpleType>
   </xs:attribute>
   <xs:attribute name='ITALIC' use='optional'>
    <xs:simpleType>
     <xs:restriction base='xs:string'>
      <xs:enumeration value='true'/>
      <xs:enumeration value='false'/>
     </xs:restriction>
    </xs:simpleType>
   </xs:attribute>
   <xs:attribute name='NAME' type='xs:string' use='optional'/>
   <xs:attribute name='SIZE' type='xs:integer' use='optional'/>
  </xs:complexType>
 </xs:element>
Replaced by element <style:text-properties ... /> with attributes
fo:color="#rrggbb"
fo:font-weight="normal|bold"
fo:font-style="normal|italic"
fo:font-family="name of the font"
fo:font-size="integer"
Note
<style:font-name> could be used instead of fo:font-family but, according to specs, this would mean a separate definition of a font through a style:font-face element and that makes the whole thing more complex. See Freeplane_File_Format#3.14_.3Coffice:font-face-decls.3E.
Note
this element should be moved to a <style:style> element that defines a style with the family value of text, and referenced by name through the text:style-name attribute.
 <xs:element name='hook'>
  <xs:complexType>
   <xs:sequence>
    <xs:element ref='Parameters' minOccurs='0' maxOccurs='1'/>
    <xs:element ref='text' minOccurs='0' maxOccurs='1'/>
   </xs:sequence>
   <xs:attribute name='NAME' type='xs:string' use='required'/>
   <!-- for embedded images NAME="ExternalObject" -->
   <xs:attribute name='URI'  type='xs:anyURI' use='optional'/>
   <xs:attribute name='SIZE' type='xs:decimal' use='optional'/>
Replaced by the following element:
<draw:frame draw:transform="scale(sx [sy])">
 <draw:image xlink:href="URL"/>
</draw:frame>
Note
if wished, the <draw:image> element could also have an attribute draw:filter-name="ExternalObject" but I wouldn't see the point (rather the name of a plugin for image formats not supported by Freeplane).
   <!-- for map config info NAME="MapStyle" -->
   <xs:attribute name='max_node_width'  type='xs:integer' use='optional'/>
   <xs:attribute name='zoom' type='xs:decimal' use='optional'/>
It actually depends if those settings shall be different from map to map (within a same file) or the same for the whole file.

In the first case, they would be attributes to the <map:map> element:

node:max-width="integer"
map:zoom="percentage"

And in the 2nd case, they would be office settings:

<config:config-item config:name="NodeMaxWidth"
                    config:type="int">40</config:config-item>
<config:config-item config:name="MapZoom"
                    config:type="int">150</config:config-item>

TBD

   <!-- for equations NAME="plugins/latex/LatexNodeHook.properties" -->
   <xs:attribute name='EQUATION' type='xs:string' use='optional'/>
  </xs:complexType>
 </xs:element>
Plugin hooks (like Latex) are replaced by an element <node:content> with a corresponding namespace definition, like in:
<node:content 
      xmlns:latex="plugins/latex/LatexNodeHook.properties">
 <latex:equation>
  <![CDATA[some equation in Latex]]>
 </latex:equation>
</node:content>

As shown here, in the case of non-XML dialect, the use of a CDATA section is highly recommended.

 <xs:element name='icon'>
  <xs:complexType>
   <xs:attribute name='BUILTIN' type='xs:string' use='required'/>
  </xs:complexType>
 </xs:element>
Replaced by element <node:icon ... /> with attributes
node:icon-name="..." (a string)
 <xs:element name='html'>
  <xs:complexType>
   <xs:sequence>
    <!--Anything that is valid XML,
                 but should be http://www.w3.org/1999/xhtml -->
    <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded"
            processContents="skip"/>
   </xs:sequence>
  </xs:complexType>
 </xs:element>
Obsolete, as all nodes are rich content...
 <xs:element name='richcontent'>
  <xs:complexType>
   <!-- And contains XHTML as unique child:-->
   <xs:sequence>
    <xs:element ref='html' minOccurs='1' maxOccurs='1'/>
   </xs:sequence>
   <!--Currently, only NODE or NOTE is allowed.-->
   <xs:attribute name='TYPE' use='required'>
    <xs:simpleType>
     <xs:restriction base='xs:string'>
      <xs:enumeration value='NODE'/>
      <xs:enumeration value='NOTE'/>
     </xs:restriction>
    </xs:simpleType>
   </xs:attribute>
  </xs:complexType>
 </xs:element>
Replaced by either
<node:content xmlns:xhtml="http://www.w3.org/1999/xhtml">
 <xhtml:body> ... </xhtml:body>

or

<office:annotation xmlns:xhtml="http://www.w3.org/1999/xhtml">
 <xhtml:body> ... </xhtml:body>
Note:the XHTML body is specific to Freeplane, ODF has actually its own markup, but that would be too much to implement. In the future, other type of elements could be implemented in a node or a note (Latex, etc...) instead of XHTML.
 <xs:element name='map'>
  <xs:complexType>
   <xs:sequence>
    <xs:element ref='attribute_registry' minOccurs='0' maxOccurs='1'/>
    <xs:element ref='node' minOccurs='1' maxOccurs='1' />
   </xs:sequence>
   <xs:attribute name='version' type='xs:string' use='required'/>
  </xs:complexType>
 </xs:element>
Replaced by element <map:map>
 <xs:element name='node'>
Replaced by element <node:node>
  <xs:complexType>
   <xs:choice minOccurs='0' maxOccurs='unbounded'>
    <xs:element ref='arrowlink'/>
    <xs:element ref='cloud'/>
    <xs:element ref='edge'/>
    <xs:element ref='font'/>
    <xs:element ref='hook'/>
    <xs:element ref='icon'/>
    <xs:element ref='node'/>
    <!-- For nodes with extended formatting content or for notes. -->
    <xs:element ref='richcontent'/>
    <xs:element ref='attribute_layout'/>
    <xs:element ref='attribute'/>
   </xs:choice>
Mapped obviously as described above...
   <xs:attribute name='BACKGROUND_COLOR'
                 type='xs:string' use='optional'/>
Replaced by attribute draw:fill-color="#rrggbb"
   <xs:attribute name='COLOR' type='xs:string' use='optional'/>
It's actually the color of the font and has been moved to the corresponding element <style:text-properties ... />.
   <xs:attribute name='FOLDED' use='optional'>
    <xs:simpleType>
     <xs:restriction base='xs:string'>
      <xs:enumeration value='true'/>
      <xs:enumeration value='false'/>
     </xs:restriction>
    </xs:simpleType>
   </xs:attribute>
Replaced by attribute node:folded="false|true"
   <xs:attribute name='ID' type='xs:ID' use='optional'/>
Replaced by attribute xml:id="ID"
   <xs:attribute name='LINK' type='xs:string' use='optional'/>
Replaced by attribute xlink:href="URL"
   <xs:attribute name='POSITION' use='optional'>
    <xs:simpleType>
     <xs:restriction base='xs:string'>
      <xs:enumeration value='left'/>
      <xs:enumeration value='right'/>
     </xs:restriction>
    </xs:simpleType>
   </xs:attribute>
Replaced by attribute node:side="left|right"
   <xs:attribute name='STYLE' type='xs:string' use='optional'/>
Replaced by attribute draw:style="fork|bubble"
   <xs:attribute name='TEXT' type='xs:string' use='optional'/>
Obsolete.
   <xs:attribute name='CREATED' type='xs:integer' use='optional'/>
   <xs:attribute name='MODIFIED' type='xs:integer' use='optional'/>
Replaced respectively by attributes node:inserted="dateTime" and node:modified="dateTime"
Note
the 'dateTime' format is normally according to ISO8601 instead of the current UN*X-like number of seconds. TBD - To Be Discussed.
   <xs:attribute name='HGAP' type='xs:integer' use='optional'/>
   <xs:attribute name='VGAP' type='xs:integer' use='optional'/>
   <xs:attribute name='VSHIFT' type='xs:integer' use='optional'/>
Replaced respectively by attributes node:margin-horizontal="integer", node:margin-vertical="integer" and node:shift-vertical="integer"
   <xs:attribute name='ENCRYPTED_CONTENT'
                 type='xs:string' use='optional'/>
Replaced by attribute node:encrypted="false|true"
  </xs:complexType>
 </xs:element>
</xs:schema>

Freeplane document format is written in XML.

Here you can find the last version of its XSD schema.

XSD information can be used as reference to understand the file format as well as for automatic validation purposes.

This is a graphical representation of the schema created with xsdvi:

Right click on the node or select menu Insert>External object...

Inserting external object  

You will be asked to open a file on your computer (with preview).

Since the object is inserted, you can:

  • resize it with the handle at the bottom right edge of the object. The proportions will be constrained.

  • double click to recover the native size

  • double click anywhere on the surface of the object to open it in your favorite editor.

External object resize

Answers to questions are to be found on different places, depending on the Freeplane version.

General

Are there books about Freeplane?

Yes, but only in French and German:

Books about Freeplane's anchestor FreeMind might be interesting as well:

And of course there are a lot of books on Mindmapping in general.

What made it worth forking from Freemind?

See the article on the Freeplane/FreeMind relationship.

What's the "Freeplane user directory"?

The Freeplane user directory can be found by invoking the menu item Tools->Open user directory. It's location is the directory 1.2.x respectively 1.3.x in %APPDATA%\Freeplane (Windows) respectively ~/.freeplane/ (Linux, Mac). It contains all user settings: options in auto.properties, scripts, configuration of data recognition, ...

Where are the preferences stored?

Almost all preferences are stored in /auto.properties. It contains all settings, keyboard bindings and more. If you want to install a second copy of Freeplane, e. g. to another computer you can copy auto.properties to copy all settings.

Where's the log file?

Sometimes you need to know where the log file is located, e.g. if you write scripts or reporting bugs . Find it in subdirectory logs of the Freeplane "user directory" (see above). It's named log.0 in most cases. If you have more than one Freeplane instance opened then it might have the name log.1 or even log.0.1. The most recently changed file matching the pattern log.* will be the one you are looking for.

How to replace the splash screen

Find directory resources in the freeplane installation directory, create directory images in it and put your file named Freeplane_splash.png there.

Weird problems

See if you find help on the Troubleshooting page. Otherwise ask in the Open discussion forum.

How to disable node selection changing when hovering over it

It's in the preferences: Tools->Preferences->Behaviour->Selection method->By click

Conceptual difference between "note" and "detail"?

Postby quinbus » 31 May 2013 19:51.

I suppose that because I'm one (of presumably many) fans of node DETAIL containers, I should at least stand up and be counted.

As I think about the uses I make of the two different containers, it becomes apparent that the differences for me are really one of style and preference; as the previous poster noted, they are technically very similar. But there are lots of examples in life where two technically similar objects or applications find different uses and proponents. Differences between NOTES and DETAILS are finally a function of the subjective discretion of any given user. So, necessarily, my uses will likely be very different that some one else's; but for what it's worth, here are a few ways I make use of the two containers.

Generally speaking, I use DETAILS to hold supplementary information that could be of immediate use to the reader of any given node. An example would be a node that serves as a parent for a set of meeting notes; the DETAIL for this parent contains the location and title of the meeting. In node details I might put the PURPOSE of the meeting, along with any administrivia that might be useful in the future (e.g., City, Time and Address). Information in the details container is discreetly indicated by the presence of the small toggle which appears below the node; unlike the notes container, there is no icon in the main node container that causes node content to be shifted over to accommodate its presence. The toggle is easily manipulated to hide important information that isn't immediately useful to the visual flow of a map, but, unlike NOTES, this information can be easily visually incorporated in the structure of map when desired.

One really nice application of the DETAILS container is a place to store image files, such as group pictures. To this end, I highly recommend the use of the amazing script out in the library that manages the process of locating images on your computer or network and helping you to size them to an appropriate visual impact and designating which of the three FP containers you want to put the resulting image in. Use of the DETAILS container for this purpose is ideal; image files can be much, much wider than the prevailing nodes in a map, crowding out everything else. Putting images in details allows you to toggle the picture in when desired, but keeping it nicely tucked away when not wanted. Example would be a group photo of a work session or, perhaps screenshots of various whiteboards. The main node container provides the label for the map and a few salient points; with a simple click of the toggle, the detail container can be opened to show the image file. A broader discussion of the way image files are handled in FP (including video examples) can be found at https://www.freeplane.org/forum2012/viewtopic.php?f=3&t=492

I personally tend to reserve NOTES containers for a free form workspace where I can make larger expansions on the brief ideas captured in the main node container. The width of NOTES containers is separate from the prevailing width set in the property panel for any given node, so the workspace is much larger and lends itself to formatting and tools that would likely feel cramped in the other two node containers (e.g., the table feature in SimplyHTML works really well in this space).

An obvious use of NOTES is a quick place to begin formatting meeting notes or letters that may have been suggested in the course of a meeting. Perhaps I took the responsibility in the meeting of formatting a letter to colleagues not present; during the break I can open the NOTES container associated with that particular action item and begin the process of constructing the flow and content. It's easy to share the information with colleagues in the meeting, and it keeps all my work on the subject together in one place. If and when the e-mail or formal letter needs to be sent or formally crafted, it's easy enough to copy and paste, but all the inputs the communique are right there . Generally I think I use the NOTES container similar to what I understand is it's primarily use in the DOCEAR environment: Node containers capture the basic outline of a more complex thought process and the NOTES editor is the place where I would start to flesh those simple ideas into something more cohesive.

Just some thoughts. As I say, your mileage will greatly vary.

But I've grown very attached to DETAILS and make an extensive application of them in my particular use case applications...

Q!

Index wiki

Download Freeplane now!

applet|title New features as a mind map|See some new features in a mind map .

The most important new features

  • Better inline_editor for all plain text nodes
  • Edge-like connectors (available from connector pop-up menu)
  • External objects: External bitmap and SVG images can be attached using menu Insert->External object and resized
    • Image size can be reset by double clicking on the bottom right corner
    • Images can be scaled by dragging the bottom right corner
  • Good Scripting support:
  • Insert image dialog and insert external object dialog have file previews
  • F-Toolbar
  • Find or Replace in all open maps
    • Perhaps the most important improvement. Here's a video of search all open maps [* Full screen mode
  • Hidden Edge Style
  • Horizontal Edge Style
  • Hot keys can be set by pressing left mouse button on menu item and holding CONTROL key
  • Outline view
  • Portable Freeplane
  • Selective paste from edit menu (Paste as...)
  • Spell checker
  • Structured HTML paste

New filtering features

  • Date based filter
  • Filter conditions for numeric values return false for non numeric values
  • Filter based on link labels
  • Filter history
  • Filter menu
  • Filter tool bar can be hidden like all other tool bars,
  • Filter status is displayed in status line
  • Filter node text by regular expressions

Other features

  • All backup or autosave files are numbered from 1 to maximum number, the bigger number the latest file.
  • Automatic backup for all loaded files on first save.
  • Backup and autosave use directory ".backup" created in the map directory.
  • Edit nodes with line breaks in in-line editor (alt+enter to quit , shift+enter for line break)
  • Enable link pop-up menu even if neither target nor source node is selected.
  • Exception traces for internal errors are automatically sent to freeplane team for analysis.
  • Export Using XSLT
  • Hide tabs if only one map is loaded
  • Hot keys: CONTROL + ALT + RIGHT, CONTROL + ALT + LEFT
  • Icon actions moved in separate menu
  • Icon toolbar hidden by default
  • Linking to arbitrary URI integrated
  • Links where target or source are selected are found first.
  • New icons: 0%, 25%, 50%, 75%, 100%
  • You can add user icons. Just create a subdirectory "icons" of your freeplane profile directory (e.g. ~/.freeplane/1.2.x/ under Linux), and populate it with PNG files (of moderate sizes, of course). You can even add links to other icons directories, for example :
    ln -s /usr/share/icons/default.kde4/22x22/actions  ~/.freeplane/1.2.x/icons/actions
  • New navigation actions useful for presentation "next node" and "previous node". They traverse the map in depth-first order.
  • Personal modification color can be set in prefeences
  • Plain text search for filter in html nodes added
  • Priority filters based on priority icons
  • Text labels can be added to any end and in the middle of any link by link pop-up menu
    • Can someone produce a video of HOW to do this?
  • Text rendering mode use more exact fractional metric based version.
  • The action is also available from pop-up menu
  • The attached file can be opened by double click on the image itself
  • The same zooms applies to all maps
  • Zoom keep selected node position
  • Zoom saved between sessions

Exporting from Freeplane to PowerPoint is quite easy. These steps where done with PowerPoint 2007 and Freeplane 1.2.12 beta.

  1. Select the node that is one level above what will be your slides in PowerPoint (usually the center topic), right click, select Copy.
  2. Open PowerPoint. Make sure you have an empty presentation open. On your left you can see the slide in smaller view, on top there is a tab called Outline, click it.
  3. On the first slide in the outline view, click next to the slide number so there is a cursor visible, press Enter and then Tab. There should still be only one slide, and the cursor is on the second row.
  4. Paste (Ctrl-V). Now the text from Freeplane should be pasted.
  5. Now to the smart part. Now select the text you pasted, do not select the first line next to slide 1.
  6. Press Shift-Tab. Now all the first level headings are transformed to slides.

That's it. Now your hiearchy from Freeplane is copied as slides to PowerPoint.

Formatting will not be copied from Freeplane to PowerPoint.

If you are not English: see Translated wiki pages if this tutorial has been translated into your language.

This tutorial refers to Freeplane 1.2, which was released on October 20, 2012.

Index wiki

Introduction

This Freeplane Tutorial Extensions describes a Tutorial with basic terms and how to use the basic Freeplane functions. In addition it contains examples of use cases and concrete instructions how to make these cases. The Tutorial is divided into parts for the Beginner, Advanced user and Professional user. The examples below are labelled in a similar way helping to indicate the level of difficulty if you want to make a map yourself. It is no problem if the beginner wants to navigate a map for the advanced or professional user.

Download example map

You may view the examples without having Freeplane installed. So it is not necessary to download the example. It is possible to download the example once you have opened an example.mm as follows. In the browser you see the address of the opened map, e.g. www.freeplane.org/mapsOnline/?map=example.map. Now remove the part "?map=" (e.g. www.freeplane.org/mapsOnline/example.map) and press the Enter key to start the download.

Instructional examples of Freeplane maps

What is mind mapping

Mind mapping - Advanced Mind mapping is a technique for collecting, developing and sharing ideas (like the plot of a story or threads of a new idea) in a visual map. Developing a mind map helps to structure information in a visual way. It follows the random way in which the mind generates thoughts rather than following a linear format such as text in a Word document. You can plan a project, summarise your notes for an exam, brainstorm a new idea, take a brief. The uses are endless.

The mind map on the right shows you some of the processes involved.

The advantage of electronic mind maps over paper mind maps is that you can have as many nodes and branches as you like and can minimise them so as not to have a lot of clutter on your screen. There's no limit to the amount of information you can put in a mind map. You can also link to documents and web pages, delete unneeded nodes and branches and do lots of editing which is more limited with paper mind maps.

The advantages of Freeplane are presented in the mind map, as hidden information. Click the link below the picture to open the map. Then click the topic help Navigation for learning how to unhide hidden information.

Brainstorming with digital post-its

Generally brainstorming starts with writing ideas on post-its and sticking them to the wall. Freeplane has a "free node" for this: if you Ctrl + double click on a free place of the mind map, a node opens. When you start typing you will see your text in this free node. Note: This feature doesn't work on Mac yet. If you're done, you can do the same with a different idea in a different place. Once you're ready, you can move similar ideas closer together and connect them in a hierarchy by dragging and dropping. See Floating nodes for more examples.

Map as index

Index wiki - Beginner Index functions - Advanced Index applications - Professional Beginner. One way to bring structure to linear text is to use categories as we have in this wiki. A limitation of these categories however is that hierarchical relations cannot be displayed in a simple way. A mind map is better suited for this, as is shown by the example map on the right.

In this particular case the categories of the wiki are represented as underlined hyperlinks. The pages of the wiki are represented by red-arrow hyperlinks. The latter are created simply by dragging the page address (URL) of a wiki page onto a node and then editing the title of the node. If you clik on the hyperlink under the image, the mind map opens and you can click the links to jump to the pages of the wiki.

Advanced. An index can have many different forms. The map on the right displays all Freeplane functions. These functions are described in more detail in two maps called Tutorial and Documentation respectively. The map contains two solutions for linking a function to the two descriptive maps. The functions on the left half have the two hyperlinks themselves, but they are hidden until the mouse cursor is hovering over the function (tool tip). The functions on the right half of the map have an external pointer - the nodes with the question mark. These external pointers contain the hyperlinks, which again are hidden until you hover with the cursor over the question mark.

Professional. The map on the right is an index map for the use of cases mentioned in this tutorial. Unlike a classical linear index the indexed items in the mind map can be displayed in any order as can the relationships between them. This map uses most of the functionalities of Freeplane in one map. Click the link under the image to open the mind map. Then read the node called Caption to learn how to navigate the map and unhide hidden information.

Meeting support

Meeting support - Beginner Meeting support - Advanced Freeplane is very suited for rapid and easy note taking during meetings. In fact Freeplane can support the whole meeting process. This process starts with designing and distributing the topics of the agenda, keeping the attendants list, adding notes to the topics of the agenda and finally producing the decisions and action list of the meeting. Actions can also be supported with time signals. It is even possible to include the incoming and outgoing information in the map, either as hyperlinks or in a special area (Notes). And last but not least, part or all of the information can be password protected.

The maps for the beginner and advanced user display the same meeting information, but differently "formatted", with the different components available in Freeplane (node core versus node details, attributes, images, styles, etc.). Click on the hyperlinks below the images to open and navigate the respective maps. In Meeting advanced: hover the nodes (texts) to see hidden text like notes.

Instructions (animation) on how to make and use the beginner meeting support are available here. When the example is stripped from its specific information, the remaining structure could be used as a template for meetings in general.

Organize your collection

[[File:CollectionBeginner.jpg|left|Collection - Beginner ]] Collection - Advanced With Freeplane you can order, index and describe your collections, whether images, audio files or any other kind of information. It's especially easy to select a group of files and copy them in one action to a mind map. In that case these files appear as clickable arrows (hyperlinks) in separate nodes, as shown in the mind map on the left (Beginner collection). Once in the mind map, you can rename and sort the nodes. For image links, you can turn the links to images which are visible in the map.

Of course it's possible to build a collection item by item too. And it is possible to add additional information and format it any way you want, as in the mind map on the right (Advanced collection). If you hover over the names, you will see additional information about location and time, which appear in a table of attributes. Or you can click the name of an image, which makes the image appear or disappear (fold).

If you have collections of different kinds in one map, consider using a different style or a different icon for each kind. In that way you can use filtering to create a view of all elements of the same kind.

Vault for information

My Vault - Advanced If you would like to keep certain information private, you can password protect it. It's possible to protect the whole map or just protect a (sub)tree of nodes. The example on the right contains a protected map "MyVault". Within this protected map are branches for finance and for websites. These are separately protected.

Open the map by clicking My Vault under the picture. Then find the unlock icon in the menubar and click it. Enter the password "MyVault". Now the map opens (unfolds) and you see the branches for websites and for finance. Select creditcard of one of the banks, click the unlock menu button and enter password "creditcard". Now the creditcard information unfolds. You can do the same with the other creditcard. Then go to the websites and select the Freeplane open forum, click the unlock button and enter "Freeplane" as a password. Now the information for login unfolds. Note that an explanation of each node is presented below each node titel.

Dashboard for GTD

Action dashboard When Freeplane opens it starts with a standard map. This map can be modelled into a dashboard with direct access to the most important information at home and on the Internet. You can do this by simply dragging hyperlinks into your map. Besides you can add (hidden) content to hyperlinks to remember their meaning. Alo you can set signals to remember when you have to give attention to this information. This makes Freeplane particularly supportive for Getting Things Done. To view and navigate the map, click on the link below the image.

For advanced features for helping to get your Getting Things Done system work more flawlessly, you can try to use the Freeplane|GTD+ plugin. There is a template designed to help you get started with the plugin available here

SWOT analysis

SWOT analysis Mind maps are a fantastic tool for carrying out all kinds of analyses. In this, Freeplane suports using images and arrows with labels to display concepts, which helps to keep oversight and focus. In case this is not enough, Freeplane supports using hidden text which the user can roll down or hover over. Click on the small triangles, or hover the cursor over the images to see a descriptive text. To view and navigate the map, click on the link below the image.


Assignment & Presentation

Sjabloon spreekbeurt Spreekbeurt A map can be used as a student assignment, and can include directions, set questions and give links to literature. The student can click the literature links to open the literature and add answers to the questions - in the map itself.
The map to the left contains a map with keywords for questions and literature links. For the advanced student these could be removed. Once the assigment is completed and the result is entered in the map, the map could be used to learn and do the presentation. The map to the right contains model answers to the questions which could be used to check the result. Answers could be password-protected so that students can only see them once given the password. To view and navigate a map, click on the link below the image.

Tutorial

Tutorial - As a book Tutorial - Professional
Freeplane's Tutorial is an example of how a Freeplane map can be used to hold extensive amounts of (hidden) information and for delivering it in a user determined way, adapted to the user's experience level.

In Freeplane the node hierarchy of parent-child-grandchild nodes is by default displayed in left-right direction. Hierarchical levels can be used to display a chapter - (sub)subchapter - content chain. To be visible, the chain needs to be horizontally scrolled. Freeplane helps to do this by automatically scrolling to make the node where the cursor is fully visible. Yet the classic book-view with titles and content oriented in a top down direction may be advantageous in situations where you gradually unfold the text and want to easily read back and forward.

On the left and right side are two example maps which at first glance may appear very similar, yet are very different if you start using them.

  • In the map on the right the content node has been moved below its parent sub chapter (= title) node. The title-nodes have Node style combined. As a result, when the title node is folded (child with content is hidden) it has a bubble and when it is unfolded the bubble disappears. When more sub chapters are unfolded, this gives a structured page like appearance with content separated by chapter headers which can be easily read back and forth - without horizontal scrolling. On the other hand, the user has maximum overview if he folds most of the nodes.

  • In the map on the left the two nodes for title and content are combined in one node: title and content are displayed in the Core and Details fields respectively. This has the advantage that node core can be styled with a colour, bubble, icon etc. to make the title stand out. And the text in Details can be formatted as a paragraph in a word processor. The result is an appearance which is very similar to a named paragraph of a book. The details field could be hidden and displayed in a tool tip, which is equivalent for the folding discussed above.

If the two maps are compared one can conclude that the view of the left map is relatively static. The view of the right map is more flexible. If in the right map you select a chapter (e.g. chapter 2) and then in the menu bar click the icon "Unfolds all selected nodes and their children", all text becomes visible as in the view of the left map. In many cases this is not what you want and then you could select a sub chapter and only unfold all text of this subchapter. From these examples it is clear that it is possible to implement book-like view in different ways, with different characteristics.

When implementing a map with tutorial information it is a choice if and when the hierarchical relations should be as prominently left-right oriented as possible or if, for practical reasons or taste, children with content could be shown below parents with titles (right hand map); or alternatively if the mechanism with core-details (and hiding) are used (left hand map).

Note that when viewing the reference through the Internet the look and feel is less and some features are not available (e.g. the predefined filters and the Freeplane menu's). If you use the reference from the Help, the look and feel is optimal, but the options are restricted to read only. Only if you load the reference as a .mm file in Freeplane, alle functionality is present.

Information management

Freeplane can support organizing, managing and accessing information. With the add-on IndexFile you can turn a clasic file system into a flexible system for information sharing and working on dossiers in teams. Read more ...

Docear Academic literature suite

Docear supports in doing all the tasks related to literature management:

  • Finding new literature (searching and exploring)
  • Organizing literature (reading, annotating, and retrieving)
  • Creating your own literature (drafting, writing, referencing, and publishing) Docear is going to be inegrated with Freeplane at the end of 2011.

Special

Floating nodes

Floating nodes come in sorts. The most easy to use is the free (posional) floating node which is created by ctrl+double clicking a free area of the map. It is handy like a post-it to gather unstructered ideas in a brain storm. They differ from the post-it because it is possible to start an independent hierachy of nodes within the cloud of the post-it node. These post-it nodes can be susequently connected to the hierarchical nodes by dragging and dropping it on the node of your choice: it will become a child node of this node. Below you see other types of free nodes as well. The formatting of a floating node is determined by the system style Floating node. This standard style can be edited to hide the cloud, to show the edges of children, color and more.

General examples

Multiple sorts of floating central nodes

Floating Nodes in DigitalLogic






Free positioned versus floating nodes
Behaviour of free or floating nodes There are several ways to make independent or semi-independent groups. The group free 1 consists of a free positionable node with free posistionable children and regular grand childern. To make the group called free 1:

  • define a free positionable parent node (free 1).
  • define its children.
  • select all children, next choose Edit > Free positionable node; (this makes appear all nodes in a pile, on top of each other)
  • set the childrens edges to visible (do it a once, keep the selection; it may be handy to define a style for this)
  • drag each child from the pile to its wanted position
  • define the children’s children – if you want them

Open the mind map on the right and read the text hidden in the root node for peculiarities of the groups free2, free 3 an free 4. For example, group free 2 is a copy of free 1, but is not the same...

Calculations with formula plug in

Iron Sulfate Production Calculations Iron_Sulfate_Production_-Calculations_with_Formula_plugin(AAGG_-_andressf).mm

Iron Sulfate Production-AAGG




Conditional styles

Example concept map





Summary nodes

Example summary nodes





Writing with Freeplane

Writing_an_essay_with_Freeplane

Novel Writer's Notebook: A sample map for writers

See node The making of this documentation in Freeplane's Help > Documentation for an example how to create a documentation mind map. See also Floating nodes above.






Developing a video script with Freeplane

http://www.freeplane.org/mapsOnline/?map=WhyFreeplane.mm

Developing a script for a film or video is a creative process in which the ordering and content of the image and audio parts are changed continuously. The mind map on the right side is being used to develop the introduction video WHY Freeplane. The left side of the map contains the structure underlying the video. At a certain level each structural part ends in a narrative and a series of actions on the screen. The narratives have been given style Narrative. You can use filtering for “style” equal to “Narrative” and with condition "do not show ancestors" to see all narratives in a linear chain. If you unfold a narrative you see a sub tree of actions taking place on the screen during the narrative. Because filtering is not possible on-line, see here for the filtered list of narratives.


Problem solving using Freeplane

For the concepts of tool maps and work maps see page Freeplane and problem solving.

Publishing multiple maps in one Java applet

Freeplane lets you export a map for publishing it on Internet or Intranet. If you have multiple maps to publish and maintain, it is more economic to use the procedure described here. The maps in Freeplane Tutorial Extensions are published in this way.

Other

Animations

The following are some examples of animations. They were made in Dutch for FP 1.1.3 and need to be adapted to 1.2 and translated in English.

User forum

Open forum Freeplane for questions and discussions.

Links

Some free icons

Some very simple scripting examples

Other

This page contains a gallery of screenshots showing the features of Freeplane, and all the nice things you can do with it.


See the discussio page for more details on how you can help here


Note: You might want to check our [External object resize File:Mezer_09-18_15-46-25.png | External object context menu

File:Contact_sc_1.png | Organization of contacts File:Contact_sc_2.png | Editing a node File:LaTeX_Equations_in_Freeplane.png | Doku map for the use of LaTeX in Freeplane (Download [File:Freeplane LaTex.mm](Mind_map_gallery](File:Freeplane_LaTex.mm](Mind_map_gallery.md)_if_you_want_to_upload_real_maps_(not_only_screenshots_I_mean).

<gallery_caption="Freeplane_features"_widths="150px"> File:Mezer_09-18_15-57-23_resize.png.md)

Here are a few screencasts of Freeplane in action.

I would highly recommend screencast-o-matic for recording as it works on every platform with Java installed.

How to Vids

*How to search across all open MM files [*How to use outline view http://www.youtube.com/watch?v=aAc8FYUeQAU *How to search and sort [*Getting FP running on Fedora 13 was not as straight forward as I would have liked but it works (obviously) http://www.youtube.com/watch?v=BoGcFq0SiWA *Command line to search within .mm files [===how to get freeplane to run as portable application=== It takes a bit of time so plan accordingly. Total start to stop for me around 2 hours with no (real) errors.

*step 1 http://www.youtube.com/watch?v=1V2PMYc5tbU step 1 installing portable apps *step 2 step 2 installing java *step 3 step 3 installing Freeplane *step 4 final test... freeplane running off USB *

user error vids

You need to embed images to make them resizable. I missed that part... [==question vids== *How to add labels? http://www.youtube.com/watch?v=9BJSVXYltcQ

request vids

*Open many MM files at once [==bug reports== If you login to SF via Open ID the links from within FP will not work http://www.youtube.com/watch?v=L3pdeLxy_UY

competitor

Freemind vs Freeplane [http://www.youtube.com/watch?v=T9uIA8JLiS0]

Because of spammer attacks, editing of this wiki is now only allowed for registered wiki editors also called Administrators. If you want to become a wiki editor, write to the Freeplane team.

Problem solving is one of the most important human activities. Here comes information about a powerful method for computer aided problem solving.

What are the basic ideas?

The method combines two basic building blocks:

  • problem solving tools and
  • Freeplane mind mapping software.

Problem Solving Tools

These are things like asking questions, creativity techniques like brainstorming and looking for analogies, and so on. Using the right tools is the key to successful problem solving, and we will provide a large, powerful repository.

Mind Mapping Software

Mind mapping software is very flexible when it comes to processing ideas: collect thoughts and arrange them in different structures, change between detail and overview, navigate through large amounts of information, combine words and images, allow jumps from one idea to another, add tables and lengthy text notes... Try all this with usual text processors or spreadsheets – mind mapping software simply does a better job.

Using two mind maps

  1. applet|title Tool Map: Problem Solving Tools|Tool Map: Problem Solving Tools
  2. applet|title Work Map: Problem Solving|Work Map: Problem Solving

With these ingredients, you can tackle a problem by using two mind maps: one 'tool map', prepared in advance and containing a large collection of tools, and one 'work map', where you work out a solution for a given problem. While working on the problem, you can use the tool map in different ways:

Get inspiration from the tool map. Your tool map can contain dozens and hundreds of items that support problem solving. Just by browsing through this massive repository of help, you may get new ideas.

Drag and drop elements from the tool map to your work map. This is a crucial idea. You can use prefab tools and apply them in your work map. Here are some examples:

  • Use lists of useful questions, like the well-known collection of w-questions: What? Why? Who? Where? How? When?
  • Use a step-by-step plan to tackle a problem, like Identify the problem Define alternative goals Explore possible strategies Assess and act Look back and learn. The starting letters of these stages nicely add up to the word IDEAL (authors: Bransford / Stein).

Ignore the tool map. In earnest: If there's no need for support, just go on with your work. Stifling ideas just to enforce a formal concept is arguably a bad idea. Beside this flow of ideas from the tool map to the work map, there is the opposite direction: Whenever you face an obstacle in problem solving, you can exploit this opportunity (it really is one) to develop useful new tools and add them to your collection.

What the method can do

Problem solving will always remain a challenge, and the method just outlined won't transform you instantly into the perfect problem solver. But it can lead to massive improvements:

Instead of getting lost in a maze of ideas, collect and arrange your thoughts by using prefab mind map structures.

Instead of shallow analysis (or none at all), choose from a wide range of powerful analysis tools.

Instead of merely collecting the obvious or the absurd, use much more effective creativity techniques.

Instead of being limited to a fixed set of problem solving tools, create and expand your own collection.

The method was designed from the start to be of high value and of no cost.

Step-by-step instructions:

1.Download Freeplane mind mapping software and install it on your computer.

2.Download the tool map and the work map

3.Open both maps by double-clicking on them.

4.Start working on the problem. You'll find some extra tips in the work map.

5.When necessary, get inspiration from the tool map. Again, there are lots of hints in the tool map.

6.Drag and drop tools from the tool map to the work map whenever you like. There are several ways to do this: Arrange the two Freeplane windows like tiles, or use ALT+TAB to change between the two maps – this works even while the drag and drop takes place.

7.Adapt your tool map to meet your personal needs. This is the most important step! The tool map contains several links to tool collections on the internet.

Some observations from experience

It may be a good idea to have several tool maps, for example a separate map with specialized tools for each of your main topics of interest.

Freeplane supports one-key-formatting of mind map nodes, just by pressing the function keys. This helps to hightlight the structure of the work maps.

A public library of tool maps seems a great idea.

Freeplane features you were missing in FreeMind

This page lists important features of Freeplane that are not available in FreeMind.

  • Simple script invocation
  • Simple hotkey assignment
  • add-ons (packaged scripts, see below)
  • Format panel
  • Formulas
  • Node formats
  • Attributes panel
  • Integration with Docear
  • 1.3.x: Inline LaTeX ("LaTeX in core") with LaTeX syntax highlighting editor
  • Node details,
  • Freely positionable nodes,
  • Summary nodes
  • (conditional) Styles
  • Different export features, including scripted ones
  • Approximate search
  • (slightly) better printing support
  • Hyperlinks available in nodes and in attributes

Add-ons

  • Several add-ons are available, including:
    • Pack and Go (ability to pull all FP dependencies into a single zip file for sharing with others)
    • Study planner (tool for assisting with the efficient use of study time, including pomodoro timers
    • Getting Things Done (task management application)
    • Wikdnode (comprehensive set of node text editing tools)
    • Wikdshell (test platform for building and testing groovy scripts)
    • Developer Tools
    • Additional icon libraries
    • Insert InLine Image (an alternative way of bringing images into FP and attaching them to nodes via details or node core)

Migrating from FreeMind to Freeplane

  • don't try to copy+paste from a FreeMind instance to Freeplane; instead open the FreeMind map in Freeplane (in another tab) and then copy+paste from inside Freeplane!
  • Freeplane has Excel-like features and formulas:
    • numbers are recognized, i.e. "001"->"1" => avoid this by putting a quote (') at the beginning of the node text
    • same thing for dates
    • Formulas start with a '=': to avoid treating a node as a formula, (again) put a quote (') before the '='

Features available only in FreeMind

  • Collaboration mode

A "light" version of Freeplane called Freeplane for Windows Mobile is available for Pocket PC running under Windows Mobile OS.

This version is really nice to read a Freeplane mind map on your Windows Mobile device and allows you to make some basic changes to the map.

Yet Freeplane for Windows Mobile is available in english only.

The Windows Mobile version of Freeplane can be downloaded here.

This page explains how to install Freeplane for the Ubuntu operating system, there are 3 main ways to proceed.

First: check Java is installed

Make sure Java is installed:

  • Choose Applications > Ubuntu Software center
  • Type in the search field: Java
  • In the list that opens, choose JDK Java 6 Runtime
  • If you see "Remove", Java is already installed. If you see "Install", click it to install Java.

Option 1 : install from the official Ubuntu software repository

  1. Freeplane is packaged for Debian/Ubuntu, you just need to run: apt-get install freeplane

If the Freeplane package for your distro is out of date, see option 2 or option 3 below (it requires download from SourceForge official Freeplane project hosting).

Option 2 : install with .deb file

For every Freeplane release, starting with 1.6.5, there is a .deb available which includes all libraries, so it works on Debian/Ubuntu.

  • download the generic .deb: go to http://sourceforge.net/projects/freeplane/, click "Browse all files", navigate to "freeplane stable"

  • download freeplane_+upstream-1_all.deb

  • install it using dpkg -i *.deb

  • this will create a menu entry for Freeplane, mime type mappings etc

  • you're done ;-).

Option 3 : install with the binary package

  1. Download Freeplane binary package
  • For newest version goto http://www.freeplane.org/preview/ and download Freeplane_bin-XXXX.zip, in which XXXX is a shown version number.
  • Or for the official version goto http://sourceforge.net/projects/freeplane/ and press download.
  • Then choose Open with Archive manager, and press OK

  1. Extract the freeplane directory
  • In the download window press extract, select the location (e.g. Documents) and press Extract again.
  • Then open the the directory where you extracted freeplane (Documents) and open the newly created Freeplane directory.

  1. Then run freeplane
  • In the extracted directory, double-click on Freeplane.sh and select Run (or run in terminal window). Now Freeplane opens and you can use it.

**If you want you can customize the installation as follows.**
  1. For easy access, add Freeplane to Applications > Office:
  • Right-click Apllications and select Edit Menus
  • Select Office (left) and select Add Menu item (right)
  • Type a name, e.g. freeplane
  • Browse to the directory with freeplane, click freeplane.sh and press ok
  • With freeplane selecte, press Properties
  • Click on the icon on the left and browse via Documenten > FreeplaneXXX to the file freeplane.svg; and select it. Now freeplane is added to Office with the freeplane icon.

  1. For faster access, add the freeplane icon to the toolbar:
  • Goto Applications > Office and right-click Freeplane.
  • Select add this launcher to toolbar.

  1. Now you can start freeplane by pressing its icon in the toolbar

Freeplane uses a distributed revision control system named git. Use this instead of the source packages that are contained in the releases if you plan to take up coding.

Our master repository if available at https://github.com/freeplane/freeplane

Our main goals for Freeplane are:

Better Mind Map editor than FreeMind

*Better usability, *More features, *Frequent releases

through better project organization,

*Big and effective developer Team. I believe that much more people were willing to contribute to this extraordinary sensible and helpful project as a mind map editor. *So the development speed can be increased and time between the releases can be significantly shortened. *People like you and me systematically contributing to the project should get more influence on the project decisions. *There should be clearly communicated and broadly discussion of the further development ideas, steps, goals and visions. *A strong project Visions and the freedom to implement new ideas

better architecture and design

*current FreeMind implementation is hard to extend and maintain. I have tried to collect the most critical points here. Such refactoring is not easy, but I think if we want to give new developer a chance to make good contributions, we must provide clear architecture and design first.

A large, friendly community in which your voice will be heard.

In this forum storment74 (Stefan) posed some questions on how to improve the menu structure of Freeplane.

In the following I would like to invite you in helping to think over the menu structure of FP. I will follow a process way of thinking, and ask you not to jump to the end result. Also, no decisions are final until the last step, the extreme being the decision that nothing will change if the end result is not evaluated as better than the current situation. Besides, it is to the programmers to make the decision to implement the result.

Once context menu’s are in place one might ask why one would need a top level menu. Fundamental and practical reasons I could think of are:

  • To create toplevel objects. Once created each has a context menu for relevant functions of it, including creating the components (subobjects) it exists of and deleting itself. Each subobject has its own contextmenu.
  • To apply a certain function simultaneously to a set of selected objects (e.g. delete object); however this functionality could also be connected to the contextmenu (e.g. not only delete itself, but all selected objects).
  • To help new users orient and find their way without knowing which contextmenu’s might exist and how to select them. This could be solved with a toplevel menu containing a hierarchical list op contextmenu’s, possibly with descriptions how to find/select and use these.
  • People expect particular menu’s because familiarity with common programs.

Keeping this in mind I propose to evaluate the current menus and first strip it to the bare minumum from a functional point of view, before adding duplicate menu items for practical reasons. I also propose to evaluate the possible advantage of applying the mechanism of the node Properties Panel more broadly as a priciple to give intuitive, quick and broad access to related functions. I propose to adress these subjects one by one, in a process like way.

Object hierarchy showing menus and context menus in Freeplane

[thumb| [Media:FP-object-hierarchy_02.mm| This mindmap ]]

This mindmap shows the the logical objects in Freeplane and their relations. Each object can consist of child objects, indicated by has_a relations. Some of these child objects are menus. Context menus are menus which open if right-clicked on the parent object.

The mindmap shows a.o. which objects have contextmenus. The benefit of context menus is (1) they only show functions which apply to the parent object; and (2) these functions are available within 2 mouse clicks.



Process step 1

Goal: strip all functions from the main menu bar which concern a selected node, node component (text, details, attributes, note), edge or connector. Kept are functions related to the mindmap as a whole.

This mindmap contains the starting point, the items of the main menu bar of FP 1.2.3_03. With green OK-icons is shown which menu items are top level functions which have effect on the mindmap as a whole and not on specific subobjects. With numbered icons is shown which items concern subobject: 1 means node object, 2 means edge object and 3 means node text object. If two icons are shown, there are two possibilities. A question mark icon symbolizes an item for which a decision still has to be made.

parameters startCollapsedToLevel=1

This mindmapis a proposal is from ldmpub-nospam for the file menu. parameters startCollapsedToLevel=1

This mindmap shows the main menu stripped from items relating to subobjects (numbered icons). Different branches show the items related to node object (=1) the items related to the edge object (2) and the items related to node text object (3).

parameters startCollapsedToLevel=1

Before proceding to the next step, I would like to ask if you would put the icons in the same way ? How do you position the question marks ? Please, give your comment in this forum.

Procedure for contributing

  • Please, give your comment in this forum.
  • Small modifications proposed in the forum will be added by the moderator to the relevant mindmap.
  • Mindmaps can be uploaded to this wiki. If you do, publish the map in the discussion page, last contribution on top. For each upload published in de discussion page, specify iso-date followed by your name and keyword of the map content. Next give a short description of the publication and a link to the uploaded mindmap

[[:FreeplaneWiki.mm |applet| Index wiki ]]

Because of spammer attacks editing of this wiki is allowed only for registered wiki editors.
  • If you want to become a wiki editor write to Freeplane team.

If you want to review existing pages or add new pages to the Freeplane Wiki,
please see the help there : http://www.mediawiki.org/wiki/Help:Contents.

If you want to add a map like the one on the right:

  • download a jpg image file, e.g. FreeplaneWiki.jpg
  • download the mind map, e.g. FreeplaneWiki.mm
  • Add the rule: [[File:FreeplaneWiki.jpg|thumb|right|<mm>[[:FreeplaneWiki.mm |applet| Index wiki]]</mm>]]

Please login into this wiki before editing wiki pages.
Your source forge account is not valid here,
but it is recommended to use your source forge user name here if you already have a source forge account.

For help with editing pages on this Wiki, please visit MediaWiki's Editing Help page.

If you are having questions, or are experiencing problems there is information in the documention and on the internet. In the following is described where to find the information for different versions of Freeplane.

Freeplane 1.1.x

Documentation in the program

*Mind Map in English *Its translations as html in many languages *Menu reference in many languages

Documentation in this Wiki

*the Troubleshooting page *the FAQ (Frequently Asked Questions)

Freeplane Release Process

Releasing a stable or unstable version of Freeplane is a two stage process. Each new test version is uploaded to a testing area prior to release. When one or more tester confirms that the test version has introduced no major bugs, it will be uploaded as an official release to the Sourceforge files section. Otherwise, a new test version will be uploaded. At the moment only team members and selected testers are alerted when new test versions are available, but you are free to periodically check and download any new versions in the testing area.

Testing an official release

If you want to test an official Freeplane release, here's what to do:

  1. Download the latest release

  2. Create a fresh map or use a testing map, and perform as many functions as you can, via both the menus and hot keys. Particularly try out any new features. Jot down any problems or bugs you encounter and record what you were doing at the time. (In the future there will be a systematic test map and/or unit-tests available).

  3. Report any problems via the bug tracker (under Project-->Bugs). Please include as much information as possible:

  • what you were doing
  • the behavior you encountered
  • error or warning messages you got
  • your Freeplane and Java versions
  • your operating system

ALWAYS SUBMIT:

  • a description of steps to reproduce the bug
  • the actual results of following these steps
  • the expected / desired results

Testing a test version

If you wish to test a bleeding edge test version, replace step 1 above with one of the two following options: you can either download the latest binary archive from the testing area, or you can check out the latest release from the development repository, and build it. See the How to Build Freeplane wiki page for more information on getting the source and building binaries.

Additionally, if you're testing a test version please complete the smoke test, until unit-tests are available to carry out these tests.

Testing the development version

If you want to test the next Freeplane version developpers are working on (also called preview version), please refer to use and download preview version.

Introduction

The add-on dView(indexfile) supports adding annotations, hyperlinks and reminders to file names in a folder structure. For this a specialized dashboard mindmap must be put into the folder to index. When this dashboard is opened and button Index is pressed, a hierarchy of nodes with hyperlinks to the subfolders and files of the indexed folder is generated. Next one can add annotations, add hyperlinks to other files or websites, and add reminders (clock) for file related actions. If email adresses are registerd, with one click all users of a particular dashboard can be sent a group-email. The resulting mindmap can be shared with other users, which can navigate it without having to install the add-on. With special options set the add-on can be used with MS Sharepoint or on the internet, and/or be used to generate NATO-compliant file names.

Installing add-on diView(indexfile) results in a new menu Extra > diView(indexfile) with different dashboard types to choose from: basic, dossier, meeting, theme, organisation, person and folders, see the descriptions below. Besides it has an extensive Help.

If you have Freeplane installed, for a demonstration of all dashboard types download and unpack this demo and open file folders.mm.

For a video introduction go to youtube

Basic dashboard

Fig.2 Annotations Each dashboard has a node called Index. When this node is clicked, a hierarchy of files, folders and (other) dashboards is generated which corresponds to the content of the current folder. The depth of the indexed hierarchy can be limited. Each generated node contains a link to open the folder or file it represents. In this way the dashboard can be used to navigate to information in an easy and fast way, especially if used in combination with Freeplane's find and filter methods. Besides main links can be annotated with text, hyperlinks to other documents or internet adresses and can be given reminders (timers) signalling planned document related actions, progress indicators, arrows etc. And generated links can be copied and pasted into e.g. an email, in which case relative links are converted into absolute links.
It is possible to exclude folders with irrelavant information, or stop indexing at a particular folder name, depth or number of files. There are different options for sorting and management information concerning the number of files, folders and dashboards is displayed. Also the maximum found length of pathnames is displayed, as in WindowsX this is limited to 256 characters.

Folder dashboard

Fig.2   Folder index A folders dashboard is a limited version of a Basic dashboard. Indexing generates only folders and other dashboards, not files. By default the number of hierarchical levels is set to a large nuber, to give a full overview of the subfolders. Hence a folder dashboard can be used when discussing and improving a folder structure, or when developing a new structure from scratch.

Fig 2. has been generated by storing a dashboard of type Folder into the main folder. Next the little button of node Index was pressed which ceated the subnodes of Index. If a child node of node Index contains an icon other than the folder icon, this depicts that this folder contains a dashboard file of a particular type (organisation, person, theme, dossier or meeting). Below we will discuss these types.

Dossier dashboard

Fig.3a Dossier template Fig. 3b Dossier dashboard
Dashboard Dossier extends the Basic dashboard with nodes for management information and use.

Figure 3a shows that in node Management you can put information like the name of the organisation, the email address of the owner (information manager) and status information. This information can be used to automatically add metadata to document names according to e.g. the NATO statndard for file names. Or by clicking the owner's email icon, you can automatically open an email with the email adress of the owner filled in.
In node Users main users and passers by can register their e-mail addresses. Next all registered users can be send a common email by clicking the email icon in node Users. Of course one can add process information for visitors of the dossier, for example in floating nodes which behave like sticky notes.
Node Favorites is meant for keeping links to documents, applications or whatever is important to have at hand when using the dossier. Finally, you could support new users by summarizing the goal of the dossier and adding links to e.g. the three most relevant documents.

Meeting dashboard

Fig.4 Meeting dashboard A meeting is a specialisation of a dossier. A meeting folder has years as subfolders and contains subsubfolders with the month and day of a meeting, see Fig.4. The documents of the meeting are contained in the subsubfolders. Node Meeting above the star shows the last meeting folder, with the current meeting documents. This content is refresched when node Index is clicked. N.B. It makes sense to use standard, short document names like Agenda and Minutes. In that case freeplane filtering can be used to display e.g. (only) all Agenda documents.

Organizing dossiers and meetings in themes

Fig.5  Theme dashboard
Basically a theme is a container for dossiers and/or meetings, see Figure 5. The main difference between a dossier and a theme might be that the owner of a dossier could be held responsible for the documents contained in the dossier subfolders, while the owner of the theme is responsible for the metadata of the theme dashboard file only. Practically a theme is implemented as a dossier with a different icon, so both could be used interchangeably. Like a dossier a can have one or more subdossiers, a theme can have subthemes. By default the depth of a theme dashboard is limited to e.g. 3, but this value can be changed.

Organization dashboard

Fig.6 Organisation dashboard
Dashboard organisation implements a dashboard for displaying an organisation with suborganisations, themes, dossiers and meetings. A typical suborganisation is the staff, in which each member could have a personal folder.

When the Index node is clicked, suborganisations, themes, dossiers and meetings are displayed, see Fig. 6. By default the hierarchical depth is limited, but the indexed depth can be increased.


Person dashboard

Fig.7 Person dashboard In general each staff memeber needs a folder/dashboard with handy access to all information needed in dayly work. This folder would contain work in progress not ready to be shared and shortcuts to relevant dossiers and meetings. It could contain favourite hyperlinks to other information or programs too. In this way the staff member can do all his work from his personal folder. The Person dashboard provides a dashboard view for this, see Fig. 7. N.B. It is important to know the user can choose to work from the personal folder only or also use his personal dashboard. A fast way to get in the personal folder is by clicking link Index.

Virtual external folders

In Fig.7 node Dossier1 displays not one but two icons. The second icon signalls that it links to a folder which could be outside the folderhierarchy, on a different disk internet or intranet. In fact the superfolder contains a shortcut to the external folder and when indexing this shortcut is recognized and displayed. The shortcut is recognized to be a a link to a dashboard type of hortcut if its name is compliant with the name of a dashboard.

Image previews

Image previews and addon Insert inline image Indexed images optionally can have a preview. The user can set the size of the preview. Double clicking opens the full image. Each preview has a button to open an inline image by means of addon Insert inline image. See the latter addon for details. In other words, dView supports manageing and annotating image directories. There is a practical limit to the number of image files hich can be shown with a preview: the preview images are based on the reduced full memory size of the images and not on thumbs which have a limited physical size.

Hyperlinks to email

The hyperlinks of a group of selected indexed nodes can be copied with one click to the clipboard and pasted into e.g. an email. Also a hyperlink to a selected mindmap and selected node can be copied to the clipboard.

Editing file names

Fig.8 Edit file name If the user option for "file context menu" is set each file link contains a small button. If you press it a context menu will be displayed with options to edit the file name, add metadata, delete the file, add an inline image, see Fig.8. (N.B. These are the only functions of IndexFile which have impact on the files of your folders.)




Making a unique, short file name

Fig.10 Unique file name If documents are kept within a hierarchy and with index files containing contextual information, document titles can be short indeed. If you would move a document without this context to a different surrounding, its meaning might get lost and there there may be name clashes. In situations like this you can automatically add basic metadata by pressing button Add metadata dossier in Fig. 10. Fig 12. shows that three metadata are added: the name of the dossier, the year of the dossier and the (sub)organisation owning the dossier. All this information is taken automatically from the current dashboard file. If necessary you can edit these data as described for Nato metadata.

Complying to NATO filenaming convention

Fig.10 Nato convention If you click the button node Add metadata Nato, a date and a classification are added. In Fig.10 the date is taken from the date the document was last modified. The classification "N" is taken from the field classification in the Management node. In this case the management node contains N which means No classification. You can edit the date and classification in the node text and then press button node Rename file to apply it to the real file.


Creating dashboard names

An index file which is saved with its template name, e.g. (i)_dosier, will not be shown in the generated index. To make these files appear in the Index hierarchy it can be renamed into a dashboard name. An example dashboard name for a dossier is:

  • (i)_myDossier(2014--ING-finance)_D

With this name it will appear in the index hiearchy of an index file higher in the folder structure with the icon for dossier (D).

Each time the small button of node Index is clicked, the default dashboard name is added to the clipboard. If you save the Index file and press Ctrl-V (paste), this name is automatically added as a new file name.

The metadata in the dashboard name are useful to find the dashboard, even if a the containg folder is moved to a different location. Once the dashboard is found, also the documents can be navigated to. This is why the documents themselves don't need to have metatdata and can have a short title as a file name.

N.B. In a multilingual environment is possible to have a dashboards for different languages in the same folder. In that case the dashboard name is extended with a (Freeplane) language code, e.g.:

  • (i)_myDossier(2014--ING-finance)_nl-D In preferences this multilangual option can be set. Whenset the language code is automatically added.

Using IndexFile with Microsoft Sharepoint

Sharepoint uses open and closed libraries to store folders and files which can be accessed with read only or write access rights. The add-on can be used to index these libraries too. Folders with dashboard files could be moved to a Sharepoint library and work there if opened with write access rights. In case of read-only rights, Sharepoint opens a file in a Temporary folder, not in the original environment where the file is stored. This means that relative hyperlinks in Freeplane do not work. If preferences are properly set dView automatically uses absolute links when in Sharepoint. The link of node Index directly opens the main folder in Explorer mode. In Sharepoint several clicks are needed to do the same. In addition it is possible to publish (copy) a file from an open library with a single click to the corresponding open library; the publication date/time is stored as a child node. Finally each dashboard in the open library has a hyperlink to the closed library and vv. This speeds up moving from the one to the other. Of course this works only for people having access rights.

Preferences and options

Fig.11 Preferences IndeFile comes with a large number of options which can be set by the user. As an example, the number of files and/or the depth of the folder hierarchie can be preset to some value. This is useful in situations with an unknown, big number of files. For more information, see menu diView (IndexFile) > Help.


Menu diView

Fig.12 Menu IndexFile When the add-on is installed, menu di-View is added to menu Tools. Here you can select the diView Help or one of the templates for Organisation, Dossier etc. Help describes how to implement the use cases described above. If the add-on is not installed, you can still use dashboards created by another user, as they are mind maps. Special functions like refreshing the Index and triggering a group mail are not active however.



Translations

At present dView(ndexfile) is available for English, Portuguese and Dutch. Menu dView > Help contains instructions how you can translate menu's, templates and the Help file to other languages.

Installation and Help

There is a map with Online help describing all options. This is the same Help file available in Tools > dView > Help which is added to Freeplane if you install the addon. So you don't have to install the addon to study all its possiblities.
The dahboards generated by dView can be viewed as a regular mind map. It is not necessary to install dView for this. To use the indexing function of dView, both Freeplane and addon dView must be installed. Installing Freeplane is possible on Freeplane's Home page. To install dView, go to downloadpage for addons and download and install add-on dView(indexfile).

If you have Freeplane installed, for a demonstration of all dashboard types download and unpack this demo and open file folders.mm. It displays the interactive use case in which all dashboards are used in context, the same as presented in the viedo on youtube. If you have the add-on installed you can experiment with adding folders and files and generating new indexes, but only if your language setting is English. (The demo can be made to work interacively for other languages bij changing the language setting in the root attributes.)

Boost your brain with Freeplane
Freeplane であなたの脳を高めてください。

Download Freeplane|link=http://sourceforge.net/projects/freeplane/|Download Freeplane

Download Freeplane now!
すぐに Freeplane をダウンロードしてください! : English

Download Freeplane now!
Freeplane プロジェクト日本語トップページ - SourceForge.JP! : sfnet_freeplane : Japanese

What is Freeplane?

Freeplane は、何ですか?

Freeplane is a powerful and free mind mapping application. It is a redesigned version of the well known FreeMind, and is created by one of FreeMind's key developers. The software is written in Java, and supports any platform capable of running current versions of Java, including:

Freeplane(フリープレーン)は、パワフルで無料のマインドマッピングアプリケーションです。それは有名な FreeMind の改良 (再デザイン) されたバージョンで、FreeMind の重要な開発者のうちの1人によってつくられました。ソフトウェアは Java で記述されて、Java の現在のバージョンを走らせることができる、どんなプラットフォームでもサポートします:

*Microsoft Windows *Mac OS X *Linux / BSD / Solaris *Portable Freeplane for Windows (runs from a USB drive) : ポータブル Freeplane (USBドライブからの起動)

Freeplane is available in several different languages. The currently available translations are: English, French, German, Italian, Russian, and Croatian.

Freeplaneは、いくつかの異なる言語で利用できます。現在利用できる翻訳は以下の通りです:英語、フランス語、ドイツ語、イタリア語、ロシア語、クロアティア語。

日本語 : Download Freeplane now!
Freeplane プロジェクト日本語トップページ - SourceForge.JP! : sfnet_freeplane : Japanese

Freeplane is released under the GNU General Public License (GPL). : Freeplane は、GPL 下でリリースされています。

Older news

Getting Freeplane : Freeplane を得ること

First make sure you have installed a recent version of Java, 1.5 or above.

To download Freeplane, go to the SourceForge page, and click on the "Download Now!" button.

To run, simply extract the downloaded zipfile, and run the "freeplane.bat" file (Windows), or the "freeplane.sh" file (Unix) file.

最初に、あなたが Java、1.5以上の最近のバージョンをインストールしたことを確認してください。 *動作にはJava Runtime Environment(JRE) が必要です。J2SE の JRE(または SDK)

ダウンロード Freeplane、SourceForge page, へ行き、そして、「すぐにダウンロードしてください!」ボタンをクリックします。 : こちらは、English Site になります。 *日本語 : Download Freeplane now!
Freeplane プロジェクト日本語トップページ - SourceForge.JP! : sfnet_freeplane : Japanese

起動するために、単にダウンロードされた zipfile を展開してください。そして、「freeplane.bat」ファイル(Windows)を走らせてください、さもなければ、「freeplane.sh」ファイル(Unix)を走らせます。 *Freeplane のインストール方法 - Freeplane - SourceForge.JP : sfnet_freeplane : Japanese Ubuntu 9.04 Linux 版のインストールが、でています。

Freeplane features : Freeplane 機能

A New User Manual is coming. Read and contribute. *新しいユーザーマニュアルはこちらにあります。読んで、使用してください。(英語です。)

The most important new features : 最も重要な新機能

*Better inline_editor for all plain text nodes **すべてのプレーンテキストノードのためのより良いインラインエディタ。 *Edge-like connectors (available from connector pop-up menu) **エッジ コネクタ (ポップアップメニューからコネクタ入手可能)。 *External objects: External bitmap and SVG images can be attached using menu Insert->External object and resized **外部オブジェクト: 外部のビットマップ、そして、SVGイメージは、リサイズと挿入-外部オブジェクトのメニューを用いて付けることができる。 **Image size can be reset by double clicking on the bottom right corner ***イメージサイズは、右下角をダブルクリックすることによってリセットすることができます。 **Images can be scaled by dragging the bottom right corner ***画像は、右下角をドラッグすることによって縮尺することができます。 *Good Scripting support: **良い Scripting サポート: **New scripting API ***新しい API スクリプト。 **Loading and execution of external groovy scripts ***外部の型にはまったスクリプトの積載と実行。 *Insert image dialog and insert external object dialog have file previews **ダイアログイメージの挿入とダイアログの外部オブジェクト挿入は、ファイルプレビューができる。 *F-Toolbar **F-ツールバー (F バー)。 *Find or Replace in all open maps **すべての開いたマップで検索、あるいは、置換ます。 *Full screen mode **フルスクリーンモード。 *Hidden Edge Style **隠れるエッジスタイル。 *Horizontal Edge Style **水平エッジスタイル。 *Hot keys can be set by pressing left mouse button on menu item and holding CONTROL key **ホットキーは、CONTROL キーを押さえてメニュー項目の上で左マウスボタン押すことでセットできます。 *Outline view **アウトライン (概略) 表示。 *Portable Freeplane **ポータブル (携帯型) Freeplane . *Selective paste from edit menu (Paste as...) **編集メニューからの選択的な貼り付け(貼り付け...)。 *Spell checker **スペルチェッカー。 *Structured HTML paste **構造化 HTML 貼り付け。

New filtering features : 新しいフィルタリング機能

*Date based filter

* データベースのフィルタ。

*Filter conditions for numeric values return false for non numeric values

* 数でない値のために間違って戻る数の値のフィルタ条件。

*Filter based on link labels

* ラベルのリンクに基づくフィルタ。

*Filter history

* フィルタ履歴。

*Filter menu

* フィルタメニュー。

*Filter tool bar can be hidden like all other tool bars,

* フィルタツールバーは、他の全てのツールバーのように隠すことができます。

*Filter status is displayed in status line

* フィルタ状態は、線の状態 (ステータスライン) で示されます。

*Filter node text by regular expressions

* 正規表現によるフィルタノードのテキスト。

Other features : 他の特徴

*All backup or autosave files are numbered from 1 to maximum number, the bigger number the latest file. **すべてのバックアップまたは自動保存ファイルは、1から最大数まで数えられます、より大きいものは、最新のファイルを数えます。 *Automatic backup for all loaded files on first save. **自動バックアップは、最初の保存ですべてのファイルをロードしました。 *Backup and autosave use directory ".backup" created in the map directory. **バックアップと自動保存は、マップディレクトリでつくった「.backup」ディレクトリを使います。 *Edit nodes with line breaks in in-line editor (alt+enter to quit , shift+enter for line break) **インラインエディタで改行してノードを編集してください (やめる alt + enter、改行 shift + enter)  (インライン エディタは、プロパティ ウィンドウで値を直接編集できるエディタです。) *Enable link pop-up menu even if neither target nor source node is selected. **たとえどちらの目標もソースノードも選ばれないとしても、関連ポップアップメニューのリンクを使用できるようにしてください。 *Exception traces for internal errors are automatically sent to freeplane team for analysis. **内部のエラーのための痕跡は例外なく、分析のために freeplane チームに自動的に送られます。 *Export Using XSLT **XSLT を使用してエクスポート。 *Hide tabs if only one map is loaded **1つのマップを載せれば、タブを隠してください。 *Hot keys: CONTROL + ALT + RIGHT, CONTROL + ALT + LEFT **ホットキー : CONTROL + ALT + RIGHT, CONTROL + ALT + LEFT . *Icon actions moved in separate menu **別々のメニューで動かされるアイコンの動作。 *Icon toolbar hidden by default **デフォルトで隠されるアイコンツールバー。 *Linking to arbitrary URI integrated **統合[組織化]される URI と任意につながること。 *Links where target or source are selected are found first. **目標またはソースが最初であるとわかり選ばれるところを結びます。 *New icons: 0%, 25%, 50%, 75%, 100% **新しいアイコン:0%、25%、50%、75%、100% . *New navigation actions useful for presentation "next node" and "previous node". They traverse the map in depth-first order. **「次のノード」と「前のノード」のプレゼンテーションに役立つ新しいナビゲーションの動作。  それらは、深い状態と最初の状態の順序でマップを行ったり来たりします。 *Personal modification color can be set in prefeences **個人の変更の色は、好きなものでセットすることができます。 *Plain text search for filter in html nodes added **加えた html ノードのフィルタのプレーンテキストの検索。 *Priority filters based on priority icons **優先するアイコンに基づく優先するフィルタ。 *Text labels can be added to any end and in the middle of any link by link pop-up menu **テキストラベルは、どんな終わりまででも、そして、関連ポップアップメニューによるどんな関連の中央ででも、加えられることができます。 *Text rendering mode use more exact fractional metric based version. **テキストレンダリング(描写)モード使用により正確なメートル法のベースのバージョン。 *The action is also available from pop-up menu **動作は、ポップアップメニューからも利用可能です。 *The attached file can be opened by double click on the image itself **添付ファイルは、イメージそのものを、ダブルクリックによって開けることができます。 *The same zooms applies to all maps **すべてのマップに同じにズーム活用します。 *Zoom keep selected node position **ズームキープは、ノードの位置を選びました。 *Zoom saved between sessions **ズームセッションの間保存される。

Contributing to Freeplane's Development :

Freeplane の発展に関与すること

*Visit the Think Tank

*Have a look at the (preliminary!) Architecture description.

*Some users might be interested in the Translation How-To.

Testing Freeplane : Freeplaneをテストすること

*How to test

*Testing/release policy

Browsing this Wiki : この Wiki を閲覧すること

Many pages on this wiki are tagged with one or more of the following Categories:

*Advanced Users - Documentation for experienced and/or technical users
*Developer Documentation - Information for software developers wishing to enhance or customize Freeplane
*Needs Updating - Pages which contain valuable information, though some of it needs to be updated
*Old Wiki - Pages imported from the previous Wiki which may now be obsolete
*Scripting - Extending Freeplane using Groovy scripts
*Team Freeplane - Freeplane team members and project coordination
*Testing - Details about testing new versions of Freeplane which are under development
*Tutorials - HowTo articles and other "hands on" documentation
*User Documentation - Basic information about Freeplane including usage and features
*Wiki - Help for using this Wiki

Contributing to the Wiki : Wiki に貢献すること

You can subscribe to atom feed to be informed about all changes in this wiki. Using this web service you can get daily e-mail notifications whenever the content changes. The same service can also be used for notifications about any changes to the project pages on SourceForge.

Useful links : 役に立つ関連

*Freeplane SourceForge page with summary on the latest project activity *Freeplane Open discussion forum *Old builds repository of Freeplane *Current test builds of Freeplane *Icons **Silk Icons organized into folders http://www.mediafire.com/file/dy4ynmkvmhz/Silk icons organized.zip **Flags of the world icons organized into folders http://www.mediafire.com/file/nomjzj3wmyw/Country Flags organized.zip

Hint: all of wiki/forum/files pages (and even sections) can be easily followed via newsfeeds, so don't hesitate to subscribe!

Thanks : 感謝

Freeplane team uses:

*YourKit Java Profiler developed and donated by YourKit, for analysis of memory consumption and performance issues *Code analyser stanj4, developed and donated by Odysseus Software GmbH

Freeplane(フリープレーン) Japanese guide(日本語ガイド)

For UBUNTU, see here

'''Update: Freeplane is packaged for Debian/Ubuntu => just run: apt-get install freeplane

The following steps are recommended if the Freeplane package for your distro is out of date:

  1. Download the Freeplane zipfile, and extract its contents to the folder of your choosing (e.g. ~/local/freeplane-xxxx , where xxxx is a version-number).

  2. Create a freeplane symlink to ~/local/freeplane-xxxx:

    ln -nsf ~/local/freeplane-xxxx ~/local/freeplane

  3. (optional) If you have a ~/bin folder which is in your shell path, you can create a symlink to the freeplane start-script:

    ln -s ~/local/freeplane/freeplane.sh ~/bin/freeplane
    If you do that you should now be able to run freeplane from the commandline by simply typing freeplane.

  4. Finally, to add an icon which will show up in your applications menu, save the following text to the file ~/.local/share/applications/freeplane.desktop :

[Entry](Desktop)
Version=1.0
Encoding=UTF-8
Name=Freeplane
Exec=/bin/sh /home/YOUR-USERNAME/local/freeplane/freeplane.sh %f
Terminal=false
Icon=/home/YOUR-USERNAME/local/freeplane/freeplane.svg
Type=Application
MimeType=application/x-freemind
Categories=Application;Office;
GenericName=Freeplane
Comment=A free mind mapping tool

(for more details on why adding this file works, see the XDG Desktop Menu Specification, which is followed by all major linux desktop-environments)

Now, any time you wish to update your Freeplane application, just repeat steps 1 and 2.

-- Eric - begin --

Freeplane as a free flat surface

When I first he ard abou t the new name, I didn't think about an (air)plane but about the geometrical figure of a plane, as a very broad synonym of a map. My graphical abilities are very limited but this is w hat came to my mind:






a plane in empty space, with a stylized mindmap hovering over this plane and a sun rising over the plane, casting a shadow of the mindmap. As for the colors, I'm not so sure but a blueish darkness for the space and yellow for the sun sounds rather logical, the plane could possibly be a shade of grey and white, whereas the map itself should be colorful to make a contrast to the rest.
-- Eric - end --

-- Dimitry - begin --

What is a Freeplane

Honestly I have never thought about the mathematical plane in connection
with the Freeplane before, although I like this nice abstraction I found
in your mail. I like the name "Freeplane" because it combines all things
together:

*I am thinking about the air plane as the fastest transport vehicle and

about freedom of flying. I think about a kind of "bird eye perspective"
one can develop for his ideas and knowledge. I think about the jazz
standard "Take the A-Trane" and the motto "take the free plane".

*I am thinking about plans because I know that the FreeMind is already

used as a tool for project planning.

And the idea of a bumble bee as a central figure for the project
including its logo, icon and splash screen combines flying, use of
powerful wings, stripes typical for plan sheets, but it is also a piece
of nature which can look lovely and friendly.
Image:Http://upload.wikimedia.org/wikipedia/commons/thumb/c/c6/bombus september 2007-1.jpg/748px-bombus september 2007-1.jpg
Wikimedia and License link

-- Dimitry - end --

-- Predrag - begin-

My vision of Freeplane

I made one sketch with hand and I 'm sending to you now. I'm reading Eric's text now and I thinking about colors.
I will try prepare some combination ( palettes ) and I will put my preposition here.

-- Predreg -- end --
-- Ryan -- begin --

A bird's eye view -- or in this case a bee.

Good work, Predrag. Here is my contribution. Since other non graphic designers are prepared to offer their sketches, I shouldn't be too embarrassed to do the same. The first image below shows the original idea for Freeplane - as a rocket overlooking the planet: that represents the relationship mind mapping software has to knowledge. The second image tries to keep the same perspective, but the planet becomes the flower and it is the bumble bee looking down:


--Ryan -- end -

-- Predrag - begin-
New motion for Freeplane splash and icons
I tried accept all your suggestions and I made new splash and icons.
Please send comments.
Blue:


Pink:

  • Ryan -- Begin -

I really like these designs, Predrag. In a sense, the blue looks better - but in my opinion blue is used too often in software projects. So I think we should use the pink.

Here are my suggestions for the very good pink design you have produced:

*I would like to see a lighter, pastel pink - with low saturation.

*I notice with the blue design, the blue background has a sky texture - maybe this can be used on the pink design.

*How about a bit of subtle shadow on the flower/honeycomb object?

*I think the icons might work better with just one object - i.e. the bee.

Good job, Predrag! I'm looking forward to seeing some new renderings. :-)

-- Ryan -- End -

An Idea: Why not both?

This might be a bit gimmicky, but why don't we offer both the blue and the pink splash, with the option to chose?

I like pink, but maybe it will put some (men) off. The options could be in one of the menus rather than tucked away in the preferences . - Ryan

Freeplane on Mac OS X

The following steps have been tested using Mac OS X Mountain Lion (10.8) and Snow Leopard (10.6.8). If you have comments on the download they are welcome on the Talk:Macintosh discussion page.

Download

Visit the Freeplane Project page at SourceForge, and click on the green "Download" button to get the latest version. As of this writing the current version is freeplane_app-1.2.18.dmg

The .dmg file will download to your Desktop or Download folder, or wherever you normally store downloaded files.

If it takes more than 30 seconds for the download to begin, you may need to click on the link at the top of the Sourceforge page which says "Please use this direct link".

Install

When the download is complete, find the downloaded .dmg file and double-click it. This will open a new Finder window called Freeplane with a Freeplane bumblebee icon inside. Drag the Freeplane icon into your Applications folder. You can also drag the Freeplane icon into your Dock so you have easy access to it. You may now delete the downloaded .dmg file.

Run

Click on the Freeplane icon in your Dock or double-click on the Freeplane icon in Applications. Click “Open” when prompted. Voilà.

Usage

When you open Freeplane you will be greeted with a Freeplane Applications window which gives you an idea of ways that Freeplane can be used. Click on any of the elements you see to learn how to create them and edit them.

If you’re working on a few maps together the file names will all be visible at the bottom of the Freemind window.

Quit

To exit Freeplane, choose File > Exit. Alternatively you can use the shortcut: Command+Q.

Future Enhancements

If you have feature and enhancement suggestions for Freeplane then add them to the Talk:Macintosh discussion page.

Any mind map can be used as a template for new mind maps. In this case its styles and nodes are copied to the new map.

  • Use action "File->new map from template..." to select a template map.
  • There are standard folders with user templates and standard templates which can be accessed from the "new map..." action, "save as..." action and "copy styles..." action.

Default template

"File->New map" action asks no questions and uses 'standard.mm' as a template. It is first searched in the user template folder (use Tools->Open user directory, then open the template folder), then in the installation template folder.

This default template could be changed in preferences (Tools > Preferences > Environment > Standard Template File)

Freeplane menus definition

Introduction

Freeplane menus are defined in a XML file. This file defines:

  • menus and commands available in menus
  • contextual menus and commands
  • toolbars
  • keyboard shortcuts (sometimes also called accelerators).

This file allows any Freeplane's user with a basic technical knowledge to customized Freeplane user interface either to use a personnalized Freeplane or to suggest new menu structure to Freeplane community.

Standard Menus file name and location

The file containing menus is named "mindmapmodemenu.xml". This file is included in Freeplane distribution and can be found in: [FP_INSTALL_DIR]\core\org.freeplane.core\lib\freeplaneeditor.jar\xml

UsageFile name
Full Freeplane modemindmapmodemenu.xml
Map view only modebrowsemodemenu.xml
File browser modefilemodemenu.xml
Style editorstylemodemenu.xml
Applet menu (when map is published on a web site)appletMenu.xml

Freeplane menus files

Structure reference for Freeplane menus file (XML format)

To be completed by Freeplane developpers...

How to customize Freeplane menus file ?

  • Step 1 : get the standard menu file
    • Goto directory:[FP_INSTALL_DIR]\resources\xml on the computer where you have installed Freeplane
    • Find file "mindmapmodemenu.xml"
  • Step 2 : install the standard menu file as a personnal menu file
    • Launch Freeplane

    • Goto menu : Tools > Open user directory (the directory displayed should be something like : "...\Data\Freeplane\1.2.x")

    • There create one of the following sub-folders: [USER_DIR]\resources\xml or [FP_INSTALL_DIR]\resources\xml

    • Copy in the new sub-folder "xml" the file "mindmapmodemenu.xml" located at the end of Step 1 *Step 3 : modifying the content of your personnal menu file

    • Open the "mindmapmodemenu.xml" with a text editor (I suggest Notepad++), now you can perform the changes you want ... see below.

Example of changes than can be performed in the Freeplane menu file

The simplest actions are to re-order commands in a menu, move commands from one menu to an other or add separator to group commands in a menu. You can perform these operations by a simple Cut/Paste of the XML content (in respect with XML structure) in your personnal "mindmapmodemenu.xml" file created through step 1 to 3 above. You can also perform other changes like adding submenus or add/remove/move toolbars icons or change keyboard shortcuts, see developper's reference above for more informations. Don't forget : you need to restart Freeplane to reflect the changes made in FreePlane menus file.

Rules applied to organize Freeplane menus

*Some rules have been established to organize and maintain Freeplane menu, see Rules to build user friendly menus.

Clicking on the images will increase their size. Clicking the hyperlink under the images will open the interactive mindmap. Because of limitations of the mind map viewer, the interactive maps may behave slightly different from the maps you download on your computer and view with Freeplane.

General Freeplane mind maps

What is mind mapping

applet|Café Chocolat

Freeplane Application areas

Freeplane functions

Meeting support - Beginner

Meeting support - Advanced

Collection - Beginner

Collection - Advanced

My Vault - Advanced

Action dashboard

SWOT analysis

applet|Node Template Script with "Notes and References" database Example

applet|Activity Cost Allocation

applet|Formulas: General Balance form

applet|Bayes theorem: arithmetic calculations in nodes

applet|Bayes theorem: arithmetic calculations in attributes

applet|Bayes theorem: Formula calculations in attributes

applet|Industry and Manufacturing industries

applet|USA Economic and Regional Structures

applet| Types of free or floating nodes

applet|Multiple sorts of floating central nodes

applet|Floating Nodes in DigitalLogic

applet|Iron Sulfate Production Calculations

applet|Iron Sulfate Production-AAGG

![](Example - ConceptMap.jpg) applet|Example concept map

applet|Example summary nodes

Map as documentation

applet|Problem Solving Tools Tool Map

![](DesigningWindowsApplications Screenshot.png) applet|Designing .NET 4 Windows (Desktop) Applications

applet|Representational State Transfer (REST)

For more information about these maps see Freeplane Tutorial Extensions and the (hidden) information in the interactive maps when you hover or unfold the nodes.

Screenshots

Galleries in other languages than English

In alphabetical order:

; Attention: : This effort is on hold until further notice (perhaps after release of version 1.2/1.3).


Introduction

Freeplane version 1.0.x (and 1.1.x) was developed using FreeMind's format and file extension (.mm) in an effort to allow a smooth transition to users willing to switch to Freeplane. As Freeplane grows mature and wants to make true its Visions, a new file format is required.

File types and extensions.

A Freeplane file can come in 4 flavors, as single XML document file or as package:

  1. Single XML document:
    1. a plain XML format with extension .freeplane.
      This format allows further for easy automated generation and XSLT transformation.
    2. the above format in a standard ZIP or JAR file, i.e. if a file named myfile.freeplane.zip or myfile.freeplane.jar contains a file named myfile.freeplane, it will be opened by Freeplane in the same way as the above plain XML format (other files in the same archive will be ignored).
      The file format is still easy to generate but takes less space than plain XML, is cleaner to email (some mailers choke on text formats) and can be used to transport other files (even though they will be ignored by Freeplane).
  2. Package Document:
    1. a more complex zipped format with extension .freeplanez.
      This format allows for embedded styles, images and other 3rd party objects.
    2. the same structure but in an uncompressed directory with extension .freeplane.d.

Overall, the XML format is the same in all flavors, and aligned (as much as possible) with the Open Document Format from the OASIS organization.

File format requirements

  1. clean XML
  2. multiple maps per file possible
  3. easy generation
  4. embedding of 3rd party objects
  5. support real styles
  6. allow for comparison between different files
  7. allow for tracked changes

Generic rules

  1. Each XML file must start with an XML declaration <?xml version="1.0" encoding="UTF-8" ?> .

    • this means that the Freeplane format is based on XML 1.0 and has UTF-8 as encoding.
    • (X)HTML entities are not used anymore for accentuated characters but just plain UTF-8 encoding.
  2. A single XML document may continue with an XSLT reference like <?xml-stylesheet type="application/xslt+xml" href="url-to-some-XHTML-transformation-sheet"?> as to allow web browsers to render directly Freeplane files.

    • Freeplane must ignore (but keep) such entries and should add a default one when creating a new map.
    • The Freeplane team should offer standard XSLT transformation sheets e.g. under http://freeplane.org/formats/2010/to-xhtml10.xsl.
  3. All XML markups are in small caps and must have an explicit namespace

  4. The namespace must be declared either as xmlns:attribute of the root element of the XML file, or, if rendered by a plug-in, as xmlns:attribute of the XML element rendered by this plug-in

  5. ; Example : if a node has the xmlns attribute <map:node xmlns:myplug="myplug-namespace" ...>[...], Freeplane could find an OSGi service NodeRenderer with a filter based on the given namespace to render this specific node.

  6. The namespace for Freeplane specific elements is xmlns:map="http://freeplane.org/formats/2010/map".

  7. Until further notice, all formatting elements are based on XHTML 1.0/1.1 and have the namespace xmlns:xhtml="http://www.w3.org/1999/xhtml".

    • SimplyHTML must be adapted accordingly, and perhaps released as OSGi bundle!?

Format Specifics

(structure aligned with version 1.2 of the Open Document Format )

Part 1 - XML File Format

1 - Introduction

1.1 to 1.4 - no changes

1.5 - Namespaces

We stick to the same namespaces wherever applicable, and add the following one:

|+ Table 6 - Freeplane namespaces |- |- | map || For all Freeplane specific elements || http://freeplane.org/formats/2010/map |- | x-office || For Freeplane elements that would belong in the 'office' namespace | http://freeplane.org/formats/2010/office |}

2 - Scope (not relevant)

3 - Document Structure

3.1 Document Representation

3.1.2 office:document(Single OpenDocument XML Files)

A typical single opendocument might look as follows:

<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="application/xslt+xml" href="http://freeplane.org/formats/2010/to-xhtml10.xsl" ?>
<office:document office:mimetype="application/x-freeplane" office:version="1.2-fp-1.0" xmlns:[...]>
<office:automatic-styles> [...] </office:automatic-styles>
<office:body>             [...] </office:body>
<office:font-face-decls>  [...] </office:font-face-decls>
<office:master-styles>    [...] </office:master-styles>
<office:meta>             [...] </office:meta>
<office:scripts>          [...] </office:scripts>
<office:settings>         [...] </office:settings>
<office:styles>           [...] </office:styles>
</office:document>

Notes : Once Freeplane has a registered mime-type, mimetype could become application/freeplane. The version is made of the ODF version 1.2, 'fp' for Freeplane and an internal version number, 1.0 to start with.

3.1.3 Package OpenDocument Files

File content.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<office:document-'''content''' office:version="1.2-fp-1.0" xmlns:[...]>
<office:automatic-styles> [...] </office:automatic-styles>
<office:body>             [...] </office:body>
<office:font-face-decls>  [...] </office:font-face-decls>
<office:scripts>          [...] </office:scripts>
</office:document>

File styles.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<office:document-'''styles''' office:version="1.2-fp-1.0" xmlns:[...]>
<office:automatic-styles> [...] </office:automatic-styles>
<office:font-face-decls>  [...] </office:font-face-decls>
<office:master-styles>    [...] </office:master-styles>
<office:styles>           [...] </office:styles>
</office:document>

File meta.xml:

<?xml version="1.0" office:version="1.2-fp-1.0" encoding="UTF-8" ?>
<office:document-'''meta''' xmlns:[...]>
<office:meta>             [...] </office:meta>
</office:document>

File settings.xml:

<?xml version="1.0" office:version="1.2-fp-1.0" encoding="UTF-8" ?>
<office:document-'''settings''' xmlns:[...]>
<office:settings>         [...] </office:settings>
</office:document>

3.2 office:meta

Section can and should be used as-is. No changes needed.

⇒ Freeplane should offer a dialog to enter document information.

3.3 office:body

Mandatory section, but only child needed is a Freeplane specific <x-office:map>.

Note : x-office is used instead of office to avoid polluting the 'office' namespace. x-office can be used as an alternative prefix for the same Freeplane namespace as 'map'.

3.4 to 3.9 not needed, replaced by x-office:map

> **TBD** : The exact content of a map will be described in [Freeplane_File_Format/Maps](Freeplane_File_Format/Maps.md)

3.10 office:settings

Section can and should be used as-is. No changes needed.

Possibly Freeplane doesn't need the full scope and could cope only with config-item-set and config-item as in:

<office:settings>
<config:config-item-set config:name="''somename''">
<config:config-item config:name="''itemname''" config:type="''itemtype''">
''ConfigValue''
</config:config-item>
[...]
</config:config-item-set>
<config:config-item-set config:name="''someothername''">
[...]
</office:settings>

Note : as described in chapter 19.32, The values of the config:type attribute are boolean, short, int, long, double, string, datetime or base64Binary.

3.11 Cursor Position Setting

A bit unclear, but I understand something like the following is possible:

<?opendocument cursor-position="''XXX''" ?>

where XXX is a mean to give the cursor position at the time where the document was saved. In Freeplane's case, it could just be a map and/or node ID, but I'm not fully convinced.

3.12 + 3.13 office:script[s]

TBD : The exact handling of scripts will be described in Freeplane_File_Format/Scripts

<office:scripts>
<office:event-listeners>
TBD: do we need event listeners in Freeplane? How to implement them?
</office:event-listeners>
<office:script script:language="groovy">
''Script Specific Text (can also be a link to an external script)''
</office:script>
<office:script script:language="lang2">
[...]
</office:scripts>

3.14 office:font-face-decls

<office:font-face-decls>
<style:font-face [...]>
</style:font-face>
<style:font-face>
[...]
</office:font-face-decls>

I would recommend to skip this function for the next release of Freeplane, chapter 16.21 style:font-face seems quite complex to implement. TBD!

3.15 Styles

The elements office:automatic-styles, office:master-styles and office:styles could possibly be used but would possibly need to contain map specific styles.

TBD : The exact handling of styles will be described in Freeplane_File_Format/Styles

3.16 Document and Macro Signatures

The section defines 2 (optional) files described in more details in chapter 2.4 of part 3 of the specification:

  • META-INF/documentsignatures.xml for signature of all files
  • META-INF/macrosignatures.xml only for signatures of macros

Does not need to be part of next Freeplane release.

4 Metadata

The specs define 2 types of metadata:

  1. RDF Metadata, to be defined in the file manifest.rdf (more details in part 3)
  2. Non-RDF Metadata, found within the element office:meta.

Both can be used as defined in the chapter.

5 to 20 (Content, Formatting, attributes, etc...)

TBD : To Be Used as needed, document here what you use as you implement it!!!

21 Document Processing

Nothing really special...

22 Conformance

Chapter 22.2.2 "Conforming OpenDocument Extended Documents" is interesting as it defines what the new Freeplane format needs to fulfill.

Freeplane itself would need to comply to 22.3.2 "Conforming OpenDocument Extended Producers" and 22.4 "Consumer Conformance".

Appendices A to G

Nothing really relevant in there.

Part 2 - OpenFormula

not applicable (yet?)

Part 3 - Packages

1 Introduction

Nothing really relevant

2 Packages

2.0 list of files

The specification doesn't explicitly contain a list of possible files, so here it is, with a reference to the relevant chapters.

The following table shows a summary of all files to be found in an OpenDocument conform package file, as described in the specification:

|+ Files found in a package according to ODF reference |- |- | mimetype | first file in ZIP file, uncompressed, contains mime type i.e. application/x-freeplane or application/freeplane | 2.3 MIME Media Type |- | META-INF/manifest.xml | manifest file in XML format listing all files in the package with their MIME type and, if needed, encryption options | 3 Manifest File |- | manifest.rdf | meta data file (probably optional for Freeplane) | 5 Metadata Manifest Files |- | META-INF/documentsignatures.xml
META-INF/macrosignatures.xml | Signature files respectively for all files and for macros (optional) | 4 Digital Signatures File (and in Part 1 - 3.16 Document and Macro Signatures) |- | Thumbnails/thumbnail.png | Preview image of size 256x256 and 24 bits (optional) | 2.8 Preview Image |- | content.xml
styles.xml
meta.xml
settings.xml | Core content, styles, metadata and settings files | Part 1 |}

The ODF specification states that a package can contain other files, but it doesn't specify any specific structure (it is also not needed because all such files are referenced in META-INF/manifest.xml). Reading between the lines and analyzing OpenOffice files, I come to the conclusion that all additional files should be in sub-directories with names starting with a capital. Here a few examples/suggestions:

|+ Directories found in a package to contain 3rd party objects |- |- | Pictures/ | for all images. Freeplane accepts JPEG, PNG and GIF formats. |- | Icons/ | for user specific icons. Freeplane accepts JPEG, PNG and GIF formats. |- | Scripts/ | for Groovy scripts. |- | Objects/ | for any object that Freeplane would embed without actually being able to do anything with it but just try to display externally. |}

Note : further directories can be added as needed.

Note : to embed objects, OpenOffice creates a binary (format ?) reference file ObjectReplacements/Object N (N a growing index) and puts the relevant data in a sub-directory Object N, but I don't think we want to do this.

2.4 Encryption

probably not in this version of Freeplane

2.7 Usage of IRIs Within Packages

the chapter is a bit unclear, but I understand basically that links to files within the package are just normal relative links. As all files present in the package need to be referenced in META-INF/manifest.xml, Freeplane can safely compare any relative link to the content of this file, and, only if not found, try to resolve the link outside of the package.

Note : when using a packaged directory, the relative link outside of the package means relative to the directory containing the packaged directory. Example: a packaged directory /home/ewl/Documents/mymap.freeplane.d where content.xml refers to Scripts/myscript.groovy; if internal to the package, the absolute path is /home/ewl/Documents/mymap.freeplane.d/Scripts/myscript.groovy, but externally resolved, it means /home/ewl/Documents/Scripts/myscript.groovy.

3 to 5 Manifest, Signatures and Metadata

Relevant without changes, chapters referenced in files table from chapter 2.

6 Datatypes

Not really of interest.

7 Conformance

Relevant summary, to be fulfilled by Freeplane and its format.

The following describes the difference between Freeplane 1.1.3 and Freeplane 1.2.x. To load the development version 1.2.x go to the preview area.''

New user configuration file folder location

If you are already a Freeplane user, you may want to transfer your previous settings to the new preview version. After installation you can copy your configuration files to the following folders depending on the OS you use:

  • under (old) Windows: %appdata%\Freeplane\1.2.x
  • Windows 7: %user%\AppData\Roaming\Freeplane\1.2.x (Only visible if Show hidden files is turned ON)
  • under Mac and Linux: ~/.freeplane/1.2.x
  • Portable Freeplane: [INSTALL]/Data/Freeplane/1.2.x

You can open this directory in a file manager via the Freeplane menu under Tools -> Open User Directory.

The most important new features

Implemented

  • Node styles replace style patterns (like in text processors)
  • Conditional node styles: node formatting depends on its content and position
  • Map templates for new maps (all previous maps can be used)
  • Menus and commands have been re-ordered to improve user efficiency (both to better integrate new features and to give a more "natural access" to already existing features)
  • Properties panel - Format tab
  • Hyperlinks for menu items
  • Keyboard shortcut documentation: Map and HTML table generation added for the documentation map
  • Check for newer auto save files on opening of a map
  • Single instance mode: open files in existing program instance instead of opening a new one.
  • Node level dependent filters
  • Improvement in search and replace functions
  • Different cloud shapes
  • New icons for rating
  • Automatic Edge Color
  • "Grid" for moving nodes (see Preferences>Behaviour, Behaviour section>Grid gap size)
  • Copy and paste attributes
  • Named filter conditions
  • Connectors : different shapes, line types, width and transparency
  • Progress icons (standard icon / 25% steps / available in menu "Icons") or external progress icon (clickable icon / 10% or 25% steps / also available in menu "Icons")
  • You can now create "brackets" to add a graphical and text summary to some nodes, see applet|sample brackets map
  • Freeplane portable version (download and install file named FreeplanePortable_X.paf.exe)
  • File -> Properties... dialog shows informations about the map (e.g. total number of nodes)
  • add new icons in main and contextual menus to improve user efficiency
  • Formulas: Use of formulas in node text, nodes and attributes (like in spreadsheet processors)
  • Node numbering and Formats/templates as style attributes
  • Parsing and formatting of numbers and dates in node texts and attribute values.

Other features

Other features

  • Ability to rearrange custom filters in the filter composer
  • Add Format=Unparsed LaTeX and \unparsedlatex node prefix to allow LaTeX content that is solely used for export
  • Add-on jar libraries
  • Allow program arguments like file.mm#ID_123456 to choose the first selected node
  • Allow to enter external http and https urls in add / change external image dialog
  • Bigger filter composer window depending on screen resolution
  • Cloud support in the scripting API
  • Command line option -U
  • Compile scripts on class path on startup
  • Docking Windows (the ability to position mind map windows independent of the parent window)
  • Editor for Latex with Syntax Highlighting
  • Enhanced export to HTML
  • Enhanced export to Open Document Text format (ODT)
  • Install url handler for protocol "freeplane" for windows and mac
  • Integration of Open Street Map
  • Latex text in nodes
  • Menu and preferences structure can be edited by users
  • Named filter conditions are part of the main menu
  • New, more easy to understand structure of the preferences dialog
  • Option to set image resolution for PNG/JPG image export
  • Performance: cache compiled scripts
  • Remove ".mm" from tab titles
  • Scripting API for node encryption, exports and map specific storage
  • Scripting API: node.style.numberingEnabled, node shifts, node.minimalDistanceBetweenChildren
  • Several Scripting API extensions
  • Textbox in preferences for common/global LaTeX macros (plugins->LaTeX)
  • Update groovy to 2.1.9
  • Use signed applet and jnlp descriptors so that local applets can run with the latest java
  • Use signed jar so that local jar files work with the latest java versions

FreeMind has a proprietary extension mechanism further called plug-ins. FreeMind plug-ins are automatically loaded by FreeMind using their XML descriptors. This mechanism should be replaced because of the following reasons:

#Current plug-in design defines many additional classes and interfaces which are actually not necessary and can be replaced by interface used in the freemind kernel. #Current XML descriptors have many not documented attributes. There is no need in big XML descriptors any more because FreePlane API allowing plug-ins to seemlesly integrate themselves to the main program e.g. add and serialize new node properties and add their own actions to Freeplane menus/toolbars. #Using of OSGI framework is a standard way to organize plug-ins in external projects with excellent IDE support.

Currently I am converting all FreeMind hooks into usual packages which reside inside of freemind.jar. Later they should be converted to OSGI packages. This task should prepare this connection. Now I prefer knopflerfish as a framework.

Up to Freeplane 1.1 patterns were a method to change the appearance of a mindmap node. Starting with Freeplane 1.2 pattern are replaced by the concept of Node styles.

Portable Freeplane

Freeplane can run as a portable application from your USB stick.

Windows

#Download a portable apps platform and install it on your USB stick, #run the platform software from the stick, #Download a portable java, #Download FreeplanePortable_XX.paf.exe, #Install portable java and freeplane as explained here

Now you can start Freeplane from the portable app platform program menu and it should use the java runtime from the stick.

Freeplane's release cycle is time boxed at 6-9 months, and meant to allow for 1-2 stable releases per year (but much more unstable releases ;-) ).

As shown above, the release cycle of Freeplane consists of 3 phases:

Alpha

3-6 months of "wild" development on trunk branch

  • Branch the next release e.g. Branch_1.0.x - developers can continue to bring in new features on MAIN/HEAD/trunk. ⇒ The phase ends when release branch is created from the trunk

Preview snapshots

Preview versions can be uploaded to a preview area.

Before downloading and trying the preview versions read and accept these warnings:

  • They are not intended for any productive use.
  • There is no support for them.
  • Data format and properties may be changed for preview versions without any notice.
  • Files and user properties saved by the preview versions may be not properly handled by any previous or following program versions.

Unstable

3 months of bug fixing releases on the release branch

Beta

2 months of bug fixing releases on Branch_1.0.x - that would be Beta releases.
⇒ Create RC1 (Release Candidate) - call for translations, 3rd party plugins and packaging.

Release Candidate (RC)

1 month of integration of translations + critical bug fixing ⇒ The phase ends when stable release is created, e.g. 1.1.0.

Test releases

Test releases will be uploaded first to a testing area https://www.freeplane.org/testversion/ and can be released on https://sourceforge.net/projects/freeplane/files/freeplane%20beta/ 4-7 days later after one or more tester confirms that no major bugs have been introduced in the test version.

Stable

final packaging can only happen after final release so we can only make sure that it all happen in a limited timeframe).
new bug fixing / stable releases can be done as required, called 1.1.1, 1.1.2...

The stable versions can be published on page https://sourceforge.net/projects/freeplane/files/freeplane%20stable/.
They appear on page https://www.freeplane.org/testversion/ 4-7 days earlier.

Another way to show the approach is the following 3 pictures. The blue line turns clockwise while we progress through a release cycle; what is right of the line (in Green) is allowed to be done, what is left of the line (in Red) isn't. This means that everything is allowed during Alpha phase, that in Beta we should avoid major rewrite unless it's needed to fix a critical bug, and, as we come to RC, almost nothing is allowed but to fix critical bugs. ; Side note: the line progresses continuously, it's not a sudden jump, e.g. during beta, we implement always less new things, even if they're easy to do, and fix always more bug, thus regularly stabilizing the code basis.

Alpha phaseBeta phaseRelease Candidate phase

Bug handling

Freeplane uses the Sourceforge/Allura ticket system as bug tracker (https://sourceforge.net/p/freeplane/bugs/). Bugs should be set to resolved once the developer has fixed it and checked-in the changes in the version tool. The bug should be kept open to allow testers to alert the developers of a recurrence. The bugs can be closed in RC phase.

Every new version is uploaded to the project web space before it is released publicly. This allows team members or interested parties to check for the basic quality before each release. When it is reported that there are no major problems, the file will be released for further and public testing.

Here is a basic check list for pre-release testing. This is not a comprehensive or systematic testing routine, it is a basic list that be carried out in a few minutes before each release:

How to test Freeplane (test release) . This page has been updated for Freeplane 1.4.x.

General functionality

If you can, have a look which new features have been added with current release and try them out as thoroughly as you can. Generally try to test the newer features.

*Run Freeplane from shell script

* Make sure that there are no errors on the command line (especially OSGi errors)

*Close all existing maps (Ctrl+W) *Create new map (Ctrl+N) *Type some text into root and press Enter *Create new child (Insert) *Type text and enter *Add sibling (Enter) *Type a full paragraph of text and press Enter *Add some more children and siblings as above *It helps to add as much text as you can and work quickly so performance can be tested *Overwrite some nodes with new text *Copy and paste some text from the web or another editor *Fold and unfold some nodes *Apply some styes with F keys *Load calendar and append date (Ctrl+T) *Add a connector, label it and move it around. *Insert one or more images, resize and move the nodes around. *Save the map. *Create an attribute *Add some icons *Apply a filter *Select two nodes and join them (Ctrl+J) *Add a note. *Test undo and redo (Ctrl+Z and Ctrl+Y) *Arbitrarily move some nodes around *Save map, close Freeplane, reload Freeplane. *Select all nodes (Ctrl+A) *Select Format-->Reset position *Save. Test done.

Ribbons

TODO

Clones

TODO

Plugins

Unfortunately missing Export-Package:/Import-Package: are only detected at runtime, so we need to test carefully!

Formula

  • enter =1+2 in a node core
  • make sure that syntax highlighting and '{'/'}' matching works

JSyntaxPane

(only used jointly by Script/LaTeX)

LaTeX

  • enter "\latex $x_2=\frac{1}{3}$" in an node core and make sure that the formula is rendered
  • make sure that syntax highlightying and '{'/'}' matching works
  • enter "$x_2=\frac{1}{3}$"and set Format=LaTeX => make sure that the formula is rendered

OpenMaps

  • make sure that the menu actions are available
  • Create an openmaps link for the current node, double-click an a location, click "done"
  • click on the icon --> the map view must appear at the same location and zoom
  • double click on a different location two times, click "done"
  • Remove the openmaps location from the node --> the icon must disappear

Scripting

  • make sure that the menu actions are available

  • Create a new script, make sure that syntax highlighting and '{'/'}' matching works

  • run this script: c.statusInfo = node.value.getClass().name + ": " + new String(node.value) --> must show class org.freeplane.plugin.script.ConvertibleNodeText: in status bar

  • test a simple add-on

SVG Plugin

  • Export map to PDF --> look at the resulting PDF
  • Export map to SVG --> look at the resulting SVG
    • known issue: LaTeX is not rendered in SVG output

Introduction

The purpose of this page is to describe basic principles to build easy to use Menus for a rich mind map software called Freeplane !

You can refer to Menus: work in progress to follow and collaborate in the design of the new FreePlane menus structure.

Rules to organize Main Menu

Main menu is the main bar of menus which gives access to all software features.

  • (MM1) A Main Menu entry is created for each kind of operation (File / Edit / Display ...).
  • (MM2) The Main Menu should be in a logical order inspired by other softwares best practices .

Rules to organize Commands in menus

A command is available in menu, it executes an action.

  • (CO1) In a Main Menu entry, items are grouped by type of operations (all commands to move nodes are at the same place).
  • (CO2) Items are ordered logicaly (items used first at the beginning : ie "Create Node" then "Edit Node" then "Delete Node" or "Print Preview" then "Print". If no logical order can be found other rules can apply:
    • the most often used commands can be set in first position
    • order can also be set from particular to generic (ie: "Fold selected node" then "Fold all nodes of map")

Use of Sub Menus

A submenu is a menu entry which opens an other menus.

  • (SM1) Submenus are created to simplify long Main or contextual menus (i.e. more than 20 items in the menu).
  • (SM2) Submenus should be limited to 3 levels (i.e. 3 clicks before displaying the wanted command).
  • (SM3) A Submenu should contain 3 items or more.

Rules to organize Contextual Menu

A contextual menu is a menu displayed only in a specific context (i.e. while on a node or on the map background).

Rules applied to build contextual menu :

  • (CM1) in Contextual menu, order should be the same as in Main Menu (consistency for end-users). For instance Node Contextual menu is yet a copy of the Main Menu structure
  • (CM2) Contextual menu should contain only very frequently used commands
  • (CM3) 3 navigation levels are the maximum allowed in contextual menu.

Node Contextual menu's benefits

  • Limited mouse movements, don't need to go to Main Menu => quick access
  • Simplified menus displaying only most used features => easy to use
  • Available and fully fonctional while working on a map in full screen mode.

Toolbars

  • (TB1) The rules for toolbars are the same as for the Contextual menu: same order as Main-Menu, only frequently used commands.

Legend

In this page :

  • MM means Main Menu.
  • CO means Command.
  • SM means Sub Menu.
  • CM means Contextual Menu.
  • TB means Toolbar.
  • XX# means rules number # for subject XX.

See Help Previous Freeplane Versions for Freeplane 1.1.3. The following is Help for Freeplane 1.2.x Index wiki

Installation (stable version)

The installation of the stable version for Windows is automatic. In other cases consult the installation for different operating systems below. For Macintosh also the windows-equivalent mouse buttons and special keys are described.

  • By default an English dictionary for the spell checker is installed. For other languages see below.
  • The menu structure is available in an increasingly number of languages. In the program, in menu Tools > Preferences, the language for the menu's can be changed. * For more information, see mind map Index wiki (upper right corner), branch Intall.

Operating systems

Freeplane runs on any operationg system which has a recent version of Java insatalled.

Install language

The Freeplane menu's are translated in many languages. For many languages spell check dictionaries are available.

If you want to supply a translation of the tutorial or documentation in your language, see [[Translation_How-To#Translation_of_Tutorial_or_Documentation_maps |how to]].

Install add-ons

The standard functionality of Freeplane can be extended in different ways:

  • See Add-ons_(install) for extensions and for customization of Freeplane.
  • See Academic liturature suite.
  • See the Freeplane CD below for free icons, clipart and examples. (N.B. It is not necessary to create a CD to use its information)
    [[File:CD_cover_f.jpg|thumb|left]]

Installation (development version)

Freeplane is being developed fast. If you want to use the newest functionality consider using a beta version. Besides you are invited to take part in testing the preview versions.

Install beta version

A beta version is a complete version of Freeplane with all new functionality of the coming new stable version and which is being installed in the same way as the stable version, with a set-up file which will automatically install Java too. Go to beta version, download the Freeplane-SetupXXX.exe and execute this file. For non-windows operating systems, see Category:System. Read here about changes between program versions.

Install last preview version

A preview version contains new functionality the programmers are still working on. Installing a preview version supposes that you have Java installed on your computer.

Go to preview and download Freeplane_bin-XXXX.zip, in which XXXX is a shown version number. Unpack the zip file, at any place you want. If your intention is to only test the new version: In Windows click freeplane.exe; you could also connect freeplane.exe to the task bar. If you want the new version to automatically start if you click on any mind map, just overwrite the directories of the older version with those of the newer version. For other operating systems, see Category:System. Read here about changes between program versions.

Tutorial

[[File:Tutorial.jpg|thumb|right| [https://www.freeplane.org/mapsOnline/?map=freeplaneTutorial.mm Tutorial ]]]

The Tutorial gives a rather complete introduction to the main functions of Freeplane. It may help to first study the Guides. Details are discussed in the Documentation.

Documentation

Documentation

The Freeplane Documenation describes the details of each Freeplane function. Use Find and Filter to find out if a function exist for the type of action you are looking for. The Documentation also contains Frequently Asked Questions (FAQ).

  • In the Freeplane program Documentation Help > Documentation opens the Documentation.
  • In the Freeplane program Help > Online documentation gives the most actual information.
  • This wiki gives detailed information on many topics, see the navigation menu of this page, applet| Index wiki .

Publishing maps on line

Freeplane lets you export a map for publishing it on Internet or Intranet. If you have multiple maps to publish and maintain, it is more economic to use the procedure described here. The maps in Freeplane Tutorial Extensions are published in this way.

Making a Freeplane animation or video

Freeplane maps can be used as a basis for creating an animation or video. There is a How to guide with guidelines to create a high quality, low storage Freeplane animation or video.

Open forum

Open forums give fast and easy access to the active user community of Freeplane. You can ask questions or post suggestions.

  • Discussions is the main forum. You must register before posting.

FAQ's

*the Troubleshooting page *the FAQ (Frequently Asked Questions) *Report bugs here or request new features here
  Please check first for existing issues using the Search box
  Use the Apply Filter button to begin the search.

Developers

Previous versions

This wiki

Index wiki Many pages on this wiki are tagged at the end of the page with Categories. You can click on the Category at the end of the page to display an index of all pages of the same Category. The categories and pages are summarized in the mind map Index wiki on the right.

NOTE: because of spammer attacks, editing of this wiki is now only allowed for registered wiki editors. If you want to become a wiki editor, [write](http://sourceforge.net/apps/phpbb/freeplane/viewforum.php?f=1) to the Freeplane team.

You can subscribe to atom feed to be informed about all changes in this wiki. Using this web service you can get daily e-mail notifications whenever the content changes. The same service can also be used for notifications about any changes to the project pages on SourceForge.

Links

  • open clipart and clker free clipart which can be used in Freeplane
  • With MetaMindMaps it is possible to automatically generate a map of maps. If you use Norton, tempory switch of SONAR to install the program. Be aware that private data might leave your map.

Think Tank

Team discussion space for developing our goals, visions and steps.

Every page can contain statements, questions, answers, discussions and team decisions.

Please start every in-page comment with "> " so that it is displayed indented and colored.

Background

Development

Non-Coding

Communication

Deze pagina ondersteunt de vertaling van Freeplane naar het Vlaams/Nederlands. Discussie is mogelijk op het forum in Dutch/Flemish translation / Vlaamse/Nederlandse vertaling. Deze pagina kan dan verder gewijzigd en aangevuld worden met conclusies uit deze discussie.

Algemene principes bij het vertalen

  1. Gebruik de metafoor van een afstammings hierarchie (ouder-kind relaties)
  2. Gebruik de voorkeurstermen uit de glossary
  3. Gebruik in menu's onvoltooide tijd en geen directieve vorm (dus Bewaren en niet Bewaar)
  4. Ga uit van gebruik door een leek
  5. Sluit aan bij populaire programma's als MS Word.
  6. &-geheugensteuntjes weglaten uit Nederlandse vertaling (zie ook [[#&-geheugensteuntjes|&-geheugensteuntjes]])

Voorkeurstermen

Het doel van de voorkeurstermen is om met verschillende vertalers tot een consistente vertaling te komen. De voorkeurstermen zijn opgenomen in de woordenlijst op Weblate. Voor de werking van de woordenlijst, zie Glossary

Deze lijst is nog niet volledig en bestaande suggesties kunnen nog voor verbetering vatbaar zijn. Nieuwe suggesties kun je gewoon toevoegen. Voor verbetering van bestaande suggesties, overleg dit in de discussie Dutch/Flemish translation / Vlaamse/Nederlandse vertaling

&-geheugensteuntjes

In de te vertalen Engelse brontekst voor menu items staat regelmatig het & teken. Dit onderstreept de daarop volgende letter in het menu. Je kunt dan door het menu navigeren door achtereenvolgens de onderstreepte letters in te tikken. Mijn voorstel is om deze & tekens uit de Nederlandse vertaling te laten. Freeplane wijst dan namelijk automatisch unieke letters toe voor onderstreping en navigatie. Als iemand toch graag de & tekens wil toevoegen (zodat deze bijvoorbeeld een vaste waarde behouden) kan deze dat melden in onze discussie op het forum en kunnen we bespreken hoe dit aan te pakken.

Voor de meest recente/uitgebreide informatie: bekijk de Engelse pagina's met Google vertalen naar het Nederlands.

Deze pagina beschrijft het maken van mindmaps met de nieuwste versie van Freeplane (1.2.x) welke zich nog in alfa-stadium bevindt. Deze versie is voor de meeste doeleinden voldoende stabiel om gebruikt te worden. Voor een inleiding in wat mindmaps zijn en voorbeelden van mindmaps, ga naar de Gallerij met voorbeelden. Voor het downloaden van Freeplane en het zelf maken van een mindmap, zie hieronder. De verwachting is dat in de zomer van 2011 1.2 in beta fase gaat en definitief wordt gemaakt.

Inleiding Freeplane 1.2

Overzicht functionaliteit

Bij Freeplane wordt elk onderwerp een knoop genoemd. Een knoop is een plaats waar informatie kan worden geraadpleegd of een functie kan worden uitgevoerd. Een knoop heeft op het beeldscherm een binnengebied en een buitengebied. In het binnengebied kunnen een titeltekst, pictogram, snelkoppeling, hyperlink en een afbeelding (met vaste grootte) worden getoond. Het binnengebied kan verder zichtbaar worden worden gemaakt door deze te omlijnen. Het buitengebied bevindt zich onder het binnengebied. In het buitengebied kan een inhoudelijke tekst, notitietekst, attributenlijst, en schaalbare afbeelding worden getoond. Deze informatie kan naar keuze worden verborgen en alleen getoond als de knoop is geselecteerd.

De titel bevat meestal niet meer dan enkele woorden. In de titel kan ook een formule worden weergegeven (LaTeX). De titel kan in plaats van tekst ook een formule bevatten. Deze begint, net als bij een spreadsheet, met “=” en wordt automatisch uitgerekend. En verder kan een tijdstip worden opgegeven waarop een signalering moet worden gegeven (agendafunctie).

Aan/onder het gebied van de basistekst kunnen de inhoud, een notitie, attributen en een externe (schaalbare) afbeelding worden getoond. De notitie is van oorsprong bedoeld voor het presenteren van een document in een afzonderlijk, schermbreed venster. Een attribuut bestaat uit een kenmerk met een waarde. Er kan worden ingesteld dat deze velden permanent zichtbaar zijn of alleen als de knoop is geslecteerd.

Er is één stam(ouder)knoop die de vorm heeft van een ovaal. Hieruit komen takken die een reeks van knopen verbinden die een ouder-kind relatie hebben. Daarnaast kunnen twee willekeurige knopen worden verbonden met een verbindingslijn (of pijl). Twee knopen kunnen digitaal worden verbonden met een snelkoppeling waarmee de focus van de ene naar de andere knoop kan worden verplaatst, of via een hyperlink met een programma of bestand op de computer of op internet.. Knopen binnen een tak kunnen visueel worden verbonden door een wolk. Ten slotte kunnen twee of meer knopen via een accolade samenkomen in een aggregatieknoop, kan een koop een taartpunt (%shijf) tonen en kunnen knopen worden voorzien van een automatische nummering.

Belangrijkste menu's De basiskenmerken van een knoop zijn toegankelijk via menu Knoop en de andere elementen via menu Knoopkenmerken.

Downloaden Freeplane 1.2.X (Windows, MAC, Linux)

Houd deze pagina in de gaten: er wordt gewerkt aan een nieuwe, betere menustructuur en dit betekent dat er regelmatig een nieuwe versie uit komt. Naar verwachting zal na de zomer van 2011 de definitieve versie uitkomen.

De laatst beschikbare ontwikkelversie van Freeplane 1.2.X is hier te downloaden. Voor de Windows versie, kies Freeplane-Setup-1.2......exe. Houd er wel rekening mee dat de software ontwikkelaars zonder waarschuwing veranderingen kunnen aanbrengen waardoor sommige delen misschien niet meer of anders werken. Er kunnen ook fouten optreden. Zie onder voor het installeren van de Nederlandse spellingcontrole.

BELANGRIJK Vanaf versie 1.2.5 is de menustructuur sterk vereenvoudigd. Nog niet alle voorbeelden zijn hier op aangepast.

Instructie en handleiding Freeplane 1.2

Instructie

Freeplane wordt geleverd met een instructie en een handleiding. Beide zijn te vinden in het menu Help van Freeplane. De instructie zie je ook hiernaast: klik onder het plaatje op de link "Instructie" om deze te openen.

Als je Freeplane gaat gebruiken, bekijk dan eerst de volgende instructievideo's:

Volg verder de Leeswijzer uit de handleiding en bekijk hieronder voor de belangrijkste instellingen die je zelf kunt wijzigen/aanbrengen.

Instellingen

Het opmaakpaneel tonen

Freeplane biedt vele mogelijkheden om kleuren, vormen en groottes van knopen en takken in te kunnen stellen. Nieuw in Freeplane 1.2 is het gebruik van een Opmaakpaneel waarin alle in te stellen elementen van een knoop/tak bij elkaar staan. Het opmaakpaneel wordt getoond door Beeld > Opmaakpaneel te kiezen. Het opmaakpaneel toont de actuele inhoud van de geselecteerde knoop. Elke verandering die wordt aangebracht, is direkt te zien in de knoop of de tak van de geselecteerde knoop.

Installeren Nederlandse spellingcontrole

De Nederlandstalige [[#Spell_checker|spellingcontrole]] wordt niet automatisch geïnstalleerd. Dit moet je dus altijd zelf doen. In de handleiding staat hoe.

Installeren: Klikken om te selecteren

Standaard selecteert Freeplane een knoop als de muiscursor zich boven de knoop bevindt. Als je dit niet handig vindt, kun je via Instellingen > Gedrag instellen dat één maal met de linker muistoets klikken leidt tot selectie.

Installeren: Automatische takkleur uitzetten

Freeplane gebruikt het bestand standaard.mm om de kleur van de takken, knopen en ander kenmerken van de nieuwe mindmap te bepalen. In standaard.mm is vastgelegd dat elke nieuwe tak automatische een andere kleur krijgt. Om dit te veranderen in standaard.mm, doe het volgende:

  • open een nieuwe (standaard) mindmap;
  • Haal in het opmaakpaneel het vinkje weg bij Automatische takkleur;
  • Kies Bestand > Opslaan als
  • De bovenste regel van het scherm dat opent is een afrolmenu. Kies hier de optie Door de gebruiker gedefinieerde mindmapstijlen
  • Vul bij file name in: standaard.mm
  • Druk op
    De volgende keer dat je een nieuwe mindmap maakt zullen de takken geen kleur hebben. Wat je ook zou kunnen doen is de bovenstaande, aangepaste mindmap onder een andere naam dan standaard te bewaren (bijvoorbeeld: mijnstandaard.mm). Freeplane gebruikt dit bestand als standaard indien je Bestand > Nieuwe mindmap met stijl kiest, en onder Gebruikerstijlen mijnstandaard kiest.

Installeren: F3-toets voor Bewerken knooptekst in hulpvenster

Het kan handig zijn om sneltoets F3 toe te wijzen aan de functie Bewerken knooptekst in hulpvenster. De beschrijving hoe dit moet staat in de Handleiding.


**Als gevolg van een cyber aanval zijn de voorbeelden op deze pagina niet in te zien.
Raadpleeg de Engelse voorbeelden...**

Deze Tutorial heeft betrekking op Freeplane 1.2.x. Je kunt Freeplane hier gratis downloaden.

Instructie Freeplane

Wat is mindmappen

[[:WhatIsMindMapping_nl.mm |applet|Wat is mindmappen ]] Een mindmap (spreek uit: maintmep) is een kaart van informatie die is geordend in onderwerpen en deelonderwerpen rond een centraal thema. Op scholen wordt ook wel de term woordweb of woordspin gebruikt. De informatie kan de vorm hebben van teksten, plaatjes en/of verwijzingen naar multimedia en andere programma’s. Het proces van het maken van een mindmap kan helpen bij het uitvoeren van creatieve processen zoals analyseren, plannen en organiseren; en bij leren en onthouden. Een elektronische mindmap kun je gebruiken als persoonlijke werkomgeving en om het werken in je bedrijf of op school te ondersteunen: zie wikipedia en de voorbeelden op deze pagina.

Er zijn mensen die de voorkeur geven aan het maken van mindmaps op papier en mensen die de voorkeur geven aan het maken van mindmaps met de computer. In de mindmap hiernaast zijn de belangrijkste voor- en nadelen opgenomen in verborgen tekst. Open de mindmap door op de link onder het plaatje te klikken. Klik vervolgens op de Help bij Navigeren om te leren hoe je de verborgen tekst kunt tonen.

Een mindmap op deze pagina bekijken

Door op een plaatje van een mindmap aan de rechterkant van deze pagina te klikken, kunt je het plaatje vergroten. Onder elk plaatje bevindt zich een snelkoppeling met de naam van de mindmap. Als je hier op klikt opent de mindmap in een presentatievenster en kunt je takken open/dichtvouwen en koppelingen (pijltjes) volgen door er op te klikken. Bij sommige takken verschijnt een onderliggende tekst als je de muiscursor boven de tekst van de tak (knoop) houdt. Je kunt ook de hele mindmap verplaatsen door op een lege plaats in de achtergrond te klikken en te slepen. Zie ook de instructievideo voor beginners. Je kunt de inhoud van de mindmap in deze gallerij niet wijzigen: daarvoor moet je een mindmap-programma gebruiken.

Hoe maak ik een mindmap ?

Deze galerij bevat voorbeelden van mindmaps. Op de pagina Hoe maak ik een mindmap is beschreven hoe je het gratis programma Freeplane kunt downloadenen en hoe je een mindmap kunt maken of aanpassen met dit programma. De software van Freeplane is voor iedereen vrij beschikbaar ("open source"). Het gebruik van Freeplane sluit daardoor aan bij het overheidsbeleid (NOIV). Voor het bekijken van de voorbeelden op deze pagina is het niet nodig om Freeplane op je computer te hebben: bij het openen van een mindmap op deze pagina wordt automatisch een freeplane-viewer geopend voor het bekijken van de mindmap. (Helaas worden de Nederlandse menubalken daarbij in het Engels weergegeven.)

Beginners instructie Handleiding Freeplane
Om inzicht te krijgen in de mogelijkheden van Freeplane kun je behalve de voorbeelden op deze pagina, ook de handleiding van Freepane bekijken. Deze handleiding is opgenomen in een mindmap en dient zo zelf ook als een voorbeeld van wat je met een elektronische mindmap kunt doen.

Kik op de hyperlink onder het plaatje om de handleiding te openen. Klik vervolgens op de woorden en snelkoppelingen in de mindmap om te zien wat de mogelijkheden van Freeplane zijn.

N.B. Je kunt een mindmap met extentie .mm ook met het programma Freemind bewerken. Omdat Freemind minder functionaliteit bevat dan Freeplane, zal je dan niet alles zien. Omgekeerd kan een mindmap die met Freemind is gemaakt wel door Freeplane worden getoond.

Inhoud van deze galerij

Deze galerij bevat Nederlandstalige mindmaps die laten zien wat een elektronische mindmap is en waarvoor je deze kunt gebruiken. De gallerij bevat tevens mindmaps en ideeën voor mindmaps die je kunt aanpassen voor eigen gebruik. In de tekst is aangegeven als je de mindmap op je eigen computer kunt laden (download) voor gebruik met het programma Freeplane of een ander mindmap-programma dat .mm bestanden kan lezen.

Mindmap als persoonlijke omgeving

Actie dashboard Freeplane start op met een standaard mindmap. Van deze mindmap kun je een persoonlijke werkomgeving maken met directe toegang tot je belangrijkste informatie op Internet en je bedrijfsomgeving. Snelkoppelingen naar pagina's, bestanden en applicaties kunnen eenvoudig met plakken en knippen (drag and drop) aan de mindmap worden toegevoegd. Verder kun je op elk punt eenvoudig notities en signaleringen toevoegen. Hiermee is Freeplane uitermate geschikt om actielijsten te maken en onderhouden. Verder is Freeplane te gebruiken als een dashboard waarmee je toegang tot al je documenten en applicaties hebt. Als je je mindmaps en andere documenten bijvoorbeeld met dropbox bewaart, kun je hier vanaf elke computer bij.

Digitale kluis

Mijn kluis Als je informatie hebt die anderen niet mogen kennen dan kun je deze informatie met een wachtwoord beschermen. Het is mogelijk een hele mindamp te beveiligen of alleen een (deel)tak met knopen. In het voorbeeld hiernaast is de hele mindmap met een wachtwoord beschermd. De mindmap heeft twee hoofdtakken voor repectievelijk geldzaken en websites. Deze zijn elk apart nogmaals beschermd.

Open the mindmap door op Mijn kluis onder het plaatje te klikken. Zoek dan het pictogram het slotje in de balken bovenin het scherm en klik hierop. Er verschijnt dan een venster waarin je een wachtwoord moet typen. Type MyVault. De mindmap opent nu en laat de takken voor geldzaken en websites zien. Selecteer van een van de banken de knoop "creditcard". Klik op het slotje en vul als wachtwoord opnieuw creditard in. Er open nu een knoop met de gegevens van de creditcard. Hetzelfde kun je doen met de andere bank. Ga nu naar de kant van de websites. Kies Freeplane open forum, klik op het slotje en voer als wachtwoord "Freeplane" in. Nu wordt de inlog informatie van de website zichtbaar.

Contacten

Contacten Er zijn verschillende manieren om adreslijsten e.d. in een mindmap te vatten. De linker kant van de mindmap toont contactgegevens welke in de attributen van een knoop zijn vastgelegd. De rechterkant van de mindmap toont contactgegevens die in zogenaamde kindknopen zijn vastgelegd. De vorm van de takken is in dit geval rechthoekig gekozen.



Mindmap op het werk

Freeplane als hulp bij vergaderen

Meeting support: Beginner Meeting support: Advanced Een van de dingen waarvoor Freeplane vaak wordt gebruikt is het maken van aantekeningen tijdens vergaderen. Freeplane kan zelfs het hele vergaderproces ondersteunen. De ondersteuning begint bij het het opstellen en verspreiden van de agenda, het bijhouden van de deelnemerslijst, het toevoegen van aantekeningen bij de agendapunten en eindigt met het vastleggen van de notulen met besluiten en acties. Daarbij kan Freeplane elke actie een herinnering koppelen zodat deze niet wordt vergeten. Ook is het mogelijk informatie die nodig is tijdens de vergadering via de mindmap te ontsluiten. En niet in de laatste plaats kan gevoelige informatie met een wachtwoord worden afgeschermd.

De boven besproken handleiding maakt onderscheid tussen drie ervaringsniveaus: Beginner, Ervaren en Professional. De twee figuren hiernaast tonen dezelfde informatie, maar dan opgemaakt door een beginnende en een ervaren Freeplane gebruiker. Als je beide mindmaps bekijkt dan zie je dat de mindmap van de ervaren gebruiker een betere ondersteuning biedt. Van belang is verder dat als je de speciefieke informatie van de behandelde vergadering weg haalt, een generiek vergadersjabloon over blijft dat ook voor andere vergaderingen kan worden gebruikt.

Klik op de hyperlinks onder de plaatjes om de beide mindmaps te openenen. In Vergadering geavanceerd: zweef met de cursor over de teksten om de verborgen teksten te zien. Je kunt hier een animatie zien hoe deze mindmap is gemaakt.

Als je precies wilt weten hoe notuleren met een mindmap in zijn werk gaat, lees dan Notuleren en mindmappen, een perfecte comninatie van Marjolein de Jong. Zij maakt een aparte mindmap voor elk agendapunt, hetgeen bij een mindmap op papier is aan te raden. Bij een elektronische mindmap kunnen alle agendapunten binnen één mindmap worden opgenomen, zoals in het voorbeeld hiernaast, omdat de agendapunten desgewenst kunnen worden verborgen (dichtgevouwen) of getoond (opengevouwen).

Dingen gedaan krijgen (GTD: Getting Things Done)

Dingen gedaan krijgen

David Allen heeft een methodiek beschreven om efficienter en relaxter te kunnen werken. Deze methodiek wordt wereldwijd door vele kenniswerkers gebruikt. De methodiek is samengevat in nevenstaande mindmap. De mindmap kan daarbij worden gebruikt als ondersteuningsmiddel om activitiviteiten en gegevens te beschrijven.

Mindmap als hulp bij plannen

Een mindmap kan worden gebruikt om acties te plannen. Hoe de mindmap er uit moet zien is afhankelijk van de situatie. Soms heb je genoeg aan een actielijst met per actie een naam en een aanduiding van de prioriteit (mindmap links; klik op het plaatje om dit te vergroten). Soms wil je ook de datum gereed en een actiehouder tonen (mindmap midden). En soms is het handig om ook een beschrijving of toelichting van de actie te kunnen tonen (mindmap rechts). Freeplane combineert deze drie mogelijkheden in één en dezelfde mindmap. Ook is het mogelijk een moment in te stellen waarop je herinnert wilt worden dat actie nodig is (aqenda). En natuurlijk kan aan elke actie (taak) een boom van deelacties worden gekoppeld. Er ontstaat zo een logisch stroomschema van gerelateerde acties. Met verbindingslijnen kunnen relaties tussen acties in verschillende stromen worden aangegeven.

Open de mindmap Actielijst door op de hyperlink onder een van de plaatjes te klikken. Klik in de bovenste actie (knoop) op het pijltje omhoog (driehoekje) om de toelichting (= bijlagetekst) te verbergen. Houd de cursor boven de tekst van de derde actie om de verborgen toelichting, actiehouder en datum gereed te zien. (Actiehouder en datum-gereed zijn opgenomen als attributen.) Houd de cursor boven de tweede actie om de brief te zien die Jan Janse heeft gestuurd en waarop een antwoord wordt gevraagd (= notitietekst). De agendafunctie is alleen beschikbaar als de mindmap met Freeplane op de eigen computer wordt uitgevoerd. [[File:Taakverdeling3.jpg|left|Actielijst ]] [[File:Taakverdeling1.jpg|left|Actielijst ]] [[File:Taakverdeling2.jpg|left|Actielijst ]]













Mindmap bij samenwerken (teamrollen van Belbin)

Teamrollen Belbin

Samenwerken binnen organisaties is niet altijd even gemakkelijk. Op basis van onderzoek onderscheidt Belbin 9 teamrollen. In de juiste verhouding en combinatie kunnen deze rollen elkaar versterken en bijdragen aan het succes van projecten. In de verkeerde verhouding kunnen ze leiden tot het mislukken van projecten. Met een test kun je bepalen welke (drie) rollen je teamleden en jou het beste liggen. Vervolgens kun je in de mindmap hiernaast achter elke rol de namen van de personen plaatsen die geschikt zijn voor de betreffende rol. Hiermee maak je inzichtelijk en bespreekbaar in hoeverre het team voldoende gevarieerd en volledig is en welke rollen bijzondere aandacht vereisen.

Open de mindmap door op de hyperlink onder het plaatje te klikken. Beweeg de cursor boven elke teamrol en er verschijnt een beschrijving van de rol; de tekst is overgenomen uit de wiki over Belbin. Klik op de pijltjes en er opent een relevante webpagina. Eén van de pijltjes opent een videofilmpje over de 9 rollen van Belbin op Youtube.

Mindmap bij een SWOT-analyse

[[File:SWOT.jpg|thumb| [http://www.kioo.nl/freeplane/swot  SWOT-analyse] ]]

Bij het analyseren van een organisatie of project wordt soms gebruik gemaakt van een SWOT-analyse, zie Wikipedia. Een elektronische mindmap kan helpen om de Sterkten, Zwakten, Kansen en Bedreigingen te beschrijven en vervolgens te ordenen. De mindmap kan bovendien helpen om de betekenis van deze begrippen uit te leggen.

Klik onder het plaatje op de hyperlink SWOT-analyse om de mindmap te openen. Merk op dat (schaalbare) plaatjes zijn gebruikt om de begrippen Sterkte, Zwakte, Kans en Bedreiging te illustreren. Breng de cursor boven respectievelijk de tekst Sterkte, Zwakte, Kans en Bedreiging om te zien wat deze begrippen betekenen. Naast elk van deze begrippen wordt een voorbeeldinvulling getoond. Breng de cursor boven de basisknoop (SWOT) om verwijzingen naar literatuur te zien.

Mindmap voor de samenhang van metagegevens

Samenhang metagegevens Informatie binnen een organisatie moet worden geordend, beschreven en beheerd om te zorgen dat dat deze kan fungeren als betrouwbaar en toegankelijk bedrijfsgeheugen. De mindmap rechts maakt zichtbaar dat de metagegevens die hiervoor nodig zijn uiteenvallen in een aantal groepen: elke groep is omgeven door een rechthoekig kader. Pijlen geven relaties tussen gegevens aan en labels bij de pijlen beschrijven de aard van de relatie. Op deze wijze kunnen bijvoorbeeld alle metagegevens voor de rijksoverheid worden beschreven.

Klik op de hyperlink onder het plaatje om de mindmap te openen. Beweeg met de cursor over de teksten om de verborgen toelichtende tekst te tonen. Selecteer de centrale knoop en klik vervolgens in de menubalk op de rode cirkel met het minteken om de hele mindmap dicht te vouwen: je ziet dat alleen de vijf groepen gegevens. Klik vervolgens op elke groep om deze één voor één open te vouwen.

Mindmap voor informatiebeheerregels

Generiek waarderingsmodel Voor de rijksoverheid is in het Generiek waarderingsmodel rijksoverheid (GWR) beschreven welke informatie blijvend (B) dan wel een bepaalde tijd (V + vernietigingstermijn in jaren) bewaard moet worden. De beschrijving bestaat uit een document en tabel van 26 pagina’s met hoofdprocessen en subprocessen; en voor elk van deze processen een beschrijving, toelichting, waardering (B/V) en voorbeelden. Dit is veel en daardoor minder makkelijk te overzien en gebruiken. Dezelfde informatie wordt in de mindmap rechts gelaagd en modulair gepresenteerd. Met het zoek- en filtermechanisme van de mindmap heb je direct toegang tot alleen die informatie die je op een bepaald moment wilt zien.

Bekijk de demonstratie. Open daarna de mindmap door op de hyperlink onder het plaatje te klikken. Beweeg de cursor over de teksten (hoofdprocessen) om de volledige beschrijving (categorie), toelichting en voorbeelden te zien. klik op een hoofdproces om deze open te vouwen zodat de subprocessen worden getoond. Beweeg de cursor over de subprocessen om de volledige beschrijving, toelichting, waardering en voorbeelden te zien. Vul in de zoek/filterbalk een term in om te zoeken/filteren zoals in de demonstratie. Raadpleeg de handleiding om meer over zoeken en filteren te lezen.

Mindmap voor informatiebeheer bij digitaal werken

Informatiebeheer bij digitaal werken Bij digitaal werken verandert er veel, zowel voor de gebruiker als de beheerder van informatie. Deze mindmap toont per proces van de gebruiker en de beheerder de belangrijkste veranderingen.



Mindmap bij het oplossen van problemen

In het engelstalige artikel Freeplane and problem solving wordt een algemene methode beschreven om met gebruik van twee mindmaps een veelheid aan problemen op te lossen.



Mindmap in de klas

Een mindmap kan worden gebruikt om op een flexibele en interactieve manier informatie voor een les aan te bieden. Dezelfde mindmap kan daarbij door de leerling worden gebruikt om de antwoorden op de vragen die hij heeft gevonden vast te leggen, en eventueel te leren. Zie ook TU Delft, sectie EduTec en Onderwijs van morgen.

Sneller leren door vooraf vragen te stellen

WH-VragenOm sneller te leren helpt het om vooraf wat- en hoe-vragen te stellen en deze tijdens het leren te beantwoorden, zie lereniseenmakkie.nl. Een mindmap kan dit proces handig ondersteunen. De mindmap is te downloaden.




Maken en geven spreekbeurt

[[File:SjabloonOctopus.jpg| left| Sjabloon spreekbeurt ]] Spreekbeurt Een mindmap kan worden gebruikt om een opdracht voor een spreekbeurt te geven met aanwijzingen (hints) op welke vragen de leerling een antwoord kan of moet zoeken en met een begin van literatuur. De leerling kan de literatuurverwijzingen in de mindmap aanklikken en bestuderen en de antwoorden op de (eigen) vragen aan de mindmap toevoegen. Links is een voorbeeld mindmap met kernwoorden voor vragen en literatuurverwijzingen opgenomen. Voor de gevorderde leerling kan men de kernwoorden en/of de literatuur eventueel verwijderen. Als de mindmap is ingevuld kan deze worden gebruikt om de spreekbeurt te leren en te houden. Rechts is een mindmap met antwoorden opgenomen die kan worden gebruikt voor het houden of controleren van de spreekbeurt. Beide mindmaps zijn te downloaden.

Geordend presenteren en verwerken van informatie

Kabinet Rutte In nevenstaande mindmap is de samenstelling van het Rutte** samengevat. Bij elke minister en staatssecretaris is een snelkoppeling opgenomen naar het politieke profiel en de CV van de betreffende minister en staatssecretaris. De les zou kunnen bestaan uit het opzoeken van de politieke partij waartoe elke lid van het kabinet behoort. Het antwoord op deze vraag zou door de leerling zelf kunnen worden toegevoegd aan de mindmap. De mindmap kan hij daarna bewaren als persoonlijke geheugensteun.



Instructievideo's

LET OP: de instructievideo's maken gebruik van de menustructuur van Freeplane 1.1.3. Vanaf versie 1.2.5 wordt een minder complexe menustructuur gebruikt (zie boven de mindmap van de handleiding met de nieuwe menustructuur).


Links

Onderwijs

Images

Add your own icons to Freeplane

Icons can be easily installed by copying them to the directory

<freeplane_userdir>/icons

The function Tools -> Open user directory takes you to the "freeplane_userdir". Create the directory icons if necessary and copy your own icons to it.

Restart Freeplane if necessary: you can now use your own icons in your maps.

Replace a built-in Freeplane icon

If one of your own icons has the same filename than a standard Freeplane icon, this standard icon will be overridden. This is perfectly safe. Just remember it if you share your map with another Freeplane user, he or she will see the standard icons, not yours.

You can find the standard icons filenames in this folder of the Freeplane sources (this link lead to the 1.8.x version of Freeplane, but you can change this with the "branch" button).

Here's a preview of the icons and their filenames for Freeplane 1.8.x:

Freeplane-1.8.x-icons.png

Some sources of free icons

Introduction

There are many programs which can capture what you are doing on the screen and turn it into a video which can be viewed on Youtube. The problem with Freeplane maps in following this procedure is:

  • the resolution of the video is too low to be able to read the content of Freeplane's nodes;
  • the amount of memory stored is disproportionally large.

The following describes a procedure which keeps the resolution necessary for crisp, readable mind maps and takes a minimum amount of storage space.

Wink

The program used is [which is a free software. Wink captures the screen and the position of the mouse cursor independently from each other. To see the cursor moving on the screen, only the begin and end points of the cursor are stored. If besides the cursor, the screen is not changing, only one screen is captured during the whole movement. Next when running the video Wink displays the screen and (re)generates the cursor movements. Each screenshot can be extended with call outs, images and recorded sounds giving an impression of a running animation or video - in the full resolution in which the screen is captured. The result can be rendered into flash. A special version could be converted to whatever format you need (e.g. mp4 or avi), although it is not clear you would want this if you are using a computer.

Principle

In the following a standard procedure is developed which:

  • makes sure the Freeplane map is readable enough;
  • helps to minimize the work involved;
  • makes possible to reorganize and adapt a recording at a later time;
  • gives the best result if conversion to a video format or YouTube is necessary.

For this setting and procedure a supporting html file is provided which will make sure the flash file is displayed the best possible way.

Solution 1: source animation or video

  • Define a directory with the name of the video you are going to make, e.g. myVideo.
  • Download http://www.debugmode.com/wink/Wink. Read its instruction.
  • Open Wink
  • Select File > New.
  • Select fixed screen size of 1280 x 720 (HD), e.g. window region 31,10 x 1310,729. Markers are shown which indicate this area.
  • Open Freeplane. Make Freeplane window fit exactly within the capture area shown by Wink.
  • Select input driven capture rate at mouse click, key press
  • Minimize Wink
  • Use Alt + Pause to start/stop input driven capture; or use Pause for a single screen shot.
  • When finished, render video for Macromedia flash (or if you want to convert it later to mpeg4 of avi, Macromedia uncompressed).
  • Save the generated files in directory myVideo. The files generated are: myVideo.htm, myVideo.sfw and myVideo.js.
  • Rename myVideo.htm into w1280x720.html
  • Use the procedure below to create file index.html and copy it into directory myVideo.
  • If you want to view the video on your computer, start index.html; or
  • If you want to use the video on your webserver, upload the directory myVideo to your webserver. The video starts if you address .../myVideo; this will automatically call index.html which will do its thing and call w1280x720.html.

N.B.1 The flash file generated should not be called right away, because image quality will be terrible because of resizing.
N.B.2 In stead of copying index.html to myVideo, you could rename myVideo.htm to index.html (in stead of renaming it to w1280x720.html). In that case your browser will take more place on the screen and the video must be scrolled vertically more frequently if your screen is too small.

Create file index.html

The wink video is played in your browser. The file index.html makes sure the viewing window for the wink video is maximal (it opens a new window) and that it is set to a fixed size which gives best video quality. For this the directory where you keep your video, e.g. .../myVideo, must contain a file index.html (see the above procedure). The content of this file is shown below. Copy the following text to an editor such as Notepad and save it as index.html:

`

Click here to open the page in a new window.

`

Example

The following video was created this way. http://www.freeplane.org/mapsOnline/video contains other examples.

Dowload and unzip this example. Execute index.html for the (compressed) wink video. Run myVideo.mpg to see the same video if converted to mpg with iWisoft. Note the difference in file sizes.

Solution 2: convert to mpeg, avi

a. plain convert

With solution 1 the basic animation/video is created. Once this has been tested and is final, it is possible to convert it to a HD quality mepg 4 or avi video:

  • render the wink project a second time, with in "Project settings" (icon in top bar) option "Macromedia uncompressed".
  • convert the resulting flash file with a free flash to mpeg convertor. Important: not every conversion program correctly converts the pauses which may be set. As an example, capture the wink video using iwIsoft. (The free version of wWisoft has an iWisof icon on the screen)

The resulting mpeg 4 can be played on your TV/video system, or uploaded to YouTube.
N.B.1 Set the conversion options for optimal resolution. The procedure described focusses on HD-quality.
N.B.2 The image quality is less and the size of the file is much larger than the file produced in solution 1.
N.B.3 The video will fit the whole screen and doesn't need scrolling.

b. 2nd screencapture

It is possible to play the wink video from solution 1 and capture it with a program of your choice, e.g. Microsoft Expression Encoder 4 Screen Capture and next encode it with Microsoft Expression Encoder 4. (This solution has no iWisoft icon on the screen.)

Hints for working with Wink

  • Wink allows you to record single frames. Wink also allows to record and handle scenes (a number of frames) independently and add together the scenes only when you have tested and finished each scene. This makes editing and testing faster.
  • The movement of the cursor can be set or changed AFTER the recording of a scene. Just drag the cursor (rectangle + cursor in the frame) to its begin or end point. In this way scenes can be connected with the cursor going as you want it. If a cursor is missing, just copy it from another frame and paste it in the frame where the cursor is missing. Next move it to the position you want. If you connect different recording, copy the cursor of the prior scene into the current scene to prevent the cursor to move unexpectedly.
  • To change a scene, you may rerecord part of it and copy and paste the selected frames into the old scene. The duration of each frame can be set AFTER the recording. Also labels and images may be added AFTER the recording. This makes designing and editing scenes flexible and productive. A narrative or sound can be added AFTER recording. If necessary adapt the duration of the frame the sound is in.
  • After recording you may have frames in which nothing changes. These frames may be deleted. This makes editing more easy and keeps the size of the Wink video very small.
  • The cursor may be changed. Select the cursor and in the right dialog load and select the mouse cursor icon. A practicle use is to duplicate (copy and paste) the frame where the mouseclick should happen. Next in the first of the two identical frames, change the cursor to the mouse cursor and set the time of this frame to 1 second.
  • Keypresses can be added in the same way as the above mousecursor. Alternatively keys may be added as images. Again duplicate the frame where the key should be shown, load the key image in the first image, and set the time to 1 second.

What is a vision?

A vision for a project is like a constitution for a state, it should give a common sense of values by which all members of the community abide, it should be broad and generic enough that it doesn't need to be changed often, but it should also be precise enough that rules and decisions can be checked against it.

Project vision: contribution driven development

The main goal of the project from its very beginning is creating a contribution friendly climate. If somebody like you and me is crazy enough to spend time and efforts for the project doing coding, documenting, testing or supporting the community, it should be welcome. The people should have a feeling of being wanted and welcome.

As a project member anyone has the freedom to develop his own ideas and document them, to implement them or have a chance to inspire and convince the community and the coders to implement the ideas. Also if somebody wants to contribute in a way not foreseen in a concept, the contribution is allowed to happen and that the concept should reflect new ideas.

Product vision: be the Eclipse of the mind mapping world

We strive to develop FreePlane as a lean framework for mind mapping, with clear and well-documented interfaces, allowing for easy extension and customization by programmers, scripters and other non-developers, federating them in a lively community supporting our project vision. We furthermore strive to make FreePlane the reference implementation of a yet-to-be-developed open and extensible mind mapping file format aligned with the Open Document Format.

On this page we collect information about what can help us to develop this project

Our requests for enhancement to SourceForge

The ideas are collected in IdeaTorrent. SourceForge claims to implement the ideas getting the most votes. You can support the project giving the requrests we need your votes. Click on green arrows to vote for the proposals.

Reported on 2017/02/19

Fix released on 2017/04/15

Reported by Wojciech Reguła, https://www.linkedin.com/in/wojciech-regula/

Description of Vulnerability

The vulnerability allowed to download any file from victim's computer when the victim opens the malicious mindmap. The vulnerability pattern is described at https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing.

Customizing Freeplane

The user directory

Contents of the user directory

Location of the user directory

Depending on your OS and personal preferences, you can find the user directory in different places.

Windows

TODO

Linux

System-wide configuration directory for Freeplane (installed via the package manager of your distribution):

/usr/share/freeplane/

User directory (in the .config folder inside the home directory of the current user):

~/.config/freeplane/

MacOS

TODO

Opening the user directory from the menu

You can open the current user directory of Freeplane in your default filebrowser via the menu: Tools > Open user directory.

Change the location of the user directory

You can change where the user directory should be.

Command line

In the command line you can change the path to the user directory when invoking Freeplane with the following command:

freeplane -U<userdir>

Customizing Freeplane

The user directory

Contents of the user directory

Location of the user directory

Depending on your OS and personal preferences, you can find the user directory in different places.

Windows

TODO

Linux

System-wide configuration directory for Freeplane (installed via the package manager of your distribution):

/usr/share/freeplane/

User directory (in the .config folder inside the home directory of the current user):

~/.config/freeplane/

MacOS

TODO

Opening the user directory from the menu

You can open the current user directory of Freeplane in your default filebrowser via the menu: Tools > Open user directory.

Change the location of the user directory

You can change where the user directory should be.

Command line

In the command line you can change the path to the user directory when invoking Freeplane with the following command:

freeplane -U<userdir>

node core

The core of a node, where one can add some text. It can also be opened and edited with the inbuilt editor.

Introduction aka many unsorted ideas related to Freeplane

Getting started

Freeplane is very powerful and customizable, so we recommend you learn the basics before reading straight through all of the documentation, and be aware that you don't need to know about all of the advanced features and concepts to benefit from Freeplane. Have fun!

Why Freeplane?

What are mind maps?

Mind maps are diagrams and a visual way of associating topics, terms and smaller graphical elements. This allows to get an overview about a topic as well as showing a certain degree of strucutre. Spreading from the center outwards, they have a hierarchy (tree-style) and connect different aspects and elements. Mind maps can therefore be used to structure topics, make outlines for texts, document brainstormings or serve as a knowledge-base. The method of "mindmapping" and mind maps are coined by the british author and psychologist Tony Buzan († 2019).

Why use mindmapping software?

Why use Freeplane rather than other mindmapping software?

Freeplane is a mind mapping program with many overwhelming advantages and a small number of significant disadvantages when compared to similar programs.

Advantages:

  • Completely free and open-source
  • 15+ years of active development
  • Frequent updates and improvements (on average, new development versions every 2 weeks)
  • Cross-platform (Win, Mac, Linux)
  • Can handle very large maps (10,000+ nodes) with good performance
  • Supports add-ons, plug-ins, and custom scripting
  • Open and well-documented API
  • You own all your data in local files with open formats
  • Extremely customizable
  • Active community
  • Allows full keyboard control
  • Supports complex formatting and styling logic
  • Supports text, number, and date/time data formats
  • Supports formulas (not just display, but actual calculations on map data)
  • Supports HTML, Markdown, and LaTex

Disadvantages:

  • UI is very dated (if you can help us improve this, please contact us!)
  • No mobile client (Freeplane API now supports mind maps as an event stream; if you want to help us develop a mobile client, please contact us!)
  • Does not currently support real-time online collaborative editing (if you want to help us develop this capability, please contact us!)
  • Does not support as wide a variety of layouts as some other programs, such as flowcharts, org-charts, and Gantt chart. We are open to developing these features if users identify them as needed.

Until recently, Freeplane has had one other significant disadvantage: documentation that was completely inadequate for conveying its immense functionality. Freeplane can do so much, and gives the user so many options, that it can be overwhelming. This documentation site is our ongoing attempt to address this concern!

A note about types of mind mapping software

There are many applications with overlapping functions but different primary purposes. You can make mind maps with Microsoft PowerPoint, but it is fundamentally a presentation program. Freeplane is not fundamentally a diagramming program, or a team project management program, or a calendar program, but it can serve all of those needs to different degrees.

It is useful to know, however, that Freeplane is fundamentally a program designed to capture, organize, and manipulate information in mind maps, and to be highly customizable down to its basic functions, including scripting and add-on support.

About this documentation

How we think about documentation

User levels

Credits and contributors

Previous documents used to create this site include:

15 part Freeplane manual written by Elmer Perry, published online in Full Circle Magazine (www.fullcirclemagazine.org) under a Creative Commons Attribution—Share Alike 3.0 Unported license; parts available at https://fullcirclemagazine.org/tag/freeplane/

Manual de Freeplane [Freeplane Manual] written by Luis Javier Gonzalez Caballero aka kewapo, 2019

Materials previously hosted on www.freeplane.org

Documentation and tutorial mind maps distributed with Freeplane and accessible (currently or previously) through Freeplane's Help menu

Understanding Freeplane concepts

Mind map elements

Speaking generally, mind maps are made of two elements: nodes and connectors. Nodes contain information, often put in a shape or "bubble", and connectors are lines that show relationships between information.

There are two main types of connectors in Freeplane that relate to two different ways people think of mind maps. Traditionally, mind maps were primarily thought of as aids for brainstorming, and this led to a "whiteboard" model where the nodes quickly captured information and were placed and connected in a loose way to show general associations between ideas. The focus was on information capture and creativity.

Mind mapping software, however, started to bring mind maps more of an "outlining" model, with increased focus on capturing information in order to organize it into more meaningful structures. Freeplane, like most mind mapping software, defaults to this type of structured approach, although it supports both models quite well.

In Freeplane, these two models are reflected in two ways to connect nodes. (Edges)[link] connect nodes in hierarchical relationships (sometimes referred to as family relationships) and reflect the "map as outline" approach. (Connectors)[link] link nodes in looser ways that can be specified by the user with labels, reflecting a "map as whiteboard" approach. We will call these "hierarchical" and "general" connections, but note that "general" refers to the broad variety of meanings that connectors can have, not that connectors can imply only vague relationships. With labels, connectors can be extremely specific.

Hierarchical node connections (using edges) are not exclusive from general node connections (using connectors). Maps can use both, and their functions overlap. Yet this distinction can help users understand why Freeplane has both edges and connectors.

Although it supports many uses, Freeplane focuses on the "map as outline" model over the "map as whiteboard" model. It emphasizes organization and manipulation of information more than diagramming flexibility. Freeplane thus considers edges more fundamental than connectors, and will automatically connect all nodes with edges, while connectors must be added manually one-by-one.

(Like almost everything in Freeplane, this is a changeable default. This documentation describes Freeplane based on its default settings, many of which can be changed in ways described elsewhere in the documentation).

There is one last fundamental element to Freeplane mind maps: the map background, which is blank white by default, but can be customized in different ways.

Summary: the four basic Freeplane mind map elements are nodes, edges, connectors, and the map background

Mind map structure

Nodes can be thought of as having levels, with first-level nodes being those nodes directly connected to the central node of the map (also known as the root node). Nodes connected to first-level nodes are second-level nodes, being two "steps" away from the central node, and so on.

Discussion about node levels can be confusing because when users refer to higher-level nodes, they are usually talking about nodes closer to the root node, which have a lower level "number". For example, a first-level node (level 1) is often thought of as higher level than a fourth-level node (level 4), even though four is more than one. Possibly for this reason, node relations are most commonly talked about using metaphors rather than numerical levels. This documentation uses two main metaphors to discuss how nodes relate to each other: 1) a tree, and 2) family relations. (These are sometimes combined in the notion of a "family tree").

Tree metaphor

The central node is called the root, like the root of a tree. The first node connected to the root is the beginning of a branch. The branch includes all nodes connected to that first branch node. Branches can divide into smaller branches. At the end of a branch are leaf nodes, which are the nodes farthest from the root node, and which have no higher-level nodes connected to them by edges.

The leaf nodes in a map are not all necessarily at the same level. Any node that is at the highest level on its branch is a leaf node, but different branches might extend to a different number of levels.

(e.g. to be added)

Family relations

Higher-level and lower-level nodes are usually described in terms of family relationships. A level one node is the parent of a level two node that is directly connected to it, and the level two node is the child of the level one node.

Child nodes that share a parent node are sibling nodes.

Sometimes, people refer to multiple levels using family terms (e.g. a node's grandparent or grandchildren), but the most common terms are parent, child, sibling, ancestor, and descendent.

Leaf nodes are more easily understood using family terms: leaf nodes are simply nodes with no children, and non-leaf nodes are any nodes with children.

Exception: free nodes (sometimes called "free positioned nodes") can be added to maps outside of the map hierarchy. They are technically children of the root node, but do not follow normal node behaviors and are formatted differently.

Map layout

Unlike some other programs, Freeplane focuses on mind maps that have a hierarchy of nodes connected in family relationships. This one logical layout can be viewed in two ways in Freeplane:

  • Freeplane defaults to a map where branches radiate outward from the root node in many directions, similar to spokes on a bicycle wheel. This is the "normal view" (sometimes called a radial view).
    • Note: the user can keep all branches on one side of the root; see [link] for more information.
  • The "outline view" lets you see the information in your map in a vertical list more like a traditional outline, with the root node at the top and branches below.

How node formatting works in Freeplane

Freeplane has the capability for much more advanced formatting than most mind mapping programs, and thus formatting can become quite complex. This section explain the basic logic of Freeplane formatting so you can understand these options and eventually learn to use the program's capabilities.

Nodes are formatted by looking at options we call formatting elements. These elements include familiar ways to change text appearance, such as making text bold, changing text size, and using different fonts. Mind maps also offer formatting options such as choosing node shape and edge color.

Each of these formatting elements has a value. The element "bold" can have the value "on" or "off". The element "font size" can have a wide range of numerical values. To format map nodes, Freeplane looks at each of the relevant format elements, determines each element's value, and then formats the node accordingly.

Node formatting in Freeplane is more complicated than typical text formatting in other programs because, for maximum flexibility and functionality, formats can be set in four ways:

  1. directly, manually, for each formatting element of an individual node
  2. directly, by manually applying a saved combination of formatting element values, which we call a style
  3. indirectly, by setting defaults that automatically apply styles to certain types of nodes according to program preferences
  4. indirectly, by setting custom logical rules that determine the values a node will have based on conditional criteria

Regardless of how format is set, Freeplane looks in several places, in a certain order, to determine the value of various formatting elements so it can format the node. For the basic user, Freeplane's formatting logic can be understood like this:

  • Freeplane sets all of the formatting options to match the node's style (either Default or another style). (For more detail on how this works, see (Styles and Templates)[link].)
  • Freeplane then checks if the user has set any specific formatting values for this individual node (e.g., "font size=12"). If they have, Freeplane changes the formatting value for this node to the user setting.

(e.g. to be added)

For the advanced user, Freeplane's formatting logic is better described in this way: for each formatting element, Freeplane checks the values set at each location in following list. It uses the value at the highest (topmost) level in this list where the element's value is set.

  • formatting tags inside node core text (hidden from most users)
  • values manually set at the individual node
  • node conditional styles (values set by user-specified rules)
  • map conditional styles (values set by user-specified rules)
  • values defined by the node style (if other than Default)
  • Default style values
  • internal program values (invisible to end user)

(e.g. to be added)

It is important to understand that not all formatting elements are given values at each of these levels. For example, a user might set an individual node to "bold = on" but change no other values. In that case, when finding a value for a different element (like "font size") Freeplane simply checks the next lower level down and uses the first value for the element that it finds.

Getting help

This documentation is a work in progress with a long way to go. If your question is not answered here, see the resources listed in Freeplane under Help->Web resources for additional help.

Asking questions in the Freeplane forum will help us figure out the documentation areas we need to improve.

Freeplane community

Installing Freeplane

Your first Freeplane map (tutorial)

Understand the Freeplane interface

Overview

The main workspace in Freeplane is the map window in the center. You can have several maps open at the same time, each one marked by a tab at the top of the map window.

Above the map window are the Menu bar and several toolbars. At the top is the Menu bar, which lets users take actions such as opening and editing maps. Below that is the toolbar (lets you perform Menu actions by clicking icons), then the filter bar (for searching and filtering nodes), and then the F-bar (for quickly performing actions using Function keys as hotkeys).

On the left is the Icon Panel, used to easily add icons to nodes, and on the right is the Tool panel, which has four tabs used for various functions. The Icon Panel and Tool Panel can be toggled open and closed by clicking on the black triangle/arrow on the skinny sidebars on either side of the map window.

When made visible, the Notes Panel is below the map window, and at the bottom of the Freeplane interface is the status bar, which shows information about the selected node.

The Freeplane interface

Here we describe the default Freeplane interface in more detail. Almost all of these elements can be customized or hidden.

Map window

Tool bar

Filter bar

F-bar

Icon panel

Tool panel

Docked on the right side of Freeplane is the Tool panel, which can be toggled open/closed with Alt+P or by clicking the arrow in the right skinny sidebar.

The Tool panel has four tabs, also called "panels": the Format Panel, the Attributes Panel, the Calendar Panel, and the Presentations panel. Of these four, most users will only use the Format Panel.

(to be added)

Format panel

Attributes panel

Calendar panel

Presentations panel

Note panel

Status bar

Undocked control windows

Some of Freeplane's functions are controlled by windows that appear upon certain user actions. These pop-up windows include the following:

Style Editor

The Style Editor is the main interface for editing node styles. See Styles for more information.

(to be added)

Filter Composer

The Filter Composer works together with the Filter Toolbar to help you find and display a subset of your map nodes, which can be useful for a wide variety of tasks. See Filtering nodes for more information.

(to be added)

Script Editor

Find Panel

The Find Panel provides a pop-up version of the Find Toolbar that can be left open to better manage searches. See Searching Nodes for more information.

(to be added)

Find and Replace Panel

In-Dialog Node Editor

Freeplane nodes and node elements can be edited "in-line" or "in dialog". Editing nodes in-line means to edit them directly in the map. This is the most common way to edit nodes. To edit nodes or node elements in dialog means to edit them in a pop-up window that offers more editing options and controls.

Freeplane uses an editor called SimplyHTML. It is a basic editor with some drawbacks (such as limited support for keyboard controls), but the team does not currently have the capacity to update it or integrate a different editor with Freeplane. Offers to help on this front are welcomed.

(to be added)

Map context menu (right-click menu)

Right-click a free space in the background to open the so-called Background Context Menu. In this menu you can activate or deactivate the "menu bar", "tool bar", "filter bar", F-key bar and "icon bar"

(to be added)

Node context menu (right-click menu)

View options

To view or hide workspace elements

Zoom

View settings

Working with map windows

Activating maps / moving between maps

Creating map windows

Arranging map windows

Split views

Hotkeys

Understanding hotkeys

Customizing hotkeys

Saving/loading hotkeys

Viewing hotkey assignments

Other resources

Videos

Understanding nodes

Node elements

Overview

Nodes are the fundamental element of mind maps. Although nodes appear simple at first, they have many optional elements that can increase their functionality.

What appears to be the whole node at first is actually just the node core. If you create a new node and begin typing, the text is entered in the node core by default. Beginning users generally limit their use of nodes to the node core.

Additional information can be stored in nodes outside the core as node details, node notes, and node attributes.

Node core

The node core is the only part of the node that is always visible whenever the node itself is visible. The node core can itself contain several types of information: text (including numbers), icons, images, and links.

Several Node cores in a mind map

The text in the node core can be interpreted or parsed by Freeplane in different ways, which can be set in the Format Panel drop-down menu Core text->Format. To understand the implications of this setting, see (to be added).

Node Details

Purpose

Node details, seen beneath the node core, displays closely-related information about the node core text. It adds meaning to the node. One way of looking at this relationship is like a book title and its sub title. It can elaborate, embellish, clarify, define, etc. - like a child node.
But sometimes a child node seems too distant.

Even images can be placed in node details.

Node details can represent many different relationships to the node core. The following examples are in this format: node core / node details
parenthetical: dialog / floating editor
appositional: Sam / my dog
factual detail: end of WW2 / Sept 2, 1945
elaboration: our wedding / beautiful day - all family members there

And so on to meet your needs.

Using node details

There are three operations or actions you can perform on node details

  • Creating and editing node details
  • Hiding node details
  • Removing node details

Create or edit node details

When a node is selected, you can create a detail for it, if none already exists, or you can edit an already-created detail. While typing your text, to force a line break, press Shift+Enter.

There are two methods to choose from.

1. In-line editing, directly beneath the node. In-line editing offers fairly basic editing tools (via right-click or hotketys on selected text). When done typing, either

  • press "Enter" to save the detail and exit the in-line editor
  • press "Insert" to save the detail and create a new child node.
  • Or, press "Esc" to cancel and exit the in-line editor without saving your work.

To access in-line editing: Select a node then either

  • press F3
  • use the Edit menu > Node properties > Edit node details in-line
  • Command search (Ctrl+F1), type "details", choose the matching menu item
  • right-click on the node > Edit > Edit node details in-line.
  • double-click on node details (if details already exist for the node).

2. Dialog editing in a floating editor. The details dialog, a basic text editor, has more robust editing tools (via a menu bar, a toolbar, and hotkeys). Hyperlinks can be created in node details - but only in the node details dialog (Ctrl+H). When done typing, either:

  • click the "OK" button to save the detail and exit the dialog (keyboard hotkey: Alt+O).
  • Or, to cancel, press "Esc" to exit the dialog without saving your work.

To access dialog editing: Select a node then either

  • press Ctrl+F3
  • use the Edit menu > Node properties > Edit node details in dialog
  • use Command search (Ctrl+F1), type "details", choose the matching menu item
  • right-click on the node > Edit > Edit node details in dialog.

Hide node details

Hiding node(s) details folds the detail out of view, leaving only a sliver visible and a small down-pointing arrow (on the bottom left corner of the node core) to mark the presence of node(s) details (known as a toggle). Hovering over such a node with display the details in a tooltip popup. Clicking the toggle displays or hides the details of that node.

Hiding node details is useful to free a bit of map real estate, viewing the details when you need remember its contents. It also can help when presenting your map to others - you can reveal the node details at an appropriate time as you step through your map. Additionally, some node details may contain confidential information you do not want others to see but which you need to have access to.

Hide node details is a toggle, hiding details then showing them.

Note: even when node details are hidden, you can see it by hovering over the node.

To access: Select the node(s) then either

  • press Alt+F2
  • use the View menu > Hide details
  • use Command search (Ctrl+F1), type "details", and choose the matching menu item
  • click the toggle arrow (lower left corner of node core)

Remove node details

Remove node details will delete the node details content from one or more nodes.

To access: Select one or more nodes then either use

  • the Edit menu > Node properties > Remove node details
  • Command search (Ctrl+F1) > type "details" > choose the option matching the menu item

Changing node details appearance (Styles)

The appearance of node details is controlled by the Details style, one of every map's Predefined styles. You can change its appearance in the Style editing dialog:

  • Ctrl+F11
  • Format menu > Manage Styles > Edit styles
  • Command search (Ctrl+F1) > type "edit style" > choose the option matching the menu item

You can make changes by selecting "Details" (under "Default") then make changes using the menu, toolbar, properties panel, and hotkeys.

see Styles

Miscellaneous

The Find-Replace dialog has a sortable column labeled "Details" which lets you see which nodes in the map contain text in its node details.

The Filter toolbar defaults to searching node core, details, and notes. But you can restrict Find's scope by looking only in Details.

A node's children can be converted to attributes. The child(ren) node core(s) contents convert to attribute name(s); node details convert to attribute value(s). (Similarly, attributes can be converted to child nodes.)

Node Notes

Node Attributes

Attributes can be defined for each node. They are displayed in a 2-column table

KeyValue
NameMac
Usernamemacmarrum

The actions related to Attributes can be listed in Help->Command Search (Ctrl+F1) – search for attribute

Once you have at least one attribute, you can right-click on the table to perform actions (New, Delete, Move up, Move down).
Alternatively, you can manage attributes in View->Controls->Tool panel – tab Attributes

Edges

Connectors

Unlike edges, connectors must be added manually. To add a connector between two nodes, select them, right-click for a context menu and choose Connect (Ctrl+L) or use the hot key. Another way is to Ctrl+Shift + drag one node onto another. On some systems it's also possible to right-click + drag one node onto another.

It's possible to add several connectors at one go by selecting more than two nodes. In this case the last selected node is the target.

Connectors' properties can be edited. When you right-click a connector (it's best to select one of the connected nodes first), the Connector dialog appears. Here you can set formatting properties individually or select a Style (or both), set labels' text and remove the connector. See also Connector styles below.

By default, a connector's shape is Curve①. The other options are Line②, Linear path③ and Simulate edge④. The last one does exactly that: simulates an edge between the nodes. Freeplane achieves this by applying the formatting properties of the edge defined for the target node, ignoring the Connector-dialog properties.

The shape of Curve①. Line② and Linear path③ can be changed using curve-shaping of either end – just click on the line near a node (it's best to select the node first). You will see handles appear. By dragging your mouse up to ~50% of the distance between the nodes, the near handle is adjusted. Going beyond ~50% or clicking near the middle adjusts both handles at once. You'll often need to repeat your click-drag-release several times before you get the expected result, i.e. without affecting the far end.

connectors

Hidden connectors

Connector lines can be hidden: Preferences…->Defaults->Connectors->Show connector lines Alternatively, they can be displayed as the lowest level: Preferences…->Defaults->Connectors->Paint connectors behind nodes

Go to a connected node

Like for clones, the right-click node menu item Goto list the other ends of Connectors.

Same-node connectors

Both ends of a connector can be attached to the same node, looping back to itself. To create such a connector, right-click a single node and select Connect (Ctrl+L) or use any of the other methods described above.

When using Line as the type, the connector appears one-ended. Line is often used to draw an arrow going out of a node into empty space (as seen in Freeplane Help->Tutorial).

Connector styles

Connectors use styles. The concept is the same as for nodes (see Styles), i.e. a bundle of connector formatting properties is saved as a connector style. Technically, a connector style is part of a node style. When a node style has a connector defined, like Default has, the style becomes also a connector style.

When a connector is added, a style is applied to it, which determines how the connector looks like. By default, it's the Default style. There's an option to apply a style based on the style defined on the source or the target node. The option can be enabled in Preferences (Ctrl+COMMA) -> Defaults -> Connectors -> Assigns node dependant styles to new connectors. The logic is the following: if the source node has a style applied which has a connector defined, the style is applied to the connector; otherwise, the target node is checked for the same.

The style of a connector can be switched in the Connector dialog. To open it, right-click on a connector. It's best to select a connected node first, to indicate which connector the dialog should open for.

Types of nodes

In addition to standard nodes, there are some special types of nodes:

  1. the root node
  2. free nodes

The root node

Every mind map begins with a central node called the root node. Node levels are defined based on their distance from the root node.

Free nodes

Free nodes are nodes that appear separate from the map hierarchy. They are "free" because they can be freely positioned around the map. They are not automatically positioned like other nodes and they generally do not affect other nodes when they are changed or moved. Any node can be freed by enabling Edit->Free positioned node (set/reset).

A special type of free node is a Floating node. It can be added by Ctrl+double-click on the map background, or by Insert->New node->New floating node. Note: although Floating nodes are positioned independently, technically, they are first-level nodes that are invisibly connected to the root node. You can add children, parents, or siblings to free floating nodes, but you may get unexpected behaviors.

Technically, a Floating node is simply a node with three features:

  • they are given the style Floating node, which connects to other nodes with invisible edges
  • they have the toggle at menu item Edit->Position node independently set to "on"
  • their oval positioning handle is filled and blue rather than unfilled and red

Other nodes can also be given the style Floating node and can be set to be positioned independently: Edit->Free positioned node (set/reset).

Clone nodes

Node groups

Summary nodes

Summary nodes

Summary nodes have brackets that suggest that their content summarizes a group of sibling nodes. Technically, summary nodes are specially marked sibling nodes of the summarized nodes. Summary nodes can include other summary nodes within their brackets, creating the impression of a "reverse" map with branches joining rather than splitting.

Summary node brackets can be customized the usual way, by changing the edge formatting properties: width, line type, color. The only exception is its shape (aka edge style) that isn't customizable.

Node clouds

Node position

Node view options

Hide nodes (per-node setting)

Show hidden nodes

Minimize nodes

Hide node details

Hide/show node attributes

Tool tips

Other resources

New documentation site

You have been redirected to the new Freeplane documentation site.

Download and install the latest Freeplane version from Sourceforge.

Most of the MediaWiki content ended up here, segregated into

The old mediawiki instance can be found at https://www.freeplane.org/oldwiki.