[gnome-builder/wip/chergert/layout] more incremental work rebasing the new editor design
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/layout] more incremental work rebasing the new editor design
- Date: Wed, 28 Jun 2017 01:07:10 +0000 (UTC)
commit becc075a14d8d5f87d33a8dc5d8b86e3ed2c371b
Author: Christian Hergert <chergert redhat com>
Date: Tue Jun 27 18:06:54 2017 -0700
more incremental work rebasing the new editor design
libide/editor/ide-editor-view-settings.c | 31 +++++
libide/editor/ide-editor-view.c | 124 +++++++++++++------
libide/editor/ide-editor-view.h | 5 +-
libide/editor/ide-editor-view.ui | 1 +
libide/editor/ide-editor-workbench-addin.c | 98 +++++++++++++---
libide/layout/ide-layout-view.c | 6 +
libide/plugins/ide-extension-set-adapter.h | 34 +++---
libide/plugins/ide-extension-util.c | 6 +
plugins/html-preview/html-preview.plugin | 1 +
.../html-preview/html_preview_plugin/__init__.py | 2 +-
10 files changed, 230 insertions(+), 78 deletions(-)
---
diff --git a/libide/editor/ide-editor-view-settings.c b/libide/editor/ide-editor-view-settings.c
index 7c32684..45eb227 100644
--- a/libide/editor/ide-editor-view-settings.c
+++ b/libide/editor/ide-editor-view-settings.c
@@ -47,6 +47,25 @@ get_wrap_mode (GValue *value,
return TRUE;
}
+static void
+on_keybindings_changed (IdeEditorView *self,
+ const gchar *key,
+ GSettings *settings)
+{
+ IdeSourceView *source_view;
+
+ g_assert (IDE_IS_EDITOR_VIEW (self));
+ g_assert (g_strcmp0 (key, "keybindings") == 0);
+ g_assert (G_IS_SETTINGS (settings));
+
+ source_view = ide_editor_view_get_view (self);
+
+ g_signal_emit_by_name (source_view,
+ "set-mode",
+ NULL,
+ IDE_SOURCE_VIEW_MODE_TYPE_PERMANENT);
+}
+
void
_ide_editor_view_init_settings (IdeEditorView *self)
{
@@ -87,6 +106,10 @@ _ide_editor_view_init_settings (IdeEditorView *self)
G_SETTINGS_BIND_GET,
get_smart_home_end, NULL, NULL, NULL);
+ g_settings_bind (editor_settings, "style-scheme-name",
+ buffer, "style-scheme-name",
+ G_SETTINGS_BIND_GET);
+
g_settings_bind (editor_settings, "font-name",
source_view, "font-name",
G_SETTINGS_BIND_GET);
@@ -116,6 +139,14 @@ _ide_editor_view_init_settings (IdeEditorView *self)
self, "auto-hide-map",
G_SETTINGS_BIND_GET);
+ g_signal_connect_object (editor_settings,
+ "changed::keybindings",
+ G_CALLBACK (on_keybindings_changed),
+ self,
+ G_CONNECT_SWAPPED);
+
+ on_keybindings_changed (self, "keybindings", editor_settings);
+
if (insight_settings == NULL)
insight_settings = g_settings_new ("org.gnome.builder.code-insight");
diff --git a/libide/editor/ide-editor-view.c b/libide/editor/ide-editor-view.c
index 2fccfd4..f1fe964 100644
--- a/libide/editor/ide-editor-view.c
+++ b/libide/editor/ide-editor-view.c
@@ -21,26 +21,28 @@
#include <dazzle.h>
#include <libpeas/peas.h>
-#include "ide-editor-private.h"
-#include "ide-editor-search-bar.h"
-#include "ide-editor-view.h"
-#include "ide-editor-view-addin.h"
+#include "editor/ide-editor-private.h"
+#include "editor/ide-editor-search-bar.h"
+#include "editor/ide-editor-view.h"
+#include "editor/ide-editor-view-addin.h"
+#include "plugins/ide-extension-set-adapter.h"
+#include "util/ide-gtk.h"
struct _IdeEditorView
{
- IdeLayoutView parent_instance;
+ IdeLayoutView parent_instance;
- PeasExtensionSet *addins;
+ IdeExtensionSetAdapter *addins;
- IdeBuffer *buffer;
- DzlBindingGroup *buffer_bindings;
- DzlSignalGroup *buffer_signals;
+ IdeBuffer *buffer;
+ DzlBindingGroup *buffer_bindings;
+ DzlSignalGroup *buffer_signals;
- GtkOverlay *overlay;
- IdeSourceView *source_view;
- GtkScrolledWindow *scroller;
- IdeEditorSearchBar *search_bar;
- GtkRevealer *search_revealer;
+ GtkOverlay *overlay;
+ IdeSourceView *source_view;
+ GtkScrolledWindow *scroller;
+ IdeEditorSearchBar *search_bar;
+ GtkRevealer *search_revealer;
};
enum {
@@ -137,14 +139,14 @@ ide_editor_view_buffer_modified_changed (IdeEditorView *self,
}
static void
-ide_editor_view_buffer_notify_language_cb (PeasExtensionSet *set,
- PeasPluginInfo *plugin_info,
- PeasExtension *exten,
- gpointer user_data)
+ide_editor_view_buffer_notify_language_cb (IdeExtensionSetAdapter *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
{
const gchar *language_id = user_data;
- g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
g_assert (plugin_info != NULL);
g_assert (IDE_IS_EDITOR_VIEW_ADDIN (exten));
@@ -168,9 +170,11 @@ ide_editor_view_buffer_notify_language (IdeEditorView *self,
if (NULL != (language = gtk_source_buffer_get_language (buffer)))
language_id = gtk_source_language_get_id (language);
- peas_extension_set_foreach (self->addins,
- ide_editor_view_buffer_notify_language_cb,
- (gpointer)language_id);
+ ide_extension_set_adapter_set_value (self->addins, language_id);
+
+ ide_extension_set_adapter_foreach (self->addins,
+ ide_editor_view_buffer_notify_language_cb,
+ (gpointer)language_id);
}
static void
@@ -194,7 +198,12 @@ ide_editor_view_set_buffer (IdeEditorView *self,
g_assert (!buffer || IDE_IS_BUFFER (buffer));
if (g_set_object (&self->buffer, buffer))
- dzl_signal_group_set_target (self->buffer_signals, buffer);
+ {
+ dzl_signal_group_set_target (self->buffer_signals, buffer);
+ dzl_binding_group_set_source (self->buffer_bindings, buffer);
+ gtk_text_view_set_buffer (GTK_TEXT_VIEW (self->source_view),
+ GTK_TEXT_BUFFER (buffer));
+ }
}
static IdeLayoutView *
@@ -211,14 +220,14 @@ ide_editor_view_create_split_view (IdeLayoutView *view)
}
static void
-ide_editor_view_addin_added (PeasExtensionSet *set,
- PeasPluginInfo *plugin_info,
- PeasExtension *exten,
- gpointer user_data)
+ide_editor_view_addin_added (IdeExtensionSetAdapter *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
{
IdeEditorView *self = user_data;
- g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
g_assert (plugin_info != NULL);
g_assert (IDE_IS_EDITOR_VIEW_ADDIN (exten));
g_assert (IDE_IS_EDITOR_VIEW (self));
@@ -227,14 +236,14 @@ ide_editor_view_addin_added (PeasExtensionSet *set,
}
static void
-ide_editor_view_addin_removed (PeasExtensionSet *set,
- PeasPluginInfo *plugin_info,
- PeasExtension *exten,
- gpointer user_data)
+ide_editor_view_addin_removed (IdeExtensionSetAdapter *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
{
IdeEditorView *self = user_data;
- g_assert (PEAS_IS_EXTENSION_SET (set));
+ g_assert (IDE_IS_EXTENSION_SET_ADAPTER (set));
g_assert (plugin_info != NULL);
g_assert (IDE_IS_EDITOR_VIEW_ADDIN (exten));
g_assert (IDE_IS_EDITOR_VIEW (self));
@@ -247,15 +256,24 @@ ide_editor_view_hierarchy_changed (GtkWidget *widget,
GtkWidget *old_toplevel)
{
IdeEditorView *self = (IdeEditorView *)widget;
+ IdeContext *context;
g_assert (IDE_IS_EDITOR_VIEW (self));
g_assert (!old_toplevel || GTK_IS_WIDGET (old_toplevel));
- GTK_WIDGET_CLASS (ide_editor_view_parent_class)->hierarchy_changed (widget, old_toplevel);
+ /* Make sure we chain up if things change in the future */
+ if (GTK_WIDGET_CLASS (ide_editor_view_parent_class)->hierarchy_changed)
+ GTK_WIDGET_CLASS (ide_editor_view_parent_class)->hierarchy_changed (widget, old_toplevel);
- if (self->addins == NULL)
+ context = ide_widget_get_context (GTK_WIDGET (self));
+
+ if (context != NULL && self->addins == NULL)
{
- self->addins = peas_extension_set_new (NULL, IDE_TYPE_EDITOR_VIEW_ADDIN, NULL);
+ self->addins = ide_extension_set_adapter_new (context,
+ peas_engine_get_default (),
+ IDE_TYPE_EDITOR_VIEW_ADDIN,
+ "Editor-View-Languages",
+ ide_editor_view_get_language_id (self));
g_signal_connect (self->addins,
"extension-added",
@@ -267,9 +285,9 @@ ide_editor_view_hierarchy_changed (GtkWidget *widget,
G_CALLBACK (ide_editor_view_addin_removed),
self);
- peas_extension_set_foreach (self->addins,
- ide_editor_view_addin_added,
- self);
+ ide_extension_set_adapter_foreach (self->addins,
+ ide_editor_view_addin_added,
+ self);
}
}
@@ -487,3 +505,31 @@ ide_editor_view_get_view (IdeEditorView *self)
return self->source_view;
}
+
+/**
+ * ide_editor_view_get_language_id:
+ * @self: a #IdeEditorView
+ *
+ * This is a helper to get the language-id of the underlying buffer.
+ *
+ * Returns: (nullable): the language-id as a string, or %NULL
+ *
+ * Since: 3.26
+ */
+const gchar *
+ide_editor_view_get_language_id (IdeEditorView *self)
+{
+ g_return_val_if_fail (IDE_IS_EDITOR_VIEW (self), NULL);
+
+ if (self->buffer != NULL)
+ {
+ GtkSourceLanguage *language;
+
+ language = gtk_source_buffer_get_language (GTK_SOURCE_BUFFER (self->buffer));
+
+ if (language != NULL)
+ return gtk_source_language_get_id (language);
+ }
+
+ return NULL;
+}
diff --git a/libide/editor/ide-editor-view.h b/libide/editor/ide-editor-view.h
index d7243fe..e64c031 100644
--- a/libide/editor/ide-editor-view.h
+++ b/libide/editor/ide-editor-view.h
@@ -30,7 +30,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeEditorView, ide_editor_view, IDE, EDITOR_VIEW, IdeLayoutView)
-IdeBuffer *ide_editor_view_get_buffer (IdeEditorView *self);
-IdeSourceView *ide_editor_view_get_view (IdeEditorView *self);
+IdeBuffer *ide_editor_view_get_buffer (IdeEditorView *self);
+IdeSourceView *ide_editor_view_get_view (IdeEditorView *self);
+const gchar *ide_editor_view_get_language_id (IdeEditorView *self);
G_END_DECLS
diff --git a/libide/editor/ide-editor-view.ui b/libide/editor/ide-editor-view.ui
index f774973..f236815 100644
--- a/libide/editor/ide-editor-view.ui
+++ b/libide/editor/ide-editor-view.ui
@@ -20,6 +20,7 @@
</child>
<child>
<object class="GtkScrolledWindow" id="scroller">
+ <property name="expand">true</property>
<property name="visible">true</property>
<child>
<object class="IdeSourceView" id="source_view">
diff --git a/libide/editor/ide-editor-workbench-addin.c b/libide/editor/ide-editor-workbench-addin.c
index 7c8b7b8..44d943d 100644
--- a/libide/editor/ide-editor-workbench-addin.c
+++ b/libide/editor/ide-editor-workbench-addin.c
@@ -38,11 +38,13 @@ struct _IdeEditorWorkbenchAddin
{
GObject parent_instance;
- IdeWorkbench *workbench;
-
+ /* Owned references */
+ DzlSignalGroup *buffer_manager_signals;
DzlDockManager *manager;
- IdeEditorPerspective *perspective;
+ /* Borrowed references */
+ IdeWorkbench *workbench;
+ IdeEditorPerspective *perspective;
GtkWidget *new_document_button;
};
@@ -59,20 +61,66 @@ G_DEFINE_TYPE_EXTENDED (IdeEditorWorkbenchAddin, ide_editor_workbench_addin, G_T
ide_workbench_addin_iface_init))
static void
-open_file_task_data_free (OpenFileTaskData *open_file_task_data)
+open_file_task_data_free (gpointer data)
+{
+ OpenFileTaskData *td = data;
+
+ ide_uri_unref (td->uri);
+ g_slice_free (OpenFileTaskData, td);
+}
+
+static void
+ide_editor_workbench_addin_on_load_buffer (IdeEditorWorkbenchAddin *self,
+ IdeBuffer *buffer,
+ gboolean create_new_view,
+ IdeBufferManager *buffer_manager)
+{
+ g_assert (IDE_IS_EDITOR_WORKBENCH_ADDIN (self));
+ g_assert (IDE_IS_BUFFER (buffer));
+ g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
+
+ /*
+ * We only want to create a new view when the buffer is originally
+ * created, not when it's reloaded.
+ */
+ if (!create_new_view)
+ {
+ ide_buffer_manager_set_focus_buffer (buffer_manager, buffer);
+ return;
+ }
+
+ IDE_TRACE_MSG ("Loading %s", ide_buffer_get_title (buffer));
+
+ ide_editor_perspective_focus_buffer_in_current_stack (self->perspective, buffer);
+}
+
+static void
+ide_editor_workbench_addin_finalize (GObject *object)
{
- ide_uri_unref (open_file_task_data->uri);
- g_slice_free (OpenFileTaskData, open_file_task_data);
+ IdeEditorWorkbenchAddin *self = (IdeEditorWorkbenchAddin *)object;
+
+ g_clear_object (&self->buffer_manager_signals);
+
+ G_OBJECT_CLASS (ide_editor_workbench_addin_parent_class)->finalize (object);
}
static void
ide_editor_workbench_addin_class_init (IdeEditorWorkbenchAddinClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_editor_workbench_addin_finalize;
}
static void
-ide_editor_workbench_addin_init (IdeEditorWorkbenchAddin *addin)
+ide_editor_workbench_addin_init (IdeEditorWorkbenchAddin *self)
{
+ self->buffer_manager_signals = dzl_signal_group_new (IDE_TYPE_BUFFER_MANAGER);
+
+ dzl_signal_group_connect_swapped (self->buffer_manager_signals,
+ "load-buffer",
+ G_CALLBACK (ide_editor_workbench_addin_on_load_buffer),
+ self);
}
static void
@@ -81,14 +129,22 @@ ide_editor_workbench_addin_load (IdeWorkbenchAddin *addin,
{
IdeEditorWorkbenchAddin *self = (IdeEditorWorkbenchAddin *)addin;
IdeWorkbenchHeaderBar *header;
+ IdeBufferManager *buffer_manager;
+ IdeContext *context;
g_assert (IDE_IS_EDITOR_WORKBENCH_ADDIN (self));
g_assert (IDE_IS_WORKBENCH (workbench));
+ g_assert (self->manager == NULL);
+ g_assert (self->workbench == NULL);
self->workbench = workbench;
-
self->manager = dzl_dock_manager_new ();
+ context = ide_workbench_get_context (workbench);
+ buffer_manager = ide_context_get_buffer_manager (context);
+
+ dzl_signal_group_set_target (self->buffer_manager_signals, buffer_manager);
+
header = ide_workbench_get_headerbar (workbench);
self->new_document_button = g_object_new (GTK_TYPE_BUTTON,
@@ -98,8 +154,11 @@ ide_editor_workbench_addin_load (IdeWorkbenchAddin *addin,
"icon-name", "document-new-symbolic",
NULL),
NULL);
+ g_signal_connect (self->new_document_button,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &self->new_document_button);
dzl_gtk_widget_add_style_class (self->new_document_button, "image-button");
-
ide_workbench_header_bar_insert_left (header,
self->new_document_button,
GTK_PACK_START,
@@ -109,7 +168,10 @@ ide_editor_workbench_addin_load (IdeWorkbenchAddin *addin,
"manager", self->manager,
"visible", TRUE,
NULL);
-
+ g_signal_connect (self->perspective,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &self->perspective);
ide_workbench_add_perspective (workbench, IDE_PERSPECTIVE (self->perspective));
}
@@ -118,21 +180,19 @@ ide_editor_workbench_addin_unload (IdeWorkbenchAddin *addin,
IdeWorkbench *workbench)
{
IdeEditorWorkbenchAddin *self = (IdeEditorWorkbenchAddin *)addin;
- IdePerspective *perspective;
g_assert (IDE_IS_EDITOR_WORKBENCH_ADDIN (self));
g_assert (IDE_IS_WORKBENCH (workbench));
- gtk_widget_destroy (self->new_document_button);
+ dzl_signal_group_set_target (self->buffer_manager_signals, NULL);
+ gtk_widget_destroy (GTK_WIDGET (self->new_document_button));
+ gtk_widget_destroy (GTK_WIDGET (self->perspective));
+ g_clear_object (&self->manager);
- perspective = IDE_PERSPECTIVE (self->perspective);
- self->perspective = NULL;
+ g_assert (self->new_document_button == NULL);
+ g_assert (self->perspective == NULL);
self->workbench = NULL;
-
- ide_workbench_remove_perspective (workbench, perspective);
-
- g_clear_object (&self->manager);
}
static gboolean
@@ -258,7 +318,7 @@ ide_editor_workbench_addin_open_async (IdeWorkbenchAddin *addin,
open_file_task_data = g_slice_new (OpenFileTaskData);
open_file_task_data->flags = flags;
open_file_task_data->uri = ide_uri_ref(uri);
- g_task_set_task_data (task, open_file_task_data, (GDestroyNotify)open_file_task_data_free);
+ g_task_set_task_data (task, open_file_task_data, open_file_task_data_free);
context = ide_workbench_get_context (self->workbench);
buffer_manager = ide_context_get_buffer_manager (context);
diff --git a/libide/layout/ide-layout-view.c b/libide/layout/ide-layout-view.c
index 3bcae94..50f4677 100644
--- a/libide/layout/ide-layout-view.c
+++ b/libide/layout/ide-layout-view.c
@@ -265,10 +265,16 @@ static void
ide_layout_view_init (IdeLayoutView *self)
{
IdeLayoutViewPrivate *priv = ide_layout_view_get_instance_private (self);
+ g_autoptr(GSimpleActionGroup) group = g_simple_action_group_new ();
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
priv->icon_name = g_intern_string ("text-x-generic-symbolic");
+
+ /* Add an action group out of convenience to plugins that want to
+ * stash a simple action somewhere.
+ */
+ gtk_widget_insert_action_group (GTK_WIDGET (self), "view", G_ACTION_GROUP (group));
}
GtkWidget *
diff --git a/libide/plugins/ide-extension-set-adapter.h b/libide/plugins/ide-extension-set-adapter.h
index 80a58bf..27ace5f 100644
--- a/libide/plugins/ide-extension-set-adapter.h
+++ b/libide/plugins/ide-extension-set-adapter.h
@@ -34,23 +34,23 @@ typedef void (*IdeExtensionSetAdapterForeachFunc) (IdeExtensionSetAdapter *set,
PeasExtension *extension,
gpointer user_data);
-IdeExtensionSetAdapter *ide_extension_set_adapter_new (IdeContext *context,
- PeasEngine *engine,
- GType interface_type,
- const gchar *key,
- const gchar *value);
-PeasEngine *ide_extension_set_adapter_get_engine (IdeExtensionSetAdapter *self);
-GType ide_extension_set_adapter_get_interface_type (IdeExtensionSetAdapter *self);
-const gchar *ide_extension_set_adapter_get_key (IdeExtensionSetAdapter *self);
-void ide_extension_set_adapter_set_key (IdeExtensionSetAdapter *self,
- const gchar *key);
-const gchar *ide_extension_set_adapter_get_value (IdeExtensionSetAdapter *self);
-void ide_extension_set_adapter_set_value (IdeExtensionSetAdapter *self,
- const gchar *value);
-guint ide_extension_set_adapter_get_n_extensions (IdeExtensionSetAdapter *self);
-void ide_extension_set_adapter_foreach (IdeExtensionSetAdapter *self,
- IdeExtensionSetAdapterForeachFunc
foreach_func,
- gpointer user_data);
+IdeExtensionSetAdapter *ide_extension_set_adapter_new (IdeContext
*context,
+ PeasEngine
*engine,
+ GType
interface_type,
+ const gchar *key,
+ const gchar
*value);
+PeasEngine *ide_extension_set_adapter_get_engine (IdeExtensionSetAdapter
*self);
+GType ide_extension_set_adapter_get_interface_type (IdeExtensionSetAdapter
*self);
+const gchar *ide_extension_set_adapter_get_key (IdeExtensionSetAdapter
*self);
+void ide_extension_set_adapter_set_key (IdeExtensionSetAdapter
*self,
+ const gchar
*key);
+const gchar *ide_extension_set_adapter_get_value (IdeExtensionSetAdapter
*self);
+void ide_extension_set_adapter_set_value (IdeExtensionSetAdapter
*self,
+ const gchar
*value);
+guint ide_extension_set_adapter_get_n_extensions (IdeExtensionSetAdapter
*self);
+void ide_extension_set_adapter_foreach (IdeExtensionSetAdapter
*self,
+ IdeExtensionSetAdapterForeachFunc
foreach_func,
+ gpointer
user_data);
G_END_DECLS
diff --git a/libide/plugins/ide-extension-util.c b/libide/plugins/ide-extension-util.c
index 5d81c53..e1c4f42 100644
--- a/libide/plugins/ide-extension-util.c
+++ b/libide/plugins/ide-extension-util.c
@@ -73,6 +73,12 @@ ide_extension_util_can_use_plugin (PeasEngine *engine,
values = peas_plugin_info_get_external_data (plugin_info, key);
values_array = g_strsplit (values ? values : "", ",", 0);
+
+ /* An empty value implies "*" to match anything */
+ if (!values || g_strv_contains ((const gchar * const *)values_array, "*"))
+ return TRUE;
+
+ /* Otherwise actually check that the key/value matches */
if (!g_strv_contains ((const gchar * const *)values_array, value))
return FALSE;
diff --git a/plugins/html-preview/html-preview.plugin b/plugins/html-preview/html-preview.plugin
index 8f33d45..17117ff 100644
--- a/plugins/html-preview/html-preview.plugin
+++ b/plugins/html-preview/html-preview.plugin
@@ -8,3 +8,4 @@ Copyright=Copyright © 2015 Christian Hergert
Builtin=true
Hidden=true
Depends=webkit
+X-Editor-View-Languages=*
diff --git a/plugins/html-preview/html_preview_plugin/__init__.py
b/plugins/html-preview/html_preview_plugin/__init__.py
index 4962266..3e1f980 100644
--- a/plugins/html-preview/html_preview_plugin/__init__.py
+++ b/plugins/html-preview/html_preview_plugin/__init__.py
@@ -198,7 +198,7 @@ class HtmlPreviewAddin(GObject.Object, Ide.EditorViewAddin):
actions = view.get_action_group('view')
actions.add_action(self.action)
- document = view.get_document()
+ document = view.get_buffer()
language = document.get_language()
language_id = language.get_id() if language else None
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]