From 3291a47e988c8074aa1d7dfa54a98f7ab8930175 Mon Sep 17 00:00:00 2001
From: Benedikt Meurer <benny@xfce.org>
Date: Fri, 24 Mar 2006 14:46:35 +0000
Subject: [PATCH] 2006-03-24	Benedikt Meurer <benny@xfce.org>

	* plugins/thunar-sbr/thunar-sbr-case-renamer.h,
	  plugins/thunar-sbr/thunar-sbr-insert-renamer.h,
	  plugins/thunar-sbr/thunar-sbr-remove-renamer.h,
	  plugins/thunar-sbr/thunar-sbr-replace-renamer.h: Fix typos.
	* docs/reference/thunarx/tmpl/thunarx-file-info.sgml,
	  thunarx/thunarx-file-info.c: Register the "changed" and "renamed"
	  signals right after the type is registered. This way gtk-doc will
	  properly display the signals (gtk-doc doesn't invoke base_init() for
	  interfaces). Bug #1418.
	* docs/reference/thunarx/tmpl/thunarx-property-page-provider.sgml,
	  docs/reference/thunarx/tmpl/thunarx-property-page.sgml,
	  thunarx/thunarx-property-page-provider.c: Properly document
	  ThunarxPropertyPage and ThunarxPropertyPageProvider. Bug #1456.




(Old svn revision: 20531)
---
 ChangeLog                                     |  16 ++
 .../thunarx/tmpl/thunarx-file-info.sgml       |  14 +
 .../tmpl/thunarx-property-page-provider.sgml  |   4 +-
 .../thunarx/tmpl/thunarx-property-page.sgml   | 246 +++++++++++++++++-
 plugins/thunar-sbr/thunar-sbr-case-renamer.h  |   2 +-
 .../thunar-sbr/thunar-sbr-insert-renamer.h    |   2 +-
 .../thunar-sbr/thunar-sbr-remove-renamer.h    |   2 +-
 .../thunar-sbr/thunar-sbr-replace-renamer.h   |   2 +-
 thunarx/thunarx-file-info.c                   |  31 +--
 thunarx/thunarx-property-page-provider.c      |  24 +-
 10 files changed, 312 insertions(+), 31 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index bca688358..c54ba74f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2006-03-24	Benedikt Meurer <benny@xfce.org>
+
+	* plugins/thunar-sbr/thunar-sbr-case-renamer.h,
+	  plugins/thunar-sbr/thunar-sbr-insert-renamer.h,
+	  plugins/thunar-sbr/thunar-sbr-remove-renamer.h,
+	  plugins/thunar-sbr/thunar-sbr-replace-renamer.h: Fix typos.
+	* docs/reference/thunarx/tmpl/thunarx-file-info.sgml,
+	  thunarx/thunarx-file-info.c: Register the "changed" and "renamed"
+	  signals right after the type is registered. This way gtk-doc will
+	  properly display the signals (gtk-doc doesn't invoke base_init() for
+	  interfaces). Bug #1418.
+	* docs/reference/thunarx/tmpl/thunarx-property-page-provider.sgml,
+	  docs/reference/thunarx/tmpl/thunarx-property-page.sgml,
+	  thunarx/thunarx-property-page-provider.c: Properly document
+	  ThunarxPropertyPage and ThunarxPropertyPageProvider. Bug #1456.
+
 2006-03-24	Benedikt Meurer <benny@xfce.org>
 
 	* thunar/thunar-renamer-progress.{c,h}: Add new helper method
diff --git a/docs/reference/thunarx/tmpl/thunarx-file-info.sgml b/docs/reference/thunarx/tmpl/thunarx-file-info.sgml
index c97bb77fb..e912baf8e 100644
--- a/docs/reference/thunarx/tmpl/thunarx-file-info.sgml
+++ b/docs/reference/thunarx/tmpl/thunarx-file-info.sgml
@@ -42,6 +42,20 @@ Stable
 </para>
 
 
