User:Jiangxin/Patch save extra attributes outof mmfile: Difference between revisions

From FreeMind
Jump to navigationJump to search
(initial)
 
m (patch for freemind 0.9)
 
Line 5: Line 5:


==Overview==
==Overview==
*Save extra attributes into another file, named *.mmx
This patch is for saving extra node data into .mmx file. Attributes saved in .mmx file will
*defined three attlist.
be loaded when .mm file is open.  
**attributes listed in WhiteAttlist are the only attributes should be saved to files.
**attributes listed in BlackAttlist are the attributes shouldn't be saved to files.
**attributes listed in EmAttlist will be list in a single line. (a kind of EMphasis)


Attributes saved in .mmx file will be loaded when .mm file is open. Please see another patch:
As how to take .mmx file as a reference when loading .mm file, is in another patch:
*[[User:Jiangxin/Patch_load_mm_file_with_mmx_file]]
*[[User:Jiangxin/Patch_load_mm_file_with_mmx_file]]
WhiteAttlist, BlackAttlist, and EmAttlist:
*attributes listed in WhiteAttlist are the only attributes should be saved to files.
*attributes listed in BlackAttlist are the attributes shouldn't be saved to files.
*attributes listed in EmAttlist will be list in a single line. (a kind of EMphasis)


==Patch file==
==Patch file==
<pre><nowiki>Index: freemind/freemind/main/FreeMind.java
this patch is for freemind 0.9
===================================================================
<pre><nowiki>
--- freemind/freemind/main/FreeMind.java (.../tags/RELEASE-0-8-0) (revision 2)
Index: freemind/main/XMLElement.java
+++ freemind/freemind/main/FreeMind.java (.../branches/WHFM-0-8-0) (working copy)
@@ -86,6 +86,7 @@
    private static final String DEFAULT_LANGUAGE = "en";
    private HookFactory nodeHookFactory;
public static final String version = "0.8.0";
+    public static final String DEFAULT_CHARSET = "UTF-8";
    //    public static final String defaultPropsURL = "freemind.properties";
    public URL defaultPropsURL;
    //    public static Properties defaultProps;
Index: freemind/freemind/main/XMLElement.java
===================================================================
===================================================================
--- freemind/freemind/main/XMLElement.java (.../tags/RELEASE-0-8-0) (revision 2)
--- a/freemind/freemind/main/XMLElement.java (修订版 2516)
+++ freemind/freemind/main/XMLElement.java (.../branches/WHFM-0-8-0) (working copy)
+++ b/freemind/freemind/main/XMLElement.java (工作拷贝)
@@ -258,7 +258,58 @@
@@ -291,7 +291,75 @@
       */
       */
     private int parserLineNr;
     private int parserLineNr;
   
   
