[latexila/wip/build-tools-revamp] Build tools: implement the run operations
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [latexila/wip/build-tools-revamp] Build tools: implement the run operations
- Date: Fri, 16 May 2014 20:49:47 +0000 (UTC)
commit c8551bb849367a521c858c107574c0dcf6400041
Author: Sébastien Wilmet <swilmet gnome org>
Date: Thu May 8 22:08:47 2014 +0200
Build tools: implement the run operations
And adds a str_replace() utils function.
docs/reference/latexila-sections.txt | 6 +-
src/liblatexila/latexila-build-job.c | 380 +++++++++++++++++++++++++++++++++
src/liblatexila/latexila-build-job.h | 12 +-
src/liblatexila/latexila-build-tool.c | 358 ++++++++++++++++++++++++++++++-
src/liblatexila/latexila-build-tool.h | 12 +-
src/liblatexila/latexila-build-view.c | 9 +-
src/liblatexila/latexila-utils.c | 36 +++
src/liblatexila/latexila-utils.h | 4 +
src/main_window_build_tools.vala | 22 +-
tests/test-utils.c | 23 ++
10 files changed, 834 insertions(+), 28 deletions(-)
---
diff --git a/docs/reference/latexila-sections.txt b/docs/reference/latexila-sections.txt
index 8d1703a..6730ec5 100644
--- a/docs/reference/latexila-sections.txt
+++ b/docs/reference/latexila-sections.txt
@@ -67,7 +67,8 @@ latexila_build_tool_add_job
latexila_build_tool_get_jobs
latexila_build_tool_get_description
latexila_build_tool_to_xml
-latexila_build_tool_run
+latexila_build_tool_run_async
+latexila_build_tool_run_finish
<SUBSECTION Standard>
LATEXILA_BUILD_TOOL
LATEXILA_BUILD_TOOL_CLASS
@@ -87,6 +88,8 @@ LatexilaBuildJob
latexila_build_job_new
latexila_build_job_clone
latexila_build_job_to_xml
+latexila_build_job_run_async
+latexila_build_job_run_finish
<SUBSECTION Standard>
LATEXILA_BUILD_JOB
LATEXILA_BUILD_JOB_CLASS
@@ -133,4 +136,5 @@ latexila_build_view_get_type
latexila_utils_get_shortname
latexila_utils_replace_home_dir_with_tilde
latexila_utils_register_icons
+latexila_utils_str_replace
</SECTION>
diff --git a/src/liblatexila/latexila-build-job.c b/src/liblatexila/latexila-build-job.c
index f6d458b..bd35801 100644
--- a/src/liblatexila/latexila-build-job.c
+++ b/src/liblatexila/latexila-build-job.c
@@ -26,12 +26,23 @@
*/
#include "latexila-build-job.h"
+#include <string.h>
+#include <glib/gi18n.h>
+#include "latexila-build-view.h"
+#include "latexila-utils.h"
#include "latexila-enum-types.h"
struct _LatexilaBuildJobPrivate
{
gchar *command;
LatexilaPostProcessorType post_processor_type;
+
+ /* Used for running the build job. */
+ GTask *task;
+ GFile *file;
+ LatexilaBuildView *build_view;
+ GtkTreeIter job_title;
+ GNode *build_messages;
};
enum
@@ -43,6 +54,30 @@ enum
G_DEFINE_TYPE_WITH_PRIVATE (LatexilaBuildJob, latexila_build_job, G_TYPE_OBJECT)
+static gboolean
+free_build_msg (GNode *node,
+ gpointer user_data)
+{
+ latexila_build_msg_free (node->data);
+ return FALSE;
+}
+
+static void
+free_build_messages (GNode *build_messages)
+{
+ if (build_messages != NULL)
+ {
+ g_node_traverse (build_messages,
+ G_POST_ORDER,
+ G_TRAVERSE_ALL,
+ -1,
+ free_build_msg,
+ NULL);
+
+ g_node_destroy (build_messages);
+ }
+}
+
static void
latexila_build_job_get_property (GObject *object,
guint prop_id,
@@ -75,6 +110,9 @@ latexila_build_job_set_property (GObject *object,
{
LatexilaBuildJob *build_job = LATEXILA_BUILD_JOB (object);
+ /* The build job can not be modified when it is running. */
+ g_return_if_fail (build_job->priv->task == NULL);
+
switch (prop_id)
{
case PROP_COMMAND:
@@ -95,6 +133,11 @@ latexila_build_job_set_property (GObject *object,
static void
latexila_build_job_dispose (GObject *object)
{
+ LatexilaBuildJob *build_job = LATEXILA_BUILD_JOB (object);
+
+ g_clear_object (&build_job->priv->task);
+ g_clear_object (&build_job->priv->file);
+ g_clear_object (&build_job->priv->build_view);
G_OBJECT_CLASS (latexila_build_job_parent_class)->dispose (object);
}
@@ -105,6 +148,7 @@ latexila_build_job_finalize (GObject *object)
LatexilaBuildJob *build_job = LATEXILA_BUILD_JOB (object);
g_free (build_job->priv->command);
+ free_build_messages (build_job->priv->build_messages);
G_OBJECT_CLASS (latexila_build_job_parent_class)->finalize (object);
}
@@ -192,3 +236,339 @@ latexila_build_job_to_xml (LatexilaBuildJob *build_job)
latexila_post_processor_get_name_from_type
(build_job->priv->post_processor_type),
build_job->priv->command != NULL ? build_job->priv->command : "");
}
+
+static gchar **
+get_command_argv (LatexilaBuildJob *build_job,
+ gboolean for_printing,
+ GError **error)
+{
+ gchar **argv;
+ gchar *base_filename;
+ gchar *base_shortname;
+ gint i;
+
+ /* Separate arguments */
+ if (!g_shell_parse_argv (build_job->priv->command, NULL, &argv, error) ||
+ argv == NULL)
+ {
+ return NULL;
+ }
+
+ /* Re-add quotes if needed */
+ if (for_printing)
+ {
+ for (i = 0; argv[i] != NULL; i++)
+ {
+ /* If the argument contains a space, add the quotes. */
+ if (strchr (argv[i], ' ') != NULL)
+ {
+ gchar *new_arg = g_strdup_printf ("\"%s\"", argv[i]);
+ g_free (argv[i]);
+ argv[i] = new_arg;
+ }
+ }
+ }
+
+ /* Replace placeholders */
+ base_filename = g_file_get_basename (build_job->priv->file);
+ base_shortname = latexila_utils_get_shortname (base_filename);
+
+ for (i = 0; argv[i] != NULL; i++)
+ {
+ gchar *new_arg = NULL;
+
+ if (strstr (argv[i], "$filename") != NULL)
+ {
+ new_arg = latexila_utils_str_replace (argv[i], "$filename", base_filename);
+ }
+ else if (strstr (argv[i], "$shortname"))
+ {
+ new_arg = latexila_utils_str_replace (argv[i], "$shortname", base_shortname);
+ }
+ else if (strstr (argv[i], "$view"))
+ {
+ g_warning ("Build job: the '$view' placeholder is deprecated.");
+ new_arg = latexila_utils_str_replace (argv[i], "$view", "xdg-open");
+ }
+
+ if (new_arg != NULL)
+ {
+ g_free (argv[i]);
+ argv[i] = new_arg;
+ }
+ }
+
+ g_free (base_filename);
+ g_free (base_shortname);
+ return argv;
+}
+
+static gchar *
+get_command_name (LatexilaBuildJob *build_job)
+{
+ gchar **argv;
+ gchar *command_name;
+
+ argv = get_command_argv (build_job, TRUE, NULL);
+
+ if (argv == NULL || argv[0] == NULL || argv[0][0] == '\0')
+ {
+ command_name = NULL;
+ }
+ else
+ {
+ command_name = g_strdup (argv[0]);
+ }
+
+ g_strfreev (argv);
+ return command_name;
+}
+
+static void
+display_error (LatexilaBuildJob *build_job,
+ const gchar *message,
+ GError *error)
+{
+ LatexilaBuildMsg *build_msg;
+
+ g_assert (error != NULL);
+
+ latexila_build_view_set_title_state (build_job->priv->build_view,
+ &build_job->priv->job_title,
+ LATEXILA_BUILD_STATE_FAILED);
+
+ build_msg = latexila_build_msg_new ();
+ build_msg->text = (gchar *) message;
+ build_msg->type = LATEXILA_BUILD_MSG_TYPE_ERROR;
+ latexila_build_view_append_single_message (build_job->priv->build_view,
+ &build_job->priv->job_title,
+ build_msg);
+
+ build_msg->text = g_strdup (error->message);
+ build_msg->type = LATEXILA_BUILD_MSG_TYPE_INFO;
+ latexila_build_view_append_single_message (build_job->priv->build_view,
+ &build_job->priv->job_title,
+ build_msg);
+
+ /* If the command doesn't seem to be installed, display a more understandable
+ * message.
+ */
+ if (error->domain == G_SPAWN_ERROR &&
+ error->code == G_SPAWN_ERROR_NOENT)
+ {
+ gchar *command_name = get_command_name (build_job);
+
+ if (command_name != NULL)
+ {
+ g_free (build_msg->text);
+ build_msg->text = g_strdup_printf (_("%s doesn't seem to be installed."), command_name);
+
+ latexila_build_view_append_single_message (build_job->priv->build_view,
+ &build_job->priv->job_title,
+ build_msg);
+
+ g_free (command_name);
+ }
+ }
+
+ g_error_free (error);
+ latexila_build_msg_free (build_msg);
+ g_task_return_boolean (build_job->priv->task, FALSE);
+}
+
+/* Returns TRUE on success. */
+static gboolean
+display_command_line (LatexilaBuildJob *build_job)
+{
+ gchar **argv;
+ gchar *command_line;
+ GError *error = NULL;
+
+ argv = get_command_argv (build_job, TRUE, &error);
+
+ if (error != NULL)
+ {
+ build_job->priv->job_title = latexila_build_view_add_job_title (build_job->priv->build_view,
+ build_job->priv->command,
+ LATEXILA_BUILD_STATE_FAILED);
+
+ display_error (build_job, "Failed to parse command line:", error);
+ return FALSE;
+ }
+
+ command_line = g_strjoinv (" ", argv);
+
+ build_job->priv->job_title = latexila_build_view_add_job_title (build_job->priv->build_view,
+ command_line,
+ LATEXILA_BUILD_STATE_RUNNING);
+
+ g_strfreev (argv);
+ g_free (command_line);
+ return TRUE;
+}
+
+static void
+subprocess_wait_cb (GSubprocess *subprocess,
+ GAsyncResult *result,
+ LatexilaBuildJob *build_job)
+{
+ LatexilaBuildMsg *msg;
+ gboolean ret;
+ LatexilaBuildState state;
+
+ ret = g_subprocess_wait_finish (subprocess, result, NULL);
+
+ if (!ret)
+ {
+ state = LATEXILA_BUILD_STATE_ABORTED;
+ g_subprocess_force_exit (subprocess);
+ }
+ else if (g_subprocess_get_successful (subprocess))
+ {
+ state = LATEXILA_BUILD_STATE_SUCCEEDED;
+ }
+ else
+ {
+ ret = FALSE;
+ state = LATEXILA_BUILD_STATE_FAILED;
+ }
+
+ msg = latexila_build_msg_new ();
+ msg->text = g_strdup ("build job output");
+ msg->type = LATEXILA_BUILD_MSG_TYPE_INFO;
+
+ latexila_build_view_append_single_message (build_job->priv->build_view,
+ &build_job->priv->job_title,
+ msg);
+
+ latexila_build_view_set_title_state (build_job->priv->build_view,
+ &build_job->priv->job_title,
+ state);
+
+ g_task_return_boolean (build_job->priv->task, ret);
+
+ latexila_build_msg_free (msg);
+ g_object_unref (subprocess);
+}
+
+static void
+launch_subprocess (LatexilaBuildJob *build_job)
+{
+ GSubprocessLauncher *launcher;
+ GSubprocess *subprocess;
+ GFile *parent_dir;
+ gchar *working_directory;
+ gchar **argv;
+ GError *error = NULL;
+
+ /* No output for the moment */
+ launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
+ G_SUBPROCESS_FLAGS_STDERR_SILENCE);
+
+ parent_dir = g_file_get_parent (build_job->priv->file);
+ working_directory = g_file_get_path (parent_dir);
+ g_object_unref (parent_dir);
+
+ g_subprocess_launcher_set_cwd (launcher, working_directory);
+ g_free (working_directory);
+
+ /* The error is already catched in display_command_line(). */
+ argv = get_command_argv (build_job, FALSE, NULL);
+
+ subprocess = g_subprocess_launcher_spawnv (launcher, (const gchar * const *) argv, &error);
+ g_strfreev (argv);
+ g_object_unref (launcher);
+
+ if (error != NULL)
+ {
+ display_error (build_job, "Failed to launch command:", error);
+ return;
+ }
+
+ g_subprocess_wait_async (subprocess,
+ g_task_get_cancellable (build_job->priv->task),
+ (GAsyncReadyCallback) subprocess_wait_cb,
+ build_job);
+}
+
+/**
+ * latexila_build_job_run_async:
+ * @build_job: a build job.
+ * @file: a file.
+ * @build_view: a build view.
+ * @cancellable: a #GCancellable object.
+ * @callback: the callback to call when the operation is finished.
+ * @user_data: the data to pass to the callback function.
+ *
+ * Runs asynchronously the build job on a file with the messages displayed in a
+ * build view. When the operation is finished, @callback will be called. You can
+ * then call latexila_build_job_run_finish().
+ */
+void
+latexila_build_job_run_async (LatexilaBuildJob *build_job,
+ GFile *file,
+ LatexilaBuildView *build_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_return_if_fail (LATEXILA_IS_BUILD_JOB (build_job));
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (LATEXILA_IS_BUILD_VIEW (build_view));
+ g_return_if_fail (build_job->priv->task == NULL);
+
+ build_job->priv->task = g_task_new (build_job, cancellable, callback, user_data);
+
+ g_clear_object (&build_job->priv->file);
+ build_job->priv->file = g_object_ref (file);
+
+ g_clear_object (&build_job->priv->build_view);
+ build_job->priv->build_view = g_object_ref (build_view);
+
+ free_build_messages (build_job->priv->build_messages);
+
+ if (!display_command_line (build_job))
+ {
+ return;
+ }
+
+ if (!g_task_return_error_if_cancelled (build_job->priv->task))
+ {
+ launch_subprocess (build_job);
+ }
+}
+
+/**
+ * latexila_build_job_run_finish:
+ * @build_job: a build job.
+ * @result: a #GAsyncResult.
+ *
+ * Finishes the operation started with latexila_build_job_run_async().
+ *
+ * Returns: %TRUE if the build job has run successfully.
+ */
+gboolean
+latexila_build_job_run_finish (LatexilaBuildJob *build_job,
+ GAsyncResult *result)
+{
+ GCancellable *cancellable;
+ gboolean succeed;
+
+ g_return_if_fail (g_task_is_valid (result, build_job));
+
+ cancellable = g_task_get_cancellable (G_TASK (result));
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ latexila_build_view_set_title_state (build_job->priv->build_view,
+ &build_job->priv->job_title,
+ LATEXILA_BUILD_STATE_ABORTED);
+ succeed = FALSE;
+ }
+ else
+ {
+ succeed = g_task_propagate_boolean (G_TASK (result), NULL);
+ }
+
+ g_clear_object (&build_job->priv->task);
+ return succeed;
+}
diff --git a/src/liblatexila/latexila-build-job.h b/src/liblatexila/latexila-build-job.h
index d09da3d..f4bef9b 100644
--- a/src/liblatexila/latexila-build-job.h
+++ b/src/liblatexila/latexila-build-job.h
@@ -20,7 +20,7 @@
#ifndef __LATEXILA_BUILD_JOB_H__
#define __LATEXILA_BUILD_JOB_H__
-#include <glib-object.h>
+#include <gio/gio.h>
#include "latexila-types.h"
#include "latexila-post-processor.h"
@@ -56,6 +56,16 @@ LatexilaBuildJob * latexila_build_job_clone (LatexilaBuild
gchar * latexila_build_job_to_xml (LatexilaBuildJob *build_job);
+void latexila_build_job_run_async (LatexilaBuildJob *build_job,
+ GFile *file,
+ LatexilaBuildView *build_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean latexila_build_job_run_finish (LatexilaBuildJob *build_job,
+ GAsyncResult *result);
+
G_END_DECLS
#endif /* __LATEXILA_BUILD_JOB_H__ */
diff --git a/src/liblatexila/latexila-build-tool.c b/src/liblatexila/latexila-build-tool.c
index 67b393a..f954e68 100644
--- a/src/liblatexila/latexila-build-tool.c
+++ b/src/liblatexila/latexila-build-tool.c
@@ -29,8 +29,11 @@
*/
#include "latexila-build-tool.h"
+#include <string.h>
+#include <glib/gi18n.h>
#include "latexila-build-job.h"
#include "latexila-build-view.h"
+#include "latexila-utils.h"
struct _LatexilaBuildToolPrivate
{
@@ -44,6 +47,17 @@ struct _LatexilaBuildToolPrivate
/* A list of LatexilaBuildJob's. */
GQueue *jobs;
+ /* Used for running the build tool. */
+ GTask *task;
+ GFile *file;
+ LatexilaBuildView *build_view;
+ GtkTreeIter main_title;
+ GList *current_job;
+
+ gchar **files_to_open_split;
+ gchar **current_file_to_open; /* Position in files_to_open_split */
+ GtkTreeIter open_file_job_title;
+
guint enabled : 1;
};
@@ -61,6 +75,10 @@ enum
G_DEFINE_TYPE_WITH_PRIVATE (LatexilaBuildTool, latexila_build_tool, G_TYPE_OBJECT)
+/* Prototypes */
+static void run_job (LatexilaBuildTool *build_tool);
+static void open_file (LatexilaBuildTool *build_tool);
+
static void
latexila_build_tool_get_property (GObject *object,
guint prop_id,
@@ -113,6 +131,9 @@ latexila_build_tool_set_property (GObject *object,
{
LatexilaBuildTool *build_tool = LATEXILA_BUILD_TOOL (object);
+ /* The build tool can not be modified when it is running. */
+ g_return_if_fail (build_tool->priv->task == NULL);
+
switch (prop_id)
{
case PROP_LABEL:
@@ -138,6 +159,13 @@ latexila_build_tool_set_property (GObject *object,
case PROP_FILES_TO_OPEN:
g_free (build_tool->priv->files_to_open);
build_tool->priv->files_to_open = g_value_dup_string (value);
+
+ g_strfreev (build_tool->priv->files_to_open_split);
+ build_tool->priv->files_to_open_split = NULL;
+ if (build_tool->priv->files_to_open != NULL)
+ {
+ build_tool->priv->files_to_open_split = g_strsplit (build_tool->priv->files_to_open, " ", -1);
+ }
break;
case PROP_ID:
@@ -165,6 +193,10 @@ latexila_build_tool_dispose (GObject *object)
build_tool->priv->jobs = NULL;
}
+ g_clear_object (&build_tool->priv->task);
+ g_clear_object (&build_tool->priv->file);
+ g_clear_object (&build_tool->priv->build_view);
+
G_OBJECT_CLASS (latexila_build_tool_parent_class)->dispose (object);
}
@@ -178,6 +210,7 @@ latexila_build_tool_finalize (GObject *object)
g_free (build_tool->priv->extensions);
g_free (build_tool->priv->icon);
g_free (build_tool->priv->files_to_open);
+ g_strfreev (build_tool->priv->files_to_open_split);
G_OBJECT_CLASS (latexila_build_tool_parent_class)->finalize (object);
}
@@ -362,6 +395,9 @@ latexila_build_tool_add_job (LatexilaBuildTool *build_tool,
g_return_if_fail (LATEXILA_IS_BUILD_TOOL (build_tool));
g_return_if_fail (LATEXILA_IS_BUILD_JOB (build_job));
+ /* The build tool can not be modified when it is running. */
+ g_return_if_fail (build_tool->priv->task == NULL);
+
g_queue_push_tail (build_tool->priv->jobs, build_job);
g_object_ref (build_job);
}
@@ -431,30 +467,332 @@ latexila_build_tool_to_xml (LatexilaBuildTool *tool)
return g_string_free (contents, FALSE);
}
+static void
+failed (LatexilaBuildTool *build_tool)
+{
+ GCancellable *cancellable;
+ LatexilaBuildState state;
+
+ cancellable = g_task_get_cancellable (build_tool->priv->task);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ state = LATEXILA_BUILD_STATE_ABORTED;
+ }
+ else
+ {
+ state = LATEXILA_BUILD_STATE_FAILED;
+ }
+
+ latexila_build_view_set_title_state (build_tool->priv->build_view,
+ &build_tool->priv->main_title,
+ state);
+
+ g_task_return_boolean (build_tool->priv->task, FALSE);
+}
+
+static void
+query_exists_cb (GFile *file,
+ GAsyncResult *result,
+ LatexilaBuildTool *build_tool)
+{
+ GFileInfo *info;
+ GCancellable *cancellable;
+ gboolean file_exists;
+ gchar *uri = NULL;
+ GError *error = NULL;
+
+ info = g_file_query_info_finish (file, result, NULL);
+
+ cancellable = g_task_get_cancellable (build_tool->priv->task);
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ latexila_build_view_set_title_state (build_tool->priv->build_view,
+ &build_tool->priv->open_file_job_title,
+ LATEXILA_BUILD_STATE_ABORTED);
+ failed (build_tool);
+ goto out;
+ }
+
+ file_exists = info != NULL;
+ g_clear_object (&info);
+
+ uri = g_file_get_uri (file);
+
+ if (!file_exists)
+ {
+ LatexilaBuildMsg *msg;
+
+ latexila_build_view_set_title_state (build_tool->priv->build_view,
+ &build_tool->priv->open_file_job_title,
+ LATEXILA_BUILD_STATE_FAILED);
+
+ msg = latexila_build_msg_new ();
+ msg->text = g_strdup_printf (_("The file '%s' doesn't exist."), uri);
+ msg->type = LATEXILA_BUILD_MSG_TYPE_ERROR;
+
+ latexila_build_view_append_single_message (build_tool->priv->build_view,
+ &build_tool->priv->open_file_job_title,
+ msg);
+
+ latexila_build_msg_free (msg);
+ failed (build_tool);
+ goto out;
+ }
+
+ /* Show URI */
+
+ gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (build_tool->priv->build_view)),
+ uri,
+ GDK_CURRENT_TIME,
+ &error);
+
+ if (error != NULL)
+ {
+ LatexilaBuildMsg *msg;
+
+ latexila_build_view_set_title_state (build_tool->priv->build_view,
+ &build_tool->priv->open_file_job_title,
+ LATEXILA_BUILD_STATE_FAILED);
+
+ msg = latexila_build_msg_new ();
+ msg->text = g_strdup_printf (_("Failed to open '%s':"), uri);
+ msg->type = LATEXILA_BUILD_MSG_TYPE_ERROR;
+
+ latexila_build_view_append_single_message (build_tool->priv->build_view,
+ &build_tool->priv->open_file_job_title,
+ msg);
+
+ g_free (msg->text);
+ msg->text = g_strdup (error->message);
+ msg->type = LATEXILA_BUILD_MSG_TYPE_INFO;
+
+ latexila_build_view_append_single_message (build_tool->priv->build_view,
+ &build_tool->priv->open_file_job_title,
+ msg);
+
+ latexila_build_msg_free (msg);
+ g_error_free (error);
+
+ failed (build_tool);
+ goto out;
+ }
+
+ latexila_build_view_set_title_state (build_tool->priv->build_view,
+ &build_tool->priv->open_file_job_title,
+ LATEXILA_BUILD_STATE_SUCCEEDED);
+
+ build_tool->priv->current_file_to_open++;
+ open_file (build_tool);
+
+out:
+ g_object_unref (file);
+ g_free (uri);
+}
+
+static void
+open_file (LatexilaBuildTool *build_tool)
+{
+ const gchar *file_to_open;
+ gchar *filename;
+ gchar *shortname;
+ gchar *uri;
+ gchar *basename;
+ gchar *message;
+ GFile *file;
+
+ while (TRUE)
+ {
+ if (build_tool->priv->current_file_to_open == NULL ||
+ build_tool->priv->current_file_to_open[0] == NULL)
+ {
+ /* Finished */
+ latexila_build_view_set_title_state (build_tool->priv->build_view,
+ &build_tool->priv->main_title,
+ LATEXILA_BUILD_STATE_SUCCEEDED);
+
+ g_task_return_boolean (build_tool->priv->task, TRUE);
+ return;
+ }
+
+ /* Check if the file to open is an empty string. It happens if there are
+ * two contiguous spaces in priv->files_to_open for example.
+ */
+ if (build_tool->priv->current_file_to_open[0][0] == '\0')
+ {
+ build_tool->priv->current_file_to_open++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ file_to_open = build_tool->priv->current_file_to_open[0];
+
+ /* Replace placeholders */
+
+ filename = g_file_get_uri (build_tool->priv->file);
+ shortname = latexila_utils_get_shortname (filename);
+
+ if (strstr (file_to_open, "$filename") != NULL)
+ {
+ uri = latexila_utils_str_replace (file_to_open, "$filename", filename);
+ }
+ else if (strstr (file_to_open, "$shortname") != NULL)
+ {
+ uri = latexila_utils_str_replace (file_to_open, "$shortname", shortname);
+ }
+ else
+ {
+ uri = g_strdup_printf ("file://%s", file_to_open);
+ }
+
+ /* Add job title in the build view */
+
+ basename = g_path_get_basename (uri);
+ message = g_strdup_printf (_("Open %s"), basename);
+
+ build_tool->priv->open_file_job_title = latexila_build_view_add_job_title (build_tool->priv->build_view,
+ message,
+ LATEXILA_BUILD_STATE_RUNNING);
+
+ /* Check if the file exists */
+
+ file = g_file_new_for_uri (uri);
+
+ g_file_query_info_async (file,
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ g_task_get_cancellable (build_tool->priv->task),
+ (GAsyncReadyCallback) query_exists_cb,
+ build_tool);
+
+ g_free (filename);
+ g_free (shortname);
+ g_free (uri);
+ g_free (basename);
+ g_free (message);
+}
+
+static void
+open_files (LatexilaBuildTool *build_tool)
+{
+ build_tool->priv->current_file_to_open = build_tool->priv->files_to_open_split;
+ open_file (build_tool);
+}
+
+static void
+run_job_cb (LatexilaBuildJob *build_job,
+ GAsyncResult *result,
+ LatexilaBuildTool *build_tool)
+{
+ gboolean success;
+
+ success = latexila_build_job_run_finish (build_job, result);
+
+ if (success)
+ {
+ build_tool->priv->current_job = build_tool->priv->current_job->next;
+ run_job (build_tool);
+ }
+ else
+ {
+ failed (build_tool);
+ }
+}
+
+static void
+run_job (LatexilaBuildTool *build_tool)
+{
+ LatexilaBuildJob *build_job;
+
+ if (g_task_return_error_if_cancelled (build_tool->priv->task))
+ {
+ return;
+ }
+
+ if (build_tool->priv->current_job == NULL)
+ {
+ open_files (build_tool);
+ return;
+ }
+
+ build_job = build_tool->priv->current_job->data;
+
+ latexila_build_job_run_async (build_job,
+ build_tool->priv->file,
+ build_tool->priv->build_view,
+ g_task_get_cancellable (build_tool->priv->task),
+ (GAsyncReadyCallback) run_job_cb,
+ build_tool);
+}
+
/**
- * latexila_build_tool_run:
+ * latexila_build_tool_run_async:
* @build_tool: a build tool.
* @file: a file.
* @build_view: a build view.
+ * @cancellable: a #GCancellable object.
+ * @callback: the callback to call when the operation is finished.
+ * @user_data: the data to pass to the callback function.
*
* Run a build tool on a file with the messages displayed in a build view.
*/
void
-latexila_build_tool_run (LatexilaBuildTool *build_tool,
- GFile *file,
- LatexilaBuildView *build_view)
+latexila_build_tool_run_async (LatexilaBuildTool *build_tool,
+ GFile *file,
+ LatexilaBuildView *build_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
g_return_if_fail (LATEXILA_IS_BUILD_TOOL (build_tool));
g_return_if_fail (G_IS_FILE (file));
g_return_if_fail (LATEXILA_IS_BUILD_VIEW (build_view));
+ g_return_if_fail (build_tool->priv->task == NULL);
+
+ build_tool->priv->task = g_task_new (build_tool, cancellable, callback, user_data);
+
+ g_clear_object (&build_tool->priv->file);
+ build_tool->priv->file = g_object_ref (file);
+
+ g_clear_object (&build_tool->priv->build_view);
+ build_tool->priv->build_view = g_object_ref (build_view);
latexila_build_view_clear (build_view);
- latexila_build_view_add_main_title (build_view,
- build_tool->priv->label,
- LATEXILA_BUILD_STATE_RUNNING);
+ build_tool->priv->main_title = latexila_build_view_add_main_title (build_view,
+ build_tool->priv->label,
+ LATEXILA_BUILD_STATE_RUNNING);
+
+ build_tool->priv->current_job = build_tool->priv->jobs->head;
+ run_job (build_tool);
+}
+
+/**
+ * latexila_build_tool_run_finish:
+ * @build_tool: a build tool.
+ * @result: a #GAsyncResult.
+ *
+ * Finishes the operation started with latexila_build_tool_run_async().
+ */
+void
+latexila_build_tool_run_finish (LatexilaBuildTool *build_tool,
+ GAsyncResult *result)
+{
+ GCancellable *cancellable;
+
+ g_return_if_fail (g_task_is_valid (result, build_tool));
+
+ cancellable = g_task_get_cancellable (G_TASK (result));
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ latexila_build_view_set_title_state (build_tool->priv->build_view,
+ &build_tool->priv->main_title,
+ LATEXILA_BUILD_STATE_ABORTED);
+ }
- latexila_build_view_add_job_title (build_view,
- "job",
- LATEXILA_BUILD_STATE_SUCCEEDED);
+ g_task_propagate_boolean (G_TASK (result), NULL);
+ g_clear_object (&build_tool->priv->task);
}
diff --git a/src/liblatexila/latexila-build-tool.h b/src/liblatexila/latexila-build-tool.h
index 77c6443..32c5dc6 100644
--- a/src/liblatexila/latexila-build-tool.h
+++ b/src/liblatexila/latexila-build-tool.h
@@ -62,9 +62,15 @@ GList * latexila_build_tool_get_jobs (LatexilaBui
gchar * latexila_build_tool_to_xml (LatexilaBuildTool *tool);
-void latexila_build_tool_run (LatexilaBuildTool *build_tool,
- GFile *file,
- LatexilaBuildView *build_view);
+void latexila_build_tool_run_async (LatexilaBuildTool *build_tool,
+ GFile *file,
+ LatexilaBuildView *build_view,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+void latexila_build_tool_run_finish (LatexilaBuildTool *build_tool,
+ GAsyncResult *result);
G_END_DECLS
diff --git a/src/liblatexila/latexila-build-view.c b/src/liblatexila/latexila-build-view.c
index 879a291..eb485c5 100644
--- a/src/liblatexila/latexila-build-view.c
+++ b/src/liblatexila/latexila-build-view.c
@@ -565,6 +565,9 @@ latexila_build_view_clear (LatexilaBuildView *build_view)
gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
gtk_tree_view_columns_autosize (GTK_TREE_VIEW (build_view));
+
+ build_view->priv->has_details = FALSE;
+ g_object_notify (G_OBJECT (build_view), "has-details");
}
static GtkTreeIter
@@ -711,7 +714,11 @@ latexila_build_view_append_single_message (LatexilaBuildView *build_view,
COLUMN_LINE_STR, line_str,
-1);
- g_object_unref (file);
+ if (file != NULL)
+ {
+ g_object_unref (file);
+ }
+
g_free (path);
g_free (basename);
g_free (line_str);
diff --git a/src/liblatexila/latexila-utils.c b/src/liblatexila/latexila-utils.c
index 3f6d93d..8c06b8a 100644
--- a/src/liblatexila/latexila-utils.c
+++ b/src/liblatexila/latexila-utils.c
@@ -201,3 +201,39 @@ latexila_utils_register_icons (void)
g_strfreev (icon_files);
}
+
+/**
+ * latexila_utils_str_replace:
+ * @string: a string
+ * @search: the search string
+ * @replacement: the replacement string
+ *
+ * Replaces all occurences of @search by @replacement.
+ *
+ * Returns: A newly allocated string with the replacements. Free with g_free().
+ */
+gchar *
+latexila_utils_str_replace (const gchar *string,
+ const gchar *search,
+ const gchar *replacement)
+{
+ gchar **chunks;
+ gchar *ret;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (search != NULL, NULL);
+ g_return_val_if_fail (replacement != NULL, NULL);
+
+ chunks = g_strsplit (string, search, -1);
+ if (chunks != NULL && chunks[0] != NULL)
+ {
+ ret = g_strjoinv (replacement, chunks);
+ }
+ else
+ {
+ ret = g_strdup (string);
+ }
+
+ g_strfreev (chunks);
+ return ret;
+}
diff --git a/src/liblatexila/latexila-utils.h b/src/liblatexila/latexila-utils.h
index cf88567..852a6f0 100644
--- a/src/liblatexila/latexila-utils.h
+++ b/src/liblatexila/latexila-utils.h
@@ -30,6 +30,10 @@ gchar * latexila_utils_replace_home_dir_with_tilde (const gchar *fi
void latexila_utils_register_icons (void);
+gchar * latexila_utils_str_replace (const gchar *string,
+ const gchar *search,
+ const gchar *replacement);
+
G_END_DECLS
#endif /* __LATEXILA_UTILS_H__ */
diff --git a/src/main_window_build_tools.vala b/src/main_window_build_tools.vala
index 1edb402..7468ed0 100644
--- a/src/main_window_build_tools.vala
+++ b/src/main_window_build_tools.vala
@@ -57,6 +57,7 @@ public class MainWindowBuildTools
private UIManager _ui_manager;
private Latexila.BuildView _build_view;
private BottomPanel _bottom_panel;
+ private Cancellable? _cancellable;
private Gtk.ActionGroup _static_action_group;
private Gtk.ActionGroup _dynamic_action_group;
@@ -355,13 +356,13 @@ public class MainWindowBuildTools
stop_exec.sensitive = true;
File main_file = active_doc.get_main_file ();
- tool.run (main_file, _build_view);
- /* TODO port this code. */
- /*
- _build_tool_runner = new BuildToolRunner (tool, main_file, _build_view);
- _build_tool_runner.finished.connect (() => stop_exec.sensitive = false);
- _build_tool_runner.run ();
- */
+ _cancellable = new Cancellable ();
+ tool.run_async.begin (main_file, _build_view, _cancellable, (obj, result) =>
+ {
+ tool.run_async.end (result);
+ _cancellable = null;
+ stop_exec.sensitive = false;
+ });
}
private void connect_toggle_actions ()
@@ -408,11 +409,8 @@ public class MainWindowBuildTools
public void on_stop_execution ()
{
- /* TODO port this code. */
- /*
- return_if_fail (_build_tool_runner != null);
- _build_tool_runner.abort ();
- */
+ return_if_fail (_cancellable != null);
+ _cancellable.cancel ();
}
public void on_clean ()
diff --git a/tests/test-utils.c b/tests/test-utils.c
index 9072428..4bfff00 100644
--- a/tests/test-utils.c
+++ b/tests/test-utils.c
@@ -63,6 +63,28 @@ test_replace_home_dir_with_tilde (void)
g_free (after);
}
+static void
+test_str_replace (void)
+{
+ gchar *result;
+
+ result = latexila_utils_str_replace ("$filename", "$filename", "blah");
+ g_assert_cmpstr (result, ==, "blah");
+ g_free (result);
+
+ result = latexila_utils_str_replace ("$shortname.pdf", "$shortname", "blah");
+ g_assert_cmpstr (result, ==, "blah.pdf");
+ g_free (result);
+
+ result = latexila_utils_str_replace ("abcdabcd", "ab", "r");
+ g_assert_cmpstr (result, ==, "rcdrcd");
+ g_free (result);
+
+ result = latexila_utils_str_replace ("abcd", "ef", "r");
+ g_assert_cmpstr (result, ==, "abcd");
+ g_free (result);
+}
+
gint
main (gint argc,
gchar **argv)
@@ -71,6 +93,7 @@ main (gint argc,
g_test_add_func ("/utils/get-shortname", test_get_shortname);
g_test_add_func ("/utils/replace-home-dir-with-tilde", test_replace_home_dir_with_tilde);
+ g_test_add_func ("/utils/str-replace", test_str_replace);
return g_test_run ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]