Hello everybody,

I have created script for comparing file/folder structure of nodes imported by in-built function File --> Import --> Import folders, for those, who use Freeplane for project managing. Description, issues, limitations and installation is included in comments in the script below.

I have also two questions:

  • Is there some option, how to compare nodes in node hierarchy? If you check attached script, there is issue of node comparation solved by dusty trick ("flatten" original node hierarchy into one-column list). I am unsatisfied, that I dont found any way, how to compare nodes in dependency of their original hierarchy. My point is to create similar node hierarchy of output nodes, as in secondary list, but only with changed nodes. I tried getPathToRoot() with some indexing tricks, also findAll(), but anyone of them didnt provide expected results. I commonly stuck on node indexing (which doesnt respect depth - the X coordinate), or unability to compare two paths to root node. Can somebody target me on some study material on it? Or to Freeplane reference (I already studied this source, but maybe I am blind)?

  • Is in Freeplane some option, how to create "horizontal node structure"? I mean - for example if you import folders hierarchy (the same issue is present also in my Calendar script - see https://sourceforge.net/p/freeplane/discussion/758437/thread/d55a3447/ ), it create vertical list of subnodes. I think, because most of us use some kind of laptops, which has their monitors wider, than their height is, could be "horizontal node structure" much better for general overview of map. On monitor should be able to put much more information (= nodes) ...

And here is the script. Comments and improvements are welcome :)

And my appologise to authors of Freeplane - I have not access to Script Incubator, therefore I posted things here ...

// Changed Files - "Show what is more between two file folder branches"
// ====================================================================
// 
// Shows difference between two nodes, containing the same imported folder structure, but
// in different time. Useful for tracking changes in selected folder, e.g. for those, who
// use Freeplane for project managing.
// 
// If you import folder into selected node by builtin import (File --> Import --> Import
// folders), you will get node structure, which respect subfolders and files structure on
// your disc. This is reference folder structure, later used for tracking changes. You can
// describe file content, tag your files, etc.
// Then, during time, this folder will contain new files, depends on your workflow. You
// can load them into Freeplane in the same way, as reference folder structure, but you
// will get only bigger node structure - and not only changes against previous
// (reference) state. So you maximally can drop one of node structures, or track changes
// manually, what is not very convenient. But this script it changes :)
//
// Usage: Import folder structure by common Freeplane function (File --> Import --> Import
// folders). This will create new node contains nodes similar to folder and files
// structure on disc. This is reference node. Then, when you add new files/folders to
// tracked folder you will need to track changes - what files was added since last import
// of reference folder. So you import the same folder structure by common Freeplane
// function, as it was done for reference node. This will create another node with similar
// folder structure, as at reference node, but containing new nodes for new files. To
// track changes you select both nodes - reference node first!! - and run this script as
// usual. It creates new node with list of files, which are not present in reference node
// structure. Each of node with changes contains link to second (tracked) node structure
// to original file. Then you know, which nodes (files) are new and you can add it
// manually to reference node for further processing (tagging etc.). And so on.
//
// Known issues:
// - New node with tracked changes between reference node and later node to
// comparation doesnt respect folder structure - is just flat list with changes. I wasnt
// able to find more elegant way, how to figure it out.
// - Order of selecting nodes for comparation is mandatory! First selected node should
// ALWAYS be a reference node!
// - Script assumes only ADDING files. That means, script assumes, that secondary selected
// node is always BIGGER than reference node. It doesnt track deleted files! If there was
// some deleted files, it is very probable, that this script will be give strange results
// (because of "algorithm").
// - If script is run from script folder, always raise up a information message "I can
// compare only two nodes!", whenever two nodes are selected, or not.
// - Script assumes similarilly SORTED node structure - but this is not an issue at all,
// because import of folder structure sort included nodes alphabetically in all cases.
// 
// Download this script to separate file, e.g. "ChangedFiles.groovy" (this extension is
// mandatory), copy it to Freeplane program folder to subfolder "scripts" and restart
// Freeplane. Script will be available in menu Tools --> Scripts.
//
// Script was tested on Freeplane 1.6.2 beta.
//
// Created by: (c) Ferdinand Mravenec, 2017
// Version: 170628

// Get selected nodes
def selected_nodes = c.getSelecteds()

// Check for their proper amount (should be 2)
if (selected_nodes.size() != 2){
    ui.informationMessage("I can compare only two nodes!")
    return
}

//Get all child nodes in both branches (expecting lexical order! - should be by default)
//It generates "flat" list of contained nodes. Overtype to list is neccessary (for later inserting)
def fn0 = selected_nodes[0].findAllDepthFirst().toList()
def sn0 = selected_nodes[1].findAllDepthFirst().toList()

// Variable for storage results with reference to original object
def outnodes = [] 

// Main loop
//-1 is in condition because we want not to take as change the theoretically different names
//of selected nodes (which are placed on end of sn0/fn0 lists)
for (i = 0; i < sn0.size() - 1 ; i++){ 
    if (sn0[i].text != fn0[i].text){ //If text on corresponding places doesnt match, its change
        outnodes.add(sn0[i]) //Add reference to output list
        fn0.add(i, null) //Align members of reference node to proper index - thats do the trick
    }
}

// Create output node
def curdat = new Date().format( 'yyyy-MM-dd hh:mm:ss' ) // Create datetime index
def outnode = node.map.root.createChild("New items\n[" + curdat + "]") // Put name together

// Loop for assembly results
for (i = 0; i < outnodes.size(); i++){
    def childnode = outnode.createChild(outnodes[i].text) // Name the node
    childnode.link.node = outnodes[i] // Refer to changed node in compared branch
}

c.select(outnode)
 

Last edit: Ferdinand Mravenec 2017-06-29