[gnome-builder/wip/chergert/docs: 105/105] wip
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/chergert/docs: 105/105] wip
- Date: Sun, 25 Aug 2019 07:24:23 +0000 (UTC)
commit 733cb57bcc17bd5835b84132217a72b1fb1c10e9
Author: Christian Hergert <chergert redhat com>
Date: Tue Jul 23 12:50:04 2019 -0700
wip
src/libide/docs/ide-docs-item.c | 42 +++-
src/libide/docs/ide-docs-library.c | 109 +++++++++-
src/libide/docs/ide-docs-library.h | 30 ++-
src/libide/docs/ide-docs-pane-row.c | 161 ++++++++++++++
src/libide/docs/ide-docs-pane-row.h | 36 ++++
src/libide/docs/ide-docs-pane-row.ui | 26 +++
src/libide/docs/ide-docs-pane.c | 153 ++++++++++++-
src/libide/docs/ide-docs-pane.h | 4 +-
src/libide/docs/ide-docs-workspace.c | 26 ++-
src/libide/docs/ide-docs-workspace.ui | 2 +-
src/libide/docs/libide-docs.gresource.xml | 1 +
src/libide/docs/meson.build | 10 +-
src/libide/gui/ide-path-bar.c | 275 ++++++++++++++++++++++++
src/libide/gui/ide-path-bar.h | 53 +++++
src/libide/gui/ide-path-element.c | 181 ++++++++++++++++
src/libide/gui/ide-path-element.h | 51 +++++
src/libide/gui/ide-path.c | 171 +++++++++++++++
src/libide/gui/ide-path.h | 49 +++++
src/libide/gui/meson.build | 6 +
src/plugins/devhelp/gbp-devhelp-docs-provider.c | 12 ++
20 files changed, 1378 insertions(+), 20 deletions(-)
---
diff --git a/src/libide/docs/ide-docs-item.c b/src/libide/docs/ide-docs-item.c
index d0d670a1e..6c7f687f3 100644
--- a/src/libide/docs/ide-docs-item.c
+++ b/src/libide/docs/ide-docs-item.c
@@ -41,7 +41,11 @@ typedef struct
guint deprecated : 1;
} IdeDocsItemPrivate;
-G_DEFINE_TYPE_WITH_PRIVATE (IdeDocsItem, ide_docs_item, G_TYPE_OBJECT)
+static void list_model_iface_init (GListModelInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (IdeDocsItem, ide_docs_item, G_TYPE_OBJECT,
+ G_ADD_PRIVATE (IdeDocsItem)
+ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init))
enum {
PROP_0,
@@ -739,3 +743,39 @@ ide_docs_item_get_nth_child (IdeDocsItem *self,
return g_list_nth_data (priv->children.head, nth);
}
+
+static guint
+ide_docs_item_get_n_items (GListModel *model)
+{
+ IdeDocsItem *self = IDE_DOCS_ITEM (model);
+ IdeDocsItemPrivate *priv = ide_docs_item_get_instance_private (self);
+
+ return priv->children.length;
+}
+
+static GType
+ide_docs_item_get_item_type (GListModel *model)
+{
+ return IDE_TYPE_DOCS_ITEM;
+}
+
+static gpointer
+ide_docs_item_get_item (GListModel *model,
+ guint position)
+{
+ IdeDocsItem *self = (IdeDocsItem *)model;
+ IdeDocsItemPrivate *priv = ide_docs_item_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_DOCS_ITEM (self), NULL);
+ g_return_val_if_fail (position < priv->children.length, NULL);
+
+ return g_object_ref (g_queue_peek_nth (&priv->children, position));
+}
+
+static void
+list_model_iface_init (GListModelInterface *iface)
+{
+ iface->get_n_items = ide_docs_item_get_n_items;
+ iface->get_item_type = ide_docs_item_get_item_type;
+ iface->get_item = ide_docs_item_get_item;
+}
diff --git a/src/libide/docs/ide-docs-library.c b/src/libide/docs/ide-docs-library.c
index 7afd39598..b665e5c7b 100644
--- a/src/libide/docs/ide-docs-library.c
+++ b/src/libide/docs/ide-docs-library.c
@@ -43,8 +43,21 @@ typedef struct
guint n_active;
} Search;
+typedef struct
+{
+ IdeDocsItem *item;
+ guint n_active;
+} Populate;
+
G_DEFINE_TYPE (IdeDocsLibrary, ide_docs_library, IDE_TYPE_OBJECT)
+static void
+populate_free (Populate *populate)
+{
+ g_clear_object (&populate->item);
+ g_slice_free (Populate, populate);
+}
+
static void
search_free (Search *search)
{
@@ -172,7 +185,6 @@ ide_docs_library_search_cb (GObject *object,
gpointer user_data)
{
IdeDocsProvider *provider = (IdeDocsProvider *)object;
- g_autoptr(GListModel) model = NULL;
g_autoptr(IdeTask) task = user_data;
g_autoptr(GError) error = NULL;
Search *search;
@@ -317,3 +329,98 @@ ide_docs_library_search_finish (IdeDocsLibrary *self,
return ide_task_propagate_boolean (IDE_TASK (result), error);
}
+
+static void
+ide_docs_library_populate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeDocsProvider *provider = (IdeDocsProvider *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ Populate *populate;
+
+ g_assert (G_IS_OBJECT (object));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ populate = ide_task_get_task_data (task);
+
+ if (!ide_docs_provider_populate_finish (provider, result, &error))
+ {
+ if (!ide_error_ignore (error))
+ g_warning ("%s failed to populate docs: %s",
+ G_OBJECT_TYPE_NAME (provider),
+ error->message);
+ }
+
+ populate->n_active--;
+
+ if (populate->n_active == 0)
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_docs_library_populate_foreach_cb (IdeExtensionSetAdapter *adapter,
+ PeasPluginInfo *plugin,
+ PeasExtension *exten,
+ gpointer user_data)
+{
+ IdeDocsProvider *provider = (IdeDocsProvider *)exten;
+ IdeTask *task = user_data;
+ Populate *populate;
+
+ g_assert (IDE_IS_EXTENSION_SET_ADAPTER (adapter));
+ g_assert (plugin != NULL);
+ g_assert (IDE_IS_DOCS_PROVIDER (provider));
+ g_assert (IDE_IS_TASK (task));
+
+ populate = ide_task_get_task_data (task);
+ populate->n_active++;
+
+ ide_docs_provider_populate_async (provider,
+ populate->item,
+ ide_task_get_cancellable (task),
+ ide_docs_library_populate_cb,
+ g_object_ref (task));
+}
+
+void
+ide_docs_library_populate_async (IdeDocsLibrary *self,
+ IdeDocsItem *item,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = NULL;
+ Populate *state;
+
+ g_return_if_fail (IDE_IS_DOCS_LIBRARY (self));
+ g_return_if_fail (IDE_IS_DOCS_ITEM (item));
+
+ state = g_slice_new0 (Populate);
+ state->item = g_object_ref (item);
+ state->n_active = 0;
+
+ task = ide_task_new (self, cancellable, callback, user_data);
+ ide_task_set_source_tag (task, ide_docs_library_populate_async);
+ ide_task_set_task_data (task, state, populate_free);
+
+ ide_extension_set_adapter_foreach (self->providers,
+ ide_docs_library_populate_foreach_cb,
+ task);
+
+ if (state->n_active == 0)
+ ide_task_return_boolean (task, TRUE);
+}
+
+gboolean
+ide_docs_library_populate_finish (IdeDocsLibrary *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_DOCS_LIBRARY (self), FALSE);
+ g_return_val_if_fail (IDE_IS_TASK (result), FALSE);
+
+ return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
diff --git a/src/libide/docs/ide-docs-library.h b/src/libide/docs/ide-docs-library.h
index 8942f920b..f9492281b 100644
--- a/src/libide/docs/ide-docs-library.h
+++ b/src/libide/docs/ide-docs-library.h
@@ -33,17 +33,27 @@ IDE_AVAILABLE_IN_3_34
G_DECLARE_FINAL_TYPE (IdeDocsLibrary, ide_docs_library, IDE, DOCS_LIBRARY, IdeObject)
IDE_AVAILABLE_IN_3_34
-IdeDocsLibrary *ide_docs_library_from_context (IdeContext *context);
+IdeDocsLibrary *ide_docs_library_from_context (IdeContext *context);
IDE_AVAILABLE_IN_3_34
-void ide_docs_library_search_async (IdeDocsLibrary *self,
- IdeDocsQuery *query,
- IdeDocsItem *results,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
+void ide_docs_library_search_async (IdeDocsLibrary *self,
+ IdeDocsQuery *query,
+ IdeDocsItem *results,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
IDE_AVAILABLE_IN_3_34
-gboolean ide_docs_library_search_finish (IdeDocsLibrary *self,
- GAsyncResult *result,
- GError **error);
+gboolean ide_docs_library_search_finish (IdeDocsLibrary *self,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_3_34
+void ide_docs_library_populate_async (IdeDocsLibrary *self,
+ IdeDocsItem *item,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_3_34
+gboolean ide_docs_library_populate_finish (IdeDocsLibrary *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS
diff --git a/src/libide/docs/ide-docs-pane-row.c b/src/libide/docs/ide-docs-pane-row.c
new file mode 100644
index 000000000..c3369681a
--- /dev/null
+++ b/src/libide/docs/ide-docs-pane-row.c
@@ -0,0 +1,161 @@
+/* ide-docs-pane-row.c
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-docs-pane-row"
+
+#include "ide-docs-pane-row.h"
+
+struct _IdeDocsPaneRow
+{
+ GtkListBoxRow parent_instance;
+
+ IdeDocsItem *item;
+
+ /* Template Widgets */
+ GtkLabel *title;
+};
+
+G_DEFINE_TYPE (IdeDocsPaneRow, ide_docs_pane_row, GTK_TYPE_LIST_BOX_ROW)
+
+enum {
+ PROP_0,
+ PROP_ITEM,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+/**
+ * ide_docs_pane_row_new:
+ *
+ * Create a new #IdeDocsPaneRow.
+ *
+ * Returns: (transfer full): a newly created #IdeDocsPaneRow
+ */
+GtkWidget *
+ide_docs_pane_row_new (IdeDocsItem *item)
+{
+ g_return_val_if_fail (IDE_IS_DOCS_ITEM (item), NULL);
+
+ return g_object_new (IDE_TYPE_DOCS_PANE_ROW,
+ "item", item,
+ NULL);
+}
+
+static void
+ide_docs_pane_row_set_item (IdeDocsPaneRow *self,
+ IdeDocsItem *item)
+{
+ const gchar *title;
+
+ g_return_if_fail (IDE_IS_DOCS_PANE_ROW (self));
+ g_return_if_fail (IDE_IS_DOCS_ITEM (item));
+
+ if (!g_set_object (&self->item, item))
+ return;
+
+ title = ide_docs_item_get_title (item);
+ gtk_label_set_label (self->title, title);
+}
+
+IdeDocsItem *
+ide_docs_pane_row_get_item (IdeDocsPaneRow *self)
+{
+ g_return_val_if_fail (IDE_IS_DOCS_PANE_ROW (self), NULL);
+
+ return self->item;
+}
+
+static void
+ide_docs_pane_row_finalize (GObject *object)
+{
+ IdeDocsPaneRow *self = (IdeDocsPaneRow *)object;
+
+ g_clear_object (&self->item);
+
+ G_OBJECT_CLASS (ide_docs_pane_row_parent_class)->finalize (object);
+}
+
+static void
+ide_docs_pane_row_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdeDocsPaneRow *self = IDE_DOCS_PANE_ROW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ITEM:
+ g_value_set_object (value, ide_docs_pane_row_get_item (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_docs_pane_row_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdeDocsPaneRow *self = IDE_DOCS_PANE_ROW (object);
+
+ switch (prop_id)
+ {
+ case PROP_ITEM:
+ ide_docs_pane_row_set_item (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_docs_pane_row_class_init (IdeDocsPaneRowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = ide_docs_pane_row_finalize;
+ object_class->get_property = ide_docs_pane_row_get_property;
+ object_class->set_property = ide_docs_pane_row_set_property;
+
+ properties [PROP_ITEM] =
+ g_param_spec_object ("item",
+ "Item",
+ "The item to be displayed",
+ IDE_TYPE_DOCS_ITEM,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/libide-docs/ui/ide-docs-pane-row.ui");
+ gtk_widget_class_bind_template_child (widget_class, IdeDocsPaneRow, title);
+}
+
+static void
+ide_docs_pane_row_init (IdeDocsPaneRow *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+}
diff --git a/src/libide/docs/ide-docs-pane-row.h b/src/libide/docs/ide-docs-pane-row.h
new file mode 100644
index 000000000..a5211b893
--- /dev/null
+++ b/src/libide/docs/ide-docs-pane-row.h
@@ -0,0 +1,36 @@
+/* ide-docs-pane-row.h
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "ide-docs-item.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_DOCS_PANE_ROW (ide_docs_pane_row_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeDocsPaneRow, ide_docs_pane_row, IDE, DOCS_PANE_ROW, GtkListBoxRow)
+
+GtkWidget *ide_docs_pane_row_new (IdeDocsItem *item);
+IdeDocsItem *ide_docs_pane_row_get_item (IdeDocsPaneRow *self);
+
+G_END_DECLS
diff --git a/src/libide/docs/ide-docs-pane-row.ui b/src/libide/docs/ide-docs-pane-row.ui
new file mode 100644
index 000000000..70a7c30d8
--- /dev/null
+++ b/src/libide/docs/ide-docs-pane-row.ui
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="IdeDocsPaneRow" parent="GtkListBoxRow">
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">horizontal</property>
+ <property name="visible">true</property>
+ <child>
+ <object class="GtkImage" id="image">
+ <property name="icon-name">help-contents-symbolic</property>
+ <property name="hexpand">false</property>
+ <property name="visible">true</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="ellipsize">end</property>
+ <property name="hexpand">true</property>
+ <property name="visible">true</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/src/libide/docs/ide-docs-pane.c b/src/libide/docs/ide-docs-pane.c
index a2ac3bbb2..1d284796b 100644
--- a/src/libide/docs/ide-docs-pane.c
+++ b/src/libide/docs/ide-docs-pane.c
@@ -22,10 +22,12 @@
#include "config.h"
+#include <glib/gi18n.h>
#include <dazzle.h>
#include "ide-docs-library.h"
#include "ide-docs-pane.h"
+#include "ide-docs-pane-row.h"
struct _IdeDocsPane
{
@@ -87,7 +89,7 @@ ide_docs_pane_set_property (GObject *object,
switch (prop_id)
{
case PROP_LIBRARY:
- self->library = g_value_dup_object (value);
+ ide_docs_pane_set_library (self, g_value_get_object (value));
break;
default:
@@ -110,7 +112,7 @@ ide_docs_pane_class_init (IdeDocsPaneClass *klass)
"Library",
"The library for the documentation pane",
IDE_TYPE_DOCS_LIBRARY,
- (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
@@ -120,10 +122,122 @@ ide_docs_pane_class_init (IdeDocsPaneClass *klass)
g_type_ensure (DZL_TYPE_STACK_LIST);
}
+static GtkWidget *
+create_pane_row_cb (gpointer item_,
+ gpointer user_data)
+{
+ IdeDocsItem *item = item_;
+
+ g_assert (IDE_IS_DOCS_ITEM (item));
+
+ return g_object_new (IDE_TYPE_DOCS_PANE_ROW,
+ "item", item,
+ "visible", TRUE,
+ NULL);
+}
+
+static void
+ide_docs_pane_activate_populate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(IdeTask) task = user_data;
+ IdeDocsPane *self;
+ IdeDocsItem *item;
+
+ g_assert (IDE_IS_DOCS_LIBRARY (object));
+ g_assert (IDE_IS_TASK (task));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ self = ide_task_get_source_object (task);
+ item = ide_task_get_task_data (task);
+
+ dzl_stack_list_push (self->stack_list,
+ create_pane_row_cb (item, self),
+ G_LIST_MODEL (item),
+ create_pane_row_cb,
+ self, NULL);
+
+ ide_task_return_boolean (task, TRUE);
+}
+
+static void
+ide_docs_pane_row_activated_cb (IdeDocsPane *self,
+ IdeDocsPaneRow *row,
+ DzlStackList *stack_list)
+{
+ g_autoptr(IdeTask) task = NULL;
+ IdeDocsLibrary *library;
+ IdeDocsItem *item;
+ IdeContext *context;
+
+ g_assert (IDE_IS_DOCS_PANE (self));
+ g_assert (IDE_IS_DOCS_PANE_ROW (row));
+ g_assert (DZL_IS_STACK_LIST (stack_list));
+
+ item = ide_docs_pane_row_get_item (row);
+ context = ide_widget_get_context (GTK_WIDGET (self));
+ library = ide_docs_library_from_context (context);
+
+ task = ide_task_new (self, NULL, NULL, NULL);
+ ide_task_set_source_tag (task, ide_docs_pane_row_activated_cb);
+ ide_task_set_task_data (task, g_object_ref (item), g_object_unref);
+
+ ide_docs_library_populate_async (library,
+ item,
+ NULL,
+ ide_docs_pane_activate_populate_cb,
+ g_steal_pointer (&task));
+}
+
static void
ide_docs_pane_init (IdeDocsPane *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
+
+ g_signal_connect_object (self->stack_list,
+ "row-activated",
+ G_CALLBACK (ide_docs_pane_row_activated_cb),
+ self,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+ide_docs_pane_populate_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeDocsLibrary *library = (IdeDocsLibrary *)object;
+ g_autoptr(IdeTask) task = user_data;
+ g_autoptr(GError) error = NULL;
+ IdeDocsPane *self;
+ IdeDocsItem *item;
+
+ g_assert (G_IS_OBJECT (object));
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (IDE_IS_TASK (task));
+
+ self = ide_task_get_source_object (task);
+ item = ide_task_get_task_data (task);
+
+ g_assert (IDE_IS_DOCS_PANE (self));
+ g_assert (IDE_IS_DOCS_ITEM (item));
+
+ if (!ide_docs_library_populate_finish (library, result, &error))
+ {
+ g_warning ("Failed to populate documentation: %s",
+ error->message);
+ return;
+ }
+
+ dzl_stack_list_clear (self->stack_list);
+ dzl_stack_list_push (self->stack_list,
+ create_pane_row_cb (item, self),
+ G_LIST_MODEL (item),
+ create_pane_row_cb,
+ self, NULL);
+
+ ide_task_return_boolean (task, TRUE);
}
/**
@@ -143,3 +257,38 @@ ide_docs_pane_get_library (IdeDocsPane *self)
return self->library;
}
+
+void
+ide_docs_pane_set_library (IdeDocsPane *self,
+ IdeDocsLibrary *library)
+{
+ g_return_if_fail (IDE_IS_DOCS_PANE (self));
+ g_return_if_fail (!library || IDE_IS_DOCS_LIBRARY (library));
+
+ if (g_set_object (&self->library, library))
+ {
+ g_autoptr(IdeDocsItem) root = NULL;
+ g_autoptr(IdeTask) task = NULL;
+
+ if (library == NULL)
+ {
+ dzl_stack_list_clear (self->stack_list);
+ return;
+ }
+
+ root = ide_docs_item_new ();
+ ide_docs_item_set_title (root, _("Library"));
+ ide_docs_item_set_kind (root, IDE_DOCS_ITEM_KIND_COLLECTION);
+
+ task = ide_task_new (self, NULL, NULL, NULL);
+ ide_task_set_task_data (task, g_object_ref (root), g_object_unref);
+
+ ide_docs_library_populate_async (library,
+ root,
+ NULL,
+ ide_docs_pane_populate_cb,
+ g_steal_pointer (&task));
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LIBRARY]);
+ }
+}
diff --git a/src/libide/docs/ide-docs-pane.h b/src/libide/docs/ide-docs-pane.h
index 0205f6be2..088ac6896 100644
--- a/src/libide/docs/ide-docs-pane.h
+++ b/src/libide/docs/ide-docs-pane.h
@@ -30,6 +30,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeDocsPane, ide_docs_pane, IDE, DOCS_PANE, IdePane)
-IdeDocsLibrary *ide_docs_pane_get_library (IdeDocsPane *self);
+IdeDocsLibrary *ide_docs_pane_get_library (IdeDocsPane *self);
+void ide_docs_pane_set_library (IdeDocsPane *self,
+ IdeDocsLibrary *library);
G_END_DECLS
diff --git a/src/libide/docs/ide-docs-workspace.c b/src/libide/docs/ide-docs-workspace.c
index 4c21ee709..78fc1c7ab 100644
--- a/src/libide/docs/ide-docs-workspace.c
+++ b/src/libide/docs/ide-docs-workspace.c
@@ -46,6 +46,7 @@ struct _IdeDocsWorkspace
IdeDocsSearchView *search_view;
IdeDocsView *view;
GtkEntry *entry;
+ IdeDocsPane *pane;
};
G_DEFINE_TYPE (IdeDocsWorkspace, ide_docs_workspace, IDE_TYPE_WORKSPACE)
@@ -124,7 +125,7 @@ on_search_view_item_activated_cb (IdeDocsWorkspace *self,
g_assert (IDE_IS_DOCS_ITEM (item));
g_assert (IDE_IS_DOCS_SEARCH_VIEW (view));
- g_print ("Activate view for %s at %s\n",
+ g_debug ("Activate view for %s at %s",
ide_docs_item_get_title (item),
ide_docs_item_get_url (item));
@@ -144,6 +145,26 @@ ide_docs_workspace_focus_search_cb (GtkWidget *widget,
gtk_widget_grab_focus (GTK_WIDGET (self->entry));
}
+static void
+ide_docs_workspace_context_set (IdeWorkspace *workspace,
+ IdeContext *context)
+{
+ IdeDocsWorkspace *self = (IdeDocsWorkspace *)workspace;
+
+ g_assert (IDE_IS_DOCS_WORKSPACE (self));
+ g_assert (!context || IDE_IS_CONTEXT (context));
+
+ IDE_WORKSPACE_CLASS (ide_docs_workspace_parent_class)->context_set (workspace, context);
+
+ if (context != NULL)
+ {
+ IdeDocsLibrary *library;
+
+ library = ide_docs_library_from_context (context);
+ ide_docs_pane_set_library (self->pane, library);
+ }
+}
+
static void
ide_docs_workspace_destroy (GtkWidget *widget)
{
@@ -164,8 +185,11 @@ ide_docs_workspace_class_init (IdeDocsWorkspaceClass *klass)
widget_class->destroy = ide_docs_workspace_destroy;
+ workspace_class->context_set = ide_docs_workspace_context_set;
+
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gnome/libide-docs/ui/ide-docs-workspace.ui");
gtk_widget_class_bind_template_child (widget_class, IdeDocsWorkspace, entry);
+ gtk_widget_class_bind_template_child (widget_class, IdeDocsWorkspace, pane);
gtk_widget_class_bind_template_child (widget_class, IdeDocsWorkspace, search_view);
gtk_widget_class_bind_template_child (widget_class, IdeDocsWorkspace, stack);
gtk_widget_class_bind_template_child (widget_class, IdeDocsWorkspace, view);
diff --git a/src/libide/docs/ide-docs-workspace.ui b/src/libide/docs/ide-docs-workspace.ui
index e796a8629..a30e28d47 100644
--- a/src/libide/docs/ide-docs-workspace.ui
+++ b/src/libide/docs/ide-docs-workspace.ui
@@ -20,7 +20,7 @@
<object class="IdeSurface" id="docs_surface">
<property name="visible">true</property>
<child type="left">
- <object class="IdeDocsPane">
+ <object class="IdeDocsPane" id="pane">
<property name="width-request">200</property>
<property name="visible">true</property>
</object>
diff --git a/src/libide/docs/libide-docs.gresource.xml b/src/libide/docs/libide-docs.gresource.xml
index d17c06357..9a864efee 100644
--- a/src/libide/docs/libide-docs.gresource.xml
+++ b/src/libide/docs/libide-docs.gresource.xml
@@ -5,6 +5,7 @@
</gresource>
<gresource prefix="/org/gnome/libide-docs/ui">
<file preprocess="xml-stripblanks">ide-docs-pane.ui</file>
+ <file preprocess="xml-stripblanks">ide-docs-pane-row.ui</file>
<file preprocess="xml-stripblanks">ide-docs-search-row.ui</file>
<file preprocess="xml-stripblanks">ide-docs-search-view.ui</file>
<file preprocess="xml-stripblanks">ide-docs-workspace.ui</file>
diff --git a/src/libide/docs/meson.build b/src/libide/docs/meson.build
index c6186e33f..fbefb87a6 100644
--- a/src/libide/docs/meson.build
+++ b/src/libide/docs/meson.build
@@ -25,18 +25,22 @@ libide_docs_public_sources = [
'libide-docs.c',
'ide-docs-item.c',
'ide-docs-library.c',
- 'ide-docs-pane.c',
'ide-docs-provider.c',
'ide-docs-query.c',
+ 'ide-docs-workspace.c',
+]
+
+libide_docs_private_sources = [
+ 'ide-docs-pane.c',
+ 'ide-docs-pane-row.c',
'ide-docs-search-model.c',
'ide-docs-search-row.c',
'ide-docs-search-section.c',
'ide-docs-search-view.c',
'ide-docs-view.c',
- 'ide-docs-workspace.c',
]
-libide_docs_sources = libide_docs_public_sources
+libide_docs_sources = libide_docs_public_sources + libide_docs_private_sources
#
# Enum generation
diff --git a/src/libide/gui/ide-path-bar.c b/src/libide/gui/ide-path-bar.c
new file mode 100644
index 000000000..311d235d5
--- /dev/null
+++ b/src/libide/gui/ide-path-bar.c
@@ -0,0 +1,275 @@
+/* ide-path-bar.c
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-path-bar"
+
+#include "config.h"
+
+#include "ide-path-bar.h"
+
+typedef struct
+{
+ IdePath *path;
+ IdePath *selection;
+} IdePathBarPrivate;
+
+enum {
+ PROP_0,
+ PROP_PATH,
+ PROP_SELECTION,
+ N_PROPS
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (IdePathBar, ide_path_bar, GTK_TYPE_CONTAINER)
+
+static GParamSpec *properties [N_PROPS];
+
+static GtkWidget *
+ide_path_bar_create_button (const gchar *title,
+ gboolean with_arrow)
+{
+ GtkButton *button;
+ GtkLabel *label;
+ GtkBox *box;
+
+ box = g_object_new (GTK_TYPE_BOX,
+ "spacing", 3,
+ "visible", TRUE,
+ NULL);
+
+ label = g_object_new (GTK_TYPE_LABEL,
+ "visible", TRUE,
+ NULL);
+ gtk_container_add (GTK_CONTAINER (box), GTK_WIDGET (label));
+
+ if (with_arrow)
+ gtk_container_add (GTK_CONTAINER (box),
+ g_object_new (GTK_TYPE_IMAGE,
+ "visible", TRUE,
+ NULL));
+
+ button = g_object_new (GTK_TYPE_BUTTON,
+ "focus-on-click", FALSE,
+ "child", box,
+ "visible", TRUE,
+ NULL);
+
+ return GTK_WIDGET (button);
+}
+
+static void
+ide_path_bar_update_buttons (IdePathBar *self)
+{
+ IdePathBarPrivate *priv = ide_path_bar_get_instance_private (self);
+ guint n_elements;
+
+ g_assert (IDE_IS_PATH_BAR (self));
+
+ gtk_container_foreach (GTK_CONTAINER (self),
+ (GtkCallback) gtk_widget_destroy,
+ NULL);
+
+ if (priv->path == NULL)
+ return;
+
+ n_elements = ide_path_get_n_elements (priv->path);
+
+ for (guint i = 0; i < n_elements; i++)
+ {
+ IdePathElement *element = ide_path_get_element (priv->path, i);
+ const gchar *title;
+ GtkWidget *button;
+ gboolean has_arrow;
+
+ g_assert (IDE_IS_PATH_ELEMENT (element));
+
+ title = ide_path_element_get_title (element);
+ has_arrow = i + 1 == n_elements;
+ button = ide_path_bar_create_button (title, has_arrow);
+
+ gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (button));
+ }
+
+}
+
+static void
+ide_path_bar_add (GtkContainer *container,
+ GtkWidget *widget)
+{
+ g_assert (IDE_IS_PATH_BAR (container));
+ g_assert (GTK_IS_WIDGET (widget));
+
+ gtk_widget_set_parent (widget, GTK_WIDGET (container));
+}
+
+static void
+ide_path_bar_finalize (GObject *object)
+{
+ IdePathBar *self = (IdePathBar *)object;
+ IdePathBarPrivate *priv = ide_path_bar_get_instance_private (self);
+
+ g_clear_object (&priv->path);
+ g_clear_object (&priv->selection);
+
+ G_OBJECT_CLASS (ide_path_bar_parent_class)->finalize (object);
+}
+
+static void
+ide_path_bar_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdePathBar *self = IDE_PATH_BAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_PATH:
+ g_value_set_object (value, ide_path_bar_get_path (self));
+ break;
+
+ case PROP_SELECTION:
+ g_value_set_object (value, ide_path_bar_get_selection (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_path_bar_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdePathBar *self = IDE_PATH_BAR (object);
+
+ switch (prop_id)
+ {
+ case PROP_PATH:
+ ide_path_bar_set_path (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_path_bar_class_init (IdePathBarClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ object_class->finalize = ide_path_bar_finalize;
+ object_class->get_property = ide_path_bar_get_property;
+ object_class->set_property = ide_path_bar_set_property;
+
+ container_class->add = ide_path_bar_add;
+
+ properties [PROP_PATH] =
+ g_param_spec_object ("path",
+ "Path",
+ "The path that is displayed",
+ IDE_TYPE_PATH,
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_SELECTION] =
+ g_param_spec_object ("selection",
+ "Selection",
+ "The selected portion of the path",
+ IDE_TYPE_PATH,
+ (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_path_bar_init (IdePathBar *self)
+{
+ GtkStyleContext *style_context;
+
+ gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
+ gtk_widget_set_redraw_on_allocate (GTK_WIDGET (self), FALSE);
+
+ style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+ gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_LINKED);
+}
+
+/**
+ * ide_path_bar_get_selection:
+ * @self: an #IdePathBar
+ *
+ * Get the path up to the selected element.
+ *
+ * Returns: (transfer none) (nullable): an #IdePathBar or %NULL
+ *
+ * Since: 3.34
+ */
+IdePath *
+ide_path_bar_get_selection (IdePathBar *self)
+{
+ IdePathBarPrivate *priv = ide_path_bar_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_PATH_BAR (self), NULL);
+
+ return priv->selection;
+}
+
+/**
+ * ide_path_bar_get_path:
+ * @self: an #IdePathBar
+ *
+ * Gets the path for the whole path bar. This may include elements
+ * after the selected element if the selected element is before
+ * the end of the path.
+ *
+ * Returns: (transfer none) (nullable): an #IdePath or %NULL
+ *
+ * Since: 3.34
+ */
+IdePath *
+ide_path_bar_get_path (IdePathBar *self)
+{
+ IdePathBarPrivate *priv = ide_path_bar_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_PATH_BAR (self), NULL);
+
+ return priv->selection;
+}
+
+void
+ide_path_bar_set_path (IdePathBar *self,
+ IdePath *path)
+{
+ IdePathBarPrivate *priv = ide_path_bar_get_instance_private (self);
+
+ g_return_if_fail (IDE_IS_PATH_BAR (self));
+ g_return_if_fail (!path || IDE_IS_PATH (path));
+
+ if (g_set_object (&priv->path, path))
+ {
+ g_set_object (&priv->selection, path);
+ ide_path_bar_update_buttons (self);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PATH]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SELECTION]);
+ }
+}
diff --git a/src/libide/gui/ide-path-bar.h b/src/libide/gui/ide-path-bar.h
new file mode 100644
index 000000000..f588762a4
--- /dev/null
+++ b/src/libide/gui/ide-path-bar.h
@@ -0,0 +1,53 @@
+/* ide-path-bar.h
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+#include <libide-core.h>
+
+#include "ide-path.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PATH_BAR (ide_path_bar_get_type())
+
+IDE_AVAILABLE_IN_3_34
+G_DECLARE_DERIVABLE_TYPE (IdePathBar, ide_path_bar, IDE, PATH_BAR, GtkContainer)
+
+struct _IdePathBarClass
+{
+ GtkContainerClass parent_instance;
+
+ /*< private >*/
+ gpointer _reserved[8];
+};
+
+IDE_AVAILABLE_IN_3_34
+GtkWidget *ide_path_bar_new (void);
+IDE_AVAILABLE_IN_3_34
+IdePath *ide_path_bar_get_path (IdePathBar *self);
+IDE_AVAILABLE_IN_3_34
+void ide_path_bar_set_path (IdePathBar *path_bar,
+ IdePath *path);
+IDE_AVAILABLE_IN_3_34
+IdePath *ide_path_bar_get_selection (IdePathBar *self);
+
+G_END_DECLS
diff --git a/src/libide/gui/ide-path-element.c b/src/libide/gui/ide-path-element.c
new file mode 100644
index 000000000..f4deabb17
--- /dev/null
+++ b/src/libide/gui/ide-path-element.c
@@ -0,0 +1,181 @@
+/* ide-path-element.c
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-path-element"
+
+#include "config.h"
+
+#include "ide-path-element.h"
+
+typedef struct
+{
+ gchar *id;
+ gchar *title;
+} IdePathElementPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (IdePathElement, ide_path_element, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_ID,
+ PROP_TITLE,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+/**
+ * ide_path_element_new:
+ * @id: the id for the path element
+ * @title: the display name for the path element
+ *
+ * Create a new #IdePathElement.
+ *
+ * Returns: (transfer full): a newly created #IdePathElement
+ *
+ * Since: 3.34
+ */
+IdePathElement *
+ide_path_element_new (const gchar *id,
+ const gchar *title)
+{
+ return g_object_new (IDE_TYPE_PATH_ELEMENT,
+ "id", id,
+ "title", title,
+ NULL);
+}
+
+static void
+ide_path_element_finalize (GObject *object)
+{
+ IdePathElement *self = (IdePathElement *)object;
+ IdePathElementPrivate *priv = ide_path_element_get_instance_private (self);
+
+ g_clear_pointer (&priv->id, g_free);
+ g_clear_pointer (&priv->title, g_free);
+
+ G_OBJECT_CLASS (ide_path_element_parent_class)->finalize (object);
+}
+
+static void
+ide_path_element_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ IdePathElement *self = IDE_PATH_ELEMENT (object);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ g_value_set_string (value, ide_path_element_get_id (self));
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, ide_path_element_get_title (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_path_element_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ IdePathElement *self = IDE_PATH_ELEMENT (object);
+ IdePathElementPrivate *priv = ide_path_element_get_instance_private (self);
+
+ switch (prop_id)
+ {
+ case PROP_ID:
+ priv->id = g_value_dup_string (value);
+ break;
+
+ case PROP_TITLE:
+ priv->title = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+ide_path_element_class_init (IdePathElementClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_path_element_finalize;
+ object_class->get_property = ide_path_element_get_property;
+ object_class->set_property = ide_path_element_set_property;
+
+ properties [PROP_ID] =
+ g_param_spec_string ("id",
+ "Id",
+ "The identifier for the element",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ properties [PROP_TITLE] =
+ g_param_spec_string ("title",
+ "Title",
+ "The display title for the element",
+ NULL,
+ (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+ide_path_element_init (IdePathElement *self)
+{
+}
+
+const gchar *
+ide_path_element_get_id (IdePathElement *self)
+{
+ IdePathElementPrivate *priv = ide_path_element_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_PATH_ELEMENT (self), NULL);
+
+ return priv->id;
+}
+
+const gchar *
+ide_path_element_get_title (IdePathElement *self)
+{
+ IdePathElementPrivate *priv = ide_path_element_get_instance_private (self);
+
+ g_return_val_if_fail (IDE_IS_PATH_ELEMENT (self), NULL);
+
+ return priv->title;
+}
+
+gboolean
+ide_path_element_equal (IdePathElement *self,
+ IdePathElement *other)
+{
+ return 0 == g_strcmp0 (ide_path_element_get_id (self),
+ ide_path_element_get_id (other));
+}
diff --git a/src/libide/gui/ide-path-element.h b/src/libide/gui/ide-path-element.h
new file mode 100644
index 000000000..4186f01be
--- /dev/null
+++ b/src/libide/gui/ide-path-element.h
@@ -0,0 +1,51 @@
+/* ide-path-element.h
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PATH_ELEMENT (ide_path_element_get_type())
+
+IDE_AVAILABLE_IN_3_34
+G_DECLARE_DERIVABLE_TYPE (IdePathElement, ide_path_element, IDE, PATH_ELEMENT, GObject)
+
+struct _IdePathElementClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ gpointer _reserved[8];
+};
+
+IDE_AVAILABLE_IN_3_34
+IdePathElement *ide_path_element_new (const gchar *id,
+ const gchar *title);
+IDE_AVAILABLE_IN_3_34
+const gchar *ide_path_element_get_id (IdePathElement *self);
+IDE_AVAILABLE_IN_3_34
+const gchar *ide_path_element_get_title (IdePathElement *self);
+IDE_AVAILABLE_IN_3_34
+gboolean ide_path_element_equal (IdePathElement *self,
+ IdePathElement *other);
+
+G_END_DECLS
diff --git a/src/libide/gui/ide-path.c b/src/libide/gui/ide-path.c
new file mode 100644
index 000000000..a2d8d430c
--- /dev/null
+++ b/src/libide/gui/ide-path.c
@@ -0,0 +1,171 @@
+/* ide-path.c
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-path"
+
+#include "config.h"
+
+#include "ide-path.h"
+
+struct _IdePath
+{
+ GObject parent_instance;
+ GPtrArray *elements;
+};
+
+G_DEFINE_TYPE (IdePath, ide_path, G_TYPE_OBJECT)
+
+/**
+ * ide_path_new:
+ * @elements: (transfer none) (element-type IdePathElement): an array of
+ * elements for the path.
+ *
+ * Create a new #IdePath using the elements provided.
+ *
+ * Returns: (transfer full): a newly created #IdePath
+ *
+ * Since: 3.34
+ */
+IdePath *
+ide_path_new (GPtrArray *elements)
+{
+ IdePath *self;
+
+ g_return_val_if_fail (elements != NULL, NULL);
+
+ self = g_object_new (IDE_TYPE_PATH, NULL);
+ self->elements = g_ptr_array_new_full (elements->len, g_object_unref);
+ for (guint i = 0; i < elements->len; i++)
+ g_ptr_array_add (self->elements, g_object_ref (g_ptr_array_index (elements, i)));
+
+ return g_steal_pointer (&self);
+}
+
+static void
+ide_path_finalize (GObject *object)
+{
+ IdePath *self = (IdePath *)object;
+
+ g_clear_pointer (&self->elements, g_ptr_array_unref);
+
+ G_OBJECT_CLASS (ide_path_parent_class)->finalize (object);
+}
+
+static void
+ide_path_class_init (IdePathClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ide_path_finalize;
+}
+
+static void
+ide_path_init (IdePath *self)
+{
+}
+
+guint
+ide_path_get_n_elements (IdePath *self)
+{
+ g_return_val_if_fail (IDE_IS_PATH (self), 0);
+
+ return self->elements->len;
+}
+
+/**
+ * ide_path_get_element:
+ * @self: an #IdePath
+ * @position: the position of the element
+ *
+ * Gets the element at the position starting from 0.
+ *
+ * Returns: (transfer none): an #IdePathElement
+ *
+ * Since: 3.34
+ */
+IdePathElement *
+ide_path_get_element (IdePath *self,
+ guint position)
+{
+ g_return_val_if_fail (IDE_IS_PATH (self), NULL);
+ g_return_val_if_fail (position < self->elements->len, NULL);
+
+ return g_ptr_array_index (self->elements, position);
+}
+
+gboolean
+ide_path_has_prefix (IdePath *self,
+ IdePath *prefix)
+{
+ g_return_val_if_fail (IDE_IS_PATH (self), FALSE);
+ g_return_val_if_fail (IDE_IS_PATH (prefix), FALSE);
+
+ if (prefix->elements->len > self->elements->len)
+ return FALSE;
+
+ for (guint i = 0; i < prefix->elements->len; i++)
+ {
+ IdePathElement *eself = g_ptr_array_index (self->elements, i);
+ IdePathElement *pself = g_ptr_array_index (prefix->elements, i);
+
+ if (!ide_path_element_equal (eself, pself))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * ide_path_get_parent:
+ * @self: an #IdePath
+ *
+ * Gets a new path for the parent of @self.
+ *
+ * Returns: (transfer full) (nullable): an #IdePath or %NULL if the
+ * path is the root path.
+ *
+ * Since: 3.34
+ */
+IdePath *
+ide_path_get_parent (IdePath *self)
+{
+ IdePath *ret;
+
+ g_return_val_if_fail (IDE_IS_PATH (self), NULL);
+
+ if (self->elements->len == 0)
+ return NULL;
+
+ ret = g_object_new (IDE_TYPE_PATH, NULL);
+ ret->elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+ for (guint i = 0; i < self->elements->len - 1; i++)
+ g_ptr_array_add (ret->elements, g_object_ref (g_ptr_array_index (self->elements, i)));
+
+ return g_steal_pointer (&ret);
+}
+
+gboolean
+ide_path_is_root (IdePath *self)
+{
+ g_return_val_if_fail (IDE_IS_PATH (self), FALSE);
+
+ return self->elements->len == 0;
+}
diff --git a/src/libide/gui/ide-path.h b/src/libide/gui/ide-path.h
new file mode 100644
index 000000000..585cf1995
--- /dev/null
+++ b/src/libide/gui/ide-path.h
@@ -0,0 +1,49 @@
+/* ide-path.h
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+#include "ide-path-element.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_PATH (ide_path_get_type())
+
+IDE_AVAILABLE_IN_3_34
+G_DECLARE_FINAL_TYPE (IdePath, ide_path, IDE, PATH, GObject)
+
+IDE_AVAILABLE_IN_3_34
+IdePath *ide_path_new (GPtrArray *elements);
+IDE_AVAILABLE_IN_3_34
+IdePath *ide_path_get_parent (IdePath *self);
+IDE_AVAILABLE_IN_3_34
+guint ide_path_get_n_elements (IdePath *self);
+IDE_AVAILABLE_IN_3_34
+IdePathElement *ide_path_get_element (IdePath *self,
+ guint position);
+IDE_AVAILABLE_IN_3_34
+gboolean ide_path_has_prefix (IdePath *self,
+ IdePath *prefix);
+IDE_AVAILABLE_IN_3_34
+gboolean ide_path_is_root (IdePath *self);
+
+G_END_DECLS
diff --git a/src/libide/gui/meson.build b/src/libide/gui/meson.build
index 9f469d2fa..768614503 100644
--- a/src/libide/gui/meson.build
+++ b/src/libide/gui/meson.build
@@ -32,6 +32,9 @@ libide_gui_public_headers = [
'ide-page.h',
'ide-pane.h',
'ide-panel.h',
+ 'ide-path.h',
+ 'ide-path-bar.h',
+ 'ide-path-element.h',
'ide-preferences-addin.h',
'ide-preferences-surface.h',
'ide-preferences-window.h',
@@ -136,6 +139,9 @@ libide_gui_public_sources = [
'ide-page.c',
'ide-pane.c',
'ide-panel.c',
+ 'ide-path.c',
+ 'ide-path-bar.c',
+ 'ide-path-element.c',
'ide-primary-workspace.c',
'ide-preferences-addin.c',
'ide-preferences-surface.c',
diff --git a/src/plugins/devhelp/gbp-devhelp-docs-provider.c b/src/plugins/devhelp/gbp-devhelp-docs-provider.c
index 0d4285df4..2e6892c49 100644
--- a/src/plugins/devhelp/gbp-devhelp-docs-provider.c
+++ b/src/plugins/devhelp/gbp-devhelp-docs-provider.c
@@ -77,6 +77,18 @@ gbp_devhelp_docs_provider_populate_async (IdeDocsProvider *provider,
g_autoptr(IdeDocsItem) child = NULL;
child = ide_docs_item_new ();
+ ide_docs_item_set_id (child, "devhelp:sdk");
+ ide_docs_item_set_title (child, "SDKs");
+ ide_docs_item_set_kind (child, IDE_DOCS_ITEM_KIND_COLLECTION);
+
+ ide_docs_item_append (item, child);
+ }
+ else if (ide_str_equal0 (ide_docs_item_get_id (item), "devhelp:sdks"))
+ {
+ g_autoptr(IdeDocsItem) child = NULL;
+
+ child = ide_docs_item_new ();
+ ide_docs_item_set_id (child, "devhelp:books");
ide_docs_item_set_title (child, "Books");
ide_docs_item_set_kind (child, IDE_DOCS_ITEM_KIND_COLLECTION);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]