+    // OSSXP.COM: some attribute saved in .mmx file, instead of the default .mm file.
+    // three attlist. 0: WhiteList, 1: BlackList, 2:EmList
+    private String special_attlist[];
+    private String special_attlist[];
+
+    private void _addtoAttlist(int list, String att)
+    private void _addtoAttlist(int list, String att)
+    {
+    {
Line 56: Line 51:
+    public boolean isInWhiteAttlist(String att)
+    public boolean isInWhiteAttlist(String att)
+    {
+    {
+    if ( this.special_attlist[0].length()==0 ) {
+    // WHITE list is not NULL
+    return true;
+    if ( this.special_attlist[0].length()!=0 ) {
+    return _isInAttlist(0, att);
+    }
+    // BLACK list is not NULL
+    if ( this.special_attlist[1].length()!=0 ) {
+    return ! _isInAttlist(1, att);
+    }
+    }
+    return _isInAttlist(0, att);
+    // Default return true;
+    return true;
+    }
+    }
+
+
+    public boolean isInBlackAttlist(String att)
+    public boolean isInBlackAttlist(String att)
+    {
+    {
+    return _isInAttlist(1, att);
+    // BLACK list is not NULL
+    if ( this.special_attlist[1].length()!=0 ) {
+    return _isInAttlist(1, att);
+    }
+    // WHITE list is not NULL
+    if ( this.special_attlist[0].length()!=0 ) {
+    return ! _isInAttlist(0, att);
+    }
+    // Default return false;
+    return false;
+    }
+    }
+
+
Line 76: Line 86:
+    _addtoAttlist(0, att);
+    _addtoAttlist(0, att);
+    }
+    }
+
+    public void addtoBlackAttlist(String att)
+    public void addtoBlackAttlist(String att)
+    {
+    {
Line 90: Line 100:
       * Creates and initializes a new XML element.
       * Creates and initializes a new XML element.
       * Calling the construction is equivalent to:
       * Calling the construction is equivalent to:
@@ -484,6 +535,10 @@
@@ -506,6 +574,11 @@
         this.children = new Vector();
         this.children = new Vector();
         this.entities = entities;
         this.entities = entities;
         this.lineNr = 0;
         this.lineNr = 0;
+        // OSSXP.COM: save some attributes out of .mm file.
+        this.special_attlist = new String[3];
+        this.special_attlist = new String[3];
+        for (int i = 0; i < 3; i++) {
+        for (int i = 0; i < 3; i++) {
+           special_attlist[i] = "";
+       special_attlist[i] = "";
+        }
+        }
         Enumeration enumerator = this.entities.keys();
         Enumeration enumerator = this.entities.keys();
         while (enumerator.hasMoreElements()) {
         while (enumerator.hasMoreElements()) {
             Object key = enumerator.nextElement();
             Object key = enumerator.nextElement();
@@ -2200,9 +2256,25 @@
@@ -2183,9 +2256,22 @@
         if (! this.attributes.isEmpty()) {
         if (! this.attributes.isEmpty()) {
             Iterator enumerator = this.attributes.keySet().iterator();
             Iterator enumerator = this.attributes.keySet().iterator();
Line 109: Line 120:
                 String value = (String) this.attributes.get(key);
                 String value = (String) this.attributes.get(key);
+
+
+                // OSSXP.COM:
+                if ( this.isInBlackAttlist(key) )
+                if ( this.isInBlackAttlist(key) )
+                {
+                continue;
+                }
+                else if ( ! this.isInWhiteAttlist(key) )
+                {
+                {
+                continue;
+                continue;
Line 128: Line 136:
                 writer.write('='); writer.write('"');
                 writer.write('='); writer.write('"');
                 this.writeEncoded(writer, value);
                 this.writeEncoded(writer, value);
Index: freemind/freemind/modes/mindmapmode/MindMapMapModel.java
Index: freemind/modes/NodeAdapter.java
===================================================================
===================================================================
--- freemind/freemind/modes/mindmapmode/MindMapMapModel.java (.../tags/RELEASE-0-8-0) (revision 2)
--- a/freemind/freemind/modes/NodeAdapter.java (修订版 2510)
+++ freemind/freemind/modes/mindmapmode/MindMapMapModel.java (.../branches/WHFM-0-8-0) (working copy)
+++ b/freemind/freemind/modes/NodeAdapter.java (工作拷贝)
@@ -49,13 +49,18 @@
@@ -924,11 +924,42 @@
import java.util.TimerTask;
    return controller.getNodeID(this);
import java.util.Vector;
}
   
   
+import javax.xml.parsers.DocumentBuilder;
-    public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveInvisible, boolean saveChildren) throws IOException {
+import javax.xml.parsers.DocumentBuilderFactory;
+ /**
  import javax.xml.transform.Result;
+ * @param writer
  import javax.xml.transform.Source;
+ * @param registry
  import javax.xml.transform.Transformer;
+ * @param managed_attr =0|1|2
  import javax.xml.transform.TransformerFactory;
+ *        0 (default): save to .mm  file. (do not save certain attributes, such as node's fold status)
+import javax.xml.transform.dom.DOMSource;
+ *        1          : save to .mmx file. (only save auxiliary attributes, such as node's fold status)
import javax.xml.transform.stream.StreamResult;
+ *        2          : all-in-one .mm file. the default behavior of vanilla freemind.
import javax.xml.transform.stream.StreamSource;
+ * @return
+ */
+ public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveInvisible, boolean saveChildren) throws IOException {
+ return save(writer, registry, saveInvisible, saveChildren, 0);
+ }
+ public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveInvisible, boolean saveChildren, int managed_attr) throws IOException {
    // pre save event to save all contents of the node:
    getModeController().firePreSaveEvent(this);
    XMLElement node = new XMLElement();
   
   
+import org.w3c.dom.Document;
+       // OSSXP.COM: new line before 'TEXT' attribute.
+        node.addtoEmAttlist("TEXT");
+        // OSSXP.COM: according to the managed_attr parameter, save or not save certain keys of this NODE.
+        switch (managed_attr)
+        {
+        case 0:
+        // Save this node to .mm file without certain attributes.
+        node.addtoBlackAttlist("CREATED");
+        node.addtoBlackAttlist("MODIFIED");
+        break;
+        case 1:
+        // Save this node to .mmx file. Only save certain attributes.
+        node.addtoWhiteAttlist("ID");
+        node.addtoWhiteAttlist("FOLDED");
+        node.addtoWhiteAttlist("CREATED");
+        node.addtoWhiteAttlist("MODIFIED");
+        break;
+        }
+
+
  import freemind.controller.MindMapNodesSelection;
  //    if (!isNodeClassToBeSaved()) {
  import freemind.main.FreeMind;
    node.setName(XMLElementAdapter.XML_NODE);
  import freemind.main.FreeMindMain;
//        } else {
@@ -414,9 +419,25 @@
@@ -937,6 +968,9 @@
             return false; }
//        }
         try {          
             //Generating output Stream          
        /** fc, 12.6.2005: XML must not contain any zero characters. */
-            BufferedWriter fileout = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(file) ) );
+    // OSSXP.COM: not save TEXT attributes in .mmx file
+    if( node.isInWhiteAttlist("TEXT"))
+    {
        String text = this.toString().replace('\0', ' ');
        if(!HtmlTools.isHtmlNode(text)) {
            node.setAttribute(XMLElementAdapter.XML_NODE_TEXT,text);
@@ -956,6 +990,7 @@
        node.addChild(htmlElement);
       
        }
+    }
    // save additional info:
    if (getAdditionalInfo() != null) {
            node.setAttribute(XMLElementAdapter.XML_NODE_ENCRYPTED_CONTENT,
@@ -963,15 +998,26 @@
        }
    // ((MindMapEdgeModel)getEdge()).save(doc,node);
+        // OSSXP.COM: not save EDGE in .mmx
+    if( node.isInWhiteAttlist("EDGE"))
+    {
    XMLElement edge = (getEdge()).save();
    if (edge != null) {
                node.addChild(edge); }
+    }
-        if(getCloud() != null) {
+        // OSSXP.COM: not save CLOUD in .mmx
+    if( node.isInWhiteAttlist("CLOUD"))
+    {
+    if(getCloud() != null) {
            XMLElement cloud = (getCloud()).save();
            node.addChild(cloud);
        }
+    }
   
+        // OSSXP.COM: not save ARROWLINK in .mmx
+    if( node.isInWhiteAttlist("ARROWLINK"))
+    {
        Vector linkVector = registry.getAllLinksFromMe(this); /* Puh... */
        for(int i = 0; i < linkVector.size(); ++i) {
            if(linkVector.get(i) instanceof ArrowLinkAdapter) {
@@ -979,10 +1025,27 @@
                node.addChild(arrowLinkElement);
            }
        }
+    }
   
-    if (isFolded()) {
-              node.setAttribute("FOLDED","true"); }
-
+        // OSSXP.COM: set FOLDED status of all nodes in .mm file to "true". Preserve orignal status in .mmx file.
+        switch (managed_attr)
+        {
+        case 0:
+        // Save this node to .mm file without certain attributes.
+        if (!isRoot() && !isLeaf()) {
+        node.setAttribute("FOLDED","true");
+        }
+        break;
+        case 1:
+        case 2:
+        default:
+        if (isFolded()) {
+        node.setAttribute("FOLDED","true");
+        } else {
+        node.setAttribute("FOLDED","false");
+        }
+        }
+       
        // fc, 17.12.2003: Remove the left/right bug.
        //                      VVV  save if and only if parent is root.
    if ((isLeft()!= null) && !(isRoot()) && (getParentNode().isRoot())) {
@@ -1033,6 +1096,9 @@
.getLastModifiedAt()));
}
    //font
+        // OSSXP.COM: not save FONT in .mmx
+    if( node.isInWhiteAttlist("FONT"))
+   {
    if (font!=null) {
        XMLElement fontElement = new XMLElement();
        fontElement.setName("font");
@@ -1048,25 +1114,38 @@
        if (isUnderlined()) {
                    fontElement.setAttribute("UNDERLINE","true"); }
        node.addChild(fontElement); }
+    }
+        // OSSXP.COM: not save ICON in .mmx
+    if( node.isInWhiteAttlist("ICON"))
+    {
        for(int i = 0; i < getIcons().size(); ++i) {
        XMLElement iconElement = new XMLElement();
        iconElement.setName("icon");
            iconElement.setAttribute("BUILTIN", ((MindIcon) getIcons().get(i)).getName());
            node.addChild(iconElement);
        }
+    }
+        // OSSXP.COM: not save HOOK in .mmx
+    if( node.isInWhiteAttlist("HOOK"))
+    {
    for (Iterator i = getActivatedHooks().iterator(); i.hasNext();) {
            XMLElement hookElement = new XMLElement();
            hookElement.setName("hook");
            ((PermanentNodeHook) i.next()).save(hookElement);
            node.addChild(hookElement);
        }
+    }
+        // OSSXP.COM: not save ATTRIBUTE in .mmx
+    if( node.isInWhiteAttlist("ATTRIBUTE"))
+    {
        attributes.save(node);
+    }
        if (saveChildren && childrenUnfolded().hasNext()) {
            node.writeWithoutClosingTag(writer);
             //recursive
-            saveChildren(writer, registry, this, saveInvisible);
+            saveChildren(writer, registry, this, saveInvisible, managed_attr);
            node.writeClosingTag(writer);
        } else {
            node.write(writer);
@@ -1078,13 +1157,17 @@
return map.getModeController();
}
+ // OSSXP.COM: PARAM managed_attr, controls whether or not save certain attrs (such as nodes's folded status) in .mm files.
    private void saveChildren(Writer writer, MindMapLinkRegistry registry, NodeAdapter node, boolean saveHidden) throws IOException {
+    saveChildren(writer, registry, node, saveHidden, 0);
+    }
+    private void saveChildren(Writer writer, MindMapLinkRegistry registry, NodeAdapter node, boolean saveHidden, int managed_attr) throws IOException {
         for (ListIterator e = node.childrenUnfolded(); e.hasNext();) {
            NodeAdapter child = (NodeAdapter) e.next();
            if(saveHidden || child.isVisible())
-                child.save(writer, registry, saveHidden, true);
+                child.save(writer, registry, saveHidden, true, managed_attr);
            else
-                saveChildren(writer, registry, child, saveHidden);
+                saveChildren(writer, registry, child, saveHidden, managed_attr);
        }
    }
Index: freemind/modes/mindmapmode/MindMapMapModel.java
===================================================================
--- a/freemind/freemind/modes/mindmapmode/MindMapMapModel.java (修订版 2516)
+++ b/freemind/freemind/modes/mindmapmode/MindMapMapModel.java (工作拷贝)
@@ -266,7 +266,23 @@
             //Generating output Stream
            // OSSXP.COM: save file using default character set.
            BufferedWriter fileout = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(file), FreeMind.DEFAULT_CHARSET ) );
-            getXml(fileout);
-            getXml(fileout);
+            // TODO user can define his/her own charset.
+            // OSSXP.COM: save tree into .mm file, without some attrs(such as node fold status).
+            BufferedWriter fileout = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(file), FreeMind.DEFAULT_CHARSET ) );
+            getXml(fileout, true, 0);
+            getXml(fileout, 0);
+           
+            // OSSXP.COM: save variable attrs(such as node fold status) into .mmx file...
+            // Save FOLDED attrib into .mmx file...
+            String ext = Tools.getExtension(file.getName());
+            String ext = Tools.getExtension(file.getName());
+            String mmxFileName = "";
+            String mmxFileName = "";
+            if(!ext.equals("mm"))  
+            if(!ext.equals("mm"))  
+            {
+            {
+            mmxFileName = file.getName()+".mmx";
+            mmxFileName = "." + file.getName()+".mmx";
+            }
+            }
+            else  
+            else  
+            {
+            {
+            mmxFileName = Tools.removeExtension(file.getName()) + ".mmx";
+            mmxFileName = "." + Tools.removeExtension(file.getName()) + ".mmx";
+            }
+            }
+            File mmxfile = new File(file.getParent(), mmxFileName);  
+            File mmxfile = new File(file.getParent(), mmxFileName);  
+            BufferedWriter mmxfileout = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(mmxfile), FreeMind.DEFAULT_CHARSET ) );
+            BufferedWriter mmxfileout = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(mmxfile), FreeMind.DEFAULT_CHARSET ) );
+            getXml(mmxfileout, 1);
+            getXml(mmxfileout, true, 1);
+
             if(!isInternal) {
             if(!isInternal) {
                 setFile(file);           
                 setFile(file);
                setSaved(true);
@@ -290,25 +306,44 @@
@@ -440,11 +461,33 @@
     /** writes the content of the map to a writer.
     /** writes the content of the map to a writer.
* @param fileout
  * @throws IOException
  * @throws IOException
+ * @param managed_attr =0|1|2
+ * @param managed_attr =0|1|2
+ *        0 (default): do not check FOLDED attribute(make all nodes folded), saved in .mm file.
+ *        0 (default): save to .mm file. (do not save certain attributes, such as node's fold status)
+ *        1          : only check and save FOLDED attributes in .mmx file.
+ *        1          : save to .mmx file. (only save auxiliary attributes, such as node's fold status)
+ *        2          : save all attributes in one single .mm file.
+ *        2          : all-in-one .mm file. the default behavior of vanilla freemind.
  */
  */
public void getXml(Writer fileout) throws IOException {
- private void getXml(Writer fileout, boolean saveInvisible) throws IOException {
+ getXml(fileout, 0);
+ private void getXml(Writer fileout, boolean saveInvisible, int managed_attr) throws IOException {
+ }
// OSSXP.COM: write xml declare.
+
fileout.write("<?xml version=\"1.0\" encoding=\"" + FreeMind.DEFAULT_CHARSET + "\"?>\n");
+ public void getXml(Writer fileout, int managed_attr) throws IOException {
  fileout.write("<map version=\""+FreeMind.XML_VERSION+"\">\n");
+ // TODO user can define his/her own charset.
// OSSXP.COM: add notice for this hacked version.
+ fileout.write("<?xml version=\"1.0\" encoding=\"" + FreeMind.DEFAULT_CHARSET + "\"?>\n");
fileout.write("<!-- This file is saved using a hacked version of FreeMind. visit: http://www.worldhello.net, http://ossxp.com -->\n");
  fileout.write("<map version=\""+getFrame().getFreemindVersion()+"\">\n");
fileout.write("<!-- Orignal FreeMind, can download from http://freemind.sourceforge.net -->\n");
- fileout.write("<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->\n");
- getRegistry().save(fileout);
- ((MindMapNodeModel)getRoot()).save(fileout, this.getLinkRegistry());
- (getRootNode()).save(fileout, this.getLinkRegistry(), saveInvisible, true);
+ switch (managed_attr)
- fileout.write("</map>\n");
+ {
+ switch (managed_attr)
+ case 0:
+ {
+ fileout.write("<!-- This .mm file is CVS/SVN friendly, also has better Chinese character support. Contribute by http://www.WorldHello.net, orignal FreeMind can be found at http://freemind.sourceforge.net -->\n");
+ case 0:
+ break;
+ fileout.write("<!-- This .mm file is CVS/SVN friendly, some atts are saved in .mmx file.(by Worldhello.net) -->\n");
+ case 1:
+ break;
+ fileout.write("<!-- .mmx files store some extra mm file attributes, which should not check in to CVS/SVN -->\n");
+ case 1:
+ break;
+ fileout.write("<!-- This .mmx files store some extra mm file attributes, which should not check in to CVS/SVN ! -->\n");
+ case 2:
+ break;
+ default:
+ case 2:
+ fileout.write("<!-- To view this file, download free mind mapping software FreeMind from http://freemind.sourceforge.net -->\n");
+ default:
+ break;
+ break;
+ }
+ }
+ ((MindMapNodeModel)getRoot()).save(fileout, this.getLinkRegistry(), managed_attr);
+ if(managed_attr != 1) {
  fileout.write("</map>\n");
+ getRegistry().save(fileout);
+ }
+ // OSSXP.COM: managed_attr control whether or not save nodes' fold status into .mm file.
+ (getRootNode()).save(fileout, this.getLinkRegistry(), saveInvisible, true, managed_attr);
+ fileout.write("</map>\n");
  fileout.close();
  fileout.close();
  }
  }
Index: freemind/freemind/modes/NodeAdapter.java
    public void getXml(Writer fileout) throws IOException{
-        getXml(fileout, true);
+        getXml(fileout, true, 0);
    }
    public void getFilteredXml(Writer fileout) throws IOException{
-        getXml(fileout, false);
+        getXml(fileout, false, 0);
    }
/**
Index: freemind/modes/MindMapNode.java
===================================================================
===================================================================
--- freemind/freemind/modes/NodeAdapter.java (.../tags/RELEASE-0-8-0) (revision 2)
--- a/freemind/freemind/modes/MindMapNode.java (修订版 2510)
+++ freemind/freemind/modes/NodeAdapter.java (.../branches/WHFM-0-8-0) (working copy)
+++ b/freemind/freemind/modes/MindMapNode.java (工作拷贝)
@@ -826,7 +826,20 @@
@@ -248,6 +248,7 @@
    return controller.getNodeID(this);
      * @param saveChildren if true, the save recurses to all of the nodes children.
}
      */
    public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveHidden, boolean saveChildren) throws IOException;
+    public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveHidden, boolean saveChildren, int managed_attr) throws IOException;
   
   
+    /**
     // fc, 10.2.2005:
+    * @param writer
    /** State icons are icons that are not saved. They indicate that
+    * @param registry
 
+    * @param managed_attr =0|1|2
</nowiki></pre>
+    *        0 (default): do not check FOLDED attribute(make all nodes folded), saved in .mm file.
+    *        1          : only check and save FOLDED attributes in .mmx file.
+    *        2          : save all attributes in one single .mm file.
+    * @return
+    */
     public XMLElement save(Writer writer, MindMapLinkRegistry registry) throws IOException {
+    return save(writer, registry, 0);
+    }
+   
+    public XMLElement save(Writer writer, MindMapLinkRegistry registry, int managed_attr) throws IOException {
    XMLElement node = new XMLElement();
   
//   if (!isNodeClassToBeSaved()) {
@@ -863,8 +876,28 @@
            }
        }
           
