Index: /trunk/src/org/expeditee/actions/Actions.java
===================================================================
--- /trunk/src/org/expeditee/actions/Actions.java	(revision 375)
+++ /trunk/src/org/expeditee/actions/Actions.java	(revision 376)
@@ -721,7 +721,8 @@
 		int ind = 0;
 
-		// if the first class in the list is a frame or item, it is the source
-		// or launcher
-		// length must be at least one if we are still running
+		/*
+		 * if the first class in the list is a frame or item, it is the source
+		 * or launcher length must be at least one if we are still running
+		 */
 		if (paramTypes[ind] == Frame.class) {
 			objects[ind] = source;
@@ -886,6 +887,8 @@
 			return PerformAction(current, launcher, command);
 		} catch (RuntimeException e) {
+			e.printStackTrace();
 			MessageBay.errorMessage("Action failed: " + e.getMessage());
 		} catch (Exception e) {
+			e.printStackTrace();
 			MessageBay.errorMessage("Action failed: "
 					+ e.getClass().getSimpleName());
Index: /trunk/src/org/expeditee/actions/GreenstoneActions.java
===================================================================
--- /trunk/src/org/expeditee/actions/GreenstoneActions.java	(revision 376)
+++ /trunk/src/org/expeditee/actions/GreenstoneActions.java	(revision 376)
@@ -0,0 +1,121 @@
+package org.expeditee.actions;
+
+import java.awt.Color;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.expeditee.agents.SearchGreenstone;
+import org.expeditee.greenstone.ResultDocument;
+import org.expeditee.gui.AttributeValuePair;
+import org.expeditee.gui.MessageBay;
+
+public class GreenstoneActions {
+	public static void givePositiveFeedback(String text) {
+		giveFeedback(1, text);
+	}
+
+	public static void giveNegativeFeedback(String text) {
+		giveFeedback(-1, text);
+	}
+
+	public static void clearGreenstoneSession() {
+		SearchGreenstone.clearSession();
+	}
+
+	public static void giveFeedback(double change, String text) {
+		Map<String, ResultDocument> sessionResults = SearchGreenstone
+				.getConnection().getSessionResults();
+
+		if (sessionResults.size() == 0) {
+			MessageBay.errorMessage("The Greenstone Session is empty");
+			return;
+		}
+
+		for (String line : text.split("\n")) {
+			AttributeValuePair avp = new AttributeValuePair(line, false);
+
+			Method getMethod = null;
+			String targetValue = null;
+
+			if (!avp.hasPair()) {
+				if (!avp.hasAttributeOrValue())
+					continue;
+				/*
+				 * If only an attribute is supplied then search for it in the
+				 * entire biliographic text.
+				 * 
+				 */
+				try {
+					getMethod = ResultDocument.class.getMethod("toString",
+							new Class[] {});
+				} catch (SecurityException e) {
+					e.printStackTrace();
+				} catch (NoSuchMethodException e) {
+					e.printStackTrace();
+				}
+				targetValue = avp.getAttributeOrValue();
+			} else {
+				targetValue = avp.getValue().trim().toLowerCase();
+				String attribute = avp.getAttribute().trim().toLowerCase();
+
+				String methodName = "get"
+						+ Character.toUpperCase(attribute.charAt(0))
+						+ attribute.substring(1);
+
+				try {
+					getMethod = ResultDocument.class.getMethod(methodName,
+							new Class[] {});
+				} catch (SecurityException e) {
+					e.printStackTrace();
+					continue;
+				} catch (NoSuchMethodException e) {
+					// User provided an invalid attribute value pair
+					MessageBay.errorMessage("Invalid feedback characteristic: "
+							+ attribute);
+					continue;
+				}
+				
+				if(getMethod == null){
+					MessageBay.errorMessage("Document attribute does not exist: " + methodName);
+				}
+			}
+
+			for (ResultDocument srd : sessionResults.values()) {
+				double sessionScore = srd.getSessionScore();
+
+				/*
+				 * You will refine this part to make more sophisticated
+				 * comparisons and more sensible score modifications
+				 */
+
+				Object value = null;
+				try {
+					if(getMethod.getReturnType() == null){
+						//Get methods should always return a value
+						assert(false);
+					}
+					value = getMethod.invoke(srd, new Object[] {}).toString();
+				} catch (IllegalArgumentException e) {
+					e.printStackTrace();
+				} catch (IllegalAccessException e) {
+					e.printStackTrace();
+				} catch (InvocationTargetException e) {
+					e.printStackTrace();
+				}catch (NullPointerException e) {
+					e.printStackTrace();
+				}
+
+				if (value != null) {
+					if (value.toString().trim().toLowerCase().contains(targetValue)) {
+						sessionScore = sessionScore + change;
+					}
+
+					srd.setSessionScore(sessionScore);
+				}
+			}
+		}
+		MessageBay.displayMessage("Feedback complete", null, Color.green
+				.darker(), true, null);
+	}
+}
Index: /trunk/src/org/expeditee/actions/Misc.java
===================================================================
--- /trunk/src/org/expeditee/actions/Misc.java	(revision 375)
+++ /trunk/src/org/expeditee/actions/Misc.java	(revision 376)
@@ -17,5 +17,5 @@
 import javax.imageio.ImageIO;
 
-import org.expeditee.agents.wordprocessing.JSpellChecker;
+import org.expeditee.gui.AttributeUtils;
 import org.expeditee.gui.Browser;
 import org.expeditee.gui.DisplayIO;
@@ -35,5 +35,5 @@
 import org.expeditee.simple.SString;
 import org.expeditee.stats.CometStats;
-import org.expeditee.stats.DocumentStats;
+import org.expeditee.stats.DocumentStatsFast;
 import org.expeditee.stats.SessionStats;
 import org.expeditee.stats.StatsLogger;
@@ -274,12 +274,13 @@
 
 	}
