GnuCash  5.6-150-g038405b370+
gnc-cell-renderer-text-view.c
1 /*************************************************************************
2  * The following code implements a text view in a custom GtkCellRenderer.
3  *
4  * Copyright (C) 2020 Robert Fewell
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *************************************************************************/
21 #include <config.h>
22 
23 #include <gtk/gtk.h>
24 #include <glib/gi18n.h>
25 #include <gdk/gdkkeysyms.h>
26 
27 #include "gnc-cell-renderer-text-view.h"
28 #include "gnc-cell-view.h"
29 
30 static GtkCellEditable *gcrtv_start_editing (GtkCellRenderer *cell,
31  GdkEvent *event,
32  GtkWidget *widget,
33  const gchar *path,
34  const GdkRectangle *background_area,
35  const GdkRectangle *cell_area,
36  GtkCellRendererState flags);
37 
38 #define GNC_CELL_RENDERER_TEXT_VIEW_PATH "gnc-cell-renderer-text-view-path"
39 
41 {
42  GtkCellRendererText parent;
43 
44  /* The editable entry. */
45  GtkWidget *editable;
46 };
47 
48 G_DEFINE_TYPE (GncCellRendererTextView, gnc_cell_renderer_text_view, GTK_TYPE_CELL_RENDERER_TEXT)
49 
50 static void
51 gnc_cell_renderer_text_view_init (GncCellRendererTextView *self)
52 {
53 }
54 
55 static void
56 gnc_cell_renderer_text_view_finalize (GObject *object)
57 {
58  G_OBJECT_CLASS (gnc_cell_renderer_text_view_parent_class)->finalize (object);
59 }
60 
61 static void
62 gnc_cell_renderer_text_view_class_init (GncCellRendererTextViewClass *klass)
63 {
64  GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
65  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass);
66 
67  gobject_class->finalize = gnc_cell_renderer_text_view_finalize;
68 
69  cell_class->start_editing = gcrtv_start_editing;
70 }
71 
72 static void
73 gcrtv_editing_done (GtkCellEditable *editable,
74  GncCellRendererTextView *cell_tv)
75 {
76  gchar *path;
77  gchar *new_text;
78 
79  if (GNC_CELL_VIEW(editable)->focus_out_id > 0)
80  {
81  g_signal_handler_disconnect (GNC_CELL_VIEW(editable)->text_view,
82  GNC_CELL_VIEW(editable)->focus_out_id);
83  GNC_CELL_VIEW(editable)->focus_out_id = 0;
84  }
85 
86  if (GNC_CELL_VIEW(editable)->populate_popup_id > 0)
87  {
88  g_signal_handler_disconnect (GNC_CELL_VIEW(editable)->text_view,
89  GNC_CELL_VIEW(editable)->populate_popup_id);
90  GNC_CELL_VIEW(editable)->populate_popup_id = 0;
91  }
92 
93  if (GNC_CELL_VIEW(editable)->editing_canceled)
94  {
95  gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER(cell_tv), TRUE);
96  return;
97  }
98 
99  path = g_object_get_data (G_OBJECT(editable),
100  GNC_CELL_RENDERER_TEXT_VIEW_PATH);
101 
102  new_text = gnc_cell_view_get_text (GNC_CELL_VIEW(editable));
103 
104  gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE(editable));
105 
106  g_signal_emit_by_name (cell_tv, "edited", path, new_text);
107 
108  g_free (new_text);
109 }
110 
111 static gboolean
112 gcrtv_button_press_event (GtkWidget *widget,
113  GdkEventButton *event,
114  gpointer user_data)
115 {
116  // allows mouse clicks in text view
117  return TRUE;
118 }
119 
120 static GtkCellEditable *
121 gcrtv_start_editing (GtkCellRenderer *cell,
122  GdkEvent *event,
123  GtkWidget *widget,
124  const gchar *path,
125  const GdkRectangle *background_area,
126  const GdkRectangle *cell_area,
127  GtkCellRendererState flags)
128 {
129  GncCellRendererTextView *cell_tv = GNC_CELL_RENDERER_TEXT_VIEW(cell);
130  GtkWidget *editable;
131  gchar *text = NULL;
132  gboolean iseditable;
133 
134  g_object_get (G_OBJECT(cell_tv), "editable", &iseditable, NULL);
135 
136  /* If the cell isn't editable we return NULL. */
137  if (iseditable == FALSE)
138  return NULL;
139 
140  editable = g_object_new (GNC_TYPE_CELL_VIEW, NULL);
141 
142  g_signal_connect (editable, "button-press-event",
143  G_CALLBACK(gcrtv_button_press_event),
144  NULL);
145 
146  g_object_get (G_OBJECT(cell), "text", &text, NULL);
147 
148  gnc_cell_view_set_text (GNC_CELL_VIEW(editable), text);
149 
150  g_free (text);
151 
152  gtk_widget_grab_focus (GTK_WIDGET(editable));
153 
154  g_object_set_data_full (G_OBJECT(editable),
155  GNC_CELL_RENDERER_TEXT_VIEW_PATH,
156  g_strdup (path),
157  g_free);
158 
159  gtk_widget_show (editable);
160 
161  g_signal_connect (editable, "editing-done", G_CALLBACK(gcrtv_editing_done), cell_tv);
162 
163  cell_tv->editable = editable;
164 
165  g_object_add_weak_pointer (G_OBJECT(cell_tv->editable),
166  (gpointer) &cell_tv->editable);
167 
168  return GTK_CELL_EDITABLE(editable);
169 }
170 
171 GtkCellRenderer *
172 gnc_cell_renderer_text_view_new (void)
173 {
174  return g_object_new (GNC_TYPE_CELL_RENDERER_TEXT_VIEW, NULL);
175 }