[libgda] GdaBrowser: more work on the query exec. perspective



commit afb591798adb89ccd5473ce81b74a77103cfad66
Author: Vivien Malerba <malerba gnome-db org>
Date:   Fri Sep 4 21:50:31 2009 +0200

    GdaBrowser: more work on the query exec. perspective

 po/POTFILES.in                                 |    1 +
 tools/browser/doc/gda-browser-sections.txt     |   84 ++-
 tools/browser/doc/tmpl/browser-connection.sgml |    9 +
 tools/browser/query-exec/Makefile.am           |    4 +
 tools/browser/query-exec/gda-sql.lang          |  632 +++++++++++++++
 tools/browser/query-exec/query-console.c       |  256 ++++++-
 tools/browser/query-exec/query-editor.c        | 1005 ++++++++++++++++++++++--
 tools/browser/query-exec/query-editor.h        |   67 ++-
 8 files changed, 1961 insertions(+), 97 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a36b405..dd1244d 100755
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -211,6 +211,7 @@ tools/browser/canvas/browser-canvas-print.c
 tools/browser/canvas/browser-canvas-table.c
 tools/browser/canvas/browser-canvas.c
 tools/browser/common/objects-cloud.c
+tools/browser/query-exec/gda-sql.lang
 tools/browser/schema-browser/favorite-selector.c
 tools/browser/schema-browser/mgr-columns.c
 tools/browser/schema-browser/objects-index.c
diff --git a/tools/browser/doc/gda-browser-sections.txt b/tools/browser/doc/gda-browser-sections.txt
index 1974a8b..f9272fd 100644
--- a/tools/browser/doc/gda-browser-sections.txt
+++ b/tools/browser/doc/gda-browser-sections.txt
@@ -13,8 +13,6 @@ browser_core_take_connection
 browser_core_get_connections
 browser_core_close_connection
 browser_core_quit
-BrowserPerspectiveFactory
-BROWSER_PERSPECTIVE_FACTORY
 browser_core_get_default_factory
 browser_core_set_default_factory
 browser_core_get_factories
@@ -70,10 +68,11 @@ AUTH_DIALOG_CLASS
 <FILE>browser-favorites</FILE>
 BrowserFavoritesPrivate
 BrowserFavoritesType
+BROWSER_FAVORITES_NB_TYPES
+BrowserFavoritesAttributes
 <TITLE>BrowserFavorites</TITLE>
 BrowserFavorites
-BrowserFavoritesAttributes
-ORDER_KEY_SCHEMA
+browser_favorites_new
 browser_favorites_add
 browser_favorites_list
 browser_favorites_delete
@@ -198,6 +197,47 @@ CC_IS_GRAY_BAR_CLASS
 </SECTION>
 
 <SECTION>
+<FILE>query-editor</FILE>
+QueryEditorPrivate
+<TITLE>QueryEditor</TITLE>
+QueryEditor
+QueryEditorHistoryItem
+query_editor_history_item_new
+query_editor_history_item_ref
+query_editor_history_item_unref
+QueryEditorHistoryBatch
+query_editor_history_batch_new
+query_editor_history_batch_ref
+query_editor_history_batch_unref
+query_editor_history_batch_add_item
+query_editor_history_batch_del_item
+QueryEditorMode
+query_editor_new
+query_editor_set_mode
+query_editor_get_mode
+query_editor_get_all_text
+query_editor_load_from_file
+query_editor_save_to_file
+query_editor_copy_clipboard
+query_editor_cut_clipboard
+query_editor_paste_clipboard
+query_editor_set_text
+query_editor_start_history_batch
+query_editor_add_history_item
+query_editor_get_current_history_item
+query_editor_get_current_history_batch
+query_editor_del_current_history_item
+query_editor_del_history_batch
+<SUBSECTION Standard>
+QUERY_EDITOR
+QUERY_IS_EDITOR
+QUERY_TYPE_EDITOR
+query_editor_get_type
+QUERY_EDITOR_CLASS
+QUERY_IS_EDITOR_CLASS
+</SECTION>
+
+<SECTION>
 <FILE>browser-perspective</FILE>
 BROWSER_PERSPECTIVE_TYPE
 BROWSER_PERSPECTIVE
@@ -221,6 +261,9 @@ BrowserPerspectiveIface
 BrowserPerspective
 BrowserPageIface
 BrowserPage
+BrowserPerspectiveFactory
+BROWSER_PERSPECTIVE_FACTORY
+ORDER_KEY_SCHEMA
 </SECTION>
 
 <SECTION>
@@ -265,6 +308,7 @@ BROWSER_STOCK_BOOKMARKS
 STOCK_NEW_WINDOW
 STOCK_ADD_BOOKMARK
 STOCK_PRINT_SETUP
+STOCK_CONSOLE
 browser_stock_icons_init
 </SECTION>
 
@@ -281,6 +325,38 @@ browser_get_pixbuf_icon
 </SECTION>
 
 <SECTION>
+<FILE>query-exec-perspective</FILE>
+TYPE_QUERY_EXEC_PERSPECTIVE
+QUERY_EXEC_PERSPECTIVE
+QUERY_EXEC_PERSPECTIVE_CLASS
+IS_QUERY_EXEC_PERSPECTIVE
+QueryExecPerspectivePrivate
+<TITLE>QueryExecPerspective</TITLE>
+QueryExecPerspective
+query_exec_perspective_get_type
+query_exec_perspective_new
+</SECTION>
+
+<SECTION>
+<FILE>query-console</FILE>
+QUERY_CONSOLE_TYPE
+QUERY_CONSOLE
+QUERY_CONSOLE_CLASS
+IS_QUERY_CONSOLE
+IS_QUERY_CONSOLE_CLASS
+QueryConsolePrivate
+<TITLE>QueryConsole</TITLE>
+QueryConsole
+query_console_get_type
+query_console_new
+</SECTION>
+
+<SECTION>
+<FILE>perspective-main</FILE>
+query_exec_perspective_get_factory
+</SECTION>
+
+<SECTION>
 <FILE>objects-cloud</FILE>
 OBJECTS_CLOUD_TYPE
 OBJECTS_CLOUD
diff --git a/tools/browser/doc/tmpl/browser-connection.sgml b/tools/browser/doc/tmpl/browser-connection.sgml
index 92e7c21..534ff21 100644
--- a/tools/browser/doc/tmpl/browser-connection.sgml
+++ b/tools/browser/doc/tmpl/browser-connection.sgml
@@ -135,3 +135,12 @@ An opened connection
 @Returns: 
 
 
+<!-- ##### FUNCTION browser_connection_create_parser ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ Returns: 
+
+
diff --git a/tools/browser/query-exec/Makefile.am b/tools/browser/query-exec/Makefile.am
index 79345f9..abfc15c 100644
--- a/tools/browser/query-exec/Makefile.am
+++ b/tools/browser/query-exec/Makefile.am
@@ -18,3 +18,7 @@ libperspective_la_SOURCES = \
 	perspective-main.h \
 	query-exec-perspective.h \
 	query-exec-perspective.c