+<!-- ##### SIGNAL ThunarxFileInfo::changed ##### -->
+<para>
+
+</para>
+
+@thunarxfileinfo: the object which received the signal.
+
+<!-- ##### SIGNAL ThunarxFileInfo::renamed ##### -->
+<para>
+
+</para>
+
+@thunarxfileinfo: the object which received the signal.
+
 <!-- ##### FUNCTION thunarx_file_info_get_name ##### -->
 <para>
 
diff --git a/docs/reference/thunarx/tmpl/thunarx-property-page-provider.sgml b/docs/reference/thunarx/tmpl/thunarx-property-page-provider.sgml
index 82efbf010..80c65139c 100644
--- a/docs/reference/thunarx/tmpl/thunarx-property-page-provider.sgml
+++ b/docs/reference/thunarx/tmpl/thunarx-property-page-provider.sgml
@@ -29,8 +29,8 @@ Stable
 
 <!-- ##### STRUCT ThunarxPropertyPageProviderIface ##### -->
 <para>
-	Interface with virtual methods implemented by extensions that provide
-	additional pages for the file properties dialog.
+  Interface with virtual methods implemented by extensions that provide
+  additional pages for the file properties dialog.
 </para>
 
 @get_pages: see thunarx_property_page_provider_get_pages().
diff --git a/docs/reference/thunarx/tmpl/thunarx-property-page.sgml b/docs/reference/thunarx/tmpl/thunarx-property-page.sgml
index 932f077e7..3c11f0ff8 100644
--- a/docs/reference/thunarx/tmpl/thunarx-property-page.sgml
+++ b/docs/reference/thunarx/tmpl/thunarx-property-page.sgml
@@ -7,7 +7,251 @@ The base class for pages added to the properties dialog
 <!-- ##### SECTION Long_Description ##### -->
 <para>
   The class for pages that can be added to Thunar's file properties dialog
