[nautilus-python/wip/jtojnar/nautilus-4: 4/4] Implement NautilusPropertiesModelProvider support




commit c0803439c16259601cc649c83502b8b68a0d2d75
Author: Jan Tojnar <jtojnar gmail com>
Date:   Wed Aug 10 22:34:35 2022 +0200

    Implement NautilusPropertiesModelProvider support
    
    This replaces NautilusPropertyPageProvider from Nautilus-3.0.

 docs/reference/nautilus-python-class-reference.xml |   1 +
 docs/reference/nautilus-python-overview.xml        |   2 +-
 .../nautilus-python-properties-model-provider.xml  | 125 +++++++++++++++++++
 .../reference/nautilus-python-properties-model.xml | 135 +++++++++++++++++++++
 .../nautilus-python-provider-reference.xml         |   1 +
 examples/md5sum-properties-model.py                |  29 +++++
 examples/meson.build                               |   1 +
 src/nautilus-python-object.c                       |  46 +++++++
 src/nautilus-python.c                              |   6 +-
 src/nautilus-python.h                              |   9 ++
 10 files changed, 353 insertions(+), 2 deletions(-)
---
diff --git a/docs/reference/nautilus-python-class-reference.xml 
b/docs/reference/nautilus-python-class-reference.xml
index bc4a751..c234996 100644
--- a/docs/reference/nautilus-python-class-reference.xml
+++ b/docs/reference/nautilus-python-class-reference.xml
@@ -9,5 +9,6 @@
     <xi:include href="nautilus-python-file-info.xml"/>
     <xi:include href="nautilus-python-menu.xml"/>
     <xi:include href="nautilus-python-menu-item.xml"/>
+    <xi:include href="nautilus-python-properties-model.xml"/>
 </chapter>
 
diff --git a/docs/reference/nautilus-python-overview.xml b/docs/reference/nautilus-python-overview.xml
index ccdc291..cac3c12 100644
--- a/docs/reference/nautilus-python-overview.xml
+++ b/docs/reference/nautilus-python-overview.xml
@@ -10,7 +10,7 @@
     One simply imports the Nautilus module from the gobject introspection repository and creates a class 
which is derived from a gobject.GObject and 
     one of the Nautilus module's classes. When an extension derives a class, it becomes a "provider", 
     telling Nautilus to ask it for information. There are several types of providers 
-    available for extensions to use: there is MenuProvider, 
+    available for extensions to use: there is MenuProvider, PropertiesModelProvider,
     ColumnProvider, and InfoProvider, all of which will be explained 
     in more detail below. Your class can be derived from multiple providers.</para>
     
