[glade/composite-templates-new: 6/10] Implemented autosave and backups



commit b669bff33127341378dbab176ab87614c71f7ef0
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Sat Apr 6 17:32:52 2013 +0900

    Implemented autosave and backups
    
    Whenever the user saves, the last version of the file is backed up.
    
    Whenever the project is modified and idle for a configurable amount of
    seconds, the project is automatically saved.
    
    At load time, if the automatically saved file is newer than the proposed
    Glade file, Glade will popup a dialog and let the user choose to load
    the autosaved version instead

 src/glade-preferences.c |   66 ++++++++++++
 src/glade-preferences.h |    5 +
 src/glade-window.c      |  148 ++++++++++++++++++++-------
 src/glade.glade         |  259 +++++++++++++++++++++++++++++++----------------
 4 files changed, 354 insertions(+), 124 deletions(-)
---
diff --git a/src/glade-preferences.c b/src/glade-preferences.c
index 6e25b5f..35865f1 100644
--- a/src/glade-preferences.c
+++ b/src/glade-preferences.c
@@ -26,11 +26,20 @@ struct _GladePreferences
 {
   GObject *toplevel;
   GtkComboBoxText *catalog_path_combo;
+
+  GtkWidget *create_backups_toggle;
+  GtkWidget *autosave_toggle;
+  GtkWidget *autosave_spin;
 };
 
 #define CONFIG_GROUP "Preferences"
 #define CONFIG_KEY_CATALOG_PATHS "catalog-paths"
 
+#define CONFIG_GROUP_LOAD_SAVE      "Load and Save"
+#define CONFIG_KEY_BACKUP           "backup"
+#define CONFIG_KEY_AUTOSAVE         "autosave"
+#define CONFIG_KEY_AUTOSAVE_SECONDS "autosave-seconds"
+
 static void
 combo_box_text_init_cell (GtkCellLayout *cell)
 {
@@ -49,6 +58,14 @@ combo_box_text_init_cell (GtkCellLayout *cell)
   g_list_free (cels);
 }
 
+static void
+autosave_toggled (GtkToggleButton  *button,
+                 GladePreferences *prefs)
+{
+  gtk_widget_set_sensitive (prefs->autosave_spin,
+                           gtk_toggle_button_get_active (button));
+}
+
 GladePreferences *
 glade_preferences_new (GtkBuilder *builder)
 {
@@ -57,6 +74,13 @@ glade_preferences_new (GtkBuilder *builder)
   prefs->toplevel = gtk_builder_get_object (builder, "preferences_dialog");
   prefs->catalog_path_combo = GTK_COMBO_BOX_TEXT (gtk_builder_get_object (builder, 
"catalog_path_comboboxtext"));
   combo_box_text_init_cell (GTK_CELL_LAYOUT (prefs->catalog_path_combo));
+
+  prefs->create_backups_toggle = GTK_WIDGET (gtk_builder_get_object (builder, "create_backups_toggle"));
+  prefs->autosave_toggle = GTK_WIDGET (gtk_builder_get_object (builder, "autosave_toggle"));
+  prefs->autosave_spin = GTK_WIDGET (gtk_builder_get_object (builder, "autosave_spin"));
+
+  g_signal_connect (G_OBJECT (prefs->autosave_toggle), "toggled",
+                   G_CALLBACK (autosave_toggled), prefs);
   
   return prefs;
 }
@@ -93,6 +117,13 @@ glade_preferences_config_save (GladePreferences *prefs, GKeyFile *config)
   
   g_key_file_set_string (config, CONFIG_GROUP, CONFIG_KEY_CATALOG_PATHS, string->str);
 
+  g_key_file_set_boolean (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_BACKUP,
+                         glade_preferences_backup (prefs));
+  g_key_file_set_boolean (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_AUTOSAVE,
+                         glade_preferences_autosave (prefs));
+  g_key_file_set_integer (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_AUTOSAVE_SECONDS,
+                         glade_preferences_autosave_seconds (prefs));
+
   g_string_free (string, TRUE);
 }
 
