summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/pychrysalide/core.c51
-rw-r--r--plugins/pychrysalide/core.h3
-rw-r--r--plugins/pychrysalide/format/format.c2
-rw-r--r--plugins/pychrysalide/gui/constants.c1
-rw-r--r--plugins/pychrysalide/gui/core/items.c35
-rw-r--r--plugins/pychrysalide/gui/core/panels.c65
-rw-r--r--plugins/pychrysalide/gui/item.c26
-rw-r--r--plugins/pychrysalide/gui/panel.c623
-rw-r--r--plugins/pychrysalide/helpers.c39
-rw-r--r--plugins/pychrysalide/helpers.h6
-rw-r--r--plugins/python/liveconv/panel.py14
-rw-r--r--plugins/python/liveconv/plugin.py4
12 files changed, 740 insertions, 129 deletions
diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index fad21bf..1ba738d 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -69,7 +69,8 @@
DEFINE_CHRYSALIDE_CONTAINER_PLUGIN("PyChrysalide", "Chrysalide bindings to Python",
PACKAGE_VERSION, CHRYSALIDE_WEBSITE("api/python/pychrysalide"),
- NO_REQ, AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT, PGA_NATIVE_LOADED));
+ NO_REQ, AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT,
+ PGA_NATIVE_LOADED, PGA_TYPE_BUILDING));
/* Note la nature du chargement */
@@ -894,6 +895,54 @@ G_MODULE_EXPORT void chrysalide_plugin_on_native_loaded(GPluginModule *plugin, P
/******************************************************************************
* *
+* Paramètres : plugin = greffon à manipuler. *
+* action = type d'action attendue. *
+* type = type d'objet à mettre en place. *
+* *
+* Description : Crée une instance à partir d'un type dynamique externe. *
+* *
+* Retour : Instance d'objet gérée par l'extension ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *plugin, PluginAction action, GType type)
+{
+ gpointer result; /* Instance à retourner */
+ PyThreadState *tstate; /* Contexte d'environnement */
+ PyTypeObject *pytype; /* Classe Python concernée */
+ PyObject *instance; /* Initialisation forcée */
+
+ result = NULL;
+
+ if (!_standalone)
+ {
+ tstate = get_pychrysalide_main_tstate();
+ PyEval_RestoreThread(tstate);
+ }
+
+ pytype = pygobject_lookup_class(type);
+
+ if (pytype != NULL)
+ {
+ instance = PyObject_CallObject((PyObject *)pytype, NULL);
+ assert(instance != NULL);
+
+ result = pygobject_get(instance);
+
+ }
+
+ if (!_standalone)
+ PyEval_SaveThread();
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : - *
* *
* Description : Fournit les informations du thread principal. *
diff --git a/plugins/pychrysalide/core.h b/plugins/pychrysalide/core.h
index 368a7c3..0f8b484 100644
--- a/plugins/pychrysalide/core.h
+++ b/plugins/pychrysalide/core.h
@@ -52,6 +52,9 @@ G_MODULE_EXPORT void chrysalide_plugin_exit(GPluginModule *);
/* Accompagne la fin du chargement des modules natifs. */
G_MODULE_EXPORT void chrysalide_plugin_on_native_loaded(GPluginModule *, PluginAction);
+/* Crée une instance à partir d'un type dynamique externe. */
+G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *, PluginAction, GType);
+
/* Fournit les informations du thread principal. */
PyThreadState *get_pychrysalide_main_tstate(void);
diff --git a/plugins/pychrysalide/format/format.c b/plugins/pychrysalide/format/format.c
index 6761392..66d346c 100644
--- a/plugins/pychrysalide/format/format.c
+++ b/plugins/pychrysalide/format/format.c
@@ -235,7 +235,7 @@ static int py_binary_format_init(PyObject *self, PyObject *args, PyObject *kwds)
" value indicating the endianness of the format.\n" \
"\n" \
"Calls to the *__init__* constructor of this abstract object expect"\
- " no particular argument.\n"
+ " no particular argument."
/* Initialisation d'un objet GLib */
diff --git a/plugins/pychrysalide/gui/constants.c b/plugins/pychrysalide/gui/constants.c
index 3cd943c..0930f41 100644
--- a/plugins/pychrysalide/gui/constants.c
+++ b/plugins/pychrysalide/gui/constants.c
@@ -53,6 +53,7 @@ bool define_panel_item_constants(PyTypeObject *type)
result = add_const_to_group(values, "INVALID", PIP_INVALID);
if (result) result = add_const_to_group(values, "SINGLETON", PIP_SINGLETON);
+ if (result) result = add_const_to_group(values, "PERSISTENT_SINGLETON", PIP_PERSISTENT_SINGLETON);
if (result) result = add_const_to_group(values, "BINARY_VIEW", PIP_BINARY_VIEW);
if (result) result = add_const_to_group(values, "OTHER", PIP_OTHER);
if (result) result = add_const_to_group(values, "COUNT", PIP_COUNT);
diff --git a/plugins/pychrysalide/gui/core/items.c b/plugins/pychrysalide/gui/core/items.c
index ce3eaee..95842fc 100644
--- a/plugins/pychrysalide/gui/core/items.c
+++ b/plugins/pychrysalide/gui/core/items.c
@@ -66,29 +66,36 @@ static PyObject *py_items_update_project(PyObject *, PyObject *);
* *
******************************************************************************/
-static PyObject *py_items_find_editor_item_by_key(PyObject *self, PyObject *args)
+static PyObject *py_items_find_editor_item_by_type(PyObject *self, PyObject *args)
{
PyObject *result; /* Trouvaille à retourner */
- const char *key; /* Objet des recherches */
+ GType type; /* Type d'élément à traiter */
int ret; /* Bilan de lecture des args. */
GEditorItem *found; /* Instance retrouvée ou NULL */
-#define ITEMS_FIND_EDITOR_ITEM_BY_KEY_METHOD PYTHON_METHOD_DEF \
-( \
- find_editor_item_by_key, "key", \
- METH_VARARGS, py_items, \
- "Find the editor component belonging to a given key." \
- "\n" \
- "The key has to be provided as a simple (short) string, and the" \
- " result is a pychrysalide.gui.EditorItem instance or None if no" \
- " component is found for the given key." \
+#define ITEMS_FIND_EDITOR_ITEM_BY_TYPE_METHOD PYTHON_METHOD_DEF \
+( \
+ find_editor_item_by_type, "cls", \
+ METH_VARARGS, py_items, \
+ "Find the editor component belonging to a given class." \
+ "\n" \
+ "The provided *cls* has to be an pychrysalide.gui.EditorItem" \
+ " derived class." \
+ "\n" \
+ "The result is an pychrysalide.gui.EditorItem instance or None" \
+ " if no component is found for the given key." \
)
- ret = PyArg_ParseTuple(args, "s", &key);
+ ret = PyArg_ParseTuple(args, "O&", convert_to_gtype, &type);
if (!ret) return NULL;
+ if (!g_type_is_a(type, G_TYPE_EDITOR_ITEM))
+ {
+ PyErr_SetString(PyExc_TypeError, "the argument must be a class derived from pychrysalide.gui.EditorItem");
+ return NULL;
+ }
- found = find_editor_item_by_key(key);
+ found = find_editor_item_by_type(type);
if (found == NULL)
{
@@ -276,7 +283,7 @@ bool populate_gui_core_module_with_items(void)
PyObject *module; /* Module à recompléter */
static PyMethodDef py_items_methods[] = {
- ITEMS_FIND_EDITOR_ITEM_BY_KEY_METHOD,
+ ITEMS_FIND_EDITOR_ITEM_BY_TYPE_METHOD,
ITEMS_CHANGE_CURRENT_CONTENT_METHOD,
ITEMS_CHANGE_CURRENT_VIEW_METHOD,
ITEMS_UPDATE_CURRENT_VIEW_METHOD,
diff --git a/plugins/pychrysalide/gui/core/panels.c b/plugins/pychrysalide/gui/core/panels.c
index 2a3c275..4fdc3f2 100644
--- a/plugins/pychrysalide/gui/core/panels.c
+++ b/plugins/pychrysalide/gui/core/panels.c
@@ -58,38 +58,59 @@ static PyObject *py_panels_register_panel(PyObject *, PyObject *);
static PyObject *py_panels_register_panel(PyObject *self, PyObject *args)
{
- GPanelItem *item; /* Panneau à traiter */
- GGenConfig *config; /* Configuration à consulter */
+ GType type; /* Type de panneau à traiter */
int ret; /* Bilan de lecture des args. */
-
-#define PANELS_REGISTER_PANEL_METHOD PYTHON_METHOD_DEF \
-( \
- register_panel, "panel", \
- METH_VARARGS, py_panels, \
- "Register a panel for the GUI." \
- "\n" \
- "The provided panel has to be a pychrysalide.gui.PanelItem" \
- " instance." \
+ PyObject *meta; /* Type _GObjectMetaBase */
+ PyObject *instance; /* Initialisation forcée */
+
+#define PANELS_REGISTER_PANEL_METHOD PYTHON_METHOD_DEF \
+( \
+ register_panel, "cls", \
+ METH_VARARGS, py_panels, \
+ "Register a panel class for the GUI." \
+ "\n" \
+ "The provided *cls* has to be a pychrysalide.gui.PanelItem" \
+ " derived class." \
)
- config = NULL;
+ ret = PyArg_ParseTuple(args, "O&", convert_to_gtype, &type);
+ if (!ret) return NULL;
+
+ if (!g_type_is_a(type, G_TYPE_PANEL_ITEM))
+ {
+ PyErr_SetString(PyExc_TypeError, "the argument must be a class derived from pychrysalide.gui.PanelItem");
+ return NULL;
+ }
+
+ /**
+ * Si la classe transmise n'a jamais été utilisée pour créer une instance,
+ * py_panel_item_new() n'a donc jamais été exécutée et le type dynamique
+ * associé au panneau n'a jamais été initialisé par Chrysalide.
+ *
+ * Cette création dynamique de type est donc forcée ici.
+ */
- ret = PyArg_ParseTuple(args, "O&", convert_to_panel_item, &item);
+ ret = PyArg_ParseTuple(args, "O", &meta);
if (!ret) return NULL;
- if (config == NULL)
- config = get_main_configuration();
+ instance = PyObject_CallObject(meta, NULL);
+
+ if (instance == NULL)
+ {
+ PyErr_SetString(PyExc_TypeError, "the argument must be a class derived from pychrysalide.gui.PanelItem");
+ return NULL;
+ }
- register_panel_item(item, config);
+ Py_DECREF(instance);
/**
- * Si Python ne voit plus la variable représentant le panneau utilisée,
- * il va la supprimer, ce qui va supprimer le composant GTK.
- *
- * On sera donc en situation de Use-After-Free, dont les conséquences
- * arrivent très vite.
+ * Rechargement du type, afin d'obtenir la version dynamique avec certitude.
*/
- pygobject_new(G_OBJECT(item));
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_gtype, &type);
+ if (!ret) return NULL;
+
+ register_panel_item(type, get_main_configuration());
Py_RETURN_NONE;
diff --git a/plugins/pychrysalide/gui/item.c b/plugins/pychrysalide/gui/item.c
index 2e32167..2046587 100644
--- a/plugins/pychrysalide/gui/item.c
+++ b/plugins/pychrysalide/gui/item.c
@@ -73,7 +73,7 @@
/* Fournit le nom interne attribué à l'élément réactif. */
-static char *py_editor_item_get_key_wrapper(const GEditorItem *);
+static char *py_editor_item_get_key_wrapper(const GEditorItemClass *);
/* Fournit le composant GTK associé à l'élément réactif. */
static GtkWidget *py_editor_item_get_widget_wrapper(const GEditorItem *);
@@ -141,7 +141,7 @@ void py_editor_item_init_gclass(GEditorItemClass *class, gpointer unused)
/******************************************************************************
* *
-* Paramètres : item = instance à consulter. *
+* Paramètres : class = classe à consulter. *
* *
* Description : Fournit le nom interne attribué à l'élément réactif. *
* *
@@ -151,31 +151,31 @@ void py_editor_item_init_gclass(GEditorItemClass *class, gpointer unused)
* *
******************************************************************************/
-static char *py_editor_item_get_key_wrapper(const GEditorItem *item)
+static char *py_editor_item_get_key_wrapper(const GEditorItemClass *class)
{
char *result; /* Désignation à retourner */
PyGILState_STATE gstate; /* Sauvegarde d'environnement */
- PyObject *pyobj; /* Objet Python concerné */
+ PyTypeObject *pytype; /* Classe Python concernée */
PyObject *pykey; /* Clef en objet Python */
int ret; /* Bilan d'une conversion */
#define EDITOR_ITEM_KEY_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \
( \
- _key, \
+ _key, \
"Provide the internal name to use for the editor item.\n" \
"\n" \
- "The result has to be a string." \
+ "The value has to be a string." \
)
result = NULL;
gstate = PyGILState_Ensure();
- pyobj = pygobject_new(G_OBJECT(item));
+ pytype = pygobject_lookup_class(G_TYPE_FROM_CLASS(class));
- if (PyObject_HasAttrString(pyobj, "_key"))
+ if (PyObject_HasAttrString((PyObject *)pytype, "_key"))
{
- pykey = PyObject_GetAttrString(pyobj, "_key");
+ pykey = PyObject_GetAttrString((PyObject *)pytype, "_key");
if (pykey != NULL)
{
@@ -190,8 +190,6 @@ static char *py_editor_item_get_key_wrapper(const GEditorItem *item)
}
- Py_DECREF(pyobj);
-
PyGILState_Release(gstate);
return result;
@@ -226,7 +224,7 @@ static GtkWidget *py_editor_item_get_widget_wrapper(const GEditorItem *item)
_widget, \
"Provide the Gtk widget base involved in the editor item.\n" \
"\n" \
- "The result has to be a Gtk.Widget instance." \
+ "The value has to be a Gtk.Widget instance." \
)
result = NULL;
@@ -574,11 +572,11 @@ static PyObject *py_editor_item_get_key(PyObject *self, void *closure)
#define EDITOR_ITEM_KEY_ATTRIB PYTHON_GET_DEF_FULL \
( \
key, py_editor_item, \
- "Internal name given to the editor item." \
+ "Internal string name given to the editor item." \
)
item = G_EDITOR_ITEM(pygobject_get(self));
- key = g_editor_item_get_key(item);
+ key = g_editor_item_class_get_key(G_EDITOR_ITEM_GET_CLASS(item));
if (key != NULL)
{
diff --git a/plugins/pychrysalide/gui/panel.c b/plugins/pychrysalide/gui/panel.c
index d9a2bc5..160a7a3 100644
--- a/plugins/pychrysalide/gui/panel.c
+++ b/plugins/pychrysalide/gui/panel.c
@@ -50,9 +50,24 @@
/* Accompagne la création d'une instance dérivée en Python. */
static PyObject *py_panel_item_new(PyTypeObject *, PyObject *, PyObject *);
-/* Initialise la classe des panneaux pour l'interface graphique. */
+/* Initialise la classe des panneaux graphiques de l'éditeur. */
static void py_panel_item_init_gclass(GPanelItemClass *, gpointer);
+/* Fournit une indication sur la personnalité du panneau. */
+static PanelItemPersonality py_panel_item_class_get_personality_wrapper(const GPanelItemClass *);
+
+/* Fournit une indication d'accroche du panneau au démarrage. */
+static bool py_panel_item_class_dock_at_startup_wrapper(const GPanelItemClass *);
+
+/* Détermine si un panneau peut être filtré. */
+static bool py_panel_item_class_can_search_wrapper(const GPanelItemClass *);
+
+/* Indique le chemin initial de la localisation d'un panneau. */
+static char *py_panel_item_class_get_path_wrapper(const GPanelItemClass *);
+
+/* Indique la définition d'un éventuel raccourci clavier. */
+static char *py_panel_item_class_get_key_bindings_wrapper(const GPanelItemClass *);
+
/* Initialise une instance sur la base du dérivé de GObject. */
static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds);
@@ -67,18 +82,30 @@ static PyObject *py_panel_item_dock(PyObject *, PyObject *);
/* Supprime un panneau de l'ensemble affiché. */
static PyObject *py_panel_item_undock(PyObject *, PyObject *);
-/* Fournit le chemin d'accès à utiliser pour les encapsulations. */
-static PyObject *py_panel_item_get_named_widget(PyObject *, void *);
-
/* Fournit une indication sur la personnalité du panneau. */
static PyObject *py_panel_item_get_personality(PyObject *, void *);
+/* Fournit une indication d'accroche du panneau au démarrage. */
+static PyObject *py_panel_item_get_dock_at_startup(PyObject *, void *);
+
+/* Définit si le composant repose sur un support de l'éditeur. */
+static int py_panel_item_set_dock_at_startup(PyObject *, PyObject *, void *);
+
+/* Détermine si un panneau peut être filtré. */
+static PyObject *py_panel_item_can_search(PyObject *, void *);
+
/* Fournit le chemin d'accès à utiliser pour les encapsulations. */
static PyObject *py_panel_item_get_path(PyObject *, void *);
/* Définit le chemin d'accès à utiliser pour les encapsulations. */
static int py_panel_item_set_path(PyObject *, PyObject *, void *);
+/* Indique la définition d'un éventuel raccourci clavier. */
+static PyObject *py_panel_item_get_key_bindings(PyObject *, void *);
+
+/* Fournit le chemin d'accès à utiliser pour les encapsulations. */
+static PyObject *py_panel_item_get_named_widget(PyObject *, void *);
+
/* Indique si le composant repose sur un support de l'éditeur. */
static PyObject *py_panel_item_get_docked(PyObject *, void *);
@@ -157,7 +184,7 @@ static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject
* Paramètres : class = classe à initialiser. *
* unused = données non utilisées ici. *
* *
-* Description : Initialise la classe des panneaux pour l'interface graphique.*
+* Description : Initialise la classe des panneaux graphiques de l'éditeur. *
* *
* Retour : - *
* *
@@ -169,6 +196,317 @@ static void py_panel_item_init_gclass(GPanelItemClass *class, gpointer unused)
{
py_editor_item_init_gclass(G_EDITOR_ITEM_CLASS(class), NULL);
+ class->get_personality = py_panel_item_class_get_personality_wrapper;
+ class->dock_at_startup = py_panel_item_class_dock_at_startup_wrapper;
+ class->can_search = py_panel_item_class_can_search_wrapper;
+ class->get_path = py_panel_item_class_get_path_wrapper;
+ class->get_bindings = py_panel_item_class_get_key_bindings_wrapper;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à consulter. *
+* *
+* Description : Fournit une indication sur la personnalité du panneau. *
+* *
+* Retour : Identifiant lié à la nature du panneau. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PanelItemPersonality py_panel_item_class_get_personality_wrapper(const GPanelItemClass *class)
+{
+ PanelItemPersonality result; /* Personnalité à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyTypeObject *pytype; /* Classe Python concernée */
+ PyObject *value; /* Valeur d'attribut en Python */
+ int ret; /* Bilan d'une conversion */
+
+#define PANEL_ITEM_PERSONALITY_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \
+( \
+ _personality, \
+ "Abstract attribute defining the initial rule for handling panel" \
+ " creation.\n" \
+ "\n" \
+ "The result has to be a pychrysalide.gui.PanelItem.PanelItemPersonality"\
+ " value.\n" \
+ "\n" \
+ "The default value is *PanelItem.PanelItemPersonality.SINGLETON*." \
+)
+
+ result = PIP_SINGLETON;
+
+ gstate = PyGILState_Ensure();
+
+ pytype = pygobject_lookup_class(G_TYPE_FROM_CLASS(class));
+
+ if (PyObject_HasAttrString((PyObject *)pytype, "_personality"))
+ {
+ value = PyObject_GetAttrString((PyObject *)pytype, "_personality");
+
+ if (value != NULL)
+ {
+ ret = convert_to_panel_item_personality(value, &result);
+
+ if (ret != 1)
+ {
+ PyErr_Clear();
+ result = PIP_OTHER;
+ }
+
+ Py_DECREF(value);
+
+ }
+
+ }
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à consulter. *
+* *
+* Description : Fournit une indication d'accroche du panneau au démarrage. *
+* *
+* Retour : true si le panneau doit être affiché de prime abord. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_panel_item_class_dock_at_startup_wrapper(const GPanelItemClass *class)
+{
+ bool result; /* Statut à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyTypeObject *pytype; /* Classe Python concernée */
+ PyObject *value; /* Valeur d'attribut en Python */
+ int ret; /* Bilan d'une conversion */
+
+#define PANEL_ITEM_DOCK_AT_STARTUP_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \
+( \
+ _dock_at_startup, \
+ "Abstract attribute defining if the panel should get docked" \
+ " automatically at startup.\n" \
+ "\n" \
+ "The value has to be a boolean value: *True* or *False*.\n" \
+ "\n" \
+ "The default value is *True*." \
+)
+
+ result = true;
+
+ gstate = PyGILState_Ensure();
+
+ pytype = pygobject_lookup_class(G_TYPE_FROM_CLASS(class));
+
+ if (PyObject_HasAttrString((PyObject *)pytype, "_dock_at_startup"))
+ {
+ value = PyObject_GetAttrString((PyObject *)pytype, "_dock_at_startup");
+
+ if (value != NULL)
+ {
+ ret = PyBool_Check(value);
+
+ if (ret)
+ result = (value == Py_True);
+
+ Py_DECREF(value);
+
+ }
+
+ }
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à consulter. *
+* *
+* Description : Détermine si un panneau peut être filtré. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool py_panel_item_class_can_search_wrapper(const GPanelItemClass *class)
+{
+ bool result; /* Statut à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyTypeObject *pytype; /* Classe Python concernée */
+ PyObject *value; /* Valeur d'attribut en Python */
+ int ret; /* Bilan d'une conversion */
+
+#define PANEL_ITEM_CAN_SEARCH_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \
+( \
+ _can_search, \
+ "Abstract attribute defining if the panel contains content which" \
+ " can get searched.\n" \
+ "\n" \
+ "The value has to be a boolean value: *True* or *False*.\n" \
+ "\n" \
+ "The default value is *False*." \
+)
+
+ result = false;
+
+ gstate = PyGILState_Ensure();
+
+ pytype = pygobject_lookup_class(G_TYPE_FROM_CLASS(class));
+
+ if (PyObject_HasAttrString((PyObject *)pytype, "_can_search"))
+ {
+ value = PyObject_GetAttrString((PyObject *)pytype, "_can_search");
+
+ if (value != NULL)
+ {
+ ret = PyBool_Check(value);
+
+ if (ret)
+ result = (value == Py_True);
+
+ Py_DECREF(value);
+
+ }
+
+ }
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à consulter. *
+* *
+* Description : Indique le chemin initial de la localisation d'un panneau. *
+* *
+* Retour : Chemin fixé associé à la position initiale. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *py_panel_item_class_get_path_wrapper(const GPanelItemClass *class)
+{
+ char *result; /* Désignation à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyTypeObject *pytype; /* Classe Python concernée */
+ PyObject *value; /* Valeur d'attribut en Python */
+ int ret; /* Bilan d'une conversion */
+
+#define PANEL_ITEM_PATH_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \
+( \
+ _path, \
+ "Abstract attribute used to provide the path to the initial" \
+ " location of the panel item.\n" \
+ "\n" \
+ "The value has to be a string." \
+)
+
+ result = NULL;
+
+ gstate = PyGILState_Ensure();
+
+ pytype = pygobject_lookup_class(G_TYPE_FROM_CLASS(class));
+
+ if (PyObject_HasAttrString((PyObject *)pytype, "_path"))
+ {
+ value = PyObject_GetAttrString((PyObject *)pytype, "_path");
+
+ if (value != NULL)
+ {
+ ret = PyUnicode_Check(value);
+
+ if (ret)
+ result = strdup(PyUnicode_AsUTF8(value));
+
+ Py_DECREF(value);
+
+ }
+
+ }
+
+ PyGILState_Release(gstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe à consulter. *
+* *
+* Description : Indique la définition d'un éventuel raccourci clavier. *
+* *
+* Retour : Description d'un raccourci ou NULL si aucun de défini. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static char *py_panel_item_class_get_key_bindings_wrapper(const GPanelItemClass *class)
+{
+ char *result; /* Désignation à retourner */
+ PyGILState_STATE gstate; /* Sauvegarde d'environnement */
+ PyTypeObject *pytype; /* Classe Python concernée */
+ PyObject *value; /* Valeur d'attribut en Python */
+ int ret; /* Bilan d'une conversion */
+
+#define PANEL_ITEM_BINDINGS_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \
+( \
+ _key_bindings, \
+ "Abstract attribute used to provide an optional key bindings as" \
+ " shortcuts for the panel item.\n" \
+ "\n" \
+ "The value has to be a string." \
+)
+
+ result = NULL;
+
+ gstate = PyGILState_Ensure();
+
+ pytype = pygobject_lookup_class(G_TYPE_FROM_CLASS(class));
+
+ if (PyObject_HasAttrString((PyObject *)pytype, "_key_bindings"))
+ {
+ value = PyObject_GetAttrString((PyObject *)pytype, "_key_bindings");
+
+ if (value != NULL)
+ {
+ ret = PyUnicode_Check(value);
+
+ if (ret)
+ result = strdup(PyUnicode_AsUTF8(value));
+
+ Py_DECREF(value);
+
+ }
+
+ }
+
+ PyGILState_Release(gstate);
+
+ return result;
+
}
@@ -188,55 +526,50 @@ static void py_panel_item_init_gclass(GPanelItemClass *class, gpointer unused)
static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds)
{
- PanelItemPersonality personality; /* Nature du panneau */
GNamedWidget *widget; /* Composant visuel du panneau */
- int startup; /* Recommandation au démarrage */
- const char *path; /* Placement à l'affichage */
int ret; /* Bilan de lecture des args. */
GPanelItem *panel; /* Panneau à manipuler */
- static char *kwlist[] = { "personality", "widget", "dock", "path", NULL };
-
#define PANEL_ITEM_DOC \
"PanelItem is an abstract class for panels available in the main GUI" \
" interface.\n" \
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
- " PanelItem(personality, widget, dock, path)" \
+ " PanelItem(widget)" \
"\n" \
"Where:\n" \
- "* personality defines how many instances of the panels can be created" \
- " at the same time.\n" \
"* widget is an implementation of the pychrysalide.glibext.NamedWidget" \
" interface (see pychrysalide.gtkext.BuiltNamedWidget for a ready-to-use" \
" helper).\n" \
- "* dock defines if the panel is docked by default.\n" \
- "* path states the location of the panel inside the main GUI.\n" \
- "\n" \
- "The easiest way to pass all this information is probably to use a" \
- " transitional dictionary inside the panel *__init__()* constructor:\n" \
- "\n" \
- " params = {\n" \
- " 'personality' : PanelItemPersonality.PIP_SINGLETON,\n" \
- " 'widget' : my_named_widget_instance,\n" \
- " 'dock' : True,\n" \
- " 'path' : 'MES'\n" \
- " }\n" \
- " super(MyPanel, self).__init__(**params)\n" \
"\n" \
"The PanelItem definition handles internally the supply of the *_widget*" \
" attribute for pychrysalide.gui.EditorItem.\n" \
"\n" \
+ "Several items have to be defined as class attribute in the final class:\n" \
+ "* pychrysalide.gui.PanelItem._path: path to the initial location of the" \
+ " panel item;\n" \
+ "* pychrysalide.gui.PanelItem._key_bindings: optional shortcut to show the" \
+ " relative panel.\n" \
+ "\n" \
+ "Some extra items offer default values and thus may be defined as class" \
+ " attribute in the final class:\n" \
+ "* pychrysalide.gui.PanelItem._personality: rule for the panel creation;\n" \
+ "* pychrysalide.gui.PanelItem._dock_at_startup: *True* if the panel should" \
+ " get docked automatically at startup;\n" \
+ "* pychrysalide.gui.PanelItem._can_search: True if the panel contains" \
+ " content which can get searched.\n" \
+ "\n" \
"For more details about the panel path, please refer to" \
- " pychrysalide.gtkext.GtkDockable."
+ " pychrysalide.gtkext.GtkDockable.\n" \
+ "\n" \
+ "Because panels aim to be created on demand by the Chrysalide core, calls" \
+ " to the *__init__* constructor of this abstract object must expect no" \
+ " particular argument."
/* Récupération des paramètres */
- ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&O&ps", kwlist,
- convert_to_panel_item_personality, &personality,
- convert_to_named_widget, &widget,
- &startup, &path);
+ ret = PyArg_ParseTuple(args, "O&", convert_to_named_widget, &widget);
if (!ret) return -1;
/* Initialisation d'un objet GLib */
@@ -248,8 +581,6 @@ static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds)
panel = G_PANEL_ITEM(pygobject_get(self));
- panel->personality = personality;
-
/**
* Si Python ne voit plus la variable représentant le panneau utilisée,
* il va la supprimer, ce qui va supprimer le composant GTK.
@@ -260,9 +591,6 @@ static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds)
panel->widget = widget;
g_object_ref(G_OBJECT(widget));
- panel->dock_at_startup = startup;
- panel->path = strdup(path);
-
return 0;
}
@@ -345,32 +673,31 @@ static PyObject *py_panel_item_undock(PyObject *self, PyObject *args)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit le chemin d'accès à utiliser pour les encapsulations.*
+* Description : Fournit une indication sur la personnalité du panneau. *
* *
-* Retour : Chemin d'accès défini. *
+* Retour : Identifiant lié à la nature du panneau. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_panel_item_get_named_widget(PyObject *self, void *closure)
+static PyObject *py_panel_item_get_personality(PyObject *self, void *closure)
{
PyObject *result; /* Valeur à retourner */
GPanelItem *item; /* Panneau à consulter */
- GNamedWidget *widget; /* Composant nommé à transférer*/
+ PanelItemPersonality personality; /* Valeur native à convertir */
-#define PANEL_ITEM_NAMED_WIDGET_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- named_widget, py_panel_item, \
- "Named widget as core component of the panel item." \
+#define PANEL_ITEM_PERSONALITY_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ personality, py_panel_item, \
+ "Rule for handling panel creations, as a" \
+ " pychrysalide.gui.PanelItem.PanelItemPersonality value." \
)
item = G_PANEL_ITEM(pygobject_get(self));
- widget = gtk_panel_item_get_named_widget(item);
-
- result = pygobject_new(G_OBJECT(widget));
+ personality = gtk_panel_item_class_get_personality(G_PANEL_ITEM_GET_CLASS(item));
- g_object_unref(G_OBJECT(widget));
+ result = cast_with_constants_group_from_type(get_python_panel_item_type(), "PanelItemPersonality", personality);
return result;
@@ -382,31 +709,102 @@ static PyObject *py_panel_item_get_named_widget(PyObject *self, void *closure)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit une indication sur la personnalité du panneau. *
+* Description : Fournit une indication d'accroche du panneau au démarrage. *
* *
-* Retour : Identifiant lié à la nature du panneau. *
+* Retour : True si le panneau doit être affiché de prime abord. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_panel_item_get_personality(PyObject *self, void *closure)
+static PyObject *py_panel_item_get_dock_at_startup(PyObject *self, void *closure)
{
PyObject *result; /* Valeur à retourner */
GPanelItem *item; /* Panneau à consulter */
- PanelItemPersonality personality; /* Valeur native à convertir */
+ bool state; /* Indication d'ancrage */
+
+#define PANEL_ITEM_DOCK_AT_STARTUP_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ dock_at_startup, py_panel_item, \
+ "Tell or define if the panel should get docked automatically at" \
+ " startup.\n" \
+ "\n" \
+ "This state is a boolean value: *True* or *False*." \
+)
-#define PANEL_ITEM_PERSONALITY_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- personality, py_panel_item, \
- "Rule for handling panel creations, as a" \
- " pychrysalide.gui.PanelItem.PanelItemPersonality value." \
+ item = G_PANEL_ITEM(pygobject_get(self));
+ state = gtk_panel_item_class_dock_at_startup(G_PANEL_ITEM_GET_CLASS(item));
+
+ result = state ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* value = valeur fournie à intégrer ou prendre en compte. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Définit si le composant repose sur un support de l'éditeur. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_panel_item_set_dock_at_startup(PyObject *self, PyObject *value, void *closure)
+{
+ GPanelItem *item; /* Panneau à manipuler */
+
+ if (!PyBool_Check(value))
+ return -1;
+
+ item = G_PANEL_ITEM(pygobject_get(self));
+
+ g_panel_item_set_dock_at_startup(item, value == Py_True);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Détermine si un panneau peut être filtré. *
+* *
+* Retour : Bilan de la consultation. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_panel_item_can_search(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GPanelItem *item; /* Panneau à consulter */
+ bool status; /* Capacité de recherche */
+
+#define PANEL_ITEM_CAN_SEARCH_ATTRIB PYTHON_CAN_DEF_FULL \
+( \
+ search, py_panel_item, \
+ "Define if the panel contains content which can get searched.\n" \
+ "\n" \
+ "The result is a boolean value: *True* or *False*.\n" \
)
item = G_PANEL_ITEM(pygobject_get(self));
- personality = gtk_panel_item_get_personality(item);
+ status = gtk_panel_item_class_can_search(G_PANEL_ITEM_GET_CLASS(item));
- result = cast_with_constants_group_from_type(get_python_panel_item_type(), "PanelItemPersonality", personality);
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
return result;
@@ -430,19 +828,23 @@ static PyObject *py_panel_item_get_path(PyObject *self, void *closure)
{
PyObject *result; /* Valeur à retourner */
GPanelItem *item; /* Panneau à consulter */
- const char *path; /* Chemin d'accès courant */
+ char *path; /* Chemin d'accès courant */
#define PANEL_ITEM_PATH_ATTRIB PYTHON_GETSET_DEF_FULL \
( \
path, py_panel_item, \
"Get or define the current path of the panel item." \
+ "\n" \
+ "The path is defined as a string." \
)
item = G_PANEL_ITEM(pygobject_get(self));
- path = gtk_panel_item_get_path(item);
+ path = gtk_panel_item_class_get_path(G_PANEL_ITEM_GET_CLASS(item));
result = PyUnicode_FromString(path);
+ free(path);
+
return result;
}
@@ -486,6 +888,91 @@ static int py_panel_item_set_path(PyObject *self, PyObject *value, void *closure
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
+* Description : Indique la définition d'un éventuel raccourci clavier. *
+* *
+* Retour : Description d'un raccourci ou None si aucun de défini. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_panel_item_get_key_bindings(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GPanelItem *item; /* Panneau à consulter */
+ char *bindings; /* Raccourci clavier éventuel */
+
+#define PANEL_ITEM_KEY_BINDINGS_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ key_bindings, py_panel_item, \
+ "Shortcuts for displaying the panel, as a string, or *None* if" \
+ " no binding is defined." \
+)
+
+ item = G_PANEL_ITEM(pygobject_get(self));
+ bindings = gtk_panel_item_class_get_key_bindings(G_PANEL_ITEM_GET_CLASS(item));
+
+ if (bindings != NULL)
+ {
+ result = PyUnicode_FromString(bindings);
+ free(bindings);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit le chemin d'accès à utiliser pour les encapsulations.*
+* *
+* Retour : Chemin d'accès défini. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_panel_item_get_named_widget(PyObject *self, void *closure)
+{
+ PyObject *result; /* Valeur à retourner */
+ GPanelItem *item; /* Panneau à consulter */
+ GNamedWidget *widget; /* Composant nommé à transférer*/
+
+#define PANEL_ITEM_NAMED_WIDGET_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ named_widget, py_panel_item, \
+ "Named widget as core component of the panel item.\n" \
+ "\n" \
+ "The result is an implementation of the" \
+ " pychrysalide.glibext.NamedWidget interface." \
+)
+
+ item = G_PANEL_ITEM(pygobject_get(self));
+ widget = gtk_panel_item_get_named_widget(item);
+
+ result = pygobject_new(G_OBJECT(widget));
+
+ g_object_unref(G_OBJECT(widget));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
* Description : Indique si le composant repose sur un support de l'éditeur. *
* *
* Retour : True si le composant est bien incrusté quelque part. *
@@ -503,7 +990,9 @@ static PyObject *py_panel_item_get_docked(PyObject *self, void *closure)
#define PANEL_ITEM_DOCKED_ATTRIB PYTHON_GET_DEF_FULL \
( \
docked, py_panel_item, \
- "Dock status of the panel item." \
+ "Dock status of the panel item.\n" \
+ "\n" \
+ "The result is a boolean value: *True* or *False*." \
)
item = G_PANEL_ITEM(pygobject_get(self));
@@ -538,9 +1027,17 @@ PyTypeObject *get_python_panel_item_type(void)
};
static PyGetSetDef py_panel_item_getseters[] = {
- PANEL_ITEM_NAMED_WIDGET_ATTRIB,
+ PANEL_ITEM_PERSONALITY_ATTRIB_WRAPPER,
+ PANEL_ITEM_DOCK_AT_STARTUP_ATTRIB_WRAPPER,
+ PANEL_ITEM_CAN_SEARCH_ATTRIB_WRAPPER,
+ PANEL_ITEM_PATH_ATTRIB_WRAPPER,
+ PANEL_ITEM_BINDINGS_ATTRIB_WRAPPER,
PANEL_ITEM_PERSONALITY_ATTRIB,
+ PANEL_ITEM_DOCK_AT_STARTUP_ATTRIB,
+ PANEL_ITEM_CAN_SEARCH_ATTRIB,
PANEL_ITEM_PATH_ATTRIB,
+ PANEL_ITEM_KEY_BINDINGS_ATTRIB,
+ PANEL_ITEM_NAMED_WIDGET_ATTRIB,
PANEL_ITEM_DOCKED_ATTRIB,
{ NULL }
};
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index 870035d..894b600 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -1129,6 +1129,45 @@ int forward_pygobjet_init(PyObject *self)
* Paramètres : arg = argument quelconque à tenter de convertir. *
* dst = destination des valeurs récupérées en cas de succès. *
* *
+* Description : Tente de convertir en valeur GType. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_gtype(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+ GType type; /* Type obtenu ou 0 */
+
+ type = pyg_type_from_object(arg);
+
+ switch (type)
+ {
+ case G_TYPE_INVALID:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ default:
+ *((GType *)dst) = type;
+ result = 1;
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : arg = argument quelconque à tenter de convertir. *
+* dst = destination des valeurs récupérées en cas de succès. *
+* *
* Description : Tente de convertir en instance GObject. *
* *
* Retour : Bilan de l'opération, voire indications supplémentaires. *
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index 428cf92..522986f 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -134,6 +134,9 @@ bool register_python_module_object(PyObject *, PyTypeObject *);
closure \
}
+#define PYTHON_CAN_DEF_FULL(name, base, doc) \
+ PYTHON_GETSET_DEF("can_" #name, base ## _can_ ## name, NULL, ATTRIB_RO doc, NULL)
+
#define PYTHON_IS_DEF_FULL(name, base, doc) \
PYTHON_GETSET_DEF("is_" #name, base ## _is_ ## name, NULL, ATTRIB_RO doc, NULL)
@@ -223,6 +226,9 @@ bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *)
/* Fait suivre à la partie GObject une initialisation nouvelle. */
int forward_pygobjet_init(PyObject *);
+/* Tente de convertir en valeur GType. */
+int convert_to_gtype(PyObject *, void *);
+
/* Tente de convertir en instance GObject. */
int convert_to_gobject(PyObject *, void *);
diff --git a/plugins/python/liveconv/panel.py b/plugins/python/liveconv/panel.py
index 6503b7b..6d308d6 100644
--- a/plugins/python/liveconv/panel.py
+++ b/plugins/python/liveconv/panel.py
@@ -13,6 +13,8 @@ class ConvPanel(PanelItem):
_key = 'liveconv'
+ _path = 'MES'
+
def __init__(self):
"""Initialize the GUI panel."""
@@ -22,17 +24,7 @@ class ConvPanel(PanelItem):
widget = BuiltNamedWidget('Converter', 'Data live converter', filename)
- params = {
-
- 'personality' : PanelItem.PanelItemPersonality.SINGLETON,
- 'widget' : widget,
-
- 'dock' : True,
- 'path' : 'MES'
-
- }
-
- super(ConvPanel, self).__init__(**params)
+ super(ConvPanel, self).__init__(widget)
self._conversions = {
diff --git a/plugins/python/liveconv/plugin.py b/plugins/python/liveconv/plugin.py
index eadbea0..8caeb17 100644
--- a/plugins/python/liveconv/plugin.py
+++ b/plugins/python/liveconv/plugin.py
@@ -21,6 +21,4 @@ class LiveConverter(PluginModule):
super(LiveConverter, self).__init__()
- p = ConvPanel()
-
- core.register_panel(p)
+ core.register_panel(ConvPanel)