[libgda] GdaBrowser: improved history browsing



commit 6acd5442fd2bb91b0f474ae853f71f7fcb1c57b1
Author: Vivien Malerba <malerba gnome-db org>
Date:   Wed Sep 9 21:17:44 2009 +0200

    GdaBrowser: improved history browsing

 tools/browser/query-exec/query-console.c |    2 +-
 tools/browser/query-exec/query-editor.c  |  169 ++++++++++++++++++++++++------
 tools/browser/query-exec/query-editor.h  |    7 +-
 tools/browser/query-exec/query-result.c  |  144 ++++++++++++++++++++------
 tools/browser/query-exec/query-result.h  |    2 +-
 5 files changed, 257 insertions(+), 67 deletions(-)
---
diff --git a/tools/browser/query-exec/query-console.c b/tools/browser/query-exec/query-console.c
index c435415..3aa3c3c 100644
--- a/tools/browser/query-exec/query-console.c
+++ b/tools/browser/query-exec/query-console.c
@@ -433,7 +433,7 @@ query_console_new (BrowserConnection *bcnc)
 	gtk_misc_set_alignment (GTK_MISC (wid), 0., -1);
 	gtk_box_pack_start (GTK_BOX (vbox), wid, FALSE, FALSE, 0);
 
-	wid = query_result_new ();
+	wid = query_result_new (tconsole->priv->history);
 	tconsole->priv->query_result = wid;
 	gtk_box_pack_start (GTK_BOX (vbox), wid, TRUE, TRUE, 6);
 
diff --git a/tools/browser/query-exec/query-editor.c b/tools/browser/query-exec/query-editor.c
index 3b7bf00..08695e7 100644
--- a/tools/browser/query-exec/query-editor.c
+++ b/tools/browser/query-exec/query-editor.c
@@ -39,6 +39,11 @@
 #define COLOR_ALTER_FACTOR 1.8
 #define MAX_HISTORY_BATCH_ITEMS 20
 
+static void query_editor_history_batch_add_item (QueryEditorHistoryBatch *qib,
+						 QueryEditorHistoryItem *qih);
+static void query_editor_history_batch_del_item (QueryEditorHistoryBatch *qib,
+						 QueryEditorHistoryItem *qih);
+
 typedef void (* CreateTagsFunc) (QueryEditor *editor, const gchar *language);
 
 typedef struct {
@@ -59,6 +64,8 @@ struct _QueryEditorPrivate {
 	GtkWidget *scrolled_window;
 	GtkWidget *text;
 
+	GtkTextTag *indent_tag;
+
 	/* HISTORY mode */
 	guint ts_timeout_id;
 	GSList *batches_list; /* list of QueryEditorHistoryBatch, in reverse order, refs held here */
@@ -93,10 +100,11 @@ static gboolean timestamps_update_cb (QueryEditor *editor);
 enum
 {
         CHANGED,
+	HISTORY_ITEM_REMOVED,
         LAST_SIGNAL
 };
 
-static gint query_editor_signals[LAST_SIGNAL] = { 0 };
+static gint query_editor_signals[LAST_SIGNAL] = { 0, 0 };
 
 
 /*
@@ -175,6 +183,14 @@ query_editor_class_init (QueryEditorClass *klass)
                               NULL, NULL,
                               g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 
+	query_editor_signals[HISTORY_ITEM_REMOVED] =
+                g_signal_new ("history-item-removed",
+                              G_TYPE_FROM_CLASS (object_class),
+                              G_SIGNAL_RUN_FIRST,
+                              G_STRUCT_OFFSET (QueryEditorClass, history_item_removed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER);
+
 	object_class->finalize = query_editor_finalize;
 	GTK_WIDGET_CLASS (object_class)->map = query_editor_map;
 }
@@ -379,6 +395,24 @@ query_editor_init (QueryEditor *editor, QueryEditorClass *klass)
 	g_signal_connect (editor->priv->text, "expose-event",
 			  G_CALLBACK (text_view_expose_event), editor);
 
+	/* create some tags */
+	GtkTextBuffer *buffer;
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->priv->text));
+	gtk_text_buffer_create_tag (buffer, "h0",
+				    "foreground", "#474A8F",
+				    "weight", PANGO_WEIGHT_BOLD,
+				    "variant", PANGO_VARIANT_SMALL_CAPS,
+				    "scale", PANGO_SCALE_LARGE,
+				    "underline", PANGO_UNDERLINE_SINGLE,
+				    NULL);
+
+	gtk_text_buffer_create_tag (buffer, "note",
+				    "left-margin", 50,
+				    "foreground", "black",
+				    "weight", PANGO_WEIGHT_NORMAL,
+				    "style", PANGO_STYLE_ITALIC,
+				    NULL);
+
 	/* initialize common data */
 	number_of_objects++;
 	if (!supported_languages) {
@@ -390,7 +424,7 @@ query_editor_init (QueryEditor *editor, QueryEditorClass *klass)
 
 	create_tags_for_sql (editor, QUERY_EDITOR_LANGUAGE_SQL);
 
-	gtk_widget_show (editor->priv->text);
+	gtk_widget_show_all (editor->priv->scrolled_window);
 
 	/* timeout function to update timestamps */
 	editor->priv->ts_timeout_id = 0;
@@ -586,9 +620,8 @@ query_editor_set_mode (QueryEditor *editor, QueryEditorMode mode)
  * query_editor_set_text
  * @editor: a #QueryEditor widget.
  * @text: text to display in the editor.
- * @len: length of @text, or -1.
  *
- * Set the contents of the given editor widget.
+ * Set @editor's text, removing any previous one
  */
 void
 query_editor_set_text (QueryEditor *editor, const gchar *text)
@@ -610,6 +643,79 @@ query_editor_set_text (QueryEditor *editor, const gchar *text)
 	}
 }
 