+
+langspecdir=$(datadir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/language-specs
+langspec_DATA= \
+	gda-sql.lang
\ No newline at end of file
diff --git a/tools/browser/query-exec/gda-sql.lang b/tools/browser/query-exec/gda-sql.lang
new file mode 100644
index 0000000..d8d1e9c
--- /dev/null
+++ b/tools/browser/query-exec/gda-sql.lang
@@ -0,0 +1,632 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Author: Evert Verhellen <evert verhellen advalvas be>
+ Copyright (C) 2003, 2005 Evert Verhellen <evert verhellen advalvas be>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+-->
+<language id="gda-sql" _name="GDA-SQL" version="2.0" _section="Sources">
+  <metadata>
+    <property name="mimetypes">text/x-sql</property>
+    <property name="globs">*.sql</property>
+    <property name="line-comment-start">--</property>
+  </metadata>
+
+  <styles>
+    <style id="comment" _name="Comment" map-to="def:comment"/>
+    <style id="floating-point" _name="Floating Point" map-to="def:floating-point"/>
+    <style id="string" _name="String" map-to="def:string"/>
+    <style id="keyword" _name="Keyword" map-to="def:keyword"/>
+    <style id="function" _name="Function" map-to="def:function"/>
+    <style id="decimal" _name="Decimal" map-to="def:decimal"/>
+    <style id="type" _name="Data Type" map-to="def:type"/>
+    <style id="variable" _name="Variable" map-to="def:type"/>
+    <style id="some-thing" _name="No idea what it is" map-to="def:preprocessor"/>
+  </styles>
+
+  <default-regex-options case-sensitive="false"/>
+
+  <definitions>
+
+    <context id="oracle-built-in-datatypes" style-ref="type">
+      <keyword>N?VARCHAR2</keyword>
+      <keyword>NUMBER</keyword>
+      <keyword>LONG</keyword>
+      <keyword>DATE</keyword>
+      <keyword>TIMESTAMP</keyword>
+      <keyword>INTERVAL</keyword>
+      <!-- FIXME no \n in patterns! -->
+      <keyword>(LONG[ \t\n]+)?RAW</keyword>
+      <keyword>U?ROWID</keyword>
+      <keyword>N?CHAR</keyword>
+      <keyword>(N?C|B)LOB</keyword>
+      <keyword>BFILE</keyword>
+      <keyword>BINARY_(FLOAT|DOUBLE)</keyword>
+    </context>
+
+    <context id="ansi-datatypes" style-ref="type">
+      <!-- FIXME no \n in patterns! -->
+      <keyword>(NATIONAL[ \t\n]+)?CHAR(ACTER)?([ \t\n]+VARYING)?</keyword>
+      <!-- FIXME no \n in patterns! -->
+      <keyword>NCHAR([ \t\n]+VARYING)?</keyword>
+      <keyword>NUMERIC|DECIMAL</keyword>
+      <keyword>INTEGER|INT|SMALLINT</keyword>
+      <!-- FIXME no \n in patterns! -->
+      <keyword>FLOAT|DOUBLE[ \t\n]+PRECISION|REAL</keyword>
+    </context>
+
+    <context id="sql-ds-and-db2-datatypes" style-ref="type">
+      <keyword>CHARACTER</keyword>
+      <!-- FIXME no \n in patterns! -->
+      <keyword>(LONG[ \t\n]+)?VARCHAR</keyword>
+      <keyword>DECIMAL</keyword>
+      <keyword>INTEGER|SMALLINT</keyword>
+      <keyword>FLOAT</keyword>
+    </context>
+
+    <context id="oracle-supplied-types" style-ref="type">
+      <keyword>SYS\.ANY(TYPE|DATA(SET)?)</keyword>
+      <keyword>XMLType</keyword>
+      <keyword>(HTTP|XDB|DB)?URIType</keyword>
+      <keyword>(MDSYS\.)?SDO_((TOPO_)?GEOMETRY|GEORASTER)</keyword>
+      <keyword>ORDSYS\.ORD(Audio|Doc|Image(Signature)?|Video)</keyword>
+      <keyword>SI_(StillImage|(Average|Positional)?Color|ColorHistogram|Texture|FeatureList)</keyword>
+    </context>
+
+    <context id="text-literals" style-ref="string">
+      <start>[NnQqUu]?(['`])</start>
+      <end>\%{1 start}</end>
+      <include>
+        <context ref="def:escape"/>
+        <context ref="def:line-continue"/>
+      </include>
+    </context>
+
+    <context id="integer-literals" style-ref="decimal">
+      <match>\b[0-9]+\b</match>
+    </context>
+
+    <context id="shortvariable" style-ref="variable">
+      <match>##[0-9a-zA-Z\+\- ]+(::[0-9a-zA-Z]+(::NULL)?)?</match>
+    </context>
+
+    <context id="longvariable" style-ref="variable">
+      <start>##( *)/\*</start>
+      <end>\*/</end>
+      <include>
+        <context ref="def:in-line-comment"/>
+      </include>
+    </context>
+
+    <context id="number-literals" style-ref="floating-point">
+      <match>(\b[0-9]+(\.[0-9]+)?|\.[0-9]+)([Ee][\+-]?[0-9]+)?\b</match>
+    </context>
+
+    <context id="size-clause" style-ref="decimal">
+      <match>\b[0-9]+[ \t]*([Kk]|[Mm]|[Gg]|[Tt])\b</match>
+    </context>
+
+    <context id="unlimited" style-ref="decimal">
+      <keyword>UNLIMITED</keyword>
+    </context>
+
+    <context id="null" style-ref="decimal">
+      <keyword>NULL</keyword>
+    </context>
+
+    <context id="block-comment" style-ref="comment">
+      <start>/\*</start>
+      <end>\*/</end>
+      <include>
+        <context ref="def:in-line-comment"/>
+      </include>
+    </context>
+
+    <context id="line-comment" style-ref="comment" end-at-line-end="true">
+      <start>--</start>
+      <include>
+        <context ref="def:in-line-comment"/>
+      </include>
+    </context>
+
+    <context id="numeric-functions" style-ref="function">
+      <keyword>ABS</keyword>
+      <keyword>A(COS|SIN|TAN2?)</keyword>
+      <keyword>BITAND</keyword>
+      <keyword>CEIL</keyword>
+      <keyword>(COS|SIN|TAN)H?</keyword>
+      <keyword>EXP</keyword>
+      <keyword>FLOOR</keyword>
+      <keyword>LN</keyword>
+      <keyword>LOG</keyword>
+      <keyword>MOD</keyword>
+      <keyword>NANVL</keyword>
+      <keyword>POWER</keyword>
+      <keyword>REMAINDER</keyword>
+      <keyword>ROUND</keyword>
+      <keyword>SIGN</keyword>
+      <keyword>SQRT</keyword>
+      <keyword>TRUNC</keyword>
+      <keyword>WIDTH_BUCKET</keyword>
+    </context>
+
+    <context id="character-functions-returning-character-values" style-ref="function">
+      <keyword>N?CHR</keyword>
+      <keyword>CONCAT</keyword>
+      <keyword>(NLS_)?(INITCAP|LOWER|UPPER)</keyword>
+      <keyword>(L|R)PAD</keyword>
+      <keyword>(L|R)?TRIM</keyword>
+      <keyword>NLSSORT</keyword>
+      <keyword>REGEXP_(REPLACE|SUBSTR)</keyword>
+      <keyword>REPLACE</keyword>
+      <keyword>SOUNDEX</keyword>
+      <keyword>SUBSTR</keyword>
+      <keyword>TRANSLATE</keyword>
+      <keyword>TREAT</keyword>
+    </context>
+
+    <context id="nls-character-functions" style-ref="function">
+      <keyword>NLS_CHARSET_DECL_LEN</keyword>
+      <keyword>NLS_CHARSET_(ID|NAME)</keyword>
+    </context>
+
+    <context id="character-functions-returning-number-values" style-ref="function">
+      <keyword>ASCII</keyword>
+      <keyword>INSTR</keyword>
+      <keyword>LENGTH</keyword>
+      <keyword>REGEXP_INSTR</keyword>
+    </context>
+
+    <context id="datetime-functions" style-ref="function">
+      <keyword>ADD_MONTHS</keyword>
+      <keyword>CURRENT_(DATE|TIMESTAMP)</keyword>
+      <keyword>DBTIMEZONE</keyword>
+      <keyword>EXTRACT</keyword>
+      <keyword>FROM_TZ</keyword>
+      <keyword>(LAST|NEXT)_DAY</keyword>
+      <keyword>LOCALTIMESTAMP</keyword>
+      <keyword>MONTHS_BETWEEN</keyword>
+      <keyword>NEW_TIME</keyword>
+      <keyword>NUMTO(DS|YM)INTERVAL</keyword>
+      <keyword>ROUND</keyword>
+      <keyword>SESSIONTIMEZONE</keyword>
+      <keyword>SYS_EXTRACT_UTC</keyword>
+      <keyword>SYS(DATE|TIMESTAMP)</keyword>
+      <keyword>TO_CHAR</keyword>
+      <keyword>TO_(DS|YM)INTERVAL</keyword>
+      <keyword>TO_TIMESTAMP(_TZ)?</keyword>
+      <keyword>TRUNC</keyword>
+      <keyword>TZ_OFFSET</keyword>
+    </context>
+
+    <context id="general-comparison-functions" style-ref="function">
+      <keyword>GREATEST</keyword>
+      <keyword>LEAST</keyword>
+    </context>
+
+    <context id="conversion-functions" style-ref="function">
+      <keyword>ASCIISTR</keyword>
+      <keyword>BIN_TO_NUM</keyword>
+      <keyword>CAST</keyword>
+      <keyword>CHARTOROWID</keyword>
+      <keyword>(DE)?COMPOSE</keyword>
+      <keyword>CONVERT</keyword>
+      <keyword>HEXTORAW</keyword>
+      <keyword>NUMTO(DS|YM)INTERVAL</keyword>
+      <keyword>RAWTON?HEX</keyword>
+      <keyword>ROWIDTON?CHAR</keyword>
+      <keyword>SCN_TO_TIMESTAMP</keyword>
+      <keyword>TIMESTAMP_TO_SCN</keyword>
+      <keyword>TO_BINARY_(DOUBLE|FLOAT)</keyword>
+      <keyword>TO_N?(CHAR|CLOB)</keyword>
+      <keyword>TO_DATE</keyword>
+      <keyword>TO_(DS|YM)INTERVAL</keyword>
+      <keyword>TO_LOB</keyword>
+      <keyword>TO_(MULTI|SINGLE)_BYTE</keyword>
+      <keyword>TO_NUMBER</keyword>
+      <keyword>TRANSLATE</keyword>
+      <keyword>UNISTR</keyword>
+    </context>
+
+    <context id="large-object-functions" style-ref="function">
+      <keyword>BFILENAME</keyword>
+      <keyword>EMPTY_(B|C)LOB</keyword>
+    </context>
+
+    <context id="collection-functions" style-ref="function">
+      <keyword>CARDINALITY</keyword>
+      <keyword>COLLECT</keyword>
+      <keyword>POWERMULTISET(_BY_CARDINALITY)?</keyword>
+    </context>
+
+    <context id="hierarchical-function" style-ref="function">
+      <keyword>SYS_CONNECT_BY_PATH</keyword>
+    </context>
+
+    <context id="data-mining-functions" style-ref="function">
+      <keyword>CLUSTER_(ID|PROBABILITY|SET)</keyword>
+      <keyword>FEATURE_(ID|SET|VALUE)</keyword>
+      <keyword>PREDICTION</keyword>
+      <keyword>PREDICTION_(COST|DETAILS|PROBABILITY|SET)</keyword>
+    </context>
+
+    <context id="xml-functions" style-ref="function">
+      <keyword>(APPEND|INSERT)CHILDXML</keyword>
+      <keyword>(DELETE|UPDATE)XML</keyword>
+      <keyword>DEPTH</keyword>
+      <keyword>EXISTSNODE</keyword>
+      <keyword>EXTRACT(VALUE)?</keyword>
+      <keyword>INSERTXMLBEFORE</keyword>
+      <keyword>PATH</keyword>
+      <keyword>SYS_DBURIGEN</keyword>
+      <keyword>SYS_XML(AGG|GEN)</keyword>
+      <keyword>XML(AGG|CDATA|COLATTVAL|COMMENT|CONCAT|ELEMENT|FOREST|PARSE|PI|QUERY|ROOT|SEQUENCE|SERIALIZE|TABLE|TRANSFORM)</keyword>
+    </context>
+
+    <context id="encoding-and-decoding-functions" style-ref="function">
+      <keyword>DECODE</keyword>
+      <keyword>DUMP</keyword>
+      <keyword>ORA_HASH</keyword>
+      <keyword>VSIZE</keyword>
+    </context>
+
+    <context id="null-related-functions" style-ref="function">
+      <keyword>COALESCE</keyword>
+      <keyword>LNNVL</keyword>
+      <keyword>NULLIF</keyword>
+      <keyword>NVL2?</keyword>
+    </context>
+
+    <context id="environment-and-identifier-functions" style-ref="function">
+      <keyword>SYS_CONTEXT</keyword>
+      <keyword>SYS_GUID</keyword>
+      <keyword>SYS_TYPEID</keyword>
+      <keyword>UID</keyword>
+      <keyword>USER</keyword>
+      <keyword>USERENV</keyword>
+    </context>
+
+    <context id="aggregate-functions" style-ref="function">
+      <keyword>AVG</keyword>
+      <keyword>CORR(_(S|K))?</keyword>
+      <keyword>COUNT</keyword>
+      <keyword>COVAR_(POP|SAMP)</keyword>
+      <keyword>CUME_DIST</keyword>
+      <keyword>(DENSE|PERCENT)_RANK</keyword>
+      <keyword>FIRST|LAST</keyword>
+      <keyword>GROUP_ID</keyword>
+      <keyword>GROUPING(_ID)?</keyword>
+      <keyword>MAX|MIN</keyword>
+      <keyword>MEDIAN</keyword>
+      <keyword>PERCENTILE_(CONT|DISC)</keyword>
+      <keyword>RANK</keyword>
+      <keyword>REGR_(SLOPE|INTERCEPT|COUNT|R2|AVGX|AVGY|SXX|SYY|SXY)</keyword>
+      <keyword>STATS_((BINOMIAL|F|KS|MW|WSR)_TEST|CROSSTAB|MODE|ONE_WAY_ANOVA|T_TEST_(ONE|PAIRED|INDEPU?))</keyword>
+      <keyword>STDDEV|VARIANCE</keyword>
+      <keyword>(STDDEV|VAR)_(POP|SAMP)</keyword>
+      <keyword>SUM</keyword>
+    </context>
+
+    <context id="analytic-functions" style-ref="function">
+      <keyword>AVG</keyword>
+      <keyword>CORR</keyword>
+      <keyword>COVAR_(POP|SAMP)</keyword>
+      <keyword>COUNT</keyword>
+      <keyword>CUME_DIST</keyword>
+      <keyword>(DENSE|PERCENT)_RANK</keyword>
+      <keyword>(FIRST|LAST)(_VALUE)?</keyword>
+      <keyword>LAG</keyword>
+      <keyword>LEAD</keyword>
+      <keyword>MAX|MIN</keyword>
+      <keyword>NTILE</keyword>
+      <keyword>PERCENTILE_(CONT|DISC)</keyword>
+      <keyword>RANK</keyword>
+      <keyword>RATIO_TO_REPORT</keyword>
+      <keyword>REGR_(SLOPE|INTERCEPT|COUNT|R2|AVGX|AVGY|SXX|SYY|SXY)</keyword>
+      <keyword>ROW_NUMBER</keyword>
+      <keyword>STDDEV|VARIANCE</keyword>
+      <keyword>(STDDEV|VAR)_(POP|SAMP)</keyword>
+      <keyword>SUM</keyword>
+    </context>
+
+    <context id="object-reference-functions" style-ref="function">
+      <keyword>DEREF</keyword>
+      <keyword>MAKE_REF</keyword>
+      <keyword>REF</keyword>
+      <keyword>REFTOHEX</keyword>
+      <keyword>VALUE</keyword>
+    </context>
+
+    <context id="model-functions" style-ref="function">
+      <keyword>CV</keyword>
+      <keyword>ITERATION_NUMBER</keyword>
+      <keyword>PRESENT(NN)?V</keyword>
+      <keyword>PREVIOUS</keyword>
+    </context>
+
+    <context id="ansi-reserved-words" style-ref="keyword">
+      <keyword>ADD</keyword>
+      <keyword>ALL</keyword>
+      <keyword>ALTER</keyword>
+      <keyword>AND</keyword>
+      <keyword>ANY</keyword>
+      <keyword>AS</keyword>
+      <keyword>ASC</keyword>
+      <keyword>BETWEEN</keyword>
+      <keyword>BY</keyword>
+      <keyword>CASE</keyword>
+      <keyword>CHECK</keyword>
+      <keyword>CREATE</keyword>
+      <keyword>CROSS</keyword>
+      <keyword>CURRENT</keyword>
+      <keyword>DECIMAL</keyword>
+      <keyword>DEFAULT</keyword>
+      <keyword>DELETE</keyword>
+      <keyword>DISTINCT</keyword>
+      <keyword>DROP</keyword>
+      <keyword>ELSE</keyword>
+      <keyword>END</keyword>
+      <keyword>FLOAT</keyword>
+      <keyword>FOR</keyword>
+      <keyword>FROM</keyword>
+      <keyword>FULL</keyword>
+      <keyword>GRANT</keyword>
+      <keyword>GROUP</keyword>
+      <keyword>HAVING</keyword>
+      <keyword>IMMEDIATE</keyword>
+      <keyword>INNER</keyword>
+      <keyword>INSERT</keyword>
+      <keyword>INTEGER</keyword>
+      <keyword>INTERSECT</keyword>
+      <keyword>INTO</keyword>
+      <keyword>IN</keyword>
+      <keyword>IS</keyword>
+      <keyword>JOIN</keyword>
+      <keyword>LEFT</keyword>
+      <keyword>LEVEL</keyword>
+      <keyword>LIKE</keyword>
+      <keyword>NATURAL</keyword>
+      <keyword>NOT</keyword>
+      <keyword>OF</keyword>
+      <keyword>ON</keyword>
+      <keyword>OPTION</keyword>
+      <keyword>ORDER</keyword>
+      <keyword>OR</keyword>
+      <keyword>OUTER</keyword>
+      <keyword>PRIOR</keyword>
+      <keyword>PRIVILEGES</keyword>
+      <keyword>PUBLIC</keyword>
+      <keyword>REVOKE</keyword>
+      <keyword>RIGHT</keyword>
+      <keyword>ROWS</keyword>
+      <keyword>SELECT</keyword>
+      <keyword>SESSION</keyword>
+      <keyword>SET</keyword>
+      <keyword>SIZE</keyword>
+      <keyword>SMALLINT</keyword>
+      <keyword>TABLE</keyword>
+      <keyword>THEN</keyword>
+      <keyword>TO</keyword>
+      <keyword>UNION</keyword>
+      <keyword>UNIQUE</keyword>
+      <keyword>UPDATE</keyword>
+      <keyword>USING</keyword>
+      <keyword>VALUES</keyword>
+      <keyword>VIEW</keyword>
+      <keyword>WHEN</keyword>
+      <keyword>WITH</keyword>
+    </context>
+
+    <context id="oracle-reserved-words" style-ref="keyword">
+      <keyword>ACCESS</keyword>
+      <keyword>AUDIT</keyword>
+      <keyword>CLUSTER</keyword>
+      <keyword>COMMENT</keyword>
+      <keyword>COMPRESS</keyword>
+      <keyword>CONNECT[ \t]+BY</keyword>
+      <keyword>CUBE</keyword>
+      <keyword>EXCLUSIVE</keyword>
+      <keyword>EXISTS</keyword>
+      <keyword>FILE</keyword>
+      <keyword>GROUPING[ \t]+SETS</keyword>
+      <keyword>IDENTIFIED</keyword>
+      <keyword>INCREMENT</keyword>
+      <keyword>INDEX</keyword>
+      <keyword>INITIAL</keyword>
+      <keyword>LOCK</keyword>
+      <keyword>MAXEXTENTS</keyword>
+      <keyword>MINUS</keyword>
+      <keyword>MLSLABEL</keyword>
+      <keyword>MODE</keyword>
+      <keyword>MODIFY</keyword>
+      <keyword>NOAUDIT</keyword>
+      <keyword>NOCOMPRESS</keyword>
+      <keyword>NOCYCLE</keyword>
+      <keyword>NOWAIT</keyword>
+      <keyword>OFFLINE</keyword>
+      <keyword>ONLINE</keyword>
+      <keyword>PCTFREE</keyword>
+      <keyword>RENAME</keyword>
+      <keyword>RESOURCE</keyword>
+      <keyword>ROLLUP</keyword>
+      <keyword>ROW</keyword>
+      <keyword>ROWNUM</keyword>
+      <keyword>SHARE</keyword>
+      <keyword>SIBLINGS</keyword>
+      <keyword>START[ \t]+WITH</keyword>
+      <keyword>SUCCESSFUL</keyword>
+      <keyword>SYNONYM</keyword>
+      <keyword>TRIGGER</keyword>
+      <keyword>VALIDATE</keyword>
+      <keyword>WHERE</keyword>
+    </context>
+
+    <context id="sql-statements" style-ref="keyword">
+      <prefix>^[ \t]*</prefix>
+      <keyword>ALTER[ \t]+(CLUSTER|DATABASE|DIMENSION|DISKGROUP|FUNCTION|INDEX(TYPE)?|JAVA|MATERIALIZED[ \t]+VIEW([ \t]+LOG)?|OPERATOR|OUTLINE|PACKAGE|PROCEDURE|PROFILE|RESOURCE[ \t]+COST|ROLE|ROLLBACK[ \t]+SEGMENT|SEQUENCE|SESSION|SYSTEM|TABLE(SPACE)?|TRIGGER|TYPE|USER|VIEW)</keyword>
+      <keyword>ANALYZE</keyword>
+      <keyword>(DIS)?ASSOCIATE[ \t]+STATISTICS</keyword>
+      <keyword>CALL</keyword>
+      <keyword>COMMIT([ \t]+WORK)?</keyword>
+      <keyword>CREATE[ \t]+(CLUSTER|CONTEXT|CONTROLFILE|DATABASE([ \t]+LINK)?|DIMENSION|DIRECTORY|DISKGROUP|FUNCTION|INDEX(TYPE)?|JAVA|LIBRARY|MATERIALIZED[ \t]+VIEW([ \t]+LOG)?|OPERATOR|OUTLINE|PACKAGE([ \t]+BODY)?|S?PFILE|PROCEDURE|PROFILE|RESTORE[ \t]+POINT|ROLE|ROLLBACK[ \t]+SEGMENT|SCHEMA|SEQUENCE|SYNONYM|TABLE(SPACE)?|TRIGGER|TYPE([ \t]+BODY)?|USER|VIEW)</keyword>
+      <keyword>DROP[ \t]+(CLUSTER|CONTEXT|DATABASE([ \t]+LINK)?|DIMENSION|DIRECTORY|DISKGROUP|FUNCTION|INDEX(TYPE)?|JAVA|LIBRARY|MATERIALIZED[ \t]+VIEW([ \t]+LOG)?|OPERATOR|OUTLINE|PACKAGE|PROCEDURE|PROFILE|RESTORE[ \t]+POINT|ROLE|ROLLBACK[ \t]+SEGMENT|SEQUENCE|SYNONYM|TABLE(SPACE)?|TRIGGER|TYPE([ \t]+BODY)?|USER|VIEW)</keyword>
+      <keyword>EXPLAIN[ \t]+PLAN</keyword>
+      <keyword>FLASHBACK[ \t]+(DATABASE|TABLE)</keyword>
+      <keyword>LOCK[ \t]+TABLE</keyword>
+      <keyword>MERGE</keyword>
+      <keyword>PURGE</keyword>
+      <keyword>ROLLBACK</keyword>
+      <keyword>SAVEPOINT</keyword>
+      <keyword>SET[ \t]+CONSTRAINTS?</keyword>
+      <keyword>SET[ \t]+ROLE</keyword>
+      <keyword>SET[ \t]+TRANSACTION</keyword>
+      <keyword>TRUNCATE</keyword>
+    </context>
+
+    <context id="operators" style-ref="keyword">
+      <keyword>CONNECT_BY_ROOT</keyword>
+      <keyword>MULTISET[ \t]+(EXCEPT|INTERSECT|UNION)</keyword>
+    </context>
+
+    <context id="conditions" style-ref="keyword">
+      <keyword>SOME</keyword>
+      <keyword>IS[ \t]+(NOT[ \t]+)?(NAN|INFINITE)</keyword>
+      <keyword>IS[ \t]+(NOT[ \t]+)?NULL</keyword>
+      <keyword>(EQUALS|UNDER)_PATH</keyword>
+      <keyword>(NOT[ \t]+)?IN</keyword>
+      <keyword>IS[ \t]+(NOT[ \t]+)?A[ \t]+SET</keyword>
+      <keyword>IS[ \t]+(NOT[ \t]+)?EMPTY</keyword>
+      <keyword>IS[ \t]+(NOT[ \t]+)?OF([ \t]+TYPE)?</keyword>
+      <keyword>IS[ \t]+PRESENT</keyword>
+      <keyword>(NOT[ \t]+)?LIKE(C|2|4)?</keyword>
+      <keyword>(NOT[ \t]+)?MEMBER([ \t]+OF)?</keyword>
+      <keyword>REGEXP_LIKE</keyword>
+      <keyword>(NOT[ \t]+)?SUBMULTISET([ \t]+OF)?</keyword>
+    </context>
+
+    <context id="sql-plus-at-sign" style-ref="some-thing">
+      <match>^[ \t]*@</match>
+    </context>
+
+    <context id="sql-plus-double-at-sign" style-ref="some-thing">
+      <match>^[ \t]*@@</match>
+    </context>
+
+    <context id="sql-plus-slash" style-ref="some-thing">
+      <match>^[ \t]*/</match>
+    </context>
+
+    <context id="sql-plus-commands" style-ref="some-thing">
+      <prefix>^[ \t]*</prefix>
+      <keyword>ACC(EPT)?</keyword>
+      <keyword>A(PPEND)?</keyword>
+      <keyword>ARCHIVE[ \t]LOG</keyword>
+      <keyword>ATTRIBUTE</keyword>
+      <keyword>BRE(AK)?</keyword>
+      <keyword>BTI(TLE)?</keyword>
+      <keyword>C(HANGE)?</keyword>
+      <keyword>CL(EAR)?</keyword>
+      <keyword>COL(UMN)?</keyword>
+      <keyword>COMP(UTE)?</keyword>
+      <keyword>CONN(ECT)?</keyword>
+      <keyword>COPY</keyword>
+      <keyword>DEF(INE)?</keyword>
+      <keyword>DEL</keyword>
+      <keyword>DESC(RIBE)?</keyword>
+      <keyword>DISC(ONNECT)?</keyword>
+      <keyword>ED(IT)?</keyword>
+      <keyword>EXEC(UTE)?</keyword>
+      <keyword>EXIT|QUIT</keyword>
+      <keyword>GET</keyword>
+      <keyword>HELP</keyword>
+      <keyword>HO(ST)?</keyword>
+      <keyword>I(NPUT)?</keyword>
+      <keyword>L(IST)?</keyword>
+      <keyword>PASSW(ORD)?</keyword>
+      <keyword>PAU(SE)?</keyword>
+      <keyword>PRI(NT)?</keyword>
+      <keyword>PRO(MPT)?</keyword>
+      <keyword>RECOVER</keyword>
+      <keyword>REM(ARK)?</keyword>
+      <keyword>REPF(OOTER)?</keyword>
+      <keyword>REPH(EADER)?</keyword>
+      <keyword>R(UN)?</keyword>
+      <keyword>SAV(E)?</keyword>
+      <keyword>SET[ \t]+(APPI(NFO)?|ARRAY(SIZE)?|AUTO(COMMIT)?|AUTOP(RINT)?|AUTORECOVERY|AUTOT(RACE)?|BLO(CKTERMINATOR)?|CMDS(EP)?|COLSEP|COM(PATIBILITY)?|CON(CAT)?|COPYC(OMMIT)?|COPYTYPECHECK|DEF(INE)?|DESCRIBE|ECHO|EDITF(ILE)?|EMB(EDDED)?|ESC(APE)?|FEED(BACK)?|FLAGGER|FLU(SH)?|HEA(DING)?|HEADS(EP)?|INSTANCE|LIN(ESIZE)?|LOBOF(FSET)?|LOGSOURCE|LONG|LONGC(HUNKSIZE)?|MARK(UP)?|NEWP(AGE)?|NULL|NUMF(ORMAT)?|NUM(WIDTH)?|PAGES(IZE)?|PAU(SE)?|RECSEP|RECSEPCHAR|SERVEROUT(PUT)?|SHIFT(INOUT)?|SHOW(MODE)?|SQLBL(ANKLINES)?|SQLC(ASE)?|SQLCO(NTINUE)?|SQLN(UMBER)?|SQLPLUSCOMPAT(IBILITY)?|SQLPRE(FIX)?|SQLP(ROMPT)?|SQLT(ERMINATOR)?|SUF(FIX)?|TAB|TERM(OUT)?|TI(ME)?|TIMI(NG)?|TRIM(OUT)?|TRIMS(POOL)?|UND(ERLINE)?|VER(IFY)?|WRA(P)?)</keyword>
+      <keyword>SHO(W)?</keyword>
+      <keyword>SHUTDOWN</keyword>
+      <keyword>SPO(OL)?</keyword>
+      <keyword>STA(RT)?</keyword>
+      <keyword>STARTUP</keyword>
+      <keyword>STORE</keyword>
+      <keyword>TIMI(NG)?</keyword>
+      <keyword>TTI(TLE)?</keyword>
+      <keyword>UNDEF(INE)?</keyword>
+      <keyword>VAR(IABLE)?</keyword>
+      <keyword>WHENEVER[ \t]+(OS|SQL)ERROR</keyword>
+    </context>
+
+    <context id="gda-sql">
+      <include>
+        <context ref="oracle-built-in-datatypes"/>
+        <context ref="ansi-datatypes"/>
+        <context ref="sql-ds-and-db2-datatypes"/>
+        <context ref="oracle-supplied-types"/>
+        <context ref="text-literals"/>
+        <context ref="integer-literals"/>
+	<context ref="shortvariable"/>
+	<context ref="longvariable"/>
+        <context ref="number-literals"/>
+        <context ref="size-clause"/>
+        <context ref="unlimited"/>
+        <context ref="null"/>
+        <context ref="block-comment"/>
+        <context ref="line-comment"/>
+        <context ref="numeric-functions"/>
+        <context ref="character-functions-returning-character-values"/>
+        <context ref="nls-character-functions"/>
+        <context ref="character-functions-returning-number-values"/>
+        <context ref="datetime-functions"/>
+        <context ref="general-comparison-functions"/>
+        <context ref="conversion-functions"/>
+        <context ref="large-object-functions"/>
+        <context ref="collection-functions"/>
+        <context ref="hierarchical-function"/>
+        <context ref="data-mining-functions"/>
+        <context ref="xml-functions"/>
+        <context ref="encoding-and-decoding-functions"/>
+        <context ref="null-related-functions"/>
+        <context ref="environment-and-identifier-functions"/>
+        <context ref="aggregate-functions"/>
+        <context ref="analytic-functions"/>
+        <context ref="object-reference-functions"/>
+        <context ref="model-functions"/>
+        <context ref="ansi-reserved-words"/>
+        <context ref="oracle-reserved-words"/>
+        <context ref="sql-statements"/>
+        <context ref="operators"/>
+        <context ref="conditions"/>
+        <context ref="sql-plus-at-sign"/>
+        <context ref="sql-plus-double-at-sign"/>
+        <context ref="sql-plus-slash"/>
+        <context ref="sql-plus-commands"/>
+      </include>
+    </context>
+
+  </definitions>
+</language>
diff --git a/tools/browser/query-exec/query-console.c b/tools/browser/query-exec/query-console.c
index 9b5944c..3f7f429 100644
--- a/tools/browser/query-exec/query-console.c
+++ b/tools/browser/query-exec/query-console.c
@@ -40,11 +40,17 @@ struct _QueryConsolePrivate {
 	CcGrayBar *header;
 	GtkWidget *vpaned; /* top=>query editor, bottom=>results */
 	QueryEditor *editor;
+
+	GtkToggleButton *params_toggle;
+	GtkWidget *params_form;
+	
+	QueryEditor *history;
 };
 
 static void query_console_class_init (QueryConsoleClass *klass);
 static void query_console_init       (QueryConsole *tconsole, QueryConsoleClass *klass);
 static void query_console_dispose   (GObject *object);
+static void query_console_show_all (GtkWidget *widget);
 
 /* BrowserPage interface */
 static void                 query_console_page_init (BrowserPageIface *iface);
@@ -71,6 +77,19 @@ query_console_class_init (QueryConsoleClass *klass)
 	parent_class = g_type_class_peek_parent (klass);
 
 	object_class->dispose = query_console_dispose;
+	GTK_WIDGET_CLASS (klass)->show_all = query_console_show_all;
+}
+
+static void
+query_console_show_all (GtkWidget *widget)
+{
+	QueryConsole *tconsole = (QueryConsole *) widget;
+	GTK_WIDGET_CLASS (parent_class)->show_all (widget);
+
+	if (gtk_toggle_button_get_active (tconsole->priv->params_toggle))
+		gtk_widget_show (tconsole->priv->params_form);
+	else
+		gtk_widget_hide (tconsole->priv->params_form);
 }
 
 static void
@@ -137,6 +156,14 @@ query_console_get_type (void)
 	return type;
 }
 
+static GtkWidget *make_small_button (gboolean is_toggle,
+				     const gchar *label, const gchar *stock_id, const gchar *tooltip);
+
+static void sql_clear_clicked_cb (GtkButton *button, QueryConsole *tconsole);
+static void sql_variables_clicked_cb (GtkToggleButton *button, QueryConsole *tconsole);
+static void sql_execute_clicked_cb (GtkButton *button, QueryConsole *tconsole);
+static void sql_indent_clicked_cb (GtkButton *button, QueryConsole *tconsole);
+
 /**
  * query_console_new
  *
@@ -169,22 +196,200 @@ query_console_new (BrowserConnection *bcnc)
 	tconsole->priv->vpaned = NULL;
 	gtk_box_pack_start (GTK_BOX (tconsole), vpaned, TRUE, TRUE, 0);	
 
-	GtkWidget *wid;
+	/* top paned for the editor */
+	GtkWidget *wid, *vbox, *hbox, *bbox, *hpaned, *button;
+
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_paned_add1 (GTK_PANED (vpaned), vbox);
+
+	wid = gtk_label_new ("");
+	str = g_strdup_printf ("<b>%s</b>", _("SQL code to execute:"));
+	gtk_label_set_markup (GTK_LABEL (wid), str);
+	g_free (str);
+	gtk_misc_set_alignment (GTK_MISC (wid), 0., -1);
+	gtk_box_pack_start (GTK_BOX (vbox), wid, FALSE, FALSE, 0);
+
+	hbox = gtk_hbox_new (FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
+
+	hpaned = gtk_hpaned_new ();
+	gtk_box_pack_start (GTK_BOX (hbox), hpaned, TRUE, TRUE, 0);
+
 	wid = query_editor_new ();
 	tconsole->priv->editor = QUERY_EDITOR (wid);
-	gtk_paned_add1 (GTK_PANED (vpaned), wid);
+	gtk_paned_pack1 (GTK_PANED (hpaned), wid, TRUE, FALSE);
+	
+	wid = gtk_label_new ("Here goes the\nparams' form");
+	tconsole->priv->params_form = wid;
+	gtk_paned_pack2 (GTK_PANED (hpaned), wid, FALSE, TRUE);
+	
+	bbox = gtk_vbutton_box_new ();
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+	gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, FALSE, 5);
+
+	button = make_small_button (FALSE, _("Clear"), GTK_STOCK_CLEAR, _("Clear the editor"));
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (sql_clear_clicked_cb), tconsole);
+
+	button = make_small_button (TRUE, _("Variables"), NULL, _("Show variables needed\nto execute SQL"));
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+	tconsole->priv->params_toggle = GTK_TOGGLE_BUTTON (button);
+	g_signal_connect (button, "toggled",
+			  G_CALLBACK (sql_variables_clicked_cb), tconsole);
+
+	button = make_small_button (FALSE, _("Execute"), GTK_STOCK_EXECUTE, _("Execute SQL in editor"));
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (sql_execute_clicked_cb), tconsole);
+	
+	button = make_small_button (FALSE, _("Indent"), GTK_STOCK_INDENT, _("Indent SQL in editor"));
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (sql_indent_clicked_cb), tconsole);
+
+	/* bottom paned for the results and history */
+	hpaned = gtk_hpaned_new ();
+	gtk_paned_add2 (GTK_PANED (vpaned), hpaned);
+
+	/* bottom left */
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_paned_pack1 (GTK_PANED (hpaned), vbox, FALSE, TRUE);
+
+	wid = gtk_label_new ("");
+	str = g_strdup_printf ("<b>%s</b>", _("Execution history:"));
+	gtk_label_set_markup (GTK_LABEL (wid), str);
+	g_free (str);
+	gtk_misc_set_alignment (GTK_MISC (wid), 0., -1);
+	gtk_box_pack_start (GTK_BOX (vbox), wid, FALSE, FALSE, 0);
+
+	wid = query_editor_new ();
+	tconsole->priv->history = QUERY_EDITOR (wid);
+	query_editor_set_mode (tconsole->priv->history, QUERY_EDITOR_HISTORY);
+	gtk_widget_set_size_request (wid, 200, -1);
+	gtk_box_pack_start (GTK_BOX (vbox), wid, TRUE, TRUE, 0);
+
+	bbox = gtk_vbutton_box_new ();
+	gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+
+	button = make_small_button (FALSE, _("Delete"), GTK_STOCK_DELETE, _("Delete history item"));
+	gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
+
+	/* bottom right */
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_paned_pack2 (GTK_PANED (hpaned), vbox, TRUE, FALSE);
+	
+	wid = gtk_label_new ("");
+	str = g_strdup_printf ("<b>%s</b>", _("Execution Results:"));
+	gtk_label_set_markup (GTK_LABEL (wid), str);
+	g_free (str);
+	gtk_misc_set_alignment (GTK_MISC (wid), 0., -1);
+	gtk_box_pack_start (GTK_BOX (vbox), wid, FALSE, FALSE, 0);
+
+	wid = gtk_label_new ("Here go the\nresults' form");
+	gtk_box_pack_start (GTK_BOX (vbox), wid, TRUE, TRUE, 0);
 
 	/* show everything */
         gtk_widget_show_all (vpaned);
+	gtk_widget_hide (tconsole->priv->params_form);
 
 	return (GtkWidget*) tconsole;
 }
 
-/*
- * UI actions
- */
+static GtkWidget *
+make_small_button (gboolean is_toggle, const gchar *label, const gchar *stock_id, const gchar *tooltip)
+{
+	GtkWidget *button, *hbox = NULL;
+
+	if (is_toggle)
+		button = gtk_toggle_button_new ();
+	else
+		button = gtk_button_new ();
+	if (label && stock_id) {
+		hbox = gtk_hbox_new (FALSE, 0);
+		gtk_container_add (GTK_CONTAINER (button), hbox);
+		gtk_widget_show (hbox);
+	}
+
+	if (stock_id) {
+		GtkWidget *image;
+		image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
+		if (hbox)
+			gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+		else
+			gtk_container_add (GTK_CONTAINER (button), image);
+		gtk_widget_show (image);
+	}
+	if (label) {
+		GtkWidget *wid;
+		wid = gtk_label_new (label);
+		if (hbox)
+			gtk_box_pack_start (GTK_BOX (hbox), wid, FALSE, FALSE, 5);
+		else
+			gtk_container_add (GTK_CONTAINER (button), wid);
+		gtk_widget_show (wid);
+	}
+
+	if (tooltip)
+		gtk_widget_set_tooltip_text (button, tooltip);
+	return button;
+}
+
 static void
-query_execute_cb (GtkAction *action, QueryConsole *tconsole)
+sql_variables_clicked_cb (GtkToggleButton *button, QueryConsole *tconsole)
+{
+	if (gtk_toggle_button_get_active (button))
+		gtk_widget_show (tconsole->priv->params_form);
+	else
+		gtk_widget_hide (tconsole->priv->params_form);
+}
+
+static void
+sql_clear_clicked_cb (GtkButton *button, QueryConsole *tconsole)
+{
+	query_editor_set_text (tconsole->priv->editor, NULL);
+}
+
+static void
+sql_indent_clicked_cb (GtkButton *button, QueryConsole *tconsole)
+{
+	gchar *sql;
+	GdaBatch *batch;
+
+	if (!tconsole->priv->parser)
+		tconsole->priv->parser = browser_connection_create_parser (tconsole->priv->bcnc);
+
+	sql = query_editor_get_all_text (tconsole->priv->editor);
+	batch = gda_sql_parser_parse_string_as_batch (tconsole->priv->parser, sql, NULL, NULL);
+	g_free (sql);
+	if (batch) {
+		GString *string;
+		const GSList *stmt_list, *list;
+		stmt_list = gda_batch_get_statements (batch);
+		string = g_string_new ("");
+		for (list = stmt_list; list; list = list->next) {
+			GError *error = NULL;
+			sql = gda_statement_to_sql_extended (GDA_STATEMENT (list->data), NULL, NULL,
+							     GDA_STATEMENT_SQL_PRETTY |
+							     GDA_STATEMENT_SQL_PARAMS_SHORT,
+							     NULL, &error);
+			if (!sql)
+				sql = gda_statement_to_sql (GDA_STATEMENT (list->data), NULL, NULL);
+			if (list != stmt_list)
+				g_string_append (string, "\n\n");
+			g_string_append_printf (string, "%s;\n", sql);
+			g_free (sql);
+
+		}
+		g_object_unref (batch);
+
+		query_editor_set_text (tconsole->priv->editor, string->str);
+		g_string_free (string, TRUE);
+	}
+}
+
+static void
+sql_execute_clicked_cb (GtkButton *button, QueryConsole *tconsole)
 {
 	gchar *sql;
 	const gchar *remain;
@@ -204,9 +409,44 @@ query_execute_cb (GtkAction *action, QueryConsole *tconsole)
 		g_free (sql);
 		return;
 	}
-
 	g_free (sql);
-	TO_IMPLEMENT;
+
+	QueryEditorHistoryBatch *hbatch;
+	GTimeVal tv;
+	g_get_current_time (&tv);
+	hbatch = query_editor_history_batch_new (tv);
+	query_editor_start_history_batch (tconsole->priv->history, hbatch);
+	query_editor_history_batch_unref (hbatch);
+
+	const GSList *stmt_list, *list;
+	stmt_list = gda_batch_get_statements (batch);
+	for (list = stmt_list; list; list = list->next) {
+		QueryEditorHistoryItem *history;
+		GdaSqlStatement *sqlst;
+		g_object_get (G_OBJECT (list->data), "structure", &sqlst, NULL);
+		if (!sqlst->sql) {
+			sql = gda_statement_to_sql (GDA_STATEMENT (list->data), NULL, NULL);
+			history = query_editor_history_item_new (sql, NULL, NULL);
+			g_free (sql);
+		}
+		else
+			history = query_editor_history_item_new (sqlst->sql, NULL, NULL);
+		gda_sql_statement_free (sqlst);
+
+		query_editor_add_history_item (tconsole->priv->history, history);
+		query_editor_history_item_unref (history);
+	}
+	g_object_unref (batch);
+}
+
+
+/*
+ * UI actions
+ */
+static void
+query_execute_cb (GtkAction *action, QueryConsole *tconsole)
+{
+	sql_execute_clicked_cb (NULL, tconsole);
 }
 
 #ifdef HAVE_GTKSOURCEVIEW
diff --git a/tools/browser/query-exec/query-editor.c b/tools/browser/query-exec/query-editor.c
index 27349c9..765ac7b 100644
--- a/tools/browser/query-exec/query-editor.c
+++ b/tools/browser/query-exec/query-editor.c
@@ -1,5 +1,5 @@
 /* GNOME DB library
- * Copyright (C) 1999 - 2008 The GNOME Foundation.
+ * Copyright (C) 1999 - 2009 The GNOME Foundation.
  *
  * AUTHORS:
  *      Rodrigo Moya <rodrigo gnome-db org>
@@ -21,33 +21,82 @@
  * Boston, MA 02111-1307, USA.
  */
 
+#include <glib/gi18n-lib.h>
 #include <string.h>
 #include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
 #ifdef HAVE_GTKSOURCEVIEW
   #include <gtksourceview/gtksourceview.h>
   #include <gtksourceview/gtksourcelanguagemanager.h>
   #include <gtksourceview/gtksourcebuffer.h>
+  #include <gtksourceview/gtksourcestyleschememanager.h>
+  #include <gtksourceview/gtksourcestylescheme.h>
 #endif
 #include "query-editor.h"
+#include <binreloc/gda-binreloc.h>
 
-#define PARENT_TYPE GTK_TYPE_VBOX
+#define QUERY_EDITOR_LANGUAGE_SQL "gda-sql"
 
 typedef void (* CreateTagsFunc) (QueryEditor *editor, const gchar *language);
 
+typedef struct {
+	QueryEditorHistoryBatch *batch; /* ref held here */
+	QueryEditorHistoryItem *item; /* ref held here */
+	GtkTextTag *tag; /* ref held here */
+	GtkTextMark *start_mark; /* ref NOT held here */
+	GtkTextMark *end_mark; /* ref NOT held here */
+
+	gint ref_count;
+} HistItemData;
+static HistItemData *hist_item_data_new (void);
+static HistItemData *hist_item_data_ref (HistItemData *hdata);
+static void          hist_item_data_unref (HistItemData *hdata);
+
 struct _QueryEditorPrivate {
+	QueryEditorMode mode;
 	GtkWidget *scrolled_window;
 	GtkWidget *text;
-	guint config_lid;
+
+	/* HISTORY mode */
+	guint ts_timeout_id;
+	GSList *batches_list; /* list of QueryEditorHistoryBatch, in reverse order, refs held here */
+	GHashTable *hash; /* crossed references:
+			   * QueryEditorHistoryBatch --> HistItemData on @batch
+			   * QueryEditorHistoryItem --> HistItemData on @item
+			   * GtkTextTag --> HistItemData on @tag
+			   *
+			   * hash table holds references to all HistItemData
+			   */
+	QueryEditorHistoryBatch *insert_into_batch; /* hold ref here */
+	HistItemData *hist_focus; /* ref held here */
 };
 
 static void query_editor_class_init (QueryEditorClass *klass);
 static void query_editor_init       (QueryEditor *editor, QueryEditorClass *klass);
 static void query_editor_finalize   (GObject *object);
 
+static void query_editor_map       (GtkWidget *widget);
+
 static GObjectClass *parent_class = NULL;
 static GHashTable *supported_languages = NULL;
 static gint number_of_objects = 0;
 
+static void focus_on_hist_data (QueryEditor *editor, HistItemData *hdata);
+static HistItemData *get_next_hist_data (QueryEditor *editor, HistItemData *hdata);
+static HistItemData *get_prev_hist_data (QueryEditor *editor, HistItemData *hdata);
+
+static gboolean timestamps_update_cb (QueryEditor *editor);
+
+/* signals */
+enum
+{
+        CHANGED,
+        LAST_SIGNAL
+};
+
+static gint query_editor_signals[LAST_SIGNAL] = { 0 };
+
+
 /*
  * Private functions
  */
@@ -58,6 +107,12 @@ create_tags_for_sql (QueryEditor *editor, const gchar *language)
 #ifdef HAVE_GTKSOURCEVIEW
 	GtkSourceLanguageManager *mgr;
 	GtkSourceLanguage *lang;
+	gchar ** current_search_path;
+	gint len;
+	gchar ** search_path;
+
+	GtkSourceStyleSchemeManager* sch_mgr;
+	GtkSourceStyleScheme *sch;
 #endif
 
 	g_return_if_fail (language != NULL);
@@ -66,14 +121,37 @@ create_tags_for_sql (QueryEditor *editor, const gchar *language)
 	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
 #ifdef HAVE_GTKSOURCEVIEW
 	mgr = gtk_source_language_manager_new ();
-	lang = gtk_source_language_manager_get_language (mgr, "sql");
 
-	if (lang) {
-		gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), lang);
-		/* FIXME: extend for Gda's variables syntax */
+	/* alter search path */
+	current_search_path = (gchar **) gtk_source_language_manager_get_search_path (mgr);
+	len = g_strv_length (current_search_path);
+	search_path = g_new0 (gchar*, len + 2);
+	memcpy (search_path, current_search_path, sizeof (gchar*) * len);
+	search_path [len] = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "language-specs", NULL);
+	gtk_source_language_manager_set_search_path (mgr, search_path);
+	g_free (search_path [len]);
+	g_free (search_path);
+
+	lang = gtk_source_language_manager_get_language (mgr, "gda-sql");
+
+	if (!lang) {
+		gchar *tmp;
+		tmp = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "language-spec", NULL);
+		g_print ("Could not find the gda-sql.lang file in %s,\nusing the default SQL highlighting rules.\n",
+			 tmp);
+		g_free (tmp);
+		lang = gtk_source_language_manager_get_language (mgr, "sql");
 	}
+	if (lang)
+		gtk_source_buffer_set_language (GTK_SOURCE_BUFFER (buffer), lang);
 
 	g_object_unref (mgr);
+
+	sch_mgr = gtk_source_style_scheme_manager_get_default ();
+	sch = gtk_source_style_scheme_manager_get_scheme (sch_mgr, "tango");
+	if (sch) 
+		gtk_source_buffer_set_style_scheme (GTK_SOURCE_BUFFER (buffer), sch);
+	
 #endif
 }
 
@@ -88,38 +166,91 @@ query_editor_class_init (QueryEditorClass *klass)
 
 	parent_class = g_type_class_peek_parent (klass);
 
+	query_editor_signals[CHANGED] =
+                g_signal_new ("changed",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (QueryEditorClass, changed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
 	object_class->finalize = query_editor_finalize;
+	GTK_WIDGET_CLASS (object_class)->map = query_editor_map;
 }
 
-#ifdef HAVE_GCONF
 static void
-configuration_changed_cb (GConfClient *conf_client, guint cnxn_id, GConfEntry *entry, gpointer user_data)
+text_buffer_changed_cb (GtkTextBuffer *buffer, QueryEditor *editor)
 {
-	QueryEditor *editor = (QueryEditor *) user_data;
-
-	g_return_if_fail (QUERY_IS_EDITOR (editor));
+	if (editor->priv->mode != QUERY_EDITOR_HISTORY)
+		g_signal_emit (editor, query_editor_signals[CHANGED], 0);
+}
 
-	if (!strcmp (entry->key, QUERY_CONFIG_KEY_EDITOR_SHOW_LINE_NUMBERS)) {
-#ifdef HAVE_GTKSOURCEVIEW
-		gtk_source_view_set_show_line_numbers (
-			GTK_SOURCE_VIEW (editor->priv->text),
-			gconf_client_get_bool (gconf_client_get_default (), QUERY_CONFIG_KEY_EDITOR_SHOW_LINE_NUMBERS, NULL));
-#else
-#endif
-	} else if (!strcmp (entry->key, QUERY_CONFIG_KEY_EDITOR_TAB_STOP)) {
-#ifdef HAVE_GTKSOURCEVIEW
-		int tab = gconf_client_get_int (gconf_client_get_default (), QUERY_CONFIG_KEY_EDITOR_TAB_STOP, NULL);
-		gtk_source_view_set_tab_width (GTK_SOURCE_VIEW (editor->priv->text),
-					       tab ? tab : 8);
-#else
-#endif
-	} else if (!strcmp (entry->key, QUERY_CONFIG_KEY_EDITOR_HIGHLIGHT)) {
-		query_editor_set_highlight_syntax (editor,
-					       gconf_client_get_bool (gconf_client_get_default (), 
-								      QUERY_CONFIG_KEY_EDITOR_HIGHLIGHT, NULL));
+/*
+ * Returns: -1 if none focussed
+ */
+static gboolean
+event_after (GtkWidget *text_view, GdkEvent *ev, QueryEditor *editor)
+{
+	GtkTextIter start, end, iter;
+	GtkTextBuffer *buffer;
+	GdkEventButton *event;
+	gint x, y;
+
+	if (editor->priv->mode != QUERY_EDITOR_HISTORY)
+		return FALSE;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+	if (ev->type == GDK_BUTTON_RELEASE) {
+		event = (GdkEventButton *)ev;
+		
+		if (event->button != 1)
+			return FALSE;
+		
+		/* we shouldn't follow a link if the user has selected something */
+		gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
+		if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
+			return FALSE;
+		
+		gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
+						       GTK_TEXT_WINDOW_WIDGET,
+						       event->x, event->y, &x, &y);
+		
+		gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
+		
+		/* go through tags */
+		GSList *tags = NULL, *tagp = NULL;
+		HistItemData *hist_focus = NULL;
+		tags = gtk_text_iter_get_tags (&iter);
+		for (tagp = tags;  tagp;  tagp = tagp->next) {
+			hist_focus = g_hash_table_lookup (editor->priv->hash, tagp->data);
+			if (hist_focus)
+				break;
+		}
+		focus_on_hist_data (editor, hist_focus);
+		
+		if (tags) 
+			g_slist_free (tags);
+	}
+	else if ((ev->type == GDK_KEY_PRESS) && 
+		 (((((GdkEventKey*) ev)->keyval == GDK_Up)) || ((((GdkEventKey*) ev)->keyval == GDK_Down)))) {
+		HistItemData *nfocus = NULL;
+		if (editor->priv->hist_focus) {
+			if (((GdkEventKey*) ev)->keyval == GDK_Up)
+				nfocus = get_prev_hist_data (editor, editor->priv->hist_focus);
+			else
+				nfocus = get_next_hist_data (editor, editor->priv->hist_focus);
+			if (!nfocus)
+				nfocus = editor->priv->hist_focus;
+		}
+
+		focus_on_hist_data (editor, nfocus);
+		return TRUE;
 	}
+	else
+		return FALSE;
+
+	return FALSE;
 }
-#endif
 
 static void
 query_editor_init (QueryEditor *editor, QueryEditorClass *klass)
@@ -132,6 +263,10 @@ query_editor_init (QueryEditor *editor, QueryEditorClass *klass)
 
 	/* allocate private structure */
 	editor->priv = g_new0 (QueryEditorPrivate, 1);
+	editor->priv->mode = QUERY_EDITOR_READWRITE;
+	editor->priv->batches_list = NULL;
+	editor->priv->hash = NULL;
+	editor->priv->hist_focus = NULL;
 
 	/* set up widgets */
 	editor->priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL);
@@ -139,7 +274,7 @@ query_editor_init (QueryEditor *editor, QueryEditorClass *klass)
                                         GTK_POLICY_AUTOMATIC,
                                         GTK_POLICY_AUTOMATIC);
         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (editor->priv->scrolled_window),
-					     GTK_SHADOW_NONE);
+					     GTK_SHADOW_ETCHED_OUT);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (editor->priv->scrolled_window),
 					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 	gtk_box_pack_start (GTK_BOX (editor), editor->priv->scrolled_window, TRUE, TRUE, 2);
@@ -153,10 +288,14 @@ query_editor_init (QueryEditor *editor, QueryEditorClass *klass)
 #else
 	editor->priv->text = gtk_text_view_new ();
 #endif
-	gtk_widget_show (editor->priv->text);
 
 	gtk_container_add (GTK_CONTAINER (editor->priv->scrolled_window), editor->priv->text);
 
+	g_signal_connect (editor->priv->text, "event-after", 
+			  G_CALLBACK (event_after), editor);
+	g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text)), "changed", 
+			  G_CALLBACK (text_buffer_changed_cb), editor);
+
 	/* initialize common data */
 	number_of_objects++;
 	if (!supported_languages) {
@@ -167,6 +306,48 @@ query_editor_init (QueryEditor *editor, QueryEditorClass *klass)
 	}
 
 	create_tags_for_sql (editor, QUERY_EDITOR_LANGUAGE_SQL);
+
+	gtk_widget_show (editor->priv->text);
+
+	/* timeout function to update timestamps */
+	editor->priv->ts_timeout_id = 0;
+}
+
+static void
+query_editor_map (GtkWidget *widget)
+{
+	GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+	if (QUERY_EDITOR (widget)->priv->mode == QUERY_EDITOR_HISTORY) {
+		GtkStyle *style;
+		style = gtk_widget_get_style (widget);
+		gtk_widget_modify_base (QUERY_EDITOR (widget)->priv->text,
+					GTK_STATE_NORMAL, &style->bg[GTK_STATE_NORMAL]);
+	}
+}
+
+static void
+hist_data_free_all (QueryEditor *editor)
+{
+	if (editor->priv->ts_timeout_id) {
+		g_source_remove (editor->priv->ts_timeout_id);
+		editor->priv->ts_timeout_id = 0;
+	}
+	if (editor->priv->batches_list) {
+		g_slist_foreach (editor->priv->batches_list, (GFunc) query_editor_history_batch_unref, NULL);
+		g_slist_free (editor->priv->batches_list);
+		editor->priv->batches_list = NULL;
+	}
+
+	if (editor->priv->hash) {
+		g_hash_table_destroy (editor->priv->hash);
+		editor->priv->hash = NULL;
+	}
+
+	if (editor->priv->hist_focus) {
+		hist_item_data_unref (editor->priv->hist_focus);
+		editor->priv->hist_focus = NULL;
+	}	
 }
 
 static void
@@ -177,9 +358,8 @@ query_editor_finalize (GObject *object)
 	g_return_if_fail (QUERY_IS_EDITOR (editor));
 
 	/* free memory */
-#ifdef HAVE_GCONF
-	gconf_client_notify_remove (gconf_client_get_default (), editor->priv->config_lid);
-#endif
+	hist_data_free_all (editor);
+
 	g_free (editor->priv);
 	editor->priv = NULL;
 
@@ -210,7 +390,7 @@ query_editor_get_type (void)
 			0,
 			(GInstanceInitFunc) query_editor_init
 		};
-		type = g_type_register_static (PARENT_TYPE, "QueryEditor", &info, 0);
+		type = g_type_register_static (GTK_TYPE_VBOX, "QueryEditor", &info, 0);
 	}
 	return type;
 }
@@ -237,88 +417,624 @@ query_editor_new (void)
 }
 
 /**
- * query_editor_get_editable
+ * query_editor_get_mode
  * @editor: a #QueryEditor widget.
  *
- * Retrieve the editable status of the given editor widget.
+ * Get @editor's mode
  *
- * Returns: the editable status.
+ * Returns: @editor's mode
  */
-gboolean
-query_editor_get_editable (QueryEditor *editor)
+QueryEditorMode
+query_editor_get_mode (QueryEditor *editor)
 {
-        g_return_val_if_fail (QUERY_IS_EDITOR (editor), FALSE);
-
-        return gtk_text_view_get_editable (GTK_TEXT_VIEW (editor->priv->text));
+	g_return_val_if_fail (QUERY_IS_EDITOR (editor), 0);
+	return editor->priv->mode;
 }
 
 /**
- * query_editor_set_editable
+ * query_editor_set_mode
  * @editor: a #QueryEditor widget.
- * @editable: editable state.
+ * @mode: new mode
  *
- * Set the editable state of the given editor widget.
+ * A mode change will empty the buffer.
  */
 void
-query_editor_set_editable (QueryEditor *editor, gboolean editable)
+query_editor_set_mode (QueryEditor *editor, QueryEditorMode mode)
 {
+	GtkTextBuffer *buffer;
+	gboolean clean = TRUE;
+
 	g_return_if_fail (QUERY_IS_EDITOR (editor));
-	gtk_text_view_set_editable (GTK_TEXT_VIEW (editor->priv->text), editable);
+	if (editor->priv->mode == mode)
+		return;
+
+	if (((editor->priv->mode == QUERY_EDITOR_READWRITE) && (mode == QUERY_EDITOR_READONLY)) ||
+	    ((editor->priv->mode == QUERY_EDITOR_READONLY) && (mode == QUERY_EDITOR_READWRITE)))
+		clean = FALSE;
+	else if (editor->priv->mode == QUERY_EDITOR_HISTORY)
+		hist_data_free_all (editor);
+
+	editor->priv->mode = mode;
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+	if (clean) {
+		GtkTextIter start, end;
+		gtk_text_buffer_get_start_iter (buffer, &start);
+		gtk_text_buffer_get_end_iter (buffer, &end);
+		gtk_text_buffer_delete (buffer, &start, &end);
+	}
+
+	switch (mode) {
+	case QUERY_EDITOR_READWRITE:
+		gtk_text_view_set_editable (GTK_TEXT_VIEW (editor->priv->text), TRUE);
+		gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (editor->priv->text), TRUE);
+		break;
+	case QUERY_EDITOR_READONLY:
+	case QUERY_EDITOR_HISTORY:
+		gtk_text_view_set_editable (GTK_TEXT_VIEW (editor->priv->text), FALSE);
+		gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (editor->priv->text), FALSE);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	if (mode == QUERY_EDITOR_HISTORY) {
+		GtkStyle *style;
+		style = gtk_widget_get_style ((GtkWidget*) editor);
+		gtk_widget_modify_base (editor->priv->text,
+					GTK_STATE_NORMAL, &style->bg[GTK_STATE_NORMAL]);
+
+		editor->priv->hash = g_hash_table_new_full (NULL, NULL, NULL,
+							    (GDestroyNotify) hist_item_data_unref);
+	}
+	else {
+		gtk_widget_modify_base (editor->priv->text,
+					GTK_STATE_NORMAL, NULL);
+	}
 }
 
 /**
- * query_editor_get_highlight
+ * query_editor_set_text
  * @editor: a #QueryEditor widget.
+ * @text: text to display in the editor.
+ * @len: length of @text, or -1.
  *
- * Retrieve the highlighting status of the given editor widget.
+ * Set the contents of the given editor widget.
+ */
+void
+query_editor_set_text (QueryEditor *editor, const gchar *text)
+{
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+
+	g_return_if_fail (QUERY_IS_EDITOR (editor));
+	g_return_if_fail (editor->priv->mode != QUERY_EDITOR_HISTORY);
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+	gtk_text_buffer_get_start_iter (buffer, &start);
+	gtk_text_buffer_get_end_iter (buffer, &end);
+	gtk_text_buffer_delete (buffer, &start, &end);
+
+	if (text) {
+		gtk_text_buffer_get_end_iter (buffer, &end);
+		gtk_text_buffer_insert (buffer, &end, text, -1);
+	}
+}
+
+static void
+focus_on_hist_data (QueryEditor *editor, HistItemData *hdata)
+{
+	if (editor->priv->hist_focus) {
+		if (editor->priv->hist_focus == hdata)
+			return;
+		if (editor->priv->hist_focus->item)
+			g_object_set (G_OBJECT (editor->priv->hist_focus->tag),
+				      "foreground-set", TRUE, NULL);
+		else {
+			/* un-highlight all the batch */
+			GSList *list;
+			for (list = editor->priv->hist_focus->batch->hist_items; list; list = list->next) {
+				HistItemData *hd;
+				hd = g_hash_table_lookup (editor->priv->hash, list->data);
+				g_object_set (G_OBJECT (hd->tag),
+					      "foreground-set", TRUE, NULL);
+			}
+		}
+		hist_item_data_unref (editor->priv->hist_focus);
+		editor->priv->hist_focus = NULL;
+	}
+
+	if (hdata) {
+		GtkTextBuffer *buffer;
+		GtkTextIter iter;
+
+		buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+		editor->priv->hist_focus = hist_item_data_ref (hdata);
+		if (hdata->item)
+			g_object_set (G_OBJECT (hdata->tag),
+				      "foreground-set", FALSE, NULL);
+		else {
+			/* highlight all the batch */
+			GSList *list;
+			for (list = hdata->batch->hist_items; list; list = list->next) {
+				HistItemData *hd;
+				hd = g_hash_table_lookup (editor->priv->hash, list->data);
+				g_object_set (G_OBJECT (hd->tag),
+					      "foreground-set", FALSE, NULL);
+			}
+		}
+		
+		gtk_text_buffer_get_iter_at_mark (buffer, &iter, hdata->start_mark);
+		gtk_text_buffer_place_cursor (buffer, &iter);
+		gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (editor->priv->text), hdata->start_mark);
+	}
+
+	g_signal_emit (editor, query_editor_signals[CHANGED], 0);
+}
+
+const char *
+get_date_format (time_t time, gint *out_timer_secs)
+{
+        static char timebuf[200];
+	GTimeVal now;
+	unsigned long diff, tmp;
+
+	*out_timer_secs = 60;
+	g_get_current_time (&now);
+
+	if (now.tv_sec < time)
+		return _("In the future:\n");
+
+	diff = now.tv_sec - time;
+	if (diff < 60)
+		return _("Less than a minute ago:\n");
+
+	/* Turn it into minutes */
+	tmp = diff / 60;
+	if (tmp < 60) {
+		snprintf (timebuf, sizeof(timebuf), ngettext ("%lu minute ago:\n",
+							      "%lu minutes ago:\n", tmp), tmp);
+		return timebuf;
+	}
+	/* Turn it into hours */
+	tmp = diff / 3600;
+	if (tmp < 24) {
+		snprintf (timebuf, sizeof(timebuf), _("%lu hours ago\n"), tmp);
+		*out_timer_secs = 3600;
+		return timebuf;
+	}
+	/* Turn it into days */
+	tmp = diff / 86400;
+	snprintf (timebuf, sizeof(timebuf), _("%lu days ago:\n"), tmp);
+	*out_timer_secs = 86400;
+	return timebuf;
+}
+
+/**
+ * query_editor_start_history_batch
+ * @editor: a #QueryEditor widget.
+ * @hist_batch: a #QueryEditorHistoryBatch to add, or %NULL
  *
- * Returns: the highlighting status.
+ * @hist_hash ref is _NOT_ stolen here
  */
