Groovy script : how to read an external map ?

2012-01-31
2012-10-07
  • How do I read the content of an external map in a script ?

    Michel.

     
  • If you are referring to a map whose URL you know then you can check out the
    devtool scripts. They are constructing MapModels from a URL. If you want to
    open the map in Freeplane you could use c.newMap(URL).

    Volker

     
  • Hi Volker,

    what I'd like to do, is read some content of an other map (actually , in the
    same directory as current map).

    For instance I'd like to have in a "reference.mm" map a node called
    "projects", with children being all projects.

    From a map called "todos.mm", I'd like to read the list of projects stored in
    the other map, for assigning each todo the parent project. I would prefer to
    not open the parameters.mm map, just read the file.

    Currently, I have both todos and projects on the same map, but it gets
    cluttered; using a parameters/reference map would allow me to have different
    lists : projects, people, domains of activities, etc.

    I think of something like :

    c.externalMap("path/reference.mm").node.getChildren()
    

    where can I find the devtool scripts ?

     
  • I found the devtool script but couldn't fin anything in the code that might
    help me.

    Then I found this discussion :
    How do I link to a node in another mindmap?

    where you mention creating a script to automate node referencing in another
    map, but the script doesn't exist anymore in the example scripts.

     
  • Hi Michel,

    sorry for not being more explicit. With "devtools scripts" I meant the scripts
    that are part of the Add-on Developer
    Tools
    . In releaseAddOn.groovy you find this code:

    private MapModel createReleaseMap(Proxy.Node node) {
        final ModeController modeController = Controller.getCurrentModeController()
        final MFileManager fileManager = (MFileManager) MFileManager.getController(modeController)
        MapModel releaseMap = new MMapModel()
        if (!fileManager.loadImpl(node.map.file.toURI().toURL(), releaseMap)) {
            LogUtils.warn("can not load " + node.map.file)
            return null
        }
        modeController.getMapController().fireMapCreated(releaseMap)
        return releaseMap
    }
    

    Note that MFileManager.loadImpl() is deprecated since the last preview and you
    should use MapIO in the future:

    MapModel referenceMap = new MMapModel()
    MapIO mapIO = Controller.getCurrentModeController().getExtension(MapIO.class);
    MapModel newMap = mapIO.load(new File('path/reference.mm').toURL(), referenceMap);
    // use the non-proxy map model
    println referenceMap.rootNode.text
    // convert to script objects:
    def root = new NodeProxy(referencesMap.rootNode, null)
    println root.plainText
    

    You may want to check out Freeplane sources for that and you have to be aware
    of the fact that if you use these internal interfaces you might have to adjust
    your code to interface changes more often than with the scripting API.

    By the way: You should use [ with the
    http://groovy.codehaus.org/Eclipse+Plugin for script editing. It will save you
    much time.

    Volker](http://freeplane.sourceforge.net/wiki/index.php/Eclipse)

     
  • thanks for the Eclipse tip.

    This solution is rather annoying as it is less sustainable and cannot be used
    in a public script or addon, I guess ...

    Is there not a way to read a external map node properties via the scripting
    API, or if not directly possible, via
    some scripting to point to the node location ?

    If a dynamic solution is not possible, I can get away with a raw solution : I
    know the URI of the node (from the contextual menu) and would prefer to use it
    to access the node properties.

    targetNode = "file:/C:/Users/Michel/Documents/-%20FREE%20PLANE/devtools.mm#ID_482322757"
    

    I'm trying to use something lilke this :

    def mapFile = node.map.file
    def myMap = c.newMap(mapFile.toURL())
    def temp = myMap.root.text
    

    this works, but I can't replace the "mapFile" address by the known target map
    address (I get an "unknown protocol c" error)

    Thanks in advance,
    Michel.

     
  • This solution is rather annoying as it is less sustainable and cannot be
    used in a public script or addon, I guess ...

    ??? I'm using this API in the Developer Tools add-on as I said. Internal APIs
    aren't subject of daily changes too. If I were you I would use the MapIO code.

    Volker

     
  • Did I misinterpret your remark ?

    you have to be aware of the fact that if you use these internal interfaces
    you might have to adjust your code to interface changes more often than with
    the scripting API.

    Will try the MaIO code anyway.

    Thank you.

     
  • some errors :

    unable to resolve class MapModel
    

    adding these (from releaseAddOn.groovy)

    import java.io.File
    import java.util.zip.ZipEntry
    import java.util.zip.ZipOutputStream
    
    import javax.swing.JOptionPane
    
    import org.freeplane.core.util.LogUtils
    import org.freeplane.features.map.MapModel
    import org.freeplane.features.map.MapWriter.Mode
    import org.freeplane.features.map.mindmapmode.MMapModel
    import org.freeplane.features.mode.Controller
    import org.freeplane.features.mode.ModeController
    import org.freeplane.features.url.mindmapmode.MFileManager
    import org.freeplane.plugin.script.proxy.NodeProxy
    import org.freeplane.plugin.script.proxy.Proxy
    

    solves it, but then I get :

    - unable to resolve class MapModel
    
     
  • oh well ... It can't be expected to work without the last preview, can it ???

    But the download links don't not work right now.
    Will try later.

     
  • with the latest preview, I get exactly the same errors.

     
  • after digging in the code and addon scripts, I got this to work :

    import org.freeplane.features.map.MapWriter.Mode
    import org.freeplane.features.mode.ModeController
    import org.freeplane.plugin.script.proxy.NodeProxy
    import org.freeplane.plugin.script.proxy.Proxy
    
    import org.freeplane.features.map.MapModel;
    import org.freeplane.features.map.NodeModel;
    import org.freeplane.features.map.mindmapmode.MMapModel;
    import org.freeplane.features.mapio.MapIO;
    import org.freeplane.features.mapio.mindmapmode.MMapIO;
    import org.freeplane.features.mode.Controller;
    import org.freeplane.features.mode.mindmapmode.MModeController;
    import org.freeplane.features.text.TextController;
    
    def mapFile = node.map.file
    path = mapFile.parent
    targetMap = path + "\\" + "testExternalMap.mm"
    
    MapModel referenceMap = new MMapModel() 
    MapIO mapIO = Controller.getCurrentModeController().getExtension(MapIO.class);
    MapModel newMap = mapIO.load(new File(targetMap).toURL(), referenceMap);
    
    def root = new NodeProxy(referenceMap.rootNode, null)
    
    def myList = root.getChildren().each{it.text == "Projects List"}
    def projects = myList[0].getChildren().text
    

    where I read a list in an external map.

    I thus can use an external map to hold many different lists / information as
    reference and use (read and update) them at will on a working map, without
    cluttering either maps.

    Uh oh ... promising :-)

    I'm not sure hot to clean the imports properly as I added them (ahem) by trial
    and error, not knowing what should stay or not or for what reason.

    I need to keep the ability to read or write the reference map at will.
    What do you think should be included ?

     
  • Did I misinterpret your remark ?

    Yes and no. The scripting API is more stable as we take special care for it in
    order to not break the scripts that people have written. But the internal APIs
    are also pretty stable and in case of MapIO the most likely change is that the
    scripting API will support it directly...

    In any case add-on developers should take some responsibility for maintaining
    the compatibility of their add-ons over time. Take for example the Firefox
    add-ons that had to be updated for each of the last releases (3, 4, 5, 6, 7,
    ...). If they had not adjusted their add-ons they had not been usable anymore.
    Good news is Freeplane's API don't change as frequent as Firefox releases.

    For the benefit of add-ons developers we should check all add-ons registered
    on the Freeplane wiki for compatibility on new releases and inform the
    developers about the required changes.

    As you have found out the missing import was

    import org.freeplane.features.mapio.MapIO
    

    Unnecessary imports don't hurt but it's a matter of good style to remove them.

    Eclipse has a "Organize imports" function that adds just the required imports
    and removes all others. This is one reason (besides code completion, immediate
    error checking etc.) to use Eclipse. I should document how to set up the
    development environment.

    Volker

     
  • thanks for the insight; I'm busy downloading Eclipse for RCP and RAP
    Developers.

    I was worrying about compatibility; could you have a check and tell me which
    imports I should keep and which I can get rid of ?

    I can find it myself by trial and error but I'm concerned that I might remove
    one that is essential for read / write tasks or for whatever good reason, and
    that I have a hard time finding the missing one further down the road.

    Also, I'm thinking about publishing some add-ons and am not very familiar yet
    with the whole thing; the proposed add-on test failed, but I will try it again
    :-)
    If you care to share your ideas about useful add-ons I could work on, let me
    know.
    I was thinking about converting / combining some of my scripts, but I don't
    have a clear idea of the direction yet.

    Anyways, I appreciate your help as usual.

    Regards,
    Michel.