@@ -100,6 +131,9 @@ void
 glade_preferences_config_load (GladePreferences *prefs, GKeyFile *config)
 {
   gchar *string;
+  gboolean backups = TRUE;
+  gboolean autosave = TRUE;
+  gint autosave_seconds = 30;
   
   string = g_key_file_get_string (config, CONFIG_GROUP, CONFIG_KEY_CATALOG_PATHS, NULL);
 
@@ -124,9 +158,41 @@ glade_preferences_config_load (GladePreferences *prefs, GKeyFile *config)
       g_strfreev (paths);
     }
 
+  if (g_key_file_has_key (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_BACKUP, NULL))
+    backups = g_key_file_get_boolean (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_BACKUP, NULL);
+
+  if (g_key_file_has_key (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_AUTOSAVE, NULL))
+    autosave = g_key_file_get_boolean (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_AUTOSAVE, NULL);
+
+  if (g_key_file_has_key (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_AUTOSAVE_SECONDS, NULL))
+    autosave_seconds = g_key_file_get_integer (config, CONFIG_GROUP_LOAD_SAVE, CONFIG_KEY_AUTOSAVE_SECONDS, 
NULL);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->create_backups_toggle), backups);
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prefs->autosave_toggle), autosave);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (prefs->autosave_spin), autosave_seconds);
+  gtk_widget_set_sensitive (prefs->autosave_spin, autosave);
+
   g_free (string);
 }
 
+gboolean
+glade_preferences_backup (GladePreferences *prefs)
+{
+  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prefs->create_backups_toggle));
+}
+
+gboolean
+glade_preferences_autosave (GladePreferences *prefs)
+{
+  return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prefs->autosave_toggle));
+}
+
+gint
+glade_preferences_autosave_seconds (GladePreferences *prefs)
+{
+  return (gint)gtk_spin_button_get_value (GTK_SPIN_BUTTON (prefs->autosave_spin));
+}
+
 /* Callbacks */
 
 static gboolean 
diff --git a/src/glade-preferences.h b/src/glade-preferences.h
index 7abc0ba..cb47b5b 100644
--- a/src/glade-preferences.h
+++ b/src/glade-preferences.h
@@ -34,6 +34,10 @@ void glade_preferences_config_save (GladePreferences *prefs,
 void glade_preferences_config_load (GladePreferences *prefs,
                                     GKeyFile *config);
 
+gboolean glade_preferences_backup   (GladePreferences *prefs);
+gboolean glade_preferences_autosave (GladePreferences *prefs);
+gint     glade_preferences_autosave_seconds (GladePreferences *prefs);
+
 /* Callbacks */
 
 void on_preferences_filechooserdialog_response (GtkDialog *dialog,
@@ -42,4 +46,5 @@ void on_preferences_filechooserdialog_response (GtkDialog *dialog,
 void on_catalog_path_remove_button_clicked     (GtkButton *button,
                                                 GtkComboBoxText *combo);
 
+
 #endif /* __GLADE_PREFERENCES_H__ */
diff --git a/src/glade-window.c b/src/glade-window.c
index b1d3360..280c61a 100644
--- a/src/glade-window.c
+++ b/src/glade-window.c
@@ -71,6 +71,11 @@
 #define CONFIG_KEY_SHOW_STATUS      "show-statusbar"
 #define CONFIG_KEY_EDITOR_HEADER    "show-editor-header"
 
+#define CONFIG_GROUP_LOAD_SAVE      "Load and Save"
+#define CONFIG_KEY_BACKUP           "backup"
+#define CONFIG_KEY_AUTOSAVE         "autosave"
+#define CONFIG_KEY_AUTOSAVE_SECONDS "autosave-seconds"
+
 #define GLADE_WINDOW_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object),  \
                                          GLADE_TYPE_WINDOW,                      \
                                          GladeWindowPrivate))
@@ -669,15 +674,76 @@ refresh_undo_redo (GladeWindow *window, GladeProject *project)
 }
 
 static void