-gboolean
-query_editor_get_highlight (QueryEditor *editor)
+void
+query_editor_start_history_batch (QueryEditor *editor, QueryEditorHistoryBatch *hist_batch)
 {
-	g_return_val_if_fail (QUERY_IS_EDITOR (editor), FALSE);
+	GtkTextIter iter;
+	GtkTextBuffer *buffer;
+	GtkTextTag *tag;
+	HistItemData *hdata;
+	gboolean empty = FALSE;
 
-#ifdef HAVE_GTKSOURCEVIEW
-	return gtk_source_buffer_get_highlight_syntax (
-		GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text))));
-#else
-	return FALSE;
-#endif
+	g_return_if_fail (QUERY_IS_EDITOR (editor));
+	g_return_if_fail (editor->priv->mode == QUERY_EDITOR_HISTORY);
+	
+	if (!hist_batch) {
+		GTimeVal run_time = {0, 0};
+		empty = TRUE;
+		
+		hist_batch = query_editor_history_batch_new (run_time);
+	}
+
+	/* update editor->priv->insert_into_batch */
+	if (editor->priv->insert_into_batch)
+		query_editor_history_batch_unref (editor->priv->insert_into_batch);
+	editor->priv->insert_into_batch = query_editor_history_batch_ref (hist_batch);
+	editor->priv->batches_list = g_slist_prepend (editor->priv->batches_list,
+						      query_editor_history_batch_ref (hist_batch));
+
+	/* new HistItemData */
+	hdata = hist_item_data_new ();
+	hdata->batch = query_editor_history_batch_ref (hist_batch);
+	hdata->item = NULL;
+	g_hash_table_insert (editor->priv->hash, hist_batch, hdata);
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+	gtk_text_buffer_get_end_iter (buffer, &iter);
+	
+	/* mark start of insertion */
+	hdata->start_mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);	
+
+	/* new tag */
+	tag = gtk_text_buffer_create_tag (buffer, NULL,
+					  "pixels-below-lines", 3,
+					  "foreground", "black",
+					  "weight", PANGO_WEIGHT_BOLD, NULL);
+	hdata->tag = g_object_ref (tag);
+	g_hash_table_insert (editor->priv->hash, tag, hist_item_data_ref (hdata));
+	
+	if (!empty) { 
+		/* insert text */
+		gint timer_res;
+		gtk_text_buffer_insert_with_tags (buffer, &iter,
+						  get_date_format (hist_batch->run_time.tv_sec, &timer_res),
+						  -1, tag, NULL);
+	}
+
+	/* mark end of insertion */
+	hdata->end_mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
+
+	if (empty)
+		query_editor_history_batch_unref (hist_batch);
+
+	/* add timout to 1 sec. */
+	editor->priv->ts_timeout_id  = g_timeout_add_seconds (60,
+							      (GSourceFunc) timestamps_update_cb, editor);
+}
+
+static gboolean
+timestamps_update_cb (QueryEditor *editor)
+{
+	GSList *list;
+	GtkTextBuffer *buffer;
+	GtkTextIter start, end;
+	gboolean timer_changed = FALSE;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+	for (list = editor->priv->batches_list; list; list = list->next) {
+		QueryEditorHistoryBatch *batch;
+		batch = (QueryEditorHistoryBatch*) list->data;
+		if (batch->run_time.tv_sec != 0) {
+			HistItemData *hdata;
+			hdata = g_hash_table_lookup (editor->priv->hash, batch);
+			
+			/* delete current text */
+			gtk_text_buffer_get_iter_at_mark (buffer, &start, hdata->start_mark);
+			gtk_text_buffer_get_iter_at_mark (buffer, &end, hdata->end_mark);
+			gtk_text_buffer_delete (buffer, &start, &end);
+			
+			/* insert text */
+			gint timer_res;
+			gtk_text_buffer_get_iter_at_mark (buffer, &start, hdata->start_mark);
+			gtk_text_buffer_insert_with_tags (buffer, &start,
+							  get_date_format (batch->run_time.tv_sec, &timer_res),
+							  -1, hdata->tag, NULL);
+			gtk_text_buffer_delete_mark (buffer, hdata->end_mark);
+			hdata->end_mark = gtk_text_buffer_create_mark (buffer, NULL, &start, TRUE);
+
+			if (! timer_changed) {
+				/* modify timer */
+				g_source_remove (editor->priv->ts_timeout_id);
+				editor->priv->ts_timeout_id  = g_timeout_add_seconds (timer_res,
+							       (GSourceFunc) timestamps_update_cb, editor);
+				timer_changed = TRUE;
+			}
+		}
+	}
+	return TRUE; /* don't remove timeout */
 }
 
 /**
- * query_editor_set_highlight
+ * query_editor_add_history_item
  * @editor: a #QueryEditor widget.
- * @highlight: highlighting status.
+ * @hist_item: a #QueryEditorHistoryItem to add, or %NULL
  *
- * Set the highlighting status on the given editor widget.
+ * Adds some text. @text_data is usefull only if @editor's mode is HISTORY, it will be ignored
+ * otherwise.
+ *
+ * Returns: the position of the added text chunk, or %0 if mode is not HISTORY
  */
 void
-query_editor_set_highlight (QueryEditor *editor, gboolean highlight)
+query_editor_add_history_item (QueryEditor *editor, QueryEditorHistoryItem *hist_item)
 {
+	GtkTextIter iter;
+	GtkTextBuffer *buffer;
+	GtkTextTag *tag;
+	HistItemData *hdata;
+
 	g_return_if_fail (QUERY_IS_EDITOR (editor));
+	g_return_if_fail (editor->priv->mode == QUERY_EDITOR_HISTORY);
+	g_return_if_fail (hist_item);
+	g_return_if_fail (hist_item->sql);
 
-#ifdef HAVE_GTKSOURCEVIEW
-	gtk_source_buffer_set_highlight_syntax (
-		GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text))), highlight);
-#endif
+	/* new HistItemData */
+	hdata = hist_item_data_new ();
+	hdata->batch = NULL;
+	hdata->item = query_editor_history_item_ref (hist_item);
+	g_hash_table_insert (editor->priv->hash, hist_item, hdata);
+
+	if (!editor->priv->insert_into_batch)
+		query_editor_start_history_batch (editor, NULL);
+
+	query_editor_history_batch_add_item (editor->priv->insert_into_batch, hist_item);
+	hdata->batch = query_editor_history_batch_ref (editor->priv->insert_into_batch);
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+	gtk_text_buffer_get_end_iter (buffer, &iter);
+
+		
+	tag = gtk_text_buffer_create_tag (buffer, NULL,
+					  "scale", PANGO_SCALE_SMALL,
+					  "foreground", "gray",
+					  "foreground-set", TRUE, NULL);
+	hdata->tag = g_object_ref (tag);
+	g_hash_table_insert (editor->priv->hash, tag, hist_item_data_ref (hdata));
+
+	/* mark start of insertion */
+	hdata->start_mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
+
+	/* insert text */
+	gchar *sql, *tmp1, *tmp2;
+	sql = g_strdup (hist_item->sql);
+	for (tmp1 = sql; (*tmp1 == ' ') || (*tmp1 == '\n') || (*tmp1 == '\t'); tmp1 ++);
+	for (tmp2 = sql + (strlen (sql) - 1);
+	     (tmp2 > tmp1) && ((*tmp2 == ' ') || (*tmp2 == '\n') || (*tmp2 == '\t'));
+	     tmp2--)
+		*tmp2 = 0;
+	gtk_text_buffer_insert_with_tags (buffer, &iter, tmp1, -1, tag, NULL);
+	gtk_text_buffer_insert_with_tags (buffer, &iter, "\n", 1, tag, NULL);
+	g_free (sql);
+
+	/* mark end of insertion */
+	hdata->end_mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
+
+	focus_on_hist_data (editor, hdata);
+	gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (editor->priv->text),
+				      &iter, 0., FALSE, 0., 0.);
 }
 
 /**
- * query_editor_set_text
+ * query_editor_get_current_history_item
  * @editor: a #QueryEditor widget.
- * @text: text to display in the editor.
- * @len: length of @text.
  *
- * Set the contents of the given editor widget.
+ * Get the current selected #QueryEditorHistoryItem
+ * passed to query_editor_add_history_item().
+ * 
+ * Returns: a #QueryEditorHistoryItem pointer, or %NULL
+ */
+QueryEditorHistoryItem *
+query_editor_get_current_history_item (QueryEditor *editor)
+{
+	g_return_val_if_fail (QUERY_IS_EDITOR (editor), NULL);
+	g_return_val_if_fail (editor->priv->mode == QUERY_EDITOR_HISTORY, NULL);
+
+	if (editor->priv->hist_focus)
+		return editor->priv->hist_focus->item;
+	else
+		return NULL;
+}
+
+/**
+ * query_editor_get_current_history_batch
+ * @editor: a #QueryEditor widget.
+ *
+ * Get the current selected #QueryEditorHistoryBatch if the selection is not on
+ * a #QueryEditorHistoryItem, but on the #QueryEditorHistoryBatch which was last
+ * set by a call to query_editor_start_history_batch().
+ * 
+ * Returns: a #QueryEditorHistoryItem pointer, or %NULL
+ */
+QueryEditorHistoryBatch *
+query_editor_get_current_history_batch (QueryEditor *editor)
+{
+	g_return_val_if_fail (QUERY_IS_EDITOR (editor), NULL);
+	g_return_val_if_fail (editor->priv->mode == QUERY_EDITOR_HISTORY, NULL);
+
+	if (editor->priv->hist_focus && !editor->priv->hist_focus->item)
+		return editor->priv->hist_focus->batch;
+	else
+		return NULL;
+}
+
+
+/**
+ * query_editor_del_current_history_item
+ * @editor: a #QueryEditor widget.
+ * 
+ * Deletes the text associated to the current selection, usefull only if @editor's mode is HISTORY
+ */
+void
+query_editor_del_current_history_item (QueryEditor *editor)
+{
+	HistItemData *hdata, *focus;
+	GtkTextBuffer *buffer;
+
+	g_return_if_fail (QUERY_IS_EDITOR (editor));
+	g_return_if_fail (editor->priv->mode == QUERY_EDITOR_HISTORY);
+
+	if (!editor->priv->hist_focus)
+		return;
+	hdata = editor->priv->hist_focus;
+	if (!hdata->item)
+		return;
+
+	focus = get_next_hist_data (editor, hdata);
+	if (focus)
+		focus_on_hist_data (editor, focus);
+	else
+		focus_on_hist_data (editor, get_prev_hist_data (editor, hdata));
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+
+	/* handle GtkTextBuffer's deletion */
+	GtkTextIter start, end;
+	gtk_text_buffer_get_iter_at_mark (buffer, &start, hdata->start_mark);
+	gtk_text_buffer_get_iter_at_mark (buffer, &end, hdata->end_mark);
+	gtk_text_buffer_delete (buffer, &start, &end);
+	gtk_text_buffer_delete_mark (buffer, hdata->start_mark);
+	gtk_text_buffer_delete_mark (buffer, hdata->end_mark);
+	
+	hist_item_data_ref (hdata);
+	g_hash_table_remove (editor->priv->hash, hdata->item);
+	g_hash_table_remove (editor->priv->hash, hdata->tag);
+	
+	if (hdata->batch) {
+		query_editor_history_batch_del_item (hdata->batch, hdata->item);
+		if (! hdata->batch->hist_items) {
+			/* remove hdata->batch */
+			HistItemData *remhdata;
+
+			editor->priv->batches_list = g_slist_remove (editor->priv->batches_list, hdata->batch);
+			query_editor_history_batch_unref (hdata->batch);
+
+			remhdata = g_hash_table_lookup (editor->priv->hash, hdata->batch);
+			gtk_text_buffer_get_iter_at_mark (buffer, &start, remhdata->start_mark);
+			gtk_text_buffer_get_iter_at_mark (buffer, &end, remhdata->end_mark);
+			gtk_text_buffer_delete (buffer, &start, &end);
+			gtk_text_buffer_delete_mark (buffer, remhdata->start_mark);
+			gtk_text_buffer_delete_mark (buffer, remhdata->end_mark);
+
+			g_hash_table_remove (editor->priv->hash, remhdata->batch);
+			g_hash_table_remove (editor->priv->hash, remhdata->tag);
+
+			if (editor->priv->insert_into_batch == hdata->batch) {
+				query_editor_history_batch_unref (editor->priv->insert_into_batch);
+				editor->priv->insert_into_batch = NULL;
+			}
+		}
+	}
+	hist_item_data_unref (hdata);
+}
+
+/**
+ * query_editor_del_history_batch
+ * @editor: a #QueryEditor
+ * @batch: a #QueryEditorHistoryBatch
+ *
+ * Deletes all regarding @batch.
  */
 void
