Sunday, September 21, 2014

FreeMind XML Parse Exception When Opening an Old Map

I think this bug has been fixed in a more recent version of FreeMind, but you may go through this with version 1.0.1 for Linux, possibly for Windows also:

1.  Try to open a map


2.  Get this error


This is clearly a bug, and I haven't seen it with newer versions of FreeMind on Windows.  A workaround is to fix the first line of the .mm file in question:

<map version="0.9.0">
<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
<node CREATED="1386726098959" ID="ID_368233367" MODIFIED="1386726102812" TEXT="git">


To resolve the issue, replace "0.9.0" with "1.0.1" using a text editor, save the file, and you should be able to open the file again.

If you want to update a large number of maps try the following (Linux command line):

sed -i -e 's/0\.9\.0/1.0.1/' *.mm

The above command will look for "0.9.0" and replace it with "1.0.1" in all files named *.mm, and the -i option means it will update the file in place.

(You can also use sed under Windows, see the unixutils package at Sourceforge)

Sunday, September 7, 2014

[Linux, Mint, Ubuntu] Update FreeMind the Lazy Way...

The latest version of FreeMind in the Ubuntu repositories as of this writing is 0.9, which is quite old.  But, there is an easy way to get the latest version, use a 3rd party repo.

See here:  http://www.ubuntuupdates.org/ppa/getdeb_apps?dist=trusty
wget -q -O - http://archive.getdeb.net/getdeb-archive.key | sudo apt-key add -
sudo sh -c 'echo "deb http://archive.getdeb.net/ubuntu trusty-getdeb apps" >> /etc/apt/sources.list.d/getdeb.list'

After this, do:

sudo apt-get update

and finally:

wskellenger@marquette ~ $ sudo apt-get install freemind
Reading package lists... Done
Building dependency tree       
Reading state information... Done
Suggested packages:
  freemind-plugins-help freemind-plugins-svg freemind-plugins-script
  freemind-plugins-map freemind-browser
Recommended packages:
  freemind-doc
The following packages will be upgraded:
  freemind
1 upgraded, 0 newly installed, 0 to remove and 27 not upgraded.
Need to get 20.1 MB of archives.
After this operation, 18.3 MB of additional disk space will be used.
Get:1 http://archive.getdeb.net/ubuntu/ trusty-getdeb/apps freemind all 1.0.1-1~getdeb1 [20.1 MB]
Fetched 20.1 MB in 15s (1,319 kB/s)            

[Linux] Create a Mind Map (Freemind) from a Directory Structure

I wanted to have a mindmap of the Cyanogenmod source tree.  It is a huge bunch of folders and I just want a nice way to have an overview of the file structure and make notes.

FreeMind, the open source mind mapping tool, has a native utility to import a directory structure, but I found that the resulting mind map was on the heavyweight side.  In fact, using FreeMind 0.9, the native import tool never completed the import -- after 30 minutes or so I had to kill the application.

So I just want to create a FreeMind file that has the directory entries as text nodes, and that's it.  How about using the awesome "tree" command line tool in Linux?