+cancel_autosave (gpointer data)
+{
+  guint autosave_id = GPOINTER_TO_UINT (data);
+
+  g_source_remove (autosave_id);
+}
+
+static gboolean
+autosave_project (gpointer data)
+{
+  GladeProject *project = (GladeProject *)data;
+  GladeWindow *window = GLADE_WINDOW (glade_app_get_window ());
+  gchar *display_name;
+
+  display_name = glade_project_get_name (project);
+
+  if (glade_project_autosave (project, NULL))
+    glade_util_flash_message (window->priv->statusbar,
+                             window->priv->statusbar_actions_context_id,
+                             _("Autosaving '%s'"), display_name);
+  else
+    /* This is problematic, should we be more intrusive and popup a dialog ? */
+    glade_util_flash_message (window->priv->statusbar,
+                             window->priv->statusbar_actions_context_id,
+                             _("Error autosaving '%s'"), display_name);
+
+  g_free (display_name);
+
+  /* This will remove the source id */
+  g_object_set_data (G_OBJECT (project), "glade-autosave-id", NULL);
+  return FALSE;
+}
+
+static void
+project_queue_autosave (GladeWindow  *window,
+                       GladeProject *project)
+{
+  if (glade_project_get_path (project) != NULL &&
+      glade_project_get_modified (project) &&
+      glade_preferences_autosave (window->priv->preferences))
+    {
+      guint autosave_id =
+       g_timeout_add_seconds (glade_preferences_autosave_seconds (window->priv->preferences),
+                              autosave_project, project);
+
+      g_object_set_data_full (G_OBJECT (project), "glade-autosave-id",
+                             GUINT_TO_POINTER (autosave_id), cancel_autosave);
+    }
+  else
+      g_object_set_data (G_OBJECT (project), "glade-autosave-id", NULL);
+}
+
+static void
+project_cancel_autosave (GladeProject *project)
+{
+  g_object_set_data (G_OBJECT (project), "glade-autosave-id", NULL);
+}
+
+static void
 project_changed_cb (GladeProject *project, 
                     GladeCommand *command,
                     gboolean      execute,
                     GladeWindow  *window)
 {
   GladeProject *active_project = get_active_project (window);
-  
+
   if (project == active_project)
     refresh_undo_redo (window, project);
+
+  project_queue_autosave (window, project);
 }
 
 static void
@@ -1079,11 +1145,48 @@ check_loading_project_for_save (GladeProject *project)
   return FALSE;
 }
 
+static gboolean
+do_save (GladeWindow *window, GladeProject *project, const gchar *path)
+{
+  GError *error = NULL;
+  gchar *display_path = g_strdup (path);
+
+  if (glade_preferences_backup (window->priv->preferences) &&
+      !glade_project_backup (project, path, NULL))
+    {
+      if (!glade_util_ui_message (GTK_WIDGET (window),
+                                 GLADE_UI_ARE_YOU_SURE, NULL,
+                                 _("Failed to backup existing file, continue saving ?")))
+       {
+         g_free (display_path);
+         return FALSE;
+       }
+    }
+
+  if (!glade_project_save (project, path, &error))
+    {
+      /* Reset path so future saves will prompt the file chooser */
+      glade_project_reset_path (project);
+
+      if (error)
+        {
+          glade_util_ui_message (GTK_WIDGET (window), GLADE_UI_ERROR, NULL,
+                                 _("Failed to save %s: %s"),
+                                 display_path, error->message);
+          g_error_free (error);
+        }
+      g_free (display_path);
+      return FALSE;
+    }
+
+  g_free (display_path);
+  return TRUE;
+}
+
 static void
 save (GladeWindow *window, GladeProject *project, const gchar *path)
 {
-  GError *error = NULL;
-  gchar *display_name, *display_path = g_strdup (path);
+  gchar *display_name;
   time_t mtime;
   GtkWidget *dialog;
   GtkWidget *button;
@@ -1132,31 +1235,15 @@ save (GladeWindow *window, GladeProject *project, const gchar *path)
          gtk_widget_destroy (dialog);
 
          if (response == GTK_RESPONSE_REJECT)
-           {
-             g_free (display_path);
-             return;
-           }
+           return;
        }
     }
 
   /* Interestingly; we cannot use `path' after glade_project_reset_path
    * because we are getting called with glade_project_get_path (project) as an argument.
    */