diff --git a/docs/reference/nautilus-python-properties-model-provider.xml 
b/docs/reference/nautilus-python-properties-model-provider.xml
new file mode 100644
index 0000000..336f4a8
--- /dev/null
+++ b/docs/reference/nautilus-python-properties-model-provider.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
+
+<refentry id="class-nautilus-python-properties-model-provider">
+  <refnamediv>
+    <refname>Nautilus.PropertiesModelProvider</refname>
+    <refpurpose>Nautilus.PropertiesModelProvider Reference</refpurpose>
+  </refnamediv>
+
+<!-- ******************************* -->
+<!-- BEGIN OF SYNOPSIS -->
+<!-- ******************************* -->
+
+  <refsect1>
+    <title>Synopsis</title>
+
+    <classsynopsis language="python">
+      <ooclass><classname>Nautilus.PropertiesModelProvider</classname></ooclass>
+
+      <methodsynopsis language="python">
+        <methodname><link 
linkend="method-nautilus-properties-model-provider--get-models">get_models</link></methodname>
+        <methodparam><parameter role="keyword">files</parameter></methodparam>
+      </methodsynopsis>
+    </classsynopsis>
+  </refsect1>
+
+<!-- ********************************** -->
+<!-- BEGIN OF DESCRIPTION -->
+<!-- ********************************** -->
+
+  <refsect1 id="description-properties-model-provider">
+    <title>Description</title>
+
+      <para>
+      If subclassed, Nautilus will request a list of custom properties models that should
+      appear when a user opens the Properties dialog for a file or folder.
+      </para>
+
+<example>
+    <title>Nautilus.PropertiesModelProvider Example</title>
+    <programlisting>
+import hashlib
+
+from urllib.parse import unquote
+
+from gi.repository import Nautilus, GObject
+
+class MD5SumPropertiesModel(GObject.GObject, Nautilus.PropertiesModelProvider):
+    def __init__(self):
+        pass
+    
+    def get_properties_models(self, files):
+        if len(files) != 1:
+            return
+        
+        file = files[0]
+        if file.get_uri_scheme() != 'file':
+            return
+
+        if file.is_directory():
+            return
+
+        filename = unquote(file.get_uri()[7:])
+
+        self.property_label = Gtk.Label('MD5Sum')
+        self.property_label.show()
+
+        self.hbox = Gtk.HBox(homogeneous=False, spacing=0)
+        self.hbox.show()
+
+        label = Gtk.Label('MD5Sum:')
+        label.show()
+        self.hbox.pack_start(label, False, False, 0)
+
+        self.value_label = Gtk.Label()
+        self.hbox.pack_start(self.value_label, False, False, 0)
+
+        md5sum = hashlib.md5(filename.encode("utf-8")).hexdigest()
+        self.value_label.set_text(md5sum)
+        self.value_label.show()
+        
+        return Nautilus.PropertiesModel(name="NautilusPython::md5_sum",
+                                     label=self.property_label, 
+                                     page=self.hbox),
+    </programlisting>
+</example>
+        
+  </refsect1>
+
+<!-- ****************************** -->
+<!-- BEGIN OF METHODS -->
+<!-- ****************************** -->
+
+  <refsect1>
+        <title>Passive Methods</title>
+
+        <refsect2 id="method-nautilus-properties-model-provider--get-models">
+          <title>Nautilus.PropertiesModelProvider.get_models</title>
+
+          <programlisting><methodsynopsis language="python">
+            <methodname>get_models</methodname>
+              <methodparam></methodparam>
+          </methodsynopsis></programlisting>
+
+          <variablelist>
+            <varlistentry>
+                   <term><parameter role="keyword">files</parameter>&nbsp;:</term>
+                   <listitem><simpara>a list of <link 
linkend="class-nautilus-python-file-info"><classname>Nautilus.FileInfo</classname></link> 
objects.</simpara></listitem>
+            </varlistentry>
+            <varlistentry>
+              <term><emphasis>Returns</emphasis>&nbsp;:</term>
+              <listitem><simpara>a list of <link 
linkend="class-nautilus-python-properties-model"><classname>Nautilus.PropertiesModel</classname></link> 
objects</simpara></listitem>
+            </varlistentry>
+          </variablelist>
+
+          <para>
+                This function is called by Nautilus when it wants properties model items from the extension. 
 
