Blob Blame History Raw
From 27a2c75409c7abae68c4ad3af99d8e90927af803 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Mon, 28 Apr 2014 13:57:05 +0200
Subject: [LIBREPORT PATCH 03/10] Worklflow: order workflows according to their
 priority

Higher number -> higher priority -> more visible place in UI

Introduce 'priority' element in XML workflow definition:
    - child of 'workflow' element
    - the type is signed integer
    - optional value, if not present, 0 is used

Related to #259

Signed-off-by: Jakub Filak <jfilak@redhat.com>

mmilata: fix DTD in manual page
---
 doc/report-gtk.txt            |  8 +++++++-
 src/cli/cli-report.c          | 32 ++++++++++++++++++--------------
 src/gui-wizard-gtk/wizard.c   | 10 ++++++----
 src/include/workflow.h        | 10 ++++++++++
 src/lib/workflow.c            | 21 +++++++++++++++++++++
 src/lib/workflow_xml_parser.c | 20 +++++++++++++++++++-
 6 files changed, 81 insertions(+), 20 deletions(-)

diff --git a/doc/report-gtk.txt b/doc/report-gtk.txt
index e7611de..f39c77c 100644
--- a/doc/report-gtk.txt
+++ b/doc/report-gtk.txt
@@ -64,11 +64,12 @@ These configuration files are placed in /usr/share/libreport/workflows.
 Each file has XML formatting with the following DTD:
 
 ------------