-  by extensions implementing the #ThunarxPropertyPageProvider interface.
+  by extensions implementing the #ThunarxPropertyPageProvider interface. The
+  pages returned by extensions from thunarx_property_page_provider_get_pages()
+  method are instances of this class or a derived class. Note that extensions
+  do not need to subclass #ThunarxPropertyPage, but may also instantiate it
+  directly and add widgets to it, but I strongly suggest to create a subclass
+  as it usually leads to better modularization and thereby better maintainability
+  in the code.
+</para>
+
+<para>
+  To pick up the #TagPage example from the thunarx_property_page_provider_get_pages()
+  description again, you'd create a new class #TagPage, that inherits #ThunarxPropertyPage
+  (using the #THUNARX_DEFINE_TYPE macro), which provides several user interface elements
+  in the property, and defines atleast one property named <literal>"file"</literal>, which
+  is the #ThunarxFileInfo whose tags are displayed in the property page. For example, the
+  <filename>tag-page.h</filename> header file would look like this (this is really just
+  an example of the suggested way to implement property pages, you may of course choose
+  a different way):
+</para>
+
+<informalexample><programlisting>
+##ifndef __TAG_PAGE_H__
+##define __TAG_PAGE_H__
+
+##include &lt;thunarx/thunarx.h&gt;
+
+G_BEGIN_DECLS;
+
+typedef struct _TagPageClass TagPageClass;
+typedef struct _TagPage      TagPage;
+
+#define TAG_TYPE_PAGE            (tag_page_get_type ())
+#define TAG_PAGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), TAG_TYPE_PAGE, TagPage))
+#define TAG_PAGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), TAG_TYPE_PAGE, TagPageClass))
+#define TAG_IS_PAGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TAG_TYPE_PAGE))
+#define TAG_IS_PAGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TAG_TYPE_PAGE))
+#define TAG_PAGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), TAG_TYPE_PAGE, TagPageClass))
+
+/* these two functions are implemented automatically by the THUNARX_DEFINE_TYPE macro */
+GType            tag_page_get_type      (void) G_GNUC_CONST G_GNUC_INTERNAL;
+void             tag_page_register_type (ThunarxProviderPlugin *plugin) G_GNUC_INTERNAL;
+
+GtkWidget       *tag_page_new           (ThunarxFileInfo       *file) G_GNUC_INTERNAL G_GNUC_MALLOC;
+
+ThunarxFileInfo *tag_page_get_file      (TagPage               *tag_page) G_GNUC_INTERNAL;
+void             tag_page_set_file      (TagPage               *tag_page,
+                                         ThunarxFileInfo       *file) G_GNUC_INTERNAL;
+
+G_END_DECLS;
+
+##endif /* !__TAG_PAGE_H__ */
+</programlisting></informalexample>
+
+<para>
+  And the <filename>tag-page.c</filename> source file could look like this:
+</para>
+
+<informalexample><programlisting>
+##include "tag-page.h"
+
+/* Property identifiers */
+enum
+{
+  PROP_0,
+  PROP_FILE,
+};
+
+static void tag_page_class_init   (TagPageClass *klass);
+static void tag_page_init         (TagPage          *tag_page);
+static void tag_page_finalize     (GObject          *object);
+static void tag_page_get_property (GObject          *object,
+                                   guint             prop_id,
+                                   GValue           *value,
+                                   GParamSpec       *pspec);
+static void tag_page_set_property (GObject          *object,
+                                   guint             prop_id,
+                                   const GValue     *value,
+                                   GParamSpec       *pspec);
+static void tag_page_file_changed (ThunarxFileInfo  *file,
+                                   TagPage          *tag_page);
+
+struct _TagPageClass
+{
+  ThunarxPropertyPageClass __parent__;
+};
+
+struct _TagPage
+{
+  ThunarxPropertyPage __parent__;
+  ThunarxFileInfo    *file;
+
+  /* your widgets... */
+};
+
+/* implements the tag_page_get_type() and tag_page_register_type() functions */
+THUNARX_DEFINE_TYPE (TagPage, tag_page, THUNARX_TYPE_PROPERTY_PAGE);
+
+static void
+tag_page_class_init (TagPageClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = tag_page_finalize;
+  gobject_class->get_property = tag_page_get_property;
+  gobject_class->set_property = tag_page_set_property;
+
+  /**
+   * TagPage:file:
+   *
+   * The #ThunarxFileInfo displayed by this #TagPage.
+   **/
+  g_object_class_install_property (gobject_class,
+                                   PROP_FILE,
+                                   g_param_spec_object ("file", "file", "file,
+                                                        THUNARX_TYPE_FILE_INFO,
+                                                        G_PARAM_READWRITE));
+}
+
+static void
+tag_page_init (TagPage *tag_page)
+{
+  GtkWidget *table;
+
+  /* you can of course also use a GtkVBox here, or whatever */
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_container_add (GTK_CONTAINER (tag_page), table);
+  gtk_widget_show (table);
+
+  /* add your widgets to the table... */
+}
+
+static void
+tag_page_finalize (GObject *object)
+{
+  TagPage *tag_page = TAG_PAGE (object);
+
+  /* disconnect from the file */
+  tag_page_set_file (tag_page, NULL);
+
+  /* release any additional resources... */
+
+  (*G_OBJECT_CLASS (tag_page_parent_class)->finalize) (object);
+}
+
+static void
+tag_page_get_property (GObject    *object,
+                       guint       prop_id,
+                       GValue     *value,
+                       GParamSpec *pspec)
+{
+  TagPage *tag_page = TAG_PAGE (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      g_value_set_object (value, tag_page_get_file (tag_page));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tag_page_set_property (GObject      *object,
+                       guint         prop_id,
+                       const GValue *value,
+                       GParamSpec   *pspec)
+{
+  TagPage *tag_page = TAG_PAGE (object);
+
+  switch (prop_id)
+    {
+    case PROP_FILE:
+      tag_page_set_file (tag_page, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+tag_page_file_changed (ThunarxFileInfo *file,
+                       TagPage         *tag_page)
+{
+  /* update your user interface elements in the tag_page
+   * to display the new state of the file...
+   */
+}
+
+GtkWidget*
+tag_page_new (ThunarxFileInfo *file)
+{
+  return g_object_new (TAG_TYPE_PAGE, "file", file, NULL);
+}
+
+ThunarxFileInfo*
+tag_page_get_file (TagPage *tag_page)
+{
+  g_return_val_if_fail (TAG_IS_PAGE (tag_page), NULL);
+  return tag_page->file;
+}
+
+void
+tag_page_set_file (TagPage         *tag_page,
+                   ThunarxFileInfo *file)
+{
+  g_return_if_fail (TAG_IS_PAGE (tag_page));
+  g_return_if_fail (file == NULL || THUNARX_IS_FILE_INFO (file));
+
+  if (tag_page->file != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (tag_page->file, tag_page_file_changed, tag_page);
+      g_object_unref (G_OBJECT (tag_page->file));
+    }
+
+  tag_page->file = file;
+
+  if (file != NULL)
+    {
+      g_object_ref (file);
+      tag_page_file_changed (file, tag_page);
+      g_signal_connect (file, "changed", G_CALLBACK (tag_page_file_changed), tag_page);
+    }
+
+  g_object_notify (G_OBJECT (tag_page), "file");
+}
+</programlisting></informalexample>
+
+<para>
+  If this seems to be too complicated to you, just don't follow the suggestion. But keep in mind, that
+  while the above solution is a little longer than a less structured solution, it yields great flexbility
+  and maintainability. For example the #TagPage class described above, once filled with user interface
+  elements, may be used for a standalone MP3-Tag editor out of the box (i.e. as an action returned from
+  the thunarx_renamer_get_actions() method).
+</para>
+
+<para>
+  What is important to remember is that you should connect to the <literal>"changed"</literal> signal
+  of the #ThunarxFileInfo<!---->s you are displaying, and update the user interface whenever the file
+  changes.
 </para>
 
 <!-- ##### SECTION See_Also ##### -->
diff --git a/plugins/thunar-sbr/thunar-sbr-case-renamer.h b/plugins/thunar-sbr/thunar-sbr-case-renamer.h
index f1939bf0d..700497145 100644
--- a/plugins/thunar-sbr/thunar-sbr-case-renamer.h
+++ b/plugins/thunar-sbr/thunar-sbr-case-renamer.h
@@ -38,7 +38,7 @@ typedef struct _ThunarSbrCaseRenamer      ThunarSbrCaseRenamer;
 GType                     thunar_sbr_case_renamer_get_type      (void) G_GNUC_CONST G_GNUC_INTERNAL;
 void                      thunar_sbr_case_renamer_register_type (ThunarxProviderPlugin   *plugin) G_GNUC_INTERNAL;
 
-ThunarSbrCaseRenamer     *thunar_sbr_case_renamer_new           (void) G_GNUC_CONST G_GNUC_INTERNAL G_GNUC_MALLOC;
+ThunarSbrCaseRenamer     *thunar_sbr_case_renamer_new           (void) G_GNUC_INTERNAL G_GNUC_MALLOC;
 
 ThunarSbrCaseRenamerMode  thunar_sbr_case_renamer_get_mode      (ThunarSbrCaseRenamer    *case_renamer) G_GNUC_INTERNAL; 
 void                      thunar_sbr_case_renamer_set_mode      (ThunarSbrCaseRenamer    *case_renamer,
diff --git a/plugins/thunar-sbr/thunar-sbr-insert-renamer.h b/plugins/thunar-sbr/thunar-sbr-insert-renamer.h
index 473d602e6..b55030ca8 100644
--- a/plugins/thunar-sbr/thunar-sbr-insert-renamer.h
+++ b/plugins/thunar-sbr/thunar-sbr-insert-renamer.h
@@ -38,7 +38,7 @@ typedef struct _ThunarSbrInsertRenamer      ThunarSbrInsertRenamer;
 GType                   thunar_sbr_insert_renamer_get_type        (void) G_GNUC_CONST G_GNUC_INTERNAL;
 void                    thunar_sbr_insert_renamer_register_type   (ThunarxProviderPlugin  *plugin) G_GNUC_INTERNAL;
 
-ThunarSbrInsertRenamer *thunar_sbr_insert_renamer_new             (void) G_GNUC_CONST G_GNUC_INTERNAL G_GNUC_MALLOC;
+ThunarSbrInsertRenamer *thunar_sbr_insert_renamer_new             (void) G_GNUC_INTERNAL G_GNUC_MALLOC;
 
 ThunarSbrInsertMode     thunar_sbr_insert_renamer_get_mode        (ThunarSbrInsertRenamer *insert_renamer) G_GNUC_INTERNAL;
 void                    thunar_sbr_insert_renamer_set_mode        (ThunarSbrInsertRenamer *insert_renamer,
diff --git a/plugins/thunar-sbr/thunar-sbr-remove-renamer.h b/plugins/thunar-sbr/thunar-sbr-remove-renamer.h
index 59ce722c1..2aa56e53f 100644
--- a/plugins/thunar-sbr/thunar-sbr-remove-renamer.h
+++ b/plugins/thunar-sbr/thunar-sbr-remove-renamer.h
@@ -38,7 +38,7 @@ typedef struct _ThunarSbrRemoveRenamer      ThunarSbrRemoveRenamer;
 GType                   thunar_sbr_remove_renamer_get_type              (void) G_GNUC_CONST G_GNUC_INTERNAL;
 void                    thunar_sbr_remove_renamer_register_type         (ThunarxProviderPlugin  *plugin) G_GNUC_INTERNAL;
 
-ThunarSbrRemoveRenamer *thunar_sbr_remove_renamer_new                   (void) G_GNUC_CONST G_GNUC_INTERNAL G_GNUC_MALLOC;
+ThunarSbrRemoveRenamer *thunar_sbr_remove_renamer_new                   (void) G_GNUC_INTERNAL G_GNUC_MALLOC;
 
 guint                   thunar_sbr_remove_renamer_get_end_offset        (ThunarSbrRemoveRenamer *remove_renamer) G_GNUC_INTERNAL;
 void                    thunar_sbr_remove_renamer_set_end_offset        (ThunarSbrRemoveRenamer *remove_renamer,  
diff --git a/plugins/thunar-sbr/thunar-sbr-replace-renamer.h b/plugins/thunar-sbr/thunar-sbr-replace-renamer.h
index c01f7bd21..ed0d4f005 100644
--- a/plugins/thunar-sbr/thunar-sbr-replace-renamer.h
+++ b/plugins/thunar-sbr/thunar-sbr-replace-renamer.h
@@ -38,7 +38,7 @@ typedef struct _ThunarSbrReplaceRenamer      ThunarSbrReplaceRenamer;
 GType                    thunar_sbr_replace_renamer_get_type            (void) G_GNUC_CONST G_GNUC_INTERNAL;
 void                     thunar_sbr_replace_renamer_register_type       (ThunarxProviderPlugin   *plugin) G_GNUC_INTERNAL;
 
-ThunarSbrReplaceRenamer *thunar_sbr_replace_renamer_new                 (void) G_GNUC_CONST G_GNUC_INTERNAL G_GNUC_MALLOC;
+ThunarSbrReplaceRenamer *thunar_sbr_replace_renamer_new                 (void) G_GNUC_INTERNAL G_GNUC_MALLOC;
 
 gboolean                 thunar_sbr_replace_renamer_get_case_sensitive  (ThunarSbrReplaceRenamer *replace_renamer) G_GNUC_INTERNAL;
 void                     thunar_sbr_replace_renamer_set_case_sensitive  (ThunarSbrReplaceRenamer *replace_renamer,
diff --git a/thunarx/thunarx-file-info.c b/thunarx/thunarx-file-info.c
index 5c555797f..d4340f4f9 100644
--- a/thunarx/thunarx-file-info.c
+++ b/thunarx/thunarx-file-info.c
@@ -38,10 +38,6 @@ enum
 
 
 
-static void thunarx_file_info_base_init (gpointer klass);
-
-
-
 static guint file_info_signals[LAST_SIGNAL];
 
 
@@ -56,7 +52,7 @@ thunarx_file_info_get_type (void)
       static const GTypeInfo info =
       {
         sizeof (ThunarxFileInfoIface),
-        (GBaseInitFunc) thunarx_file_info_base_init,
+        NULL,
         NULL,
         NULL,
         NULL,
@@ -67,22 +63,12 @@ thunarx_file_info_get_type (void)
         NULL,
       };
 
+      /* register the interface type */
       type = g_type_register_static (G_TYPE_INTERFACE, I_("ThunarxFileInfo"), &info, 0);
-      g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
-    }
-
-  return type;
-}
 
+      /* implementations must inherit GObject */
+      g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
 
-
-static void
-thunarx_file_info_base_init (gpointer klass)
-{
-  static gboolean initialized = FALSE;
-
-  if (G_UNLIKELY (!initialized))
-    {
       /**
        * ThunarxFileInfo::changed:
        * @file_info : a #ThunarxFileInfo.
@@ -96,7 +82,7 @@ thunarx_file_info_base_init (gpointer klass)
        **/
       file_info_signals[CHANGED] =
         g_signal_new (I_("changed"),
-                      G_TYPE_FROM_CLASS (klass),
+                      type,
                       G_SIGNAL_RUN_FIRST,
                       G_STRUCT_OFFSET (ThunarxFileInfoIface, changed),
                       NULL, NULL,
@@ -116,16 +102,15 @@ thunarx_file_info_base_init (gpointer klass)
        **/
       file_info_signals[RENAMED] =
         g_signal_new (I_("renamed"),
-                      G_TYPE_FROM_CLASS (klass),
+                      type,
                       G_SIGNAL_RUN_FIRST,
                       G_STRUCT_OFFSET (ThunarxFileInfoIface, renamed),
                       NULL, NULL,
                       g_cclosure_marshal_VOID__VOID,
                       G_TYPE_NONE, 0);
-
-      /* yep, we're initialized now */
-      initialized = TRUE;
     }
+
+  return type;
 }
 
 
diff --git a/thunarx/thunarx-property-page-provider.c b/thunarx/thunarx-property-page-provider.c
index d45f3caf8..0cb9fd87d 100644
--- a/thunarx/thunarx-property-page-provider.c
+++ b/thunarx/thunarx-property-page-provider.c
@@ -1,6 +1,6 @@
 /* $Id$ */
 /*-
- * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org>
+ * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -66,6 +66,28 @@ thunarx_property_page_provider_get_type (void)
  *
  * Returns the list of #ThunarxPropertyPage<!---->s that @provider has to offer for @files.
  *
+ * Extensions that implement this interface, must first check whether they support all the
+ * #ThunarxFileInfo<!---->s in the list of @files. Most extensions will probably only support
+ * #ThunarxPropertyPage<!---->s for exactly one file of a certain type. For example an MP3-Tag
+ * editor property page will most probably support only a single audio file, and so the method
+ * would be implemented like this
+ * <informalexample><programlisting>
+ * GList*
+ * tag_provider_get_pages (ThunarxPropertyPageProvider *property_page_provider,
+ *                         GList                       *files)
+ * {
+ *   if (g_list_length (files) != 1)
+ *     return NULL;
+ *   else if (!thunarx_file_info_has_mime_type (files->data, "audio/mp3"))
+ *     return NULL;
+ *   else
+ *     return g_list_append (NULL, tag_page_new (files->data));
+ * }
+ * </programlisting></informalexample>
+ * where tag_page_new() allocates a new #TagPage instance for a #ThunarxFileInfo object
+ * passed to it. See the description of the #ThunarxPropertyPage class for additional
+ * information about the #TagPage example class.
+ *
  * As a special note, this method automatically takes a reference on the
  * @provider for every #ThunarxPropertyPage object returned from the real implementation
  * of this method in @provider. This is to make sure that the extension stays
-- 
GitLab