[latexila/wip/build-tools-revamp] LatexilaBuildView



commit aa1e2735373bff2ccdbfff7a7c4195354ab02392
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Mon May 5 22:07:01 2014 +0200

    LatexilaBuildView
    
    Almost finished, there is no icons, and the path doesn't have a tilde
    for the home directory (it is not the end of the world for a first
    iteration).

 docs/reference/Makefile.am            |    1 +
 docs/reference/latexila-docs.xml      |    5 +-
 docs/reference/latexila-sections.txt  |   28 ++
 src/liblatexila/Makefile.am           |    6 +-
 src/liblatexila/latexila-build-view.c |  737 +++++++++++++++++++++++++++++++++
 src/liblatexila/latexila-build-view.h |  150 +++++++
 src/liblatexila/latexila-types.h      |    1 +
 7 files changed, 924 insertions(+), 4 deletions(-)
---
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 0734f32..9d900a7 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -53,6 +53,7 @@ EXTRA_HFILES =
 # Header files or dirs to ignore when scanning. Use base file/dir names
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
 IGNORE_HFILES =                                        \
+       latexila-enum-types.h                   \
        latexila-post-processor.h               \
        latexila-post-processor-all-output.h
 
diff --git a/docs/reference/latexila-docs.xml b/docs/reference/latexila-docs.xml
index 018642e..db7b0ed 100644
--- a/docs/reference/latexila-docs.xml
+++ b/docs/reference/latexila-docs.xml
@@ -11,11 +11,12 @@
 
   <chapter>
     <title>API reference</title>
+    <xi:include href="xml/build-job.xml"/>
+    <xi:include href="xml/build-tool.xml"/>
     <xi:include href="xml/build-tools.xml"/>
     <xi:include href="xml/build-tools-default.xml"/>
     <xi:include href="xml/build-tools-personal.xml"/>
-    <xi:include href="xml/build-tool.xml"/>
-    <xi:include href="xml/build-job.xml"/>
+    <xi:include href="xml/build-view.xml"/>
   </chapter>
 
   <chapter id="object-tree">
diff --git a/docs/reference/latexila-sections.txt b/docs/reference/latexila-sections.txt
index 7b5ac01..e8e291c 100644
--- a/docs/reference/latexila-sections.txt
+++ b/docs/reference/latexila-sections.txt
@@ -94,3 +94,31 @@ LatexilaBuildJobClass
 LatexilaBuildJobPrivate
 latexila_build_job_get_type
 </SECTION>
+
+<SECTION>
+<FILE>build-view</FILE>
+<TITLE>LatexilaBuildView</TITLE>
+LatexilaBuildView
+LatexilaBuildMsg
+LatexilaBuildMsgType
+LatexilaBuildState
+latexila_build_msg_new
+latexila_build_msg_free
+latexila_build_view_new
+latexila_build_view_clear
+latexila_build_view_add_main_title
+latexila_build_view_add_job_title
+latexila_build_view_set_title_state
+latexila_build_view_append_single_message
+latexila_build_view_append_messages
+latexila_build_view_remove_children
+<SUBSECTION Standard>
+LATEXILA_BUILD_VIEW
+LATEXILA_BUILD_VIEW_CLASS
+LATEXILA_BUILD_VIEW_GET_CLASS
+LATEXILA_IS_BUILD_VIEW
+LATEXILA_IS_BUILD_VIEW_CLASS
+LATEXILA_TYPE_BUILD_VIEW
+LatexilaBuildViewPrivate
+latexila_build_view_get_type
+</SECTION>
diff --git a/src/liblatexila/Makefile.am b/src/liblatexila/Makefile.am
index 4c17717..2f9a003 100644
--- a/src/liblatexila/Makefile.am
+++ b/src/liblatexila/Makefile.am
@@ -11,6 +11,7 @@ liblatexila_headers =                         \
        latexila-build-tools.h                  \
        latexila-build-tools-default.h          \
        latexila-build-tools-personal.h         \
+       latexila-build-view.h                   \
        latexila-post-processor.h               \
        latexila-post-processor-all-output.h    \
        latexila-types.h
@@ -25,6 +26,7 @@ liblatexila_la_SOURCES =                      \
        latexila-build-tools.c                  \
        latexila-build-tools-default.c          \
        latexila-build-tools-personal.c         \
+       latexila-build-view.c                   \
        latexila-post-processor.c               \
        latexila-post-processor-all-output.c    \
        $(liblatexila_headers)                  \
