]> Pileus Git - ~andy/gtk/blob - gtk/gtkselectionwindow.c
Do without GtkSelectionWindow
[~andy/gtk] / gtk / gtkselectionwindow.c
1 /* GTK - The GIMP Toolkit
2  * Copyright © 2013 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 /**
19  * SECTION:gtkselectionwindow
20  * @Short_description: Bubble window for content edition
21  * @Title: GtkSelectionWindow
22  *
23  * GtkSelection widget is a small helper object to implement
24  * touch-friendly content edition. #GtkEntry and #GtkTextView
25  * use this internally to allow text selection edition and
26  * manipulation.
27  */
28
29 #include "config.h"
30 #include "gtkselectionwindowprivate.h"
31 #include "gtkactiongroup.h"
32 #include "gtkuimanager.h"
33 #include "gtkclipboard.h"
34 #include "gtktoolbar.h"
35 #include "gtkprivate.h"
36 #include "gtkintl.h"
37
38 #define TOOLBAR_UI                               \
39   "<ui>"                                         \
40   "  <toolbar>"                                  \
41   "    <toolitem name='cut' action='Cut' />"     \
42   "    <toolitem name='copy' action='Copy' />"   \
43   "    <toolitem name='paste' action='Paste' />" \
44   "    <separator />"                            \
45   "  </toolbar>"                                 \
46   "</ui>"
47
48 static void _action_cut_cb   (GtkAction          *action,
49                               GtkSelectionWindow *window);
50 static void _action_copy_cb  (GtkAction          *action,
51                               GtkSelectionWindow *window);
52 static void _action_paste_cb (GtkAction          *action,
53                               GtkSelectionWindow *window);
54
55 static GtkActionEntry entries[] = {
56   { "Cut", GTK_STOCK_CUT, NULL, NULL, NULL, G_CALLBACK (_action_cut_cb) },
57   { "Copy", GTK_STOCK_COPY, NULL, NULL, NULL, G_CALLBACK (_action_copy_cb) },
58   { "Paste", GTK_STOCK_PASTE, NULL, NULL, NULL, G_CALLBACK (_action_paste_cb) }
59 };
60
61 enum {
62   PROP_EDITABLE = 1,
63   PROP_HAS_SELECTION
64 };
65
66 enum {
67   CUT,
68   COPY,
69   PASTE,
70   N_SIGNALS
71 };
72
73 static guint signals[N_SIGNALS] = { 0 };
74
75 struct _GtkSelectionWindowPrivate
76 {
77   GtkUIManager *ui_manager;
78   GtkWidget *toolbar;
79   guint editable      : 1;
80   guint has_selection : 1;
81 };
82
83 G_DEFINE_TYPE (GtkSelectionWindow, gtk_selection_window, GTK_TYPE_BUBBLE_WINDOW)
84
85 static void
86 _action_cut_cb (GtkAction          *action,
87                 GtkSelectionWindow *window)
88 {
89   g_signal_emit (window, signals[CUT], 0);
90 }
91
92 static void
93 _action_copy_cb (GtkAction          *action,
94                  GtkSelectionWindow *window)
95 {
96   g_signal_emit (window, signals[COPY], 0);
97 }
98
99 static void
100 _action_paste_cb (GtkAction          *action,
101                   GtkSelectionWindow *window)
102 {
103   g_signal_emit (window, signals[PASTE], 0);
104 }
105
106 static void
107 _gtk_selection_window_update_state (GtkSelectionWindow *window)
108 {
109   GtkSelectionWindowPrivate *priv;
110   GtkClipboard *clipboard;
111   gboolean text_available;
112   GtkAction *action;
113
114   priv = window->_priv;
115   clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window),
116                                         GDK_SELECTION_CLIPBOARD);
117   text_available = gtk_clipboard_wait_is_text_available (clipboard);
118
119   action = gtk_ui_manager_get_action (priv->ui_manager, "/toolbar/cut");
120   gtk_action_set_sensitive (action, priv->editable && priv->has_selection);
121
122   action = gtk_ui_manager_get_action (priv->ui_manager, "/toolbar/copy");
123   gtk_action_set_sensitive (action, priv->has_selection);
124
125   action = gtk_ui_manager_get_action (priv->ui_manager, "/toolbar/paste");
126   gtk_action_set_sensitive (action, text_available && priv->editable);
127 }
128
129 static void
130 gtk_selection_window_map (GtkWidget *widget)
131 {
132   _gtk_selection_window_update_state (GTK_SELECTION_WINDOW (widget));
133   GTK_WIDGET_CLASS (gtk_selection_window_parent_class)->map (widget);
134 }
135
136 static void
137 gtk_selection_window_finalize (GObject *object)
138 {
139   GtkSelectionWindowPrivate *priv;
140
141   priv = GTK_SELECTION_WINDOW (object)->_priv;
142   g_object_unref (priv->ui_manager);
143
144   G_OBJECT_CLASS (gtk_selection_window_parent_class)->finalize (object);
145 }
146
147 static void
148 gtk_selection_window_set_property (GObject      *object,
149                                    guint         prop_id,
150                                    const GValue *value,
151                                    GParamSpec   *pspec)
152 {
153   switch (prop_id)
154     {
155     case PROP_EDITABLE:
156       gtk_selection_window_set_editable (GTK_SELECTION_WINDOW (object),
157                                          g_value_get_boolean (value));
158       break;
159     case PROP_HAS_SELECTION:
160       gtk_selection_window_set_has_selection (GTK_SELECTION_WINDOW (object),
161                                               g_value_get_boolean (value));
162       break;
163     default:
164       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
165       break;
166     }
167 }
168
169 static void
170 gtk_selection_window_get_property (GObject    *object,
171                                    guint       prop_id,
172                                    GValue     *value,
173                                    GParamSpec *pspec)
174 {
175   GtkSelectionWindowPrivate *priv;
176
177   priv = GTK_SELECTION_WINDOW (object)->_priv;
178
179   switch (prop_id)
180     {
181     case PROP_EDITABLE:
182       g_value_set_boolean (value, priv->editable);
183       break;
184     case PROP_HAS_SELECTION:
185       g_value_set_boolean (value, priv->has_selection);
186       break;
187     default:
188       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189       break;
190     }
191 }
192
193 static void
194 gtk_selection_window_class_init (GtkSelectionWindowClass *klass)
195 {
196   GObjectClass *object_class = G_OBJECT_CLASS (klass);
197   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
198
199   object_class->finalize = gtk_selection_window_finalize;
200   object_class->set_property = gtk_selection_window_set_property;
201   object_class->get_property = gtk_selection_window_get_property;
202
203   widget_class->map = gtk_selection_window_map;
204
205   g_object_class_install_property (object_class,
206                                    PROP_EDITABLE,
207                                    g_param_spec_boolean ("editable",
208                                                          P_("Editable"),
209                                                          P_("Whether content is editable"),
210                                                          TRUE,
211                                                          GTK_PARAM_READWRITE |
212                                                          G_PARAM_CONSTRUCT));
213   g_object_class_install_property (object_class,
214                                    PROP_HAS_SELECTION,
215                                    g_param_spec_boolean ("has-selection",
216                                                          P_("Has selection"),
217                                                          P_("Whether there is any content currently selected"),
218                                                          TRUE,
219                                                          GTK_PARAM_READWRITE |
220                                                          G_PARAM_CONSTRUCT));
221   signals[CUT] =
222     g_signal_new (I_("cut"),
223                   G_OBJECT_CLASS_TYPE (object_class),
224                   G_SIGNAL_RUN_LAST, 0,
225                   NULL, NULL,
226                   g_cclosure_marshal_VOID__VOID,
227                   G_TYPE_NONE, 0);
228   signals[COPY] =
229     g_signal_new (I_("copy"),
230                   G_OBJECT_CLASS_TYPE (object_class),
231                   G_SIGNAL_RUN_LAST, 0,
232                   NULL, NULL,
233                   g_cclosure_marshal_VOID__VOID,
234                   G_TYPE_NONE, 0);
235   signals[PASTE] =
236     g_signal_new (I_("paste"),
237                   G_OBJECT_CLASS_TYPE (object_class),
238                   G_SIGNAL_RUN_LAST, 0,
239                   NULL, NULL,
240                   g_cclosure_marshal_VOID__VOID,
241                   G_TYPE_NONE, 0);
242
243   g_type_class_add_private (klass, sizeof (GtkSelectionWindowPrivate));
244 }
245
246 static void
247 gtk_selection_window_init (GtkSelectionWindow *window)
248 {
249   GtkSelectionWindowPrivate *priv;
250   GtkActionGroup *group;
251
252   window->_priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (window,
253                                                       GTK_TYPE_SELECTION_WINDOW,
254                                                       GtkSelectionWindowPrivate);
255
256   group = gtk_action_group_new ("SelectionToolbar");
257   gtk_action_group_add_actions (group, entries, G_N_ELEMENTS (entries), window);
258
259   priv->ui_manager = gtk_ui_manager_new ();
260   gtk_ui_manager_insert_action_group (priv->ui_manager, group, 0);
261   gtk_ui_manager_add_ui_from_string (priv->ui_manager, TOOLBAR_UI, -1, NULL);
262
263   priv->toolbar = gtk_ui_manager_get_widget (priv->ui_manager, "/toolbar");
264   gtk_toolbar_set_show_arrow (GTK_TOOLBAR (priv->toolbar), FALSE);
265   gtk_widget_show_all (priv->toolbar);
266
267   gtk_container_add (GTK_CONTAINER (window), priv->toolbar);
268 }
269
270 /**
271  * gtk_selection_window_new:
272  *
273  * Creates a new #GtkSelectionWindow
274  *
275  * Returns: a newly created #GtkSelectionWindow
276  **/
277 GtkWidget *
278 gtk_selection_window_new (void)
279 {
280   return g_object_new (GTK_TYPE_SELECTION_WINDOW, NULL);
281 }
282
283 /**
284  * gtk_selection_window_set_editable:
285  * @window: a #GtkSelectionWindow
286  * @editable: whether the current selection is editable
287  *
288  * Sets whether the current selection is editable. Toolbar options'
289  * sensitivity will change according to this.
290  *
291  * Since: 3.8
292  **/
293 void
294 gtk_selection_window_set_editable (GtkSelectionWindow *window,
295                                    gboolean            editable)
296 {
297   GtkSelectionWindowPrivate *priv;
298   gboolean need_update;
299
300   g_return_if_fail (GTK_IS_SELECTION_WINDOW (window));
301
302   priv = window->_priv;
303   need_update = priv->editable != editable &&
304     gtk_widget_get_visible (GTK_WIDGET (window));
305   priv->editable = editable;
306
307   if (need_update)
308     _gtk_selection_window_update_state (window);
309
310   g_object_notify (G_OBJECT (window), "editable");
311 }
312
313 /**
314  * gtk_selection_window_get_editable:
315  * @window: a #GtkSelectionWindow
316  *
317  * Returns whether the contents are editable according to @window
318  *
319  * Returns: whether the contents are editable
320  *
321  * Since: 3.8
322  **/
323 gboolean
324 gtk_selection_window_get_editable (GtkSelectionWindow *window)
325 {
326   GtkSelectionWindowPrivate *priv;
327
328   g_return_val_if_fail (GTK_IS_SELECTION_WINDOW (window), FALSE);
329
330   priv = window->_priv;
331
332   return priv->editable;
333 }
334
335 /**
336  * gtk_selection_window_set_has_selection:
337  * @window: a #GtkSelectionWindow
338  * @has_selection: whether there is currently a selection
339  *
340  * Sets whether there is any selected content. Toolbar options'
341  * sensitivity will change according to this.
342  *
343  * Since: 3.8
344  **/
345 void
346 gtk_selection_window_set_has_selection (GtkSelectionWindow *window,
347                                         gboolean            has_selection)
348 {
349   GtkSelectionWindowPrivate *priv;
350   gboolean need_update;
351
352   g_return_if_fail (GTK_IS_SELECTION_WINDOW (window));
353
354   priv = window->_priv;
355   need_update = priv->has_selection != has_selection &&
356     gtk_widget_get_visible (GTK_WIDGET (window));
357   priv->has_selection = has_selection;
358
359   if (need_update)
360     _gtk_selection_window_update_state (window);
361
362   g_object_notify (G_OBJECT (window), "has-selection");
363 }
364
365 /**
366  * gtk_selection_window_get_has_selection:
367  * @window: a #GtkSelectionWindow
368  *
369  * Returns whether there any content is selected according to @window
370  *
371  * Returns: whether there is selected content
372  *
373  * Since: 3.8
374  **/
375 gboolean
376 gtk_selection_window_get_has_selection (GtkSelectionWindow *window)
377 {
378   GtkSelectionWindowPrivate *priv;
379
380   g_return_val_if_fail (GTK_IS_SELECTION_WINDOW (window), FALSE);
381
382   priv = window->_priv;
383
384   return priv->has_selection;
385 }
386
387 /**
388  * gtk_selection_window_get_toolbar:
389  * @window: a #GtkSelectionWindow
390  *
391  * Returns the toolbar contained by @window so e.g. new elements
392  * can be added.
393  *
394  * Returns: the internal toolbar
395  *
396  * Since: 3.8
397  **/
398 GtkWidget *
399 gtk_selection_window_get_toolbar (GtkSelectionWindow *window)
400 {
401   GtkSelectionWindowPrivate *priv;
402
403   g_return_val_if_fail (GTK_IS_SELECTION_WINDOW (window), FALSE);
404
405   priv = window->_priv;
406
407   return priv->toolbar;
408 }