Undoable actions: Difference between revisions

From FreeMind
Jump to navigationJump to search
No edit summary
(+cat)
 
(12 intermediate revisions by 9 users not shown)
Line 1: Line 1:
== Background ==
As an example, we look at the implementation of the NodeColorAction that changes the color of a node.
We assume, that you want to make an action belonging to the mindmap mode undoable.


== Summary ==
* The mode controller is responsible for your action.
* You make your action serializable via XML.
* You divide your action into separate "do"- and an "undo"-(xml-)actions.
* Each XML action is executed by "freemind.modes.mindmapmode.actions.xml.ActionFactory.executeAction".
* To every XML action a (dynamically added) handler belongs that takes a XmlAction argument and does something useful with it.


[http://www.action-meds.com cheap butalbital]
[http://www.5stardrugs.com buy tramadol]
[http://www.24-7pills.net tramadol online]
[http://www.american-meds.net butalbital discount]
[http://www.amazing-pills.com butalbital cheap]
buy tramadol online. online tramadol from our pharmacy, taking tramadol buy information tramadol, side effects tramadol, purchase tramadol online. cod online tramadol, tramadol india, cheap tramadol online, tramadol online, pharmacy online store
tramadol 50 mg. low price tramadol, tramadol pain treatment - tramadol hcl 50? - 120 tramadol. tramadol sales, buying cod tramado l, tramadol for humans, cheap tramadol online, overdose tramadol. order tramadol pictured tramadol pill tramadol seizure. cod tramadol cod, tramadol pdr, order pharmacy tramadol. buy prescription tramadol drug tramadol - tramadol side.
is tramadol a, order tramadol online, tramadol hcl, tramadol drug test .tramadol uses order tramadol overnight paypal tramadol
tramadol com tramadol tablets tramadol no perscription remove tramadol.
[http://20six.co.uk/cheaptramadol cheap tramadol]
[http://20six.co.uk/ordertramadol order tramadol]
[http://20six.co.uk/onlinetramadol1 online tramadol]
[http://20six.co.uk/tramadolonline tramadol online]
[http://20six.co.uk/tramadoldiscount tramadol discount]
[http://20six.co.uk/purchasetramadol purchase tramadol]
[http://20six.co.uk/ordersoma order soma]
[http://20six.co.uk/onlinesoma1 online soma]
[http://20six.co.uk/online-viagra online viagea]
[http://20six.co.uk/orderviagra order viagra]
[http://20six.co.uk/cheapviagraonline cheap viagra online]
[http://20six.co.uk/purchaseviagra purchase viagra]
[http://20six.co.uk/cheap-ultram cheap ultram]


[http://spaces.msn.com/cheap-tramadol/ cheap tramadol]
== Step 1: The ModeController implements the low level action ==
[http://spaces.msn.com/buy-viagra/ buy viagra]
The interface MindMapActions describes all actions that can be performed on a mindmap in mindmap mode.
We find the method
<pre>public void setNodeColor(MindMapNode node, Color color);</pre>


SEO: UndoneHeaven
The implementation in MindMapController is as follows:
<pre>
    public void setNodeColor(MindMapNode node, Color color) {
        nodeColor.setNodeColor(node, color);
    }
</pre>


[http://www.replicahours.com rolex replica]
It is delegated to a separate class that handles all necessary actions (strongly recommended).
[http://www.replicahours.com/index.php?cPath=51_25 fake rolex daydate]
[http://www.replicahours.com/index.php?cPath=29 replica swiss]
[http://www.google.com/search?sourceid=navclient&gfns=1&ie=UTF-8&q=replicahours replicahours]
buy replica cheap best price rolex discounf fake. watches fake watch online store using paypal fedex rolex replicahours. order rolex replica now. cheap wholesale fake rolex online free shipping. 80% discount rolex replica and replicas watches. woman how to adjust a chronometer watch authorized rolex dealer, rolex watches rolex dial rolex oyster perpetual date reloj panerai replica en usa rolex watches serial numbers rolex woman daytona daytona watch replica panerai watch rolex 50th anniversary rolex daytona paul newman replica rolex buy rolex watches. ladies rolex yachtmaster white dial faux. rolex daytona manual cellini rolex for sale pictures of rolex oyster perpetual datejust rolex rolex gmt-master ii buying rolex on line fake rolex daytona gold on silver how to tell fake tag rolex oyster perpetual new tell. Replica rolex? Swiss made replica rolex watch! Cost does fake much rolex rolex presidential rolex. Rolex dials rolex sea dweller. Rolex  tudor fake rolex turkey datejust oyster perpetual rolex man rolex submariner cosmograph daytona oyster professional rolex? Datejust rolex rolex replica rolex fake rolexes for sale. Rolex submariner for sale, rolex yachtmaster! Explorer ii rolex preowned rolex watch? Cheap rolex watch, rolex daytona 116520 forum rolex. 18k gold replica ex part rolex daytona review rolex submariner 50 anniversary rolex cellini replica rolex watch fake rolex omega?


[http://www.customsoftwarenow.com custom software development]
'''The only way to perform the action for an external programmer must be the method described in the interface.''' The method must carry out all redisplay of the map.
Software Development, custom software development, offshore  software development, outsourcing software development


[http://www.thepublish.com press release]
== Step 2: The XML-Serialization ==
press release, articles, business directory, ezines, classifieds, job search,business free  b2b search advertising aerospace defense agriculture airlines automotive chemicals computers electronics semiconductors energy utilities
The undo mechanism is realized via xml serialization: you specify what data you need to perform and to undo your action. The data consists of strings. As an example: you describe the node, the action is applied to, via its identifier.
The serialization is declarated in the file <pre>freemind_actions.xsd</pre>.
There we find:
<pre>
<!-- Sets the color of the nodes Action -->
<xs:element name="node_color_format_action">
  <xs:complexType>
<xs:complexContent>
<xs:extension base="format_node_action">
      <xs:attribute name="color" use="optional" type="xs:string"/>
</xs:extension>
</xs:complexContent>
  </xs:complexType>
</xs:element>
</pre>
The "format_node_action" extends "node_action" which is the following:
<pre>
<!-- Node actions. These actions involve exactly one node.-->
  <xs:complexType name="node_action">
<xs:complexContent>
<xs:extension base="xml_action">
      <xs:attribute name="node" use="required" type="xs:string"/>
</xs:extension>
</xs:complexContent>
  </xs:complexType>
</pre>
Here, we see the string attribute "node" (the id).
node_color_format_action contained the color attribute (a string, too).


[http://www.ez-agents.com wholesale atv]
== Step 3: Don't forget to add your xml type to the compound type==
Often forgotten: at the top of the schema there you'll find the compound type declared. It is requested that your type occures there as a list of actions are tied together in a single xml via
<pre>
<!-- Compound action.  -->
<xs:element name="compound_action">
  <xs:complexType>
<xs:complexContent>
<xs:extension base="xml_action">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="compound_action"/>
...
<xs:element ref="node_color_format_action"/>
...
</xs:choice>
</xs:extension>
</xs:complexContent>
  </xs:complexType>
</xs:element>
</pre>
 
== Step 4: Look at the xml serialization interface ==
Run "ant dist", refresh, close your eclipse project and reopen it. Then open the type "NodeColorFormatActionType" and you get:
<pre>
public interface NodeColorFormatActionType
    extends freemind.controller.actions.generated.instance.FormatNodeAction
{
 
 
    /**
    *
    * @return possible object is
    * {@link java.lang.String}
    */
    java.lang.String getColor();
 
    /**
    *
    * @param value allowed object is
    * {@link java.lang.String}
    */
    void setColor(java.lang.String value);
 
}
</pre>
 
== Step 5: Instrument the action ==
The class that realizes the action (it is often derived from the "AbstractAction" class of swing) must implement "ActorXml" to serve as an actor in the undo game. This means that during the xml deserialization a XML element that is found can be linked to a Java class. In this game, no undo is present anymore.
 
ActorXml is:
<pre>
public interface ActorXml {
 
 
public void act(XmlAction action);
/**
* @return
*/
Class getDoActionClass();
 
}
</pre>
 
"getDoActionClass" must return the Java class that belongs to the xml action we specified in step 2. We say
<pre>
    public Class getDoActionClass() {
        return NodeColorFormatAction.class;
    }
</pre>
 
And the "act" method should do the work:
<pre>
    public void act(XmlAction action) {
if (action instanceof NodeColorFormatAction) {
NodeColorFormatAction nodeColorAction = (NodeColorFormatAction) action;
Color color = Tools.xmlToColor(nodeColorAction.getColor());
MindMapNode node = controller.getNodeFromID(nodeColorAction.getNode());
Color oldColor = node.getColor() ;
if (!Tools.safeEquals(color, oldColor)) {
                node.setColor(color); // null
                controller.nodeChanged(node);
            }
}
  }
</pre>
You can see, that it basically decodes the XML information and performs the action, but only if necessary.
 
== Step 6: Add your XML action handler dynamically==
Often forgotten:
During construction of your action, add
<pre>
        controller.getActionFactory().registerActor(this, getDoActionClass());
</pre>
Thus, the action factory knows, that it call you to perform the work belonging to the "node_color_format_action" xml code.
 
== Step 7: Create do and undo actions ==
We write a helper method that fills the xml action with reasonable values:
<pre>
    public NodeColorFormatAction createNodeColorFormatAction(MindMapNode node, Color color) throws JAXBException {
NodeColorFormatAction nodeAction = controller.getActionXmlFactory().createNodeColorFormatAction();
nodeAction.setNode(node.getObjectId(controller));
    nodeAction.setColor(Tools.colorToXml(color));
return nodeAction;
    }
</pre>
 
And we implement the main method:
<pre>
    public void setNodeColor(MindMapNode node, Color color) {
try {
NodeColorFormatAction doAction = createNodeColorFormatAction(node, color);
NodeColorFormatAction undoAction = createNodeColorFormatAction(node, node.getColor());
controller.getActionFactory().startTransaction(this.getClass().getName());
controller.getActionFactory().executeAction(new ActionPair(doAction, undoAction));
controller.getActionFactory().endTransaction(this.getClass().getName());
} catch (JAXBException e) {
e.printStackTrace();
}
    }
</pre>
 
The procedure is always the same:
* Collect the do action (what should be done?)
* Collect the undo action (what should be done to undo the stuff?). Often, this is an action of a different type (think of adding something: to undo, you have to remove it...)
* Execute the do action in a transaction (this is not used so far but will be in the future).
 
== Grouping several actions together ==
If you need to carry out several actions in one step, you can use the CompoundAction we've already seen in Step 3. The reason to do this can be that you want to carry out different types of XmlActions or that an action consists of more than one step.
 
As an example, we look at the removal of all icons of the selected nodes. To undo this action, you have to add several icons to several different nodes. We take a look at the code:
 
<pre>
    public ActionPair apply(MapAdapter model, MindMapNode selected) throws JAXBException {
        CompoundAction undoAction = modeController.getActionXmlFactory().createCompoundAction();
        for (Iterator i = selected.getIcons().iterator(); i.hasNext();) {
            MindIcon icon = (MindIcon) i.next();
            undoAction.getCompoundActionOrSelectNodeActionOrCutNodeAction().add(addIconAction.createAddIconAction(selected, icon));
        }
        return new ActionPair(createRemoveAllIconsXmlAction(selected), undoAction);
    }
</pre>
 
The strange getter "getCompoundActionOrSelectNodeActionOrCutNodeAction()" is something generated by JaxB. Correction: as of version 0.9.0, we are using JibX instead. The strange getter has another name with this (free!) library.
 
[[Category:Development]]

Latest revision as of 19:21, 24 September 2009

Background

As an example, we look at the implementation of the NodeColorAction that changes the color of a node. We assume, that you want to make an action belonging to the mindmap mode undoable.

Summary

  • The mode controller is responsible for your action.
  • You make your action serializable via XML.
  • You divide your action into separate "do"- and an "undo"-(xml-)actions.
  • Each XML action is executed by "freemind.modes.mindmapmode.actions.xml.ActionFactory.executeAction".
  • To every XML action a (dynamically added) handler belongs that takes a XmlAction argument and does something useful with it.


Step 1: The ModeController implements the low level action

The interface MindMapActions describes all actions that can be performed on a mindmap in mindmap mode. We find the method

public void setNodeColor(MindMapNode node, Color color);

The implementation in MindMapController is as follows:

    public void setNodeColor(MindMapNode node, Color color) {
        nodeColor.setNodeColor(node, color);
    }

It is delegated to a separate class that handles all necessary actions (strongly recommended).

The only way to perform the action for an external programmer must be the method described in the interface. The method must carry out all redisplay of the map.

Step 2: The XML-Serialization

The undo mechanism is realized via xml serialization: you specify what data you need to perform and to undo your action. The data consists of strings. As an example: you describe the node, the action is applied to, via its identifier.

The serialization is declarated in the file

freemind_actions.xsd

.

There we find:

	<!-- Sets the color of the nodes Action -->
	<xs:element name="node_color_format_action">
	  <xs:complexType>
		<xs:complexContent>
			<xs:extension base="format_node_action">
		      <xs:attribute name="color" use="optional" type="xs:string"/>
			</xs:extension>
		</xs:complexContent>
	  </xs:complexType>
	</xs:element>

The "format_node_action" extends "node_action" which is the following:

	<!-- Node actions. These actions involve exactly one node.-->
	  <xs:complexType name="node_action">
		<xs:complexContent>
			<xs:extension base="xml_action">
		      <xs:attribute name="node" use="required" type="xs:string"/>
			</xs:extension>
		</xs:complexContent>
	  </xs:complexType>

Here, we see the string attribute "node" (the id). node_color_format_action contained the color attribute (a string, too).

Step 3: Don't forget to add your xml type to the compound type

Often forgotten: at the top of the schema there you'll find the compound type declared. It is requested that your type occures there as a list of actions are tied together in a single xml via

	<!-- Compound action.  -->
	<xs:element name="compound_action">
	  <xs:complexType>
		<xs:complexContent>
			<xs:extension base="xml_action">
				<xs:choice minOccurs="0" maxOccurs="unbounded">
					<xs:element ref="compound_action"/>
...
					<xs:element ref="node_color_format_action"/>
...
				</xs:choice>
			</xs:extension>
		</xs:complexContent>
	  </xs:complexType>
	</xs:element>

Step 4: Look at the xml serialization interface

Run "ant dist", refresh, close your eclipse project and reopen it. Then open the type "NodeColorFormatActionType" and you get:

public interface NodeColorFormatActionType
    extends freemind.controller.actions.generated.instance.FormatNodeAction
{


    /**
     * 
     * @return possible object is
     * {@link java.lang.String}
     */
    java.lang.String getColor();

    /**
     * 
     * @param value allowed object is
     * {@link java.lang.String}
     */
    void setColor(java.lang.String value);

}

Step 5: Instrument the action

The class that realizes the action (it is often derived from the "AbstractAction" class of swing) must implement "ActorXml" to serve as an actor in the undo game. This means that during the xml deserialization a XML element that is found can be linked to a Java class. In this game, no undo is present anymore.

ActorXml is:

public interface ActorXml {


	public void act(XmlAction action); 
		
	/**
	 * @return
	 */
	Class getDoActionClass();

}

"getDoActionClass" must return the Java class that belongs to the xml action we specified in step 2. We say

    public Class getDoActionClass() {
        return NodeColorFormatAction.class;
    }

And the "act" method should do the work:

    public void act(XmlAction action) {
		if (action instanceof NodeColorFormatAction) {
			NodeColorFormatAction nodeColorAction = (NodeColorFormatAction) action;
			Color color = Tools.xmlToColor(nodeColorAction.getColor());
			MindMapNode node = controller.getNodeFromID(nodeColorAction.getNode());
			Color oldColor = node.getColor() ;
			if (!Tools.safeEquals(color, oldColor)) {
                		node.setColor(color); // null
                		controller.nodeChanged(node);
            		}
		}
   }

You can see, that it basically decodes the XML information and performs the action, but only if necessary.

Step 6: Add your XML action handler dynamically

Often forgotten: During construction of your action, add

        controller.getActionFactory().registerActor(this, getDoActionClass());

Thus, the action factory knows, that it call you to perform the work belonging to the "node_color_format_action" xml code.

Step 7: Create do and undo actions

We write a helper method that fills the xml action with reasonable values:

    public NodeColorFormatAction createNodeColorFormatAction(MindMapNode node, Color color) throws JAXBException {
		NodeColorFormatAction nodeAction = controller.getActionXmlFactory().createNodeColorFormatAction();
		nodeAction.setNode(node.getObjectId(controller));
	    	nodeAction.setColor(Tools.colorToXml(color));
		return nodeAction;
    }

And we implement the main method:

    public void setNodeColor(MindMapNode node, Color color) {
		try {
			NodeColorFormatAction doAction = createNodeColorFormatAction(node, color);
			NodeColorFormatAction undoAction = createNodeColorFormatAction(node, node.getColor());
			controller.getActionFactory().startTransaction(this.getClass().getName());
			controller.getActionFactory().executeAction(new ActionPair(doAction, undoAction));
			controller.getActionFactory().endTransaction(this.getClass().getName());
		} catch (JAXBException e) {
			e.printStackTrace();
		}
    }

The procedure is always the same:

  • Collect the do action (what should be done?)
  • Collect the undo action (what should be done to undo the stuff?). Often, this is an action of a different type (think of adding something: to undo, you have to remove it...)
  • Execute the do action in a transaction (this is not used so far but will be in the future).

Grouping several actions together

If you need to carry out several actions in one step, you can use the CompoundAction we've already seen in Step 3. The reason to do this can be that you want to carry out different types of XmlActions or that an action consists of more than one step.

As an example, we look at the removal of all icons of the selected nodes. To undo this action, you have to add several icons to several different nodes. We take a look at the code:

    public ActionPair apply(MapAdapter model, MindMapNode selected) throws JAXBException {
        CompoundAction undoAction = modeController.getActionXmlFactory().createCompoundAction();
        for (Iterator i = selected.getIcons().iterator(); i.hasNext();) {
            MindIcon icon = (MindIcon) i.next();
            undoAction.getCompoundActionOrSelectNodeActionOrCutNodeAction().add(addIconAction.createAddIconAction(selected, icon));
        }
        return new ActionPair(createRemoveAllIconsXmlAction(selected), undoAction);
    }

The strange getter "getCompoundActionOrSelectNodeActionOrCutNodeAction()" is something generated by JaxB. Correction: as of version 0.9.0, we are using JibX instead. The strange getter has another name with this (free!) library.