+/**
+ * query_editor_append_text
+ * @editor: a #QueryEditor widget.
+ * @text: text to display in the editor.
+ *
+ * Appends some text to @editor.
+ */
+void
+query_editor_append_text (QueryEditor *editor, const gchar *text)
+{
+	GtkTextBuffer *buffer;
+
+	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));
+
+	if (text) {
+		GtkTextIter end;
+		gint len;
+		len = strlen (text);
+		gtk_text_buffer_get_end_iter (buffer, &end);
+		gtk_text_buffer_insert (buffer, &end, text, -1);
+
+		if ((len >= 1) && (text [len - 1] != '\n'))
+			gtk_text_buffer_insert (buffer, &end, "\n", 1);
+	}
+}
+
+/**
+ * query_editor_append_note
+ * @editor: a #QueryEditor widget.
+ * @text: text to display in the editor.
+ * @level: 0 for header, 1 for text with marging and in italics
+ *
+ * Appends some text to @editor.
+ */
+void
+query_editor_append_note (QueryEditor *editor, const gchar *text, gint level)
+{
+	GtkTextBuffer *buffer;
+
+	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));
+	if (text) {
+		GtkTextIter end;
+		gchar *str;
+		
+		switch (level) {
+		case 0:
+			str = g_strdup_printf ("%s\n", text);
+			gtk_text_buffer_get_end_iter (buffer, &end);
+			gtk_text_buffer_insert_with_tags_by_name (buffer, &end,
+								  str, -1,
+								  "h0", NULL);
+			g_free (str);
+			break;
+		case 1:
+			str = g_strdup_printf ("%s\n", text);
+			gtk_text_buffer_get_end_iter (buffer, &end);
+			gtk_text_buffer_insert_with_tags_by_name (buffer, &end,
+								  str, -1,
+								  "note", NULL);
+			g_free (str);
+			break;
+		default:
+			g_assert_not_reached ();
+		}
+	}	
+}
+
 static void
 focus_on_hist_data (QueryEditor *editor, HistItemData *hdata)
 {
@@ -693,7 +799,7 @@ get_date_format (time_t time)
 	}
 	/* Turn it into days */
 	tmp = diff / 86400;
-	snprintf (timebuf, sizeof(timebuf), ngettext ("%lu days ago\n",
+	snprintf (timebuf, sizeof(timebuf), ngettext ("%lu day ago\n",
 						      "%lu days ago\n", tmp), tmp);
 
 	return timebuf;
@@ -968,29 +1074,32 @@ query_editor_del_current_history_item (QueryEditor *editor)
 	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;
-			}
+	g_assert (hdata->batch);
+	query_editor_history_item_ref (hdata->item);
+	query_editor_history_batch_del_item (hdata->batch, hdata->item);
+	g_signal_emit (editor, query_editor_signals[HISTORY_ITEM_REMOVED], 0, hdata->item);
+	query_editor_history_item_unref (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);
@@ -1299,7 +1408,7 @@ query_editor_history_batch_unref (QueryEditorHistoryBatch *qib)
 	}
 }
 