@@ -58,7 +60,7 @@ INTROSPECTION_GIRS = Latexila.gir
 
 Latexila.gir: liblatexila.la
 Latexila_gir_NAMESPACE = Latexila
-Latexila_gir_INCLUDES = Gio-2.0
+Latexila_gir_INCLUDES = Gtk-3.0
 Latexila_gir_LIBS = liblatexila.la
 Latexila_gir_FILES = $(liblatexila_la_SOURCES)
 
@@ -74,7 +76,7 @@ latexila.vapi: Latexila.gir
 
 VAPIGEN_VAPIS = latexila.vapi
 
-latexila_vapi_DEPS = gio-2.0
+latexila_vapi_DEPS = gio-2.0 gtk+-3.0
 latexila_vapi_FILES = Latexila.gir
 
 noinst_DATA += latexila.vapi
diff --git a/src/liblatexila/latexila-build-view.c b/src/liblatexila/latexila-build-view.c
new file mode 100644
index 0000000..78e496c
--- /dev/null
+++ b/src/liblatexila/latexila-build-view.c
@@ -0,0 +1,737 @@
+/*
+ * This file is part of LaTeXila.
+ *
+ * Copyright (C) 2014 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * LaTeXila is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LaTeXila 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LaTeXila.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:build-view
+ * @title: LatexilaBuildView
+ * @short_description: Build view
+ *
+ * A #LatexilaBuildView is a #GtkTreeView containing the build messages.
+ * The build view is contained in the bottom panel.
+ */
+
+#include "latexila-build-view.h"
+#include "latexila-enum-types.h"
+
+struct _LatexilaBuildViewPrivate
+{
+  GtkTreeStore *store;
+  GtkTreeModelFilter *filtered_model;
+
+  guint show_warnings : 1;
+  guint show_badboxes : 1;
+  guint show_details : 1;
+  guint has_details : 1;
+};
+
+enum
+{
+  PROP_0,
+  PROP_SHOW_WARNINGS,
+  PROP_SHOW_BADBOXES,
+  PROP_SHOW_DETAILS,
+  PROP_HAS_DETAILS
+};
+
+/* Columns for the GtkTreeView */
+enum
+{
+  COLUMN_ICON,
+  COLUMN_MESSAGE,
+  COLUMN_MESSAGE_TYPE,
+  COLUMN_WEIGHT,
+  COLUMN_BASENAME,
+  COLUMN_PATH,
+  COLUMN_FILE,
+  COLUMN_START_LINE,
+  COLUMN_END_LINE,
+  COLUMN_LINE_STR,
+  NB_COLUMNS
+};
+
+enum
+{
+  SIGNAL_JUMP_TO_FILE,
+  LAST_SIGNAL
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (LatexilaBuildView, latexila_build_view, GTK_TYPE_TREE_VIEW)
+
+static guint signals[LAST_SIGNAL];
+
+/**
+ * latexila_build_msg_new: (skip)
+ *
+ * Free the return value with latexila_build_msg_free() when no longer needed.
+ *
+ * Returns: a newly-allocated #LatexilaBuildMsg.
+ */
+LatexilaBuildMsg *
+latexila_build_msg_new (void)
+{
+  LatexilaBuildMsg *build_msg = g_slice_new0 (LatexilaBuildMsg);
+
+  build_msg->start_line = -1;
+  build_msg->end_line = -1;
+  build_msg->expand = TRUE;
+
+  return build_msg;
+}
+
+/**
+ * latexila_build_msg_free: (skip)
+ * @build_msg: a #LatexilaBuildMsg.
+ *
+ * Frees the @build_msg structure.
+ */
+void
+latexila_build_msg_free (LatexilaBuildMsg *build_msg)
+{
+  if (build_msg != NULL)
+    {
+      g_free (build_msg->text);
+      g_free (build_msg->filename);
+      g_slice_free (LatexilaBuildMsg, build_msg);
+    }
+}
+
+static void
+latexila_build_view_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  LatexilaBuildView *build_view = LATEXILA_BUILD_VIEW (object);
+
+  switch (prop_id)
+    {
+    case PROP_SHOW_WARNINGS:
+      g_value_set_boolean (value, build_view->priv->show_warnings);
+      break;
+
+    case PROP_SHOW_BADBOXES:
+      g_value_set_boolean (value, build_view->priv->show_badboxes);
+      break;
+
+    case PROP_SHOW_DETAILS:
+      g_value_set_boolean (value, build_view->priv->show_details);
+      break;
+
+    case PROP_HAS_DETAILS:
+      g_value_set_boolean (value, build_view->priv->has_details);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+latexila_build_view_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  LatexilaBuildView *build_view = LATEXILA_BUILD_VIEW (object);
+
+  switch (prop_id)
+    {
+    case PROP_SHOW_WARNINGS:
+      build_view->priv->show_warnings = g_value_get_boolean (value);
+
+      if (build_view->priv->filtered_model != NULL)
+        {
+          gtk_tree_model_filter_refilter (build_view->priv->filtered_model);
+        }
+      break;
+
+    case PROP_SHOW_BADBOXES:
+      build_view->priv->show_badboxes = g_value_get_boolean (value);
+
+      if (build_view->priv->filtered_model != NULL)
+        {
+          gtk_tree_model_filter_refilter (build_view->priv->filtered_model);
+        }
+      break;
+
+    case PROP_SHOW_DETAILS:
+      build_view->priv->show_details = g_value_get_boolean (value);
+      break;
+
+    case PROP_HAS_DETAILS:
+      build_view->priv->has_details = g_value_get_boolean (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+latexila_build_view_dispose (GObject *object)
+{
+  LatexilaBuildView *build_view = LATEXILA_BUILD_VIEW (object);
+
+  g_clear_object (&build_view->priv->store);
+  g_clear_object (&build_view->priv->filtered_model);
+
+  G_OBJECT_CLASS (latexila_build_view_parent_class)->dispose (object);
+}
+
+#if 0
+static void
+latexila_build_view_finalize (GObject *object)
+{
+
+  G_OBJECT_CLASS (latexila_build_view_parent_class)->finalize (object);
+}
+#endif
+
+static void
+latexila_build_view_class_init (LatexilaBuildViewClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->get_property = latexila_build_view_get_property;
+  object_class->set_property = latexila_build_view_set_property;
+  object_class->dispose = latexila_build_view_dispose;
+  /*object_class->finalize = latexila_build_view_finalize;*/
+
+  g_object_class_install_property (object_class,
+                                   PROP_SHOW_WARNINGS,
+                                   g_param_spec_boolean ("show-warnings",
+                                                         "Show warnings",
+                                                         "",
+                                                         TRUE,
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT |
+                                                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SHOW_BADBOXES,
+                                   g_param_spec_boolean ("show-badboxes",
+                                                         "Show badboxes",
+                                                         "",
+                                                         TRUE,
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT |
+                                                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class,
+                                   PROP_SHOW_DETAILS,
+                                   g_param_spec_boolean ("show-details",
+                                                         "Show details",
+                                                         "",
+                                                         FALSE,
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT |
+                                                         G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (object_class,
+                                   PROP_HAS_DETAILS,
+                                   g_param_spec_boolean ("has-details",
+                                                         "Has details",
+                                                         "",
+                                                         FALSE,
+                                                         G_PARAM_READWRITE |
+                                                         G_PARAM_CONSTRUCT |
+                                                         G_PARAM_STATIC_STRINGS));
+
+  /**
+   * LatexilaBuildView::jump-to-file:
+   * @build_view: a #LatexilaBuildView.
+   * @file: the file to open.
+   * @start_line: the line where to jump and the start of the selection, or -1.
+   * @end_line: the end of the selection, or -1.
+   *
+   * The ::jump-to-file signal is emitted when a row in the build view is
+   * selected. The row must contain a file, otherwise the signal is not emitted.
+   * The file should be opened and presented to the user. If @start_line and
+   * @end_line are not -1, jump to the @start_line and select those lines. If
+   * only @start_line is provided, jump to it and select it.
+   */
+  signals[SIGNAL_JUMP_TO_FILE] = g_signal_new ("jump-to-file",
+                                               LATEXILA_TYPE_BUILD_VIEW,
+                                               G_SIGNAL_RUN_LAST,
+                                               0, NULL, NULL, NULL,
+                                               G_TYPE_NONE,
+                                               3,
+                                               G_TYPE_FILE,
+                                               G_TYPE_INT,
+                                               G_TYPE_INT);
+}
+
+static gboolean
+visible_func (GtkTreeModel *model,
+              GtkTreeIter  *iter,
+              gpointer      user_data)
+{
+  LatexilaBuildMsgType msg_type;
+  LatexilaBuildView *build_view = user_data;
+
+  gtk_tree_model_get (model, iter,
+                      COLUMN_MESSAGE_TYPE, &msg_type,
+                      -1);
+
+  switch (msg_type)
+    {
+    case LATEXILA_BUILD_MSG_TYPE_WARNING:
+      return build_view->priv->show_warnings;
+
+    case LATEXILA_BUILD_MSG_TYPE_BADBOX:
+      return build_view->priv->show_badboxes;
+
+    default:
+      return TRUE;
+    }
+}
+
+static void
+init_tree_models (LatexilaBuildView *build_view)
+{
+  g_assert (build_view->priv->store == NULL);
+
+  build_view->priv->store = gtk_tree_store_new (NB_COLUMNS,
+                                                GDK_TYPE_PIXBUF,  /* icon */
+                                                G_TYPE_STRING,    /* message */
+                                                LATEXILA_TYPE_BUILD_MSG_TYPE,
+                                                G_TYPE_INT,       /* weight (normal or bold) */
+                                                G_TYPE_STRING,    /* basename */
+                                                G_TYPE_STRING,    /* path */
+                                                G_TYPE_FILE,
+                                                G_TYPE_INT,       /* start line */
+                                                G_TYPE_INT,       /* end line */
+                                                G_TYPE_STRING);   /* line (same as start line but for 
display) */
+
+  build_view->priv->filtered_model = GTK_TREE_MODEL_FILTER (
+    gtk_tree_model_filter_new (GTK_TREE_MODEL (build_view->priv->store), NULL));
+
+  gtk_tree_model_filter_set_visible_func (build_view->priv->filtered_model,
+                                          visible_func,
+                                          build_view,
+                                          NULL);
+}
+
+/* Returns TRUE to select the row. */
+static gboolean
+select_row (LatexilaBuildView *build_view,
+            GtkTreeModel      *model,
+            GtkTreePath       *path)
+{
+  GtkTreeView *tree_view = GTK_TREE_VIEW (build_view);
+  GtkTreeIter iter;
+  GFile *file;
+  gint start_line;
+  gint end_line;
+
+  if (!gtk_tree_model_get_iter (model, &iter, path))
+    {
+      return FALSE;
+    }
+
+  if (gtk_tree_model_iter_has_child (model, &iter))
+    {
+      if (gtk_tree_view_row_expanded (tree_view, path))
+        {
+          gtk_tree_view_collapse_row (tree_view, path);
+        }
+      else
+        {
+          gtk_tree_view_expand_to_path (tree_view, path);
+        }
+
+      return FALSE;
+    }
+
+  gtk_tree_model_get (model, &iter,
+                      COLUMN_FILE, &file,
+                      COLUMN_START_LINE, &start_line,
+                      COLUMN_END_LINE, &end_line,
+                      -1);
+
+  if (file != NULL)
+    {
+      g_signal_emit (build_view,
+                     signals[SIGNAL_JUMP_TO_FILE],
+                     0,
+                     file,
+                     start_line,
+                     end_line);
+
+      g_object_unref (file);
+    }
+
+  /* Select the row, so the user can copy/paste its contents. */
+  return TRUE;
+}
+
+static gboolean
+select_func (GtkTreeSelection *selection,
+             GtkTreeModel     *model,
+             GtkTreePath      *path,
+             gboolean          path_currently_selected,
+             gpointer          user_data)
+{
+  LatexilaBuildView *build_view = user_data;
+
+  if (path_currently_selected)
+    {
+      /* Always allow deselect */
+      return TRUE;
+    }
+
+  return select_row (build_view, model, path);
+}
+
+static void
+row_activated_cb (LatexilaBuildView *build_view,
+                  GtkTreePath       *path)
+{
+  select_row (build_view,
+              GTK_TREE_MODEL (build_view->priv->filtered_model),
+              path);
+}
+
+static void
+init_tree_view (LatexilaBuildView *build_view)
+{
+  GtkTreeView *tree_view = GTK_TREE_VIEW (build_view);
+  GtkTreeViewColumn *column;
+  GtkCellRenderer *renderer;
+  GtkTreeSelection *selection;
+
+  gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (build_view->priv->store));
+  gtk_tree_view_set_headers_visible (tree_view, FALSE);
+
+  /* Columns, cell renderers */
+
+  column = gtk_tree_view_column_new ();
+
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_add_attribute (column, renderer, "pixbuf", COLUMN_ICON);
+
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (renderer,
+                "weight-set", TRUE,
+                "editable", TRUE,
+                "editable-set", TRUE,
+                NULL);
+
+  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+  gtk_tree_view_column_add_attribute (column, renderer, "text", COLUMN_MESSAGE);
+  gtk_tree_view_column_add_attribute (column, renderer, "weight", COLUMN_WEIGHT);
+
+  gtk_tree_view_append_column (tree_view, column);
+
+  gtk_tree_view_insert_column_with_attributes (tree_view, -1, NULL,
+                                               gtk_cell_renderer_text_new (),
+                                               "text", COLUMN_BASENAME,
+                                               NULL);
+
+  gtk_tree_view_insert_column_with_attributes (tree_view, -1, NULL,
+                                               gtk_cell_renderer_text_new (),
+                                               "text", COLUMN_LINE_STR,
+                                               NULL);
+
+  gtk_tree_view_set_tooltip_column (tree_view, COLUMN_PATH);
+
+  /* Selection */
+
+  selection = gtk_tree_view_get_selection (tree_view);
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+  gtk_tree_selection_set_select_function (selection, select_func, build_view, NULL);
+
+  /* Double-click */
+
+  g_signal_connect (build_view,
+                    "row-activated",
+                    G_CALLBACK (row_activated_cb),
+                    NULL);
+}
+
+static void
+latexila_build_view_init (LatexilaBuildView *build_view)
+{
+  build_view->priv = latexila_build_view_get_instance_private (build_view);
+
+  init_tree_models (build_view);
+  init_tree_view (build_view);
+}
+
+/**
+ * latexila_build_view_new:
+ *
+ * Returns: a new #LatexilaBuildView.
+ */
+LatexilaBuildView *
+latexila_build_view_new (void)
+{
+  return g_object_new (LATEXILA_TYPE_BUILD_VIEW, NULL);
+}
+
+/**
+ * latexila_build_view_clear:
+ * @build_view: a #LatexilaBuildView.
+ *
+ * Clears the build view.
+ */
+void
+latexila_build_view_clear (LatexilaBuildView *build_view)
+{
+  GtkTreeSelection *selection;
+
+  g_return_if_fail (LATEXILA_IS_BUILD_VIEW (build_view));
+
+  /* No selection allowed when clearing the GtkTreeStore. Else, all the rows are
+   * selected, and if there are warnings or errors, the program jumps to all
+   * warnings/errors one by one. It's fun, but after four or five times, it
+   * becomes less fun because our text cursor moves all the time ;) Another
+   * means would have been to remove and re-add the select function, but I
+   * prefer this hack, shorter :)
+   */
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (build_view));
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_NONE);
+  gtk_tree_store_clear (build_view->priv->store);
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+
+  gtk_tree_view_columns_autosize (GTK_TREE_VIEW (build_view));
+}
+
+static GtkTreeIter
+add_title (LatexilaBuildView    *build_view,
+           const gchar          *message,
+           LatexilaBuildState    state,
+           LatexilaBuildMsgType  type)
+{
+  gboolean bold = type == LATEXILA_BUILD_MSG_TYPE_MAIN_TITLE;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+
+  gtk_tree_store_append (build_view->priv->store, &iter, NULL);
+  gtk_tree_store_set (build_view->priv->store, &iter,
+                      COLUMN_ICON, NULL, /* TODO */
+                      COLUMN_MESSAGE, message,
+                      COLUMN_MESSAGE_TYPE, type,
+                      COLUMN_WEIGHT, bold ? 800 : 400,
+                      -1);
+
+  path = gtk_tree_model_get_path (GTK_TREE_MODEL (build_view->priv->store), &iter);
+  gtk_tree_view_expand_to_path (GTK_TREE_VIEW (build_view), path);
+  gtk_tree_path_free (path);
+
+  return iter;
+}
+
+/**
+ * latexila_build_view_add_main_title:
+ * @build_view: a #LatexilaBuildView.
+ * @main_title: the title.
+ * @state: the current state of the build tool.
+ *
+ * Adds a build tool title. There should be only one main title.
+ *
+ * Returns: the title ID as a #GtkTreeIter.
+ */
+GtkTreeIter
+latexila_build_view_add_main_title (LatexilaBuildView  *build_view,
+                                    const gchar        *main_title,
+                                    LatexilaBuildState  state)
+{
+  return add_title (build_view, main_title, state, LATEXILA_BUILD_MSG_TYPE_MAIN_TITLE);
+}
+
+/**
+ * latexila_build_view_add_job_title:
+ * @build_view: a #LatexilaBuildView.
+ * @job_title: the title.
+ * @state: the current state of the build job.
+ *
+ * Adds a build job title.
+ *
+ * Returns: the title ID as a #GtkTreeIter.
+ */
+GtkTreeIter
+latexila_build_view_add_job_title (LatexilaBuildView  *build_view,
+                                   const gchar        *job_title,
+                                   LatexilaBuildState  state)
+{
+  return add_title (build_view, job_title, state, LATEXILA_BUILD_MSG_TYPE_JOB_TITLE);
+}
+
+/**
+ * latexila_build_view_set_title_state:
+ * @build_view: a #LatexilaBuildView.
+ * @title_id: the title ID as a #GtkTreeIter.
+ * @state: the new state.
+ *
+ * Changes the build state of a title, represented as an icon.
+ * If @title_id is the main title, @state is for the whole build tool. If
+ * @title_id is for a job title, @state is for the build job.
+ */
+void
+latexila_build_view_set_title_state (LatexilaBuildView  *build_view,
+                                     GtkTreeIter        *title_id,
+                                     LatexilaBuildState  state)
+{
+  g_return_if_fail (LATEXILA_IS_BUILD_VIEW (build_view));
+  g_return_if_fail (title_id != NULL);
+
+  gtk_tree_store_set (build_view->priv->store, title_id,
+                      COLUMN_ICON, NULL, /* TODO */
+                      -1);
+}
+
+/**
+ * latexila_build_view_append_single_message:
+ * @build_view: a #LatexilaBuildView.
+ * @parent: the parent row in the tree.
+ * @message: the build message structure.
+ *
+ * Appends a single message to the build view.
+ *
+ * Returns: the #GtkTreeIter where the message has been added.
+ */
+GtkTreeIter
+latexila_build_view_append_single_message (LatexilaBuildView *build_view,
+                                           GtkTreeIter       *parent,
+                                           LatexilaBuildMsg  *message)
+{
+  GFile *file = NULL;
+  gchar *path = NULL;
+  gchar *basename = NULL;
+  gchar *line_str = NULL;
+  gint end_line;
+  GtkTreeIter iter;
+
+  if (message->filename != NULL)
+    {
+      file = g_file_new_for_path (message->filename);
+
+      /* TODO implement and call latexila_utils_replace_home_dir_with_tilde() on
+       * the path. See if gedit has already this function in C.
+       */
+      path = g_markup_escape_text (message->filename, -1);
+
+      basename = g_file_get_basename (file);
+    }
+
+  if (message->start_line != -1)
+    {
+      line_str = g_strdup_printf ("%d", message->start_line);
+    }
+
+  end_line = message->end_line;
+  if (message->start_line != -1 && end_line == -1)
+    {
+      end_line = message->start_line + 1;
+    }
+
+  gtk_tree_store_append (build_view->priv->store, &iter, parent);
+  gtk_tree_store_set (build_view->priv->store, &iter,
+                      COLUMN_ICON, NULL, /* TODO */
+                      COLUMN_MESSAGE, message->text,
+                      COLUMN_MESSAGE_TYPE, message->type,
+                      COLUMN_WEIGHT, 400,
+                      COLUMN_BASENAME, basename,
+                      COLUMN_FILE, file,
+                      COLUMN_PATH, path,
+                      COLUMN_START_LINE, message->start_line,
+                      COLUMN_END_LINE, end_line,
+                      COLUMN_LINE_STR, line_str,
+                      -1);
+
+  g_object_unref (file);
+  g_free (path);
+  g_free (basename);
+  g_free (line_str);
+
+  return iter;
+}
+
+/**
+ * latexila_build_view_append_messages:
+ * @build_view: a #LatexilaBuildView.
+ * @parent: the parent row in the tree.
+ * @messages: the tree of #LatexilaBuildMsg's to append.
+ * @expand: whether to expand the @parent.
+ *
+ * Appends a tree of messages to the build view.
+ */
+void
+latexila_build_view_append_messages (LatexilaBuildView *build_view,
+                                     GtkTreeIter       *parent,
+                                     GNode             *messages,
+                                     gboolean           expand)
+{
+  GNode *node;
+
+  for (node = messages; node != NULL; node = node->next)
+    {
+      GtkTreeIter child;
+      LatexilaBuildMsg *build_msg = node->data;
+
+      g_assert (build_msg != NULL);
+
+      child = latexila_build_view_append_single_message (build_view, parent, build_msg);
+
+      if (node->children != NULL)
+        {
+          latexila_build_view_append_messages (build_view,
+                                               &child,
+                                               node->children,
+                                               build_msg->expand);
+        }
+    }
+
+  if (expand)
+    {
+      GtkTreePath *path;
+      path = gtk_tree_model_get_path (GTK_TREE_MODEL (build_view->priv->store), parent);
+      gtk_tree_view_expand_to_path (GTK_TREE_VIEW (build_view), path);
+      gtk_tree_path_free (path);
+    }
+}
+
+/**
+ * latexila_build_view_remove_children:
+ * @build_view: a #LatexilaBuildView.
+ * @parent: the row for which the children must be removed.
+ *
+ * Removes the children of @parent.
+ */
+void
+latexila_build_view_remove_children (LatexilaBuildView *build_view,
+                                     GtkTreeIter       *parent)
+{
+  GtkTreeIter child;
+  GtkTreeModel *model;
+
+  g_return_if_fail (LATEXILA_IS_BUILD_VIEW (build_view));
+
+  model = GTK_TREE_MODEL (build_view->priv->store);
+  if (!gtk_tree_model_iter_children (model, &child, parent))
+    {
+      return;
+    }
+
+  while (gtk_tree_store_remove (build_view->priv->store, &child));
+}
diff --git a/src/liblatexila/latexila-build-view.h b/src/liblatexila/latexila-build-view.h
new file mode 100644
index 0000000..c85b7cd
--- /dev/null
+++ b/src/liblatexila/latexila-build-view.h
@@ -0,0 +1,150 @@
+/*
+ * This file is part of LaTeXila.
+ *
+ * Copyright (C) 2014 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * LaTeXila is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LaTeXila 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with LaTeXila.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LATEXILA_BUILD_VIEW_H__
+#define __LATEXILA_BUILD_VIEW_H__
+
+#include <gtk/gtk.h>
+#include "latexila-types.h"
+
+G_BEGIN_DECLS
+
+#define LATEXILA_TYPE_BUILD_VIEW             (latexila_build_view_get_type ())
+#define LATEXILA_BUILD_VIEW(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), LATEXILA_TYPE_BUILD_VIEW, 
LatexilaBuildView))
+#define LATEXILA_BUILD_VIEW_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), LATEXILA_TYPE_BUILD_VIEW, 
LatexilaBuildViewClass))
+#define LATEXILA_IS_BUILD_VIEW(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LATEXILA_TYPE_BUILD_VIEW))
+#define LATEXILA_IS_BUILD_VIEW_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), LATEXILA_TYPE_BUILD_VIEW))
+#define LATEXILA_BUILD_VIEW_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), LATEXILA_TYPE_BUILD_VIEW, 
LatexilaBuildViewClass))
+
+typedef struct _LatexilaBuildMsg         LatexilaBuildMsg;
+typedef struct _LatexilaBuildViewClass   LatexilaBuildViewClass;
+typedef struct _LatexilaBuildViewPrivate LatexilaBuildViewPrivate;
+
+/**
+ * LatexilaBuildState:
+ * @LATEXILA_BUILD_STATE_RUNNING: running.
+ * @LATEXILA_BUILD_STATE_SUCCEEDED: succeeded.
+ * @LATEXILA_BUILD_STATE_FAILED: failed.
+ * @LATEXILA_BUILD_STATE_ABORTED: aborted.
+ */
+typedef enum
+{
+  LATEXILA_BUILD_STATE_RUNNING,
+  LATEXILA_BUILD_STATE_SUCCEEDED,
+  LATEXILA_BUILD_STATE_FAILED,
+  LATEXILA_BUILD_STATE_ABORTED
+} LatexilaBuildState;
+
+/**
+ * LatexilaBuildMsgType:
+ * @LATEXILA_BUILD_MSG_TYPE_MAIN_TITLE: main title.
+ * @LATEXILA_BUILD_MSG_TYPE_JOB_TITLE: build job title.
+ * @LATEXILA_BUILD_MSG_TYPE_JOB_SUB_COMMAND: build job sub-command.
+ * @LATEXILA_BUILD_MSG_TYPE_ERROR: error.
+ * @LATEXILA_BUILD_MSG_TYPE_WARNING: warning.
+ * @LATEXILA_BUILD_MSG_TYPE_BADBOX: badbox.
+ * @LATEXILA_BUILD_MSG_TYPE_INFO: other info.
+ */
+typedef enum
+{
+  LATEXILA_BUILD_MSG_TYPE_MAIN_TITLE,
+  LATEXILA_BUILD_MSG_TYPE_JOB_TITLE,
+  LATEXILA_BUILD_MSG_TYPE_JOB_SUB_COMMAND,
+  LATEXILA_BUILD_MSG_TYPE_ERROR,
+  LATEXILA_BUILD_MSG_TYPE_WARNING,
+  LATEXILA_BUILD_MSG_TYPE_BADBOX,
+  LATEXILA_BUILD_MSG_TYPE_INFO
+} LatexilaBuildMsgType;
+
+/**
+ * LatexilaBuildMsg:
+ * @type: the message type.
+ * @text: the text.
+ * @filename: reference to a certain file.
+ * @start_line: reference to a line in the file. -1 to unset.
+ * @end_line: reference to a line in the file. -1 to unset.
+ * @expand: if the message has children, whether to show them by default.
+ *
+ * A build message, one line in the #GtkTreeView. If a @filename is provided,
+ * the file will be opened when the user clicks on the message. If @start_line
+ * and @end_line are provided, the lines between the two positions will be
+ * selected (or just @start_line will be selected if @end_line is -1).
+ *
+ * The @expand field assumes that a #LatexilaBuildMsg is included in a #GNode or
+ * similar N-ary tree structure.
+ */
+struct _LatexilaBuildMsg
+{
+  LatexilaBuildMsgType type;
+  gchar *text;
+  gchar *filename;
+  gint start_line;
+  gint end_line;
+  guint expand : 1;
+};
+
+struct _LatexilaBuildView
+{
+  GtkTreeView parent;
+
+  LatexilaBuildViewPrivate *priv;
+};
+
+struct _LatexilaBuildViewClass
+{
+  GtkTreeViewClass parent_class;
+};
+
+LatexilaBuildMsg *    latexila_build_msg_new                        (void);
+
+void                  latexila_build_msg_free                       (LatexilaBuildMsg *build_msg);
+
+GType                 latexila_build_view_get_type                  (void) G_GNUC_CONST;
+
+LatexilaBuildView *   latexila_build_view_new                       (void);
+
+void                  latexila_build_view_clear                     (LatexilaBuildView *build_view);
+
+GtkTreeIter           latexila_build_view_add_main_title            (LatexilaBuildView  *build_view,
+                                                                     const gchar        *main_title,
+                                                                     LatexilaBuildState  state);
+
+GtkTreeIter           latexila_build_view_add_job_title             (LatexilaBuildView  *build_view,
+                                                                     const gchar        *job_title,
+                                                                     LatexilaBuildState  state);
+
+void                  latexila_build_view_set_title_state           (LatexilaBuildView  *build_view,
+                                                                     GtkTreeIter        *title_id,
+                                                                     LatexilaBuildState  state);
+
+GtkTreeIter           latexila_build_view_append_single_message     (LatexilaBuildView *build_view,
+                                                                     GtkTreeIter       *parent,
+                                                                     LatexilaBuildMsg  *message);
+
+void                  latexila_build_view_append_messages           (LatexilaBuildView *build_view,
+                                                                     GtkTreeIter       *parent,
+                                                                     GNode             *messages,
+                                                                     gboolean           expand);
+
+void                  latexila_build_view_remove_children           (LatexilaBuildView *build_view,
+                                                                     GtkTreeIter       *parent);
+
+G_END_DECLS
+
+#endif /* __LATEXILA_BUILD_VIEW_H__ */
diff --git a/src/liblatexila/latexila-types.h b/src/liblatexila/latexila-types.h
index dce5031..9ca5d99 100644
--- a/src/liblatexila/latexila-types.h
+++ b/src/liblatexila/latexila-types.h
@@ -29,6 +29,7 @@ typedef struct _LatexilaBuildTool               LatexilaBuildTool;
 typedef struct _LatexilaBuildTools              LatexilaBuildTools;
 typedef struct _LatexilaBuildToolsDefault       LatexilaBuildToolsDefault;
 typedef struct _LatexilaBuildToolsPersonal      LatexilaBuildToolsPersonal;
+typedef struct _LatexilaBuildView               LatexilaBuildView;
 typedef struct _LatexilaPostProcessor           LatexilaPostProcessor;
 typedef struct _LatexilaPostProcessorAllOutput  LatexilaPostProcessorAllOutput;
 


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