User:Jiangxin/Patch save extra attributes outof mmfile

From FreeMind
Jump to navigationJump to search

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