Author: jackson
Date: 2007-01-25 11:39:01 -0500 (Thu, 25 Jan 2007)
New Revision: 71677
Modified:
trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs
trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs
Log:
* TextControl.cs: Add a Suspend/Resume for updating, basically
* the
same as the Suspend/Resume for recalc, except this will do
actual
Invalidates.
- New Undo manager, works much like the MS version.
- Implemented Redo
* TextBoxBase.cs: The Cut operation is undoable.
Modified: trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
===================================================================
--- trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
2007-01-25 16:37:25 UTC (rev 71676)
+++ trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
2007-01-25 16:39:01 UTC (rev 71677)
@@ -1,3 +1,12 @@
+2007-01-25 Jackson Harper <[EMAIL PROTECTED]>
+
+ * TextControl.cs: Add a Suspend/Resume for updating, basically the
+ same as the Suspend/Resume for recalc, except this will do actual
+ Invalidates.
+ - New Undo manager, works much like the MS version.
+ - Implemented Redo
+ * TextBoxBase.cs: The Cut operation is undoable.
+
2007-01-25 Rolf Bjarne Kvinge <[EMAIL PROTECTED]>
* XplatUIWin32.cs: Set SWP_NOACTIVATE in RequestNCRecalc as well,
Modified:
trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs
===================================================================
--- trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs
2007-01-25 16:37:25 UTC (rev 71676)
+++ trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextBoxBase.cs
2007-01-25 16:39:01 UTC (rev 71677)
@@ -704,7 +704,10 @@
o.SetData(DataFormats.Rtf,
((RichTextBox)this).SelectedRtf);
}
Clipboard.SetDataObject (o);
- document.ReplaceSelection ("", false);
+
+ document.undo.BeginUserAction (Locale.GetText ("Cut"));
+ document.ReplaceSelection (String.Empty, false);
+ document.undo.EndUserAction ();
}
public void Paste() {
Modified:
trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs
===================================================================
--- trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs
2007-01-25 16:37:25 UTC (rev 71676)
+++ trunk/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs
2007-01-25 16:39:01 UTC (rev 71677)
@@ -725,6 +725,10 @@
private int recalc_end;
private bool recalc_optimize;
+ private int update_suspended;
+ private bool update_pending;
+ private int update_start = 1;
+
internal bool multiline;
internal bool wrap;
@@ -997,6 +1001,22 @@
}
}
+ internal void SuspendUpdate ()
+ {
+ update_suspended++;
+ }
+
+ internal void ResumeUpdate (bool immediate_update)
+ {
+ if (update_suspended > 0)
+ update_suspended--;
+
+ if (immediate_update && update_suspended == 0 &&
update_pending) {
+ UpdateView (GetLine (update_start), 0);
+ update_pending = false;
+ }
+ }
+
// For debugging
internal int DumpTree(Line line, bool with_tags) {
int total;
@@ -1286,11 +1306,11 @@
return;
}
- if (recalc_suspended > 0) {
- recalc_start = Math.Min (recalc_start,
line.line_no);
- recalc_end = Math.Max (recalc_end,
line.line_no);
- recalc_optimize = true;
- recalc_pending = true;
+ if (update_suspended > 0) {
+ update_start = Math.Min (update_start,
line.line_no);
+ // update_end = Math.Max (update_end,
line.line_no);
+ // recalc_optimize = true;
+ update_pending = true;
return;
}
@@ -1829,7 +1849,6 @@
line_no = start;
- g.FillRectangle (new SolidBrush (Color.White), clip);
#if Debug
DateTime n = DateTime.Now;
Console.WriteLine ("Started drawing: {0}s
{1}ms", n.Second, n.Millisecond);
@@ -1899,6 +1918,7 @@
}
if (tag.back_color != null) {
+ Console.WriteLine ("TAG BACK
COLOR: {0}", tag.back_color.Color);
g.FillRectangle
(tag.back_color, tag.X + line.align_shift - viewport_x,
line.Y +
tag.shift - viewport_y, tag.width, line.height);
}
@@ -2099,6 +2119,7 @@
line.Grow(1);
line.recalc = true;
+ undo.RecordTyping (line, pos, ch);
UpdateView(line, pos);
}
@@ -2130,6 +2151,7 @@
UpdateCaret();
SetSelectionToCaret(true);
}
+
}
internal void InsertImage (LineTag tag, int pos, Image image)
@@ -2175,6 +2197,8 @@
CharIndexToLineTag (start_index + length, out end.line,
out end.tag, out end.pos);
+ SuspendUpdate ();
+
if (start.line == end.line) {
DeleteChars (start.tag, pos, end.pos - pos);
} else {
@@ -2196,6 +2220,8 @@
// Join start and end
Combine (start.line.line_no, current);
}
+
+ ResumeUpdate (true);
}
@@ -2217,7 +2243,7 @@
line.text.Remove(pos, count);
// Make sure the tag points to the right spot
- while ((tag != null) && (tag.start + tag.length - 1) <=
pos) {
+ while ((tag != null) && (tag.end) < pos) {
tag = tag.next;
}
@@ -3265,7 +3291,7 @@
// First, delete any selected text
if ((selection_start.pos != selection_end.pos) ||
(selection_start.line != selection_end.line)) {
if (!multiline || (selection_start.line ==
selection_end.line)) {
-
undo.RecordDeleteChars(selection_start.line, selection_start.pos + 1,
selection_end.pos - selection_start.pos);
+ undo.RecordDeleteString
(selection_start.line, selection_start.pos, selection_end.line,
selection_end.pos);
DeleteChars(selection_start.tag,
selection_start.pos, selection_end.pos - selection_start.pos);
@@ -3278,7 +3304,7 @@
start = selection_start.line.line_no;
end = selection_end.line.line_no;
- undo.RecordDelete(selection_start.line,
selection_start.pos + 1, selection_end.line, selection_end.pos);
+ undo.RecordDeleteString
(selection_start.line, selection_start.pos, selection_end.line,
selection_end.pos);
// Delete first line
DeleteChars(selection_start.tag,
selection_start.pos, selection_start.line.text.Length - selection_start.pos);
@@ -4591,11 +4617,12 @@
internal class UndoManager {
internal enum ActionType {
- InsertChar,
+
+ Typing,
+
+ // This is basically just cut & paste
InsertString,
- DeleteChar,
- DeleteChars,
- Mark,
+ DeleteString,
UserActionBegin,
UserActionEnd
@@ -4615,6 +4642,9 @@
private int caret_line;
private int caret_pos;
+
+ // When performing an action, we lock the queue, so that the
action can't be undone
+ private bool locked;
#endregion // Local Variables
#region Constructors
@@ -4628,42 +4658,32 @@
#region Properties
internal bool CanUndo {
- get {
- foreach (Action action in undo_actions) {
- if (action.type ==
ActionType.UserActionEnd)
- return true;
- }
- return false;
- }
+ get { return undo_actions.Count > 0; }
}
internal bool CanRedo {
- get {
- foreach (Action action in undo_actions) {
- if (action.type ==
ActionType.UserActionBegin)
- return true;
- }
- return false;
- }
+ get { return redo_actions.Count > 0; }
}
- internal string UndoActionName
- {
+ internal string UndoActionName {
get {
foreach (Action action in undo_actions) {
if (action.type ==
ActionType.UserActionBegin)
return (string) action.data;
+ if (action.type == ActionType.Typing)
+ return Locale.GetText
("Typing");
}
return String.Empty;
}
}
- internal string RedoActionName
- {
+ internal string RedoActionName {
get {
foreach (Action action in redo_actions) {
if (action.type ==
ActionType.UserActionBegin)
return (string) action.data;
+ if (action.type == ActionType.Typing)
+ return Locale.GetText
("Typing");
}
return String.Empty;
}
@@ -4671,59 +4691,145 @@
#endregion // Properties
#region Internal Methods
- internal void Clear() {
+ internal void Clear ()
+ {
undo_actions.Clear();
redo_actions.Clear();
}
- internal void Undo() {
+ internal void Undo ()
+ {
Action action;
- int user_action_depth = 0;
+ bool user_action_finished = false;
- if (undo_actions.Count == 0) {
+ if (undo_actions.Count == 0)
return;
- }
+ // Nuke the redo queue
+ redo_actions.Clear ();
+
+ locked = true;
do {
- action = (Action) undo_actions.Pop();
+ Line start;
+ action = (Action) undo_actions.Pop ();
// Put onto redo stack
redo_actions.Push(action);
// Do the thing
switch(action.type) {
+
+ case ActionType.UserActionBegin:
+ user_action_finished = true;
+ break;
+
case ActionType.UserActionEnd:
- user_action_depth++;
+ // noop
break;
+ case ActionType.InsertString:
+ start = document.GetLine
(action.line_no);
+ document.SuspendUpdate ();
+ document.DeleteMultiline (start,
action.pos, ((string) action.data).Length + 1);
+ document.PositionCaret (start,
action.pos);
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+ break;
+
+ case ActionType.Typing:
+ start = document.GetLine
(action.line_no);
+ document.SuspendUpdate ();
+ document.DeleteMultiline (start,
action.pos, ((StringBuilder) action.data).Length);
+ document.PositionCaret (start,
action.pos);
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+
+ // This is an open ended operation, so
only a single typing operation can be undone at once
+ user_action_finished = true;
+ break;
+
+ case ActionType.DeleteString:
+ start = document.GetLine
(action.line_no);
+ document.SuspendUpdate ();
+ Insert (start, action.pos, (Line)
action.data, true);
+ document.ResumeUpdate (true);
+ break;
+ }
+ } while (!user_action_finished && undo_actions.Count >
0);
+
+ locked = false;
+ }
+
+ internal void Redo ()
+ {
+ Action action;
+ bool user_action_finished = false;
+
+ if (redo_actions.Count == 0)
+ return;
+
+ // You can't undo anything after redoing
+ undo_actions.Clear ();
+
+ locked = true;
+ do {
+ Line start;
+ int start_index;
+
+ action = (Action) redo_actions.Pop ();
+
+ switch (action.type) {
+
case ActionType.UserActionBegin:
- user_action_depth--;
+ // Noop
break;
+ case ActionType.UserActionEnd:
+ user_action_finished = true;
+ break;
+
case ActionType.InsertString:
- document.DeleteMultiline
(document.GetLine (action.line_no),
- action.pos, ((string)
action.data).Length + 1);
- document.PositionCaret
(document.GetLine (action.line_no), action.pos);
+ start = document.GetLine
(action.line_no);
+ document.SuspendUpdate ();
+ start_index =
document.LineTagToCharIndex (start, action.pos);
+ document.InsertString (start,
action.pos, (string) action.data);
+ document.CharIndexToLineTag
(start_index + ((string) action.data).Length,
+ out
document.caret.line, out document.caret.tag,
+ out document.caret.pos);
+ document.UpdateCaret ();
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
break;
- case ActionType.InsertChar: {
- // FIXME - implement me
+ case ActionType.Typing:
+ start = document.GetLine
(action.line_no);
+ document.SuspendUpdate ();
+ start_index =
document.LineTagToCharIndex (start, action.pos);
+ document.InsertString (start,
action.pos, ((StringBuilder) action.data).ToString ());
+ document.CharIndexToLineTag
(start_index + ((StringBuilder) action.data).Length,
+ out
document.caret.line, out document.caret.tag,
+ out document.caret.pos);
+ document.UpdateCaret ();
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+
+ // This is an open ended operation, so
only a single typing operation can be undone at once
+ user_action_finished = true;
break;
- }
-
- case ActionType.DeleteChars: {
-
this.Insert(document.GetLine(action.line_no), action.pos, (Line)action.data);
-
+
+ case ActionType.DeleteString:
+ start = document.GetLine
(action.line_no);
+ document.SuspendUpdate ();
+ document.DeleteMultiline (start,
action.pos, ((Line) action.data).text.Length);
+ document.PositionCaret (start,
action.pos);
+ document.SetSelectionToCaret (true);
+ document.ResumeUpdate (true);
+
break;
}
- }
- } while (user_action_depth >= 0 && undo_actions.Count >
0);
- }
+ } while (!user_action_finished && redo_actions.Count >
0);
- internal void Redo() {
- if (redo_actions.Count == 0) {
- return;
- }
+ locked = false;
}
#endregion // Internal Methods
@@ -4731,6 +4837,9 @@
public void BeginUserAction (string name)
{
+ if (locked)
+ return;
+
Action ua = new Action ();
ua.type = ActionType.UserActionBegin;
ua.data = name;
@@ -4740,35 +4849,37 @@
public void EndUserAction ()
{
+ if (locked)
+ return;
+
Action ua = new Action ();
ua.type = ActionType.UserActionEnd;
undo_actions.Push (ua);
}
- // pos = 1-based
- public void RecordDeleteChars(Line line, int pos, int length) {
- RecordDelete(line, pos, line, pos + length - 1);
- }
-
// start_pos, end_pos = 1 based
- public void RecordDelete(Line start_line, int start_pos, Line
end_line, int end_pos) {
- Line l;
- Action a;
+ public void RecordDeleteString (Line start_line, int start_pos,
Line end_line, int end_pos)
+ {
+ if (locked)
+ return;
- l = Duplicate(start_line, start_pos, end_line, end_pos);
+ Action a = new Action ();
- a = new Action();
- a.type = ActionType.DeleteChars;
- a.data = l;
+ // We cant simply store the string, because then
formatting would be lost
+ a.type = ActionType.DeleteString;
a.line_no = start_line.line_no;
- a.pos = start_pos - 1;
+ a.pos = start_pos;
+ a.data = Duplicate (start_line, start_pos, end_line,
end_pos);
undo_actions.Push(a);
}
public void RecordInsertString (Line line, int pos, string str)
{
+ if (locked || str.Length == 0)
+ return;
+
Action a = new Action ();
a.type = ActionType.InsertString;
@@ -4779,6 +4890,30 @@
undo_actions.Push (a);
}
+ public void RecordTyping (Line line, int pos, char ch)
+ {
+ if (locked)
+ return;
+
+ Action a = null;
+
+ if (undo_actions.Count > 0)
+ a = (Action) undo_actions.Peek ();
+
+ if (a == null || a.type != ActionType.Typing) {
+ a = new Action ();
+ a.type = ActionType.Typing;
+ a.data = new StringBuilder ();
+ a.line_no = line.line_no;
+ a.pos = pos;
+
+ undo_actions.Push (a);
+ }
+
+ StringBuilder data = (StringBuilder) a.data;
+ data.Append (ch);
+ }
+
// start_pos = 1-based
// end_pos = 1-based
public Line Duplicate(Line start_line, int start_pos, Line
end_line, int end_pos) {
@@ -4810,10 +4945,10 @@
}
// Text for the tag
- line.text = new
StringBuilder(current.text.ToString(start - 1, end - start + 1));
+ line.text = new StringBuilder
(current.text.ToString (start, end - start));
// Copy tags from start to start+length onto
new line
- current_tag = current.FindTag(start - 1);
+ current_tag = current.FindTag (start);
while ((current_tag != null) &&
(current_tag.start < end)) {
if ((current_tag.start <= start) &&
(start < (current_tag.start + current_tag.length))) {
// start tag is within this tag
@@ -4856,7 +4991,8 @@
}
// Insert multi-line text at the given position; use formatting
at insertion point for inserted text
- internal void Insert(Line line, int pos, Line insert) {
+ internal void Insert(Line line, int pos, Line insert, bool
select)
+ {
Line current;
LineTag tag;
int offset;
@@ -4884,7 +5020,7 @@
tag.next = insert.tags;
line.text.Insert(offset,
insert.text.ToString());
-
+
// Adjust start locations
tag = tag.next;
while (tag != null) {
@@ -4894,6 +5030,12 @@
}
// Put it back together
document.Combine(line.line_no, line.line_no +
1);
+
+ if (select) {
+ document.SetSelectionStart (line, pos);
+ document.SetSelectionEnd (line, pos +
insert.text.Length);
+ }
+
document.UpdateView(line, pos);
return;
}
@@ -4901,6 +5043,7 @@
first = line;
lines = 1;
current = insert;
+
while (current != null) {
if (current == insert) {
// Inserting the first line we split
the line (and make space)
_______________________________________________
Mono-patches maillist - [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches