I've attached some patches to the textbox/richtextbox that I have been
working on.  I am hoping some people can do some testing on windows and
tell me if they notice any problems, specifically with line endings.
I've been working on making carriage returns work a little better with
our text controls, but i have a feeling this is going to busticate
things on windows.

Love,
Jackson




Index: System.Windows.Forms/TextBoxBase.cs
===================================================================
--- System.Windows.Forms/TextBoxBase.cs	(revision 68864)
+++ System.Windows.Forms/TextBoxBase.cs	(working copy)
@@ -34,6 +34,7 @@
 using System.Drawing.Text;
 using System.Text;
 using System.Runtime.InteropServices;
+using System.Collections;
 
 namespace System.Windows.Forms {
 	[DefaultEvent("TextChanged")]
@@ -252,7 +253,7 @@
 		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
 		public bool CanUndo {
 			get {
-				return undo;
+				return document.undo.UndoLevels != 0;
 			}
 		}
 
@@ -294,24 +295,32 @@
 		[MWFCategory("Appearance")]
 		public string[] Lines {
 			get {
-				string[]	lines;
-				int		i;
-				int		l;
+				int count;
+				ArrayList lines;
 
-				l = document.Lines;
+				count = document.Lines;
 
 				// Handle empty document
-				if ((l == 1) && (document.GetLine(1).text.Length == 0)) {
-					return new string[0];
+				if ((count == 1) && (document.GetLine (1).text.Length == 0)) {
+					return new string [0];
 				}
 
-				lines = new string[l];
+				lines = new ArrayList ();
 
-				for (i = 1; i <= l; i++) {
-					lines[i - 1] = document.GetLine(i).text.ToString();
+				int i = 1;
+				while (i <= count) {
+					Line line;
+					StringBuilder lt = new StringBuilder ();
+
+					do {
+						line = document.GetLine (i++);
+						lt.Append (line.text.ToString ());
+					} while (line.soft_break && i < count);
+
+					lines.Add (lt.ToString ());	
 				}
 
-				return lines;
+				return (string []) lines.ToArray (typeof (string));
 			}
 
 			set {
@@ -324,10 +333,30 @@
 				l = value.Length;
 				brush = ThemeEngine.Current.ResPool.GetSolidBrush(this.ForeColor);
 
+				document.NoRecalc = true;
 				for (i = 0; i < l; i++) {
+
+					// Don't add the last line if it is just an empty line feed
+					// the line feed is reflected in the previous line's soft_break = false
+					if (i == l - 1 && value [i].Length == 0)
+						break;
+
+					bool carriage_return = false;
+					if (value [i].EndsWith ("\r")) {
+						value [i] = value [i].Substring (0, value [i].Length - 1);
+						carriage_return = true;
+					}
+
 					document.Add(i+1, CaseAdjust(value[i]), alignment, Font, brush);
+					if (carriage_return) {
+						Line line = document.GetLine (i + 1);
+						line.carriage_return = true;
+					}
 				}
-				CalculateDocument();
+
+				document.NoRecalc = false;
+
+				// CalculateDocument();
 				OnTextChanged(EventArgs.Empty);
 			}
 		}
@@ -520,6 +549,8 @@
 							sb.Append (Environment.NewLine);
 						line = document.GetLine (i);
 						sb.Append(line.text.ToString());
+						if (line.carriage_return)
+							sb.Append ("\r");
 					}
 					sb.Append(document.GetLine(document.Lines).text.ToString());
 					return sb.ToString();
@@ -538,13 +569,8 @@
 
 						lines = value.Split(new char[] {'\n'});
 
-						for (int i = 0; i < lines.Length; i++) {
-							if (lines[i].EndsWith("\r")) {
-								lines[i] = lines[i].Substring(0, lines[i].Length - 1);
-							}
-						}
 						this.Lines = lines;
-
+							
 						document.PositionCaret (document.GetLine (1), 0);
 						document.SetSelectionToCaret (true);
 
@@ -628,14 +654,9 @@
 		#region Public Instance Methods
 		public void AppendText(string text) {
 			if (multiline) {
-				// Grab the formatting for the last element
-				document.MoveCaret(CaretDirection.CtrlEnd);
-				// grab the end tag
-				if (document.CaretTag.next != null) {
-					document.CaretTag = document.CaretTag.next;
-				}
-				document.Insert(document.CaretLine, document.CaretTag, document.CaretPosition, false, text);
 
+				document.MoveCaret(CaretDirection.CtrlEnd);				
+				document.Insert (document.caret.line, document.caret.tag, document.caret.pos, false, text);
 				CalculateDocument();
 			} else {
 				document.MoveCaret(CaretDirection.CtrlEnd);
@@ -645,9 +666,7 @@
 			}
 
 			document.MoveCaret(CaretDirection.CtrlEnd);
-			document.SetSelectionStart(document.CaretLine, document.CaretPosition);
-			document.SetSelectionEnd(document.CaretLine, document.CaretPosition);
-			selection_length = -1;
+			document.SetSelectionToCaret (true);
 
 			OnTextChanged(EventArgs.Empty);
 		}
Index: System.Windows.Forms/TextControl.cs
===================================================================
--- System.Windows.Forms/TextControl.cs	(revision 68864)
+++ System.Windows.Forms/TextControl.cs	(working copy)
@@ -117,6 +117,7 @@
 		internal int			indent;			// Left indent for the first line
 		internal int			hanging_indent;		// Hanging indent (left indent for all but the first line)
 		internal int			right_indent;		// Right indent for all lines
+		internal bool carriage_return;
 
 
 		// Stuff that's important for the tree
@@ -501,8 +502,8 @@
 
 					if (pos == len) {
 						line = doc.GetLine(this.line_no + 1);
-						if ((line != null) && (line.soft_break)) {
-							// Pull the previous line back into this one
+						if ((line != null) && soft_break) {
+							// Pull the two lines together
 							doc.Combine(this.line_no, this.line_no + 1);
 							len = this.text.Length;
 							retval = true;
@@ -1021,7 +1022,7 @@
 
 			total = 1;
 
-			Console.Write("Line {0} [# {1}], Y: {2}, soft break: {3}, Text {4}",
+			Console.Write("Line {0} [# {1}], Y: {2}, soft: {3},  Text {4}",
 					line.line_no, line.GetHashCode(), line.Y, line.soft_break,
 					line.text != null ? line.text.ToString() : "undefined");
 
@@ -2080,6 +2081,7 @@
 			string[]	ins;
 			int		insert_lines;
 			int		old_line_count;
+			bool carriage_return = false;
 
 			NoRecalc = true;
 
@@ -2092,27 +2094,41 @@
 
 			ins = s.Split(new char[] {'\n'});
 
-			for (int j = 0; j < ins.Length; j++) {
-				if (ins[j].EndsWith("\r")) {
-					ins[j] = ins[j].Substring(0, ins[j].Length - 1);
-				}
-			}
-
 			insert_lines = ins.Length;
 			old_line_count = lines;
-			
+
 			// Bump the text at insertion point a line down if we're inserting more than one line
 			if (insert_lines > 1) {
 				Split(line, pos);
+				line.soft_break = false;
 				// Remainder of start line is now in base_line + 1
 			}
 
+			if (ins [0].EndsWith ("\r")) {
+				ins [0] = ins[0].Substring (0, ins[0].Length - 1);
+				carriage_return = true;
+			}
+
 			// Insert the first line
 			InsertString(tag, pos, ins[0]);
 
+			if (carriage_return) {
+				Line l = GetLine (base_line);
+				l.carriage_return = true;
+			}
+
 			if (insert_lines > 1) {
 				for (i = 1; i < insert_lines; i++) {
+					carriage_return = false;
+					if (ins [i].EndsWith ("\r")) {
+						ins [i] = ins[i].Substring (0, ins[i].Length - 1);
+						carriage_return = true;
+					}
 					Add(base_line + i, ins[i], line.alignment, tag.font, tag.color);
+					if (carriage_return) {
+						Line l = GetLine (base_line + i);
+						l.carriage_return = true;
+					}
 				}
 				if (!s.EndsWith("\n\n")) {
 					this.Combine(base_line + (lines - old_line_count) - 1, base_line + lines - old_line_count);
@@ -2132,7 +2148,6 @@
 				}
 				DisplayCaret ();
 			}
-
 		}
 
 		// Inserts a character at the given position
@@ -2153,6 +2168,7 @@
 			line.text.Insert(pos, s);
 			tag.length += len;
 
+			// TODO: sometimes getting a null tag here when pasting ???
 			tag = tag.next;
 			while (tag != null) {
 				tag.start += len;
@@ -2248,6 +2264,43 @@
 			}
 		}
 
+		internal void DeleteMultiline (Line start_line, int pos, int length)
+		{
+			Marker start = new Marker ();
+			Marker end = new Marker ();
+			int start_index = LineTagToCharIndex (start_line, pos);
+
+			start.line = start_line;
+			start.pos = pos;
+			start.tag = LineTag.FindTag (start_line, pos);
+
+			CharIndexToLineTag (start_index + length, out end.line,
+					out end.tag, out end.pos);
+
+			if (start.line == end.line) {
+				DeleteChars (start.tag, pos, end.pos - pos);
+			} else {
+
+				// Delete first and last lines
+				DeleteChars (start.tag, start.pos, start.line.text.Length - start.pos);
+				DeleteChars (end.line.tags, 0, end.pos);
+
+				int current = start.line.line_no + 1;
+				if (current < end.line.line_no) {
+					for (int i = end.line.line_no - 1; i >= current; i--) {
+						Delete (i);
+					}
+				}
+
+				// BIG FAT WARNING - selection_end.line might be stale due 
+				// to the above Delete() call. DONT USE IT before hitting the end of this method!
+
+				// Join start and end
+				Combine (start.line.line_no, current);
+			}
+		}
+
+		
 		// Deletes n characters at the given position; it will not delete past line limits
 		// pos is 0-based
 		internal void DeleteChars(LineTag tag, int pos, int count) {
@@ -2535,6 +2588,9 @@
 
 				new_line = GetLine(line.line_no + 1);
 
+				line.carriage_return = false;
+				new_line.carriage_return = line.carriage_return;
+				
 				if (soft) {
 					if (move_caret) {
 						caret.line = new_line;
@@ -2565,6 +2621,10 @@
 
 			// Now transfer our tags from this line to the next
 			new_line = GetLine(line.line_no + 1);
+
+			line.carriage_return = false;
+			new_line.carriage_return = line.carriage_return;
+
 			line.recalc = true;
 			new_line.recalc = true;
 
@@ -3303,6 +3363,8 @@
 		internal void ReplaceSelection(string s, bool select_new) {
 			int		i;
 
+			undo.BeginCompoundAction ();
+
 			int selection_start_pos = LineTagToCharIndex (selection_start.line, selection_start.pos);
 			// First, delete any selected text
 			if ((selection_start.pos != selection_end.pos) || (selection_start.line != selection_end.line)) {
@@ -3344,7 +3406,8 @@
 			}
 
 			Insert(selection_start.line, null, selection_start.pos, true, s);
-
+			undo.RecordInsertString (selection_start.line, selection_start.pos, s);
+			
 			if (!select_new) {
 				CharIndexToLineTag(selection_start_pos + s.Length, out selection_start.line,
 						out selection_start.tag, out selection_start.pos);
@@ -3370,6 +3433,8 @@
 
 				SetSelectionVisible (true);
 			}
+
+			undo.EndCompoundAction ();
 		}
 
 		internal void CharIndexToLineTag(int index, out Line line_out, out LineTag tag_out, out int pos) {
@@ -4564,6 +4629,8 @@
 			DeleteChars,
 			CursorMove,
 			Mark,
+			CompoundBegin,
+			CompoundEnd,
 		}
 
 		internal class Action {
@@ -4653,23 +4720,40 @@
 
 		internal void Undo() {
 			Action action;
+			int compound_stack = 0;
 
 			if (undo_actions.Count == 0) {
 				return;
 			}
 
-			action = (Action)undo_actions.Pop();
+			
 
-			// Put onto redo stack
-			redo_actions.Push(action);
+			do {
+				action = (Action)undo_actions.Pop();
 
-			// Do the thing
-			switch(action.type) {
+				// Put onto redo stack
+				redo_actions.Push(action);
+
+				// Do the thing
+				switch(action.type) {
+				case ActionType.CompoundEnd:
+					compound_stack++;
+					break;
+
+				case ActionType.CompoundBegin:
+					compound_stack--;
+					break;
+
+				case ActionType.InsertString:
+					document.DeleteMultiline (document.GetLine (action.line_no),
+							action.pos, ((string) action.data).Length + 1);
+					break;
+
 				case ActionType.InsertChar: {
 					// FIXME - implement me
 					break;
 				}
-
+					
 				case ActionType.DeleteChars: {
 					this.Insert(document.GetLine(action.line_no), action.pos, (Line)action.data);
 					Undo();	// Grab the cursor location
@@ -4699,7 +4783,8 @@
 					//if (document.CaretMoved != null) document.CaretMoved(this, EventArgs.Empty);
 					break;
 				}
-			}
+				}
+			} while (compound_stack > 0);
 		}
 
 		internal void Redo() {
@@ -4710,6 +4795,23 @@
 		#endregion	// Internal Methods
 
 		#region Private Methods
+
+		public void BeginCompoundAction ()
+		{
+			Action cb = new Action ();
+			cb.type = ActionType.CompoundBegin;
+
+			undo_actions.Push (cb);
+		}
+
+		public void EndCompoundAction ()
+		{
+			Action ce = new Action ();
+			ce.type = ActionType.CompoundEnd;
+
+			undo_actions.Push (ce);
+		}
+
 		// pos = 1-based
 		public void RecordDeleteChars(Line line, int pos, int length) {
 			RecordDelete(line, pos, line, pos + length - 1);
@@ -4733,6 +4835,18 @@
 			undo_actions.Push(a);
 		}
 
+		public void RecordInsertString (Line line, int pos, string str)
+		{
+			Action a = new Action ();
+
+			a.type = ActionType.InsertString;
+			a.data = str;
+			a.line_no = line.line_no;
+			a.pos = pos;
+
+			undo_actions.Push (a);
+		}
+
 		public void RecordCursor() {
 			if (document.caret.line == null) {
 				return;
_______________________________________________
Mono-winforms-list maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-winforms-list

Reply via email to