2 // SqlEditor.cs - writen in C# using GTK#
5 // Daniel Morgan <danmorg@sc.rr.com>
6 // Rodrigo Moya <rodrigo@gnome-db.org>
8 // (c)copyright 2002 Daniel Morgan
9 // (c)copyright 2002 Rodrigo Moya
11 // SqlEditorSharp is based on the gnome-db-sql-editor.c in libgnomedb.
12 // SqlEditorSharp falls under the GPL license and is included
13 // in SQL# For GTK#. SQL# For GTK# is a database query tool for Mono.
16 namespace SqlEditorSharp
22 using System.Collections;
25 using System.Runtime.InteropServices;
26 using System.Diagnostics;
27 using Mono.Data.SqlSharp.Gui.GtkSharp;
29 /// <summary> SqlEditor Class</summary>
32 public class SqlEditorSharp : Gtk.VBox
36 // text tags for TextTagTable in TextBuffer
37 private TextTag freecomment_tag;
38 private TextTag linecomment_tag;
39 private TextTag singlequotedconstant_tag;
40 private TextTag sql_tag;
41 private TextTag normaltext_tag;
43 // determine if something has changed beyond a line
44 // updating one line is faster than the whole buffer
45 //private int line_last_changed;
46 //private int last_freecomment_count;
49 private bool use_hi_lighting;
50 private string family;
53 private ScrolledWindow scroll;
54 private TextView sqlTextView;
55 private TextBuffer sqlTextBuffer;
56 private EditorTab tab = null;
60 public SqlEditorSharp() : base(false, 4) {
61 scroll = new ScrolledWindow (
62 new Adjustment (0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
63 new Adjustment (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
64 scroll.HscrollbarPolicy = Gtk.PolicyType.Automatic;
65 scroll.VscrollbarPolicy = Gtk.PolicyType.Automatic;
66 scroll.ShadowType = Gtk.ShadowType.In;
67 this.PackStart (scroll, true, true, 0);
69 // default font famly for SQL editor
72 // other default settings
73 use_hi_lighting = false;
75 // create text tag table
76 TextTagTable textTagTable = new TextTagTable ();
78 // anything else is normaltext
79 normaltext_tag = new TextTag ("normaltext");
80 normaltext_tag.Family = family;
81 normaltext_tag.Foreground = "black";
82 normaltext_tag.Style = Pango.Style.Normal;
83 textTagTable.Add (normaltext_tag);
85 // SQL Keywords - SELECT FROM WHERE, etc
86 sql_tag = new TextTag ("sql");
87 sql_tag.Family = family;
88 sql_tag.Foreground = "blue";
89 sql_tag.Style = Pango.Style.Normal;
90 textTagTable.Add (sql_tag);
92 // c like free comment - used within a SQL statement
93 freecomment_tag = new TextTag ("freecomment");
94 freecomment_tag.Family = family;
95 freecomment_tag.Foreground = "darkgreen";
96 freecomment_tag.Style = Pango.Style.Italic;
97 textTagTable.Add (freecomment_tag);
99 // c++ like line comment, but using two hyphens
100 linecomment_tag = new TextTag ("linecomment");
101 linecomment_tag.Family = family;
102 linecomment_tag.Foreground = "darkgreen";
103 linecomment_tag.Style = Pango.Style.Italic;
104 textTagTable.Add (linecomment_tag);
106 /* single quoted constant - WHERE COL1 = 'ABC' */
107 singlequotedconstant_tag = new TextTag ("singlequotedconstant");
108 singlequotedconstant_tag.Family = family;
109 singlequotedconstant_tag.Foreground = "red";
110 singlequotedconstant_tag.Style = Pango.Style.Normal;
111 textTagTable.Add (singlequotedconstant_tag);
113 // create TextBuffer and TextView
114 sqlTextBuffer = new TextBuffer (textTagTable);
115 sqlTextView = new TextView (sqlTextBuffer);
117 // allow it to be edited
118 sqlTextView.Editable = true;
120 //line_last_changed = -1;
121 //last_freecomment_count = -1;
123 // attach OnTextChanged callback function
124 // to "changed" signal so we can do something
125 // when the text has changed in the buffer
126 sqlTextBuffer.Changed += new EventHandler (OnTextChanged);
128 // add the TextView to the ScrolledWindow
129 scroll.Add (sqlTextView);
134 public TextBuffer Buffer {
136 return sqlTextBuffer;
140 public TextView View {
146 public EditorTab Tab {
156 public bool UseSyntaxHiLighting {
158 return use_hi_lighting;
162 use_hi_lighting = value;
168 void OnTextChanged (object o, EventArgs args)
171 tab.label.Text = tab.basefilename + " *";
173 SqlSharpGtk.DebugWriteLine ("[[[[[ Syntax Hi-Light Text BEGIN ]]]]]");
175 if (use_hi_lighting == true) {
176 SyntaxHiLightText ();
179 SqlSharpGtk.DebugWriteLine ("[[[[[ Syntax Hi-Light Text END ]]]]]\n");
182 void SyntaxHiLightText ()
184 TextIter start_iter, end_iter,
186 TextIter match_start1, match_end1,
187 match_start2, match_end2;
189 int hyphen = 0, single_quotes = 0;
190 string text = String.Empty;
191 int i = 0, start_con = 0, end_con = 0;
193 //int freecomment_count = 0;
195 TextMark insert_mark;
198 insert_mark = sqlTextBuffer.InsertMark;
199 sqlTextBuffer.GetIterAtMark (out insert_iter, insert_mark);
200 //line = insert_iter.Line;
202 /* get the starting and ending text iterators */
203 sqlTextBuffer.GetIterAtOffset (out start_iter, 0);
204 char_count = sqlTextBuffer.CharCount;
205 sqlTextBuffer.GetIterAtOffset (out end_iter, char_count);
207 SqlSharpGtk.DebugWriteLine ("char_count: " + char_count);
209 /* since line is not same - redo all */
210 //if (line != line_last_changed) {
211 /* remove all previously applied tags */
212 sqlTextBuffer.RemoveAllTags (start_iter, end_iter);
214 /* apply the entire buffer to the normaltext tag */
215 sqlTextBuffer.ApplyTag (normaltext_tag, start_iter, end_iter);
217 //else { /* just worry about current insertion line */
218 // /* get start iter */
219 // if (insert_iter.StartsLine () == true) {
220 // start_iter = insert_iter;
223 // start_iter = insert_iter;
224 // start_iter.LineOffset = 0;
226 // /* get end iter */
227 // end_iter.ForwardToLineEnd ();
228 // char_count = start_iter.CharsInLine;
230 // /* remove all previously applied tags */
231 // sqlTextBuffer.RemoveAllTags (start_iter, end_iter);
233 // /* apply the entire buffer to the normaltext tag */
234 // sqlTextBuffer.ApplyTag (normaltext_tag,
235 // start_iter, end_iter);
237 // /* get the starting and ending text iterators */
238 // sqlTextBuffer.GetIterAtOffset (out start_iter, 0);
239 // char_count = sqlTextBuffer.CharCount;
240 // sqlTextBuffer.GetIterAtOffset (out end_iter, char_count);
243 /* ------------------------------------
244 * Free Comments (sort of like c style)
245 * ------------------------------------
246 * except in SQL, a c like comment occurs within
249 match_start1 = start_iter; // dummy
250 match_end1 = end_iter; // dummy
251 match_start2 = start_iter; // dummy
252 match_end2 = end_iter; // dummy
254 while (start_iter.IsEnd == false) {
255 // FIXME: match_start1, match_end1, end_iter
256 // need to be set to have ref in front
257 // Problem with TextIter's ForwardSearch()
258 // in GTK# (not GTK+)
259 if (start_iter.ForwardSearch (
261 TextSearchFlags.TextOnly,
266 /* beginning of free comment found */
267 //freecomment_count++;
268 // FIXME: fix match_start2, match_end2, end_iter
270 if (match_end1.ForwardSearch (
272 TextSearchFlags.TextOnly,
277 // ending of free comment found,
278 // now hi-light comment
279 sqlTextBuffer.ApplyTag (
283 match_end2.ForwardChars (1);
284 start_iter = match_end2;
288 // hi-light to the end,
289 // to let the user know
290 // the ending asterisk slash is missing
303 /* if free comments is different than last time,
304 * invalidate line_last_changed - causes
305 * a complete redo (instead hi-lighting just the current line -
306 * do the whole buffer)
307 * THIS IS JUST AN ATTEMPT FOR SPEED
309 //if (freecomment_count != last_freecomment_count) {
310 // line_last_changed = -1;
313 /*********************************************************************
314 * See if the following needs hi-lighting:
315 * - Line Comments (sort of like C++ slash slash comments
316 * but uses hypen hyphen and it is based at the beginning of a line)
317 * - Single-Quoted Constants ( WHERE COL1 = 'ABC' )
318 * - SQL keywords (SELECT, FROM, WHERE, UPDATE, etc)
319 *********************************************************************/
320 //if (line != line_last_changed) {
321 sqlTextBuffer.GetIterAtOffset (out start_iter, 0);
324 // if (insert_iter.StartsLine () == true) {
325 // start_iter = insert_iter;
328 // start_iter = insert_iter;
329 // start_iter.LineOffset = 0;
333 // get starting and ending iters
334 // and character count of line
335 char_count = sqlTextBuffer.CharCount;
336 sqlTextBuffer.GetIterAtOffset (out end_iter, char_count);
338 // for each line, look for:
339 // line comments, constants, and keywoards
342 iter.ForwardToLineEnd ();
343 text = sqlTextBuffer.GetText (
344 start_iter, iter, false);
346 // look for line comment
347 char_count = start_iter.CharsInLine;
349 for (i = 0; i < char_count - 1; i++) {
354 // line comment found
371 // this line is not line commented
372 i = char_count; // break out of for loop
376 // if not line commented,
377 // look for singled quoted constants
380 if (start_iter.IsEnd == true)
381 break; // break out of for loop
386 LookForSingleQuotesAndWords (
395 } while (start_iter.ForwardLine () == true);
398 // POOR ATTEMPTS AT SPEED - last_freecomment_count
399 // and line_last_changed
401 //last_freecomment_count = freecomment_count;
402 //line_last_changed = line;
405 void LookForSingleQuotesAndWords (ref TextIter start_iter,
406 string text, int char_count,
407 ref int start_word, ref int single_quotes,
408 ref int start_con, ref int end_con)
410 TextIter match_start1, match_end1;
414 for (i = 0; i < char_count; i++) {
415 match_start1 = start_iter;
416 match_end1 = start_iter;
418 if (match_end1.IsEnd == true)
421 if (CharHasTag (start_iter,
425 if (single_quotes == 0 &&
433 else if (Char.IsLetter (ch)) {
440 else if (single_quotes == 1) {
444 // single quoted constant
448 // ending of constant
453 singlequotedconstant_tag,
462 else if (start_word != -1) {
464 // is character alphabetic, numeric, or '_'
465 if (Char.IsLetterOrDigit (ch) ||
474 if (IsTextSQL (text, start_word, i)) {
475 // word is a SQL keyword,
496 if( start_word != -1) {
497 if (IsTextSQL (text, start_word, i)) {
498 // word is a SQL keyword,
509 void ApplyTag ( TextTag apply_tag, TextTag remove_tag,
510 TextIter start_iter, TextIter end_iter )
513 DebugText(start_iter, end_iter, "ApplyTag() " +
514 "remove: " + remove_tag.Name +
515 " apply: " + apply_tag.Name);
518 sqlTextBuffer.RemoveTag (
520 start_iter, end_iter);
522 sqlTextBuffer.ApplyTag (
524 start_iter, end_iter);
527 void ApplyTagOffsets (TextIter start_iter,
528 int start_offset, int end_offset,
532 TextIter begin_iter, end_iter;
534 begin_iter = start_iter;
535 end_iter = start_iter;
537 begin_iter.LineOffset = start_offset;
538 end_iter.LineOffset = end_offset;
541 DebugText(start_iter, end_iter, "ApplyTagOffsets() " +
542 "remove: " + remove_tag.Name +
543 " apply: " + apply_tag.Name +
544 " start: " + start_offset.ToString() +
545 " end: " + end_offset.ToString());
548 sqlTextBuffer.RemoveTag (remove_tag,
549 begin_iter, end_iter);
551 sqlTextBuffer.ApplyTag (apply_tag,
552 begin_iter, end_iter);
555 /* is word a SQL keyword? */
556 bool IsTextSQL (string text, int begin, int end)
562 if(text.Equals(String.Empty))
574 text_len = end - begin;
579 SqlSharpGtk.DebugWriteLine("IsTextSQL - " +
580 "begin: " + begin.ToString() +
581 " end: " + end.ToString() +
582 " text_len: " + text_len);
583 SqlSharpGtk.DebugWriteLine("[TEXT BEGIN]");
584 SqlSharpGtk.DebugWriteLine(text);
585 SqlSharpGtk.DebugWriteLine("[TEXT END ]");
588 for (i = 0; sql_keywords[i] != String.Empty; i++) {
589 if(text_len == sql_keywords[i].Length) {
591 SqlSharpGtk.DebugWriteLine(
592 "Test length: " + text_len +
593 " keyword: " + keyword);
596 keyword = text.Substring (begin, text_len);
598 catch(ArgumentOutOfRangeException a) {
599 Console.WriteLine ("Internal Error: SqlSharpGtk: text.Substring() ArgumentOutOfRange");
602 keyword = keyword.ToUpper();
604 if(keyword.Equals (sql_keywords [i]))
612 // does the character at offset in the GtkTextIter has
613 // this text tag applied?
614 bool CharHasTag(TextIter iter,
615 TextTag tag, int char_offset_in_line)
618 TextIter offset_iter;
621 offset_iter.LineOffset = char_offset_in_line;
623 return offset_iter.HasTag (tag);
629 start = sqlTextBuffer.StartIter;
630 end = sqlTextBuffer.EndIter;
631 sqlTextBuffer.Delete(start,end);
634 public void LoadFromFile(string inFilename)
636 StreamReader sr = new StreamReader(inFilename);
641 while((NextLine = sr.ReadLine()) != null) {
642 line = NextLine + "\n";
643 sqlTextBuffer.Insert (sqlTextBuffer.EndIter, line);
648 public void SaveToFile(string outFilename)
650 TextIter start_iter, iter;
652 StreamWriter sw = null;
654 sw = new StreamWriter(outFilename);
655 sqlTextBuffer.GetIterAtOffset (out iter, 0);
657 while (iter.ForwardLine()) {
658 text = sqlTextBuffer.GetText(start_iter, iter, false);
662 text = sqlTextBuffer.GetText(start_iter, iter, false);
668 void DebugText (TextIter iter_start, TextIter iter_end,
673 string text = sqlTextBuffer.GetText (
674 iter_start, iter_end, false);
681 SqlSharpGtk.DebugWriteLine(msg);
685 static readonly string[] sql_keywords =