summaryrefslogtreecommitdiffstats
path: root/gedit/gedit-documents-panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'gedit/gedit-documents-panel.c')
-rw-r--r--gedit/gedit-documents-panel.c1740
1 files changed, 1740 insertions, 0 deletions
diff --git a/gedit/gedit-documents-panel.c b/gedit/gedit-documents-panel.c
new file mode 100644
index 0000000..5ffe77e
--- /dev/null
+++ b/gedit/gedit-documents-panel.c
@@ -0,0 +1,1740 @@
+/*
+ * gedit-documents-panel.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2014 - Sébastien Lafargue <slafargue@gnome.org>
+ *
+ * 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 2 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/>.
+ */
+
+#include "config.h"
+
+#include "gedit-documents-panel.h"
+
+#include <glib/gi18n.h>
+#include <tepl/tepl.h>
+
+#include "gedit-debug.h"
+#include "gedit-document.h"
+#include "gedit-document-private.h"
+#include "gedit-multi-notebook.h"
+#include "gedit-notebook.h"
+#include "gedit-notebook-popup-menu.h"
+#include "gedit-tab.h"
+#include "gedit-tab-private.h"
+#include "gedit-utils.h"
+#include "gedit-commands-private.h"
+
+typedef struct _GeditDocumentsGenericRow GeditDocumentsGenericRow;
+typedef struct _GeditDocumentsGenericRow GeditDocumentsGroupRow;
+typedef struct _GeditDocumentsGenericRow GeditDocumentsDocumentRow;
+
+struct _GeditDocumentsGenericRow
+{
+ GtkListBoxRow parent_instance;
+
+ GeditDocumentsPanel *panel;
+ GtkWidget *ref;
+
+ GtkWidget *box;
+ GtkWidget *label;
+ GtkWidget *close_button;
+
+ /* Not used in GeditDocumentsGroupRow */
+ GtkWidget *image;
+ GtkWidget *status_label;
+};
+
+#define GEDIT_TYPE_DOCUMENTS_GROUP_ROW (gedit_documents_group_row_get_type ())
+#define GEDIT_DOCUMENTS_GROUP_ROW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_DOCUMENTS_GROUP_ROW, GeditDocumentsGroupRow))
+#define GEDIT_DOCUMENTS_GROUP_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_DOCUMENTS_GROUP_ROW, GeditDocumentsGroupRowClass))
+#define GEDIT_IS_DOCUMENTS_GROUP_ROW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_DOCUMENTS_GROUP_ROW))
+#define GEDIT_IS_DOCUMENTS_GROUP_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_DOCUMENTS_GROUP_ROW))
+#define GEDIT_DOCUMENTS_GROUP_ROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_DOCUMENTS_GROUP_ROW, GeditDocumentsGroupRowClass))
+
+typedef struct _GeditDocumentsGroupRowClass GeditDocumentsGroupRowClass;
+
+struct _GeditDocumentsGroupRowClass
+{
+ GtkListBoxRowClass parent_class;
+};
+
+GType gedit_documents_group_row_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (GeditDocumentsGroupRow, gedit_documents_group_row, GTK_TYPE_LIST_BOX_ROW)
+
+#define GEDIT_TYPE_DOCUMENTS_DOCUMENT_ROW (gedit_documents_document_row_get_type ())
+#define GEDIT_DOCUMENTS_DOCUMENT_ROW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_DOCUMENTS_DOCUMENT_ROW, GeditDocumentsDocumentRow))
+#define GEDIT_DOCUMENTS_DOCUMENT_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_DOCUMENTS_DOCUMENT_ROW, GeditDocumentsDocumentRowClass))
+#define GEDIT_IS_DOCUMENTS_DOCUMENT_ROW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_DOCUMENTS_DOCUMENT_ROW))
+#define GEDIT_IS_DOCUMENTS_DOCUMENT_ROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_DOCUMENTS_DOCUMENT_ROW))
+#define GEDIT_DOCUMENTS_DOCUMENT_ROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_DOCUMENTS_DOCUMENT_ROW, GeditDocumentsDocumentRowClass))
+
+typedef struct _GeditDocumentsDocumentRowClass GeditDocumentsDocumentRowClass;
+
+struct _GeditDocumentsDocumentRowClass
+{
+ GtkListBoxRowClass parent_class;
+};
+
+GType gedit_documents_document_row_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (GeditDocumentsDocumentRow, gedit_documents_document_row, GTK_TYPE_LIST_BOX_ROW)
+
+static GtkWidget *gedit_documents_document_row_new (GeditDocumentsPanel *panel,
+ GeditTab *tab);
+static GtkWidget *gedit_documents_group_row_new (GeditDocumentsPanel *panel,
+ GeditNotebook *notebook);
+
+struct _GeditDocumentsPanel
+{
+ GtkBox parent_instance;
+
+ GeditWindow *window;
+ GeditMultiNotebook *mnb;
+ GtkWidget *listbox;
+
+ guint selection_changed_handler_id;
+ guint tab_switched_handler_id;
+ gboolean is_in_tab_switched;
+
+ /* Flag to workaround first GroupRow selection at start ( we don't want to show it ) */
+ gboolean first_selection;
+ GtkWidget *current_selection;
+
+ GtkAdjustment *adjustment;
+
+ guint nb_row_notebook;
+ guint nb_row_tab;
+
+ GtkTargetList *source_targets;
+ GtkWidget *dnd_window;
+ GtkWidget *row_placeholder;
+ guint row_placeholder_index;
+ guint row_destination_index;
+ GtkWidget *drag_document_row;
+ gint row_source_row_offset;
+ gint document_row_height;
+ gint drag_document_row_x;
+ gint drag_document_row_y;
+ gint drag_root_x;
+ gint drag_root_y;
+ gboolean is_on_drag;
+};
+
+enum
+{
+ PROP_0,
+ PROP_WINDOW,
+ LAST_PROP
+};
+
+static GParamSpec *properties[LAST_PROP];
+
+G_DEFINE_TYPE (GeditDocumentsPanel, gedit_documents_panel, GTK_TYPE_BOX)
+
+static const GtkTargetEntry panel_targets [] = {
+ {"GEDIT_DOCUMENTS_DOCUMENT_ROW", GTK_TARGET_SAME_APP, 0},
+};
+
+#define MAX_DOC_NAME_LENGTH 60
+
+#define ROW_OUTSIDE_LISTBOX -1
+
+static guint
+get_nb_visible_rows (GeditDocumentsPanel *panel)
+{
+ guint nb = 0;
+
+ if (panel->nb_row_notebook > 1)
+ {
+ nb += panel->nb_row_notebook;
+ }
+
+ nb += panel->nb_row_tab;
+
+ return nb;
+}
+
+static guint
+get_row_visible_index (GeditDocumentsPanel *panel,
+ GtkWidget *searched_row)
+{
+ GList *children;
+ GList *l;
+ guint nb_notebook_row = 0;
+ guint nb_tab_row = 0;
+
+ children = gtk_container_get_children (GTK_CONTAINER (panel->listbox));
+
+ for (l = children; l != NULL; l = g_list_next (l))
+ {
+ GtkWidget *row = l->data;
+
+ if (GEDIT_IS_DOCUMENTS_GROUP_ROW (row))
+ {
+ nb_notebook_row += 1;
+ }
+ else
+ {
+ nb_tab_row += 1;
+ }
+
+ if (row == searched_row)
+ {
+ break;
+ }
+ }
+
+ g_list_free (children);
+
+ if (panel->nb_row_notebook == 1)
+ {
+ nb_notebook_row = 0;
+ }
+
+ return nb_tab_row + nb_notebook_row - 1;
+}
+
+/* We do not grab focus on the row, so scroll it into view manually */
+static void
+make_row_visible (GeditDocumentsPanel *panel,
+ GtkWidget *row)
+{
+ gdouble adjustment_value;
+ gdouble adjustment_lower;
+ gdouble adjustment_upper;
+ gdouble adjustment_page_size;
+ gdouble nb_visible_rows;
+ gdouble row_visible_index;
+ gdouble row_size;
+ gdouble row_position;
+ gdouble offset;
+ gdouble new_adjustment_value;
+
+ adjustment_value = gtk_adjustment_get_value (panel->adjustment);
+ adjustment_lower = gtk_adjustment_get_lower (panel->adjustment);
+ adjustment_upper = gtk_adjustment_get_upper (panel->adjustment);
+ adjustment_page_size = gtk_adjustment_get_page_size (panel->adjustment);
+
+ nb_visible_rows = get_nb_visible_rows (panel);
+ row_visible_index = get_row_visible_index (panel, GTK_WIDGET (row));
+
+ row_size = (adjustment_upper - adjustment_lower) / nb_visible_rows;
+ row_position = row_size * row_visible_index;
+
+ if (row_position < adjustment_value)
+ {
+ new_adjustment_value = row_position;
+ }
+ else if ((row_position + row_size) > (adjustment_value + adjustment_page_size))
+ {
+ offset = (row_position + row_size) - (adjustment_value + adjustment_page_size);
+ new_adjustment_value = adjustment_value + offset;
+ }
+ else
+ {
+ new_adjustment_value = adjustment_value;
+ }
+
+ gtk_adjustment_set_value (panel->adjustment, new_adjustment_value);
+}
+
+/* This function is a GCompareFunc to use with g_list_find_custom */
+static gint
+listbox_search_function (gconstpointer row,
+ gconstpointer item)
+{
+ GeditDocumentsGenericRow *generic_row = (GeditDocumentsGenericRow *)row;
+ gpointer *searched_item = (gpointer *)generic_row->ref;
+
+ return searched_item == item ? 0 : -1;
+}
+
+static GtkListBoxRow *
+get_row_from_widget (GeditDocumentsPanel *panel,
+ GtkWidget *widget)
+{
+ GList *children;
+ GList *item;
+ GtkListBoxRow *row;
+
+ children = gtk_container_get_children (GTK_CONTAINER (panel->listbox));
+
+ item = g_list_find_custom (children, widget, listbox_search_function);
+ row = item ? item->data : NULL;
+
+ g_list_free (children);
+
+ return row;
+}
+
+static void
+row_select (GeditDocumentsPanel *panel,
+ GtkListBox *listbox,
+ GtkListBoxRow *row)
+{
+ GtkListBoxRow *selected_row = gtk_list_box_get_selected_row (listbox);
+
+ if (row != selected_row)
+ {
+ g_signal_handler_block (listbox, panel->selection_changed_handler_id);
+ gtk_list_box_select_row (listbox, row);
+ g_signal_handler_unblock (listbox, panel->selection_changed_handler_id);
+ }
+
+ panel->current_selection = GTK_WIDGET (row);
+ make_row_visible (panel, GTK_WIDGET (row));
+}
+
+static void
+insert_row (GeditDocumentsPanel *panel,
+ GtkListBox *listbox,
+ GtkWidget *row,
+ gint position)
+{
+ g_signal_handler_block (listbox, panel->selection_changed_handler_id);
+ gtk_list_box_insert (listbox, row, position);
+ g_signal_handler_unblock (listbox, panel->selection_changed_handler_id);
+}
+
+static void
+select_active_tab (GeditDocumentsPanel *panel)
+{
+ GeditNotebook *notebook;
+ gboolean have_tabs;
+ GeditTab *tab;
+
+ notebook = gedit_multi_notebook_get_active_notebook (panel->mnb);
+ have_tabs = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)) > 0;
+ tab = gedit_multi_notebook_get_active_tab (panel->mnb);
+
+ if (notebook != NULL && tab != NULL && have_tabs)
+ {
+ GtkListBoxRow *row = get_row_from_widget (panel, GTK_WIDGET (tab));
+
+ if (row)
+ {
+ row_select (panel, GTK_LIST_BOX (panel->listbox), row);
+ }
+ }
+}
+
+static GtkListBoxRow *
+get_first_notebook_found (GeditDocumentsPanel *panel)
+{
+ GList *children;
+ GList *l;
+ GtkListBoxRow *row = NULL;
+
+ children = gtk_container_get_children (GTK_CONTAINER (panel->listbox));
+
+ for (l = children; l != NULL; l = g_list_next (l))
+ {
+ if (GEDIT_IS_DOCUMENTS_GROUP_ROW (l->data))
+ {
+ row = l->data;
+ break;
+ }
+ }
+
+ g_list_free (children);
+
+ return row;
+}
+
+static void
+multi_notebook_tab_switched (GeditMultiNotebook *mnb,
+ GeditNotebook *old_notebook,
+ GeditTab *old_tab,
+ GeditNotebook *new_notebook,
+ GeditTab *new_tab,
+ GeditDocumentsPanel *panel)
+{
+ gedit_debug (DEBUG_PANEL);
+
+ if (!_gedit_window_is_removing_tabs (panel->window) &&
+ panel->is_in_tab_switched == FALSE)
+ {
+ GtkListBoxRow *row;
+
+ panel->is_in_tab_switched = TRUE;
+
+ row = get_row_from_widget (panel, GTK_WIDGET (new_tab));
+
+ if (row)
+ {
+ row_select (panel, GTK_LIST_BOX (panel->listbox), row);
+ }
+
+ panel->is_in_tab_switched = FALSE;
+ }
+}
+
+static void
+group_row_set_notebook_name (GtkWidget *row)
+{
+ GeditNotebook *notebook;
+ GeditMultiNotebook *mnb;
+ guint num;
+ gchar *name;
+ GeditDocumentsGroupRow *group_row = GEDIT_DOCUMENTS_GROUP_ROW (row);
+
+ notebook = GEDIT_NOTEBOOK (group_row->ref);
+
+ mnb = group_row->panel->mnb;
+ num = gedit_multi_notebook_get_notebook_num (mnb, notebook);
+
+ name = g_strdup_printf (_("Tab Group %i"), num + 1);
+
+ gtk_label_set_text (GTK_LABEL (group_row->label), name);
+
+ g_free (name);
+}
+
+static void
+group_row_update_names (GeditDocumentsPanel *panel,
+ GtkWidget *listbox)
+{
+ GList *children;
+ GList *l;
+ GtkWidget *row;
+
+ children = gtk_container_get_children (GTK_CONTAINER (listbox));
+
+ for (l = children; l != NULL; l = g_list_next (l))
+ {
+ row = l->data;
+
+ if (GEDIT_IS_DOCUMENTS_GROUP_ROW (row))
+ {
+ group_row_set_notebook_name (row);
+ }
+ }
+
+ g_list_free (children);
+}
+
+static void
+group_row_refresh_visibility (GeditDocumentsPanel *panel)
+{
+ gboolean notebook_is_unique;
+ GtkWidget *first_group_row;
+
+ notebook_is_unique = gedit_multi_notebook_get_n_notebooks (panel->mnb) <= 1;
+ first_group_row = GTK_WIDGET (get_first_notebook_found (panel));
+
+ gtk_widget_set_no_show_all (first_group_row, notebook_is_unique);
+ gtk_widget_set_visible (first_group_row, !notebook_is_unique);
+}
+
+static gchar *
+doc_get_name (GeditDocument *doc)
+{
+ gchar *name;
+ gchar *docname;
+
+ name = tepl_file_get_short_name (tepl_buffer_get_file (TEPL_BUFFER (doc)));
+
+ /* Truncate the name so it doesn't get insanely wide. */
+ docname = tepl_utils_str_middle_truncate (name, MAX_DOC_NAME_LENGTH);
+
+ g_free (name);
+
+ return docname;
+}
+
+static void
+document_row_sync_tab_name_and_icon (GeditTab *tab,
+ GParamSpec *pspec,
+ GtkWidget *row)
+{
+ GeditDocumentsDocumentRow *document_row = GEDIT_DOCUMENTS_DOCUMENT_ROW (row);
+ GeditDocument *doc;
+ GtkSourceFile *file;
+ gchar *name;
+ GdkPixbuf *pixbuf;
+
+ doc = gedit_tab_get_document (tab);
+ name = doc_get_name (doc);
+
+ if (!gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc)))
+ {
+ gtk_label_set_text (GTK_LABEL (document_row->label), name);
+ }
+ else
+ {
+ gchar *markup;
+
+ markup = g_markup_printf_escaped ("<b>%s</b>", name);
+ gtk_label_set_markup (GTK_LABEL (document_row->label), markup);
+
+ g_free (markup);
+ }
+
+ g_free (name);
+
+ file = gedit_document_get_file (doc);
+
+ /* The status has as separate label to prevent ellipsizing */
+ if (!gtk_source_file_is_readonly (file))
+ {
+ gtk_widget_hide (GTK_WIDGET (document_row->status_label));
+ }
+ else
+ {
+ gchar *status;
+
+ status = g_strdup_printf ("[%s]", _("Read-Only"));
+
+ gtk_label_set_text (GTK_LABEL (document_row->status_label), status);
+ gtk_widget_show (GTK_WIDGET (document_row->status_label));
+
+ g_free (status);
+ }
+
+ /* Update header of the row */
+ pixbuf = _gedit_tab_get_icon (tab);
+
+ if (pixbuf)
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (document_row->image), pixbuf);
+ }
+ else
+ {
+ gtk_image_clear (GTK_IMAGE (document_row->image));
+ }
+}
+
+static void
+refresh_notebook (GeditDocumentsPanel *panel,
+ GeditNotebook *notebook)
+{
+ GList *tabs;
+ GList *l;
+
+ tabs = gtk_container_get_children (GTK_CONTAINER (notebook));
+
+ for (l = tabs; l != NULL; l = g_list_next (l))
+ {
+ GtkWidget *row;
+
+ row = gedit_documents_document_row_new (panel, GEDIT_TAB (l->data));
+ insert_row (panel, GTK_LIST_BOX (panel->listbox), row, -1);
+ panel->nb_row_tab += 1;
+ }
+
+ g_list_free (tabs);
+}
+
+static void
+refresh_notebook_foreach (GeditNotebook *notebook,
+ GeditDocumentsPanel *panel)
+{
+ GtkWidget *row;
+
+ row = gedit_documents_group_row_new (panel, notebook);
+ insert_row (panel, GTK_LIST_BOX (panel->listbox), row, -1);
+ panel->nb_row_notebook += 1;
+
+ group_row_refresh_visibility (panel);
+ refresh_notebook (panel, notebook);
+}
+
+static void
+refresh_list (GeditDocumentsPanel *panel)
+{
+ GList *children;
+ GList *l;
+
+ /* Clear the listbox */
+ children = gtk_container_get_children (GTK_CONTAINER (panel->listbox));
+
+ for (l = children; l != NULL; l = g_list_next (l))
+ {
+ GeditDocumentsGenericRow *row = l->data;
+
+ if (GEDIT_IS_DOCUMENTS_DOCUMENT_ROW (row))
+ {
+ GeditTab *tab = GEDIT_TAB (row->ref);
+ g_signal_handlers_disconnect_matched (tab,
+ G_SIGNAL_MATCH_FUNC,
+ 0,
+ 0,
+ NULL,
+ G_CALLBACK (document_row_sync_tab_name_and_icon),
+ NULL);
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (row));
+ }
+
+ g_list_free (children);
+
+ gedit_multi_notebook_foreach_notebook (panel->mnb,
+ (GtkCallback)refresh_notebook_foreach,
+ panel);
+ select_active_tab (panel);
+}
+
+static void
+multi_notebook_tab_removed (GeditMultiNotebook *mnb,
+ GeditNotebook *notebook,
+ GeditTab *tab,
+ GeditDocumentsPanel *panel)
+{
+ GtkListBoxRow *row;
+
+ gedit_debug (DEBUG_PANEL);
+
+ row = get_row_from_widget (panel, GTK_WIDGET (tab));
+
+ /* Disconnect before destroy it so document_row_sync_tab_name_and_icon()
+ * don't get invalid data */
+ g_signal_handlers_disconnect_by_func (GEDIT_DOCUMENTS_DOCUMENT_ROW (row)->ref,
+ G_CALLBACK (document_row_sync_tab_name_and_icon),
+ row);
+
+ gtk_widget_destroy (GTK_WIDGET (row));
+ panel->nb_row_tab -= 1;
+}
+
+static gint
+get_dest_position_for_tab (GeditDocumentsPanel *panel,
+ GeditNotebook *notebook,
+ GeditTab *tab)
+{
+ gint page_num;
+ GList *children;
+ GList *item;
+ gint res = -1;
+
+ /* Get tab's position in notebook and notebook's position in GtkListBox
+ * then return future tab's position in GtkListBox */
+
+ page_num = gtk_notebook_page_num (GTK_NOTEBOOK (notebook), GTK_WIDGET (tab));
+
+ children = gtk_container_get_children (GTK_CONTAINER (panel->listbox));
+ item = g_list_find_custom (children, notebook, listbox_search_function);
+
+ if (item)
+ {
+ res = 1 + page_num + g_list_position (children, item);
+ }
+
+ g_list_free (children);
+
+ return res;
+}
+
+static void
+multi_notebook_tab_added (GeditMultiNotebook *mnb,
+ GeditNotebook *notebook,
+ GeditTab *tab,
+ GeditDocumentsPanel *panel)
+{
+ gint position;
+ GtkWidget *row;
+
+ gedit_debug (DEBUG_PANEL);
+
+ position = get_dest_position_for_tab (panel, notebook, tab);
+
+ if (position == -1)
+ {
+ panel->nb_row_tab = 0;
+ panel->nb_row_notebook = 0;
+
+ refresh_list (panel);
+ }
+ else
+ {
+ /* Add a new tab's row to the listbox */
+ row = gedit_documents_document_row_new (panel, tab);
+ insert_row (panel, GTK_LIST_BOX (panel->listbox), row, position);
+
+ panel->nb_row_tab += 1;
+
+ if (tab == gedit_multi_notebook_get_active_tab (mnb))
+ {
+ row_select (panel, GTK_LIST_BOX (panel->listbox), GTK_LIST_BOX_ROW (row));
+ }
+ }
+}
+
+static void
+multi_notebook_notebook_removed (GeditMultiNotebook *mnb,
+ GeditNotebook *notebook,
+ GeditDocumentsPanel *panel)
+{
+ GtkListBoxRow *row;
+
+ gedit_debug (DEBUG_PANEL);
+
+ row = get_row_from_widget (panel, GTK_WIDGET (notebook));
+ gtk_container_remove (GTK_CONTAINER (panel->listbox), GTK_WIDGET (row));
+
+ panel->nb_row_notebook -= 1;
+
+ group_row_refresh_visibility (panel);
+ group_row_update_names (panel, panel->listbox);
+}
+
+static void
+row_move (GeditDocumentsPanel *panel,
+ GeditNotebook *notebook,
+ GtkWidget *tab,
+ GtkWidget *row)
+{
+ gint position;
+
+ g_object_ref (row);
+
+ gtk_container_remove (GTK_CONTAINER (panel->listbox), GTK_WIDGET (row));
+ position = get_dest_position_for_tab (panel, notebook, GEDIT_TAB (tab));
+
+ g_signal_handler_block (panel->listbox, panel->selection_changed_handler_id);
+
+ gtk_list_box_insert (GTK_LIST_BOX (panel->listbox), row, position);
+ g_object_unref (row);
+
+ g_signal_handler_unblock (GTK_LIST_BOX (panel->listbox), panel->selection_changed_handler_id);
+}
+
+static void
+multi_notebook_tabs_reordered (GeditMultiNotebook *mnb,
+ GeditNotebook *notebook,
+ GtkWidget *page,
+ gint page_num,
+ GeditDocumentsPanel *panel)
+{
+ GtkListBoxRow *row;
+
+ gedit_debug (DEBUG_PANEL);
+
+ row = get_row_from_widget (panel, GTK_WIDGET (page));
+
+ row_move (panel, notebook, page, GTK_WIDGET (row));
+
+ row_select (panel, GTK_LIST_BOX (panel->listbox), GTK_LIST_BOX_ROW (row));
+}
+
+static void
+set_window (GeditDocumentsPanel *panel,
+ GeditWindow *window)
+{
+ panel->window = g_object_ref (window);
+ panel->mnb = GEDIT_MULTI_NOTEBOOK (_gedit_window_get_multi_notebook (window));
+
+ g_signal_connect (panel->mnb,
+ "notebook-removed",
+ G_CALLBACK (multi_notebook_notebook_removed),
+ panel);
+ g_signal_connect (panel->mnb,
+ "tab-added",
+ G_CALLBACK (multi_notebook_tab_added),
+ panel);
+ g_signal_connect (panel->mnb,
+ "tab-removed",
+ G_CALLBACK (multi_notebook_tab_removed),
+ panel);
+ g_signal_connect (panel->mnb,
+ "page-reordered",
+ G_CALLBACK (multi_notebook_tabs_reordered),
+ panel);
+
+ panel->tab_switched_handler_id = g_signal_connect (panel->mnb,
+ "switch-tab",
+ G_CALLBACK (multi_notebook_tab_switched),
+ panel);
+
+ panel->first_selection = TRUE;
+
+ refresh_list (panel);
+ group_row_refresh_visibility (panel);
+}
+
+static void
+listbox_selection_changed (GtkListBox *listbox,
+ GtkListBoxRow *row,
+ GeditDocumentsPanel *panel)
+{
+ if (row == NULL)
+ {
+ /* No selection on document panel */
+ return;
+ }
+
+ /* When the window is shown, the first notebook row is selected
+ * and therefore also shown - we don't want this */
+
+ if (panel->first_selection)
+ {
+ panel->first_selection = FALSE;
+ group_row_refresh_visibility (panel);
+ }
+
+ g_signal_handler_block (panel->mnb, panel->tab_switched_handler_id);
+
+ if (GEDIT_IS_DOCUMENTS_DOCUMENT_ROW (row))
+ {
+ gedit_multi_notebook_set_active_tab (panel->mnb,
+ GEDIT_TAB (GEDIT_DOCUMENTS_DOCUMENT_ROW (row)->ref));
+
+ panel->current_selection = GTK_WIDGET (row);
+ }
+ else if (GEDIT_IS_DOCUMENTS_GROUP_ROW (row) && panel->current_selection)
+ {
+ row_select (panel,
+ GTK_LIST_BOX (panel->listbox),
+ GTK_LIST_BOX_ROW (panel->current_selection));
+
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ g_signal_handler_unblock (panel->mnb, panel->tab_switched_handler_id);
+}
+
+static void
+gedit_documents_panel_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_WINDOW:
+ set_window (panel, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_documents_panel_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (object);
+
+ switch (prop_id)
+ {
+ case PROP_WINDOW:
+ g_value_set_object (value, panel->window);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gedit_documents_panel_finalize (GObject *object)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (object);
+
+ g_signal_handlers_disconnect_by_func (panel->mnb,
+ G_CALLBACK (multi_notebook_notebook_removed),
+ panel);
+ g_signal_handlers_disconnect_by_func (panel->mnb,
+ G_CALLBACK (multi_notebook_tab_added),
+ panel);
+ g_signal_handlers_disconnect_by_func (panel->mnb,
+ G_CALLBACK (multi_notebook_tab_removed),
+ panel);
+ g_signal_handlers_disconnect_by_func (panel->mnb,
+ G_CALLBACK (multi_notebook_tabs_reordered),
+ panel);
+ g_signal_handlers_disconnect_by_func (panel->mnb,
+ G_CALLBACK (multi_notebook_tab_switched),
+ panel);
+
+ G_OBJECT_CLASS (gedit_documents_panel_parent_class)->finalize (object);
+}
+
+static void
+gedit_documents_panel_dispose (GObject *object)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (object);
+
+ g_clear_object (&panel->window);
+
+ if (panel->source_targets)
+ {
+ gtk_target_list_unref (panel->source_targets);
+ panel->source_targets = NULL;
+ }
+
+ G_OBJECT_CLASS (gedit_documents_panel_parent_class)->dispose (object);
+}
+
+static GtkWidget *
+create_placeholder_row (gint height)
+{
+ GtkStyleContext *context;
+
+ GtkWidget *placeholder_row = gtk_list_box_row_new ();
+
+ context = gtk_widget_get_style_context (placeholder_row);
+ gtk_style_context_add_class (context, "gedit-document-panel-placeholder-row");
+
+ gtk_widget_set_size_request (placeholder_row, -1, height);
+
+ return placeholder_row;
+}
+
+static void
+panel_on_drag_begin (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+ GtkWidget *drag_document_row;
+ GtkAllocation allocation;
+ const gchar *name;
+ GtkWidget *label;
+ gint width, height;
+ GtkWidget *image_box;
+ GtkWidget *box;
+ GtkStyleContext *style_context;
+
+ drag_document_row = panel->drag_document_row;
+ gtk_widget_get_allocation (drag_document_row, &allocation);
+ gtk_widget_hide (drag_document_row);
+
+ panel->document_row_height = allocation.height;
+
+ name = gtk_label_get_label (GTK_LABEL (GEDIT_DOCUMENTS_DOCUMENT_ROW (drag_document_row)->label));
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (label), name);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_widget_set_halign (label, GTK_ALIGN_START);
+ gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
+ image_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_set_size_request (image_box, width, height);
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+
+ gtk_box_pack_start (GTK_BOX (box), image_box, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+
+ panel->dnd_window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_widget_set_size_request (panel->dnd_window, allocation.width, allocation.height);
+ gtk_window_set_screen (GTK_WINDOW (panel->dnd_window),
+ gtk_widget_get_screen (drag_document_row));
+
+ style_context = gtk_widget_get_style_context (panel->dnd_window);
+ gtk_style_context_add_class (style_context, "gedit-document-panel-dragged-row");
+
+ gtk_container_add (GTK_CONTAINER (panel->dnd_window), box);
+ gtk_widget_show_all (panel->dnd_window);
+ gtk_widget_set_opacity (panel->dnd_window, 0.8);
+
+ gtk_drag_set_icon_widget (context,
+ panel->dnd_window,
+ panel->drag_document_row_x,
+ panel->drag_document_row_y);
+}
+
+static gboolean
+panel_on_drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+ GeditDocumentsGenericRow *generic_row;
+ GtkWidget *source_panel;
+ gint dest_x, dest_y;
+ gint row_placeholder_index;
+ gint row_index;
+
+ GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
+
+ if (target != gdk_atom_intern_static_string ("GEDIT_DOCUMENTS_DOCUMENT_ROW"))
+ {
+ gdk_drag_status (context, 0, time);
+ return FALSE;
+ }
+
+ gtk_widget_translate_coordinates (widget, panel->listbox,
+ x, y,
+ &dest_x, &dest_y);
+
+ generic_row = (GeditDocumentsGenericRow *)gtk_list_box_get_row_at_y (GTK_LIST_BOX (panel->listbox), dest_y);
+ source_panel = gtk_drag_get_source_widget (context);
+
+ if (!panel->row_placeholder)
+ {
+ if (!generic_row)
+ {
+ /* We don't have a row height to use, so use the source one */
+ panel->document_row_height = GEDIT_DOCUMENTS_PANEL (source_panel)->document_row_height;
+ }
+ else
+ {
+ GtkAllocation allocation;
+
+ gtk_widget_get_allocation (GTK_WIDGET (generic_row), &allocation);
+ panel->document_row_height = allocation.height;
+ }
+
+ panel->row_placeholder = create_placeholder_row (panel->document_row_height);
+ gtk_widget_show (panel->row_placeholder);
+ g_object_ref_sink (panel->row_placeholder);
+ }
+ else if (GTK_WIDGET (generic_row) == panel->row_placeholder)
+ {
+ /* cursor on placeholder */
+ gdk_drag_status (context, GDK_ACTION_MOVE, time);
+
+ return TRUE;
+ }
+
+ if (!generic_row)
+ {
+ /* cursor on empty space => put the placeholder at end of list */
+ GList *children = gtk_container_get_children (GTK_CONTAINER (panel->listbox));
+
+ row_placeholder_index = g_list_length (children);
+ g_list_free (children);
+ }
+ else
+ {
+ row_index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (generic_row));
+
+ gtk_widget_translate_coordinates (widget, GTK_WIDGET (generic_row),
+ x, y,
+ &dest_x, &dest_y);
+
+ if (dest_y <= panel->document_row_height / 2 && row_index > 0)
+ {
+ row_placeholder_index = row_index;
+ }
+ else
+ {
+ row_placeholder_index = row_index + 1;
+ }
+ }
+
+ if (source_panel == widget)
+ {
+ /* Adjustment because of hidden source row */
+ gint source_row_index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (panel->drag_document_row));
+ panel->row_source_row_offset = source_row_index < row_placeholder_index ? -1 : 0;
+ }
+
+ if (panel->row_placeholder_index != row_placeholder_index)
+ {
+ if (panel->row_placeholder_index != ROW_OUTSIDE_LISTBOX)
+ {
+ gtk_container_remove (GTK_CONTAINER (panel->listbox),
+ panel->row_placeholder);
+
+ if (panel->row_placeholder_index < row_placeholder_index)
+ {
+ /* Adjustment because of existing placeholder row */
+ row_placeholder_index -= 1;
+ }
+ }
+
+ panel->row_destination_index = panel->row_placeholder_index = row_placeholder_index;
+
+ gtk_list_box_insert (GTK_LIST_BOX (panel->listbox),
+ panel->row_placeholder,
+ panel->row_placeholder_index);
+ }
+
+ gdk_drag_status (context, GDK_ACTION_MOVE, time);
+
+ return TRUE;
+}
+
+static void
+panel_on_drag_leave (GtkWidget *widget,
+ GdkDragContext *context,
+ guint time)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+
+ if (panel->row_placeholder_index != ROW_OUTSIDE_LISTBOX)
+ {
+ gtk_container_remove (GTK_CONTAINER (panel->listbox), panel->row_placeholder);
+ panel->row_placeholder_index = ROW_OUTSIDE_LISTBOX;
+ }
+}
+
+static gboolean
+panel_on_drag_drop (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+
+ GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
+ GtkWidget *source_widget = gtk_drag_get_source_widget (context);
+
+ if (GEDIT_IS_DOCUMENTS_PANEL (source_widget))
+ {
+ gtk_widget_show (GEDIT_DOCUMENTS_PANEL (source_widget)->drag_document_row);
+ }
+
+ if (target == gdk_atom_intern_static_string ("GEDIT_DOCUMENTS_DOCUMENT_ROW"))
+ {
+ gtk_drag_get_data (widget, context, target, time);
+ return TRUE;
+ }
+
+ panel->row_placeholder_index = ROW_OUTSIDE_LISTBOX;
+ return FALSE;
+}
+
+static void
+panel_on_drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *data,
+ guint info,
+ guint time)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+ GdkAtom target = gtk_selection_data_get_target (data);
+ GdkAtom result;
+
+ if (target == gdk_atom_intern_static_string ("GEDIT_DOCUMENTS_DOCUMENT_ROW"))
+ {
+ gtk_selection_data_set (data,
+ target,
+ 8,
+ (void*)&panel->drag_document_row,
+ sizeof (gpointer));
+ return;
+ }
+
+ result = gtk_drag_dest_find_target (widget, context, panel->source_targets);
+
+ if (result != GDK_NONE)
+ {
+ GeditTab *tab;
+ GeditDocument *doc;
+ gchar *full_name;
+
+ tab = GEDIT_TAB (GEDIT_DOCUMENTS_DOCUMENT_ROW (panel->drag_document_row)->ref);
+ doc = gedit_tab_get_document (tab);
+
+ if (!_gedit_document_is_untitled (doc))
+ {
+ GtkSourceFile *file = gedit_document_get_file (doc);
+ GFile *location = gtk_source_file_get_location (file);
+ full_name = g_file_get_parse_name (location);
+
+ gtk_selection_data_set (data,
+ target,
+ 8,
+ (guchar *)full_name,
+ strlen (full_name));
+ g_free (full_name);
+ }
+ }
+
+ gtk_widget_show (panel->drag_document_row);
+}
+
+static GeditNotebook *
+get_notebook_and_position_from_document_row (GeditDocumentsPanel *panel,
+ gint row_index,
+ gint *position)
+{
+ GList *l;
+ gint index = 0;
+ GeditDocumentsGroupRow *row;
+
+ GList *children = gtk_container_get_children (GTK_CONTAINER (panel->listbox));
+ gint nb_elements = g_list_length (children);
+
+ if (nb_elements == 1)
+ {
+ row = children->data;
+ }
+ else
+ {
+ l = g_list_nth (children, row_index - 1);
+
+ while (TRUE)
+ {
+ row = l->data;
+
+ if (GEDIT_IS_DOCUMENTS_GROUP_ROW (row))
+ {
+ break;
+ }
+
+ l = g_list_previous (l);
+ index += 1;
+ }
+ }
+
+ g_list_free (children);
+
+ *position = index;
+ return GEDIT_NOTEBOOK (row->ref);
+}
+
+static void
+panel_on_drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *data,
+ guint info,
+ guint time)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+ GeditDocumentsPanel *source_panel = NULL;
+
+ GtkWidget *source_widget = gtk_drag_get_source_widget (context);
+
+ if (GEDIT_IS_DOCUMENTS_PANEL (source_widget))
+ {
+ source_panel = GEDIT_DOCUMENTS_PANEL (source_widget);
+ }
+
+ GtkWidget **source_row = (void*) gtk_selection_data_get_data (data);
+
+ if (source_panel &&
+ gtk_selection_data_get_target (data) == gdk_atom_intern_static_string ("GEDIT_DOCUMENTS_DOCUMENT_ROW"))
+ {
+ gint source_index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (*source_row));
+
+ /* And finally, we can move the row */
+ if (source_panel != panel ||
+ (panel->row_destination_index != source_index &&
+ panel->row_destination_index != source_index + 1))
+ {
+ GeditNotebook *old_notebook, *new_notebook;
+ gint position;
+
+ GeditTab *tab = GEDIT_TAB (GEDIT_DOCUMENTS_DOCUMENT_ROW (*source_row)->ref);
+
+ old_notebook = gedit_multi_notebook_get_notebook_for_tab (source_panel->mnb, tab);
+ new_notebook = get_notebook_and_position_from_document_row (panel,
+ panel->row_destination_index,
+ &position);
+ if (old_notebook == new_notebook)
+ {
+ gtk_widget_show (*source_row);
+
+ gtk_notebook_reorder_child (GTK_NOTEBOOK (new_notebook),
+ GTK_WIDGET (tab),
+ position + panel->row_source_row_offset);
+ }
+ else
+ {
+ gedit_notebook_move_tab (old_notebook, new_notebook, tab, position);
+ }
+
+ if (tab != gedit_multi_notebook_get_active_tab (panel->mnb))
+ {
+ g_signal_handler_block (panel->mnb, panel->tab_switched_handler_id);
+ gedit_multi_notebook_set_active_tab (panel->mnb, tab);
+ g_signal_handler_unblock (panel->mnb, panel->tab_switched_handler_id);
+ }
+ }
+
+ gtk_drag_finish (context, TRUE, FALSE, time);
+ }
+ else
+ {
+ gtk_drag_finish (context, FALSE, FALSE, time);
+ }
+
+ panel->row_destination_index = panel->row_placeholder_index = ROW_OUTSIDE_LISTBOX;
+
+ if (panel->row_placeholder)
+ {
+ gtk_widget_destroy (panel->row_placeholder);
+ panel->row_placeholder = NULL;
+ }
+}
+
+static void
+panel_on_drag_end (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+
+ panel->drag_document_row = NULL;
+ panel->is_on_drag = FALSE;
+
+ gtk_widget_destroy (panel->dnd_window);
+ panel->dnd_window = NULL;
+}
+
+static gboolean
+panel_on_drag_failed (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkDragResult result)
+{
+ GtkWidget *source_widget = gtk_drag_get_source_widget (context);
+
+ if (GEDIT_IS_DOCUMENTS_PANEL (source_widget))
+ {
+ gtk_widget_show (GEDIT_DOCUMENTS_PANEL (source_widget)->drag_document_row);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+panel_on_motion_notify (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ GeditDocumentsPanel *panel = GEDIT_DOCUMENTS_PANEL (widget);
+
+ if (panel->drag_document_row == NULL || panel->is_on_drag)
+ {
+ return FALSE;
+ }
+
+ if (!(event->state & GDK_BUTTON1_MASK))
+ {
+ panel->drag_document_row = NULL;
+
+ return FALSE;
+ }
+
+ if (gtk_drag_check_threshold (widget,
+ panel->drag_root_x, panel->drag_root_y,
+ event->x_root, event->y_root))
+ {
+ panel->is_on_drag = TRUE;
+
+ gtk_drag_begin_with_coordinates (widget, panel->source_targets, GDK_ACTION_MOVE,
+ GDK_BUTTON_PRIMARY, (GdkEvent*)event,
+ -1, -1);
+ }
+
+ return FALSE;
+}
+
+static void
+gedit_documents_panel_class_init (GeditDocumentsPanelClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->finalize = gedit_documents_panel_finalize;
+ object_class->dispose = gedit_documents_panel_dispose;
+ object_class->get_property = gedit_documents_panel_get_property;
+ object_class->set_property = gedit_documents_panel_set_property;
+
+ widget_class->motion_notify_event = panel_on_motion_notify;
+
+ widget_class->drag_begin = panel_on_drag_begin;
+ widget_class->drag_end = panel_on_drag_end;
+ widget_class->drag_failed = panel_on_drag_failed;
+ widget_class->drag_motion = panel_on_drag_motion;
+ widget_class->drag_leave = panel_on_drag_leave;
+ widget_class->drag_drop = panel_on_drag_drop;
+ widget_class->drag_data_get = panel_on_drag_data_get;
+ widget_class->drag_data_received = panel_on_drag_data_received;
+
+ properties[PROP_WINDOW] =
+ g_param_spec_object ("window",
+ "Window",
+ "The GeditWindow this GeditDocumentsPanel is associated with",
+ GEDIT_TYPE_WINDOW,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, properties);
+}
+
+static void
+gedit_documents_panel_init (GeditDocumentsPanel *panel)
+{
+ GtkWidget *sw;
+ GtkStyleContext *context;
+
+ gedit_debug (DEBUG_PANEL);
+
+ gtk_orientable_set_orientation (GTK_ORIENTABLE (panel),
+ GTK_ORIENTATION_VERTICAL);
+
+ /* Create the scrolled window */
+ sw = gtk_scrolled_window_new (NULL, NULL);
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_show (sw);
+ gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0);
+
+ /* Create the listbox */
+ panel->listbox = gtk_list_box_new ();
+
+ gtk_container_add (GTK_CONTAINER (sw), panel->listbox);
+
+ panel->adjustment = gtk_list_box_get_adjustment (GTK_LIST_BOX (panel->listbox));
+
+ /* Disable focus so it doesn't steal focus each time from the view */
+ gtk_widget_set_can_focus (panel->listbox, FALSE);
+
+ /* Css style */
+ context = gtk_widget_get_style_context (panel->listbox);
+ gtk_style_context_add_class (context, "gedit-document-panel");
+
+ panel->selection_changed_handler_id = g_signal_connect (panel->listbox,
+ "row-selected",
+ G_CALLBACK (listbox_selection_changed),
+ panel);
+ panel->is_in_tab_switched = FALSE;
+ panel->current_selection = NULL;
+ panel->nb_row_notebook = 0;
+ panel->nb_row_tab = 0;
+
+ /* Drag and drop support */
+ panel->source_targets = gtk_target_list_new (panel_targets, G_N_ELEMENTS (panel_targets));
+ gtk_target_list_add_text_targets (panel->source_targets, 0);
+
+ gtk_drag_dest_set (GTK_WIDGET (panel), 0,
+ panel_targets, G_N_ELEMENTS (panel_targets),
+ GDK_ACTION_MOVE);
+
+ gtk_drag_dest_set_track_motion (GTK_WIDGET (panel), TRUE);
+
+ panel->drag_document_row = NULL;
+ panel->row_placeholder = NULL;
+ panel->row_placeholder_index = ROW_OUTSIDE_LISTBOX;
+ panel->row_destination_index = ROW_OUTSIDE_LISTBOX;
+ panel->row_source_row_offset = 0;
+ panel->is_on_drag = FALSE;
+}
+
+GtkWidget *
+gedit_documents_panel_new (GeditWindow *window)
+{
+ g_return_val_if_fail (GEDIT_IS_WINDOW (window), NULL);
+
+ return g_object_new (GEDIT_TYPE_DOCUMENTS_PANEL,
+ "window", window,
+ NULL);
+}
+
+static void
+row_on_close_button_clicked (GtkWidget *close_button,
+ GtkWidget *row)
+{
+ GeditDocumentsGenericRow *generic_row = (GeditDocumentsGenericRow *)row;
+ GeditWindow *window = generic_row->panel->window;
+ GtkWidget *ref;
+
+ if (GEDIT_IS_DOCUMENTS_GROUP_ROW (row))
+ {
+ ref = GEDIT_DOCUMENTS_GROUP_ROW (row)->ref;
+ _gedit_cmd_file_close_notebook (window, GEDIT_NOTEBOOK (ref));
+ }
+ else if (GEDIT_IS_DOCUMENTS_DOCUMENT_ROW (row))
+ {
+ ref = GEDIT_DOCUMENTS_DOCUMENT_ROW (row)->ref;
+ _gedit_cmd_file_close_tab (GEDIT_TAB (ref), window);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+row_on_button_pressed (GtkWidget *row_event_box,
+ GdkEventButton *event,
+ GtkWidget *row)
+{
+ if (gdk_event_get_event_type ((GdkEvent *)event) == GDK_BUTTON_PRESS &&
+ GEDIT_IS_DOCUMENTS_DOCUMENT_ROW (row))
+ {
+ GeditDocumentsDocumentRow *document_row = GEDIT_DOCUMENTS_DOCUMENT_ROW (row);
+ GeditDocumentsPanel *panel = document_row->panel;
+
+ if (event->button == GDK_BUTTON_PRIMARY)
+ {
+ /* memorize row and clicked position for possible drag'n drop */
+ panel->drag_document_row = row;
+ panel->drag_document_row_x = (gint)event->x;
+ panel->drag_document_row_y = (gint)event->y;
+
+ panel->drag_root_x = event->x_root;
+ panel->drag_root_y = event->y_root;
+
+ return FALSE;
+ }
+
+ panel->drag_document_row = NULL;
+
+ if (gdk_event_triggers_context_menu ((GdkEvent *)event))
+ {
+ GeditWindow *window = panel->window;
+ GeditTab *tab = GEDIT_TAB (document_row->ref);
+ GtkWidget *menu = gedit_notebook_popup_menu_new (window, tab);
+
+ g_signal_connect (menu,
+ "selection-done",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *)event);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+document_row_create_header (GtkWidget *row)
+{
+ GeditDocumentsDocumentRow *document_row = GEDIT_DOCUMENTS_DOCUMENT_ROW (row);
+ GtkWidget *image_box;
+ gint width, height;
+
+ gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height);
+
+ image_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_set_size_request (image_box, width, height);
+
+ document_row->image = gtk_image_new ();
+
+ gtk_container_add (GTK_CONTAINER (image_box), document_row->image);
+
+ gtk_box_pack_start (GTK_BOX (document_row->box),
+ image_box, FALSE, FALSE, 0);
+
+ /* Set the header on front of all other widget in the row */
+ gtk_box_reorder_child (GTK_BOX (document_row->box),
+ image_box, 0);
+
+ gtk_widget_show_all (image_box);
+}
+
+static GtkWidget *
+row_create (GtkWidget *row)
+{
+ GeditDocumentsGenericRow *generic_row = (GeditDocumentsGenericRow *)row;
+ GtkWidget *event_box;
+ GtkStyleContext *context;
+ GtkWidget *image;
+ GIcon *icon;
+
+ gedit_debug (DEBUG_PANEL);
+
+ event_box = gtk_event_box_new ();
+ generic_row->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
+
+ gtk_container_add (GTK_CONTAINER (event_box), generic_row->box);
+
+ generic_row->label = gtk_label_new (NULL);
+ gtk_label_set_ellipsize (GTK_LABEL (generic_row->label), PANGO_ELLIPSIZE_END);
+ gtk_widget_set_halign (generic_row->label, GTK_ALIGN_START);
+ gtk_widget_set_valign (generic_row->label, GTK_ALIGN_CENTER);
+
+ generic_row->status_label = gtk_label_new (NULL);
+ gtk_widget_set_halign (generic_row->status_label, GTK_ALIGN_END);
+ gtk_widget_set_valign (generic_row->status_label, GTK_ALIGN_CENTER);
+
+ generic_row->close_button = GTK_WIDGET (g_object_new (GTK_TYPE_BUTTON,
+ "relief", GTK_RELIEF_NONE,
+ "focus-on-click", FALSE,
+ NULL));
+
+ context = gtk_widget_get_style_context (generic_row->close_button);
+ gtk_style_context_add_class (context, "flat");
+ gtk_style_context_add_class (context, "small-button");
+
+ icon = g_themed_icon_new_with_default_fallbacks ("window-close-symbolic");
+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU);
+ gtk_widget_show (image);
+ g_object_unref (icon);
+
+ gtk_container_add (GTK_CONTAINER (generic_row->close_button), image);
+
+ gtk_box_pack_start (GTK_BOX (generic_row->box),
+ generic_row->label, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (generic_row->box),
+ generic_row->status_label, FALSE, FALSE, 0);
+
+ gtk_box_pack_end (GTK_BOX (generic_row->box),
+ generic_row->close_button, FALSE, FALSE, 0);
+
+ g_signal_connect (event_box,
+ "button-press-event",
+ G_CALLBACK (row_on_button_pressed),
+ row);
+ g_signal_connect (generic_row->close_button,
+ "clicked",
+ G_CALLBACK (row_on_close_button_clicked),
+ row);
+
+ gtk_widget_set_no_show_all (generic_row->status_label, TRUE);
+ gtk_widget_show_all (event_box);
+
+ return event_box;
+}
+
+static gboolean
+document_row_query_tooltip (GtkWidget *row,
+ gint x,
+ gint y,
+ gboolean keyboard_tip,
+ GtkTooltip *tooltip)
+{
+ GeditDocumentsGenericRow *generic_row = (GeditDocumentsGenericRow *)row;
+ gchar *markup;
+
+ if (!GEDIT_IS_DOCUMENTS_DOCUMENT_ROW (row))
+ {
+ return FALSE;
+ }
+
+ markup = _gedit_tab_get_tooltip (GEDIT_TAB (generic_row->ref));
+ gtk_tooltip_set_markup (tooltip, markup);
+
+ g_free (markup);
+
+ return TRUE;
+}
+
+/* Gedit Document Row */
+static void
+gedit_documents_document_row_class_init (GeditDocumentsDocumentRowClass *klass)
+{
+}
+
+static void
+gedit_documents_document_row_init (GeditDocumentsDocumentRow *row)
+{
+ GtkWidget *row_widget;
+ GtkStyleContext *context;
+
+ gedit_debug (DEBUG_PANEL);
+
+ row_widget = row_create (GTK_WIDGET (row));
+ gtk_container_add (GTK_CONTAINER (row), row_widget);
+
+ document_row_create_header (GTK_WIDGET (row));
+
+ gtk_widget_set_has_tooltip (GTK_WIDGET (row), TRUE);
+
+ /* Css style */
+ context = gtk_widget_get_style_context (GTK_WIDGET (row));
+ gtk_style_context_add_class (context, "gedit-document-panel-document-row");
+
+ gtk_widget_show_all (GTK_WIDGET (row));
+
+ gtk_widget_set_can_focus (GTK_WIDGET (row), FALSE);
+}
+
+/* Gedit Group Row */
+static void
+gedit_documents_group_row_class_init (GeditDocumentsGroupRowClass *klass)
+{
+}
+
+static void
+gedit_documents_group_row_init (GeditDocumentsGroupRow *row)
+{
+ GtkWidget *row_widget;
+ GtkStyleContext *context;
+
+ gedit_debug (DEBUG_PANEL);
+
+ row_widget = row_create (GTK_WIDGET (row));
+ gtk_container_add (GTK_CONTAINER (row), row_widget);
+
+ /* Css style */
+ context = gtk_widget_get_style_context (GTK_WIDGET (row));
+ gtk_style_context_add_class (context, "gedit-document-panel-group-row");
+
+ gtk_widget_show_all (GTK_WIDGET (row));
+
+ gtk_widget_set_can_focus (GTK_WIDGET (row), FALSE);
+}
+
+static GtkWidget *
+gedit_documents_document_row_new (GeditDocumentsPanel *panel,
+ GeditTab *tab)
+{
+ GeditDocumentsDocumentRow *row;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENTS_PANEL (panel), NULL);
+ g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL);
+
+ gedit_debug (DEBUG_PANEL);
+
+ row = g_object_new (GEDIT_TYPE_DOCUMENTS_DOCUMENT_ROW, NULL);
+ row->ref = GTK_WIDGET (tab);
+ row->panel = panel;
+
+ g_signal_connect (row->ref,
+ "notify::name",
+ G_CALLBACK (document_row_sync_tab_name_and_icon),
+ row);
+ g_signal_connect (row->ref,
+ "notify::state",
+ G_CALLBACK (document_row_sync_tab_name_and_icon),
+ row);
+ g_signal_connect (row,
+ "query-tooltip",
+ G_CALLBACK (document_row_query_tooltip),
+ NULL);
+
+ document_row_sync_tab_name_and_icon (GEDIT_TAB (row->ref), NULL, GTK_WIDGET (row));
+
+ return GTK_WIDGET (row);
+}
+
+static GtkWidget *
+gedit_documents_group_row_new (GeditDocumentsPanel *panel,
+ GeditNotebook *notebook)
+{
+ GeditDocumentsGroupRow *row;
+
+ g_return_val_if_fail (GEDIT_IS_DOCUMENTS_PANEL (panel), NULL);
+ g_return_val_if_fail (GEDIT_IS_NOTEBOOK (notebook), NULL);
+
+ gedit_debug (DEBUG_PANEL);
+
+ row = g_object_new (GEDIT_TYPE_DOCUMENTS_GROUP_ROW, NULL);
+ row->ref = GTK_WIDGET (notebook);
+ row->panel = panel;
+
+ group_row_set_notebook_name (GTK_WIDGET (row));
+
+ return GTK_WIDGET (row);
+}
+
+/* ex:set ts=8 noet: */