-query_editor_set_text (QueryEditor *editor, const gchar *text, gint len)
+query_editor_del_history_batch (QueryEditor *editor, QueryEditorHistoryBatch *batch)
 {
+	GtkTextBuffer *buffer;
+	GSList *list;
+	HistItemData *hdata;
+	GtkTextIter start, end;
+	HistItemData *focus;
+	gint i;
+
 	g_return_if_fail (QUERY_IS_EDITOR (editor));
-	gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text)),
-				  text, len);
+	g_return_if_fail (editor->priv->mode == QUERY_EDITOR_HISTORY);
+	g_return_if_fail (batch);
+	i = g_slist_index (editor->priv->batches_list, batch);	
+	g_return_if_fail (i >= 0);
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+
+	/* compute new focus */
+	if (i > 0) {
+		focus = NULL;
+		list = g_slist_nth (editor->priv->batches_list, i - 1);
+		focus = g_hash_table_lookup (editor->priv->hash, list->data);
+	}
+	focus_on_hist_data (editor, focus);
+
+	/* remove all history items */
+	for (list =  batch->hist_items; list; list =  batch->hist_items) {
+		hdata = g_hash_table_lookup (editor->priv->hash, list->data);
+		g_assert (hdata);
+
+		gtk_text_buffer_get_iter_at_mark (buffer, &start, hdata->start_mark);
+		gtk_text_buffer_get_iter_at_mark (buffer, &end, hdata->end_mark);
+		gtk_text_buffer_delete (buffer, &start, &end);
+		gtk_text_buffer_delete_mark (buffer, hdata->start_mark);
+		gtk_text_buffer_delete_mark (buffer, hdata->end_mark);
+		
+		g_hash_table_remove (editor->priv->hash, hdata->item);
+		g_hash_table_remove (editor->priv->hash, hdata->tag);
+		query_editor_history_batch_del_item (batch, (QueryEditorHistoryItem*) list->data);
+	}
+	
+	/* remove batch */
+	editor->priv->batches_list = g_slist_remove (editor->priv->batches_list, batch);
+	query_editor_history_batch_unref (batch);
+	
+	hdata = g_hash_table_lookup (editor->priv->hash, batch);
+	gtk_text_buffer_get_iter_at_mark (buffer, &start, hdata->start_mark);
+	gtk_text_buffer_get_iter_at_mark (buffer, &end, hdata->end_mark);
+	gtk_text_buffer_delete (buffer, &start, &end);
+	gtk_text_buffer_delete_mark (buffer, hdata->start_mark);
+	gtk_text_buffer_delete_mark (buffer, hdata->end_mark);
+	
+	if (editor->priv->insert_into_batch == batch) {
+		query_editor_history_batch_unref (editor->priv->insert_into_batch);
+		editor->priv->insert_into_batch = NULL;
+	}
+
+	g_hash_table_remove (editor->priv->hash, hdata->batch);
+	g_hash_table_remove (editor->priv->hash, hdata->tag);	
+}
+
+static HistItemData *
+get_next_hist_data (QueryEditor *editor, HistItemData *hdata)
+{
+	GSList *node;
+	g_return_val_if_fail (hdata, NULL);
+	g_assert (hdata->batch);
+	
+	if (hdata->item) {
+		node = g_slist_find (hdata->batch->hist_items, hdata->item);
+		g_assert (node);
+		node = node->next;
+		if (node)
+			return g_hash_table_lookup (editor->priv->hash, node->data);
+	}
+	else
+		if (hdata->batch->hist_items)
+			return g_hash_table_lookup (editor->priv->hash, hdata->batch->hist_items->data);
+
+	/* move on to the next batch if any */
+	gint i;
+	i = g_slist_index (editor->priv->batches_list, hdata->batch);
+	if (i > 0) {
+		node = g_slist_nth (editor->priv->batches_list, i-1);
+		hdata = g_hash_table_lookup (editor->priv->hash, node->data);
+		return get_next_hist_data (editor, hdata);
+	}
+	return NULL;
+}
+
+static HistItemData *
+get_prev_hist_data (QueryEditor *editor, HistItemData *hdata)
+{
+	GSList *node;
+	gint i;
+	g_return_val_if_fail (hdata, NULL);
+	g_assert (hdata->batch);
+	
+	if (hdata->item) {
+		node = g_slist_find (hdata->batch->hist_items, hdata->item);
+		g_assert (node);
+		i = g_slist_position (hdata->batch->hist_items, node);
+		if (i > 0) {
+			node = g_slist_nth (hdata->batch->hist_items, i - 1);
+			return g_hash_table_lookup (editor->priv->hash, node->data);
+		}
+	}
+
+	/* move to the previous batch, if any */
+	node = g_slist_find (editor->priv->batches_list, hdata->batch);
+	node = node->next;
+	while (node) {
+		QueryEditorHistoryBatch *b;
+		b = (QueryEditorHistoryBatch*) node->data;
+		GSList *l;
+		l = g_slist_last (b->hist_items);
+		if (l)
+			return g_hash_table_lookup (editor->priv->hash, l->data);
+		node = node->next;
+	}
+
+	return NULL;
 }
 
 /**
@@ -367,7 +1083,7 @@ query_editor_load_from_file (QueryEditor *editor, const gchar *filename)
 	g_return_val_if_fail (filename != NULL, FALSE);
 
 	if (g_file_get_contents (filename, &contents, NULL, NULL)) {
-		query_editor_set_text (editor, contents, -1);
+		query_editor_set_text (editor, contents);
 		g_free (contents);
 	}
 	else 
@@ -449,3 +1165,136 @@ query_editor_paste_clipboard (QueryEditor *editor)
                                          NULL,
                                          gtk_text_view_get_editable (GTK_TEXT_VIEW (editor->priv->text)));
 }
+
+/*
+ * QueryEditorHistoryBatch
+ */
+QueryEditorHistoryBatch *
+query_editor_history_batch_new (GTimeVal run_time)
+{
+	QueryEditorHistoryBatch *qib;
+	
+	qib = g_new0 (QueryEditorHistoryBatch, 1);
+	qib->ref_count = 1;
+	qib->run_time = run_time;
+	return qib;
+}
+
+QueryEditorHistoryBatch *
+query_editor_history_batch_ref (QueryEditorHistoryBatch *qib)
+{
+	g_return_val_if_fail (qib, NULL);
+	qib->ref_count++;
+	return qib;
+}
+
+void
+query_editor_history_batch_unref (QueryEditorHistoryBatch *qib)
+{
+	g_return_if_fail (qib);
+	qib->ref_count--;
+	if (qib->ref_count <= 0) {
+		if (qib->hist_items) {
+			g_slist_foreach (qib->hist_items, (GFunc) query_editor_history_item_unref, NULL);
+			g_slist_free (qib->hist_items);
+		}
+		g_free (qib);
+	}
+}
+
+void
+query_editor_history_batch_add_item (QueryEditorHistoryBatch *qib, QueryEditorHistoryItem *qih)
+{
+	g_return_if_fail (qib);
+	g_return_if_fail (qih);
+	qib->hist_items = g_slist_append (qib->hist_items, query_editor_history_item_ref (qih));
+}
+
+void
+query_editor_history_batch_del_item (QueryEditorHistoryBatch *qib, QueryEditorHistoryItem *qih)
+{
+	g_return_if_fail (qib);
+	g_return_if_fail (qih);
+	qib->hist_items = g_slist_remove (qib->hist_items, qih);
+	query_editor_history_item_unref (qih);
+}
+
+/*
+ * QueryEditorHistoryItem
+ */
+QueryEditorHistoryItem *
+query_editor_history_item_new (const gchar *sql, GdaSet *params, GObject *result)
+{
+	QueryEditorHistoryItem *qih;
+	
+	g_return_val_if_fail (sql, NULL);
+
+	qih = g_new0 (QueryEditorHistoryItem, 1);
+	qih->ref_count = 1;
+	qih->sql = g_strdup (sql);
+	if (params)
+		qih->params = gda_set_copy (params);
+	if (result)
+		qih->result = g_object_ref (result);
+
+	return qih;
+}
+
+QueryEditorHistoryItem *
+query_editor_history_item_ref (QueryEditorHistoryItem *qih)
+{
+	g_return_val_if_fail (qih, NULL);
+	qih->ref_count++;
+	return qih;
+}
+
+void
+query_editor_history_item_unref (QueryEditorHistoryItem *qih)
+{
+	g_return_if_fail (qih);
+	qih->ref_count--;
+	if (qih->ref_count <= 0) {
+		g_free (qih->sql);
+		if (qih->params)
+			g_object_unref (qih->params);
+		if (qih->result)
+			g_object_unref (qih->result);
+		g_free (qih);
+	}
+}
+
+/*
+ * HistItemData
+ */
+static HistItemData *
+hist_item_data_new (void)
+{
+	HistItemData *hdata;
+	hdata = g_new0 (HistItemData, 1);
+	hdata->ref_count = 1;
+	return hdata;
+}
+
+static HistItemData *
+hist_item_data_ref (HistItemData *hdata)
+{
+	g_return_val_if_fail (hdata, NULL);
+	hdata->ref_count ++;
+	return hdata;
+}
+
+static void
+hist_item_data_unref (HistItemData *hdata)
+{
+	g_return_if_fail (hdata);
+	hdata->ref_count --;
+	if (hdata->ref_count <= 0) {
+		if (hdata->batch)
+			query_editor_history_batch_unref (hdata->batch);
+		if (hdata->item)
+			query_editor_history_item_unref (hdata->item);
+		if (hdata->tag)
+			g_object_unref (hdata->tag);
+		g_free (hdata);
+	}
+}
diff --git a/tools/browser/query-exec/query-editor.h b/tools/browser/query-exec/query-editor.h
index e55e386..d92dab1 100644
--- a/tools/browser/query-exec/query-editor.h
+++ b/tools/browser/query-exec/query-editor.h
@@ -25,6 +25,7 @@
 #define __QUERY_EDITOR_H__
 
 #include <gtk/gtkvbox.h>
+#include <libgda/libgda.h>
 
 G_BEGIN_DECLS
 
@@ -47,19 +48,59 @@ struct _QueryEditorClass {
 	GtkVBoxClass parent_class;
 
 	/* signals */
-	void (* text_changed) (QueryEditor editor);
+	void (* changed) (QueryEditor editor);
 };
 
-#define QUERY_EDITOR_LANGUAGE_SQL "sql"
+/*
+ * Query history item
+ */
+typedef struct {
+	gchar *sql;
+	GdaSet *params;
+	GObject *result;
+
+	gint ref_count;
+} QueryEditorHistoryItem;
+
+QueryEditorHistoryItem *query_editor_history_item_new (const gchar *sql, GdaSet *params, GObject *result);
+QueryEditorHistoryItem *query_editor_history_item_ref (QueryEditorHistoryItem *qih);
+void                    query_editor_history_item_unref (QueryEditorHistoryItem *qih);
+
+/*
+ * Query history batch
+ */
+typedef struct {
+	GTimeVal run_time;
+	GSList *hist_items; /* list of QueryEditorHistoryItem, ref held here */
+
+	gint ref_count;
+} QueryEditorHistoryBatch;
+
+QueryEditorHistoryBatch *query_editor_history_batch_new (GTimeVal run_time);
+QueryEditorHistoryBatch *query_editor_history_batch_ref (QueryEditorHistoryBatch *qib);
+void                     query_editor_history_batch_unref (QueryEditorHistoryBatch *qib);
+void                     query_editor_history_batch_add_item (QueryEditorHistoryBatch *qib,
+							      QueryEditorHistoryItem *qih);
+void                     query_editor_history_batch_del_item (QueryEditorHistoryBatch *qib,
+							      QueryEditorHistoryItem *qih);
+
+/*
+ * Editor modes
+ */
+typedef enum {
+	QUERY_EDITOR_READWRITE,
+	QUERY_EDITOR_READONLY,
+	QUERY_EDITOR_HISTORY
+} QueryEditorMode;
+
 
 GType      query_editor_get_type (void) G_GNUC_CONST;
 GtkWidget *query_editor_new (void);
 
-gboolean   query_editor_get_editable (QueryEditor *editor);
-void       query_editor_set_editable (QueryEditor *editor, gboolean editable);
-gboolean   query_editor_get_highlight (QueryEditor *editor);
-void       query_editor_set_highlight (QueryEditor *editor, gboolean highlight);
-void       query_editor_set_text (QueryEditor *editor, const gchar *text, gint len);
+/* common API */
+void       query_editor_set_mode (QueryEditor *editor, QueryEditorMode mode);
+QueryEditorMode query_editor_get_mode (QueryEditor *editor);
+
 gchar     *query_editor_get_all_text (QueryEditor *editor);
 gboolean   query_editor_load_from_file (QueryEditor *editor, const gchar *filename);
 gboolean   query_editor_save_to_file (QueryEditor *editor, const gchar *filename);
@@ -68,6 +109,18 @@ void       query_editor_copy_clipboard (QueryEditor *editor);
 void       query_editor_cut_clipboard (QueryEditor *editor);
 void       query_editor_paste_clipboard (QueryEditor *editor);
 
+/* normal editor's API */
+void       query_editor_set_text (QueryEditor *editor, const gchar *text);
+
+/* history API */
+void       query_editor_start_history_batch (QueryEditor *editor, QueryEditorHistoryBatch *hist_batch);
+void       query_editor_add_history_item (QueryEditor *editor, QueryEditorHistoryItem *hist_item);
+QueryEditorHistoryItem *query_editor_get_current_history_item (QueryEditor *editor);
+QueryEditorHistoryBatch *query_editor_get_current_history_batch (QueryEditor *editor);
+
+void       query_editor_del_current_history_item (QueryEditor *editor);
+void       query_editor_del_history_batch (QueryEditor *editor, QueryEditorHistoryBatch *batch);
+
 G_END_DECLS
 
 #endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]