-    if (isFolded()) {
-              node.setAttribute("FOLDED","true"); }
+    // do not check FOLDED attribute, save all nodes as Folded, except root and leaf.
+        node.addtoEmAttlist("TEXT");
+        switch (managed_attr)
+    {
+        case 0:
+        if (!isRoot() && !isLeaf()) {
+    node.setAttribute("FOLDED","true");
+    }
+          node.addtoBlackAttlist("CREATED");
+          node.addtoBlackAttlist("MODIFIED");
+        break;
+        case 1:
+        node.addtoWhiteAttlist("ID");
+        node.addtoWhiteAttlist("FOLDED");
+          node.addtoWhiteAttlist("CREATED");
+          node.addtoWhiteAttlist("MODIFIED");
+        case 2:
+        default:
+                if (isFolded()) {
+                        node.setAttribute("FOLDED","true");
+                }
+    }
   
        // fc, 17.12.2003: Remove the left/right bug.
        //                      VVV  save if and only if parent is root.
@@ -950,7 +983,7 @@
            //recursive
            for (ListIterator e = childrenUnfolded(); e.hasNext();) {
                NodeAdapter child = (NodeAdapter) e.next();
-                child.save(writer, registry);
+                child.save(writer, registry, managed_attr);
            }
            node.writeClosingTag(writer);
        } else {</nowiki></pre>

Latest revision as of 08:42, 15 March 2007

Why this patch?

All my .mm files are version controled using CVS/SVN. What FreeMind has scratched my personal itch:

  • Some attributes of FreeMind's .mm file are not suitable for version control.
  • e.g., 'FOLDED' attribute saved in .mm file, makes documents changed frequently and unnecessarily.

Overview

This patch is for saving extra node data into .mmx file. Attributes saved in .mmx file will be loaded when .mm file is open.

As how to take .mmx file as a reference when loading .mm file, is in another patch:

WhiteAttlist, BlackAttlist, and EmAttlist:

  • attributes listed in WhiteAttlist are the only attributes should be saved to files.
  • attributes listed in BlackAttlist are the attributes shouldn't be saved to files.
  • attributes listed in EmAttlist will be list in a single line. (a kind of EMphasis)


Patch file

this patch is for freemind 0.9

Index: freemind/main/XMLElement.java
===================================================================
--- a/freemind/freemind/main/XMLElement.java	(修订版 2516)
+++ b/freemind/freemind/main/XMLElement.java	(工作拷贝)
@@ -291,7 +291,75 @@
      */
     private int parserLineNr;
 
+    // OSSXP.COM: some attribute saved in .mmx file, instead of the default .mm file.
+    // three attlist. 0: WhiteList, 1: BlackList, 2:EmList
+    private String special_attlist[];
+
+    private void _addtoAttlist(int list, String att)
+    {
+    	if (list >= special_attlist.length || list <0)
+    		return;
+    	this.special_attlist[list] += att;
+    	this.special_attlist[list] += ":";
+    	return;
+    }
+    
+    private boolean _isInAttlist(int list, String att)
+    {
+    	if ( list >= special_attlist.length || list <0 || special_attlist[list].length()==0 ) {
+    		return false;
+    	}
+    	return this.special_attlist[list].contains(att+':');
+    }
+
+    public boolean isInWhiteAttlist(String att)
+    {
+    	// WHITE list is not NULL
+    	if ( this.special_attlist[0].length()!=0 ) {
+    		return _isInAttlist(0, att);
+    	}
+    	// BLACK list is not NULL
+    	if ( this.special_attlist[1].length()!=0 ) {
+    		return ! _isInAttlist(1, att);
+    	}
+    	// Default return true;
+    	return true;
+    }
+
+    public boolean isInBlackAttlist(String att)
+    {
+    	// BLACK list is not NULL
+    	if ( this.special_attlist[1].length()!=0 ) {
+    		return _isInAttlist(1, att);
+    	}
+    	// WHITE list is not NULL
+    	if ( this.special_attlist[0].length()!=0 ) {
+    		return ! _isInAttlist(0, att);
+    	}
+    	// Default return false;
+    	return false;
+    }
+
+    public boolean isInEmAttlist(String att)
+    {
+    	return _isInAttlist(2, att);
+    }
+
+    public void addtoWhiteAttlist(String att)
+    {
+    	_addtoAttlist(0, att);
+    }
 
+    public void addtoBlackAttlist(String att)
+    {
+    	_addtoAttlist(1, att);
+    }
+
+    public void addtoEmAttlist(String att)
+    {
+    	_addtoAttlist(2, att);
+    }
+    
     /**
      * Creates and initializes a new XML element.
      * Calling the construction is equivalent to:
@@ -506,6 +574,11 @@
         this.children = new Vector();
         this.entities = entities;
         this.lineNr = 0;
+        // OSSXP.COM: save some attributes out of .mm file.
+        this.special_attlist = new String[3];
+        for (int i = 0; i < 3; i++) {
+        	special_attlist[i] = "";
+        }
         Enumeration enumerator = this.entities.keys();
         while (enumerator.hasMoreElements()) {
             Object key = enumerator.nextElement();
@@ -2183,9 +2256,22 @@
         if (! this.attributes.isEmpty()) {
             Iterator enumerator = this.attributes.keySet().iterator();
             while (enumerator.hasNext()) {
-                writer.write(' ');
                 String key = (String) enumerator.next();
                 String value = (String) this.attributes.get(key);
+
+                // OSSXP.COM: 
+                if ( this.isInBlackAttlist(key) )
+                {
+                	continue;
+                }
+
+                writer.write(' ');
+
+                if ( this.isInEmAttlist(key) )
+                {
+                	writer.write("\n\t");
+                }
+
                 writer.write(key);
                 writer.write('='); writer.write('"');
                 this.writeEncoded(writer, value);
Index: freemind/modes/NodeAdapter.java
===================================================================
--- a/freemind/freemind/modes/NodeAdapter.java	(修订版 2510)
+++ b/freemind/freemind/modes/NodeAdapter.java	(工作拷贝)
@@ -924,11 +924,42 @@
 	    return controller.getNodeID(this);
 	}
 
-    public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveInvisible, boolean saveChildren) throws IOException {
+	/**
+	 * @param writer
+	 * @param registry
+	 * @param managed_attr =0|1|2
+	 *         0 (default): save to .mm  file. (do not save certain attributes, such as node's fold status)
+	 *         1          : save to .mmx file. (only save auxiliary attributes, such as node's fold status)
+	 *         2          : all-in-one .mm file. the default behavior of vanilla freemind.
+	 * @return
+	 */
+	public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveInvisible, boolean saveChildren) throws IOException {
+		return save(writer, registry, saveInvisible, saveChildren, 0);
+	}
+	public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveInvisible, boolean saveChildren, int managed_attr) throws IOException {
     	// pre save event to save all contents of the node:
     	getModeController().firePreSaveEvent(this);
     	XMLElement node = new XMLElement();
 
+        // OSSXP.COM: new line before 'TEXT' attribute.
+        node.addtoEmAttlist("TEXT");
+        // OSSXP.COM: according to the managed_attr parameter, save or not save certain keys of this NODE.
+        switch (managed_attr)
+        {
+        case 0:
+        	// Save this node to .mm file without certain attributes.
+        	node.addtoBlackAttlist("CREATED");
+        	node.addtoBlackAttlist("MODIFIED");
+        	break;
+        case 1:
+        	// Save this node to .mmx file. Only save certain attributes.
+        	node.addtoWhiteAttlist("ID");
+        	node.addtoWhiteAttlist("FOLDED");
+        	node.addtoWhiteAttlist("CREATED");
+        	node.addtoWhiteAttlist("MODIFIED");
+        	break;
+        }
+
 //    	if (!isNodeClassToBeSaved()) {
     	node.setName(XMLElementAdapter.XML_NODE);
 //        } else {
@@ -937,6 +968,9 @@
 //        }
 
         /** fc, 12.6.2005: XML must not contain any zero characters. */
+    	// OSSXP.COM: not save TEXT attributes in .mmx file
+    	if( node.isInWhiteAttlist("TEXT"))
+    	{
         String text = this.toString().replace('\0', ' ');
         if(!HtmlTools.isHtmlNode(text)) {
             node.setAttribute(XMLElementAdapter.XML_NODE_TEXT,text);
@@ -956,6 +990,7 @@
 	        	node.addChild(htmlElement);
         	
         }
+    	}
     	// save additional info:
     	if (getAdditionalInfo() != null) {
             node.setAttribute(XMLElementAdapter.XML_NODE_ENCRYPTED_CONTENT,
@@ -963,15 +998,26 @@
         }
     	//	((MindMapEdgeModel)getEdge()).save(doc,node);
 
+        // OSSXP.COM: not save EDGE in .mmx
+    	if( node.isInWhiteAttlist("EDGE"))
+    	{
     	XMLElement edge = (getEdge()).save();
     	if (edge != null) {
                node.addChild(edge); }
+    	}
 
-        if(getCloud() != null) {
+        // OSSXP.COM: not save CLOUD in .mmx
+    	if( node.isInWhiteAttlist("CLOUD"))
+    	{
+    	if(getCloud() != null) {
             XMLElement cloud = (getCloud()).save();
             node.addChild(cloud);
         }
+    	}
 
+        // OSSXP.COM: not save ARROWLINK in .mmx
+    	if( node.isInWhiteAttlist("ARROWLINK"))
+    	{
         Vector linkVector = registry.getAllLinksFromMe(this); /* Puh... */
         for(int i = 0; i < linkVector.size(); ++i) {
             if(linkVector.get(i) instanceof ArrowLinkAdapter) {
@@ -979,10 +1025,27 @@
                 node.addChild(arrowLinkElement);
             }
         }
+    	}
 
-    	if (isFolded()) {
-               node.setAttribute("FOLDED","true"); }
-
+        // OSSXP.COM: set FOLDED status of all nodes in .mm file to "true". Preserve orignal status in .mmx file. 
+        switch (managed_attr)
+        {
+        case 0:
+        	// Save this node to .mm file without certain attributes.
+        	if (!isRoot() && !isLeaf()) {
+        		node.setAttribute("FOLDED","true");
+        	}
+        	break;
+        case 1:
+        case 2:
+        default:
+        	if (isFolded()) {
+        		node.setAttribute("FOLDED","true"); 
+        	} else {
+        		node.setAttribute("FOLDED","false");
+        	}
+        }
+        
         // fc, 17.12.2003: Remove the left/right bug.
         //                       VVV  save if and only if parent is root.
     	if ((isLeft()!= null) && !(isRoot()) && (getParentNode().isRoot())) {
@@ -1033,6 +1096,9 @@
 									.getLastModifiedAt()));
 	}
     	//font
+        // OSSXP.COM: not save FONT in .mmx
+    	if( node.isInWhiteAttlist("FONT"))
+    	{
     	if (font!=null) {
     	    XMLElement fontElement = new XMLElement();
     	    fontElement.setName("font");
@@ -1048,25 +1114,38 @@
     	    if (isUnderlined()) {
                    fontElement.setAttribute("UNDERLINE","true"); }
     	    node.addChild(fontElement); }
+    	}
+        // OSSXP.COM: not save ICON in .mmx
+    	if( node.isInWhiteAttlist("ICON"))
+    	{
         for(int i = 0; i < getIcons().size(); ++i) {
     	    XMLElement iconElement = new XMLElement();
     	    iconElement.setName("icon");
             iconElement.setAttribute("BUILTIN", ((MindIcon) getIcons().get(i)).getName());
             node.addChild(iconElement);
         }
+    	}
 
+        // OSSXP.COM: not save HOOK in .mmx
+    	if( node.isInWhiteAttlist("HOOK"))
+    	{
     	for (Iterator i = getActivatedHooks().iterator(); i.hasNext();) {
             XMLElement hookElement = new XMLElement();
             hookElement.setName("hook");
             ((PermanentNodeHook) i.next()).save(hookElement);
             node.addChild(hookElement);
         }
+    	}
 
+        // OSSXP.COM: not save ATTRIBUTE in .mmx
+    	if( node.isInWhiteAttlist("ATTRIBUTE"))
+    	{
         attributes.save(node);
+    	}
         if (saveChildren && childrenUnfolded().hasNext()) {
             node.writeWithoutClosingTag(writer);
             //recursive
-            saveChildren(writer, registry, this, saveInvisible);
+            saveChildren(writer, registry, this, saveInvisible, managed_attr);
             node.writeClosingTag(writer);
         } else {
             node.write(writer);
@@ -1078,13 +1157,17 @@
 		return map.getModeController();
 	}
 
+	// OSSXP.COM: PARAM managed_attr, controls whether or not save certain attrs (such as nodes's folded status) in .mm files. 
     private void saveChildren(Writer writer, MindMapLinkRegistry registry, NodeAdapter node, boolean saveHidden) throws IOException {
+    	saveChildren(writer, registry, node, saveHidden, 0);
+    }
+    private void saveChildren(Writer writer, MindMapLinkRegistry registry, NodeAdapter node, boolean saveHidden, int managed_attr) throws IOException {
         for (ListIterator e = node.childrenUnfolded(); e.hasNext();) {
             NodeAdapter child = (NodeAdapter) e.next();
             if(saveHidden || child.isVisible())
-                child.save(writer, registry, saveHidden, true);
+                child.save(writer, registry, saveHidden, true, managed_attr);
             else
-                saveChildren(writer, registry, child, saveHidden);
+                saveChildren(writer, registry, child, saveHidden, managed_attr);
         }
     }
 
Index: freemind/modes/mindmapmode/MindMapMapModel.java
===================================================================
--- a/freemind/freemind/modes/mindmapmode/MindMapMapModel.java	(修订版 2516)
+++ b/freemind/freemind/modes/mindmapmode/MindMapMapModel.java	(工作拷贝)
@@ -266,7 +266,23 @@
             //Generating output Stream
             // OSSXP.COM: save file using default character set.
             BufferedWriter fileout = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(file), FreeMind.DEFAULT_CHARSET ) );
