#region Disclaimer / License // Copyright (C) 2012, Jackie Ng // http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@gmail.com // // Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1) // Copyright 2002-2010 by // // AlphaSierraPapa, Christoph Wille // Vordernberger Strasse 27/8 // A-8700 Leoben // Austria // // email: office@alphasierrapapa.com // court of jurisdiction: Landesgericht Leoben // // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion using ICSharpCode.TextEditor; using ICSharpCode.TextEditor.Document; using ICSharpCode.TextEditor.Gui.CompletionWindow; using OSGeo.MapGuide.MaestroAPI; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Maestro.Editors.Common { public abstract class TextEditorBase : ITextEditor { delegate string GetLineInvoker(int index); delegate void WriteInvoker(string text, Color color, Color fore); protected TextEditorControl textEditorControl; protected TextArea textArea; protected Color customLineColour = Color.LightGray; protected TextMarker readOnlyMarker; protected TextEditorBase(TextEditorControl textEditorControl) { this.textEditorControl = textEditorControl; this.textArea = textEditorControl.ActiveTextAreaControl.TextArea; textEditorControl.TextEditorProperties.SupportReadOnlySegments = true; } public IndentStyle IndentStyle { get { return textEditorControl.IndentStyle; } set { SetIndentStyle(value); } } public event ICSharpCode.TextEditor.KeyEventHandler KeyPress { add { textArea.KeyEventHandler += value; } remove { textArea.KeyEventHandler -= value; } } public event DialogKeyProcessor DialogKeyPress { add { textArea.DoProcessDialogKey += value; } remove { textArea.DoProcessDialogKey -= value; } } public Color CustomLineColour { get { return customLineColour; } } public void Write(string text) { Write(text, Color.Empty, default(Color)); } public void Write(string text, Color backgroundColour) { Write(text, backgroundColour, default(Color)); } public void Write(string text, Color backgroundColour, Color foregroundColor) { if (textEditorControl.InvokeRequired) { WriteInvoker invoker = new WriteInvoker(Write); textEditorControl.Invoke(invoker, new object[] { text, backgroundColour, foregroundColor }); } else { int offset = textEditorControl.Document.PositionToOffset(new TextLocation(Column, Line)); textEditorControl.ActiveTextAreaControl.TextArea.InsertString(text); if (!backgroundColour.IsEmpty) { TextMarker marker = new TextMarker(offset, text.Length, TextMarkerType.SolidBlock, backgroundColour, foregroundColor); textEditorControl.Document.MarkerStrategy.AddMarker(marker); textEditorControl.Refresh(); } } } public int Column { get { return textEditorControl.ActiveTextAreaControl.Caret.Column; } set { textEditorControl.ActiveTextAreaControl.Caret.Column = value; } } public int SelectionStart { get { ColumnRange range = GetSelectionRange(); if (range != ColumnRange.NoColumn) { return range.StartColumn; } return Column; } } public int SelectionLength { get { ColumnRange range = GetSelectionRange(); return range.EndColumn - range.StartColumn; } } /// /// Gets the current cursor line. /// public int Line { get { return textArea.Caret.Line; } } /// /// Gets the total number of lines in the text editor. /// public int TotalLines { get { return textEditorControl.Document.TotalNumberOfLines; } } /// /// Gets the text for the specified line. /// public string GetLine(int index) { if (textEditorControl.InvokeRequired) { GetLineInvoker invoker = new GetLineInvoker(GetLine); return (string)textEditorControl.Invoke(invoker, new object[] { index }); } else { LineSegment lineSegment = textEditorControl.Document.GetLineSegment(index); return textEditorControl.Document.GetText(lineSegment); } } /// /// Replaces the text at the specified index on the current line with the specified text. /// public void Replace(int index, int length, string text) { int currentLine = textEditorControl.ActiveTextAreaControl.Caret.Line; LineSegment lineSegment = textEditorControl.Document.GetLineSegment(currentLine); textEditorControl.Document.Replace(lineSegment.Offset + index, length, text); } /// /// Makes the current text read only. Text can still be entered at the end. /// public void MakeCurrentContentReadOnly() { IDocument doc = textEditorControl.Document; if (readOnlyMarker == null) { readOnlyMarker = new TextMarker(0, doc.TextLength, TextMarkerType.Invisible); readOnlyMarker.IsReadOnly = true; doc.MarkerStrategy.AddMarker(readOnlyMarker); } readOnlyMarker.Offset = 0; readOnlyMarker.Length = doc.TextLength; doc.UndoStack.ClearAll(); } public virtual void ShowCompletionWindow(ICompletionDataProvider completionDataProvider) { ShowCompletionWindow(completionDataProvider, ' '); } public abstract void ShowCompletionWindow(ICompletionDataProvider completionDataProvider, char firstChar); public abstract bool IsCompletionWindowDisplayed { get; } /// /// Gets the range of the currently selected text. /// ColumnRange GetSelectionRange() { return textArea.SelectionManager.GetSelectionAtLine(textArea.Caret.Line); } void SetIndentStyle(IndentStyle style) { if (textEditorControl.InvokeRequired) { Action action = SetIndentStyle; textEditorControl.Invoke(action, new object[] { style }); } else { textEditorControl.IndentStyle = style; } } public virtual bool ProcessKeyPress(Keys keyData) { return false; } public virtual void SetParent(Control frm) { } } public static class TextEditorFactory { public static ITextEditor CreateEditor(TextEditorControl textEditor) { if (Platform.IsRunningOnMono) return new MonoCompatibleTextEditor(textEditor); else return new DefaultTextEditor(textEditor); } } /// /// A text editor controller using Mono-friendly auto-completion /// internal class MonoCompatibleTextEditor : TextEditorBase { private AutoCompletionListBox _autoBox; private ToolTip _autoCompleteTooltip; internal MonoCompatibleTextEditor(TextEditorControl textEditor) : base(textEditor) { _autoBox = new AutoCompletionListBox(); _autoCompleteTooltip = new ToolTip(); } private Control _parent; public override void SetParent(Control ctrl) { _parent = ctrl; _parent.Controls.Add(_autoBox); } public override bool IsCompletionWindowDisplayed { get { return _autoBox.IsShown; } } public override void ShowCompletionWindow(ICompletionDataProvider completionDataProvider, char firstChar) { //Not ready for beta 5. Remove after release of beta 5. return; var context = new AutoCompletionListBox.AutoCompleteContext() { AutoCompleteTooltip = _autoCompleteTooltip, CompletionProvider = completionDataProvider, Editor = textEditorControl, FirstChar = firstChar, GetCaretPoint = GetCaretPoint, InsertionOffset = textEditorControl.ActiveTextAreaControl.Caret.Offset }; _autoBox.SetCompletionItems(textEditorControl.ParentForm, context, string.Empty); } private Point GetCaretPoint() { var pt = textArea.Caret.ScreenPosition; var cpt = textEditorControl.PointToScreen(pt); int dx = 15; //Shift a bit int dy = 0; //Adjust the postion to accomodate as much space for the auto-complete box as much as possible if (_parent != null) { if (_autoBox.Height > _parent.Height) dy = -pt.Y; } pt.Offset(dx, dy); return pt; } static bool IsAlphanumeric(Keys key) { return (key >= Keys.D0 && key <= Keys.Z); } public override bool ProcessKeyPress(Keys keyData) { bool bProcessed = false; if (IsCompletionWindowDisplayed) { if (IsAlphanumeric(keyData)) { _autoBox.AdvanceInsertionOffset(); return false; } switch (keyData) { case Keys.Up: _autoBox.MoveAutoCompleteSelectionUp(); bProcessed = true; break; case Keys.Down: _autoBox.MoveAutoCompleteSelectionDown(); bProcessed = true; break; case Keys.Enter: _autoBox.HandleEnterKey(); bProcessed = true; break; case Keys.Escape: _autoBox.HideBox(); break; } } return bProcessed; } } /// /// Default text editor, using the ICSharpCode.TextEditor auto-completion facilities /// internal class DefaultTextEditor : TextEditorBase { CodeCompletionWindow completionWindow; internal DefaultTextEditor(TextEditorControl textEditor) : base(textEditor) { } public override bool IsCompletionWindowDisplayed { get { return completionWindow != null; } } public override void ShowCompletionWindow(ICompletionDataProvider completionDataProvider, char ch) { completionWindow = CodeCompletionWindow.ShowCompletionWindow(textEditorControl.ParentForm, textEditorControl, String.Empty, completionDataProvider, ch); if (completionWindow != null) { completionWindow.Width = 250; completionWindow.Closed += CompletionWindowClosed; } } void CompletionWindowClosed(object source, EventArgs e) { if (completionWindow != null) { completionWindow.Closed -= CompletionWindowClosed; completionWindow.Dispose(); completionWindow = null; } } } }