+                It is called in the main thread before a properties model is shown, so it should return 
quickly.
+          </para>
+        </refsect2>
+    </refsect1>
+
+</refentry>
+
diff --git a/docs/reference/nautilus-python-properties-model.xml 
b/docs/reference/nautilus-python-properties-model.xml
new file mode 100644
index 0000000..2b3a4f5
--- /dev/null
+++ b/docs/reference/nautilus-python-properties-model.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd";>
+
+<refentry id="class-nautilus-python-properties-model">
+  <refnamediv>
+    <refname>Nautilus.PropertiesModel</refname>
+    <refpurpose>Nautilus.PropertiesModel Reference</refpurpose>
+  </refnamediv>
+
+<!-- ******************************* -->
+<!-- BEGIN OF NAUTILUS-PYTHON SYNOPSIS -->
+<!-- ******************************* -->
+
+  <refsect1>
+    <title>Synopsis</title>
+
+    <classsynopsis language="python">
+        <ooclass><classname>Nautilus.PropertiesModel</classname></ooclass>
+        <ooclass><classname><link linkend="class-gobject">gobject.GObject</link></classname></ooclass>
+
+        <constructorsynopsis language="python">
+            <methodname><link 
linkend="constructor-nautilus-properties-model">Nautilus.PropertiesModel</link></methodname>
+            <methodparam><parameter role="keyword">name</parameter></methodparam>
+            <methodparam><parameter role="keyword">label</parameter></methodparam>
+            <methodparam><parameter role="keyword">page</parameter></methodparam>
+        </constructorsynopsis>
+    </classsynopsis>
+  </refsect1>
+
+<!-- ********************************* -->
+<!-- BEGIN OF ANCESTRY -->
+<!-- ********************************* -->
+
+<refsect1>
+    <title>Ancestry</title>
+
+<synopsis>+-- <link linkend="class-gobject">gobject.GObject</link>
+    +-- <link linkend="class-nautilus-python-properties-model">Nautilus.PropertiesModel</link>
+</synopsis>
+</refsect1>
+
+
+<!-- ********************************** -->
+<!-- BEGIN OF DESCRIPTION -->
+<!-- ********************************** -->
+
+  <refsect1 id="description-properties-model">
+    <title>Description</title>
+
+      <para>
+        A <link 
linkend="class-nautilus-python-properties-model"><classname>Nautilus.PropertiesModel</classname></link> 
object is returned by <link 
linkend="class-nautilus-python-properties-model-provider"><classname>Nautilus.PropertyPageProvider</classname></link>
 extensions.
+      </para>
+
+  </refsect1>
+
+
+<!-- *********************************** -->
+<!-- BEGIN OF PROPERTIES -->
+<!-- *********************************** -->
+
+<refsect1>
+    <title>Properties</title>
+
+    <blockquote role="properties">
+      <informaltable pgwide="1" frame="none">
+      <tgroup cols="3">
+        <colspec column="1" colwidth="1in"/>
+        <colspec column="2" colwidth="1in"/>
+        <colspec column="3" colwidth="4in"/>
+          <tbody>
+      
+            <row valign="top">
+              <entry>"label"</entry>
+              <entry>The label widget displayed in the notebook tab.</entry>
+              <entry>Read-Write</entry>
+            </row>
+      
+            <row valign="top">
+              <entry>"name"</entry>
+              <entry>The name of the page.  Default value: None</entry>
+              <entry>Read-Write-ConstructOnly</entry>
+            </row>
+      
+            <row valign="top">
+              <entry>"page"</entry>
+              <entry>The properties model widget</entry>
+              <entry>Read-Write</entry>
+            </row>
+
+          </tbody>
+        </tgroup>
+      </informaltable>
+    </blockquote>
+</refsect1>
+
+
+<!-- ************************************ -->
+<!-- BEGIN OF CONSTRUCTOR -->
+<!-- ************************************ -->
+
+<refsect1 id="constructor-nautilus-properties-model">
+  <title>Constructor</title>
+
+  <programlisting><constructorsynopsis language="python">
+        <methodname>Nautilus.PropertiesModel</methodname>
+        <methodparam><parameter role="keyword">name</parameter></methodparam>
+        <methodparam><parameter role="keyword">label</parameter></methodparam>
+        <methodparam><parameter role="keyword">page</parameter></methodparam>
+  </constructorsynopsis></programlisting>
+    
+  <variablelist>
+    <varlistentry>
+           <term><parameter role="keyword">name</parameter>&nbsp;:</term>
+           <listitem><simpara>identifier of the properties model</simpara></listitem>
+    </varlistentry>
+    <varlistentry>
+           <term><parameter role="keyword">label</parameter>&nbsp;:</term>
+           <listitem><simpara>the user-visible label for the properties model</simpara></listitem>
+    </varlistentry>
+    <varlistentry>
+           <term><parameter role="keyword">page</parameter>&nbsp;:</term>
+           <listitem><simpara>the properties model widget</simpara></listitem>
+    </varlistentry>
+  </variablelist>
+
+  <para>
+    Creates a new <link 
linkend="class-nautilus-python-properties-model"><classname>Nautilus.PropertiesModel</classname></link> 
object.
+  </para>
+</refsect1>
+
+
+
+</refentry>
+
diff --git a/docs/reference/nautilus-python-provider-reference.xml 
b/docs/reference/nautilus-python-provider-reference.xml
index 3c0d335..4a87e3a 100644
--- a/docs/reference/nautilus-python-provider-reference.xml
+++ b/docs/reference/nautilus-python-provider-reference.xml
@@ -8,5 +8,6 @@
     <xi:include href="nautilus-python-column-provider.xml"/>
     <xi:include href="nautilus-python-info-provider.xml"/>
     <xi:include href="nautilus-python-menu-provider.xml"/>