-            getXml(fileout);
+            // OSSXP.COM: save tree into .mm file, without some attrs(such as node fold status).
+            getXml(fileout, true, 0);
+            
+            // OSSXP.COM: save variable attrs(such as node fold status) into .mmx file...
+            String ext = Tools.getExtension(file.getName());
+            String mmxFileName = "";
+            if(!ext.equals("mm")) 
+            {
+            	mmxFileName = "." + file.getName()+".mmx";
+            }
+            else 
+            {
+            	mmxFileName = "." + Tools.removeExtension(file.getName()) + ".mmx";
+            }
+            File mmxfile = new File(file.getParent(), mmxFileName); 
+            BufferedWriter mmxfileout = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(mmxfile), FreeMind.DEFAULT_CHARSET ) );
+            getXml(mmxfileout, true, 1);
 
             if(!isInternal) {
                 setFile(file);
@@ -290,25 +306,44 @@
 
     /** writes the content of the map to a writer.
 	 * @throws IOException
+ 	 * @param managed_attr =0|1|2
+ 	 *         0 (default): save to .mm  file. (do not save certain attributes, such as node's fold status)
+ 	 *         1          : save to .mmx file. (only save auxiliary attributes, such as node's fold status)
+ 	 *         2          : all-in-one .mm file. the default behavior of vanilla freemind.
 	 */
-	private void getXml(Writer fileout, boolean saveInvisible) throws IOException {
+ 	private void getXml(Writer fileout, boolean saveInvisible, int managed_attr) throws IOException {
 		// OSSXP.COM: write xml declare.
 		fileout.write("<?xml version=\"1.0\" encoding=\"" + FreeMind.DEFAULT_CHARSET + "\"?>\n");
 		fileout.write("<map version=\""+FreeMind.XML_VERSION+"\">\n");
 		// OSSXP.COM: add notice for this hacked version.
 		fileout.write("<!-- This file is saved using a hacked version of FreeMind. visit: http://www.worldhello.net, http://ossxp.com -->\n");
 		fileout.write("<!-- Orignal FreeMind, can download from http://freemind.sourceforge.net -->\n");
-		getRegistry().save(fileout);
-		(getRootNode()).save(fileout, this.getLinkRegistry(), saveInvisible, true);
-		fileout.write("</map>\n");
+ 		switch (managed_attr)
+ 		{
+ 		case 0:
+ 			fileout.write("<!-- This .mm file is CVS/SVN friendly, some atts are saved in .mmx file.(by Worldhello.net) -->\n");
+ 			break;
+ 		case 1:
+ 			fileout.write("<!-- This .mmx files store some extra mm file attributes, which should not check in to CVS/SVN ! -->\n");
+ 			break;
+ 		case 2:
+ 		default:
+ 			break;
+ 		}
+ 		if(managed_attr != 1) {
+ 			getRegistry().save(fileout);
+ 		}
+ 		// OSSXP.COM: managed_attr control whether or not save nodes' fold status into .mm file.
+ 		(getRootNode()).save(fileout, this.getLinkRegistry(), saveInvisible, true, managed_attr);
+  		fileout.write("</map>\n");
 		fileout.close();
 	}
     public void getXml(Writer fileout) throws IOException{
-        getXml(fileout, true);
+        getXml(fileout, true, 0);
     }
 
     public void getFilteredXml(Writer fileout) throws IOException{
-        getXml(fileout, false);
+        getXml(fileout, false, 0);
     }
 
 	/**
Index: freemind/modes/MindMapNode.java
===================================================================
--- a/freemind/freemind/modes/MindMapNode.java	(修订版 2510)
+++ b/freemind/freemind/modes/MindMapNode.java	(工作拷贝)
@@ -248,6 +248,7 @@
      * @param saveChildren if true, the save recurses to all of the nodes children.
      */
     public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveHidden, boolean saveChildren) throws IOException;
+    public XMLElement save(Writer writer, MindMapLinkRegistry registry, boolean saveHidden, boolean saveChildren, int managed_attr) throws IOException;
 
     // fc, 10.2.2005:
     /** State icons are icons that are not saved. They indicate that