diff options
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/pychrysalide/core.c | 51 | ||||
-rw-r--r-- | plugins/pychrysalide/core.h | 3 | ||||
-rw-r--r-- | plugins/pychrysalide/format/format.c | 2 | ||||
-rw-r--r-- | plugins/pychrysalide/gui/constants.c | 1 | ||||
-rw-r--r-- | plugins/pychrysalide/gui/core/items.c | 35 | ||||
-rw-r--r-- | plugins/pychrysalide/gui/core/panels.c | 65 | ||||
-rw-r--r-- | plugins/pychrysalide/gui/item.c | 26 | ||||
-rw-r--r-- | plugins/pychrysalide/gui/panel.c | 623 | ||||
-rw-r--r-- | plugins/pychrysalide/helpers.c | 39 | ||||
-rw-r--r-- | plugins/pychrysalide/helpers.h | 6 | ||||
-rw-r--r-- | plugins/python/liveconv/panel.py | 14 | ||||
-rw-r--r-- | plugins/python/liveconv/plugin.py | 4 |
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) |