X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FManaged.Windows.Forms%2FSystem.Windows.Forms%2FTextControl.cs;h=71e5f4207c888601bb5fc7ed4eb7d8a1cd37104b;hb=fe405951f51ed81b13956a3188460c9c281f605f;hp=bee98aef51273a6f1ebc13847f9ce98d09e86fe7;hpb=3d027b086d5a92bbf48d7a0420272b65a1e811fe;p=mono.git diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs index bee98aef512..71e5f4207c8 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/TextControl.cs @@ -223,14 +223,14 @@ namespace System.Windows.Forms { internal int viewport_x; internal int viewport_y; // The visible area of the document + internal int offset_x; + internal int offset_y; internal int viewport_width; internal int viewport_height; internal int document_x; // Width of the document internal int document_y; // Height of the document - internal Rectangle invalid; - internal int crlf_size; // 1 or 2, depending on whether we use \r\n or just \n internal TextBoxBase owner; // Who's owning us? @@ -285,6 +285,9 @@ namespace System.Windows.Forms { viewport_x = 0; viewport_y = 0; + offset_x = 0; + offset_y = 0; + crlf_size = 2; // Default selection is empty @@ -309,6 +312,7 @@ namespace System.Windows.Forms { } } + // UIA: Method used via reflection in TextRangeProvider internal int Lines { get { return lines; @@ -425,6 +429,32 @@ namespace System.Windows.Forms { } } + internal int OffsetX + { + get + { + return offset_x; + } + + set + { + offset_x = value; + } + } + + internal int OffsetY + { + get + { + return offset_y; + } + + set + { + offset_y = value; + } + } + internal int ViewPortWidth { get { return viewport_width; @@ -629,11 +659,14 @@ namespace System.Windows.Forms { private void SetSelectionVisible (bool value) { + bool old_selection_visible = selection_visible; selection_visible = value; // cursor and selection are enemies, we can't have both in the same room at the same time if (owner.IsHandleCreated && !owner.show_caret_w_selection) XplatUI.CaretVisible (owner.Handle, !selection_visible); + if (UIASelectionChanged != null && (selection_visible || old_selection_visible)) + UIASelectionChanged (this, EventArgs.Empty); } private void DecrementLines(int line_no) { @@ -838,7 +871,11 @@ namespace System.Windows.Forms { // Lineheight changed, invalidate the rest of the document if ((line.Y - viewport_y) >=0 ) { // We formatted something that's in view, only draw parts of the screen - owner.Invalidate(new Rectangle(0, line.Y - viewport_y, viewport_width, owner.Height - line.Y - viewport_y)); + owner.Invalidate(new Rectangle( + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + owner.Height - (line.Y - viewport_y))); } else { // The tag was above the visible area, draw everything owner.Invalidate(); @@ -846,17 +883,29 @@ namespace System.Windows.Forms { } else { switch(line.alignment) { case HorizontalAlignment.Left: { - owner.Invalidate(new Rectangle(line.X + (int)line.widths[pos] - viewport_x - 1, line.Y - viewport_y, viewport_width, line.height + 1)); + owner.Invalidate(new Rectangle( + line.X + ((int)line.widths[pos] - viewport_x - 1) + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + line.height + 1)); break; } case HorizontalAlignment.Center: { - owner.Invalidate(new Rectangle(line.X, line.Y - viewport_y, viewport_width, line.height + 1)); + owner.Invalidate(new Rectangle( + line.X + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + line.height + 1)); break; } case HorizontalAlignment.Right: { - owner.Invalidate(new Rectangle(line.X, line.Y - viewport_y, (int)line.widths[pos + 1] - viewport_x + line.X, line.height + 1)); + owner.Invalidate(new Rectangle( + line.X + offset_x, + line.Y - viewport_y + offset_y, + (int)line.widths[pos + 1] - viewport_x + line.X, + line.height + 1)); break; } } @@ -880,29 +929,32 @@ namespace System.Windows.Forms { int start_line_top = line.Y; - int end_line_bottom; - Line end_line; - - end_line = GetLine (line.line_no + line_count); + Line end_line = GetLine (line.line_no + line_count); if (end_line == null) end_line = GetLine (lines); - - end_line_bottom = end_line.Y + end_line.height; + if (end_line == null) + return; + + int end_line_bottom = end_line.Y + end_line.height; if (RecalculateDocument(owner.CreateGraphicsInternal(), line.line_no, line.line_no + line_count, true)) { // Lineheight changed, invalidate the rest of the document if ((line.Y - viewport_y) >=0 ) { // We formatted something that's in view, only draw parts of the screen - owner.Invalidate(new Rectangle(0, line.Y - viewport_y, viewport_width, owner.Height - line.Y - viewport_y)); + owner.Invalidate(new Rectangle( + offset_x, + line.Y - viewport_y + offset_y, + viewport_width, + owner.Height - (line.Y - viewport_y))); } else { // The tag was above the visible area, draw everything owner.Invalidate(); } } else { - int x = 0 - viewport_x; + int x = 0 - viewport_x + offset_x; int w = viewport_width; - int y = Math.Min (start_line_top - viewport_y, line.Y - viewport_y); + int y = Math.Min (start_line_top - viewport_y, line.Y - viewport_y) + offset_y; int h = Math.Max (end_line_bottom - y, end_line.Y + end_line.height - y); owner.Invalidate (new Rectangle (x, y, w, h)); @@ -988,7 +1040,7 @@ namespace System.Windows.Forms { } } else { if (char.IsLetterOrDigit (line_no_breaks_string [i]) == false && - "@-/:~.?=".IndexOf (line_no_breaks_string [i].ToString ()) == -1) { + "@-/:~.?=_&".IndexOf (line_no_breaks_string [i].ToString ()) == -1) { link_end = i - 1; line_no_breaks_index = i; break; @@ -1093,11 +1145,7 @@ namespace System.Windows.Forms { int best_index = -1; for (int i = 0; i < needles.Length; i++) { -#if NET_2_0 int index = haystack.IndexOf (needles [i], start_index, StringComparison.InvariantCultureIgnoreCase); -#else - int index = haystack.ToLower().IndexOf(needles[i], start_index); -#endif if (index > -1) { if (term_found > -1) { @@ -1200,7 +1248,9 @@ namespace System.Windows.Forms { if (owner.Focused) { if (caret.height != caret.tag.Height) XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + XplatUI.SetCaretPos(owner.Handle, + offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); @@ -1226,7 +1276,9 @@ namespace System.Windows.Forms { if (owner.ShowSelection && (!selection_visible || owner.show_caret_w_selection)) { XplatUI.CreateCaret (owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + XplatUI.SetCaretPos(owner.Handle, + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x + offset_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); } if (CaretMoved != null) CaretMoved(this, EventArgs.Empty); @@ -1235,7 +1287,9 @@ namespace System.Windows.Forms { internal void CaretHasFocus() { if ((caret.tag != null) && owner.IsHandleCreated) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos(owner.Handle, (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + XplatUI.SetCaretPos(owner.Handle, + offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); DisplayCaret (); } @@ -1281,7 +1335,9 @@ namespace System.Windows.Forms { if (owner.Focused) { XplatUI.CreateCaret(owner.Handle, caret_width, caret.height); - XplatUI.SetCaretPos (owner.Handle, (int) caret.tag.Line.widths [caret.pos] + caret.line.X - viewport_x, caret.line.Y + viewport_y + caret_shift); + XplatUI.SetCaretPos (owner.Handle, + offset_x + (int) caret.tag.Line.widths [caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + viewport_y + caret_shift); DisplayCaret (); } @@ -1303,7 +1359,9 @@ namespace System.Windows.Forms { } if (owner.Focused) { - XplatUI.SetCaretPos(owner.Handle, (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); + XplatUI.SetCaretPos(owner.Handle, + offset_x + (int)caret.tag.Line.widths[caret.pos] + caret.line.X - viewport_x, + offset_y + caret.line.Y + caret.tag.Shift - viewport_y + caret_shift); DisplayCaret (); } @@ -1620,6 +1678,22 @@ namespace System.Windows.Forms { Console.WriteLine (""); } + // UIA: Used via reflection by TextProviderBehavior + internal void GetVisibleLineIndexes (Rectangle clip, out int start, out int end) + { + if (multiline) { + /* Expand the region slightly to be sure to + * paint the full extent of the line of text. + * See bug 464464. + */ + start = GetLineByPixel(clip.Top + viewport_y - offset_y - 1, false).line_no; + end = GetLineByPixel(clip.Bottom + viewport_y - offset_y + 1, false).line_no; + } else { + start = GetLineByPixel(clip.Left + viewport_x - offset_x, false).line_no; + end = GetLineByPixel(clip.Right + viewport_x - offset_x, false).line_no; + } + } + internal void Draw (Graphics g, Rectangle clip) { Line line; // Current line being drawn @@ -1632,14 +1706,7 @@ namespace System.Windows.Forms { Color current_color; // First, figure out from what line to what line we need to draw - - if (multiline) { - start = GetLineByPixel(clip.Top + viewport_y, false).line_no; - end = GetLineByPixel(clip.Bottom + viewport_y, false).line_no; - } else { - start = GetLineByPixel(clip.Left + viewport_x, false).line_no; - end = GetLineByPixel(clip.Right + viewport_x, false).line_no; - } + GetVisibleLineIndexes (clip, out start, out end); // remove links in the list (used for mouse down events) that are within the clip area. InvalidateLinks (clip); @@ -1653,7 +1720,7 @@ namespace System.Windows.Forms { /// Make sure that we aren't drawing one more line then we need to line = GetLine (end - 1); - if (line != null && clip.Bottom == line.Y + line.height - viewport_y) + if (line != null && clip.Bottom == offset_y + line.Y + line.height - viewport_y) end--; line_no = start; @@ -1669,9 +1736,9 @@ namespace System.Windows.Forms { // Non multiline selection can be handled outside of the loop if (!multiline && selection_visible && owner.ShowSelection) { g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), - selection_start.line.widths [selection_start.pos] + + offset_x + selection_start.line.widths [selection_start.pos] + selection_start.line.X - viewport_x, - selection_start.line.Y, + offset_y + selection_start.line.Y, (selection_end.line.X + selection_end.line.widths [selection_end.pos]) - (selection_start.line.X + selection_start.line.widths [selection_start.pos]), selection_start.line.height); @@ -1679,7 +1746,7 @@ namespace System.Windows.Forms { while (line_no <= end) { line = GetLine (line_no); - float line_y = line.Y - viewport_y; + float line_y = line.Y - viewport_y + offset_y; tag = line.tags; if (!calc_pass) { @@ -1715,7 +1782,7 @@ namespace System.Windows.Forms { } else if (multiline) { // lets draw some selection baby!! (non multiline selection is drawn outside the loop) g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight), - line.widths [line_selection_start - 1] + line.X - viewport_x, + offset_x + line.widths [line_selection_start - 1] + line.X - viewport_x, line_y, line.widths [line_selection_end - 1] - line.widths [line_selection_start - 1], line.height); } @@ -1730,13 +1797,15 @@ namespace System.Windows.Forms { continue; } - if (((tag.X + tag.Width) < (clip.Left - viewport_x)) && (tag.X > (clip.Right - viewport_x))) { + if (((tag.X + tag.Width) < (clip.Left - viewport_x - offset_x)) && + (tag.X > (clip.Right - viewport_x - offset_x))) { tag = tag.Next; continue; } if (tag.BackColor != Color.Empty) { - g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (tag.BackColor), tag.X + line.X - viewport_x, + g.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (tag.BackColor), + offset_x + tag.X + line.X - viewport_x, line_y + tag.Shift, tag.Width, line.height); } @@ -1771,7 +1840,7 @@ namespace System.Windows.Forms { Rectangle text_size; tag.Draw (g, current_color, - line.X - viewport_x, + offset_x + line.X - viewport_x, line_y + tag.Shift, old_tag_pos - 1, Math.Min (tag.Start + tag.Length, tag_pos) - 1, text.ToString (), out text_size, tag.IsLink); @@ -1878,6 +1947,22 @@ namespace System.Windows.Forms { return string.Empty; } + internal LineEnding StringToLineEnding (string ending) + { + switch (ending) { + case "\r": + return LineEnding.Limp; + case "\r\n": + return LineEnding.Hard; + case "\r\r\n": + return LineEnding.Soft; + case "\n": + return LineEnding.Rich; + default: + return LineEnding.None; + } + } + internal void Insert (Line line, int pos, bool update_caret, string s) { Insert (line, pos, update_caret, s, line.FindTag (pos)); @@ -1899,6 +1984,11 @@ namespace System.Windows.Forms { base_line = line.line_no; old_line_count = lines; + // Discard chars after any possible -unlikely- end of file + int eof_index = s.IndexOf ('\0'); + if (eof_index != -1) + s = s.Substring (0, eof_index); + break_index = GetLineEnding (s, 0, out ending, LineEnding.Hard | LineEnding.Rich); // There are no line feeds in our text to be pasted @@ -1941,6 +2031,9 @@ namespace System.Windows.Forms { // Allow the document to recalculate things ResumeRecalc (false); + // Update our character count + CharCount += s.Length; + UpdateView (line, lines - old_line_count + 1, pos); // Move the caret to the end of the inserted text if requested @@ -1966,6 +2059,9 @@ namespace System.Windows.Forms { { caret.line.InsertString (caret.pos, ch.ToString(), caret.tag); + // Update our character count + CharCount++; + undo.RecordTyping (caret.line, caret.pos, ch); UpdateView (caret.line, caret.pos); @@ -2095,10 +2191,17 @@ namespace System.Windows.Forms { if ((pos == 0 && forward == false) || (pos == line.text.Length && forward == true)) return; - if (forward) + undo.BeginUserAction ("Delete"); + + if (forward) { + undo.RecordDeleteString (line, pos, line, pos + 1); DeleteChars (line, pos, 1); - else + } else { + undo.RecordDeleteString (line, pos - 1, line, pos); DeleteChars (line, pos - 1, 1); + } + + undo.EndUserAction (); } // Combine two lines @@ -2627,9 +2730,9 @@ namespace System.Windows.Forms { #endif owner.Invalidate(new Rectangle ( - (int)l1.widths[p1] + l1.X - viewport_x, - l1.Y - viewport_y, - endpoint - (int)l1.widths[p1] + 1, + offset_x + (int)l1.widths[p1] + l1.X - viewport_x, + offset_y + l1.Y - viewport_y, + endpoint - (int) l1.widths [p1] + 1, l1.height)); return; } @@ -2641,7 +2744,11 @@ namespace System.Windows.Forms { // Three invalidates: // First line from start - owner.Invalidate(new Rectangle((int)l1.widths[p1] + l1.X - viewport_x, l1.Y - viewport_y, viewport_width, l1.height)); + owner.Invalidate(new Rectangle( + offset_x + (int)l1.widths[p1] + l1.X - viewport_x, + offset_y + l1.Y - viewport_y, + viewport_width, + l1.height)); // lines inbetween @@ -2649,7 +2756,11 @@ namespace System.Windows.Forms { int y; y = GetLine(l1.line_no + 1).Y; - owner.Invalidate(new Rectangle(0, y - viewport_y, viewport_width, l2.Y - y)); + owner.Invalidate(new Rectangle( + offset_x, + offset_y + y - viewport_y, + viewport_width, + l2.Y - y)); #if Debug Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} Middle => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, 0, y - viewport_y, viewport_width, l2.Y - y); @@ -2658,10 +2769,14 @@ namespace System.Windows.Forms { // Last line to end - owner.Invalidate(new Rectangle((int)l2.widths[0] + l2.X - viewport_x, l2.Y - viewport_y, (int)l2.widths[p2] + 1, l2.height)); + owner.Invalidate(new Rectangle( + offset_x + (int)l2.widths[0] + l2.X - viewport_x, + offset_y + l2.Y - viewport_y, + (int)l2.widths[p2] + 1, + l2.height)); + #if Debug Console.WriteLine("Invaliding from {0}:{1} to {2}:{3} End => x={4}, y={5}, {6}x{7}", l1.line_no, p1, l2.line_no, p2, (int)l2.widths[0] + l2.X - viewport_x, l2.Y - viewport_y, (int)l2.widths[p2] + 1, l2.height); - #endif } @@ -3055,11 +3170,11 @@ namespace System.Windows.Forms { start = selection_start.line.line_no; end = selection_end.line.line_no; - sb.Append(selection_start.line.text.ToString(selection_start.pos, selection_start.line.text.Length - selection_start.pos) + Environment.NewLine); + sb.Append(selection_start.line.text.ToString(selection_start.pos, selection_start.line.text.Length - selection_start.pos)); if ((start + 1) < end) { for (i = start + 1; i < end; i++) { - sb.Append(GetLine(i).text.ToString() + Environment.NewLine); + sb.Append(GetLine(i).text.ToString()); } } @@ -3264,6 +3379,8 @@ namespace System.Windows.Forms { } + // UIA: Method used via reflection in TextRangeProvider + /// Give it a Line number and it returns the Line object at with that line number internal Line GetLine(int LineNo) { Line line = document; @@ -3388,11 +3505,16 @@ namespace System.Windows.Forms { return last; } + // UIA: Method used via reflection in TextProviderBehavior + // Give it x/y pixel coordinates and it returns the Tag at that position internal LineTag FindCursor (int x, int y, out int index) { Line line; + x -= offset_x; + y -= offset_y; + line = GetLineByPixel (multiline ? y : x, false); LineTag tag = line.GetTag (x); @@ -3899,6 +4021,7 @@ namespace System.Windows.Forms { internal event EventHandler WidthChanged; internal event EventHandler HeightChanged; internal event EventHandler LengthChanged; + internal event EventHandler UIASelectionChanged; #endregion // Events #region Administrative @@ -4059,16 +4182,13 @@ namespace System.Windows.Forms { redo_actions.Clear(); } - internal void Undo () + internal bool Undo () { Action action; bool user_action_finished = false; if (undo_actions.Count == 0) - return; - - // Nuke the redo queue - redo_actions.Clear (); + return false; locked = true; do { @@ -4120,18 +4240,17 @@ namespace System.Windows.Forms { } while (!user_action_finished && undo_actions.Count > 0); locked = false; + + return true; } - internal void Redo () + internal bool Redo () { Action action; bool user_action_finished = false; if (redo_actions.Count == 0) - return; - - // You can't undo anything after redoing - undo_actions.Clear (); + return false; locked = true; do { @@ -4139,6 +4258,7 @@ namespace System.Windows.Forms { int start_index; action = (Action) redo_actions.Pop (); + undo_actions.Push (action); switch (action.type) { @@ -4192,6 +4312,8 @@ namespace System.Windows.Forms { } while (!user_action_finished && redo_actions.Count > 0); locked = false; + + return true; } #endregion // Internal Methods @@ -4202,6 +4324,9 @@ namespace System.Windows.Forms { if (locked) return; + // Nuke the redo queue + redo_actions.Clear (); + Action ua = new Action (); ua.type = ActionType.UserActionBegin; ua.data = name; @@ -4226,6 +4351,9 @@ namespace System.Windows.Forms { if (locked) return; + // Nuke the redo queue + redo_actions.Clear (); + Action a = new Action (); // We cant simply store the string, because then formatting would be lost @@ -4242,6 +4370,9 @@ namespace System.Windows.Forms { if (locked || str.Length == 0) return; + // Nuke the redo queue + redo_actions.Clear (); + Action a = new Action (); a.type = ActionType.InsertString; @@ -4257,6 +4388,9 @@ namespace System.Windows.Forms { if (locked) return; + // Nuke the redo queue + redo_actions.Clear (); + Action a = null; if (undo_actions.Count > 0)