+    <xi:include href="nautilus-python-properties-model-provider.xml"/>
 </chapter>
 
diff --git a/examples/md5sum-properties-model.py b/examples/md5sum-properties-model.py
new file mode 100644
index 0000000..9cffe43
--- /dev/null
+++ b/examples/md5sum-properties-model.py
@@ -0,0 +1,29 @@
+import hashlib
+
+from urllib.parse import unquote
+from gi.repository import Nautilus, GObject
+from typing import List
+
+class MD5SumPropertiesModel(GObject.GObject, Nautilus.PropertiesModelProvider):
+    def get_models(self, files: List[Nautilus.FileInfo]) -> List[Nautilus.PropertiesModel]:
+        if len(files) != 1:
+            return []
+
+        file = files[0]
+        if file.get_uri_scheme() != 'file':
+            return []
+
+        if file.is_directory():
+            return []
+
+        filename = unquote(file.get_uri()[7:])
+
+        section_model = Gio.ListStore.new(item_type=Nautilus.PropertiesItem)
+        section_model.append(Nautilus.PropertiesItem(name='MD5Sum:', value=md5sum))
+
+        return [
+            Nautilus.PropertiesModel(
+                title='MD5Sum',
+                model=section_model,
+            ),
+        ]
diff --git a/examples/meson.build b/examples/meson.build
index 266c0eb..914f5fd 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -10,6 +10,7 @@ install_data(
     'background-image.py',
     'block-size-column.py',
     'open-terminal.py',
+    'md5sum-properties-model.py',
     'submenu.py',
     'update-file-info-async.py',
   ],
diff --git a/src/nautilus-python-object.c b/src/nautilus-python-object.c
index 3ee2a0a..0301e5c 100644
--- a/src/nautilus-python-object.c
+++ b/src/nautilus-python-object.c
@@ -156,6 +156,40 @@ nautilus_python_boxed_new (PyTypeObject *type, gpointer boxed, gboolean free_on_
     return (PyObject *) self;
 }
 