-	
+
 	public static String GetDocumentStats(Frame frame) {
 		TimeKeeper timer = new TimeKeeper();
 		MessageBay.displayMessage("Computing document stats...");
-
-		DocumentStats docStats = new DocumentStats(frame);
+		FrameIO.ForceSaveFrame(frame);
+		DocumentStatsFast docStats = new DocumentStatsFast(frame.getName(),
+				frame.getTitle());
 		String result = docStats.toString();
-		
+
 		MessageBay.overwriteMessage("Document stats time: "
 				+ timer.getElapsedStringSeconds());
@@ -436,18 +437,27 @@
 	 * PNGFrame(currentFrame.getName())
 	 */
-	public static void PNGFrame() {
-		ImageFrame(DisplayIO.getCurrentFrame().getName(), "PNG");
+	public static void PNGFrame(Frame frame) {
+		ImageFrame(frame.getName(), "PNG");
 	}
 
 	public static String SaveImage(BufferedImage screen, String format,
 			String directory, String fileName) {
+		String suffix = "." + format.toLowerCase();
+		String shortFileName = fileName;
 		// Check if we need to append the suffix
 		if (fileName.indexOf('.') < 0)
-			fileName += "." + format.toLowerCase();
+			fileName += suffix;
+		else
+			shortFileName = fileName.substring(0, fileName.length() - suffix.length());
 
 		try {
+			int count = 2;
 			// set up the file for output
-			String fullFileName = directory + fileName;
-			File out = new File(fullFileName);
+			File out = new File(directory + fileName);
+			while (out.exists()) {
+				fileName = shortFileName + "_" + count++ + suffix;
+				out = new File(directory + fileName);
+			}
+
 			if (!out.getParentFile().exists())
 				out.mkdirs();
@@ -910,41 +920,37 @@
 	}
 
-	public static String checkSpelling(String word) {
-		try {
-			return JSpellChecker.getInstance().getSuggestions(word);
-		} catch (FileNotFoundException e) {
-			MessageBay.errorMessage("Could not find dictionary: "
-					+ e.getMessage());
-		} catch (IOException e) {
-			// TODO Auto-generated catch block
-			e.printStackTrace();
-		}
-		return null;
-	}
-	
-	public static String spellCheck(String word) {
-		return checkSpelling(word);
-	}
-	
 	public static int wordCount(String paragraph) {
 		return paragraph.trim().split("\\s+").length + 1;
 	}
-	
+
 	public static int wordCount(Frame frame) {
 		int count = 0;
-		
-		for(Text t: frame.getBodyTextItems(false)){
+
+		for (Text t : frame.getBodyTextItems(false)) {
 			count += wordCount(t.getText());
 		}
-		
+
 		return count;
 	}
-	
-	public static void moveToPublic(Frame frame){
+
+	public static void moveToPublic(Frame frame) {
 		FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.PUBLIC_PATH);
 	}
-	
-	public static void moveToPrivate(Frame frame){
+
+	public static void moveToPrivate(Frame frame) {
 		FrameIO.moveFrameset(frame.getFramesetName(), FrameIO.FRAME_PATH);
 	}
+
+	/**
+	 * Returns the value of a specified item attribute.
+	 * 
+	 * @param item
+	 *            from which to extract the value
+	 * @param attribute
+	 *            name of an items attribute
+	 * @return the value of the attribute
+	 */
+	public static String extract(Item item, String attribute) {
+		return AttributeUtils.getAttribute(item, attribute);
+	}
 }
Index: /trunk/src/org/expeditee/actions/Simple.java
===================================================================
--- /trunk/src/org/expeditee/actions/Simple.java	(revision 375)
+++ /trunk/src/org/expeditee/actions/Simple.java	(revision 376)
@@ -20,8 +20,8 @@
 import org.expeditee.agents.DisplayTree;
 import org.expeditee.agents.SearchAgent;
+import org.expeditee.agents.SearchFramesetAndReplace;
 import org.expeditee.agents.SearchFrameset;
-import org.expeditee.agents.SearchFramesetFast;
+import org.expeditee.agents.SearchTreeAndReplace;
 import org.expeditee.agents.SearchTree;
-import org.expeditee.agents.SearchTreeFast;
 import org.expeditee.agents.WriteTree;
 import org.expeditee.gui.AttributeUtils;
@@ -328,5 +328,11 @@
 			boolean acceptKeyboardInput, boolean step, int pause, Color color) {
 		try {
-			DisplayIO.addToBack(current.getParent());
+			if (current != null) {
+				DisplayIO.addToBack(current.getParent());
+			} else {
+				/*TODO we should not have to pass an item just to run a frame!*/
+				current = new Text("Dummy");
+				current.setLink(frame.getName());
+			}
 
 			_stepColor = color == null ? Color.green : color;
@@ -339,5 +345,5 @@
 
 			// an item without a link signals to run the current frame
-			if (current.getLink() == null) {
+			if (current != null && current.getLink() == null) {
 				// Make a copy but hide it
 				current = current.copy();
@@ -351,4 +357,5 @@
 			t.start();
 		} catch (Exception e) {
+			e.printStackTrace();
 		}
 	}
@@ -932,7 +939,8 @@
 				// The fast search does not do replacement
 				if (bReplace) {
+					searchAgent = new SearchFramesetAndReplace(firstFrame,
+							maxFrame, null);
+				} else {
 					searchAgent = new SearchFrameset(firstFrame, maxFrame, null);
-				} else {
-					searchAgent = new SearchFramesetFast(firstFrame, maxFrame, null);
 				}
 				searchAgent.initialise(null, null, frameset, resultsFrameset,
@@ -975,7 +983,7 @@
 				// now The fast search does not do replacement
 				if (bReplace) {
+					searchAgent = new SearchTreeAndReplace(null);
+				} else {
 					searchAgent = new SearchTree(null);
-				} else {
-					searchAgent = new SearchTreeFast(null);
 				}
 				_agent = searchAgent;
@@ -1675,5 +1683,5 @@
 			String s = getMessage(tokens, context, code.toString(), tokens[0]
 					.equals("type") ? " " : "", 1);
-			
+
 			DisplayIO.typeStringDirect(0.025, s);
 		} else if (tokens[0].equals("runstring")) {
@@ -2031,6 +2039,7 @@
 				} catch (Exception e) {
 				}
-			}else{
-				Frame zero = FrameIO.LoadFrame(freshCopy.getFramesetName() + "0");
+			} else {
+				Frame zero = FrameIO.LoadFrame(freshCopy.getFramesetName()
+						+ "0");
 				freshCopy.setPath(zero.getPath());
 			}
Index: /trunk/src/org/expeditee/actions/Spelling.java
===================================================================
--- /trunk/src/org/expeditee/actions/Spelling.java	(revision 376)
+++ /trunk/src/org/expeditee/actions/Spelling.java	(revision 376)
@@ -0,0 +1,81 @@
+package org.expeditee.actions;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.expeditee.agents.wordprocessing.JSpellChecker;
+import org.expeditee.gui.FrameIO;
+import org.expeditee.gui.MessageBay;
+import org.expeditee.gui.UserSettings;
+
+public class Spelling {
+	public static Collection<String> spellCheckFrame(String frameName,
+			String path) {
+		String fullPath = null;
+		JSpellChecker spellChecker = null;
+		try {
+			spellChecker = JSpellChecker.getInstance();
+		} catch (FileNotFoundException e1) {
+			e1.printStackTrace();
+			return null;
+		} catch (IOException e1) {
+			e1.printStackTrace();
+			return null;
+		}
+		if (path == null) {
+			for (String possiblePath : UserSettings.FrameDirs) {
+				fullPath = FrameIO
+						.getFrameFullPathName(possiblePath, frameName);
+				if (fullPath != null)
+					break;
+			}
+		} else {
+			fullPath = FrameIO.getFrameFullPathName(path, frameName);
+		}
+		// If the frame was not located return null
+		if (fullPath == null)
+			return null;
+		Collection<String> results = new LinkedList<String>();
+		// Open the file and search the text items
+		try {
+			BufferedReader reader = new BufferedReader(new FileReader(fullPath));
+			String next;
+			while (reader.ready() && ((next = reader.readLine()) != null)) {
+				if (next.startsWith("T")) {
+					String toSearch = next.substring(2);
+					spellChecker.setText(toSearch);
+					String misspelled = spellChecker.getMisspelledWord();
+					if (misspelled != null && misspelled.length() > 0) {
+						results.add(toSearch);
+					}
+				}
+			}
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+			return null;
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return results;
+	}
+
+	public static String checkSpelling(String word) {
+		try {
+			return JSpellChecker.getInstance().getSuggestions(word);
+		} catch (FileNotFoundException e) {
+			MessageBay.errorMessage("Could not find dictionary: "
+					+ e.getMessage());
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return null;
+	}
+
+	public static String spellCheck(String word) {
+		return checkSpelling(word);
+	}
+}
Index: /trunk/src/org/expeditee/agents/DisplayGreenstoneSession.java
===================================================================
--- /trunk/src/org/expeditee/agents/DisplayGreenstoneSession.java	(revision 376)
+++ /trunk/src/org/expeditee/agents/DisplayGreenstoneSession.java	(revision 376)
@@ -0,0 +1,84 @@
+package org.expeditee.agents;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.expeditee.greenstone.ResultDocument;
+import org.expeditee.gui.FrameCreator;
+import org.expeditee.io.Logger;
+
+public class DisplayGreenstoneSession extends SearchGreenstone {
+
+	public DisplayGreenstoneSession(int resultsCount) {
+		super(resultsCount);
+	}
+
+	public DisplayGreenstoneSession() {
+		super();
+	}
+
+	protected void createResults() {
+		if (!_gsdl.getSessionResults().isEmpty()) {
+			viewSessionResults(_gsdl.getSessionResults(), _results);
+		}
+	}
+	
+	protected String getResultsTitle() {
+		return "SessionResults at " + Logger.EasyDateFormat(Logger.LONG_DATE_FORMAT);
+	}
+
+	/**
+	 * This method provides an alternative view of the result set It uses the
+	 * dateMap which organises results according to the year in which they were
+	 * published
+	 * 
+	 * You will need to write a similar method for any additional view that you
+	 * implement
+	 * 
+	 * You may wish to modify this method to provide a better layout of the
+	 * output
+	 */
+	private void viewSessionResults(Map<String, ResultDocument> sessionResults,
+			FrameCreator results) {
+
+		List<ResultDocument> resultDocArrayList = new ArrayList<ResultDocument>(
+				sessionResults.values());
+		Collections.sort(resultDocArrayList,
+				new DescendingSessionScoreComparator());
+
+		int docRank = 1;
+		
+		for(ResultDocument rd: resultDocArrayList){
+			addText(rd, results, docRank++ + ". " + rd.getTitle());
+		}
+
+	}
+	
+	protected String getCursorText() {
+		return getResultsTitle();
+	}
+
+	static class DescendingSessionScoreComparator implements Comparator<ResultDocument> {
+
+		public int compare(ResultDocument d1, ResultDocument d2) {
+
+			double sessionScore1 = d1.getSessionScore();
+			double sessionScore2 = d2.getSessionScore();
+
+			if (sessionScore1 > sessionScore2) {
+				return -1;
+			} else if (sessionScore1 < sessionScore2) {
+				return 1;
+			} else {
+				return 0;
+			}
+		}
+	}
+	
+	protected String getNoResultsMessage() {
+		return "The session results set is empty";
+	}
+}
Index: /trunk/src/org/expeditee/agents/Format.java
===================================================================
--- /trunk/src/org/expeditee/agents/Format.java	(revision 375)
+++ /trunk/src/org/expeditee/agents/Format.java	(revision 376)
@@ -5,4 +5,5 @@
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 
@@ -45,12 +46,24 @@
 	@Override
 	public Frame process(Frame start) {
-		//TODO What will happen if user runs the SIMPLE form of this...
-		//Does format box need to be disabled?!?!
-		//Check the position of the cursor and only format stuff inside the same box as the cursor
+		// TODO What will happen if user runs the SIMPLE form of this...
+		// Does format box need to be disabled?!?!
+		// Check the position of the cursor and only format stuff inside the
+		// same box as the cursor
 		Collection<Text> itemsToFormat = FrameUtils.getCurrentTextItems();
-		if(itemsToFormat.size() < 1){
+
+		// If the cursor is not inside a box...
+		if (itemsToFormat.size() < 1) {
+			// Add all the items that are in free space
 			itemsToFormat = start.getBodyTextItems(true);
+			// Remove all the enclosed items
+			Collection<Item> seen = new HashSet<Item>();
+			for (Item i : start.getVisibleItems()) {
+				if (!seen.contains(i) && i.isEnclosed()) {
+					seen.addAll(i.getEnclosingDots());
+					itemsToFormat.removeAll(i.getEnclosedItems());
+				}
+			}
 		}
-		
+
 		ArrayList<Item> columnHeads = new ArrayList<Item>();
 
@@ -175,5 +188,5 @@
 			overwriteMessage("Formatting complete.");
 	}
-	
+
 	@Override
 	protected void message(String message) {
Index: /trunk/src/org/expeditee/agents/SearchAgent.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchAgent.java	(revision 375)
+++ /trunk/src/org/expeditee/agents/SearchAgent.java	(revision 376)
@@ -1,3 +1,5 @@
 package org.expeditee.agents;
+
+import java.util.Collection;
 
 import org.expeditee.gui.Frame;
@@ -24,5 +26,6 @@
 
 	public SearchAgent(String searchText) {
-		_pattern = searchText.toLowerCase();
+		if (searchText != null)
+			_pattern = searchText.toLowerCase();
 	}
 
@@ -39,6 +42,14 @@
 					false);
 		}
-		return initialise(frame, item, frame.getFramesetName(), resultFrameset,
+		return initialise(frame, item, getSearchDescription(frame), resultFrameset,
 				null, pattern);
+	}
+
+	/**
+	 * @param frame
+	 * @return
+	 */
+	protected String getSearchDescription(Frame frame) {
+		return frame.getFramesetName();
 	}
 
@@ -56,6 +67,7 @@
 	public boolean initialise(Frame frame, Item item, String startName,
 			String resultsFrameset, String replacementString, String pattern) {
-		//TODO: Put the init params in the constructor!! Dont want to be setting _pattern in two places!
-		
+		// TODO: Put the init params in the constructor!! Dont want to be
+		// setting _pattern in two places!
+
 		if (_pattern == null)
 			_pattern = pattern.toLowerCase();
@@ -66,10 +78,15 @@
 		// and type as the title
 		String title = this.getClass().getSimpleName() + " [" + startName
-				+ "] [" + _pattern + "]";
-		_results = new FrameCreator(resultsFrameset, FrameIO.FRAME_PATH, title, false, true);
+				+ "]"+getResultsTitleSuffix();
+		_results = new FrameCreator(resultsFrameset, FrameIO.FRAME_PATH, title,
+				false, true);
 		// Set the frame to be displayed after running the agent
 		_end = _results.getFirstFrame();
 
 		return super.initialise(frame, item);
+	}
+
+	protected String getResultsTitleSuffix() {
+		return " [" + _pattern + "]";
 	}
 
@@ -111,3 +128,39 @@
 		return true;
 	}
+	
+	protected int addResults(String frameName, Collection<String> found) {
+		return addResults(frameName, frameName, found);
+	}
+	
+	/**
+	 * @param frameNumber
+	 * @param frameName
+	 * @param found
+	 * @return
+	 */
+	protected int addResults(String frameNumber, String frameName, Collection<String> found) {
+		int size = found == null ? 0 : found.size();
+		// If the frame exists
+		if (found != null)
+			_frameCount++;
+		if (size > 0) {
+			// String repeats = size > 1? ("("+ size+ ")") : "";
+			for (String s : found) {
+				StringBuffer surrogate = new StringBuffer();
+				surrogate.append("[").append(frameNumber).append("] ");
+				if (s.length() > SearchAgent.SURROGATE_LENGTH)
+					surrogate.append(
+							s.substring(0, SearchAgent.SURROGATE_LENGTH - 3))
+							.append("...");
+				else {
+					surrogate.append(s);
+				}
+
+				_results.addText(surrogate.toString(), null,
+						frameName, null, false);
+				FrameGraphics.requestRefresh(true);
+			}
+		}
+		return size;
+	}
 }
Index: /trunk/src/org/expeditee/agents/SearchFrameset.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchFrameset.java	(revision 375)
+++ /trunk/src/org/expeditee/agents/SearchFrameset.java	(revision 376)
@@ -1,3 +1,5 @@
 package org.expeditee.agents;
+
+import java.util.Collection;
 
 import org.expeditee.gui.Frame;
@@ -6,6 +8,7 @@
 public class SearchFrameset extends SearchAgent {
 	private long _firstFrame = 1;
+
 	private long _maxFrame = Integer.MAX_VALUE;
-	
+
 	public SearchFrameset(long firstFrame, long maxFrame, String searchText) {
 		this(searchText);
@@ -13,5 +16,5 @@
 		_maxFrame = maxFrame;
 	}
-	
+
 	public SearchFrameset(String searchText) {
 		super(searchText);
@@ -20,6 +23,11 @@
 	@Override
 	protected Frame process(Frame frame) {
+		if (frame == null) {
+			frame = FrameIO.LoadFrame(_startName + '0');
+		}
+		String path = frame.getPath();
+
 		int count = FrameIO.getLastNumber(_startName);
-		for (long i = _firstFrame;i <= _maxFrame && i <= count; i++) {
+		for (long i = _firstFrame; i <= _maxFrame && i <= count; i++) {
 			if (_stop) {
 				break;
@@ -27,7 +35,7 @@
 			String frameName = _startName + i;
 			overwriteMessage("Searching " + frameName);
-			if(searchFrame(_results, frameName, _pattern,
-					_replacementString))
-				_frameCount++;
+			Collection<String> found = FrameIO.searchFrame(frameName, _pattern,
+					path);
+			addResults(i + "", frameName, found);
 		}
 		_results.save();
Index: /trunk/src/org/expeditee/agents/SearchFramesetAndReplace.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchFramesetAndReplace.java	(revision 376)
+++ /trunk/src/org/expeditee/agents/SearchFramesetAndReplace.java	(revision 376)
@@ -0,0 +1,41 @@
+package org.expeditee.agents;
+
+import org.expeditee.gui.Frame;
+import org.expeditee.gui.FrameIO;
+
+public class SearchFramesetAndReplace extends SearchAgent {
+	private long _firstFrame = 1;
+	private long _maxFrame = Integer.MAX_VALUE;
+	
+	public SearchFramesetAndReplace(long firstFrame, long maxFrame, String searchText) {
+		this(searchText);
+		_firstFrame = firstFrame;
+		_maxFrame = maxFrame;
+	}
+	
+	public SearchFramesetAndReplace(String searchText) {
+		super(searchText);
+	}
+
+	@Override
+	protected Frame process(Frame frame) {
+		int count = FrameIO.getLastNumber(_startName);
+		for (long i = _firstFrame;i <= _maxFrame && i <= count; i++) {
+			if (_stop) {
+				break;
+			}
+			String frameName = _startName + i;
+			overwriteMessage("Searching " + frameName);
+			if(searchFrame(_results, frameName, _pattern,
+					_replacementString))
+				_frameCount++;
+		}
+		_results.save();
+
+		String resultFrameName = _results.getName();
+		if (_clicked != null)
+			_clicked.setLink(resultFrameName);
+
+		return _results.getFirstFrame();
+	}
+}
Index: unk/src/org/expeditee/agents/SearchFramesetFast.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchFramesetFast.java	(revision 375)
+++ 	(revision )
@@ -1,71 +1,0 @@
-package org.expeditee.agents;
-
-import java.util.Collection;
-
-import org.expeditee.gui.Frame;
-import org.expeditee.gui.FrameGraphics;
-import org.expeditee.gui.FrameIO;
-
-public class SearchFramesetFast extends SearchAgent {
-	private long _firstFrame = 1;
-
-	private long _maxFrame = Integer.MAX_VALUE;
-
-	public SearchFramesetFast(long firstFrame, long maxFrame, String searchText) {
-		this(searchText);
-		_firstFrame = firstFrame;
-		_maxFrame = maxFrame;
-	}
-
-	public SearchFramesetFast(String searchText) {
-		super(searchText);
-	}
-
-	@Override
-	protected Frame process(Frame frame) {
-		if (frame == null) {
-			frame = FrameIO.LoadFrame(_startName + '0');
-		}
-		String path = frame.getPath();
-
-		int count = FrameIO.getLastNumber(_startName);
-		for (long i = _firstFrame; i <= _maxFrame && i <= count; i++) {
-			if (_stop) {
-				break;
-			}
-			String frameName = _startName + i;
-			overwriteMessage("Searching " + frameName);
-			Collection<String> found = FrameIO.searchFrame(frameName, _pattern,
-					path);
-			int size = found == null ? 0 : found.size();
-			// If the frame exists
-			if (found != null)
-				_frameCount++;
-			if (size > 0) {
-				// String repeats = size > 1? ("("+ size+ ")") : "";
-				for (String s : found) {
-					StringBuffer surrogate = new StringBuffer();
-					surrogate.append("[").append(i).append("] ");
-					if (s.length() > SearchAgent.SURROGATE_LENGTH)
-						surrogate.append(
-								s.substring(0, SearchAgent.SURROGATE_LENGTH - 3))
-								.append("...");
-					else {
-						surrogate.append(s);
-					}
-
-					_results.addText(surrogate.toString(), null,
-							frameName, null, false);
-					FrameGraphics.requestRefresh(true);
-				}
-			}
-		}
-		_results.save();
-
-		String resultFrameName = _results.getName();
-		if (_clicked != null)
-			_clicked.setLink(resultFrameName);
-
-		return _results.getFirstFrame();
-	}
-}
Index: /trunk/src/org/expeditee/agents/SearchGreenstone.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchGreenstone.java	(revision 375)
+++ /trunk/src/org/expeditee/agents/SearchGreenstone.java	(revision 376)
@@ -1,5 +1,4 @@
 package org.expeditee.agents;
 
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
@@ -30,4 +29,8 @@
 	protected static Greenstone3Connection _gsdl = null;
 
+	public static Greenstone3Connection getConnection() {
+		return _gsdl;
+	}
+
 	private static String _maxResults = "10";
 
@@ -84,4 +87,9 @@
 	}
 
+	public SearchGreenstone(int resultsCount) {
+		this(null);
+		_thisMaxResults = resultsCount + "";
+	}
+
 	public SearchGreenstone() {
 		super(null);
@@ -113,5 +121,4 @@
 			else if (attribute.equals("autoconnect"))
 				connect();
-
 			else if (attribute.equals("maxresults")) {
 				try {
@@ -119,7 +126,5 @@
 				} catch (Exception e) {
 				}
-			}
-
-			else if (attribute.equals("dostemming"))
+			} else if (attribute.equals("dostemming"))
 				_doStemming = true;
 			else if (attribute.startsWith("showabstract"))
@@ -139,8 +144,11 @@
 	}
 
+	protected String getResultsTitle() {
+		return this.getClass().getSimpleName() + "[" + getCursorText() + "]";
+	}
+
 	@Override
 	protected Frame process(Frame frame) {
-		String resultsTitle = this.getClass().getSimpleName() + "["
-				+ _fullCaseSearchQuery + "]";
+		String resultsTitle = getResultsTitle();
 		_results.setTitle(resultsTitle);
 
@@ -150,11 +158,11 @@
 		} else if (_currentResultSet != null) {
 			Text newText = DisplayIO.getCurrentFrame().createNewText(
-					_fullCaseSearchQuery);
+					getCursorText());
 			_clicked = newText;
 			FrameMouseActions.pickup(newText);
 		}
 
-		if (_currentResultSet == null) {
-			MessageBay.errorMessage("Could not find Greenstone query text");
+		if (_currentResultSet == null || _currentResultSet.size() == 0) {
+			MessageBay.errorMessage(getNoResultsMessage());
 			return null;
 		}
@@ -171,4 +179,15 @@
 
 		return _results.getFirstFrame();
+	}
+
+	protected String getNoResultsMessage() {
+		return "Could not find Greenstone query text";
+	}
+
+	/**
+	 * @return
+	 */
+	protected String getCursorText() {
+		return _fullCaseSearchQuery;
 	}
 
@@ -189,5 +208,6 @@
 		Query query = createQuery(queryText);
 		QueryOutcome queryOutcome = _gsdl.issueQueryToServer(query);
-		_currentResultSet = getResultSetMetadata(queryOutcome);
+		if (queryOutcome != null)
+			_currentResultSet = getResultSetMetadata(queryOutcome);
 	}
 
@@ -281,43 +301,41 @@
 
 		if (rd.metadataExists("Title")) {
-			resultText.append("title = " + rd.getTitle()).append('\n');
+			resultText.append("title: " + rd.getTitle()).append('\n');
 		}
 		if (rd.metadataExists("Date")) {
-			resultText.append("date = " + rd.getDate()).append('\n');
+			resultText.append("date: " + rd.getDate()).append('\n');
 		}
 		if (rd.metadataExists("Booktitle")) {
-			resultText.append("booktitle = " + rd.getBooktitle()).append('\n');
+			resultText.append("booktitle: " + rd.getBooktitle()).append('\n');
 		}
 		if (rd.metadataExists("Pages")) {
-			resultText.append("pages = " + rd.getPages()).append('\n');
+			resultText.append("pages: " + rd.getPages()).append('\n');
 		}
 		if (rd.metadataExists("Journal")) {
-			resultText.append("journal = " + rd.getJournal()).append('\n');
+			resultText.append("journal: " + rd.getJournal()).append('\n');
 		}
 		if (rd.metadataExists("Volume")) {
-			resultText.append("volume = " + rd.getVolume()).append('\n');
+			resultText.append("volume: " + rd.getVolume()).append('\n');
 		}
 		if (rd.metadataExists("Number")) {
-			resultText.append("number = " + rd.getNumber()).append('\n');
+			resultText.append("number: " + rd.getNumber()).append('\n');
 		}
 		if (rd.metadataExists("Editor")) {
-			resultText.append("editor = " + rd.getEditor()).append('\n');
+			resultText.append("editor: " + rd.getEditor()).append('\n');
 		}
 		if (rd.metadataExists("Publisher")) {
-			resultText.append("publisher = " + rd.getPublisher()).append('\n');
+			resultText.append("publisher: " + rd.getPublisher()).append('\n');
 		}
 		if (rd.metadataExists("Abstract")) {
-			resultText.append("abstract = " + rd.getAbstract()).append('\n');
-		}
-		Vector<String> authors = rd.getAuthors();
-		for (Enumeration a = authors.elements(); a.hasMoreElements();) {
-			String author = (String) a.nextElement();
-			resultText.append("author = " + author).append('\n');
-		}
-		Vector<String> keywords = rd.getKeywords();
-		for (Enumeration k = keywords.elements(); k.hasMoreElements();) {
-			String keyword = (String) k.nextElement();
-			resultText.append("keyword = " + keyword).append('\n');
-		}
+			resultText.append("abstract: " + rd.getAbstract()).append('\n');
+		}
+		for (String author : rd.getAuthors()) {
+			resultText.append("author: " + author).append('\n');
+		}
+
+		for (String keyword : rd.getKeywords()) {
+			resultText.append("keyword: " + keyword).append('\n');
+		}
+
 		resultText.deleteCharAt(resultText.length() - 1);
 
@@ -356,3 +374,8 @@
 	}
 
+	public static void clearSession() {
+		getConnection().getSessionResults().clear();
+		_currentResultSet = null;
+	}
+
 }
Index: /trunk/src/org/expeditee/agents/SearchTree.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchTree.java	(revision 375)
+++ /trunk/src/org/expeditee/agents/SearchTree.java	(revision 376)
@@ -1,24 +1,33 @@
 package org.expeditee.agents;
 
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
 
+import org.expeditee.gui.AttributeValuePair;
 import org.expeditee.gui.Frame;
-import org.expeditee.gui.FrameGraphics;
 import org.expeditee.gui.FrameIO;
-import org.expeditee.items.Text;
+import org.expeditee.gui.UserSettings;
+import org.expeditee.io.Conversion;
 
 public class SearchTree extends SearchAgent {
+	private Map<String, Collection<String>> _searchResults = new HashMap<String, Collection<String>>();
+
 	public SearchTree(String searchText) {
 		super(searchText);
 	}
-	
+
 	@Override
 	protected Frame process(Frame frame) {
-		try {
-			searchTree(new HashSet<String>(), _startName);
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
+		if (frame == null)
+			frame = FrameIO.LoadFrame(_startName);
+
+		searchTree(frame.getName(), _searchResults, new HashSet<String>());
 		_results.save();
 
@@ -30,38 +39,131 @@
 	}
 
-	public boolean searchTree(Collection<String> visitedFrames, String frameName)
-			throws Exception {
-		if (_stop) {
-			return false;
+	@Override
+	/**
+	 * @param frame
+	 * @return
+	 */
+	protected String getSearchDescription(Frame frame) {
+		return frame.getName();
+	}
+
+	/**
+	 * Returns a list of the frames searched and any matches on those frames.
+	 * 
+	 * @param frameName
+	 *            the name of the top not in the tree of frames to search
+	 * @param pattern
+	 *            the pattern to search for
+	 * @param results
+	 *            a list of frames on which matches were found and the text that
+	 *            matched the pattern
+	 * @param visited
+	 *            a list of the frames that were visited in the searchTree
+	 */
+	public void searchTree(String frameName,
+			Map<String, Collection<String>> results, Collection<String> visited) {
+		// Check if this node has already been visited
+		if (visited.contains(frameName))
+			return;
+
+		visited.add(frameName);
+
+		String fullPath = null;
+		for (String possiblePath : UserSettings.FrameDirs) {
+			fullPath = FrameIO.getFrameFullPathName(possiblePath, frameName);
+			if (fullPath != null)
+				break;
 		}
-		// Avoid infinate loops
-		if (visitedFrames.contains(frameName))
-			return false;
-		visitedFrames.add(frameName);
 
-		Frame frameToSearch = FrameIO.LoadFrame(frameName);
-		if (frameToSearch == null)
-			return false;
+		// If the frame was not located return null
+		if (fullPath == null)
+			return;
 
+		_frameCount++;
 		overwriteMessage("Searching " + frameName);
 
-		for (Text itemToSearch : frameToSearch.getTextItems()) {
-			// Search for the item and add it to the results page if
-			// it is found
-			if (searchItem(itemToSearch, _pattern,
-					_replacementString)) {
-				// Add a linked item to the results frame
-				_results.addText(frameName, null, frameName, null, false);
-			}
-			if (!itemToSearch.isAnnotation()) {
-				String link = itemToSearch.getAbsoluteLink();
-				if (link != null) {
-					searchTree(visitedFrames, link);
+		String frameset = Conversion.getFramesetName(frameName);
+
+		Collection<String> frameResults = new LinkedList<String>();
+		// Open the file and search the text items
+		try {
+			BufferedReader reader = new BufferedReader(new FileReader(fullPath));
+			String next;
+			StringBuffer sb = new StringBuffer();
+			String link = null;
+			boolean ignore = false;
+
+			while (reader.ready() && ((next = reader.readLine()) != null)) {
+
+				if (next.length() == 0) {
+					// Ignore annotations
+					if (ignore) {
+						ignore = false;
+						link = null;
+						continue;
+					}
+
+					// Ignore non text items
+					if (sb.length() == 0) {
+						link = null;
+						continue;
+					}
+
+					String toSearch = sb.substring(0, sb.length() - 1);
+					String resultSurrogate = getResultSurrogate(toSearch);
+					if (resultSurrogate != null) {
+						frameResults.add(resultSurrogate);
+					}
+
+					if (link != null) {
+						searchTree(link, results, visited);
+					}
+
+					// Reinit the item variables
+					link = null;
+					sb = new StringBuffer();
+
+				} else if (ignore) {
+					continue;
+				} else if (next.startsWith("T")) {
+					String text = next.substring(2).trim();
+					// Ignore the rest of annotation items...
+					if (text.length() > 0
+							&& text.charAt(0) == AttributeValuePair.ANNOTATION_CHAR) {
+						ignore = true;
+						continue;
+					}
+					sb.append(text).append('\n');
+				} else if (next.startsWith("F")) {
+					link = next.substring(2);
+					// Convert number only links
+					if (Character.isDigit(link.charAt(0)))
+						link = frameset + link;
 				}
 			}
+			// Only add the results if a match was found on the frame
+			if (frameResults.size() > 0) {
+				results.put(frameName, frameResults);
+			}
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
 		}
-		FrameGraphics.requestRefresh(true);
-		FrameIO.SaveFrame(frameToSearch, false);
-		return true;
+		int size = frameResults.size();
+		if (size > 0) {
+			addResults(frameName, frameResults);
+
+			// String repeats = size > 1 ? ("(" + size + ")") : "";
+			// _results.addText(frameName + repeats, null, frameName, null,
+			// false);
+			// FrameGraphics.requestRefresh(true);
+		}
+	}
+
+	protected String getResultSurrogate(String toSearch) {
+		if (toSearch.toLowerCase().contains(_pattern))
+			return toSearch;
+		return null;
 	}
 }
Index: /trunk/src/org/expeditee/agents/SearchTreeAndReplace.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchTreeAndReplace.java	(revision 376)
+++ /trunk/src/org/expeditee/agents/SearchTreeAndReplace.java	(revision 376)
@@ -0,0 +1,67 @@
+package org.expeditee.agents;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.expeditee.gui.Frame;
+import org.expeditee.gui.FrameGraphics;
+import org.expeditee.gui.FrameIO;
+import org.expeditee.items.Text;
+
+public class SearchTreeAndReplace extends SearchAgent {
+	public SearchTreeAndReplace(String searchText) {
+		super(searchText);
+	}
+	
+	@Override
+	protected Frame process(Frame frame) {
+		try {
+			searchTree(new HashSet<String>(), _startName);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		_results.save();
+
+		String resultFrameName = _results.getName();
+		if (_clicked != null)
+			_clicked.setLink(resultFrameName);
+
+		return _results.getFirstFrame();
+	}
+
+	public boolean searchTree(Collection<String> visitedFrames, String frameName)
+			throws Exception {
+		if (_stop) {
+			return false;
+		}
+		// Avoid infinate loops
+		if (visitedFrames.contains(frameName))
+			return false;
+		visitedFrames.add(frameName);
+
+		Frame frameToSearch = FrameIO.LoadFrame(frameName);
+		if (frameToSearch == null)
+			return false;
+
+		overwriteMessage("Searching " + frameName);
+
+		for (Text itemToSearch : frameToSearch.getTextItems()) {
+			// Search for the item and add it to the results page if
+			// it is found
+			if (searchItem(itemToSearch, _pattern,
+					_replacementString)) {
+				// Add a linked item to the results frame
+				_results.addText(frameName, null, frameName, null, false);
+			}
+			if (!itemToSearch.isAnnotation()) {
+				String link = itemToSearch.getAbsoluteLink();
+				if (link != null) {
+					searchTree(visitedFrames, link);
+				}
+			}
+		}
+		FrameGraphics.requestRefresh(true);
+		FrameIO.SaveFrame(frameToSearch, false);
+		return true;
+	}
+}
Index: unk/src/org/expeditee/agents/SearchTreeFast.java
===================================================================
--- /trunk/src/org/expeditee/agents/SearchTreeFast.java	(revision 375)
+++ 	(revision )
@@ -1,105 +1,0 @@
-package org.expeditee.agents;
-
-import java.io.BufferedReader;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Map;
-
-import org.expeditee.gui.Frame;
-import org.expeditee.gui.FrameGraphics;
-import org.expeditee.gui.FrameIO;
-import org.expeditee.gui.UserSettings;
-import org.expeditee.io.Conversion;
-
-public class SearchTreeFast extends SearchAgent {
-	private Map<String, Collection<String>> _searchResults = new HashMap<String, Collection<String>>();
-
-	public SearchTreeFast(String searchText) {
-		super(searchText);
-	}
-	
-	@Override
-	protected Frame process(Frame frame) {
-		if(frame == null)
-			frame = FrameIO.LoadFrame(_startName);
-		
-		searchTree(frame.getName(), _pattern, _searchResults, new HashSet<String>());
-		
-		_results.save();
-
-		String resultFrameName = _results.getName();
-		if (_clicked != null)
-			_clicked.setLink(resultFrameName);
-		
-		return _results.getFirstFrame();
-	}
-	
-	/**
-	 * Returns a list of the frames searched and any matches on those frames.
-	 * @param frameName the name of the top not in the tree of frames to search
-	 * @param pattern the pattern to search for
-	 * @param results a list of frames on which matches were found and the text that matched the pattern
-	 * @param visited a list of the frames that were visited in the searchTree
-	 */
-	public void searchTree(String frameName, String pattern, Map<String, Collection<String>> results, Collection<String> visited) {
-		//Check if this node has already been visited
-		if(visited.contains(frameName))
-			return;
-		
-		visited.add(frameName);
-		
-		String fullPath = null;
-		for (String possiblePath : UserSettings.FrameDirs) {
-			fullPath = FrameIO.getFrameFullPathName(possiblePath, frameName);
-			if (fullPath != null)
-				break;
-		}
-
-		// If the frame was not located return null
-		if (fullPath == null)
-			return;
-		
-		_frameCount++;
-		overwriteMessage("Searching " + frameName);
-		
-		String frameset = Conversion.getFramesetName(frameName);
-		
-		Collection<String> frameResults = new LinkedList<String>();
-		// Open the file and search the text items
-		try {
-			BufferedReader reader = new BufferedReader(new FileReader(fullPath));
-			String next;
-			while (reader.ready() && ((next = reader.readLine()) != null)) {
-				if (next.startsWith("T")) {
-					String toSearch = next.substring(2);
-					if (toSearch.toLowerCase().contains(pattern))
-						frameResults.add(toSearch);
-				}else if (next.startsWith("F")) {
-					String link = next.substring(2);
-					if(!FrameIO.isValidFrameName(link))
-						link = frameset + link;
-					searchTree(link, pattern, results, visited);
-				}
-			}
-			//Only add the results if a match was found on the frame
-			if(frameResults.size() > 0){
-				results.put(frameName, frameResults);
-			}
-		} catch (FileNotFoundException e) {
-			e.printStackTrace();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
-		int size = frameResults.size();
-		if(size > 0){
-			String repeats = size > 1? ("("+ size+ ")") : "";
-			_results.addText(frameName + repeats, null, frameName, null, false);
-			FrameGraphics.requestRefresh(true);
-		}
-	}
-}
Index: /trunk/src/org/expeditee/agents/SpellcheckTree.java
===================================================================
--- /trunk/src/org/expeditee/agents/SpellcheckTree.java	(revision 376)
+++ /trunk/src/org/expeditee/agents/SpellcheckTree.java	(revision 376)
@@ -0,0 +1,52 @@
+package org.expeditee.agents;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import org.expeditee.agents.wordprocessing.JSpellChecker;
+
+public class SpellcheckTree extends SearchTree {
+
+	private JSpellChecker _spellChecker = null;
+
+	public SpellcheckTree() {
+		super(null);
+
+		try {
+			_spellChecker = JSpellChecker.getInstance();
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		// TODO better handle errors
+	}
+
+	@Override
+	protected String getResultSurrogate(String toSearch) {
+		if (_spellChecker == null)
+			return null;
+		_spellChecker.setText(toSearch);
+		_spellChecker.check();
+
+		String badSpelling = _spellChecker.getMisspelledWord();
+		String result = badSpelling;
+//		while (badSpelling != null) {
+//			_spellChecker.ignoreWord(true);
+//			_spellChecker.check();
+//			badSpelling = _spellChecker.getMisspelledWord();
+//			if (badSpelling != null)
+//				result += "," + badSpelling;
+//		}
+
+		if (badSpelling == null || badSpelling.length() <= 1)
+			return null;
+
+		return "[" + result + "] " + toSearch;
+	}
+	
+	@Override
+	protected String getResultsTitleSuffix() {
+		return "";
+	}
+}
Index: /trunk/src/org/expeditee/agents/wordprocessing/JSpellChecker.java
===================================================================
--- /trunk/src/org/expeditee/agents/wordprocessing/JSpellChecker.java	(revision 375)
+++ /trunk/src/org/expeditee/agents/wordprocessing/JSpellChecker.java	(revision 376)
@@ -1,4 +1,5 @@
 package org.expeditee.agents.wordprocessing;
 
+import java.awt.Color;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -8,5 +9,8 @@
 import java.util.List;
 
+import org.expeditee.gui.Frame;
 import org.expeditee.gui.FrameIO;
+import org.expeditee.gui.MessageBay;
+import org.expeditee.items.Text;
 
 import com.swabunga.spell.engine.Configuration;
@@ -59,5 +63,6 @@
 	public static JSpellChecker _theInstance = null;
 
-	public static JSpellChecker getInstance() throws FileNotFoundException, IOException {
+	public static JSpellChecker getInstance() throws FileNotFoundException,
+			IOException {
 		if (_theInstance == null) {
 			create();
@@ -66,10 +71,24 @@
 	}
 
+	public static void create(Frame frame) throws FileNotFoundException,
+			IOException {
+		if(_theInstance == null)
+			_theInstance = new JSpellChecker();
+		_theInstance.init();
+
+		if (frame != null) {
+			for (Text t : frame.getBodyTextItems(false)) {
+				for (String s : t.getText().split(" ")) {
+					_theInstance.checker.addToDictionary(s);
+				}
+			}
+		}
+	}
+
 	public static void create() throws FileNotFoundException, IOException {
-		_theInstance = new JSpellChecker();
-		_theInstance.init();
-	}
-
-	public static String dictFile = FrameIO.PARENT_FOLDER + "dict/english.0";
+		create(null);
+	}
+
+	public static String dictDirectory = FrameIO.PARENT_FOLDER + "dict/";
 
 	public JSpellChecker() {
@@ -79,10 +98,18 @@
 	public void init() throws FileNotFoundException, IOException {
 		log(this.hashCode() + ": JSpellChecker.init");
+		MessageBay.displayMessage("Loading spell checker...");
 
 		checker = new SpellChecker();
-
-		checker.addDictionary(new SpellDictionaryHashMap(new File(dictFile)));
+		SpellDictionaryHashMap dictionaryHashMap = new SpellDictionaryHashMap();
+
+		for (File dict : new File(dictDirectory).listFiles()) {
+			dictionaryHashMap.addDictionary(dict);
+		}
+
+		checker.addDictionary(dictionaryHashMap);
 
 		initialized = true;
+
+		MessageBay.displayMessage("Spell checker Loaded", Color.green.darker());
 	}
 
@@ -97,4 +124,5 @@
 		checker.addSpellCheckListener(listener);
 		checker.reset();
+		event = null;
 	}
 
@@ -137,6 +165,6 @@
 
 		}
-		
-		if(s.length() == 0){
+
+		if (s.length() == 0) {
 			return "No suggestions";
 		}
@@ -146,5 +174,5 @@
 		// + "|";
 		// }
-		return s.substring(0, s.length()-1);
+		return s.substring(0, s.length() - 1);
 	}
 
Index: /trunk/src/org/expeditee/greenstone/Greenstone3Connection.java
===================================================================
--- /trunk/src/org/expeditee/greenstone/Greenstone3Connection.java	(revision 375)
+++ /trunk/src/org/expeditee/greenstone/Greenstone3Connection.java	(revision 376)
@@ -17,5 +17,5 @@
 import java.util.Set;
 
-//import org.apache.xerces.parsers.DOMParser;
+import org.apache.xerces.parsers.DOMParser;
 import org.w3c.dom.Document;
 import org.w3c.dom.NamedNodeMap;
@@ -53,5 +53,5 @@
 	 * keys. All the results returned in this session.
 	 */
-	private Map allResults;
+	private Map<String, ResultDocument> allResults;
 
 	/**
@@ -156,5 +156,6 @@
 		}
 		this.queryList = Collections.synchronizedList(new ArrayList());
-		this.allResults = Collections.synchronizedMap(new HashMap());
+		this.allResults = Collections
+				.synchronizedMap(new HashMap<String, ResultDocument>());
 		this.allKeywords = Collections.synchronizedMap(new HashMap());
 		this.allAuthors = Collections.synchronizedMap(new HashMap());
@@ -164,5 +165,5 @@
 	}
 
-	public Map getSessionResults() {
+	public Map<String, ResultDocument> getSessionResults() {
 		return this.allResults;
 	};
@@ -270,6 +271,5 @@
 		while (iter.hasNext()) {
 			String docID = (String) iter.next();
-			ResultDocument resultDocument = (ResultDocument) allResults
-					.get(docID);
+			ResultDocument resultDocument = allResults.get(docID);
 			System.out.println("____________" + docID + " ___________");
 			System.out.println(resultDocument.toString());
@@ -286,6 +286,5 @@
 		while (iter.hasNext()) {
 			String docID = (String) iter.next();
-			ResultDocument resultDocument = (ResultDocument) allResults
-					.get(docID);
+			ResultDocument resultDocument = allResults.get(docID);
 			System.out.println(docID + "\t" + resultDocument.getTitle());
 		}
@@ -305,5 +304,5 @@
 	 */
 	public ResultDocument getDocument(String docID) {
-		return (ResultDocument) allResults.get(docID);
+		return allResults.get(docID);
 	}
 
@@ -425,76 +424,63 @@
 		StringReader sr = new StringReader(result);
 		InputSource is = new InputSource(sr);
-		
-		
-		
-		
-		
-		
-		
-		
-		
-		
-		return null;
-		
-//		DOMParser p = new DOMParser();
-//
-//		try {
-//			p.parse(is);
-//		} catch (SAXException se) {
-//			System.err.println(se);
-//		} catch (IOException ioe) {
-//			System.err.println(ioe);
-//		}
-//		Document d = p.getDocument();
-//		NodeList metadataList = d.getElementsByTagName("metadata");
-//		for (int i = 0; i < metadataList.getLength(); i++) {
-//			Node n = metadataList.item(i);
-//			NamedNodeMap nnm = n.getAttributes();
-//			Node att = nnm.getNamedItem("name");
-//			if (att.getNodeValue().compareTo("numDocsMatched") == 0) {
-//				queryOutcome.setHowManyDocsMatched(n.getFirstChild()
-//						.getNodeValue());
-//			} else if (att.getNodeValue().compareTo("numDocsReturned") == 0) {
-//				queryOutcome.setHowManyDocsReturned(n.getFirstChild()
-//						.getNodeValue());
-//			}
-//		}
-//
-//		NodeList documentList = d.getElementsByTagName("documentNode");
-//		for (int i = 0; i < documentList.getLength(); i++) {
-//			Node n = documentList.item(i);
-//			NamedNodeMap nnm = n.getAttributes();
-//			Node nid = nnm.getNamedItem("nodeID");
-//			Node nscore = nnm.getNamedItem("rank");
-//			String docID = nid.getFirstChild().getNodeValue();
-//			queryOutcome.addResult(docID, firstDoc + i, nscore.getFirstChild()
-//					.getNodeValue());
-//		}
-//		query.addQueryOutcome(queryOutcome);
-//		Query q = (Query) query.clone();
-//		queryList.add(q);
-//
-//		for (int i = 0; i < documentList.getLength(); i++) {
-//			Node n = documentList.item(i);
-//			NamedNodeMap nnm = n.getAttributes();
-//			Node nid = nnm.getNamedItem("nodeID");
-//			Node nscore = nnm.getNamedItem("rank");
-//			String docID = nid.getFirstChild().getNodeValue();
-//
-//			QueryContext queryContext = new QueryContext(firstDoc + i, nscore
-//					.getFirstChild().getNodeValue(), q);
-//			if (allResults.containsKey(docID)) {
-//				ResultDocument resultDocument = (ResultDocument) allResults
-//						.get(docID);
-//				resultDocument.incrementFrequencyReturned();
-//				resultDocument.addQueryContext(queryContext);
-//				allResults.put(docID, resultDocument);
-//			} else {
-//				ResultDocument resultDocument = new ResultDocument();
-//				resultDocument.addQueryContext(queryContext);
-//				allResults.put(docID, resultDocument);
-//			}
-//		}
-//		return queryOutcome;
+
+		DOMParser p = new DOMParser();
+		try {
+			p.parse(is);
+		} catch (SAXException se) {
+			System.err.println(se);
+		} catch (IOException ioe) {
+			System.err.println(ioe);
+		}
+		Document d = p.getDocument();
+		NodeList metadataList = d.getElementsByTagName("metadata");
+		for (int i = 0; i < metadataList.getLength(); i++) {
+			Node n = metadataList.item(i);
+			NamedNodeMap nnm = n.getAttributes();
+			Node att = nnm.getNamedItem("name");
+			if (att.getNodeValue().compareTo("numDocsMatched") == 0) {
+				queryOutcome.setHowManyDocsMatched(n.getFirstChild()
+						.getNodeValue());
+			} else if (att.getNodeValue().compareTo("numDocsReturned") == 0) {
+				queryOutcome.setHowManyDocsReturned(n.getFirstChild()
+						.getNodeValue());
+			}
+		}
+
+		NodeList documentList = d.getElementsByTagName("documentNode");
+		for (int i = 0; i < documentList.getLength(); i++) {
+			Node n = documentList.item(i);
+			NamedNodeMap nnm = n.getAttributes();
+			Node nid = nnm.getNamedItem("nodeID");
+			Node nscore = nnm.getNamedItem("rank");
+			String docID = nid.getFirstChild().getNodeValue();
+			queryOutcome.addResult(docID, firstDoc + i, nscore.getFirstChild()
+					.getNodeValue());
+		}
+		query.addQueryOutcome(queryOutcome);
+		Query q = (Query) query.clone();
+		queryList.add(q);
+
+		for (int i = 0; i < documentList.getLength(); i++) {
+			Node n = documentList.item(i);
+			NamedNodeMap nnm = n.getAttributes();
+			Node nid = nnm.getNamedItem("nodeID");
+			Node nscore = nnm.getNamedItem("rank");
+			String docID = nid.getFirstChild().getNodeValue();
+
+			QueryContext queryContext = new QueryContext(firstDoc + i, nscore
+					.getFirstChild().getNodeValue(), q);
+			if (allResults.containsKey(docID)) {
+				ResultDocument resultDocument = allResults.get(docID);
+				resultDocument.incrementFrequencyReturned();
+				resultDocument.addQueryContext(queryContext);
+				allResults.put(docID, resultDocument);
+			} else {
+				ResultDocument resultDocument = new ResultDocument();
+				resultDocument.addQueryContext(queryContext);
+				allResults.put(docID, resultDocument);
+			}
+		}
+		return queryOutcome;
 	}
 
@@ -545,5 +531,5 @@
 	 */
 	public void getDocumentMetadataFromServer(String docID, String metadata) {
-		ResultDocument resultDocument = (ResultDocument) allResults.get(docID);
+		ResultDocument resultDocument = allResults.get(docID);
 		if (resultDocument.metadataExists(metadata)) {
 			return;
@@ -566,14 +552,13 @@
 		StringReader sr = new StringReader(result);
 		InputSource is = new InputSource(sr);
-		//DOMParser p = new DOMParser();
-	/*	try {
-			//p.parse(is);
+		DOMParser p = new DOMParser();
+		try {
+			p.parse(is);
 		} catch (SAXException se) {
 			System.err.println(se);
 		} catch (IOException ioe) {
 			System.err.println(ioe);
-		}*/
-		//Document d = p.getDocument();
-		Document d = null;
+		}
+		Document d = p.getDocument();
 		NodeList metadataList = d.getElementsByTagName("metadata");
 		String metadataval = null;
@@ -609,5 +594,5 @@
 					String s = authors[i] + ", " + authors[i + 1];
 
-					//Handle names with jr. in them
+					// Handle names with jr. in them
 					if (containsExtraName) {
 						if (i + 2 < authors.length
@@ -703,17 +688,17 @@
 		StringReader sr = new StringReader(result);
 		InputSource is = new InputSource(sr);
-//		DOMParser p = new DOMParser();
-//		try {
-//			p.parse(is);
-//		} catch (SAXException se) {
-//			System.err.println(se);
-//		} catch (IOException ioe) {
-//			System.err.println(ioe);
-//		}
+		DOMParser p = new DOMParser();
+		try {
+			p.parse(is);
+		} catch (SAXException se) {
+			System.err.println(se);
+		} catch (IOException ioe) {
+			System.err.println(ioe);
+		}
 
 		String returnName = null;
 
-		//Document d = p.getDocument();
-		Document d = null;
+		Document d = p.getDocument();
+		// Document d = null;
 		NodeList metadataList = d.getElementsByTagName("metadata");
 		for (int i = 0; i < metadataList.getLength(); i++) {
@@ -750,14 +735,14 @@
 		StringReader sr = new StringReader(result);
 		InputSource is = new InputSource(sr);
-//		DOMParser p = new DOMParser();
-//		try {
-//			p.parse(is);
-//		} catch (SAXException se) {
-//			System.err.println(se);
-//		} catch (IOException ioe) {
-//			System.err.println(ioe);
-//		}
-//		Document d = p.getDocument();
-		Document d = null;
+		DOMParser p = new DOMParser();
+		try {
+			p.parse(is);
+		} catch (SAXException se) {
+			System.err.println(se);
+		} catch (IOException ioe) {
+			System.err.println(ioe);
+		}
+		Document d = p.getDocument();
+
 		NodeList childList = d.getElementsByTagName("classifierNode");
 		NodeList documentList = d.getElementsByTagName("documentNode");
Index: /trunk/src/org/expeditee/greenstone/ResultDocument.java
===================================================================
--- /trunk/src/org/expeditee/greenstone/ResultDocument.java	(revision 375)
+++ /trunk/src/org/expeditee/greenstone/ResultDocument.java	(revision 376)
@@ -35,4 +35,6 @@
 
 	private Set<String> retrievedMetadata;
+
+	private double sessionScore;
 
 	public ResultDocument() {
@@ -50,4 +52,5 @@
 		publisher = null;
 		frequencyReturned = 1;
+		sessionScore = 0;
 		queryContexts = new Vector<QueryContext>();
 		retrievedMetadata = new HashSet<String>();
@@ -158,4 +161,11 @@
 		this.retrievedMetadata.add("Publisher");
 	}
+	
+	public double getSessionScore() {
+		return this.sessionScore;
+	}
+	public void setSessionScore(double s) {
+		this.sessionScore  = s;
+	}
 
 	public void incrementFrequencyReturned() {
@@ -165,4 +175,6 @@
 	public void addQueryContext(QueryContext queryContext) {
 		this.queryContexts.addElement(queryContext);
+		if (this.frequencyReturned == 1)
+			this.sessionScore = Double.parseDouble(queryContext.getScore());
 	}
 
@@ -170,8 +182,16 @@
 		return authors;
 	}
+	
+	public Vector<String> getAuthor() {
+		return getAuthors();
+	}
 
 	public Vector<String> getKeywords() {
 		return keywords;
 	}
+	
+	public Vector<String> getKeyword() {
+		return getKeywords();
+	}
 
 	public String getTitle() {
@@ -218,6 +238,6 @@
 		return frequencyReturned;
 	}
-
-	public Vector getQueryContexts() {
+	
+	public Vector<QueryContext> getQueryContexts() {
 		return this.queryContexts;
 	}
Index: /trunk/src/org/expeditee/gui/AttributeUtils.java
===================================================================
--- /trunk/src/org/expeditee/gui/AttributeUtils.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/AttributeUtils.java	(revision 376)
@@ -171,4 +171,5 @@
 
 			_SetMethods.put("p", Item.class.getMethod("setPosition", pPoint));
+			_SetMethods.put("xy", Item.class.getMethod("setPosition", pPoint));
 			_SetMethods.put("pos", Item.class.getMethod("setPosition", pPoint));
 			_SetMethods.put("thickness", Item.class.getMethod("setThickness",
@@ -209,6 +210,6 @@
 					"setGradientColor", pColor));
 
-			_SetMethods.put("ga", Item.class.getMethod("setGradientAngle",
-					pInt));
+			_SetMethods.put("ga", Item.class
+					.getMethod("setGradientAngle", pInt));
 			_SetMethods.put("gradientangle", Item.class.getMethod(
 					"setGradientAngle", pInt));
@@ -272,4 +273,6 @@
 			_SetMethods.put("s", Item.class.getMethod("setSize", pFloat));
 
+			// TODO have a separate map for item and frame methods.
+			// This will remove the need for p0 etc
 			_SetMethods.put("foregroundcolor", Frame.class.getMethod(
 					"setForegroundColor", pColor));
@@ -282,4 +285,6 @@
 			_SetMethods.put("permission", Frame.class.getMethod(
 					"setPermission", pPermission));
+			_SetMethods.put("p0", Frame.class.getMethod("setPermission",
+					pPermission));
 
 		} catch (SecurityException e) {
@@ -321,99 +326,12 @@
 			if (m.getDeclaringClass().isAssignableFrom(toExtract.getClass())) {
 				try {
-					Object o = m.invoke(toExtract, (Object[]) null);
-
-					if (o == null) {
-						// methods that return null are only included if they
-						// are in the AllowNull list
-						if (_AllowNull.contains(m)) {
-							String name = m.getName().substring(GET_LENGTH)
-									.toLowerCase();
-							if (name.equals("color"))
-								o = "default";
-							else if (name.equals("backgroundcolor"))
-								o = "transparent";
-							else if (name.equals("foregroundcolor"))
-								o = "auto";
-							else
-								o = "";
-						} else {
-							continue;
-						}
-					}
-					// skip methods that are in the ignore lists
-					if (_ExtractIgnore.contains(m.getName().substring(
-							GET_LENGTH).toLowerCase())) {
+					String s = getValue(m, toExtract, true);
+
+					if (s == null)
 						continue;
-					}
-
-					if (o instanceof Integer) {
-						Integer i = (Integer) o;
-						if (i == Item.DEFAULT_INTEGER)
-							continue;
-						if (m.getName().endsWith("Justification")
-								&& ((Justification) o).toString() != null)
-							o = ((Justification) o).toString();
-						// -1 indicates default value
-						else
-							o = i;
-					} else if (o instanceof Float) {
-						if (((Float) o) < -0.0001)
-							continue;
-						// Null indicates default
-						o = Math.round((Float) o);
-					} else if (o instanceof Double) {
-						// -1 indicates default value
-						if (((Double) o) < 0.0001)
-							continue;
-					} else if (o instanceof Color) {
-						// converts the color to the Expeditee code
-						o = Conversion.getExpediteeColorCode((Color) o);
-						if (o == null)
-							continue;
-					} else if (o instanceof Point) {
-						Point p = (Point) o;
-						o = Math.round(p.getX()) + " " + Math.round(p.getY());
-					} else if (o instanceof Font) {
-						Font f = (Font) o;
-
-						String s = f.getName() + "-";
-						if (f.isPlain())
-							s += "Plain";
-
-						if (f.isBold())
-							s += "Bold";
-
-						if (f.isItalic())
-							s += "Italic";
-
-						s += "-" + f.getSize();
-						o = s;
-					} else if (o instanceof Text) {
-						o = ((Text) o).getFirstLine();
-					} else if (o instanceof List) {
-						List list = (List) o;
-						for (Object ob : list)
-							attributes
-									.append(m.getName().substring(GET_LENGTH))
-									.append(AttributeValuePair.SEPARATOR_STRING)
-									.append(ob).append('\n');
-						continue;
-					} else if (o instanceof int[]) {
-						StringBuffer sb = new StringBuffer();
-						int[] values = (int[]) o;
-						for (int i = 0; i < values.length; i++) {
-							sb.append(values[i]).append(' ');
-						}
-						sb.deleteCharAt(sb.length() - 1);
-						o = sb.toString();
-					} else if (o instanceof Boolean) {
-						// true is the default for boolean values
-						if (((Boolean) o).booleanValue())
-							continue;
-					}
 					// Append the attributes
 					attributes.append(m.getName().substring(GET_LENGTH))
 							.append(AttributeValuePair.SEPARATOR_STRING)
-							.append(o).append('\n');
+							.append(s).append('\n');
 				} catch (Exception e) {
 					// TODO Auto-generated catch block
@@ -434,4 +352,126 @@
 		Item attribs = current.getStatsTextItem(attributes.toString());
 		return attribs;
+	}
+
+	/**
+	 * Gets a string form of the value for a given item get method.
+	 * @param method
+	 * @param item
+	 * @param ignore true if the attributes in the IGNORE list should be ignored
+	 * @return
+	 */
+	private static String getValue(Method method, Object item, boolean ignore) {
+		assert(method.getName().startsWith("get"));
+		
+		Object o = null;
+		try {
+			o = method.invoke(item, (Object[]) null);
+		} catch (IllegalArgumentException e) {
+			e.printStackTrace();
+			return null;
+		} catch (IllegalAccessException e) {
+			e.printStackTrace();
+			return null;
+		} catch (InvocationTargetException e) {
+			e.printStackTrace();
+			return null;
+		}
+
+		if (o == null) {
+			// methods that return null are only included if they
+			// are in the AllowNull list
+			if (_AllowNull.contains(method)) {
+				String name = method.getName().substring(GET_LENGTH)
+						.toLowerCase();
+				if (name.equals("color"))
+					o = "default";
+				else if (name.equals("backgroundcolor"))
+					o = "transparent";
+				else if (name.equals("foregroundcolor"))
+					o = "auto";
+				else
+					o = "";
+			} else {
+				return null;
+			}
+		}
+		// skip methods that are in the ignore lists
+		if (ignore
+				&& _ExtractIgnore.contains(method.getName().substring(
+						GET_LENGTH).toLowerCase())) {
+			return null;
+		}
+
+		if (o instanceof Integer) {
+			Integer i = (Integer) o;
+			if (i == Item.DEFAULT_INTEGER)
+				return null;
+			if (method.getName().endsWith("Justification")
+					&& ((Justification) o).toString() != null)
+				o = ((Justification) o).toString();
+			// -1 indicates default value
+			else
+				o = i;
+		} else if (o instanceof Float) {
+			if (((Float) o) < -0.0001)
+				return null;
+			// Null indicates default
+			o = Math.round((Float) o);
+		} else if (o instanceof Double) {
+			// -1 indicates default value
+			if (((Double) o) < 0.0001)
+				return null;
+		} else if (o instanceof Color) {
+			// converts the color to the Expeditee code
+			o = Conversion.getExpediteeColorCode((Color) o);
+			if (o == null)
+				return null;
+		} else if (o instanceof Point) {
+			Point p = (Point) o;
+			o = Math.round(p.getX()) + " " + Math.round(p.getY());
+		} else if (o instanceof Font) {
+			Font f = (Font) o;
+
+			String s = f.getName() + "-";
+			if (f.isPlain())
+				s += "Plain";
+
+			if (f.isBold())
+				s += "Bold";
+
+			if (f.isItalic())
+				s += "Italic";
+
+			s += "-" + f.getSize();
+			o = s;
+		} else if (o instanceof Text) {
+			o = ((Text) o).getFirstLine();
+		} else if (o instanceof List) {
+			List list = (List) o;
+			StringBuffer sb = new StringBuffer();
+			for (Object ob : list)
+				// TODO check that this works ok
+				if (sb.length() == 0) {
+					sb.append(ob);
+				} else {
+					sb.append('\n').append(
+							method.getName().substring(GET_LENGTH)).append(
+							AttributeValuePair.SEPARATOR_STRING).append(ob);
+				}
+			return sb.toString();
+		} else if (o instanceof int[]) {
+			StringBuffer sb = new StringBuffer();
+			int[] values = (int[]) o;
+			for (int i = 0; i < values.length; i++) {
+				sb.append(values[i]).append(' ');
+			}
+			sb.deleteCharAt(sb.length() - 1);
+			o = sb.toString();
+		} else if (o instanceof Boolean) {
+			// true is the default for boolean values
+			if (((Boolean) o).booleanValue())
+				return null;
+		}
+		return o.toString();
 	}
 
@@ -653,3 +693,29 @@
 		text.setText(avp.toString());
 	}
+
+	public static String getAttribute(Item item, String attribute) {
+
+		// ensure the lists are populated
+		if (_Ignore == null)
+			initLists();
+
+		// separate attribute and value from string
+		String lowerAttribute = attribute.trim().toLowerCase();
+
+		String methodName = "get"
+				+ Character.toUpperCase(lowerAttribute.charAt(0))
+				+ lowerAttribute.substring(1);
+
+		try {
+			return attribute + ": " + getValue(item.getClass().getMethod(methodName,
+					new Class[] {}), item, false);
+		} catch (SecurityException e) {
+			e.printStackTrace();
+		} catch (NoSuchMethodException e) {
+			MessageBay
+					.errorMessage("Could no extract unknown attribute value: "
+							+ attribute);
+		}
+		return null;
+	}
 }
Index: /trunk/src/org/expeditee/gui/AttributeValuePair.java
===================================================================
--- /trunk/src/org/expeditee/gui/AttributeValuePair.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/AttributeValuePair.java	(revision 376)
@@ -54,5 +54,6 @@
 		if (text.charAt(0) == ANNOTATION_CHAR) {
 			_bAnnotation = true;
-			if (text.length() == 1 || !Character.isLetterOrDigit(text.charAt(1)))
+			if (text.length() == 1
+					|| !Character.isLetterOrDigit(text.charAt(1)))
 				return;
 			// All chars in the attribute must be letters or digits
@@ -98,4 +99,9 @@
 	public Double getDoubleValue() throws NumberFormatException {
 		assert (_value != null);
+		// Can be null if the text for the AVP was empty
+		if (_value == null) {
+			return Double.NaN;
+		}
+
 		return _value.doubleValue();
 	}
@@ -103,5 +109,4 @@
 	public Double getDoubleAttribute() throws NumberFormatException {
 		assert (_attribute != null);
-
 		return _attribute.doubleValue();
 	}
@@ -186,3 +191,7 @@
 	}
 
+	public boolean hasAttributeOrValue() {
+		return _attribute != null || _value != null;
+	}
+
 }
Index: /trunk/src/org/expeditee/gui/Browser.java
===================================================================
--- /trunk/src/org/expeditee/gui/Browser.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/Browser.java	(revision 376)
@@ -16,4 +16,5 @@
 import java.io.File;
 import java.util.Collection;
+import java.util.LinkedList;
 
 import javax.swing.JFrame;
@@ -163,9 +164,7 @@
 		Frame defaultProfile = loadProfile(UserSettings.DEFAULT_PROFILE_NAME);
 
-		Collection<String> warningMessages = FrameUtils
-				.ParseProfile(defaultProfile);
-
+		Collection<String> warningMessages = new LinkedList<String>();
+		warningMessages.addAll(FrameUtils.ParseProfile(defaultProfile));
 		warningMessages.addAll(FrameUtils.ParseProfile(profile));
-
 		// set the layout to absolute layout for widgets
 		this.getContentPane().setLayout(new AbsoluteLayout());
@@ -239,5 +238,6 @@
 				MessageBay.warningMessage(message);
 
-			this.getContentPane().addKeyListener(FrameKeyboardActions.getInstance());
+			this.getContentPane().addKeyListener(
+					FrameKeyboardActions.getInstance());
 			this.addKeyListener(FrameKeyboardActions.getInstance());
 
Index: /trunk/src/org/expeditee/gui/DisplayIO.java
===================================================================
--- /trunk/src/org/expeditee/gui/DisplayIO.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/DisplayIO.java	(revision 376)
@@ -72,5 +72,5 @@
 	 * The title to display in the Title bar.
 	 */
-	public static final String TITLE = "Exp09Oct2008A";
+	public static final String TITLE = "Exp31Oct2008A";
 
 	private DisplayIO() {
@@ -142,13 +142,16 @@
 
 	public static void setTextCursor(Text text, int cursorMovement) {
-		setTextCursor(text, cursorMovement, false, false);
+		setTextCursor(text, cursorMovement, false, false, false, false);
 	}
 
 	public static void setTextCursor(Text text, int cursorMovement,
-			boolean newSize, boolean isShiftDown) {
+			boolean newSize, boolean isShiftDown, boolean isCtrlDown, boolean allowClearSelection) {
 
 		int size = Math.round(text.getSize());
+		if(allowClearSelection && !isShiftDown && text.hasSelection())
+			text.clearSelection();
+		
 		Point2D.Float newMouse = text.moveCursor(cursorMovement, DisplayIO
-				.getFloatMouseX(), FrameMouseActions.MouseY, isShiftDown);
+				.getFloatMouseX(), FrameMouseActions.MouseY, isShiftDown, isCtrlDown);
 
 		if (!newSize && cursorType == Item.TEXT_CURSOR) {
@@ -187,5 +190,5 @@
 
 		for (int i = start; i < cursorSize; i++)
-			pixels[i * cursorSize] = pixels[(i * cursorSize) + 1] = 0xFF000000;
+			pixels[i * cursorSize] = pixels[i * cursorSize + 1] = 0xFF000000;
 
 		Image image = Toolkit.getDefaultToolkit().createImage(
@@ -846,5 +849,5 @@
 	 */
 	public static void MoveCursorToEndOfItem(Item i) {
-		setTextCursor((Text) i, Text.END, true, false);
+		setTextCursor((Text) i, Text.END, true, false, false, false);
 	}
 
Index: /trunk/src/org/expeditee/gui/Frame.java
===================================================================
--- /trunk/src/org/expeditee/gui/Frame.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/Frame.java	(revision 376)
@@ -204,7 +204,7 @@
 		boolean oldValue = _change;
 
-		if (value) {
-			notifyObservers();
-		}
+		// if (value) {
+		// notifyObservers();
+		// }
 
 		if (oldValue == value)
@@ -219,8 +219,31 @@
 	}
 
-	public void notifyObservers() {
+	//private static int updateCount = 0;
+
+	/**
+	 * Notify items observing the data on this frame that the frame content has
+	 * changed.
+	 * 
+	 * @param recalculate
+	 *            true if the frame should be recalculated first.
+	 */
+	public void notifyObservers(boolean bRecalculate) {
+		if(bRecalculate){
+			recalculate();
+		}
 		// Notify the frame listeners that the frame has changed
-		for (FrameObserver fl : _observers) {
-			fl.update();
+		/*
+		 * Avoid ConcurrentMod Exceptions when user anchors an item onto this
+		 * frame which is observing this frame, by NOT using foreach loop.
+		 * Calling update on a dataFrameWidget resets its subjects hence
+		 * changing this frames observer list.
+		 */
+		Collection<FrameObserver> observersCopy = new LinkedList<FrameObserver>(
+				_observers);
+		//System.out.println(++updateCount + " update");
+
+		for (FrameObserver fl : observersCopy) {
+			if (/* !Item.isLocked(fl) && */fl.isVisible())
+				fl.update();
 		}
 	}
@@ -370,4 +393,9 @@
 			if (UserSettings.TitleTemplate == null) {
 				frameTitle = new Text(getNextItemID(), title);
+				/*
+				 * Need to set the parent otherwise an exception is thrown when
+				 * new profile is created
+				 */
+				frameTitle.setParent(this);
 				frameTitle.resetTitlePosition();
 			} else {
@@ -721,6 +749,7 @@
 		item.onParentStateChanged(new ItemParentStateChangedEvent(this,
 				ItemParentStateChangedEvent.EVENT_TYPE_ADDED));
-		if (recalculate && item.recalculateWhenChanged())
-			recalculate();
+
+		// if (recalculate && item.recalculateWhenChanged())
+		// recalculate();
 
 		change();
@@ -799,6 +828,6 @@
 			}
 			// TODO Improve efficiency when removeAll is called
-			if (recalculate && item.recalculateWhenChanged())
-				recalculate();
+			// if (recalculate && item.recalculateWhenChanged())
+			// recalculate();
 		}
 	}
@@ -834,4 +863,5 @@
 		Item undo = null;
 		boolean bReparse = false;
+		boolean bRecalculate = false;
 
 		if (_undo.size() <= 0)
@@ -871,4 +901,5 @@
 			for (Item i : toRestore) {
 				bReparse |= i.hasOverlay();
+				bRecalculate |= i.recalculateWhenChanged();
 				if (i instanceof Line) {
 					Line line = (Line) i;
@@ -885,4 +916,7 @@
 		if (bReparse)
 			FrameUtils.Parse(this, false);
+		else {
+			notifyObservers(bRecalculate);
+		}
 		FrameGraphics.Repaint();
 		ItemUtils.EnclosedCheck(_body);
@@ -1455,14 +1489,14 @@
 		// t.setMaxWidth(FrameGraphics.getMaxFrameSize().width);
 		// if (t.getWidth() <= 0) {
-//		String maxWidthString = getAnnotationValue("maxwidth");
-//		int width = FrameGraphics.getMaxFrameSize().width;
-//		if (maxWidthString != null) {
-//			try {
-//				width = Math.min(width, Integer.parseInt(maxWidthString));
-//			} catch (NumberFormatException nfe) {
-//			}
-//		}
-//
-//		t.setRightMargin(width);
+		// String maxWidthString = getAnnotationValue("maxwidth");
+		// int width = FrameGraphics.getMaxFrameSize().width;
+		// if (maxWidthString != null) {
+		// try {
+		// width = Math.min(width, Integer.parseInt(maxWidthString));
+		// } catch (NumberFormatException nfe) {
+		// }
+		// }
+		//
+		// t.setRightMargin(width);
 		// }
 		addItem(t);
@@ -2023,4 +2057,5 @@
 
 	public void recalculate() {
+
 		for (Item i : getItems()) {
 			if (i.hasFormula() && !i.isAnnotation()) {
@@ -2118,3 +2153,7 @@
 		}
 	}
+
+	public boolean hasObservers() {
+		return _observers != null && _observers.size() > 0;
+	}
 }
Index: /trunk/src/org/expeditee/gui/FrameGraphics.java
===================================================================
--- /trunk/src/org/expeditee/gui/FrameGraphics.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/FrameGraphics.java	(revision 376)
@@ -351,7 +351,11 @@
 		}
 
+		// if(isActual)
 		bg.setColor(backgroundColor);
-		// bg.setColor(Color.pink); // TODO: TEMP FOR DEBUGGING
-
+		if (isActualFrame){
+			//bg.setColor(Color.white); // TODO: TEMP FOR DEBUGGING
+			
+			//System.out.println("paintPic");
+		}
 		bg.fillRect(0, 0, _MaxSize.width, _MaxSize.height);
 
@@ -514,42 +518,42 @@
 	// creates a new line so that lines are shown correctly when spanning
 	// across frames in TwinFrames mode
-	private static Line TransposeLine(Line line, Item d, Frame toPaint,
-			int base, int adj) {
-		Line nl = null;
-
-		if (toPaint != DisplayIO.getCurrentFrame() && d.getParent() == null
-				&& line.getOppositeEnd(d).getParent() == toPaint) {
-			nl = line.copy();
-			if (d == line.getStartItem())
-				d = nl.getStartItem();
-			else
-				d = nl.getEndItem();
-
-			if (DisplayIO.FrameOnSide(toPaint) == 0)
-				d.setX(base);
-			else
-				d.setX(base + adj);
-
-		} else if (toPaint == DisplayIO.getCurrentFrame()
-				&& d.getParent() == null
-				&& line.getOppositeEnd(d).getParent() != toPaint) {
-			nl = line.copy();
-
-			if (d == line.getStartItem())
-				d = nl.getEndItem();
-			else
-				d = nl.getStartItem();
-
-			if (DisplayIO.FrameOnSide(toPaint) == 1)
-				d.setX(d.getX() - DisplayIO.getMiddle());
-			else
-				d.setX(d.getX() + DisplayIO.getMiddle());
-		}
-		if (nl != null) {
-			nl.invalidateAll();
-			FrameGraphics.requestRefresh(true);
-		}
-		return nl;
-	}
+	// private static Line TransposeLine(Line line, Item d, Frame toPaint,
+	// int base, int adj) {
+	// Line nl = null;
+	//
+	// if (toPaint != DisplayIO.getCurrentFrame() && d.getParent() == null
+	// && line.getOppositeEnd(d).getParent() == toPaint) {
+	// nl = line.copy();
+	// if (d == line.getStartItem())
+	// d = nl.getStartItem();
+	// else
+	// d = nl.getEndItem();
+	//
+	// if (DisplayIO.FrameOnSide(toPaint) == 0)
+	// d.setX(base);
+	// else
+	// d.setX(base + adj);
+	//
+	// } else if (toPaint == DisplayIO.getCurrentFrame()
+	// && d.getParent() == null
+	// && line.getOppositeEnd(d).getParent() != toPaint) {
+	// nl = line.copy();
+	//
+	// if (d == line.getStartItem())
+	// d = nl.getEndItem();
+	// else
+	// d = nl.getStartItem();
+	//
+	// if (DisplayIO.FrameOnSide(toPaint) == 1)
+	// d.setX(d.getX() - DisplayIO.getMiddle());
+	// else
+	// d.setX(d.getX() + DisplayIO.getMiddle());
+	// }
+	// if (nl != null) {
+	// nl.invalidateAll();
+	// FrameGraphics.requestRefresh(true);
+	// }
+	// return nl;
+	// }
 
 	private static void Paint(Graphics g, Image left, Image right,
@@ -658,5 +662,6 @@
 				if (done.contains(i))
 					continue;
-				else if (!isAudienceMode() || !i.isConnectedToAnnotation()) {
+				else if (!isAudienceMode() || 
+						!i.isConnectedToAnnotation()) {
 					toFill.add(i);
 				}
@@ -674,11 +679,11 @@
 					// System.out.println(a.getEnclosureID() + " " +
 					// b.getID());\
-					//Shapes to the left go underneath
+					// Shapes to the left go underneath
 					Polygon pA = a.getEnclosedShape();
 					Polygon pB = b.getEnclosedShape();
-					if(pA == null || pB == null)
+					if (pA == null || pB == null)
 						return 0;
-					return new Integer(pA.getBounds().x)
-							.compareTo(pB.getBounds().x);
+					return new Integer(pA.getBounds().x).compareTo(pB
+							.getBounds().x);
 				}
 				return cmp * -1;
Index: /trunk/src/org/expeditee/gui/FrameIO.java
===================================================================
--- /trunk/src/org/expeditee/gui/FrameIO.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/FrameIO.java	(revision 376)
@@ -771,4 +771,10 @@
 	}
 
+	/**
+	 * Saves a frame.
+	 * @param toSave the frame to save
+	 * @param inc true if the frames counter should be incremented
+	 * @return the text content of the frame
+	 */
 	public static String SaveFrame(Frame toSave, boolean inc) {
 		return SaveFrame(toSave, inc, true);
Index: /trunk/src/org/expeditee/gui/FrameKeyboardActions.java
===================================================================
--- /trunk/src/org/expeditee/gui/FrameKeyboardActions.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/FrameKeyboardActions.java	(revision 376)
@@ -57,4 +57,5 @@
 
 	public synchronized void keyTyped(KeyEvent e) {
+
 		if (Simple.isProgramRunning()) {
 			if (e.isControlDown()
@@ -153,8 +154,11 @@
 		}
 
-		FrameUtils.setLastEdited(text);
-
 		// if the user is in free space, create a new text item
-		if (on == null || !on.isHighlighted()) {
+		/*
+		 * MikeSays: Why do we have to check is highlighted... doing so causes
+		 * problems if you type characters to fast, they turn into multiple text
+		 * items. ie. JK together on the Linux laptop.
+		 */
+		if (on == null /* || !on.isHighlighted() */) {
 			// DisplayIO.UpdateTitle();
 			text = createText(ch);
@@ -164,5 +168,9 @@
 			DisplayIO.setTextCursor(text, Text.NONE);
 			return;
-		}
+		} else {
+			FrameUtils.setLastEdited(text);
+		}
+
+		float oldY = FrameMouseActions.MouseY;
 
 		DisplayIO.setTextCursor(text, Text.NONE);
@@ -180,4 +188,30 @@
 					FrameMouseActions.MouseY);
 		}
+		/*
+		 * check if the user hit enter and the cursor is now on another text
+		 * item
+		 */
+		if (oldY < newMouse.y) {
+			//float diff = newMouse.y - oldY;
+			// System.out.print("c");
+			Rectangle rect = text.getPolygon().getBounds();
+			
+			//Text lastEdited = FrameUtils.getLastEdited();
+			//FrameUtils.setLastEdited(null);
+			
+			Item justBelow = FrameUtils.onItem(DisplayIO.getCurrentFrame(),
+					text.getX() + 10, rect.y + rect.height + 1, false);
+			
+			//FrameUtils.setLastEdited(lastEdited);
+			
+			//Dont drop unless 
+			if (justBelow != null && justBelow instanceof Text && justBelow != on) {
+				// Drop all the items below it down!
+				// Get the list of items that must be dropped
+				List<Text> column = DisplayIO.getCurrentFrame().getColumn(on);
+				FrameUtils.Align(column, false, 0);
+			}
+		}
+
 		DisplayIO.setCursorPosition(newMouse.x, newMouse.y, false);
 
@@ -303,5 +337,5 @@
 	}
 
-	private void move(int direction, boolean isShiftDown) {
+	private void move(int direction, boolean isShiftDown, boolean isCtrlDown) {
 		Item on = FrameUtils.getCurrentItem();
 
@@ -320,7 +354,6 @@
 			} else {
 				FrameUtils.setLastEdited(text);
-				if (!isShiftDown)
-					text.clearSelection();
-				DisplayIO.setTextCursor(text, direction, false, isShiftDown);
+				DisplayIO.setTextCursor(text, direction, false, isShiftDown,
+						isCtrlDown, true);
 			}
 		}
@@ -426,8 +459,8 @@
 			break;
 		case KeyEvent.VK_LEFT:
-			move(Text.LEFT, e.isShiftDown());
+			move(Text.LEFT, e.isShiftDown(), e.isControlDown());
 			break;
 		case KeyEvent.VK_RIGHT:
-			move(Text.RIGHT, e.isShiftDown());
+			move(Text.RIGHT, e.isShiftDown(), e.isControlDown());
 			break;
 		case KeyEvent.VK_PAGE_DOWN:
@@ -441,5 +474,5 @@
 				NextTextItem(FrameUtils.getCurrentItem(), false);
 			} else {
-				move(Text.UP, e.isShiftDown());
+				move(Text.UP, e.isShiftDown(), e.isControlDown());
 			}
 			break;
@@ -448,18 +481,18 @@
 				NextTextItem(FrameUtils.getCurrentItem(), true);
 			} else {
-				move(Text.DOWN, e.isShiftDown());
+				move(Text.DOWN, e.isShiftDown(), e.isControlDown());
 			}
 			break;
 		case KeyEvent.VK_END:
 			if (e.isControlDown())
-				move(Text.END, e.isShiftDown());
+				move(Text.END, e.isShiftDown(), e.isControlDown());
 			else
-				move(Text.LINE_END, e.isShiftDown());
+				move(Text.LINE_END, e.isShiftDown(), e.isControlDown());
 			break;
 		case KeyEvent.VK_HOME:
 			if (e.isControlDown())
-				move(Text.HOME, e.isShiftDown());
+				move(Text.HOME, e.isShiftDown(), e.isControlDown());
 			else
-				move(Text.LINE_HOME, e.isShiftDown());
+				move(Text.LINE_HOME, e.isShiftDown(), e.isControlDown());
 			break;
 		// TODO remove this when upgrading Java
@@ -486,5 +519,5 @@
 		// Move the cursor to the next text item
 		Frame current = DisplayIO.getCurrentFrame();
-		Item title = current.getTitleItem();
+		Text title = current.getTitleItem();
 
 		Collection<Text> currentItems = FrameUtils.getCurrentTextItems();
@@ -494,5 +527,6 @@
 			textItems.addAll(currentItems);
 		} else {
-			textItems.add(current.getTitleItem());
+			if (title != null)
+				textItems.add(title);
 			textItems.addAll(current.getBodyTextItems(true));
 		}
@@ -504,5 +538,6 @@
 			if (title == null)
 				return;
-			DisplayIO.MoveCursorToEndOfItem(title);
+			if (title != null)
+				DisplayIO.MoveCursorToEndOfItem(title);
 			FrameGraphics.Repaint();
 			return;
@@ -634,5 +669,5 @@
 		// FrameMouseActions.pickup(t);
 		// } else {
-		// remove the link for alt+l
+		// remove the link for ctrl+l
 		Item current = FrameUtils.getCurrentItem();
 		Frame currentFrame = DisplayIO.getCurrentFrame();
@@ -641,5 +676,5 @@
 		case KeyEvent.VK_HOME:
 			if (current != null && current instanceof Text) {
-				move(Text.HOME, isShiftDown);
+				move(Text.HOME, isShiftDown, true);
 			} else {
 				while (DisplayIO.Back())
@@ -649,5 +684,5 @@
 		case KeyEvent.VK_END:
 			if (current != null && current instanceof Text) {
-				move(Text.END, isShiftDown);
+				move(Text.END, isShiftDown, true);
 			} else {
 				while (DisplayIO.Forward())
@@ -682,22 +717,32 @@
 			break;
 		case KeyEvent.VK_LEFT:
-			DisplayIO.translateCursor(-distance, 0);
+			if (current instanceof Text) {
+				DisplayIO.setTextCursor((Text) current, Text.LEFT, false,
+						isShiftDown, true, true);
+			} else {
+				DisplayIO.translateCursor(-distance, 0);
+			}
 			break;
 		case KeyEvent.VK_RIGHT:
-			DisplayIO.translateCursor(distance, 0);
+			if (current instanceof Text) {
+				DisplayIO.setTextCursor((Text) current, Text.RIGHT, false,
+						isShiftDown, true, true);
+			} else {
+				DisplayIO.translateCursor(distance, 0);
+			}
 			break;
 		case KeyEvent.VK_UP:
-			if (current instanceof Text) {
-				NextTextItem(FrameUtils.getCurrentItem(), false);
-			} else {
-				DisplayIO.translateCursor(0, -distance);
-			}
+			// if (current instanceof Text) {
+			NextTextItem(FrameUtils.getCurrentItem(), false);
+			// } else {
+			// DisplayIO.translateCursor(0, -distance);
+			// }
 			break;
 		case KeyEvent.VK_DOWN:
-			if (current instanceof Text) {
-				NextTextItem(FrameUtils.getCurrentItem(), true);
-			} else {
-				DisplayIO.translateCursor(0, distance);
-			}
+			// if (current instanceof Text) {
+			NextTextItem(FrameUtils.getCurrentItem(), true);
+			// } else {
+			// DisplayIO.translateCursor(0, distance);
+			// }
 			break;
 		case KeyEvent.VK_L:
@@ -923,5 +968,5 @@
 			Text text = getCurrentTextItem();
 			if (text == null) {
-				for (Text t : FrameUtils.getCurrentTextItems()) {
+				for (Text t : currentFrame.getBodyTextItems(false)) {
 					justify(t);
 				}
@@ -1134,5 +1179,6 @@
 			SetSize(on, repeat, true, false);
 			if (on instanceof Text) {
-				DisplayIO.setTextCursor((Text) on, Text.NONE, true, false);
+				DisplayIO.setTextCursor((Text) on, Text.NONE, true, false,
+						false, true);
 			}
 			break;
@@ -1140,5 +1186,6 @@
 			SetSize(on, -repeat, true, false);
 			if (on instanceof Text) {
-				DisplayIO.setTextCursor((Text) on, Text.NONE, true, false);
+				DisplayIO.setTextCursor((Text) on, Text.NONE, true, false,
+						false, true);
 			}
 			break;
@@ -1181,4 +1228,7 @@
 
 	private static void calculateItem(Item toCalculate) {
+		if (toCalculate == null)
+			return;
+
 		if (!toCalculate.update()) {
 			toCalculate.setFormula(null);
@@ -1421,4 +1471,5 @@
 		if (firstItem == null) {
 			firstItem = null;
+			return;
 		}
 
@@ -2187,5 +2238,5 @@
 
 		// Refresh widgets that use its self as a data source
-		currentFrame.notifyObservers();
+		currentFrame.notifyObservers(true);
 
 		if (FrameIO.isProfileFrame(currentFrame)) {
Index: /trunk/src/org/expeditee/gui/FrameMouseActions.java
===================================================================
--- /trunk/src/org/expeditee/gui/FrameMouseActions.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/FrameMouseActions.java	(revision 376)
@@ -639,4 +639,5 @@
 	private void leftButton(Item clicked, Collection<Item> clickedIn,
 			boolean isShiftDown, boolean isControlDown) {
+
 		// if the user is pointing at something then either follow the link or
 		// do TDFC
@@ -698,7 +699,9 @@
 		if (clicked != null) {
 			// check item permissions
-			if ((clicked.hasLink() && !clicked
+			boolean hasLinkOrAction = clicked.hasLink() || clicked.hasAction();
+
+			if ((hasLinkOrAction && !clicked
 					.hasPermission(Permission.followLinks))
-					|| (!clicked.hasLink() && !clicked
+					|| (!hasLinkOrAction && !clicked
 							.hasPermission(Permission.createFrames))) {
 				Item editTarget = clicked.getEditTarget();
@@ -756,5 +759,5 @@
 					tdfc(clickedOn);
 				} catch (RuntimeException e) {
-					MessageBay.errorMessage(e.getMessage());
+					MessageBay.errorMessage("TDFC error: " + e.getMessage());
 				}
 				return;
@@ -997,5 +1000,5 @@
 		} else {
 			Item on = FrameUtils.onItem(DisplayIO.getCurrentFrame(), Math
-					.round(MouseX), Math.round(MouseY));
+					.round(MouseX), Math.round(MouseY), true);
 			// If we have permission to copy this item then pick it up
 			if (on != null && on.isLineEnd()
@@ -1344,5 +1347,5 @@
 				} else {
 					Item on = FrameUtils.onItem(DisplayIO.getCurrentFrame(),
-							MouseX, MouseY);
+							MouseX, MouseY, true);
 					// if its on a line then create a line from that line
 					if (on instanceof Line && on.hasPermission(Permission.full)) {
@@ -1510,5 +1513,5 @@
 			}
 
-			DisplayIO.setTextCursor(_lastRanged, Text.NONE);
+			DisplayIO.setTextCursor(_lastRanged, Text.NONE, false, e.isShiftDown(), e.isControlDown(), false);
 			FrameGraphics.Repaint();
 			return;
@@ -1544,5 +1547,5 @@
 				&& _lastClickedOn == null && _lastClickedIn == null) {
 			Item on = FrameUtils.onItem(DisplayIO.getCurrentFrame(), e.getX(),
-					e.getY());
+					e.getY(), true);
 
 			if (FreeItems.getInstance().size() == 0) {
@@ -2162,11 +2165,13 @@
 
 	public static void delete(Item toDelete) {
+		boolean bRecalculate = false;
+
 		FrameUtils.setLastEdited(null);
 		_offX = _offY = 0;
 
-		Frame current = DisplayIO.getCurrentFrame();
+		Frame currentFrame = DisplayIO.getCurrentFrame();
 		// check if the user is pointing at the frame's framename
-		if (toDelete != null && toDelete == current.getNameItem()) {
-			current.clear(false);
+		if (toDelete != null && toDelete == currentFrame.getNameItem()) {
+			currentFrame.clear(false);
 			FrameGraphics.Repaint();
 			return;
@@ -2190,5 +2195,6 @@
 				SessionStats.DeletedItem(free);
 				// List<String> temp = anchored.getText();
-				anchored.setTextList(free.getTextList());
+				anchored.setText(free.getText());
+				anchored.setFormula(free.getFormula());
 
 				// free.setTextList(temp);
@@ -2196,4 +2202,7 @@
 
 				anchored.getParent().setChanged(true);
+
+				bRecalculate |= free.recalculateWhenChanged();
+				bRecalculate |= anchored.recalculateWhenChanged();
 
 				// update the offset since the text has changed
@@ -2206,6 +2215,4 @@
 			// reset the mouse cursor
 			updateCursor();
-			FrameGraphics.Repaint();
-			return;
 			// the user is not pointing at an item
 		} else if (toDelete == null) {
@@ -2304,4 +2311,5 @@
 				toUndo = toDelete.getConnected();
 			} else {
+				bRecalculate |= toDelete.recalculateWhenChanged();
 				toUndo = toDelete.getConnected(); // copy(toDelete.getConnected());
 			}
@@ -2318,8 +2326,12 @@
 				FrameGraphics.requestRefresh(false);
 			}
-			FrameGraphics.Repaint();
-		}
-		// check
-		DisplayIO.setCursor(Item.DEFAULT_CURSOR);
+
+			DisplayIO.setCursor(Item.DEFAULT_CURSOR);
+
+		}
+
+		currentFrame.notifyObservers(bRecalculate);
+
+		FrameGraphics.Repaint();
 	}
 
@@ -2330,4 +2342,6 @@
 	public static void deleteItems(Collection<Item> itemList, boolean addToUndo) {
 		boolean bReparse = false;
+		boolean bRecalculate = false;
+
 		SessionStats.DeletedItems(itemList);
 		List<Frame> modifiedFrames = new LinkedList<Frame>();
@@ -2339,4 +2353,5 @@
 			i.setHighlightMode(HighlightMode.None);
 			bReparse |= i.hasOverlay();
+			bRecalculate |= i.recalculateWhenChanged();
 		}
 		// If they are all free items then add the current frame
@@ -2388,6 +2403,13 @@
 		currentFrame.addAllToUndo(itemList);
 		itemList.clear();
-		if (bReparse)
+		if (bReparse) {
 			FrameUtils.Parse(currentFrame, false, false);
+			/*
+			 * TODO check if I need to recalculate even if reparse occurs, here
+			 * and in anchor, pickup etc
+			 */
+		} else {
+			currentFrame.notifyObservers(bRecalculate);
+		}
 
 	}
@@ -2558,5 +2580,6 @@
 							if (merger.size() == 1 && txt.getLink() != null) {
 								// If the text item is linked then use that
-								((WidgetCorner)mergee).setLink(txt.getAbsoluteLink(), txt);
+								((WidgetCorner) mergee).setLink(txt
+										.getAbsoluteLink(), txt);
 							} else {
 								remain.addAll(merger);
@@ -2566,5 +2589,6 @@
 							if (merger.size() == 1 && txt.getLink() != null) {
 								// If the text item is linked then use that
-								((WidgetEdge)mergee).setLink(txt.getAbsoluteLink(), txt);
+								((WidgetEdge) mergee).setLink(txt
+										.getAbsoluteLink(), txt);
 							} else {
 								remain.addAll(merger);
@@ -2608,5 +2632,7 @@
 		}
 		updateCursor();
+
 		mergee.getParent().setChanged(true);
+
 		ItemUtils.EnclosedCheck(mergee.getParent().getItems());
 		// Mike: Why does parse frame have to be called?!?
@@ -2666,6 +2692,8 @@
 
 		boolean bReparse = false;
-		Frame frame = DisplayIO.getCurrentFrame();
-		String currentFrame = frame.getName();
+		boolean bRecalculate = false;
+
+		Frame currentFrame = DisplayIO.getCurrentFrame();
+		String currentFrameName = currentFrame.getName();
 		Iterator<Item> iter = toGrab.iterator();
 		while (iter.hasNext()) {
@@ -2677,4 +2705,6 @@
 			if (i.equals(_lastHighlightedItem))
 				_lastHighlightedItem = null;
+
+			bRecalculate |= i.recalculateWhenChanged();
 			// i.setSelectedMode(SelectedMode.None);
 			// Check if it has a relative link if so make it absolute
@@ -2683,5 +2713,5 @@
 			if (i.getParent() != null) {
 				i.getParent().removeItem(i);
-				if (currentFrame.equals(i.getParent().getName()))
+				if (currentFrameName.equals(i.getParent().getName()))
 					i.setParent(null);
 			}
@@ -2704,5 +2734,6 @@
 			}
 		}
-		frame.recalculate();
+		currentFrame.change();
+
 		_lastHighlightedItem = null;
 		updateCursor();
@@ -2744,5 +2775,7 @@
 		}
 		if (bReparse)
-			FrameUtils.Parse(DisplayIO.getCurrentFrame(), false, false);
+			FrameUtils.Parse(currentFrame, false, false);
+		else
+			currentFrame.notifyObservers(bRecalculate);
 
 		FrameGraphics.Repaint();
@@ -2805,4 +2838,5 @@
 	public static void anchor(Collection<Item> toAnchor) {
 		boolean bReparse = false;
+		boolean bRecalculate = false;
 		// Need to make sure we check enclosure for overlays etc
 		Set<Frame> checkEnclosure = new HashSet<Frame>();
@@ -2827,4 +2861,5 @@
 				checkEnclosure.add(i.getParentOrCurrentFrame());
 				bReparse |= i.hasOverlay();
+				bRecalculate |= i.recalculateWhenChanged();
 			}
 		}
@@ -2834,8 +2869,12 @@
 		for (Frame f : checkEnclosure) {
 			ItemUtils.EnclosedCheck(f.getItems());
-			f.recalculate();
-		}
+		}
+
+		Frame currentFrame = DisplayIO.getCurrentFrame();
 		if (bReparse)
-			FrameUtils.Parse(DisplayIO.getCurrentFrame(), false, false);
+			FrameUtils.Parse(currentFrame, false, false);
+		else {
+			currentFrame.notifyObservers(bRecalculate);
+		}
 		FrameGraphics.Repaint();
 	}
Index: /trunk/src/org/expeditee/gui/FrameObserver.java
===================================================================
--- /trunk/src/org/expeditee/gui/FrameObserver.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/FrameObserver.java	(revision 376)
@@ -5,3 +5,5 @@
 
 	public abstract void removeSubject(Frame frame);
+	
+	public abstract boolean isVisible();
 }
Index: /trunk/src/org/expeditee/gui/FrameUtils.java
===================================================================
--- /trunk/src/org/expeditee/gui/FrameUtils.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/FrameUtils.java	(revision 376)
@@ -240,18 +240,19 @@
 			}
 
-			if (above != curr.getNameItem() && above != curr.getTitleItem())
+			// Need to do things differently for FORMAT than for DROPPING
+			if (moveAll && above != curr.getNameItem()
+					&& above != curr.getTitleItem()) {
 				x = above.getX();
+				from.setY((int) above.getPolygon().getBounds().getMaxY()
+						+ space
+						+ ((int) (from.getY() - from.getPolygon().getBounds()
+								.getMinY())));
+				from.setX(x);
+			} else {
+				x = from.getX();
+			}
 
 			space += adjust;
-
-			from.setY((int) above.getPolygon().getBounds().getMaxY()
-					+ space
-					+ ((int) (from.getY() - from.getPolygon().getBounds()
-							.getMinY())));
-
-			if (moveAll)
-				from.setX(x);
-		}
-
+		}
 		for (int i = 1; i < toAlign.size(); i++) {
 			Item current = toAlign.get(i);
@@ -580,109 +581,119 @@
 		// check for all tags setting user values
 		for (Text item : profile.getBodyTextItems(false)) {
-
-			AttributeValuePair avp = new AttributeValuePair(item.getText());
-			String attributeFullCase = avp.getAttributeOrValue();
-
-			if (attributeFullCase == null)
-				continue;
-			String attribute = attributeFullCase.toLowerCase();
-
-			if (attribute.equals("homeframe")) {
-				String first = getLink(item, UserSettings.HomeFrame);
-				// do not use non-existant frames as the first frame
-				if (FrameIO.isValidFrameName(first)) {
-					UserSettings.HomeFrame = first;
-				}
-				// warn the user
-				else {
-					// MessageBay.warningMessage("Home frame: " + first
-					// + " is not a valid frame.");
-					UserSettings.HomeFrame = profile.getName();
-				}
-			} else if (attribute.equals("username")) {
-				UserSettings.UserName = avp.getValue();
-			} else if (attribute.equals("spellchecker")) {
-
-				try {
-					JSpellChecker.create();
-				} catch (FileNotFoundException e) {
-					MessageBay.errorMessage("Could not find dictionary: "
-							+ e.getMessage());
-				} catch (IOException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			} else if (attribute.equals("defaultframe"))
-				UserSettings.DefaultFrame = getLink(item,
-						UserSettings.DefaultFrame);
-			else if (attribute.equals("mailsettings"))
-				MailSession.init(item.getChild());
-			else if (attribute.equals("networksettings"))
-				FrameShare.init(item.getChild());
-			else if (attribute.equals("greenstonesettings")) {
-				SearchGreenstone.init(item.getChild());
-			} else if (attribute.equals("reminders"))
-				Reminders.init(item.getChild());
-			else if (attribute.equals("antialias"))
-				UserSettings.AntiAlias = avp.getBooleanValue();
-			else if (attribute.equals("gravity"))
-				UserSettings.Gravity = avp.getIntegerValue();
-			else if (attribute.equals("showlinehighlight"))
-				UserSettings.LineHighlight = avp.getBooleanValue();
-			else if (attribute.equals("linestraightenthreshold"))
-				UserSettings.LineStraightenThreshold = avp.getIntegerValue();
-			else if (attribute.equals("noopthreshold"))
-				UserSettings.NoOpThreshold = avp.getIntegerValue();
-			else if (attribute.equals("formatspacingmin")) {
-				FrameUtils.MINIMUM_SPACING_RATIO = avp.getDoubleValue();
-			} else if (attribute.equals("formatspacingmax")) {
-				FrameUtils.MAXIMUM_SPACING_RATIO = avp.getDoubleValue();
-			} else if (attribute.equals("initialwidth")) {
-				UserSettings.InitialWidth = avp.getIntegerValue();
-			} else if (attribute.equals("initialheight")) {
-				UserSettings.InitialHeight = avp.getIntegerValue();
-			} else if (attribute.equals("titleposition")) {
-				UserSettings.TitlePosition = avp.getIntegerValue();
-			} else if (attribute.equals("logging")) {
-				UserSettings.Logging = avp.getBooleanValue();
-			} else if (attribute.equals("itemtemplate")) {
-				UserSettings.ItemTemplate = ((Text) item).getTemplateForm();
-			} else if (attribute.equals("annotationtemplate")) {
-				UserSettings.AnnotationTemplate = ((Text) item)
-						.getTemplateForm();
-			} else if (attribute.equals("statstemplate")) {
-				UserSettings.StatTemplate = ((Text) item).getTemplateForm();
-			} else if (attribute.equals("commenttemplate")) {
-				UserSettings.CodeCommentTemplate = ((Text) item)
-						.getTemplateForm();
-			} else if (attribute.equals("dottemplate")) {
-				UserSettings.DotTemplate = ((Text) item).getTemplateForm();
-			} else if (attribute.equals("framesetdir")) {
-				String dir = getDir(avp.getValue());
-				if (dir != null) {
-					UserSettings.FrameDirs.add(dir);
-				}
-			} else if (attribute.equals("logdir")) {
-				org.expeditee.gui.FrameIO.LOGS_DIR = getDir(avp.getValue());
-			} else if (attribute.equals("imagedir")) {
-				String dir = getDir(avp.getValue());
-				if (dir != null)
-					UserSettings.ImageDirs.add(0, dir);
-			} else if (attribute.equals("threading")) {
-				UserSettings.Threading = avp.getBooleanValue();
-			} else if (attribute.equals("colorwheel")) {
-				Item.COLOR_WHEEL = getColorWheel(item);
-			} else if (attribute.equals("fillcolorwheel")) {
-				Item.FILL_COLOR_WHEEL = getColorWheel(item);
-			} else if (attribute.equals("backgroundcolorwheel")) {
-				Frame.COLOR_WHEEL = getColorWheel(item);
-			} else if (attribute.equals("framesetdirs")) {
-				UserSettings.FrameDirs.addAll(getDirs(item));
-			} else if (attribute.equals("imagedirs")) {
-				UserSettings.ImageDirs.addAll(getDirs(item));
-			} else if (attribute.equals("style")) {
-				UserSettings.Style = getStyle(item.getChild());
-			} else {
-				errors.add(attributeFullCase + " is not a profile frame tag");
+			try {
+
+				AttributeValuePair avp = new AttributeValuePair(item.getText());
+				String attributeFullCase = avp.getAttributeOrValue();
+
+				if (attributeFullCase == null)
+					continue;
+				String attribute = attributeFullCase.toLowerCase();
+
+				if (attribute.equals("homeframe")) {
+					String first = getLink(item, UserSettings.HomeFrame);
+					// do not use non-existant frames as the first frame
+					if (FrameIO.isValidFrameName(first)) {
+						UserSettings.HomeFrame = first;
+					}
+					// warn the user
+					else {
+						// MessageBay.warningMessage("Home frame: " + first
+						// + " is not a valid frame.");
+						UserSettings.HomeFrame = profile.getName();
+					}
+				} else if (attribute.equals("username")) {
+					UserSettings.UserName = avp.getValue();
+				} else if (attribute.equals("spellchecker")) {
+
+					try {
+						JSpellChecker.create();
+					} catch (FileNotFoundException e) {
+						MessageBay.errorMessage("Could not find dictionary: "
+								+ e.getMessage());
+					} catch (IOException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+				} else if (attribute.equals("defaultframe"))
+					UserSettings.DefaultFrame = getLink(item,
+							UserSettings.DefaultFrame);
+				else if (attribute.equals("mailsettings"))
+					MailSession.init(item.getChild());
+				else if (attribute.equals("networksettings"))
+					FrameShare.init(item.getChild());
+				else if (attribute.equals("spelling"))
+					JSpellChecker.create(item.getChild());
+				else if (attribute.equals("greenstonesettings")) {
+					SearchGreenstone.init(item.getChild());
+				} else if (attribute.equals("reminders"))
+					Reminders.init(item.getChild());
+				else if (attribute.equals("antialias"))
+					UserSettings.AntiAlias = avp.getBooleanValue();
+				else if (attribute.equals("gravity"))
+					UserSettings.Gravity = avp.getIntegerValue();
+				else if (attribute.equals("showlinehighlight"))
+					UserSettings.LineHighlight = avp.getBooleanValue();
+				else if (attribute.equals("linestraightenthreshold"))
+					UserSettings.LineStraightenThreshold = avp
+							.getIntegerValue();
+				else if (attribute.equals("noopthreshold"))
+					UserSettings.NoOpThreshold = avp.getIntegerValue();
+				else if (attribute.equals("formatspacingmin")) {
+					FrameUtils.MINIMUM_SPACING_RATIO = avp.getDoubleValue();
+				} else if (attribute.equals("formatspacingmax")) {
+					FrameUtils.MAXIMUM_SPACING_RATIO = avp.getDoubleValue();
+				} else if (attribute.equals("initialwidth")) {
+					UserSettings.InitialWidth = avp.getIntegerValue();
+				} else if (attribute.equals("initialheight")) {
+					UserSettings.InitialHeight = avp.getIntegerValue();
+				} else if (attribute.equals("titleposition")) {
+					UserSettings.TitlePosition = avp.getIntegerValue();
+				} else if (attribute.equals("logging")) {
+					UserSettings.Logging = avp.getBooleanValue();
+				} else if (attribute.equals("itemtemplate")) {
+					UserSettings.ItemTemplate = ((Text) item).getTemplateForm();
+				} else if (attribute.equals("annotationtemplate")) {
+					UserSettings.AnnotationTemplate = ((Text) item)
+							.getTemplateForm();
+				} else if (attribute.equals("statstemplate")) {
+					UserSettings.StatTemplate = ((Text) item).getTemplateForm();
+				} else if (attribute.equals("commenttemplate")) {
+					UserSettings.CodeCommentTemplate = ((Text) item)
+							.getTemplateForm();
+				} else if (attribute.equals("dottemplate")) {
+					UserSettings.DotTemplate = ((Text) item).getTemplateForm();
+				} else if (attribute.equals("framesetdir")) {
+					String dir = getDir(avp.getValue());
+					if (dir != null) {
+						UserSettings.FrameDirs.add(dir);
+					}
+				} else if (attribute.equals("logdir")) {
+					org.expeditee.gui.FrameIO.LOGS_DIR = getDir(avp.getValue());
+				} else if (attribute.equals("imagedir")) {
+					String dir = getDir(avp.getValue());
+					if (dir != null)
+						UserSettings.ImageDirs.add(0, dir);
+				} else if (attribute.equals("threading")) {
+					UserSettings.Threading = avp.getBooleanValue();
+				} else if (attribute.equals("colorwheel")) {
+					Item.COLOR_WHEEL = getColorWheel(item);
+				} else if (attribute.equals("fillcolorwheel")) {
+					Item.FILL_COLOR_WHEEL = getColorWheel(item);
+				} else if (attribute.equals("backgroundcolorwheel")) {
+					Frame.COLOR_WHEEL = getColorWheel(item);
+				} else if (attribute.equals("framesetdirs")) {
+					UserSettings.FrameDirs.addAll(getDirs(item));
+				} else if (attribute.equals("imagedirs")) {
+					UserSettings.ImageDirs.addAll(getDirs(item));
+				} else if (attribute.equals("style")) {
+					UserSettings.Style = getStyle(item.getChild());
+				} else {
+					errors.add(attributeFullCase
+							+ " is not a profile frame tag");
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+				errors.add("Error parsing [" + item.getText() + "] on "
+						+ profile.getName());
 			}
 		}
@@ -692,4 +703,7 @@
 
 	private static List<Text> getStyle(Frame child) {
+		if (child == null)
+			return new LinkedList<Text>();
+
 		List<Text> style = new ArrayList<Text>(8);
 		for (int i = 0; i < 10; i++) {
@@ -750,10 +764,13 @@
 			return alt;
 
-		String value = new AttributeValuePair(item.getText()).getValue().trim();
-		if (value.length() > 0) {
-			item.setLink(value);
-			return value;
-		} else if (item.getLink() != null)
-			return item.getLink();
+		AttributeValuePair avp = new AttributeValuePair(item.getText());
+		assert (avp != null);
+		
+		if (avp.hasPair()) {
+			item.setLink(avp.getValue());
+			return avp.getValue();
+		} else if (item.getLink() != null) {
+			return item.getAbsoluteLink();
+		}
 
 		return alt;
@@ -1125,4 +1142,10 @@
 	}
 
+	public static Item onItem(float floatX, float floatY,
+			boolean changeLastEdited) {
+		return onItem(DisplayIO.getCurrentFrame(), floatX, floatY,
+				changeLastEdited);
+	}
+
 	/**
 	 * Searches through the list of items on this frame to find one at the given
@@ -1135,5 +1158,6 @@
 	 * @return The Item at the given coordinates, or NULL if none is found.
 	 */
-	public static Item onItem(Frame toCheck, float floatX, float floatY) {
+	public static Item onItem(Frame toCheck, float floatX, float floatY,
+			boolean bResetLastEdited) {
 		// System.out.println("MouseX: " + floatX + " MouseY: " + floatY);
 		int x = Math.round(floatX);
@@ -1172,14 +1196,16 @@
 			// otherwise, the mouse is on the frame
 		} else {
-			if (LastEdited != null && /*
-										 * LastEdited.isVisible() &&
-										 */LastEdited.contains(x, y)
-					&& !FreeItems.getInstance().contains(LastEdited)
-					&& LastEdited.getParent() == DisplayIO.getCurrentFrame()
-					&& LastEdited.getParent().getItems().contains(LastEdited)) {
-				LastEdited.setPermission(Permission.full);
-				return LastEdited;
-			} else {
-				setLastEdited(null);
+			if (LastEdited != null) {
+				if (LastEdited.contains(x, y)
+						&& !FreeItems.getInstance().contains(LastEdited)
+						&& LastEdited.getParent() == DisplayIO
+								.getCurrentFrame()
+						&& LastEdited.getParent().getItems().contains(
+								LastEdited)) {
+					LastEdited.setPermission(Permission.full);
+					return LastEdited;
+				} else if (bResetLastEdited) {
+					setLastEdited(null);
+				}
 			}
 			ArrayList<Item> checkList = new ArrayList<Item>();
@@ -1236,5 +1262,5 @@
 	public synchronized static Item getCurrentItem() {
 		return onItem(DisplayIO.getCurrentFrame(), DisplayIO.getMouseX(),
-				FrameMouseActions.getY());
+				FrameMouseActions.getY(), true);
 	}
 
@@ -1433,9 +1459,9 @@
 
 		yPos += spacing;
-		profile.addText(xPos, yPos, "@HomeFrame: " + profile.getName(), null,
+		profile.addText(xPos, yPos, "@HomeFrame", null,
 				profile.getName());
 		yPos += spacing;
 		String defaultFrameName = profile.getFramesetName() + "0";
-		profile.addText(xPos, yPos, "@DefaultFrame: " + defaultFrameName, null,
+		profile.addText(xPos, yPos, "@DefaultFrame", null,
 				defaultFrameName);
 		yPos += spacing;
@@ -1539,8 +1565,16 @@
 
 	public static void setLastEdited(Text lastEdited) {
+
 		// If the lastEdited is being changed then check if its @i
 		Frame toReparse = null;
 		Frame toRecalculate = null;
-		if (LastEdited != null) {
+		Frame toUpdateObservers = null;
+
+		if (LastEdited == null) {
+			// System.out.print("N");
+		} else if (LastEdited != null) {
+			// System.out.print("T");
+			Frame parent = LastEdited.getParentOrCurrentFrame();
+
 			if (lastEdited != LastEdited) {
 				if (LastEdited.startsWith("@i")) {
@@ -1574,7 +1608,11 @@
 						}
 					}
-					toReparse = LastEdited.getParent();
+					toReparse = parent;
 				} else if (LastEdited.recalculateWhenChanged()) {
-					toRecalculate = LastEdited.getParentOrCurrentFrame();
+					toRecalculate = parent;
+				}
+
+				if (parent.hasObservers()) {
+					toUpdateObservers = parent;
 				}
 				// Update the formula if in XRay mode
@@ -1584,5 +1622,5 @@
 			}
 			if (lastEdited != LastEdited && LastEdited.getText().length() == 0) {
-				LastEdited.getParentOrCurrentFrame().removeItem(LastEdited);
+				parent.removeItem(LastEdited);
 			}
 		}
@@ -1592,6 +1630,12 @@
 			if (toReparse != null) {
 				Parse(toReparse, false, false);
-			} else if (toRecalculate != null) {
-				toRecalculate.recalculate();
+			} else {
+				if (toRecalculate != null) {
+					toRecalculate.recalculate();
+				}
+
+				if (toUpdateObservers != null) {
+					toUpdateObservers.notifyObservers(false);
+				}
 			}
 		}
Index: /trunk/src/org/expeditee/gui/MessageBay.java
===================================================================
--- /trunk/src/org/expeditee/gui/MessageBay.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/MessageBay.java	(revision 376)
@@ -262,5 +262,6 @@
 			boolean displayAlways, String action) {
 		List<String> actions = new LinkedList<String>();
-		actions.add(action);
+		if (action != null)
+			actions.add(action);
 		return displayMessage(message, link, actions, color, displayAlways);
 	}
Index: /trunk/src/org/expeditee/gui/MouseEventRouter.java
===================================================================
--- /trunk/src/org/expeditee/gui/MouseEventRouter.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/MouseEventRouter.java	(revision 376)
@@ -39,7 +39,9 @@
 
 	private Container _contentPane;
-	
+
 	private List<MouseListener> _mouseListeners = new LinkedList<MouseListener>();
+
 	private List<MouseMotionListener> _mouseMotionListeners = new LinkedList<MouseMotionListener>();
+
 	private List<MouseWheelListener> _mouseWheelListeners = new LinkedList<MouseWheelListener>();
 
@@ -50,8 +52,8 @@
 	 * 
 	 * @param menuBar
-	 * 		Must not be null.
+	 *            Must not be null.
 	 * 
 	 * @param contentPane
-	 * 		Must not be null.
+	 *            Must not be null.
 	 */
 	public MouseEventRouter(JMenuBar menuBar, Container contentPane) {
@@ -69,39 +71,44 @@
 		this._contentPane = contentPane;
 	}
-	
+
 	/**
 	 * Listens only to events to frames... i.e. to exeditee, not to widgets.
 	 * 
 	 * @param listener
-	 * 		The listener to add.
+	 *            The listener to add.
 	 */
 	public void addExpediteeMouseListener(MouseListener listener) {
-		if (listener == null) throw new NullPointerException("listener");
+		if (listener == null)
+			throw new NullPointerException("listener");
 		_mouseListeners.add(listener);
 	}
-	
-	
+
 	public void removeExpediteeMouseListener(MouseListener listener) {
-		if (listener == null) throw new NullPointerException("listener");
+		if (listener == null)
+			throw new NullPointerException("listener");
 		_mouseListeners.remove(listener);
 	}
-	
+
 	public void addExpediteeMouseMotionListener(MouseMotionListener listener) {
-		if (listener == null) throw new NullPointerException("listener");
+		if (listener == null)
+			throw new NullPointerException("listener");
 		_mouseMotionListeners.add(listener);
 	}
-	
+
 	public void removeExpediteeMouseMotionListener(MouseMotionListener listener) {
-		if (listener == null) throw new NullPointerException("listener");
+		if (listener == null)
+			throw new NullPointerException("listener");
 		_mouseMotionListeners.remove(listener);
 	}
-	
+
 	public void addExpediteeMouseWheelListener(MouseWheelListener listener) {
-		if (listener == null) throw new NullPointerException("listener");
+		if (listener == null)
+			throw new NullPointerException("listener");
 		_mouseWheelListeners.add(listener);
 	}
-	
+
 	public void removeExpediteeMouseWheelListener(MouseWheelListener listener) {
-		if (listener == null) throw new NullPointerException("listener");
+		if (listener == null)
+			throw new NullPointerException("listener");
 		_mouseWheelListeners.remove(listener);
 	}
@@ -109,8 +116,9 @@
 	/**
 	 * Conceal event catching from outside
+	 * 
 	 * @author Brook Novak
 	 */
 	private class EventCatcher implements AWTEventListener {
-		
+
 		/**
 		 * All events for every component in frame are fired to here
@@ -121,5 +129,5 @@
 			}
 		}
-		
+
 	}
 
@@ -133,7 +141,7 @@
 	 */
 	private void routeMouseEvent(MouseEvent e) {
-		
+
 		_currentMouseEvent = e;
-		
+
 		// First convert the point to expeditee space
 		Point containerPoint = SwingUtilities.convertPoint(e.getComponent(), e
@@ -158,10 +166,12 @@
 			// whether an expeditee item is currently picked up
 			boolean forwardToExpiditee = false;
-			boolean isOverPopup = PopupManager.getInstance().isPointOverPopup(containerPoint);
+			boolean isOverPopup = PopupManager.getInstance().isPointOverPopup(
+					containerPoint);
 			if (isOverPopup) {
 				// Popups have highest preference
 				// forwardToExpiditee = false...
-				
-				// If there ate items in free space - keep them moving with the cursor over the
+
+				// If there ate items in free space - keep them moving with the
+				// cursor over the
 				// popups.
 				if (!FreeItems.getInstance().isEmpty()) {
@@ -169,13 +179,11 @@
 				}
 
-			// Note: all frame.content pane events belong to expeditee
+				// Note: all frame.content pane events belong to expeditee
 			} else if (e.getSource() == _contentPane
 					|| e.getSource() == Browser._theBrowser
 					|| !FreeItems.getInstance().isEmpty()) {
 				forwardToExpiditee = true;
-			} else if (DisplayIO.getCurrentFrame() != null) { // is mouse over
-				// a specific
-				// expeditee
-				// item?
+			} else if (DisplayIO.getCurrentFrame() != null) {
+				/* is mouse over a specific expeditee item? */
 				// NOTE: Do not use FrameUtils.getCurrentItem() - thats relevent
 				// for old mouse position only
@@ -188,11 +196,12 @@
 				// when passing mouse events!!!
 				forwardToExpiditee = (FrameUtils.onItem(DisplayIO
-						.getCurrentFrame(), containerPoint.x, containerPoint.y) != null);
-			}
-			
+						.getCurrentFrame(), containerPoint.x, containerPoint.y,
+						true) != null);
+			}
+
 			// Create artificial mouse event and forward it to expeditee
-			MouseEvent expediteeEvent = SwingUtilities.convertMouseEvent(
-					e.getComponent(), e, _contentPane);
-			
+			MouseEvent expediteeEvent = SwingUtilities.convertMouseEvent(e
+					.getComponent(), e, _contentPane);
+
 			// NOTE: Convert util masks-out the needed extensions
 			MouseEvent withExtensions = null;
@@ -205,9 +214,9 @@
 				switch (e.getID()) {
 				case MouseEvent.MOUSE_MOVED:
-					
+
 					for (MouseMotionListener listener : _mouseMotionListeners) {
 						listener.mouseMoved(expediteeEvent);
 					}
-					
+
 					// Ensure that expiditee has focus only if no popups exist
 					if (Browser._theBrowser != null
@@ -221,27 +230,33 @@
 
 					break;
-					
+
 				case MouseEvent.MOUSE_CLICKED:
-					
-					withExtensions = duplicateMouseEvent(expediteeEvent, e.getModifiers() | e.getModifiersEx());
-					
+
+					withExtensions = duplicateMouseEvent(expediteeEvent, e
+							.getModifiers()
+							| e.getModifiersEx());
+
 					for (MouseListener listener : _mouseListeners) {
 						listener.mouseClicked(withExtensions);
 					}
-					
-					break;
-					
+
+					break;
+
 				case MouseEvent.MOUSE_PRESSED:
-					
-					withExtensions = duplicateMouseEvent(expediteeEvent, e.getModifiers() | e.getModifiersEx());
+
+					withExtensions = duplicateMouseEvent(expediteeEvent, e
+							.getModifiers()
+							| e.getModifiersEx());
 
 					for (MouseListener listener : _mouseListeners) {
 						listener.mousePressed(withExtensions);
 					}
-					
-					break;
-					
+
+					break;
+
 				case MouseEvent.MOUSE_RELEASED:
-					withExtensions = duplicateMouseEvent(expediteeEvent, e.getModifiers() | e.getModifiersEx());
+					withExtensions = duplicateMouseEvent(expediteeEvent, e
+							.getModifiers()
+							| e.getModifiersEx());
 
 					for (MouseListener listener : _mouseListeners) {
@@ -251,5 +266,5 @@
 					break;
 				case MouseEvent.MOUSE_WHEEL:
-					MouseWheelEvent mwe = (MouseWheelEvent)expediteeEvent;
+					MouseWheelEvent mwe = (MouseWheelEvent) expediteeEvent;
 					for (MouseWheelListener listener : _mouseWheelListeners) {
 						listener.mouseWheelMoved(mwe);
@@ -274,5 +289,5 @@
 
 			} else {
-				
+
 				// Keep expeditees mouse X/Y updated
 				FrameMouseActions.MouseX = expediteeEvent.getX();
@@ -283,6 +298,8 @@
 				// to give visual feedback yo users such that swing has focus.
 				Item i = FrameMouseActions.getlastHighlightedItem();
-				if (i != null && i.getHighlightMode() != Item.HighlightMode.None) {
-					FrameGraphics.changeHighlightMode(i, Item.HighlightMode.None);
+				if (i != null
+						&& i.getHighlightMode() != Item.HighlightMode.None) {
+					FrameGraphics.changeHighlightMode(i,
+							Item.HighlightMode.None);
 				}
 
@@ -297,8 +314,11 @@
 						}
 					}
-					// Auto-hide popups when user click on something other other than 
+					// Auto-hide popups when user click on something other other
+					// than
 					// a popup - and is not a on a popup invoker
-				} else if (!isOverPopup && e.getID() == MouseEvent.MOUSE_PRESSED &&
-						!PopupManager.getInstance().isInvoker(e.getComponent())) {
+				} else if (!isOverPopup
+						&& e.getID() == MouseEvent.MOUSE_PRESSED
+						&& !PopupManager.getInstance().isInvoker(
+								e.getComponent())) {
 					PopupManager.getInstance().hideAutohidePopups();
 				}
@@ -327,23 +347,17 @@
 		return false;
 	}
-	
+
 	private MouseEvent duplicateMouseEvent(MouseEvent e, int modifiers) {
-		return new MouseEvent(
-				e.getComponent(), 
-				e.getID(),
-				e.getWhen(),
-				modifiers,
-				e.getX(),
-				e.getY(),
-				/**The below methods are not compatible with Java 1.5*/
-				/*e.getXOnScreen(),
-				e.getYOnScreen(),*/
-				e.getClickCount(),
-				e.isPopupTrigger(),
-				e.getButton());
+		return new MouseEvent(e.getComponent(), e.getID(), e.getWhen(),
+				modifiers, e.getX(), e.getY(),
+				/** The below methods are not compatible with Java 1.5 */
+				/*
+				 * e.getXOnScreen(), e.getYOnScreen(),
+				 */
+				e.getClickCount(), e.isPopupTrigger(), e.getButton());
 	}
 
 	public static MouseEvent getCurrentMouseEvent() {
-		
+
 		return _currentMouseEvent;
 
Index: /trunk/src/org/expeditee/gui/Reminders.java
===================================================================
--- /trunk/src/org/expeditee/gui/Reminders.java	(revision 375)
+++ /trunk/src/org/expeditee/gui/Reminders.java	(revision 376)
@@ -11,4 +11,7 @@
 
 	public synchronized static void init(final Frame reminderFrame) {
+		if(reminderFrame == null)
+			return;
+		
 		for (Text text : reminderFrame.getBodyTextItems(false)) {
 			try {
Index: /trunk/src/org/expeditee/io/AbstractHTMLWriter.java
===================================================================
--- /trunk/src/org/expeditee/io/AbstractHTMLWriter.java	(revision 375)
+++ /trunk/src/org/expeditee/io/AbstractHTMLWriter.java	(revision 376)
@@ -9,4 +9,5 @@
 
 import org.expeditee.gui.Frame;
+import org.expeditee.gui.FrameIO;
 import org.expeditee.gui.MessageBay;
 import org.expeditee.gui.UserSettings;
@@ -23,4 +24,15 @@
 		_format = ".html";
 		super.initialise(start, writer);
+
+		// Clear the filesFolder
+		String filesFolderName = FrameIO.EXPORTS_DIR + getFilesFolder();
+		if (filesFolderName.length() > 0) {
+			File filesFolder = new File(filesFolderName);
+			for (File f : filesFolder.listFiles()) {
+				f.delete();
+			}
+			filesFolder.delete();
+			_filesFolderName = null;
+		}
 
 		_writer.write("<html>" + ItemWriter.NEW_LINE);
Index: /trunk/src/org/expeditee/io/DefaultFrameWriter.java
===================================================================
--- /trunk/src/org/expeditee/io/DefaultFrameWriter.java	(revision 375)
+++ /trunk/src/org/expeditee/io/DefaultFrameWriter.java	(revision 376)
@@ -75,4 +75,5 @@
 			_ItemTags.put("I", Item.class.getMethod("getAnchorBottom", param));
 			_ItemTags.put("P", Item.class.getMethod("getPosition", param));
+			_ItemTags.put("T", Text.class.getMethod("getText", param));
 			_ItemTags.put("F", Item.class.getMethod("getLink", param));
 			_ItemTags.put("X", Item.class.getMethod("getAction", param));
@@ -107,5 +108,4 @@
 			// Store the formula in the text property NOT the answer
 			_ItemTags.put("J", Item.class.getMethod("getFormula", param));
-			_ItemTags.put("T", Text.class.getMethod("getText", param));
 
 			_ItemTags.put("a", Text.class.getMethod("getWordSpacing", param));
Index: /trunk/src/org/expeditee/io/DefaultTreeWriter.java
===================================================================
--- /trunk/src/org/expeditee/io/DefaultTreeWriter.java	(revision 375)
+++ /trunk/src/org/expeditee/io/DefaultTreeWriter.java	(revision 376)
@@ -15,5 +15,5 @@
 
 	private int _indent = 0;
-	
+
 	// the list of frames currently being processed
 	private Stack<FrameCounter> _frames = new Stack<FrameCounter>();
@@ -81,7 +81,10 @@
 
 			Frame next = FrameIO.LoadFrame(cur.frame);
+
 			if (next == null) {
 				return;
 			}
+
+			Text title = next.getTitleItem();
 
 			// the items on the frame currently being processed.
@@ -109,7 +112,11 @@
 				// ignore annotation and framenames
 				if (item.getID() >= 0) {
-					//Only follow the links of text items
-					if (item instanceof Text && item.getLink() != null
-							&& !item.isAnnotation()) {
+					// Only follow the links of non annotation text items
+					boolean followLink = item instanceof Text
+							&& item.getLink() != null
+							&& (!item.isAnnotation() /*|| item.getText()
+									.toLowerCase().equals("@next")*/);
+
+					if (followLink) {
 						cur.index = i;
 						_frames.push(cur);
@@ -139,5 +146,5 @@
 						// Dont write out the title here because it is written
 						// out earlier
-					} else if (item != next.getTitleItem())
+					} else if (item != title)
 						this.writeItem(item);
 				}
@@ -177,5 +184,5 @@
 		}
 	}
-	
+
 	protected int getIndent() {
 		return _indent;
Index: unk/src/org/expeditee/io/HTMLBWriter.java
===================================================================
--- /trunk/src/org/expeditee/io/HTMLBWriter.java	(revision 375)
+++ 	(revision )
@@ -1,83 +1,0 @@
-package org.expeditee.io;
-
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.List;
-
-import org.expeditee.actions.Misc;
-import org.expeditee.gui.FrameIO;
-import org.expeditee.items.Item;
-import org.expeditee.items.Picture;
-import org.expeditee.items.Text;
-
-import sun.awt.image.ToolkitImage;
-
-public class HTMLBWriter extends AbstractHTMLWriter {
-
-	@Override
-	protected void writeTitle(Text toWrite, List<Item> items)
-			throws IOException {
-		int indent = getIndent();
-		if(indent == 0)
-			return;
-		
-		String heading = toWrite.getText();
-		String tag = "h" + indent;
-		// indenting for tag
-		indent();
-		_writer.write("<" + tag + ">" + heading + "</" + tag + ">"
-				+ ItemWriter.NEW_LINE);
-	}
-
-	@Override
-	protected void writeText(Text text) throws IOException {
-		indent();
-		_writer.write("<p>");
-		_writer.write(text.getText().replace('\n', ' '));
-		_writer.write("</p>" + ItemWriter.NEW_LINE);
-	}
-
-	@Override
-	protected void writePicture(Picture pic) throws IOException {
-		//TODO: Deal with cropped images!
-		
-		Image image = pic.getImage();
-		String filesFolder = getFilesFolder();
-		String fileName;
-		// If its a bufferedImage then just write it out to the files directory
-		//This means it is probably a FrameImage
-		if (image instanceof BufferedImage || image instanceof ToolkitImage) {
-			String link = pic.getAbsoluteLink();
-			// Account for the possiblitly of an unlinked buffered image
-			fileName = link == null ? ("Image" + pic.getID()) : link;
-			fileName = Misc.SaveImage((BufferedImage) image, "PNG", FrameIO.EXPORTS_DIR
-					+ filesFolder, fileName);
-		} else {//It is a normal Image stored somewhere
-			
-			Text source = pic.getSource();
-
-			fileName = source.getFirstLine();
-			fileName = fileName.substring(fileName.indexOf(":") + 1).trim();
-
-			String oldImageName = FrameIO.IMAGES_PATH + fileName;
-			String newImageName = FrameIO.EXPORTS_DIR + filesFolder + fileName;
-			try {
-				FrameIO.copyFile(oldImageName, newImageName);
-			} catch (Exception e) {
-				filesFolder = "";
-			}
-			if (filesFolder.equals("")) {
-				filesFolder = "../" + FrameIO.IMAGES_FOLDER;
-			}
-		}
-		indent();
-		StringBuffer imageTag = new StringBuffer("<img src=\"");
-		imageTag.append(filesFolder).append(fileName);
-		imageTag.append("\" height=").append(pic.getHeight());
-		imageTag.append(" width=").append(pic.getWidth());
-		imageTag.append(" border=1>");
-		_writer.write(imageTag.toString());
-		_writer.write(ItemWriter.NEW_LINE);
-	}
-}
Index: /trunk/src/org/expeditee/io/HTMLWriter.java
===================================================================
--- /trunk/src/org/expeditee/io/HTMLWriter.java	(revision 375)
+++ /trunk/src/org/expeditee/io/HTMLWriter.java	(revision 376)
@@ -1,120 +1,95 @@
 package org.expeditee.io;
 
+import java.awt.Image;
+import java.awt.image.BufferedImage;
 import java.io.IOException;
-import java.io.Writer;
 import java.util.List;
 
-import org.expeditee.gui.Frame;
+import org.expeditee.actions.Misc;
+import org.expeditee.gui.FrameIO;
+import org.expeditee.items.FramePicture;
 import org.expeditee.items.Item;
 import org.expeditee.items.Picture;
 import org.expeditee.items.Text;
 
-public class HTMLWriter extends DefaultTreeWriter {
+import sun.awt.image.ToolkitImage;
 
-	private int _indent = 0;
-
-	private static final String INDENT = "   ";
+public class HTMLWriter extends AbstractHTMLWriter {
 
 	@Override
-	protected void initialise(Frame start, Writer writer) throws IOException {
-		_format = ".html";
-		super.initialise(start, writer);
-	}
-
-	@Override
-	protected void writeStartLink(Item linker) throws IOException {
-		// only output text items
-		if (!(linker instanceof Text)) {
-			_indent++;
-			return;
-		}
-
-		Text text = (Text) linker;
-		List<String> toWrite = text.getTextList();
-
-		String first = toWrite.get(0);
-		int ind = first.indexOf(":");
-
-		if (ind > 0) {
-			String tag = first.substring(0, ind);
-			String remain = first.substring(ind + 1);
-
-			if (remain.length() > 0) {
-				// indenting for comments
-				indent();
-				_writer.write("<!-- " + remain);
-
-				for (int i = 1; i < toWrite.size(); i++)
-					_writer.write(ItemWriter.NEW_LINE + toWrite.get(i));
-
-				_writer.write(" -->" + ItemWriter.NEW_LINE);
-			}
-
-			// indenting for tag
-			indent();
-			_writer.write("<" + tag + ">" + ItemWriter.NEW_LINE);
-		}
-
-		_indent++;
-	}
-
-	@Override
-	protected void writeEndLink(Item linker) throws IOException {
-		_indent--;
-
-		// only output text items
-		if (!(linker instanceof Text))
+	protected void writeTitle(Text toWrite, List<Item> items)
+			throws IOException {
+		int indent = getIndent();
+		if (indent == 0)
 			return;
 
-		Text text = (Text) linker;
-		List<String> toWrite = text.getTextList();
-
-		String first = toWrite.get(0);
-		int ind = first.indexOf(":");
-
-		if (ind > 0) {
-			String tag = first.substring(0, ind);
-
-			// indenting for tag
-			indent();
-			_writer.write("</" + tag + ">" + ItemWriter.NEW_LINE);
-		}
-
+		String heading = toWrite.getText();
+		String tag = "h" + indent;
+		// indenting for tag
+		indent();
+		_writer.write("<" + tag + ">" + heading + "</" + tag + ">"
+				+ ItemWriter.NEW_LINE);
 	}
 
 	@Override
 	protected void writeText(Text text) throws IOException {
-		for (String s : text.getTextList()) {
-
-			indent();
-			// check if the first word is proceeded by a :
-			int firstColonIndex = s.indexOf(":");
-			int firstSpaceIndex = s.indexOf(" ");
-			if (firstColonIndex > 0 && firstColonIndex < firstSpaceIndex) {
-				_writer.write("<" + s.substring(0, firstColonIndex) + ">");
-				if (firstColonIndex < s.length())
-					_writer.write(s.substring(firstColonIndex + 1));
-				_writer.write("</" + s.substring(0, firstColonIndex) + ">");
-			} else
-				_writer.write(s);
-			_writer.write(ItemWriter.NEW_LINE);
-		}
-	}
-
-	private void indent() throws IOException {
-		for (int i = 0; i < _indent; i++)
-			_writer.write(INDENT);
+		indent();
+		_writer.write("<p>");
+		_writer.write(text.getText().replace('\n', ' '));
+		_writer.write("</p>" + ItemWriter.NEW_LINE);
 	}
 
 	@Override
 	protected void writePicture(Picture pic) throws IOException {
-		Text source = pic.getSource();
+		// TODO handle different colored @f's of the same frame
+		// TODO handle cropped images
+		Image image = null;
 
-		String line = source.getFirstLine();
-		line = line.substring(line.indexOf(":") + 1).trim();
+		if (pic instanceof FramePicture || pic.isCropped()) {
+			image = pic.getImage();
+			// Crop the image
+			BufferedImage bufferedImage = new BufferedImage(pic
+					.getUnscaledWidth(), pic.getUnscaledHeight(),
+					BufferedImage.TYPE_INT_ARGB);
+			bufferedImage.getGraphics().drawImage(image, 0, 0,
+					pic.getUnscaledWidth(), pic.getUnscaledHeight(),
+					pic.getStart().x, pic.getStart().y, pic.getEnd().x,
+					pic.getEnd().y, null);
+			image = bufferedImage;
+		} else {
+			image = pic.getImage();
+		}
 
+		String filesFolder = getFilesFolder();
+		String fileName;
+		// If its a bufferedImage then just write it out to the files directory
+		// This means it is probably a FrameImage
+		if (image instanceof BufferedImage) {
+			String link = pic.getAbsoluteLink();
+			// Account for the possiblitly of an unlinked buffered image
+			fileName = link == null ? ("Image" + pic.getID()) : link;
+			fileName = Misc.SaveImage((BufferedImage) image, "PNG",
+					FrameIO.EXPORTS_DIR + filesFolder, fileName);
+		} else {// It is a normal Image stored somewhere
+			fileName = pic.getName();
+
+			String oldImageName = FrameIO.IMAGES_PATH + fileName;
+			String newImageName = FrameIO.EXPORTS_DIR + filesFolder + fileName;
+			try {
+				FrameIO.copyFile(oldImageName, newImageName);
+			} catch (Exception e) {
+				filesFolder = "";
+			}
+			if (filesFolder.equals("")) {
+				filesFolder = "../" + FrameIO.IMAGES_FOLDER;
+			}
+		}
 		indent();
-
-		_writer.write("<img src = '../images/" + line + "'>");
+		StringBuffer imageTag = new StringBuffer("<img src=\"");
+		imageTag.append(filesFolder).append(fileName);
+		imageTag.append("\" height=").append(pic.getHeight());
+		imageTag.append(" width=").append(pic.getWidth());
+		imageTag.append(" border=1>");
+		_writer.write(imageTag.toString());
 		_writer.write(ItemWriter.NEW_LINE);
 	}
Index: /trunk/src/org/expeditee/io/TXTWriter.java
===================================================================
--- /trunk/src/org/expeditee/io/TXTWriter.java	(revision 375)
+++ /trunk/src/org/expeditee/io/TXTWriter.java	(revision 376)
@@ -10,5 +10,5 @@
 import org.expeditee.items.Text;
 
-public class TXTWriter extends DefaultTreeWriter{
+public class TXTWriter extends DefaultTreeWriter {
 
 	private boolean _join = false;
@@ -72,12 +72,11 @@
 	@Override
 	protected void writeText(Text text) throws IOException {
-		for (String s : text.getTextList()) {
+		String s = text.getText();
 
-			for (int i = 0; i < _indent; i++)
-				_writer.write("\t");
+		for (int i = 0; i < _indent; i++)
+			_writer.write("\t");
 
-			_writer.write(s);
-			_writer.write(ItemWriter.NEW_LINE);
-		}
+		_writer.write(s);
+		_writer.write(ItemWriter.NEW_LINE);
 
 		if (!_join)
Index: /trunk/src/org/expeditee/io/oldHTMLWriter.java
===================================================================
--- /trunk/src/org/expeditee/io/oldHTMLWriter.java	(revision 376)
+++ /trunk/src/org/expeditee/io/oldHTMLWriter.java	(revision 376)
@@ -0,0 +1,121 @@
+package org.expeditee.io;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+
+import org.expeditee.gui.Frame;
+import org.expeditee.items.Item;
+import org.expeditee.items.Picture;
+import org.expeditee.items.Text;
+
+public class oldHTMLWriter extends DefaultTreeWriter {
+
+	private int _indent = 0;
+
+	private static final String INDENT = "   ";
+
+	@Override
+	protected void initialise(Frame start, Writer writer) throws IOException {
+		_format = ".html";
+		super.initialise(start, writer);
+	}
+
+	@Override
+	protected void writeStartLink(Item linker) throws IOException {
+		// only output text items
+		if (!(linker instanceof Text)) {
+			_indent++;
+			return;
+		}
+
+		Text text = (Text) linker;
+		List<String> toWrite = text.getTextList();
+
+		String first = toWrite.get(0);
+		int ind = first.indexOf(":");
+
+		if (ind > 0) {
+			String tag = first.substring(0, ind);
+			String remain = first.substring(ind + 1);
+
+			if (remain.length() > 0) {
+				// indenting for comments
+				indent();
+				_writer.write("<!-- " + remain);
+
+				for (int i = 1; i < toWrite.size(); i++)
+					_writer.write(ItemWriter.NEW_LINE + toWrite.get(i));
+
+				_writer.write(" -->" + ItemWriter.NEW_LINE);
+			}
+
+			// indenting for tag
+			indent();
+			_writer.write("<" + tag + ">" + ItemWriter.NEW_LINE);
+		}
+
+		_indent++;
+	}
+
+	@Override
+	protected void writeEndLink(Item linker) throws IOException {
+		_indent--;
+
+		// only output text items
+		if (!(linker instanceof Text))
+			return;
+
+		Text text = (Text) linker;
+		List<String> toWrite = text.getTextList();
+
+		String first = toWrite.get(0);
+		int ind = first.indexOf(":");
+
+		if (ind > 0) {
+			String tag = first.substring(0, ind);
+
+			// indenting for tag
+			indent();
+			_writer.write("</" + tag + ">" + ItemWriter.NEW_LINE);
+		}
+
+	}
+
+	@Override
+	protected void writeText(Text text) throws IOException {
+		for (String s : text.getTextList()) {
+
+			indent();
+			// check if the first word is proceeded by a :
+			int firstColonIndex = s.indexOf(":");
+			int firstSpaceIndex = s.indexOf(" ");
+			if (firstColonIndex > 0 && firstColonIndex < firstSpaceIndex) {
+				_writer.write("<" + s.substring(0, firstColonIndex) + ">");
+				if (firstColonIndex < s.length())
+					_writer.write(s.substring(firstColonIndex + 1));
+				_writer.write("</" + s.substring(0, firstColonIndex) + ">");
+			} else
+				_writer.write(s);
+			_writer.write(ItemWriter.NEW_LINE);
+		}
+	}
+
+	private void indent() throws IOException {
+		for (int i = 0; i < _indent; i++)
+			_writer.write(INDENT);
+	}
+
+	@Override
+	protected void writePicture(Picture pic) throws IOException {
+		Text source = pic.getSource();
+
+		String line = source.getFirstLine();
+		line = line.substring(line.indexOf(":") + 1).trim();
+
+		indent();
+
+		_writer.write("<img src = '../images/" + line + "'>");
+		_writer.write(ItemWriter.NEW_LINE);
+	}
+}
Index: /trunk/src/org/expeditee/items/Circle.java
===================================================================
--- /trunk/src/org/expeditee/items/Circle.java	(revision 375)
+++ /trunk/src/org/expeditee/items/Circle.java	(revision 376)
@@ -143,5 +143,5 @@
 				+ Math.pow(Math.abs(_center.getY() - y), 2));
 
-		return Math.abs(distance - radius) < Item.getGravity() * 2;
+		return Math.abs(distance - radius) < getGravity() * 2;
 	}
 
@@ -337,3 +337,8 @@
 		_line.refreshStroke(thick);
 	}
+	
+	@Override
+	public boolean isConnectedToAnnotation() {
+		return false;
+	}
 }
Index: /trunk/src/org/expeditee/items/Dot.java
===================================================================
--- /trunk/src/org/expeditee/items/Dot.java	(revision 375)
+++ /trunk/src/org/expeditee/items/Dot.java	(revision 376)
@@ -26,5 +26,5 @@
 	// Standard Item variables
 
-	private static final int _MINIMUM_DOT_SIZE = 6;
+	//private static final int _MINIMUM_DOT_SIZE = 6;
 
 	private static final int MINIMUM_DOT_SIZE = 2;
@@ -120,4 +120,8 @@
 			// Draw the highlighting rectangle surrounding the dot
 			// this is drawn even if its part of a rectangle
+			
+			if(isVectorItem())
+				updatePolygon();
+			
 			Rectangle rect = getPolygon().getBounds();
 			if (_mode == HighlightMode.Enclosed ||
@@ -177,5 +181,5 @@
 		int thick = Math.round(getThickness());
 		// Sets a minimum size for the dot
-		thick = Math.max(thick, _MINIMUM_DOT_SIZE);
+		thick = Math.max(thick, getGravity() * 2);
 
 		int x = getX() - thick / 2;
Index: /trunk/src/org/expeditee/items/Item.java
===================================================================
--- /trunk/src/org/expeditee/items/Item.java	(revision 375)
+++ /trunk/src/org/expeditee/items/Item.java	(revision 376)
@@ -26,4 +26,5 @@
 import org.expeditee.actions.Misc;
 import org.expeditee.actions.Simple;
+import org.expeditee.gui.AttributeValuePair;
 import org.expeditee.gui.DisplayIO;
 import org.expeditee.gui.Frame;
@@ -31,4 +32,5 @@
 import org.expeditee.gui.FrameIO;
 import org.expeditee.gui.FrameKeyboardActions;
+import org.expeditee.gui.FrameMouseActions;
 import org.expeditee.gui.FrameUtils;
 import org.expeditee.gui.FreeItems;
@@ -229,5 +231,8 @@
 	}
 
-	public static int getGravity() {
+	public int getGravity() {
+		if (isVectorItem()) {
+			return 2;
+		}
 		return org.expeditee.gui.UserSettings.Gravity;
 	}
@@ -323,4 +328,6 @@
 
 	protected int _highlightThickness = 2;
+
+	protected int _vectorHighlightThickness = 1;
 
 	// arrowhead parameters
@@ -700,6 +707,6 @@
 	public Color getHighlightColor() {
 		if (_highlightColor.equals(getPaintColor()))
-			return ALTERNATE_HIGHLIGHT;
-		return _highlightColor;
+			return getAlternateHighlightColor();
+		return getDefaultHighlightColor();
 	}
 
@@ -762,4 +769,8 @@
 	public boolean hasFormula() {
 		return _formula != null;
+	}
+	
+	public boolean hasAttributeValuePair() {
+		return _attributeValuePair != null && _attributeValuePair.hasPair();
 	}
 
@@ -853,11 +864,11 @@
 
 	protected Color getPaintHighlightColor() {
-		Color highlightColor = _highlightColor;
+		Color highlightColor = getDefaultHighlightColor();
 		if (hasVisibleBorder()) {
 			if (getPaintBorderColor().equals(highlightColor)) {
-				highlightColor = ALTERNATE_HIGHLIGHT;
+				highlightColor = getDefaultHighlightColor();
 			}
 		} else if (getPaintBackgroundColor().equals(highlightColor)) {
-			highlightColor = ALTERNATE_HIGHLIGHT;
+			highlightColor = getDefaultHighlightColor();
 		}
 		if (getParent() != null
@@ -867,5 +878,5 @@
 		if (hasVisibleBorder()) {
 			if (highlightColor.equals(getBorderColor())
-					&& getThickness() == _highlightThickness) {
+					&& getThickness() == getHighlightThickness()) {
 				highlightColor = new Color(highlightColor.getRed(),
 						highlightColor.getGreen(), highlightColor.getBlue(),
@@ -875,4 +886,30 @@
 
 		return highlightColor;
+	}
+
+	static final int BRIGHTNESS = 185;
+
+	protected Color getDefaultHighlightColor() {
+		if (isVectorItem()
+				&& !this.contains(FrameMouseActions.getX(), FrameMouseActions
+						.getY())) {
+			return new Color(255, BRIGHTNESS, BRIGHTNESS);
+		}
+		return _highlightColor;
+	}
+
+	protected Color getAlternateHighlightColor() {
+		if (isVectorItem()
+				&& !this.contains(FrameMouseActions.getX(), FrameMouseActions
+						.getY())) {
+			return new Color(BRIGHTNESS, BRIGHTNESS, 255);
+		}
+		return ALTERNATE_HIGHLIGHT;
+	}
+
+	protected int getHighlightThickness() {
+		if (isVectorItem())
+			return _vectorHighlightThickness;
+		return _highlightThickness;
 	}
 
@@ -2461,4 +2498,6 @@
 	private Overlay _overlay = null;
 
+	protected AttributeValuePair _attributeValuePair = null;
+
 	/**
 	 * For now there can only be one enclosure per item
@@ -2745,3 +2784,28 @@
 		updatePolygon();
 	}
+
+	protected boolean isVectorItem() {
+		return _editTarget != this;
+	}
+
+	public AttributeValuePair getAttributeValuePair() {
+		if(_attributeValuePair  == null){
+			_attributeValuePair = new AttributeValuePair(getText());
+		}
+		return _attributeValuePair;
+	}
+
+	/*private static Set<Object> _locks = new HashSet<Object>();
+
+	public static void lock(Object itemToLock) {
+		_locks.add(itemToLock);
+	}
+	
+	public static void unlock(Object itemToUnlock) {
+		_locks.remove(itemToUnlock);
+	}
+	
+	public static boolean isLocked(Object item) {
+		return _locks.contains(item);
+	}*/
 }
Index: /trunk/src/org/expeditee/items/Permission.java
===================================================================
--- /trunk/src/org/expeditee/items/Permission.java	(revision 375)
+++ /trunk/src/org/expeditee/items/Permission.java	(revision 376)
@@ -1,13 +1,13 @@
 package org.expeditee.items;
 
-public enum Permission{
+public enum Permission {
 	none, followLinks, copy, createFrames, full;
 
 	/**
-	 * Converts the given Expeditee justification code into a int corresponding
-	 * to the constants defined in Item.
+	 * Converts the given Expeditee permission code into a int corresponding to
+	 * the constants defined in Item.
 	 * 
 	 * @param permissionCode
-	 *            The Expeditee justification code to convert
+	 *            The Expeditee permission code to convert
 	 * @return The resulting int corresponding to one of the constants defined
 	 *         in Item
@@ -16,21 +16,22 @@
 		return getPermission(permissionCode, Permission.full);
 	}
-	
-	public static Permission getPermission(String permissionCode, Permission defaultPermission) {
+
+	public static Permission getPermission(String permissionCode,
+			Permission defaultPermission) {
 		if (permissionCode == null)
 			return defaultPermission;
-		
+
 		permissionCode = permissionCode.trim().toLowerCase();
 		if (permissionCode.length() == 0)
 			return defaultPermission;
-		
+
 		// if it is a single char just match the first character
-		try{
+		try {
 			return values()[Integer.parseInt(permissionCode)];
 			// Otherwise match the whole string
-		}catch(Exception ex){
-			try{
-			return valueOf(permissionCode);
-			}catch (Exception e) {
+		} catch (Exception ex) {
+			try {
+				return valueOf(permissionCode);
+			} catch (Exception e) {
 			}
 		}
@@ -39,5 +40,4 @@
 		return defaultPermission;
 	}
-
 
 	public int getCode() {
@@ -52,5 +52,5 @@
 		return p1.ordinal() < p2.ordinal() ? p1 : p2;
 	}
-	
+
 	public static Permission max(Permission p1, Permission p2) {
 		return p1.ordinal() > p2.ordinal() ? p1 : p2;
Index: /trunk/src/org/expeditee/items/Picture.java
===================================================================
--- /trunk/src/org/expeditee/items/Picture.java	(revision 375)
+++ /trunk/src/org/expeditee/items/Picture.java	(revision 376)
@@ -64,7 +64,7 @@
 	private Point _cropEnd = null;
 
-	private Point _start = new Point(0, 0);;
-
-	private Point _end = new Point(0, 0);;
+	private Point _start = new Point(0, 0);
+
+	private Point _end = new Point(0, 0);
 
 	private boolean _showCropping = false;
@@ -277,4 +277,12 @@
 	}
 
+	public Point getStart() {
+		return _start;
+	}
+	
+	public Point getEnd() {
+		return _end;
+	}
+	
 	/**
 	 * Gets the width with which the picture is displayed on the screen.
@@ -354,5 +362,5 @@
 			g.drawPolygon(getPolygon());
 		}
-		
+
 		if (isHighlighted()) {
 			Stroke borderStroke = new BasicStroke(1, CAP, JOIN);
@@ -361,6 +369,8 @@
 			g.drawPolygon(getPolygon());
 		}
-	}
-	
+		
+		//System.out.print("p_");	
+	}
+
 	@Override
 	public Color getHighlightColor() {
@@ -484,9 +494,29 @@
 
 	public Image getCroppedImage() {
-		if(_image == null)
+		if (_image == null)
 			return null;
-		return Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(
-				_image.getSource(),
-				new CropImageFilter(_start.x, _start.y, getWidth(), getHeight())));
+		if (!isCropped()) {
+			return _image;
+		}
+		
+		return Toolkit.getDefaultToolkit().createImage(
+				new FilteredImageSource(_image.getSource(),
+						new CropImageFilter(_start.x, _start.y,
+								getUnscaledWidth(), getUnscaledHeight())));
+	}
+
+	public int getUnscaledWidth() {
+		return _end.x - _start.x;
+	}
+
+	public int getUnscaledHeight() {
+		return _end.y - _start.y;
+	}
+
+	/**
+	 * @return true if this is a cropped image.
+	 */
+	public boolean isCropped() {
+		return _end.x != 0 || _end.y != 0 || _start.y != 0 || _start.x != 0;
 	}
 
@@ -616,7 +646,7 @@
 
 	}
-	
-	@Override
-	public void scale(Float scale, int originX, int originY){
+
+	@Override
+	public void scale(Float scale, int originX, int originY) {
 		setScale(getScale() * scale);
 		super.scale(scale, originX, originY);
Index: /trunk/src/org/expeditee/items/Text.java
===================================================================
--- /trunk/src/org/expeditee/items/Text.java	(revision 375)
+++ /trunk/src/org/expeditee/items/Text.java	(revision 376)
@@ -259,5 +259,6 @@
 
 	/**
-	 * Sets the text displayed on the screen to the given String
+	 * Sets the text displayed on the screen to the given String. It does not
+	 * reset the formula, attributeValuePair or other cached values.
 	 * 
 	 * @param text
@@ -266,7 +267,15 @@
 	@Override
 	public void setText(String text) {
-		if (_text != null && text.length() < _text.length())
-			invalidateAll();
+		// if (_text != null && text.length() < _text.length())
+		invalidateAll();
 		_text = new StringBuffer(text);
+
+		/*
+		 * Adding the lines below remove formulas when moving in and out of XRay
+		 * mode
+		 */
+		// Reset properties
+		// setProcessedText(null);
+		// setFormula(null);
 		rebuild(true);
 		invalidateAll();
@@ -277,10 +286,19 @@
 			return;
 
-		setText(text.get(0));
-		for (int i = 1; i < text.size(); i++) {
-			appendText("\n");
-			appendText(text.get(i));
-		}
-		rebuild(false);
+		invalidateAll();
+
+		StringBuffer sb = new StringBuffer();
+
+		for (int i = 0; i < text.size(); i++) {
+			sb.append(text.get(i)).append('\n');
+		}
+
+		if (sb.length() > 0)
+			sb.deleteCharAt(sb.length() - 1);
+
+		setText(sb.toString());
+
+		rebuild(true);
+		invalidateAll();
 	}
 
@@ -589,6 +607,5 @@
 			// otherwise, we are inserting text
 		} else {
-			setProcessedText(null);
-			setFormula(null);
+			clearCache();
 			// determine what line is being pointed to
 			line = getLinePosition(mouseY);
@@ -729,4 +746,13 @@
 
 	/**
+	 * 
+	 */
+	private void clearCache() {
+		_attributeValuePair = null;
+		setProcessedText(null);
+		setFormula(null);
+	}
+
+	/**
 	 * @param pos
 	 * @return
@@ -741,9 +767,11 @@
 
 	public Point2D.Float moveCursor(int direction, float mouseX, float mouseY,
-			boolean setSelection) {
+			boolean setSelection, boolean wholeWord) {
 		if (setSelection) {
-			if (getSelectionSize() <= 0) {
+			if (!hasSelection()) {
 				setSelectionStart(mouseX, mouseY);
 			}
+		} else {
+			// clearSelection();
 		}
 
@@ -789,11 +817,26 @@
 				if (direction == LEFT) {
 					if (hit.getInsertionIndex() > 0) {
-						hit = _textLayouts.get(line).getNextLeftHit(hit);
-						// This takes care of the case where the user has put a
-						// hard
-						// line break in
-						if (line > 0
-								&& _text.charAt(hit.getInsertionIndex()
-										+ _lineOffsets.get(line)) == '\n') {
+
+						char prevChar = ' ';
+						do {
+							hit = _textLayouts.get(line).getNextLeftHit(hit);
+
+							// Stop if at the start of the line
+							if (hit.getInsertionIndex() == 0)
+								break;
+							// Keep going if the char to the left is a
+							// letterOrDigit
+							prevChar = _text.charAt(hit.getInsertionIndex() - 1
+									+ _lineOffsets.get(line));
+						} while (wholeWord
+								&& Character.isLetterOrDigit(prevChar));
+						// TODO Go to the start of the word instead of before
+						// the word
+						char nextChar = _text.charAt(hit.getInsertionIndex()
+								+ _lineOffsets.get(line));
+						/*
+						 * This takes care of hard line break in
+						 */
+						if (line > 0 && nextChar == '\n') {
 							line--;
 							hit = _textLayouts.get(line)
@@ -807,4 +850,8 @@
 						hit = _textLayouts.get(line).getNextRightHit(
 								_textLayouts.get(line).getCharacterCount() - 1);
+						/*
+						 * Skip the spaces at the end of a line with soft
+						 * linebreak
+						 */
 						while (hit.getCharIndex() > 0
 								&& _text.charAt(_lineOffsets.get(line)
@@ -817,9 +864,12 @@
 							.getCharacterCount()) {
 						hit = _textLayouts.get(line).getNextRightHit(hit);
-						while (hit.getCharIndex() > 0
+						// Skip whole word if needs be
+						while (wholeWord
+								&& hit.getCharIndex() > 0
 								&& hit.getCharIndex() < _textLayouts.get(line)
 										.getCharacterCount()
-								&& _text.charAt(_lineOffsets.get(line)
-										+ hit.getCharIndex() - 1) == '\t')
+								&& Character.isLetterOrDigit(_text
+										.charAt(_lineOffsets.get(line)
+												+ hit.getCharIndex() - 1)))
 							hit = _textLayouts.get(line).getNextRightHit(hit);
 					} else if (line < _textLayouts.size() - 1) {
@@ -1514,5 +1564,5 @@
 			g.setColor(getPaintHighlightColor());
 			Stroke highlightStroke = new BasicStroke(
-					(float) _highlightThickness, CAP, JOIN);
+					(float) getHighlightThickness(), CAP, JOIN);
 			g.setStroke(highlightStroke);
 			if (HighlightMode.Enclosed.equals(getHighlightMode()))
@@ -1553,5 +1603,5 @@
 				}
 
-				layout.draw(g, getX() + getJustOffset(layout), y);
+				layout.draw(g, 1 + getX() + getJustOffset(layout), y);
 
 				/*
@@ -1608,5 +1658,9 @@
 		copy.setWidth(getWidth());
 		copy.setFont(getFont());
-		copy.setText(_text.toString());
+		if (hasFormula()) {
+			copy.calculate(getFormula());
+		} else {
+			copy.setText(_text.toString());
+		}
 		copy.setHidden(!isVisible());
 		// copy.setWidth(getWidth());
@@ -1798,7 +1852,8 @@
 		Frame modelFrame = getParentOrCurrentFrame();
 		if (modelFrame != null) { 
-			setRightMargin(getParentOrCurrentFrame().getNameItem().getX()
+			setRightMargin(modelFrame.getNameItem().getX()
 					- MARGIN_LEFT);
 		} else {
+			System.out.print("Error: text.resetTitlePosition, getParent or currentFrame returned null");
 			setRightMargin(MARGIN_LEFT);
 		}
@@ -1837,8 +1892,9 @@
 		Text template = this.copy();
 		template.setID(-1);
-		// The template must have text otherwise the bounds height will be
-		// zero!!
-		// This will stop escape drop down from working if there is no item
-		// template
+		/*
+		 * The template must have text otherwise the bounds height will be
+		 * zero!! This will stop escape drop down from working if there is no
+		 * item template
+		 */
 		template.setText("@");
 		return template;
@@ -1958,4 +2014,6 @@
 			return false;
 		}
+		formula = formula.replace(':', '=');
+
 		String lowercaseFormula = formula.toLowerCase();
 		ExpediteeJEP myParser = new ExpediteeJEP();
@@ -1970,5 +2028,5 @@
 				continue;
 			if (i instanceof Text && !i.isAnnotation()) {
-				AttributeValuePair pair = new AttributeValuePair(i.getText());
+				AttributeValuePair pair = i.getAttributeValuePair();
 				if (pair.hasPair()) {
 					try {
@@ -1985,5 +2043,6 @@
 				try {
 					double value = pair.getDoubleValue();
-					myParser.addVariable("$" + nextVarNo++, value);
+					if (value != Double.NaN)
+						myParser.addVariable("$" + nextVarNo++, value);
 				} catch (NumberFormatException nfe) {
 					continue;
@@ -2022,9 +2081,19 @@
 				this.setText(result);
 				this.setFormula(formula);
+
+				if (!this.hasAction()) {
+					setActionMark(false);
+					setAction("extract formula");
+				}
 			}
 		} catch (Throwable e) {
-			this.setText(getFormula());
+			String formula2 = getFormula();
+			this.setText(formula2);
+			this.setFormula(formula2);
 			return false;
 		}
+
+		_attributeValuePair = null;
+
 		return true;
 	}
@@ -2042,6 +2111,8 @@
 		double enclosureArea = Double.MAX_VALUE;
 		for (Item i : parent.getVisibleItems()) {
-			// Go through all the enclosures looking for one that includes this
-			// shape
+			/*
+			 * Go through all the enclosures looking for one that includes this
+			 * item
+			 */
 			if (!seen.contains(i) && i.isEnclosed()) {
 				seen.addAll(i.getEnclosingDots());
@@ -2064,16 +2135,21 @@
 
 	/**
-	 * Returns true if this text item should be recalculated when it is modified
+	 * Returns true if items of the parent frame should be recalculated when
+	 * this item is modified
 	 */
 	public boolean recalculateWhenChanged() {
 		if (/*
 			 * !isAnnotation() &&
-			 */(hasFormula() || getText().contains(":") || isLineEnd()))
+			 */(hasFormula() || isLineEnd()))
 			return true;
 		try {
-			Double.parseDouble(getText());
-			return true;
+			AttributeValuePair avp = getAttributeValuePair();
+
+			if (!avp.getDoubleValue().equals(Double.NaN))
+				return true;
 		} catch (Exception e) {
-		}
+			e.printStackTrace();
+		}
+
 		return false;
 	}
Index: /trunk/src/org/expeditee/items/widgets/DataFrameWidget.java
===================================================================
--- /trunk/src/org/expeditee/items/widgets/DataFrameWidget.java	(revision 375)
+++ /trunk/src/org/expeditee/items/widgets/DataFrameWidget.java	(revision 376)
@@ -59,6 +59,6 @@
 				 * changed so it will be refreshed when the user goes back
 				 */
-				assert(false);
-				//_needsUpdating = true;
+				assert (false);
+				// _needsUpdating = true;
 				// update();
 			}
@@ -119,4 +119,7 @@
 		if (oldLink == null) {
 			_needsUpdating = true;
+			// Need to refresh imediately so that the data appears when adding a
+			// link to a graph
+			refresh();
 		} else {
 			refresh();
Index: /trunk/src/org/expeditee/items/widgets/SampleWidget2.java
===================================================================
--- /trunk/src/org/expeditee/items/widgets/SampleWidget2.java	(revision 375)
+++ /trunk/src/org/expeditee/items/widgets/SampleWidget2.java	(revision 376)
@@ -2,7 +2,9 @@
 
 
+import java.awt.Color;
 import java.awt.FlowLayout;
+import java.awt.Font;
 
-import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
@@ -10,4 +12,5 @@
 import javax.swing.JSplitPane;
 import javax.swing.JTextArea;
+import javax.swing.JToggleButton;
 
 import org.expeditee.items.Text;
@@ -21,22 +24,36 @@
 		super(source, new JSplitPane(JSplitPane.VERTICAL_SPLIT), 60, -1, 40, -1);
 
+		Font bigFont = null;
+		
 		JSplitPane sp = (JSplitPane)super._swingComponent;
 		
 		JPanel p = new JPanel(new FlowLayout());
+		p.setBackground(new Color(255,228,195));
 
-		JLabel lbl = new JLabel("This widget has multiple JComponents!");
+		JLabel lbl = new JLabel("This is an example InteractiveWidget!");
+		bigFont = lbl.getFont().deriveFont(24F);
+		lbl.setFont(bigFont);
 		
-		JButton button = new JButton("Click Me!");
+		JToggleButton button = new JToggleButton("Toggle Style");
+		button.setFont(bigFont);
 		
-		JButton button2 = new JButton("Or Me!");
+		JCheckBox checkBox = new JCheckBox("Big Font");
+		checkBox.setBackground(null);
+		checkBox.setSelected(true);
+		checkBox.setFont(bigFont);
+		
+		
+		//JButton button2 = new JButton("Example CheckBox");
 		
 		_text = new JTextArea();
+		_text.setFont(bigFont);
 		
-		_combo = new JComboBox(new String[] {"Item 1", "Item 2", "Item 3", "Item 21", "Item 22", "Item 23", "Item 31", "Item 32", "Item 33", "Item 41", "Item 42", "Item 43"});
+		_combo = new JComboBox(new String[] {"Peach", "Item 2", "Item 3", "Item 21", "Item 22", "Item 23", "Item 31", "Item 32", "Item 33", "Item 41", "Item 42", "Item 43"});
+		_combo.setFont(bigFont);
 		
 		p.add(lbl);
 		p.add(_combo);
 		p.add(button);
-		p.add(button2);
+		p.add(checkBox);
 		
 		sp.setTopComponent(p);
Index: /trunk/src/org/expeditee/items/widgets/charts/AbstractCategory.java
===================================================================
--- /trunk/src/org/expeditee/items/widgets/charts/AbstractCategory.java	(revision 375)
+++ /trunk/src/org/expeditee/items/widgets/charts/AbstractCategory.java	(revision 376)
@@ -54,5 +54,5 @@
 					}
 				}
-			} catch (NumberFormatException e) {
+			} catch (Exception e) {
 
 			}
Index: /trunk/src/org/expeditee/items/widgets/charts/AbstractChart.java
===================================================================
--- /trunk/src/org/expeditee/items/widgets/charts/AbstractChart.java	(revision 375)
+++ /trunk/src/org/expeditee/items/widgets/charts/AbstractChart.java	(revision 376)
@@ -85,17 +85,19 @@
 				case SizeUp:
 					invalidateLink();
-					FrameKeyboardActions.SetSize(getFirstCorner(), 1, false, true);
+					FrameKeyboardActions.SetSize(getFirstCorner(), 1, false,
+							true);
 					invalidateSelf();
 					FrameGraphics.refresh(true);
-					//FrameGraphics.requestRefresh(true);
+					// FrameGraphics.requestRefresh(true);
 					break;
 				case SizeDown:
 					invalidateLink();
-					FrameKeyboardActions.SetSize(getFirstCorner(), -1, false, true);
+					FrameKeyboardActions.SetSize(getFirstCorner(), -1, false,
+							true);
 					invalidateSelf();
 					FrameGraphics.refresh(true);
-					//FrameGraphics.ForceRepaint();
-					//FrameGraphics.refresh(true);
-					//FrameGraphics.requestRefresh(true);
+					// FrameGraphics.ForceRepaint();
+					// FrameGraphics.refresh(true);
+					// FrameGraphics.requestRefresh(true);
 					break;
 				case ChangeColor:
@@ -221,4 +223,5 @@
 	protected void refreshData(Frame dataFrame) {
 		clearSubjects();
+		
 		boolean swap = false;
 		if (dataFrame.hasAnnotation("swap")) {
@@ -265,4 +268,8 @@
 		}
 		/* if (foundData) */{
+			/*
+			 * At minimum add the data frame as a subject even if there is no data
+			 * on it... yet
+			 */
 			addSubject(dataFrame);
 		}
@@ -362,5 +369,5 @@
 		if (legend != null) {
 			legend.setFrame(new BlockBorder(newThickness, newThickness,
-					newThickness, newThickness, getSource().getColor()));
+					newThickness, newThickness, getSource().getPaintColor()));
 			legend.setItemFont(legend.getItemFont().deriveFont(fontSize));
 			float pad = newThickness + 1;
Index: /trunk/src/org/expeditee/math/ExpediteeJEP.java
===================================================================
--- /trunk/src/org/expeditee/math/ExpediteeJEP.java	(revision 375)
+++ /trunk/src/org/expeditee/math/ExpediteeJEP.java	(revision 376)
@@ -84,10 +84,13 @@
 				continue;
 
-			AttributeValuePair avp = new AttributeValuePair(t.getText());
+			AttributeValuePair avp = t.getAttributeValuePair();
 			if (avp.hasPair()) {
 				try {
-					if (getVar(avp.getAttribute()) == null)
-						addVariable(avp.getAttribute(), avp.getDoubleValue());
-				} catch (NumberFormatException e) {
+					if (getVar(avp.getAttribute()) == null) {
+						Double d = avp.getDoubleValue();
+						if (!d.equals(Double.NaN))
+							addVariable(avp.getAttribute(), avp
+									.getDoubleValue());
+					}
 				} catch (Exception e) {
 					e.printStackTrace();
@@ -111,10 +114,10 @@
 			if (i instanceof Text && !i.isAnnotation() && !i.isLineEnd()) {
 				try {
-					Double value = new AttributeValuePair(i.getText())
-							.getDoubleValue();
-					if (value != null) {
+					Double value = i.getAttributeValuePair().getDoubleValue();
+					if (!value.equals(Double.NaN)) {
 						vector.add(value);
 					}
-				} catch (NumberFormatException e) {
+				} catch (Exception e) {
+					e.printStackTrace();
 				}
 			}
Index: /trunk/src/org/expeditee/simple/SString.java
===================================================================
--- /trunk/src/org/expeditee/simple/SString.java	(revision 375)
+++ /trunk/src/org/expeditee/simple/SString.java	(revision 376)
@@ -3,4 +3,6 @@
 public class SString extends SPrimitive<String> {
 	public static String prefix = SVariable.prefix + "s" + SVariable.separator;
+
+	Double doubleValue_ = null;
 
 	public SString() {
@@ -12,5 +14,5 @@
 	}
 
-	public SString(String value) /*throws Exception*/ {
+	public SString(String value) /* throws Exception */{
 		super(value);
 	}
@@ -19,4 +21,5 @@
 	public void parse(String s) {
 		value_ = s;
+		doubleValue_ = null;
 	}
 
@@ -39,11 +42,21 @@
 	@Override
 	public Double doubleValue() {
+		if (doubleValue_ != null)
+			return doubleValue_;
+
 		if (value_.equals(""))
-			return 0.0;
-		try {
-			return Double.parseDouble(value_);
-		} catch (NumberFormatException ne) {
+			doubleValue_ = 0.0;
+		else {
+			try {
+				doubleValue_ = Double.parseDouble(value_);
+			} catch (NumberFormatException ne) {
+				try{
+				doubleValue_ =(double) Long.decode(value_);
+				}catch(Exception e){
+					doubleValue_ = Double.NaN;
+				}
+			}
 		}
-		return (double) Long.decode(value_);
+		return doubleValue_;
 	}
 
@@ -64,4 +77,5 @@
 	public void setValue(SPrimitive v) {
 		value_ = v.stringValue();
+		doubleValue_ = null;
 	}
 
Index: /trunk/src/org/expeditee/stats/DocumentStats.java
===================================================================
--- /trunk/src/org/expeditee/stats/DocumentStats.java	(revision 375)
+++ /trunk/src/org/expeditee/stats/DocumentStats.java	(revision 376)
@@ -12,4 +12,6 @@
 	protected int _treeFrames = 0;
 
+	protected int _characters = 0;
+	
 	protected int _words = 0;
 
@@ -33,4 +35,5 @@
 
 		// Initialise variables with the data for this frames comet
+		_characters = 0;
 		_words = 0;
 		_textItems = 0;
@@ -44,4 +47,5 @@
 			_words += text.split("\\s+").length;
 			_sentances += text.split("\\.+").length;
+			_characters += text.length();
 			
 			String link = i.getAbsoluteLink();
@@ -59,4 +63,5 @@
 					visited);
 			_words += childItemStats._words;
+			_characters += childItemStats._characters;
 			_textItems += childItemStats._textItems;
 			_sentances += childItemStats._sentances;
@@ -69,10 +74,11 @@
 		StringBuffer sb = new StringBuffer();
 		sb.append(SessionStats.getDate());
-		sb.append("DocStats:  ").append(_name).append('\n');
-		sb.append("Title:  ").append(_title).append('\n');
+		sb.append("DocStats: ").append(_name).append('\n');
+		sb.append("Title:    ").append(_title).append('\n');
 		sb.append("Frames:    ").append(_treeFrames).append('\n');
 		sb.append("TextItems: ").append(_textItems).append('\n');
 		sb.append("Sentances: ").append(_sentances).append('\n');
-		sb.append("Words:     ").append(_words);
+		sb.append("Words:     ").append(_words).append('\n');
+		sb.append("Chars:     ").append(_characters);
 		return sb.toString();
 	}
Index: /trunk/src/org/expeditee/stats/DocumentStatsFast.java
===================================================================
--- /trunk/src/org/expeditee/stats/DocumentStatsFast.java	(revision 376)
+++ /trunk/src/org/expeditee/stats/DocumentStatsFast.java	(revision 376)
@@ -0,0 +1,150 @@
+package org.expeditee.stats;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.expeditee.gui.AttributeValuePair;
+import org.expeditee.gui.FrameIO;
+import org.expeditee.gui.MessageBay;
+import org.expeditee.gui.UserSettings;
+import org.expeditee.io.Conversion;
+
+public class DocumentStatsFast extends Stats {
+	protected int _treeFrames = 0;
+	
+	protected int _characters = 0;
+
+	protected int _words = 0;
+
+	protected int _textItems = 0;
+
+	protected int _sentances = 0;
+
+	protected String _name = null;
+
+	protected String _title = null;
+
+	public static int wordCount(String paragraph) {
+		return paragraph.trim().split("\\s+").length + 1;
+	}
+
+	public DocumentStatsFast(String topFrame, String title) {
+		this(topFrame, new HashSet<String>());
+		_title = title;
+	}
+
+	public DocumentStatsFast(String topFrame, Set<String> visited) {
+		_name = topFrame;
+		String lowerName = _name.toLowerCase();
+
+		if (visited.contains(lowerName)) {
+			return;
+		}
+
+		visited.add(_name.toLowerCase());
+		MessageBay.overwriteMessage("Computed: " + _name);
+
+		// Initialise variables with the data for this frames comet
+		_words = 0;
+		_characters = 0;
+		_textItems = 0;
+		_sentances = 0;
+		_treeFrames = 1;
+
+		String fullPath = null;
+		for (String possiblePath : UserSettings.FrameDirs) {
+			fullPath = FrameIO.getFrameFullPathName(possiblePath, _name);
+			if (fullPath != null)
+				break;
+		}
+
+		// If the frame was not located return null
+		if (fullPath == null)
+			return;
+
+		String frameset = Conversion.getFramesetName(_name);
+
+		// Open the file and search the text items
+		try {
+			BufferedReader reader = new BufferedReader(new FileReader(fullPath));
+			String next;
+			StringBuffer sb = new StringBuffer();
+			String link = null;
+			boolean ignore = false;
+			while (reader.ready() && ((next = reader.readLine()) != null)) {
+				if (next.length() == 0) {
+					// Ignore annotations
+					if (ignore) {
+						ignore = false;
+						link = null;
+						continue;
+					}
+
+					// Ignore non text items
+					if (sb.length() == 0) {
+						link = null;
+						continue;
+					}
+
+					if (link == null) {
+						// remove the last newLine... not absolutely needed
+						String text = sb.substring(0, sb.length() - 1);
+						_textItems++;
+						_characters += text.length();
+						_words += text.split("\\s+").length;
+						_sentances += text.split("\\.+").length;
+					} else {
+						DocumentStatsFast childItemStats = new DocumentStatsFast(
+								link, visited);
+						_characters += childItemStats._characters;
+						_words += childItemStats._words;
+						_textItems += childItemStats._textItems;
+						_sentances += childItemStats._sentances;
+						_treeFrames += childItemStats._treeFrames;
+					}
+					// Reinit the item variables
+					link = null;
+					sb = new StringBuffer();
+				} else if (ignore) {
+					continue;
+				} else if (next.startsWith("T")) {
+					String text = next.substring(2).trim();
+					// Ignore the rest of annotation items...
+					if (text.length() > 0
+							&& text.charAt(0) == AttributeValuePair.ANNOTATION_CHAR) {
+						ignore = true;
+						continue;
+					}
+					sb.append(text).append('\n');
+				} else if (next.startsWith("F")) {
+					link = next.substring(2);
+					// Convert number only links
+					if (Character.isDigit(link.charAt(0)))
+						link = frameset + link;
+				}
+			}
+		} catch (FileNotFoundException e) {
+			e.printStackTrace();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+
+	@Override
+	public String toString() {
+		StringBuffer sb = new StringBuffer();
+		sb.append(SessionStats.getDate());
+		sb.append("DocStats:  ").append(_name).append('\n');
+		sb.append("Title:  ").append(_title).append('\n');
+		sb.append("Frames:    ").append(_treeFrames).append('\n');
+		sb.append("TextItems: ").append(_textItems).append('\n');
+		sb.append("Sentances: ").append(_sentances).append('\n');
+		sb.append("Words:     ").append(_words).append('\n');
+		sb.append("Chars:     ").append(_characters);
+		return sb.toString();
+	}
+}