Here is what the output looks like from my /usr/share folder (note I'm using the -d option to show only directories):

wskellenger@marquette /usr/share $ tree -d
.
├── aclocal
├── acpi-support
├── adduser
├── alsa
│   ├── alsa.conf.d
│   ├── cards
│   │   └── SI7018
│   ├── init
│   ├── pcm
│   ├── speaker-test
│   └── ucm
│       ├── apq8064-tabla-snd-card
│       ├── DAISY-I2S
│       ├── Manta-I2S
│       ├── Manta-SPDIF
│       ├── PandaBoard
│       ├── PandaBoardES
│       ├── SDP4430
│       ├── tegraalc5632
│       ├── tegra-rt5640
│       └── Tuna
├── alsa-base
...snip...

Now if you take a look at the options for tree, there already is an option to output XML!  Try "tree --help" at the commandline, and you'll see something like this:

  ------- Graphics options ------
  -i            Don't print indentation lines.
  -A            Print ANSI lines graphic indentation lines.
  -S            Print with ASCII graphics indentation lines.
  -n            Turn colorization off always (-C overrides).
  -C            Turn colorization on always.
  ------- XML/HTML options -------
  -X            Prints out an XML representation of the tree.
  -H baseHREF   Prints out HTML format with baseHREF as top directory.
  -T string     Replace the default HTML title and H1 header with string.
  --nolinks     Turn off hyperlinks in HTML output.
  ---- Miscellaneous options ----
  --version     Print version and exit.
  --help        Print usage and this help message and exit.

So, awesome, shall we see what this option does?

wskellenger@marquette ~/cm11 $ tree -d -X | more
<?xml version="1.0" encoding="UTF-8"?>
<tree>
  <directory name=".">
    <directory name="abi">
      <directory name="cpp">
        <directory name="include">
        </directory>
        <directory name="src">
        </directory>
      </directory>
    </directory>
    <directory name="android">
    </directory>
    <directory name="art">
      <directory name="build">
      </directory>
      <directory name="compiler">
        <directory name="dex">
          <directory name="portable">
          </directory>
          <directory name="quick">
            <directory name="arm">
            </directory>
            <directory name="mips">
            </directory>
            <directory name="x86">
            </directory>
          </directory>
        </directory>
        <directory name="driver">
        </directory>
        <directory name="jni">
          <directory name="portable">
...snip...

And here is what a FreeMind file looks like:

<map version="0.9.0">
<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->
<node CREATED="1410111246409" ID="ID_718284210" MODIFIED="1410122249321" TEXT="Android build env">
<node CREATED="1410122250455" HGAP="11" ID="ID_1487627158" MODIFIED="1410122267863" POSITION="right" TEXT="cm11" VSHIFT="-41">
<node CREATED="1410111257071" ID="ID_181927416" MODIFIED="1410111257071" TEXT="abi"/>
<node CREATED="1410111257072" ID="ID_1980677560" MODIFIED="1410111257072" TEXT="android"/>
<node CREATED="1410111257072" ID="ID_584603213" MODIFIED="1410111257072" TEXT="art"/>
<node CREATED="1410111257073" ID="ID_821356947" MODIFIED="1410111257073" TEXT="bionic"/>
<node CREATED="1410111257073" ID="ID_1847225096" MODIFIED="1410111257073" TEXT="bootable"/>
<node CREATED="1410111257074" ID="ID_777789702" MODIFIED="1410111257074" TEXT="build"/>
<node CREATED="1410111257074" ID="ID_1798981557" MODIFIED="1410111257074" TEXT="cts"/>
<node CREATED="1410111257075" ID="ID_1299267080" MODIFIED="1410111257075" TEXT="dalvik"/>
<node CREATED="1410111257076" ID="ID_283530905" MODIFIED="1410111257076" TEXT="developers"/>
<node CREATED="1410111257077" ID="ID_1162422382" MODIFIED="1410111257077" TEXT="development"/>
<node CREATED="1410111257078" ID="ID_772625792" MODIFIED="1410111257078" TEXT="device">
<node CREATED="1410122307224" FOLDED="true" ID="ID_981437287" MODIFIED="1410122649648" TEXT="common">
<node CREATED="1410122647210" ID="ID_1480883631" MODIFIED="1410122647823" TEXT="gps"/>
</node>
...snip...

To dump the output of "tree" we just do a simple redirect of the output:

wskellenger@marquette ~/cm11 $ tree -d -X > out.xml

Now we just need to make some simple substitutions in the "out.xml" file from "tree" to make it compatible with FreeMind.  This is really simple with Vim.

It looks like we need to do the following:

  1. Rename the "directory" elements to "node".
  2. Add the "CREATED" attribute with today's date.
  3. Add the "ID" attribute (this appears to hold a random number).
  4. Add the "MODIFIED" attribute, which also contains a date.
  5. Rename the "name" attribute to "TEXT"
  6. Get rid of the <?xml> element at the top.
  7. Replace the <tree> tag with <map version="0.9.0"> (use version="1.0.1" for the newer version of FreeMind).
  8. Replace </tree> at the bottom of the file with </map>
  9. Bonus hint: If you have a huge directory structure, like the Cyanogenmod file tree, you might want to add another attribute, FOLDED="true" to each "node" element.

This is really a search/replace problem.  If you don't know regular expressions, you should learn them, because this problem becomes pretty easy, except for the random number part, but even that can be solved with Vim.

So generally we will do some searching and replacing with Vim:

:%s/<directory/<node/gc
:%s/directory>/node>/gc
:%s/name=/TEXT=/gc
:%! perl -pne '$random=int(rand 100000000); s/<node/<node CREATED="1410111247071" ID="ID_$random" MODIFIED="1410111247072" /gc'
:%s/ID=/FOLDED="true" ID=/gc

I manually removed the <tree> tags and added the <map> tags.  I also manually removed the <?xml> tag at the top.  

The tricky part is in yellow: generating the random numbers.  I found the solution for that at StackOverflow.  In that line, we basically callupon perl to generate a random integer, and stuff it into a variable "$random".  After that, perl creates a vim-like search/replace string, searching for <node and updating it as shown.  Vim executes this for each and every line and performs the search/replace.  Slick.

After this, save the file and open it with FreeMind.

WARNING:  FreeMind 0.9.0 is really terrible about handling large maps.  With a huge directory tree (like what is in Cyanogenmod), you may open a few nodes and have it crash on you.  FreePlane seems to behave better with large maps.  Here is the result opened in FreePlane:


WARNING2: After you save the file in FreePlane, you probably won't be able to open it in FreeMind.  So save it as a new filename.

UPDATE: FreeMind 1.0.1 is much better at handling large maps.