+#define METHOD_NAME "get_models"
+static GList *
+nautilus_python_object_get_models (NautilusPropertiesModelProvider *provider,
+                                   GList                           *files) {
+    NautilusPythonObject *object = (NautilusPythonObject*)provider;
+    PyObject *py_files, *py_ret = NULL;
+    GList *ret = NULL;
+    PyGILState_STATE state = pyg_gil_state_ensure();
+
+    debug_enter();
+
+    CHECK_OBJECT(object);
+    CHECK_METHOD_NAME(object->instance);
+
+    CONVERT_LIST(py_files, files);
+
+    py_ret = PyObject_CallMethod(object->instance, METHOD_PREFIX METHOD_NAME,
+                                 "(N)", py_files);
+    HANDLE_RETVAL(py_ret);
+
+    HANDLE_LIST(py_ret, NautilusPropertiesModel, "Nautilus.PropertiesModel");
+
+beach:
+    Py_XDECREF(py_ret);
+    pyg_gil_state_release(state);
+    return ret;
+}
+#undef METHOD_NAME
+
+static void
+nautilus_python_object_properties_model_provider_interface_init (NautilusPropertiesModelProviderInterface 
*interface) {
+    interface->get_models = nautilus_python_object_get_models;
+}
+
 #define METHOD_NAME "get_file_items"
 static GList *
 nautilus_python_object_get_file_items (NautilusMenuProvider *provider,
@@ -401,6 +435,12 @@ nautilus_python_object_get_type (GTypeModule *module,
     const char *type_name;
     GType gtype;
 
+    static const GInterfaceInfo properties_model_provider_interface_info = {
+        (GInterfaceInitFunc) nautilus_python_object_properties_model_provider_interface_init,
+        NULL,
+        NULL
+    };
+
     static const GInterfaceInfo menu_provider_interface_info = {
         (GInterfaceInitFunc) nautilus_python_object_menu_provider_interface_init,
         NULL,
@@ -438,6 +478,12 @@ nautilus_python_object_get_type (GTypeModule *module,
                                          type_name,
                                          info, 0);
 
+    if (PyObject_IsSubclass(type, (PyObject*)&PyNautilusPropertiesModelProvider_Type)) {
+        g_type_module_add_interface (module, gtype,
+                                     NAUTILUS_TYPE_PROPERTIES_MODEL_PROVIDER,
+                                     &properties_model_provider_interface_info);
+    }
+
     if (PyObject_IsSubclass(type, (PyObject*)&PyNautilusMenuProvider_Type)) {
         g_type_module_add_interface (module, gtype, 
                                      NAUTILUS_TYPE_MENU_PROVIDER,
diff --git a/src/nautilus-python.c b/src/nautilus-python.c
index 39b27a0..df2dc7c 100644
--- a/src/nautilus-python.c
+++ b/src/nautilus-python.c
@@ -84,7 +84,8 @@ nautilus_python_load_file(GTypeModule *type_module,
 
         if (PyObject_IsSubclass(value, (PyObject*)&PyNautilusColumnProvider_Type) ||
                                PyObject_IsSubclass(value, (PyObject*)&PyNautilusInfoProvider_Type) ||
-                               PyObject_IsSubclass(value, (PyObject*)&PyNautilusMenuProvider_Type)) {
+                               PyObject_IsSubclass(value, (PyObject*)&PyNautilusMenuProvider_Type) ||
+                               PyObject_IsSubclass(value, 
(PyObject*)&PyNautilusPropertiesModelProvider_Type)) {
             gtype = nautilus_python_object_get_type(type_module, value);
             g_array_append_val(all_types, gtype);
         }
@@ -211,6 +212,9 @@ nautilus_python_init_python (void) {
     IMPORT(Menu, "Menu");
     IMPORT(MenuItem, "MenuItem");
     IMPORT(MenuProvider, "MenuProvider");
+    IMPORT(PropertiesItem, "PropertiesItem");
+    IMPORT(PropertiesModel, "PropertiesModel");
+    IMPORT(PropertiesModelProvider, "PropertiesModelProvider");
     IMPORT(OperationHandle, "OperationHandle");
 
 #undef IMPORT
diff --git a/src/nautilus-python.h b/src/nautilus-python.h
index 652f470..80f23a1 100644
--- a/src/nautilus-python.h
+++ b/src/nautilus-python.h
@@ -61,6 +61,15 @@ PyTypeObject *_PyNautilusMenuItem_Type;
 PyTypeObject *_PyNautilusMenuProvider_Type;
 #define PyNautilusMenuProvider_Type (*_PyNautilusMenuProvider_Type)
 
+PyTypeObject *_PyNautilusPropertiesItem_Type;
+#define PyNautilusPropertiesItem_Type (*_PyNautilusPropertiesItem_Type)
+
+PyTypeObject *_PyNautilusPropertiesModel_Type;
+#define PyNautilusPropertiesModel_Type (*_PyNautilusPropertiesModel_Type)
+
+PyTypeObject *_PyNautilusPropertiesModelProvider_Type;
+#define PyNautilusPropertiesModelProvider_Type (*_PyNautilusPropertiesModelProvider_Type)
+
 PyTypeObject *_PyNautilusOperationHandle_Type;
 #define PyNautilusOperationHandle_Type (*_PyNautilusOperationHandle_Type)
 


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