(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / tools / SqlSharp / gui / gtk-sharp / SqlEditorSharp.cs
blobafad1c3176af51f90e1dc37f4d8bce8f2adad560
1 //
2 // SqlEditor.cs - writen in C# using GTK#
3 //
4 // Authors:
5 // Daniel Morgan <danmorg@sc.rr.com>
6 // Rodrigo Moya <rodrigo@gnome-db.org>
7 //
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
18 using System;
19 using Gtk;
20 using Gdk;
21 using GLib;
22 using System.Collections;
23 using System.IO;
24 using System.Text;
25 using System.Runtime.InteropServices;
26 using System.Diagnostics;
27 using Mono.Data.SqlSharp.Gui.GtkSharp;
29 /// <summary> SqlEditor Class</summary>
30 /// <remarks>
31 /// </remarks>
32 public class SqlEditorSharp : Gtk.VBox
34 // Fields
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;
48 // settings
49 private bool use_hi_lighting;
50 private string family;
52 // widgets
53 private ScrolledWindow scroll;
54 private TextView sqlTextView;
55 private TextBuffer sqlTextBuffer;
56 private EditorTab tab = null;
58 // Constructors
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
70 family = "courier";
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);
132 // Public Properties
134 public TextBuffer Buffer {
135 get {
136 return sqlTextBuffer;
140 public TextView View {
141 get {
142 return sqlTextView;
146 public EditorTab Tab {
147 get {
148 return tab;
150 set {
151 tab = value;
156 public bool UseSyntaxHiLighting {
157 get {
158 return use_hi_lighting;
161 set {
162 use_hi_lighting = value;
166 // Private Methods
168 void OnTextChanged (object o, EventArgs args)
170 if(tab != null)
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,
185 iter, insert_iter;
186 TextIter match_start1, match_end1,
187 match_start2, match_end2;
188 int char_count = 0;
189 int hyphen = 0, single_quotes = 0;
190 string text = String.Empty;
191 int i = 0, start_con = 0, end_con = 0;
192 //int line = 0;
193 //int freecomment_count = 0;
194 int start_word = -1;
195 TextMark insert_mark;
196 char ch = ' ';
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;
221 // }
222 // else {
223 // start_iter = insert_iter;
224 // start_iter.LineOffset = 0;
225 // }
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
247 * a SQL statement
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 (
260 "/*",
261 TextSearchFlags.TextOnly,
262 out match_start1,
263 out match_end1,
264 end_iter) == true) {
266 /* beginning of free comment found */
267 //freecomment_count++;
268 // FIXME: fix match_start2, match_end2, end_iter
269 // with ref if front
270 if (match_end1.ForwardSearch (
271 "*/",
272 TextSearchFlags.TextOnly,
273 out match_start2,
274 out match_end2,
275 end_iter) == true) {
277 // ending of free comment found,
278 // now hi-light comment
279 sqlTextBuffer.ApplyTag (
280 freecomment_tag,
281 match_start1,
282 match_end2);
283 match_end2.ForwardChars (1);
284 start_iter = match_end2;
286 else {
287 // if no end found,
288 // hi-light to the end,
289 // to let the user know
290 // the ending asterisk slash is missing
291 ApplyTag (
292 freecomment_tag,
293 normaltext_tag,
294 match_start1,
295 end_iter);
296 break;
299 else
300 break;
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);
323 //else {
324 // if (insert_iter.StartsLine () == true) {
325 // start_iter = insert_iter;
326 // }
327 // else {
328 // start_iter = insert_iter;
329 // start_iter.LineOffset = 0;
330 // }
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
340 do {
341 iter = start_iter;
342 iter.ForwardToLineEnd ();
343 text = sqlTextBuffer.GetText (
344 start_iter, iter, false);
346 // look for line comment
347 char_count = start_iter.CharsInLine;
348 hyphen = 0;
349 for (i = 0; i < char_count - 1; i++) {
350 switch (text[i]) {
351 case '-':
352 if (hyphen == 1) {
353 hyphen = 2;
354 // line comment found
355 i = char_count;
357 ApplyTag (
358 linecomment_tag,
359 normaltext_tag,
360 start_iter,
361 iter);
363 else {
364 hyphen = 1;
366 break;
367 case ' ':
368 // continue
369 break;
370 default:
371 // this line is not line commented
372 i = char_count; // break out of for loop
373 break;
376 // if not line commented,
377 // look for singled quoted constants
378 // and keywords
379 if (hyphen < 2) {
380 if (start_iter.IsEnd == true)
381 break; // break out of for loop
383 start_word = -1;
384 single_quotes = 0;
386 LookForSingleQuotesAndWords (
387 ref start_iter,
388 text, char_count,
389 ref start_word,
390 ref single_quotes,
391 ref start_con,
392 ref end_con);
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;
411 int i;
412 char ch;
414 for (i = 0; i < char_count; i++) {
415 match_start1 = start_iter;
416 match_end1 = start_iter;
418 if (match_end1.IsEnd == true)
419 break;
421 if (CharHasTag (start_iter,
422 freecomment_tag, i)
423 == false) {
425 if (single_quotes == 0 &&
426 start_word == -1) {
428 ch = text[i];
429 if (ch == '\'') {
430 single_quotes = 1;
431 start_con = i + 1;
433 else if (Char.IsLetter (ch)) {
434 start_word = i;
436 else {
437 // continue
440 else if (single_quotes == 1) {
441 ch = text[i];
442 switch (ch) {
443 case '\'':
444 // single quoted constant
445 end_con = i;
447 // get starting and
448 // ending of constant
449 // excluding quotes
450 ApplyTagOffsets (
451 start_iter,
452 start_con, i,
453 singlequotedconstant_tag,
454 normaltext_tag);
456 single_quotes = 0;
457 break;
458 default:
459 break;
462 else if (start_word != -1) {
463 ch = text[i];
464 // is character alphabetic, numeric, or '_'
465 if (Char.IsLetterOrDigit (ch) ||
466 ch == '_') {
468 // continue
470 else {
471 // using start_word
472 // and i offsets,
473 // get word
474 if (IsTextSQL (text, start_word, i)) {
475 // word is a SQL keyword,
476 // hi-light word
477 ApplyTagOffsets (
478 start_iter,
479 start_word, i,
480 sql_tag,
481 normaltext_tag);
483 start_word = -1;
484 switch (text[i]) {
485 case '\'':
486 single_quotes = 1;
487 start_con = i + 1;
488 break;
489 default:
490 break;
496 if( start_word != -1) {
497 if (IsTextSQL (text, start_word, i)) {
498 // word is a SQL keyword,
499 // hi-light word
500 ApplyTagOffsets(
501 start_iter,
502 start_word, i,
503 sql_tag,
504 normaltext_tag);
509 void ApplyTag ( TextTag apply_tag, TextTag remove_tag,
510 TextIter start_iter, TextIter end_iter )
512 #if DEBUG
513 DebugText(start_iter, end_iter, "ApplyTag() " +
514 "remove: " + remove_tag.Name +
515 " apply: " + apply_tag.Name);
516 #endif // DEBUG
518 sqlTextBuffer.RemoveTag (
519 remove_tag,
520 start_iter, end_iter);
522 sqlTextBuffer.ApplyTag (
523 apply_tag,
524 start_iter, end_iter);
527 void ApplyTagOffsets (TextIter start_iter,
528 int start_offset, int end_offset,
529 TextTag apply_tag,
530 TextTag remove_tag)
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;
540 #if DEBUG
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());
546 #endif
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)
558 string keyword = "";
560 int i;
561 int text_len;
562 if(text.Equals(String.Empty))
563 return false;
565 if(begin < 0)
566 return false;
568 if(end < 2)
569 return false;
571 if(begin >= end)
572 return false;
574 text_len = end - begin;
575 if(text_len < 1)
576 return false;
578 #if DEBUG
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 ]");
586 #endif // DEBUG
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);
595 try {
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]))
605 return true;
609 return false;
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;
620 offset_iter = iter;
621 offset_iter.LineOffset = char_offset_in_line;
623 return offset_iter.HasTag (tag);
626 public void Clear()
628 TextIter start, end;
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);
637 Clear();
638 string NextLine;
639 string line;
641 while((NextLine = sr.ReadLine()) != null) {
642 line = NextLine + "\n";
643 sqlTextBuffer.Insert (sqlTextBuffer.EndIter, line);
645 sr.Close();
648 public void SaveToFile(string outFilename)
650 TextIter start_iter, iter;
651 string text;
652 StreamWriter sw = null;
654 sw = new StreamWriter(outFilename);
655 sqlTextBuffer.GetIterAtOffset (out iter, 0);
656 start_iter = iter;
657 while (iter.ForwardLine()) {
658 text = sqlTextBuffer.GetText(start_iter, iter, false);
659 sw.Write(text);
660 start_iter = iter;
662 text = sqlTextBuffer.GetText(start_iter, iter, false);
663 sw.Write(text);
664 sw.Close();
665 sw = null;
668 void DebugText (TextIter iter_start, TextIter iter_end,
669 string debugMessage)
672 #if DEBUG
673 string text = sqlTextBuffer.GetText (
674 iter_start, iter_end, false);
675 string msg =
676 "[DEBUG-TEXT]: " +
677 debugMessage +
678 " (" +
679 text +
680 ")";
681 SqlSharpGtk.DebugWriteLine(msg);
682 #endif // DEBUG
685 static readonly string[] sql_keywords =
686 new string[] {
687 "DELETE",
688 "FROM",
689 "SELECT",
690 "UPDATE",
691 "SET",
692 "INSERT",
693 "INTO",
694 "VALUES",
695 "WHERE",
696 "COUNT",
697 "SUM",
698 "MAX",
699 "MIN",
700 "AVG",
701 "DROP",
702 "ALTER",
703 "CREATE",
704 "VIEW",
705 "TABLE",
706 "AS",
707 "AND",
708 "OR",
709 "ORDER",
710 "GROUP",
711 "BY",
712 "HAVING",
713 "IS",
714 "NULL",
715 "NOT",
716 "COMMIT",
717 "ROLLBACK",
718 "EXISTS",
719 "IN",
720 "LIKE",
721 "GRANT",
722 "REVOKE",
723 "ON",
724 "TO",
725 String.Empty