-  if (!glade_project_save (project, path, &error))
-    {
-      /* Reset path so future saves will prompt the file chooser */
-      glade_project_reset_path (project);
-
-      if (error)
-        {
-          glade_util_ui_message (GTK_WIDGET (window), GLADE_UI_ERROR, NULL,
-                                 _("Failed to save %s: %s"),
-                                 display_path, error->message);
-          g_error_free (error);
-        }
-      g_free (display_path);
-      return;
-    }
+  if (!do_save (window, project, path))
+    return;
 
   /* Get display_name here, it could have changed with "Save As..." */
   display_name = glade_project_get_name (project);
@@ -1173,7 +1260,6 @@ save (GladeWindow *window, GladeProject *project, const gchar *path)
                             window->priv->statusbar_actions_context_id,
                             _("Project '%s' saved"), display_name);
 
-  g_free (display_path);
   g_free (display_name);
 }
 
@@ -1320,7 +1406,6 @@ confirm_close_project (GladeWindow *window, GladeProject *project)
   gboolean close = FALSE;
   gchar *msg, *project_name = NULL;
   gint ret;
-  GError *error = NULL;
 
   project_name = glade_project_get_name (project);
 
@@ -1357,17 +1442,7 @@ confirm_close_project (GladeWindow *window, GladeProject *project)
          */
         if (glade_project_get_path (project) != NULL)
           {
-            if ((close = glade_project_save
-                 (project, glade_project_get_path (project), &error)) == FALSE)
-              {
-
-                glade_util_ui_message
-                    (GTK_WIDGET (window), GLADE_UI_ERROR, NULL,
-                     _("Failed to save %s to %s: %s"),
-                     project_name, glade_project_get_path (project),
-                     error->message);
-                g_error_free (error);
-              }
+            close = do_save (window, project, glade_project_get_path (project));
           }
         else
           {
@@ -1459,6 +1534,9 @@ do_close (GladeWindow *window, GladeProject *project)
 
   view = glade_design_view_get_from_project (project);
 
+  /* Cancel any queued autosave activity */
+  project_cancel_autosave (project);
+
   if (glade_project_is_loading (project))
     {
       glade_project_cancel_load (project);
diff --git a/src/glade.glade b/src/glade.glade
index 2eb54a6..bf337be 100644
--- a/src/glade.glade
+++ b/src/glade.glade
@@ -2,6 +2,13 @@
 <interface>
   <!-- interface-requires gtk+ 3.8 -->
   <object class="GtkAccelGroup" id="accelgroup"/>
+  <object class="GtkAdjustment" id="autosave_seconds_adjustment">
+    <property name="lower">1</property>
+    <property name="upper">60</property>
+    <property name="value">1</property>
+    <property name="step_increment">1</property>
+    <property name="page_increment">10</property>
+  </object>
   <object class="GtkActionGroup" id="pointer_mode_actiongroup">
     <property name="accel_group">accelgroup</property>
     <child>
@@ -1193,124 +1200,198 @@ Andreas Nilsson &lt;andreas andreasn se&gt;</property>
           </packing>
         </child>
         <child>
-          <object class="GtkNotebook" id="notebook1">
+          <object class="GtkBox" id="box1">
             <property name="visible">True</property>
-            <property name="can_focus">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">7</property>
+            <property name="orientation">vertical</property>
             <child>
-              <object class="GtkBox" id="box1">
+              <object class="GtkFrame" id="frame2">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
-                <property name="border_width">7</property>
-                <property name="orientation">vertical</property>
+                <property name="label_xalign">0</property>
+                <property name="label_yalign">0</property>
+                <property name="shadow_type">none</property>
                 <child>
-                  <object class="GtkFrame" id="frame1">
+                  <object class="GtkGrid" id="grid2">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
-                    <property name="label_xalign">0</property>
+                    <property name="margin_left">12</property>
+                    <property name="margin_top">6</property>
+                    <property name="row_spacing">6</property>
+                    <property name="column_spacing">6</property>
                     <child>
-                      <object class="GtkGrid" id="grid1">
+                      <object class="GtkCheckButton" id="create_backups_toggle">
+                        <property name="label" translatable="yes">Create Backups</property>
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="border_width">6</property>
-                        <property name="row_spacing">6</property>
-                        <property name="column_spacing">6</property>
-                        <child>
-                          <object class="GtkButton" id="catalog_path_remove_button">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="tooltip_text" translatable="yes">Removes the selected catalog 
path</property>
-                            <signal name="clicked" handler="on_catalog_path_remove_button_clicked" 
object="catalog_path_comboboxtext" swapped="no"/>
-                            <child>
-                              <object class="GtkImage" id="image1">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="stock">gtk-remove</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">0</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="tooltip_text" translatable="yes">Create a backup of the last version 
of the project every time the project is saved</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">2</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkSpinButton" id="autosave_spin">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="invisible_char">•</property>
+                        <property name="adjustment">autosave_seconds_adjustment</property>
+                        <property name="numeric">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkCheckButton" id="autosave_toggle">
+                        <property name="label" translatable="yes">Autosave after timeout:</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="tooltip_text" translatable="yes">Automatically save the project 
after the specified timeout passes
+whenever the project is modified</property>
+                        <property name="xalign">0</property>
+                        <property name="draw_indicator">True</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+                <child type="label">
+                  <object class="GtkLabel" id="label3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Load and Save</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkFrame" id="frame1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label_xalign">0</property>
+                <property name="label_yalign">0</property>
+                <property name="shadow_type">none</property>
+                <child>
+                  <object class="GtkGrid" id="grid1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="margin_left">12</property>
+                    <property name="margin_top">6</property>
+                    <property name="row_spacing">6</property>
+                    <property name="column_spacing">6</property>
+                    <child>
+                      <object class="GtkButton" id="catalog_path_remove_button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="tooltip_text" translatable="yes">Removes the selected catalog 
path</property>
+                        <property name="margin_top">2</property>
+                        <property name="margin_bottom">2</property>
+                        <signal name="clicked" handler="on_catalog_path_remove_button_clicked" 
object="catalog_path_comboboxtext" swapped="no"/>
                         <child>
-                          <object class="GtkComboBoxText" id="catalog_path_comboboxtext">
+                          <object class="GtkImage" id="image1">
                             <property name="visible">True</property>
                             <property name="can_focus">False</property>
-                            <property name="hexpand">True</property>
-                            <property name="entry_text_column">0</property>
-                            <property name="id_column">1</property>
-                          </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">0</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="catalog_path_add_button">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <property name="tooltip_text" translatable="yes">Add a new catalog 
path</property>
-                            <signal name="clicked" handler="gtk_widget_show" 
object="preferences_filechooserdialog" swapped="yes"/>
-                            <child>
-                              <object class="GtkImage" id="image2">
-                                <property name="visible">True</property>
-                                <property name="can_focus">False</property>
-                                <property name="stock">gtk-add</property>
-                              </object>
-                            </child>
+                            <property name="icon_name">list-remove-symbolic</property>
                           </object>
-                          <packing>
-                            <property name="left_attach">2</property>
-                            <property name="top_attach">0</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
                         </child>
                       </object>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
                     </child>
-                    <child type="label">
-                      <object class="GtkLabel" id="label2">
+                    <child>
+                      <object class="GtkComboBoxText" id="catalog_path_comboboxtext">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="label" translatable="yes">Extra catalog paths</property>
-                        <property name="use_markup">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="entry_text_column">0</property>
+                        <property name="id_column">1</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkButton" id="catalog_path_add_button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="tooltip_text" translatable="yes">Add a new catalog path</property>
+                        <property name="margin_top">2</property>
+                        <property name="margin_bottom">2</property>
+                        <signal name="clicked" handler="gtk_widget_show" 
object="preferences_filechooserdialog" swapped="yes"/>
+                        <child>
+                          <object class="GtkImage" id="image2">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">list-add-symbolic</property>
+                          </object>
+                        </child>
                       </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
                     </child>
                   </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <placeholder/>
                 </child>
-                <child>
-                  <placeholder/>
+                <child type="label">
+                  <object class="GtkLabel" id="label2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label" translatable="yes">Extra catalog paths</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
                 </child>
               </object>
-            </child>
-            <child type="tab">
-              <object class="GtkLabel" id="label1">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="label" translatable="yes">General</property>
-              </object>
               <packing>
-                <property name="tab_fill">False</property>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
               </packing>
             </child>
+            <child>
+              <placeholder/>
+            </child>
           </object>
           <packing>
-            <property name="expand">True</property>
+            <property name="expand">False</property>
             <property name="fill">True</property>
             <property name="position">1</property>
           </packing>


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