-<!ELEMENT workflow    (name+,description+,events*)>
+<!ELEMENT workflow    (name+,description+,priority?,events*)>
 <!ELEMENT name        (#PCDATA)>
 <!ATTLIST name         xml:lang CDATA #IMPLIED>
 <!ELEMENT description (#PCDATA)>
 <!ATTLIST description  xml:lang CDATA #IMPLIED>
+<!ELEMENT priority =  (#PCDATA)>
 <!ELEMENT events =    (event)+>
 <!ELEMENT event =     (#PCDATA)>
 ------------
@@ -79,6 +80,10 @@ name::
 description::
    User visible description
 
+priority::
+   Priority of the workflow. Higher number means a more visible place in UI.
+   If not provided, 0 is used. The value is signed integer.
+
 events::
    List of executed events
 
@@ -98,6 +103,7 @@ Simple reporting work flow
   <name xml:lang="cs">Příklad</name>
   <description xml:lang="en">Example description</description>
   <description xml:lang="cs">Příklad popisu</description>
+  <priority>10</priority>
   <evetns>
      <event>analyze_example</event>
      <event>collect_example</event>
diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c
index 68baa8b..9cc7613 100644
--- a/src/cli/cli-report.c
+++ b/src/cli/cli-report.c
@@ -824,32 +824,36 @@ int run_event_chain(const char *dump_dir_name, GList *chain, int interactive)
 
 static workflow_t *select_workflow(GHashTable *workflows)
 {
-    GHashTableIter iter;
-    gpointer key = NULL;
-    workflow_t *value = NULL;
+    GList *wf_list = g_hash_table_get_values(workflows);
 
-    g_hash_table_iter_init(&iter, workflows);
-
-    if (!g_hash_table_iter_next(&iter, &key, (gpointer *)&value))
+    if (wf_list == NULL)
     {
         error_msg("No workflow suitable for this problem was found!");
         return NULL;
     }
 
-    if (g_hash_table_size(workflows) == 1)
+    const guint wf_cnt = g_list_length(wf_list);
+    if (wf_cnt == 1)
     {
-        log_notice("autoselected workflow: '%s'", (char *)key);
-        return value;
+        workflow_t *wf_selected = (workflow_t *)wf_list->data;
+        log_notice("autoselected workflow: '%s'", (char *)wf_get_name(wf_selected));
+        g_list_free(wf_list);
+        return wf_selected;
     }
 
-    workflow_t *help_wf_array[g_hash_table_size(workflows)];
+    wf_list = g_list_sort(wf_list, (GCompareFunc)wf_priority_compare);
+
+    workflow_t *help_wf_array[wf_cnt];
     unsigned count = 0;
-    do
+
+    for(GList *wf_iter = wf_list; wf_iter; wf_iter = g_list_next(wf_iter))
     {
-        help_wf_array[count] = value;
-        printf("%d %s\n  %s\n\n", ++count, wf_get_screen_name(value), wf_get_description(value));
+        workflow_t *wf = (workflow_t *)wf_iter->data;
+        help_wf_array[count] = wf;
+        printf("%d %s\n  %s\n\n", ++count, wf_get_screen_name(wf), wf_get_description(wf));
     }
-    while (g_hash_table_iter_next(&iter, &key, (gpointer *)&value));
+
+    g_list_free(wf_list);
 
     const unsigned picked = choose_number_from_range(1, count, _("Select a workflow to run: "));
     return help_wf_array[picked - 1];
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index 82bdf3e..e6f6ee7 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -2736,10 +2736,12 @@ static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback f
                         list_possible_events_glist(g_dump_dir_name, "workflow"),
                         WORKFLOWS_DIR);
 
-    GList *keys = g_hash_table_get_keys(workflow_table);
-    while(keys)
+    GList *wf_list = g_hash_table_get_values(workflow_table);
+    wf_list = g_list_sort(wf_list, (GCompareFunc)wf_priority_compare);
+
+    for (GList *wf_iter = wf_list; wf_iter; wf_iter = g_list_next(wf_iter))
     {
-        workflow_t *w = g_hash_table_lookup(workflow_table, keys->data);
+        workflow_t *w = (workflow_t *)wf_iter->data;
         char *btn_label = xasprintf("<b>%s</b>\n%s", wf_get_screen_name(w), wf_get_description(w));
         GtkWidget *button = gtk_button_new_with_label(btn_label);
         GList *children = gtk_container_get_children(GTK_CONTAINER(button));
@@ -2756,9 +2758,9 @@ static void add_workflow_buttons(GtkBox *box, GHashTable *workflows, GCallback f
         free(btn_label);
         g_signal_connect(button, "clicked", func, w);
         gtk_box_pack_start(box, button, true, false, 2);
-        keys = g_list_next(keys);
     }
 
+    g_list_free(wf_list);
 }
 
 static char *setup_next_processed_event(GList **events_list)
diff --git a/src/include/workflow.h b/src/include/workflow.h
index 66bbdaf..d79708e 100644
--- a/src/include/workflow.h
+++ b/src/include/workflow.h
@@ -39,11 +39,21 @@ GList *wf_get_event_names(workflow_t *w);
 const char *wf_get_screen_name(workflow_t *w);
 const char *wf_get_description(workflow_t *w);
 const char *wf_get_long_desc(workflow_t *w);
+int wf_get_priority(workflow_t *w);
 
 void wf_set_screen_name(workflow_t *w, const char* screen_name);
 void wf_set_description(workflow_t *w, const char* description);
 void wf_set_long_desc(workflow_t *w, const char* long_desc);
 void wf_add_event(workflow_t *w, event_config_t *ec);
+void wf_set_priority(workflow_t *w, int priority);
+
+/*
+ * Returns a negative integer if the first value comes before the second, 0 if
+ * they are equal, or a positive integer if the first value comes after the
+ * second.
+ */
+int wf_priority_compare(const workflow_t *first, const workflow_t *second);
+
 GHashTable *load_workflow_config_data_from_list(GList *wf_names, const char *path);
 
 #endif
diff --git a/src/lib/workflow.c b/src/lib/workflow.c
index 52ad924..c6eedf4 100644
--- a/src/lib/workflow.c
+++ b/src/lib/workflow.c
@@ -24,6 +24,7 @@
 struct workflow
 {
     config_item_info_t *info;
+    int priority; // direct correlation: higher number -> higher priority
 
     GList *events; //list of event_option_t
 };
@@ -193,6 +194,11 @@ const char *wf_get_long_desc(workflow_t *w)
     return ci_get_long_desc(workflow_get_config_info(w));
 }
 
+int wf_get_priority(workflow_t *w)
+{
+    return w->priority;
+}
+
 void wf_set_screen_name(workflow_t *w, const char* screen_name)
 {
     ci_set_screen_name(workflow_get_config_info(w), screen_name);
@@ -213,3 +219,18 @@ void wf_add_event(workflow_t *w, event_config_t *ec)
     w->events = g_list_append(w->events, ec);
     log_info("added to ev list: '%s'", ec_get_screen_name(ec));
 }
+
+void wf_set_priority(workflow_t *w, int priority)
+{
+    w->priority = priority;
+}
+
+/*
+ * Returns a negative integer if the first value comes before the second, 0 if
+ * they are equal, or a positive integer if the first value comes after the
+ * second.
+ */
+int wf_priority_compare(const workflow_t *first, const workflow_t *second)
+{
+    return second->priority - first->priority;
+}
diff --git a/src/lib/workflow_xml_parser.c b/src/lib/workflow_xml_parser.c
index 0efc733..f216c18 100644
--- a/src/lib/workflow_xml_parser.c
+++ b/src/lib/workflow_xml_parser.c
@@ -26,6 +26,7 @@
 #define EVENT_ELEMENT           "event"
 #define DESCRIPTION_ELEMENT     "description"
 #define NAME_ELEMENT            "name"
+#define PRIORITY_ELEMENT        "priority"
 
 static void start_element(GMarkupParseContext *context,
                   const gchar *element_name,
@@ -134,9 +135,26 @@ static void text(GMarkupParseContext *context,
                 }
             }
         }
-
     }
 
+    else if(strcmp(inner_element, PRIORITY_ELEMENT) == 0)
+    {
+        log_debug("workflow priority:'%s'", text);
+
+        char *end = NULL;
+        long long val = strtoll(text, &end, 10);
+
+        if (text == end || end[0] != '\0'
+            || (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN))
+            || (val > INT_MAX || val < INT_MIN)
+            || (errno != 0 && val == 0))
+        {
+            error_msg("Workflow's priority is not a number in range <%d,%d>", INT_MIN, INT_MAX);
+            return;
+        }
+
+        wf_set_priority(workflow, (int)val);
+    }
 }
 
   // Called for strings that should be re-saved verbatim in this same
-- 
1.8.3.1