-void
+static void
 query_editor_history_batch_add_item (QueryEditorHistoryBatch *qib, QueryEditorHistoryItem *qih)
 {
 	g_return_if_fail (qib);
@@ -1307,7 +1416,7 @@ query_editor_history_batch_add_item (QueryEditorHistoryBatch *qib, QueryEditorHi
 	qib->hist_items = g_slist_append (qib->hist_items, query_editor_history_item_ref (qih));
 }
 
-void
+static void
 query_editor_history_batch_del_item (QueryEditorHistoryBatch *qib, QueryEditorHistoryItem *qih)
 {
 	g_return_if_fail (qib);
diff --git a/tools/browser/query-exec/query-editor.h b/tools/browser/query-exec/query-editor.h
index bf42bad..c5bdb39 100644
--- a/tools/browser/query-exec/query-editor.h
+++ b/tools/browser/query-exec/query-editor.h
@@ -68,10 +68,6 @@ typedef struct {
 QueryEditorHistoryBatch *query_editor_history_batch_new (GTimeVal run_time, GdaSet *params);
 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);
 
 
 struct _QueryEditor {
@@ -84,6 +80,7 @@ struct _QueryEditorClass {
 
 	/* signals */
 	void (* changed) (QueryEditor *editor);
+	void (* history_item_removed) (QueryEditor *editor, QueryEditorHistoryItem *item);
 };
 
 /*
@@ -113,6 +110,8 @@ void       query_editor_paste_clipboard (QueryEditor *editor);
 
 /* normal editor's API */
 void       query_editor_set_text (QueryEditor *editor, const gchar *text);
+void       query_editor_append_text (QueryEditor *editor, const gchar *text);
+void       query_editor_append_note (QueryEditor *editor, const gchar *text, gint level);
 
 /* history API */
 void       query_editor_start_history_batch (QueryEditor *editor, QueryEditorHistoryBatch *hist_batch);
diff --git a/tools/browser/query-exec/query-result.c b/tools/browser/query-exec/query-result.c
index 546f9e4..491b579 100644
--- a/tools/browser/query-exec/query-result.c
+++ b/tools/browser/query-exec/query-result.c
@@ -26,9 +26,11 @@
 #include <libgda-ui/libgda-ui.h>
 
 struct _QueryResultPrivate {
+	QueryEditor *history;
 	QueryEditorHistoryBatch *hbatch;
 	QueryEditorHistoryItem *hitem;
 
+	GHashTable *hash; /* key = a QueryEditorHistoryItem, value = a #GtkWidget, refed here all the times */
 	GtkWidget *child;
 };
 
@@ -64,8 +66,10 @@ query_result_init (QueryResult *result, QueryResultClass *klass)
 
 	/* allocate private structure */
 	result->priv = g_new0 (QueryResultPrivate, 1);
+	result->priv->history = NULL;
 	result->priv->hbatch = NULL;
 	result->priv->hitem = NULL;
+	result->priv->hash = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
 
 	wid = make_widget_for_notice ();
 	gtk_box_pack_start (GTK_BOX (result), wid, TRUE, TRUE, 0);
@@ -74,6 +78,13 @@ query_result_init (QueryResult *result, QueryResultClass *klass)
 }
 
 static void
+history_item_removed_cb (QueryEditor *history, QueryEditorHistoryItem *item, QueryResult *result)
+{
+	g_hash_table_remove (result->priv->hash, item);
+	g_print ("Removed GtkWidget for item %p\n", item);
+}
+
+static void
 query_result_finalize (GObject *object)
 {
 	QueryResult *result = (QueryResult *) object;
@@ -81,6 +92,13 @@ query_result_finalize (GObject *object)
 	g_return_if_fail (IS_QUERY_RESULT (result));
 
 	/* free memory */
+	if (result->priv->hash)
+		g_hash_table_destroy (result->priv->hash);
+	if (result->priv->history) {
+		g_signal_handlers_disconnect_by_func (result->priv->history,
+						      G_CALLBACK (history_item_removed_cb), result);
+		g_object_unref (result->priv->history);
+	}
 	if (result->priv->hbatch)
 		query_editor_history_batch_unref (result->priv->hbatch);
 	if (result->priv->hitem)
@@ -116,17 +134,23 @@ query_result_get_type (void)
 
 /**
  * query_result_new
+ * @history: a #QueryEditor to take history from
  *
  * Create a new #QueryResult widget
  *
  * Returns: the newly created widget.
  */
 GtkWidget *
-query_result_new (void)
+query_result_new (QueryEditor *history)
 {
 	QueryResult *result;
+	g_return_val_if_fail (QUERY_IS_EDITOR (history), NULL);
 
 	result = g_object_new (QUERY_TYPE_RESULT, NULL);
+	g_signal_connect (history, "history-item-removed",
+			  G_CALLBACK (history_item_removed_cb), result);
+	result->priv->history = g_object_ref (history);
+
 
 	return GTK_WIDGET (result);
 }
@@ -141,14 +165,14 @@ query_result_new (void)
 void
 query_result_show_history_batch (QueryResult *qres, QueryEditorHistoryBatch *hbatch)
 {
-	GtkWidget *sw, *vbox;
 	GSList *list;
-	GtkWidget *child;
-	
+	GtkWidget *child;	
+	GtkWidget *vbox;
+	gchar *str;
 
 	g_return_if_fail (IS_QUERY_RESULT (qres));
 	if (qres->priv->child)
-		gtk_widget_destroy (qres->priv->child);
+		gtk_container_remove (GTK_CONTAINER (qres), qres->priv->child);
 
 	if (!hbatch) {
 		child = make_widget_for_notice ();
@@ -159,32 +183,83 @@ query_result_show_history_batch (QueryResult *qres, QueryEditorHistoryBatch *hba
 	}
 
 	vbox = gtk_vbox_new (FALSE, 0);
+
+	child = query_editor_new ();
+	query_editor_set_mode (QUERY_EDITOR (child), QUERY_EDITOR_READONLY);
+	gtk_box_pack_start (GTK_BOX (vbox), child, TRUE, TRUE, 0);
 	for (list = hbatch->hist_items; list; list = list->next) {
 		QueryEditorHistoryItem *hitem;
-
-		hitem = (QueryEditorHistoryItem*) list->data;
+		GString *string;
+		hitem = (QueryEditorHistoryItem *) list->data;
+		if (list != hbatch->hist_items)
+			query_editor_append_text (QUERY_EDITOR (child), "\n");
+		query_editor_append_note (QUERY_EDITOR (child), _("Statement:"), 0);
+		query_editor_append_text (QUERY_EDITOR (child), hitem->sql);
+
+		string = g_string_new ("");
 		if (hitem->result) {
-			if (GDA_IS_DATA_MODEL (hitem->result))
-				child = make_widget_for_data_model (GDA_DATA_MODEL (hitem->result));
-			else if (GDA_IS_SET (hitem->result))
-				child = make_widget_for_set (GDA_SET (hitem->result));
+			if (GDA_IS_DATA_MODEL (hitem->result)) {
+				gint n, c;
+				n = gda_data_model_get_n_rows (GDA_DATA_MODEL (hitem->result));
+				c = gda_data_model_get_n_columns (GDA_DATA_MODEL (hitem->result));
+				g_string_append_printf (string, 
+							_("Data set with %d rows and %d columns"),
+							n, c);
+			}
+			else if (GDA_IS_SET (hitem->result)) {
+				GdaSet *set;
+				GSList *list;
+				set = GDA_SET (hitem->result);
+				for (list = set->holders; list; list = list->next) {
+					GdaHolder *h;
+					const GValue *value;
+					const gchar *cstr;
+					gchar *tmp;
+					h = GDA_HOLDER (list->data);
+					
+					if (list != set->holders)
+						g_string_append_c (string, '\n');
+					
+					cstr = gda_holder_get_id (h);
+					if (!strcmp (cstr, "IMPACTED_ROWS"))
+						g_string_append (string, _("Number of rows impacted"));
+					else
+						g_string_append (string, cstr);
+					
+					g_string_append (string, ": ");
+					value = gda_holder_get_value (h);
+					tmp = gda_value_stringify (value);
+					g_string_append_printf (string, "%s", tmp);
+					g_free (tmp);
+				}
+			}
 			else
 				g_assert_not_reached ();
 		}
 		else 
-			child = make_widget_for_error (hitem->exec_error);
-		gtk_box_pack_start (GTK_BOX (vbox), child, TRUE, TRUE, 10);
+			g_string_append_printf (string, _("Error: %s"),
+						hitem->exec_error && hitem->exec_error->message ?
+						hitem->exec_error->message : _("No detail"));
+		query_editor_append_note (QUERY_EDITOR (child), string->str, 1);
+		g_string_free (string, TRUE);
 	}
 
-	sw = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
-					GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);
-	gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), vbox);
+	if (hbatch->params) {
+		GtkWidget *exp, *form;
+		str = g_strdup_printf ("<b>%s:</b>", _("Execution Parameters"));
+		exp = gtk_expander_new (str);
+		g_free (str);
+		gtk_expander_set_use_markup (GTK_EXPANDER (exp), TRUE);
+		gtk_box_pack_start (GTK_BOX (vbox), exp, FALSE, FALSE, 0);
+
+		form = gdaui_basic_form_new (hbatch->params);
+		gdaui_basic_form_entry_set_editable (GDAUI_BASIC_FORM (form), NULL, FALSE);
+		gtk_container_add (GTK_CONTAINER (exp), form);
+	}
 
-	gtk_box_pack_start (GTK_BOX (qres), sw, TRUE, TRUE, 0);
-	gtk_widget_show_all (sw);
-	qres->priv->child = sw;
+	gtk_box_pack_start (GTK_BOX (qres), vbox, TRUE, TRUE, 0);
+	gtk_widget_show_all (vbox);
+	qres->priv->child = vbox;
 }
 
 /**
@@ -201,20 +276,27 @@ query_result_show_history_item (QueryResult *qres, QueryEditorHistoryItem *hitem
 
 	g_return_if_fail (IS_QUERY_RESULT (qres));
 	if (qres->priv->child)
-		gtk_widget_destroy (qres->priv->child);
+		gtk_container_remove (GTK_CONTAINER (qres), qres->priv->child);
 	
 	if (!hitem)
 		child = make_widget_for_notice ();
-	else if (hitem->result) {
-		if (GDA_IS_DATA_MODEL (hitem->result))
-			child = make_widget_for_data_model (GDA_DATA_MODEL (hitem->result));
-		else if (GDA_IS_SET (hitem->result))
-			child = make_widget_for_set (GDA_SET (hitem->result));
-		else
-			g_assert_not_reached ();
+	else {
+		child = g_hash_table_lookup (qres->priv->hash, hitem);
+		if (!child) {
+			if (hitem->result) {
+				if (GDA_IS_DATA_MODEL (hitem->result))
+					child = make_widget_for_data_model (GDA_DATA_MODEL (hitem->result));
+				else if (GDA_IS_SET (hitem->result))
+					child = make_widget_for_set (GDA_SET (hitem->result));
+				else
+					g_assert_not_reached ();
+			}
+			else 
+				child = make_widget_for_error (hitem->exec_error);
+			g_print ("Inserted GtkWidget %p for item %p\n", child, hitem);
+			g_hash_table_insert (qres->priv->hash, hitem, g_object_ref (G_OBJECT (child)));
+		}
 	}
-	else 
-		child = make_widget_for_error (hitem->exec_error);
 
 	gtk_box_pack_start (GTK_BOX (qres), child, TRUE, TRUE, 0);
 	gtk_widget_show (child);
diff --git a/tools/browser/query-exec/query-result.h b/tools/browser/query-exec/query-result.h
index 581062f..e000526 100644
--- a/tools/browser/query-exec/query-result.h
+++ b/tools/browser/query-exec/query-result.h
@@ -50,7 +50,7 @@ struct _QueryResultClass {
 
 
 GType      query_result_get_type (void) G_GNUC_CONST;
-GtkWidget *query_result_new (void);
+GtkWidget *query_result_new (QueryEditor *history);
 
 void       query_result_show_history_batch (QueryResult *qres, QueryEditorHistoryBatch *hbatch);
 void       query_result_show_history_item (QueryResult *qres, QueryEditorHistoryItem *hitem);



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