1 /*
2 * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
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
8 * as published by the Free Software Foundation; either version 2
9 * of the 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <string.h>
22 #include <glib/gi18n-lib.h>
23 #include "browser-window.h"
24 #include <libgda/binreloc/gda-binreloc.h>
25 #include "login-dialog.h"
26 #include "browser-core.h"
27 #include "support.h"
28 #include "browser-perspective.h"
29 #include "browser-connection.h"
30 #include "browser-connections-list.h"
31 #include "browser-spinner.h"
32 #include "browser-stock-icons.h"
33 #include "connection-binding-properties.h"
34 #include <gdk/gdkkeysyms.h>
35
36 /*
37 * structure representing a 'tab' in a window
38 *
39 * a 'page' is a set of widgets created by a single BrowserPerspectiveFactory object, for a connection
40 * Each is owned by a BrowserWindow
41 */
42 typedef struct {
43 BrowserWindow *bwin; /* pointer to window the tab is in, no ref held here */
44 BrowserPerspectiveFactory *factory;
45 gint page_number; /* in reference to bwin->perspectives_nb */
46 BrowserPerspective *perspective_widget;
47
48 GtkActionGroup *customized_actions;
49 guint customized_merge_id;
50 gchar *customized_ui;
51 } PerspectiveData;
52 #define PERSPECTIVE_DATA(x) ((PerspectiveData*)(x))
53 static PerspectiveData *perspective_data_new (BrowserWindow *bwin, BrowserPerspectiveFactory *factory);
54 static void perspective_data_free (PerspectiveData *pers);
55
56 /*
57 * Main static functions
58 */
59 static void browser_window_class_init (BrowserWindowClass *klass);
60 static void browser_window_init (BrowserWindow *bwin);
61 static void browser_window_dispose (GObject *object);
62
63 static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event);
64 static gboolean key_press_event (GtkWidget *widget, GdkEventKey *event);
65 static void connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar *reason, BrowserWindow *bwin);
66
67 static void connection_added_cb (BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin);
68 static void connection_removed_cb (BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin);
69
70 static void transaction_status_changed_cb (BrowserConnection *bcnc, BrowserWindow *bwin);
71
72
73 enum {
74 FULLSCREEN_CHANGED,
75 LAST_SIGNAL
76 };
77
78 static gint browser_window_signals[LAST_SIGNAL] = { 0 };
79
80
81 /* get a pointer to the parents to be able to call their destructor */
82 static GObjectClass *parent_class = NULL;
83
84 struct _BrowserWindowPrivate {
85 BrowserConnection *bcnc;
86 GtkNotebook *perspectives_nb; /* notebook used to switch between tabs, for the selector part */
87 GSList *perspectives; /* list of PerspectiveData pointers, owned here */
88 PerspectiveData *current_perspective;
89 guint ui_manager_merge_id; /* for current perspective */
90
91 GtkWidget *menubar;
92 GtkWidget *toolbar;
93 gboolean toolbar_shown;
94 gboolean cursor_in_toolbar;
95 GtkWidget *spinner;
96 guint spinner_timer;
97 GtkUIManager *ui_manager;
98 GtkActionGroup *agroup;
99 GtkActionGroup *perspectives_actions;
100 gboolean updating_transaction_status;
101
102 GtkToolbarStyle toolbar_style;
103 GtkActionGroup *cnc_agroup; /* one GtkAction for each BrowserConnection */
104 gulong cnc_added_sigid;
105 gulong cnc_removed_sigid;
106
107 GtkWidget *notif_box;
108 GSList *notif_widgets;
109
110 GtkWidget *statusbar;
111 guint cnc_statusbar_context;
112
113 gboolean fullscreen;
114 gulong fullscreen_motion_sig_id;
115 guint fullscreen_timer_id;
116 };
117
118 GType
browser_window_get_type(void)119 browser_window_get_type (void)
120 {
121 static GType type = 0;
122
123 if (G_UNLIKELY (type == 0)) {
124 static GMutex registering;
125 static const GTypeInfo info = {
126 sizeof (BrowserWindowClass),
127 (GBaseInitFunc) NULL,
128 (GBaseFinalizeFunc) NULL,
129 (GClassInitFunc) browser_window_class_init,
130 NULL,
131 NULL,
132 sizeof (BrowserWindow),
133 0,
134 (GInstanceInitFunc) browser_window_init,
135 0
136 };
137
138
139 g_mutex_lock (®istering);
140 if (type == 0)
141 type = g_type_register_static (GTK_TYPE_WINDOW, "BrowserWindow", &info, 0);
142 g_mutex_unlock (®istering);
143 }
144 return type;
145 }
146
147 static void
browser_window_class_init(BrowserWindowClass * klass)148 browser_window_class_init (BrowserWindowClass *klass)
149 {
150 GObjectClass *object_class = G_OBJECT_CLASS (klass);
151 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
152
153 widget_class->window_state_event = window_state_event;
154 widget_class->key_press_event = key_press_event;
155 parent_class = g_type_class_peek_parent (klass);
156
157 browser_window_signals[FULLSCREEN_CHANGED] =
158 g_signal_new ("fullscreen_changed",
159 G_TYPE_FROM_CLASS (object_class),
160 G_SIGNAL_RUN_LAST,
161 G_STRUCT_OFFSET (BrowserWindowClass, fullscreen_changed),
162 NULL, NULL,
163 g_cclosure_marshal_VOID__BOOLEAN,
164 G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
165
166 object_class->dispose = browser_window_dispose;
167 klass->fullscreen_changed = NULL;
168 }
169
170 static void
browser_window_init(BrowserWindow * bwin)171 browser_window_init (BrowserWindow *bwin)
172 {
173 bwin->priv = g_new0 (BrowserWindowPrivate, 1);
174 bwin->priv->bcnc = NULL;
175 bwin->priv->perspectives_nb = NULL;
176 bwin->priv->perspectives = NULL;
177 bwin->priv->cnc_agroup = NULL;
178 bwin->priv->cnc_added_sigid = 0;
179 bwin->priv->cnc_removed_sigid = 0;
180 bwin->priv->updating_transaction_status = FALSE;
181 bwin->priv->fullscreen = FALSE;
182 bwin->priv->fullscreen_motion_sig_id = 0;
183 bwin->priv->fullscreen_timer_id = 0;
184 bwin->priv->spinner_timer = 0;
185 }
186
187 static void
browser_window_dispose(GObject * object)188 browser_window_dispose (GObject *object)
189 {
190 BrowserWindow *bwin;
191
192 g_return_if_fail (object != NULL);
193 g_return_if_fail (BROWSER_IS_WINDOW (object));
194
195 bwin = BROWSER_WINDOW (object);
196 if (bwin->priv) {
197 GSList *connections, *list;
198
199 if (bwin->priv->spinner_timer) {
200 g_source_remove (bwin->priv->spinner_timer);
201 bwin->priv->spinner_timer = 0;
202 }
203 connections = browser_core_get_connections ();
204 for (list = connections; list; list = list->next)
205 connection_removed_cb (browser_core_get(), BROWSER_CONNECTION (list->data), bwin);
206 g_slist_free (connections);
207
208 if (bwin->priv->fullscreen_timer_id)
209 g_source_remove (bwin->priv->fullscreen_timer_id);
210
211 if (bwin->priv->fullscreen_motion_sig_id)
212 g_signal_handler_disconnect (bwin, bwin->priv->fullscreen_motion_sig_id);
213
214 if (bwin->priv->cnc_added_sigid > 0)
215 g_signal_handler_disconnect (browser_core_get (), bwin->priv->cnc_added_sigid);
216 if (bwin->priv->cnc_removed_sigid > 0)
217 g_signal_handler_disconnect (browser_core_get (), bwin->priv->cnc_removed_sigid);
218 if (bwin->priv->ui_manager)
219 g_object_unref (bwin->priv->ui_manager);
220 if (bwin->priv->cnc_agroup)
221 g_object_unref (bwin->priv->cnc_agroup);
222
223 if (bwin->priv->bcnc) {
224 g_signal_handlers_disconnect_by_func (bwin->priv->bcnc,
225 G_CALLBACK (transaction_status_changed_cb),
226 bwin);
227 g_object_unref (bwin->priv->bcnc);
228 }
229 if (bwin->priv->perspectives) {
230 g_slist_foreach (bwin->priv->perspectives, (GFunc) perspective_data_free, NULL);
231 g_slist_free (bwin->priv->perspectives);
232 }
233 if (bwin->priv->perspectives_nb)
234 g_object_unref (bwin->priv->perspectives_nb);
235
236 if (bwin->priv->notif_widgets)
237 g_slist_free (bwin->priv->notif_widgets);
238 g_free (bwin->priv);
239 bwin->priv = NULL;
240 }
241
242 /* parent class */
243 parent_class->dispose (object);
244 }
245
246
247 static gboolean
delete_event(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEvent * event,BrowserWindow * bwin)248 delete_event (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEvent *event, BrowserWindow *bwin)
249 {
250 browser_core_close_window (bwin);
251 return TRUE;
252 }
253
254 static void transaction_begin_cb (GtkAction *action, BrowserWindow *bwin);
255 static void transaction_commit_cb (GtkAction *action, BrowserWindow *bwin);
256 static void transaction_rollback_cb (GtkAction *action, BrowserWindow *bwin);
257 static void quit_cb (GtkAction *action, BrowserWindow *bwin);
258 static void about_cb (GtkAction *action, BrowserWindow *bwin);
259 #ifdef HAVE_GDU
260 static void manual_cb (GtkAction *action, BrowserWindow *bwin);
261 #endif
262 static void window_close_cb (GtkAction *action, BrowserWindow *bwin);
263 static void window_fullscreen_cb (GtkToggleAction *action, BrowserWindow *bwin);
264 static void window_new_cb (GtkAction *action, BrowserWindow *bwin);
265 static void window_new_with_cnc_cb (GtkAction *action, BrowserWindow *bwin);
266 static void connection_properties_cb (GtkAction *action, BrowserWindow *bwin);
267 static void connection_close_cb (GtkAction *action, BrowserWindow *bwin);
268 static void connection_open_cb (GtkAction *action, BrowserWindow *bwin);
269 static void connection_bind_cb (GtkAction *action, BrowserWindow *bwin);
270 static void connection_list_cb (GtkAction *action, BrowserWindow *bwin);
271 static void connection_meta_update_cb (GtkAction *action, BrowserWindow *bwin);
272 static void perspective_toggle_cb (GtkRadioAction *action, GtkRadioAction *current, BrowserWindow *bwin);
273
274 static const GtkToggleActionEntry ui_toggle_actions [] =
275 {
276 { "WindowFullScreen", GTK_STOCK_FULLSCREEN, N_("_Fullscreen"), "F11", N_("Use the whole screen"), G_CALLBACK (window_fullscreen_cb), FALSE}
277 };
278
279 static const GtkActionEntry ui_actions[] = {
280 { "Connection", NULL, N_("_Connection"), NULL, N_("Connection"), NULL },
281 { "ConnectionOpen", GTK_STOCK_CONNECT, N_("_Connect"), NULL, N_("Open a connection"), G_CALLBACK (connection_open_cb)},
282 { "ConnectionBind", NULL, N_("_Bind Connection"), "<control>I", N_("Use connection to create\n"
283 "a new binding connection to access data\n"
284 "from multiple databases at once"), G_CALLBACK (connection_bind_cb)},
285 { "ConnectionProps", GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, N_("Connection properties"), G_CALLBACK (connection_properties_cb)},
286 { "ConnectionList", NULL, N_("_Connections List"), NULL, N_("Connections list"), G_CALLBACK (connection_list_cb)},
287 { "ConnectionMetaSync", GTK_STOCK_REFRESH, N_("_Fetch Meta Data"), NULL, N_("Fetch meta data"), G_CALLBACK (connection_meta_update_cb)},
288 { "ConnectionClose", GTK_STOCK_CLOSE, N_("_Close Connection"), NULL, N_("Close this connection"), G_CALLBACK (connection_close_cb)},
289 { "Quit", GTK_STOCK_QUIT, N_("_Quit"), NULL, N_("Quit"), G_CALLBACK (quit_cb)},
290 { "Edit", NULL, N_("_Edit"), NULL, N_("Edit"), NULL },
291 { "Display", NULL, N_("_Display"), NULL, N_("Display"), NULL },
292 { "Perspective", NULL, N_("_Perspective"), NULL, N_("Perspective"), NULL },
293 { "Window", NULL, N_("_Window"), NULL, N_("Window"), NULL },
294 { "WindowNew", STOCK_NEW_WINDOW, N_("_New Window"), "<control>N", N_("Open a new window for current connection"), G_CALLBACK (window_new_cb)},
295 { "WindowNewOthers", NULL, N_("New Window for _Connection"), NULL, N_("Open a new window for a connection"), NULL},
296 { "WindowClose", GTK_STOCK_CLOSE, N_("_Close"), NULL, N_("Close this window"), G_CALLBACK (window_close_cb)},
297 { "Help", NULL, N_("_Help"), NULL, N_("Help"), NULL },
298 { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("About"), G_CALLBACK (about_cb) },
299 #ifdef HAVE_GDU
300 { "HelpManual", GTK_STOCK_HELP, N_("_Manual"), "F1", N_("Manual"), G_CALLBACK (manual_cb) },
301 #endif
302 { "TransactionBegin", BROWSER_STOCK_BEGIN, N_("Begin"), NULL, N_("Begin a new transaction"),
303 G_CALLBACK (transaction_begin_cb)},
304 { "TransactionCommit", BROWSER_STOCK_COMMIT, N_("Commit"), NULL, N_("Commit current transaction"),
305 G_CALLBACK (transaction_commit_cb)},
306 { "TransactionRollback", BROWSER_STOCK_ROLLBACK, N_("Rollback"), NULL, N_("Rollback current transaction"),
307 G_CALLBACK (transaction_rollback_cb)},
308 };
309
310 static const gchar *ui_actions_info =
311 "<ui>"
312 " <menubar name='MenuBar'>"
313 " <menu name='Connection' action='Connection'>"
314 " <menuitem name='ConnectionOpen' action= 'ConnectionOpen'/>"
315 " <menuitem name='ConnectionList' action= 'ConnectionList'/>"
316 " <menuitem name='ConnectionMetaSync' action= 'ConnectionMetaSync'/>"
317 " <separator/>"
318 " <menuitem name='ConnectionProps' action= 'ConnectionProps'/>"
319 " <menuitem name='ConnectionBind' action= 'ConnectionBind'/>"
320 " <menuitem name='ConnectionClose' action= 'ConnectionClose'/>"
321 " <separator/>"
322 " <menuitem name='TransactionBegin' action= 'TransactionBegin'/>"
323 " <menuitem name='TransactionCommit' action= 'TransactionCommit'/>"
324 " <menuitem name='TransactionRollback' action= 'TransactionRollback'/>"
325 " <separator/>"
326 " <menuitem name='Quit' action= 'Quit'/>"
327 " <separator/>"
328 " </menu>"
329 " <menu name='Edit' action='Edit'>"
330 " </menu>"
331 " <menu name='Display' action='Display'>"
332 " </menu>"
333 " <menu name='Perspective' action='Perspective'>"
334 " <placeholder name='PersList'/>"
335 " </menu>"
336 " <menu name='Window' action='Window'>"
337 " <menuitem name='WindowFullScreen' action= 'WindowFullScreen'/>"
338 " <separator/>"
339 " <menuitem name='WindowNew' action= 'WindowNew'/>"
340 " <menu name='WindowNewOthers' action='WindowNewOthers'>"
341 " <placeholder name='CncList'/>"
342 " </menu>"
343 " <separator/>"
344 " <menuitem name='WindowClose' action= 'WindowClose'/>"
345 " </menu>"
346 " <placeholder name='MenuExtension'/>"
347 " <menu name='Help' action='Help'>"
348 #ifdef HAVE_GDU
349 " <menuitem name='HelpManual' action= 'HelpManual'/>"
350 #endif
351 " <menuitem name='HelpAbout' action= 'HelpAbout'/>"
352 " </menu>"
353 " </menubar>"
354 " <toolbar name='ToolBar'>"
355 " <toolitem action='WindowClose'/>"
356 " <toolitem action='WindowFullScreen'/>"
357 " <toolitem action='TransactionBegin'/>"
358 " <toolitem action='TransactionCommit'/>"
359 " <toolitem action='TransactionRollback'/>"
360 " </toolbar>"
361 "</ui>";
362
363 /**
364 * browser_window_new
365 * @bcnc: a #BrowserConnection
366 * @factory: a #BrowserPerspectiveFactory, may be %NULL
367 *
368 * Creates a new #BrowserWindow window for the @bcnc connection, and displays it.
369 * If @factory is not %NULL, then the new window will show the perspective corresponding
370 * to @factory. If it's %NULL, then the default #BrowserPerspectiveFactory will be used,
371 * see browser_core_get_default_factory().
372 *
373 * Don't forget to call browser_core_take_window() to have the new window correctly
374 * managed by the browser. Similarly, to close the window, use browser_core_close_window()
375 * and not simply gtk_widget_destroy().
376 *
377 * Returns: the new object
378 */
379 BrowserWindow*
browser_window_new(BrowserConnection * bcnc,BrowserPerspectiveFactory * factory)380 browser_window_new (BrowserConnection *bcnc, BrowserPerspectiveFactory *factory)
381 {
382 BrowserWindow *bwin;
383
384 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
385
386 bwin = BROWSER_WINDOW (g_object_new (BROWSER_TYPE_WINDOW, NULL));
387 bwin->priv->bcnc = g_object_ref (bcnc);
388 g_signal_connect (bcnc, "transaction-status-changed",
389 G_CALLBACK (transaction_status_changed_cb), bwin);
390
391 gchar *tmp;
392 tmp = browser_connection_get_long_name (bcnc);
393 gtk_window_set_title (GTK_WINDOW (bwin), tmp);
394 g_free (tmp);
395
396 gtk_window_set_default_size ((GtkWindow*) bwin, 900, 650);
397 g_signal_connect (G_OBJECT (bwin), "delete-event",
398 G_CALLBACK (delete_event), bwin);
399 /* icon */
400 GdkPixbuf *icon;
401 gchar *path;
402 path = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "pixmaps", "gda-browser.png", NULL);
403 icon = gdk_pixbuf_new_from_file (path, NULL);
404 g_free (path);
405 if (icon) {
406 gtk_window_set_icon (GTK_WINDOW (bwin), icon);
407 g_object_unref (icon);
408 }
409
410 /* main VBox */
411 GtkWidget *vbox;
412 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
413 gtk_container_add (GTK_CONTAINER (bwin), vbox);
414 gtk_widget_show (vbox);
415
416 /* menu */
417 GtkWidget *menubar;
418 GtkWidget *toolbar;
419 GtkUIManager *ui;
420 GtkActionGroup *group;
421
422 group = gtk_action_group_new ("Actions");
423 gtk_action_group_set_translation_domain (group, GETTEXT_PACKAGE);
424
425 bwin->priv->agroup = group;
426 gtk_action_group_add_actions (group, ui_actions, G_N_ELEMENTS (ui_actions), bwin);
427 gtk_action_group_add_toggle_actions (group, ui_toggle_actions, G_N_ELEMENTS (ui_toggle_actions), bwin);
428 if (browser_connection_is_virtual (bwin->priv->bcnc)) {
429 GtkAction *action;
430 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin");
431 gtk_action_set_visible (action, FALSE);
432 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit");
433 gtk_action_set_visible (action, FALSE);
434 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback");
435 gtk_action_set_visible (action, FALSE);
436 }
437 transaction_status_changed_cb (bwin->priv->bcnc, bwin);
438
439 ui = gtk_ui_manager_new ();
440 gtk_ui_manager_insert_action_group (ui, group, 0);
441 gtk_ui_manager_add_ui_from_string (ui, ui_actions_info, -1, NULL);
442 bwin->priv->ui_manager = ui;
443
444 GtkAccelGroup *accel_group;
445 accel_group = gtk_ui_manager_get_accel_group (ui);
446 gtk_window_add_accel_group (GTK_WINDOW (bwin), accel_group);
447
448 menubar = gtk_ui_manager_get_widget (ui, "/MenuBar");
449 bwin->priv->menubar = menubar;
450 #ifdef HAVE_MAC_INTEGRATION
451 gtk_osxapplication_set_menu_bar (theApp, GTK_MENU_SHELL (menubar));
452 #else
453 gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
454 gtk_widget_show (menubar);
455 #endif
456
457 toolbar = gtk_ui_manager_get_widget (ui, "/ToolBar");
458 bwin->priv->toolbar = toolbar;
459 bwin->priv->toolbar_shown = TRUE;
460 gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, TRUE, 0);
461 gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), TRUE);
462 gtk_widget_show (toolbar);
463 bwin->priv->toolbar_style = gtk_toolbar_get_style (GTK_TOOLBAR (toolbar));
464
465 bwin->priv->notif_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
466 gtk_box_pack_start (GTK_BOX (vbox), bwin->priv->notif_box, FALSE, FALSE, 0);
467 gtk_widget_show (bwin->priv->notif_box);
468 bwin->priv->notif_widgets = NULL;
469
470 GtkToolItem *ti;
471 GtkWidget *spinner, *svbox, *align;
472
473 ti = gtk_separator_tool_item_new ();
474 gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (ti), FALSE);
475 gtk_tool_item_set_expand (ti, TRUE);
476 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), ti, -1);
477 gtk_widget_show (GTK_WIDGET (ti));
478
479 spinner = browser_spinner_new ();
480 browser_spinner_set_size ((BrowserSpinner*) spinner, GTK_ICON_SIZE_SMALL_TOOLBAR);
481
482 svbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
483 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
484 gtk_container_add (GTK_CONTAINER (align), spinner);
485 gtk_box_pack_start (GTK_BOX (svbox), align, TRUE, TRUE, 0);
486
487 ti = gtk_tool_item_new ();
488 gtk_container_add (GTK_CONTAINER (ti), svbox);
489 gtk_toolbar_insert (GTK_TOOLBAR (toolbar), ti, -1);
490 gtk_widget_show_all (GTK_WIDGET (ti));
491 gtk_widget_hide (GTK_WIDGET (spinner));
492 bwin->priv->spinner = spinner;
493
494 /* statusbar */
495 bwin->priv->statusbar = gtk_statusbar_new ();
496
497 GSList *connections, *list;
498 bwin->priv->cnc_agroup = gtk_action_group_new ("CncActions");
499 gtk_action_group_set_translation_domain (bwin->priv->cnc_agroup, GETTEXT_PACKAGE);
500
501 connections = browser_core_get_connections ();
502 for (list = connections; list; list = list->next)
503 connection_added_cb (browser_core_get(), BROWSER_CONNECTION (list->data), bwin);
504 g_slist_free (connections);
505
506 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, bwin->priv->cnc_agroup, 0);
507 bwin->priv->cnc_added_sigid = g_signal_connect (browser_core_get (), "connection-added",
508 G_CALLBACK (connection_added_cb), bwin);
509 bwin->priv->cnc_removed_sigid = g_signal_connect (browser_core_get (), "connection-removed",
510 G_CALLBACK (connection_removed_cb), bwin);
511
512
513 /* create a PerspectiveData */
514 PerspectiveData *pers;
515 if (! factory && browser_connection_is_ldap (bcnc))
516 factory = browser_core_get_factory (_("LDAP browser"));
517 pers = perspective_data_new (bwin, factory);
518 bwin->priv->perspectives = g_slist_prepend (bwin->priv->perspectives, pers);
519 GtkActionGroup *actions;
520 actions = browser_perspective_get_actions_group (BROWSER_PERSPECTIVE (pers->perspective_widget));
521 if (actions) {
522 gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE);
523 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, actions, 0);
524 g_object_unref (actions);
525 }
526 const gchar *ui_info;
527 ui_info = browser_perspective_get_actions_ui (BROWSER_PERSPECTIVE (pers->perspective_widget));
528 if (ui_info)
529 bwin->priv->ui_manager_merge_id = gtk_ui_manager_add_ui_from_string (bwin->priv->ui_manager,
530 ui_info, -1, NULL);
531 bwin->priv->current_perspective = pers;
532 browser_perspective_get_current_customization (BROWSER_PERSPECTIVE (pers->perspective_widget),
533 &actions, &ui_info);
534 browser_window_customize_perspective_ui (bwin, BROWSER_PERSPECTIVE (pers->perspective_widget),
535 actions, ui_info);
536 if (actions)
537 g_object_unref (actions);
538
539 /* insert perspective into window */
540 bwin->priv->perspectives_nb = (GtkNotebook*) gtk_notebook_new ();
541 g_object_ref (bwin->priv->perspectives_nb);
542 gtk_notebook_set_show_tabs (bwin->priv->perspectives_nb, FALSE);
543 gtk_box_pack_start (GTK_BOX (vbox), (GtkWidget*) bwin->priv->perspectives_nb,
544 TRUE, TRUE, 0);
545
546 pers->page_number = gtk_notebook_append_page (bwin->priv->perspectives_nb,
547 GTK_WIDGET (pers->perspective_widget), NULL);
548 gtk_widget_show_all ((GtkWidget*) bwin->priv->perspectives_nb);
549 gtk_widget_grab_focus (GTK_WIDGET (pers->perspective_widget));
550
551 /* build the perspectives menu */
552 GtkActionGroup *agroup;
553 const GSList *plist;
554 GSList *radio_group = NULL;
555 guint mid;
556
557 mid = gtk_ui_manager_new_merge_id (bwin->priv->ui_manager);
558 agroup = gtk_action_group_new ("Perspectives");
559 gtk_action_group_set_translation_domain (agroup, GETTEXT_PACKAGE);
560
561 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, agroup, 0);
562 bwin->priv->perspectives_actions = agroup;
563 g_object_unref (agroup);
564
565 GtkAction *active_action = NULL;
566 for (plist = browser_core_get_factories (); plist; plist = plist->next) {
567 GtkAction *action;
568 const gchar *name;
569
570 name = BROWSER_PERSPECTIVE_FACTORY (plist->data)->perspective_name;
571 if (!strcmp (name, _("LDAP browser")) && !browser_connection_is_ldap (bcnc))
572 continue;
573
574 action = GTK_ACTION (gtk_radio_action_new (name, name, NULL, NULL, FALSE));
575
576 if (!active_action &&
577 ((factory && (BROWSER_PERSPECTIVE_FACTORY (plist->data) == factory)) ||
578 (!factory && (BROWSER_PERSPECTIVE_FACTORY (plist->data) == browser_core_get_default_factory ()))))
579 active_action = action;
580 if (BROWSER_PERSPECTIVE_FACTORY (plist->data)->menu_shortcut)
581 gtk_action_group_add_action_with_accel (agroup, action,
582 BROWSER_PERSPECTIVE_FACTORY (plist->data)->menu_shortcut);
583 else
584 gtk_action_group_add_action (agroup, action);
585
586 gtk_radio_action_set_group (GTK_RADIO_ACTION (action), radio_group);
587 radio_group = gtk_radio_action_get_group (GTK_RADIO_ACTION (action));
588
589 g_object_set_data (G_OBJECT (action), "pers", plist->data);
590 g_signal_connect (action, "changed",
591 G_CALLBACK (perspective_toggle_cb), bwin);
592
593 g_object_unref (action);
594
595 gtk_ui_manager_add_ui (bwin->priv->ui_manager, mid, "/MenuBar/Perspective/PersList",
596 name, name,
597 GTK_UI_MANAGER_AUTO, FALSE);
598 }
599
600 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (active_action), TRUE);
601
602 gtk_box_pack_start (GTK_BOX (vbox), bwin->priv->statusbar, FALSE, FALSE, 0);
603 gtk_widget_show (bwin->priv->statusbar);
604 bwin->priv->cnc_statusbar_context = gtk_statusbar_get_context_id (GTK_STATUSBAR (bwin->priv->statusbar),
605 "cncbusy");
606
607 gtk_widget_show (GTK_WIDGET (bwin));
608
609 gtk_widget_set_can_focus ((GtkWidget* )pers->perspective_widget, TRUE);
610 gtk_widget_grab_focus ((GtkWidget* )pers->perspective_widget);
611
612 return bwin;
613 }
614
615 static void
perspective_toggle_cb(GtkRadioAction * action,GtkRadioAction * current,BrowserWindow * bwin)616 perspective_toggle_cb (GtkRadioAction *action, GtkRadioAction *current, BrowserWindow *bwin)
617 {
618 BrowserPerspectiveFactory *pf;
619 GSList *list;
620 PerspectiveData *pers;
621 if (action != current)
622 return;
623
624 pf = BROWSER_PERSPECTIVE_FACTORY (g_object_get_data (G_OBJECT (action), "pers"));
625 g_assert (pf);
626
627 /* current perspective's cleanups */
628 if (bwin->priv->current_perspective) {
629 pers = bwin->priv->current_perspective;
630 if (pers->customized_merge_id) {
631 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, pers->customized_merge_id);
632 pers->customized_merge_id = 0;
633 }
634 bwin->priv->current_perspective = NULL;
635 }
636
637 /* check if perspective already exists */
638 for (list = bwin->priv->perspectives, pers = NULL; list; list = list->next) {
639 if (PERSPECTIVE_DATA (list->data)->factory == pf) {
640 pers = PERSPECTIVE_DATA (list->data);
641 break;
642 }
643 }
644
645 if (!pers) {
646 pers = perspective_data_new (bwin, pf);
647 bwin->priv->perspectives = g_slist_prepend (bwin->priv->perspectives, pers);
648 pers->page_number = gtk_notebook_append_page (bwin->priv->perspectives_nb,
649 GTK_WIDGET (pers->perspective_widget), NULL);
650 gtk_widget_show (GTK_WIDGET (pers->perspective_widget));
651
652 GtkActionGroup *actions;
653 actions = browser_perspective_get_actions_group (BROWSER_PERSPECTIVE (pers->perspective_widget));
654 if (actions) {
655 gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE);
656 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, actions, 0);
657 g_object_unref (actions);
658 }
659 }
660
661 gtk_notebook_set_current_page (bwin->priv->perspectives_nb, pers->page_number);
662
663 /* menus and toolbar handling */
664 if (bwin->priv->ui_manager_merge_id > 0) {
665 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, bwin->priv->ui_manager_merge_id);
666 bwin->priv->ui_manager_merge_id = 0;
667 }
668
669 const gchar *ui_info;
670 ui_info = browser_perspective_get_actions_ui (BROWSER_PERSPECTIVE (pers->perspective_widget));
671 if (ui_info)
672 bwin->priv->ui_manager_merge_id = gtk_ui_manager_add_ui_from_string (bwin->priv->ui_manager,
673 ui_info, -1, NULL);
674
675 /* current perspective's customizations */
676 bwin->priv->current_perspective = pers;
677
678 GtkActionGroup *actions;
679 browser_perspective_get_current_customization (BROWSER_PERSPECTIVE (pers->perspective_widget),
680 &actions, &ui_info);
681 browser_window_customize_perspective_ui (bwin, BROWSER_PERSPECTIVE (pers->perspective_widget),
682 actions, ui_info);
683 if (actions)
684 g_object_unref (actions);
685 }
686
687 static gboolean
spinner_stop_timer(BrowserWindow * bwin)688 spinner_stop_timer (BrowserWindow *bwin)
689 {
690 browser_spinner_stop (BROWSER_SPINNER (bwin->priv->spinner));
691 bwin->priv->spinner_timer = 0;
692 return FALSE; /* remove timer */
693 }
694
695 static void
connection_busy_cb(BrowserConnection * bcnc,gboolean is_busy,gchar * reason,BrowserWindow * bwin)696 connection_busy_cb (BrowserConnection *bcnc, gboolean is_busy, gchar *reason, BrowserWindow *bwin)
697 {
698 GtkAction *action;
699 if (bcnc == bwin->priv->bcnc) {
700 /* @bcbc is @bwin's own connection */
701 if (bwin->priv->spinner_timer) {
702 g_source_remove (bwin->priv->spinner_timer);
703 bwin->priv->spinner_timer = 0;
704 }
705 if (is_busy) {
706 browser_spinner_start (BROWSER_SPINNER (bwin->priv->spinner));
707 gtk_widget_set_tooltip_text (bwin->priv->spinner, reason);
708 gtk_statusbar_push (GTK_STATUSBAR (bwin->priv->statusbar),
709 bwin->priv->cnc_statusbar_context,
710 reason);
711 }
712 else {
713 bwin->priv->spinner_timer = g_timeout_add (300,
714 (GSourceFunc) spinner_stop_timer, bwin);
715 gtk_widget_set_tooltip_text (bwin->priv->spinner, NULL);
716 gtk_statusbar_pop (GTK_STATUSBAR (bwin->priv->statusbar),
717 bwin->priv->cnc_statusbar_context);
718 }
719
720 gboolean bsens = FALSE, csens = FALSE;
721 if (!is_busy) {
722 if (browser_connection_get_transaction_status (bcnc))
723 csens = TRUE;
724 else
725 bsens = TRUE;
726 }
727 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin");
728 gtk_action_set_sensitive (action, bsens);
729 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit");
730 gtk_action_set_sensitive (action, csens);
731 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback");
732 gtk_action_set_sensitive (action, csens);
733
734 action = gtk_action_group_get_action (bwin->priv->agroup, "WindowNew");
735 gtk_action_set_sensitive (action, !is_busy);
736 action = gtk_action_group_get_action (bwin->priv->agroup, "ConnectionMetaSync");
737 gtk_action_set_sensitive (action, !is_busy);
738 }
739
740 gchar *cncname;
741 cncname = browser_connection_get_long_name (bcnc);
742 action = gtk_action_group_get_action (bwin->priv->cnc_agroup, cncname);
743 g_free (cncname);
744 if (action)
745 gtk_action_set_sensitive (action, !is_busy);
746 }
747
748 /* update @bwin->priv->cnc_agroup and @bwin->priv->ui_manager */
749 static void
connection_added_cb(G_GNUC_UNUSED BrowserCore * bcore,BrowserConnection * bcnc,BrowserWindow * bwin)750 connection_added_cb (G_GNUC_UNUSED BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin)
751 {
752 GtkAction *action;
753 gchar *cncname;
754 guint mid;
755
756 mid = gtk_ui_manager_new_merge_id (bwin->priv->ui_manager);
757 cncname = browser_connection_get_long_name (bcnc);
758 action = gtk_action_new (cncname, cncname, NULL, NULL);
759 gtk_action_group_add_action (bwin->priv->cnc_agroup, action);
760 guint *amid = g_new (guint, 1);
761 *amid = mid;
762 g_object_set_data_full (G_OBJECT (action), "mid", amid, g_free);
763
764 gtk_ui_manager_add_ui (bwin->priv->ui_manager, mid, "/MenuBar/Window/WindowNewOthers/CncList",
765 cncname, cncname,
766 GTK_UI_MANAGER_AUTO, FALSE);
767 g_free (cncname);
768 g_signal_connect (action, "activate",
769 G_CALLBACK (window_new_with_cnc_cb), bwin);
770 g_object_set_data (G_OBJECT (action), "bcnc", bcnc);
771 gtk_action_set_sensitive (action, ! browser_connection_is_busy (bcnc, NULL));
772 g_object_unref (action);
773
774 gchar *reason = NULL;
775 if (browser_connection_is_busy (bcnc, &reason)) {
776 connection_busy_cb (bcnc, TRUE, reason, bwin);
777 g_free (reason);
778 }
779 g_signal_connect (bcnc, "busy",
780 G_CALLBACK (connection_busy_cb), bwin);
781 }
782
783 /* update @bwin->priv->cnc_agroup and @bwin->priv->ui_manager */
784 static void
connection_removed_cb(G_GNUC_UNUSED BrowserCore * bcore,BrowserConnection * bcnc,BrowserWindow * bwin)785 connection_removed_cb (G_GNUC_UNUSED BrowserCore *bcore, BrowserConnection *bcnc, BrowserWindow *bwin)
786 {
787 GtkAction *action;
788 gchar *path;
789 gchar *cncname;
790 guint *mid;
791
792 cncname = browser_connection_get_long_name (bcnc);
793 path = g_strdup_printf ("/MenuBar/Window/WindowNewOthers/CncList/%s", cncname);
794 g_free (cncname);
795 action = gtk_ui_manager_get_action (bwin->priv->ui_manager, path);
796 g_free (path);
797 g_assert (action);
798
799 mid = g_object_get_data (G_OBJECT (action), "mid");
800 g_assert (mid);
801
802 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, *mid);
803 gtk_action_group_remove_action (bwin->priv->cnc_agroup, action);
804
805 g_signal_handlers_disconnect_by_func (bcnc,
806 G_CALLBACK (connection_busy_cb), bwin);
807 }
808
809 static void
connection_close_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)810 connection_close_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
811 {
812 /* confirmation dialog */
813 GtkWidget *dialog;
814 char *str;
815 BrowserConnection *bcnc;
816 bcnc = browser_window_get_connection (bwin);
817
818 str = g_strdup_printf (_("Do you want to close the '%s' connection?"),
819 browser_connection_get_name (bcnc));
820 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (bwin), GTK_DIALOG_MODAL,
821 GTK_MESSAGE_QUESTION,
822 GTK_BUTTONS_YES_NO,
823 "<b>%s</b>", str);
824 g_free (str);
825
826 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) {
827 /* actual connection closing */
828 browser_core_close_connection (bcnc);
829
830 /* list all the windows using bwin's connection */
831 GSList *list, *windows, *bwin_list = NULL;
832
833 windows = browser_core_get_windows ();
834 for (list = windows; list; list = list->next) {
835 if (browser_window_get_connection (BROWSER_WINDOW (list->data)) == bcnc)
836 bwin_list = g_slist_prepend (bwin_list, list->data);
837 }
838 g_slist_free (windows);
839
840 for (list = bwin_list; list; list = list->next)
841 delete_event (NULL, NULL, BROWSER_WINDOW (list->data));
842 g_slist_free (bwin_list);
843 }
844 gtk_widget_destroy (dialog);
845 }
846
847 static void
quit_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)848 quit_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
849 {
850 /* confirmation dialog */
851 GtkWidget *dialog;
852 GSList *connections;
853
854 connections = browser_core_get_connections ();
855 if (connections && connections->next)
856 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (bwin), GTK_DIALOG_MODAL,
857 GTK_MESSAGE_QUESTION,
858 GTK_BUTTONS_YES_NO,
859 "<b>%s</b>\n<small>%s</small>",
860 _("Do you want to quit the application?"),
861 _("all the connections will be closed."));
862 else
863 dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (bwin), GTK_DIALOG_MODAL,
864 GTK_MESSAGE_QUESTION,
865 GTK_BUTTONS_YES_NO,
866 "<b>%s</b>\n<small>%s</small>",
867 _("Do you want to quit the application?"),
868 _("the connection will be closed."));
869
870
871 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES) {
872 /* actual connection closing */
873 GSList *list;
874 for (list = connections; list; list = list->next)
875 browser_core_close_connection (BROWSER_CONNECTION (list->data));
876
877 /* list all the windows using bwin's connection */
878 GSList *windows;
879 windows = browser_core_get_windows ();
880 for (list = windows; list; list = list->next)
881 delete_event (NULL, NULL, BROWSER_WINDOW (list->data));
882 g_slist_free (windows);
883 }
884 g_slist_free (connections);
885 gtk_widget_destroy (dialog);
886 }
887
888 static void
transaction_status_changed_cb(BrowserConnection * bcnc,BrowserWindow * bwin)889 transaction_status_changed_cb (BrowserConnection *bcnc, BrowserWindow *bwin)
890 {
891 if (!bwin->priv->agroup)
892 return;
893
894 GtkAction *action;
895 gboolean trans_started;
896
897 trans_started = browser_connection_get_transaction_status (bcnc) ? TRUE : FALSE;
898 bwin->priv->updating_transaction_status = TRUE;
899
900 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionBegin");
901 gtk_action_set_sensitive (action, !trans_started);
902
903 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionCommit");
904 gtk_action_set_sensitive (action, trans_started);
905
906 action = gtk_action_group_get_action (bwin->priv->agroup, "TransactionRollback");
907 gtk_action_set_sensitive (action, trans_started);
908
909 bwin->priv->updating_transaction_status = FALSE;
910 }
911
912 static void
transaction_begin_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)913 transaction_begin_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
914 {
915 if (!bwin->priv->updating_transaction_status) {
916 GError *error = NULL;
917 if (! browser_connection_begin (bwin->priv->bcnc, &error)) {
918 browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)),
919 _("Error starting transaction: %s"),
920 error && error->message ? error->message : _("No detail"));
921 g_clear_error (&error);
922 }
923 }
924 }
925
926 static void
transaction_commit_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)927 transaction_commit_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
928 {
929 if (!bwin->priv->updating_transaction_status) {
930 GError *error = NULL;
931 if (! browser_connection_commit (bwin->priv->bcnc, &error)) {
932 browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)),
933 _("Error committing transaction: %s"),
934 error && error->message ? error->message : _("No detail"));
935 g_clear_error (&error);
936 }
937 }
938 }
939
940 static void
transaction_rollback_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)941 transaction_rollback_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
942 {
943 if (!bwin->priv->updating_transaction_status) {
944 GError *error = NULL;
945 if (! browser_connection_rollback (bwin->priv->bcnc, &error)) {
946 browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) bwin)),
947 _("Error rolling back transaction: %s"),
948 error && error->message ? error->message : _("No detail"));
949 g_clear_error (&error);
950 }
951 }
952 }
953
954
955 static void
window_close_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)956 window_close_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
957 {
958 delete_event (NULL, NULL, bwin);
959 }
960
961 static gboolean
toolbar_hide_timeout_cb(BrowserWindow * bwin)962 toolbar_hide_timeout_cb (BrowserWindow *bwin)
963 {
964 if (!bwin->priv->cursor_in_toolbar) {
965 gtk_widget_hide (bwin->priv->toolbar);
966 gtk_widget_hide (bwin->priv->menubar);
967 bwin->priv->toolbar_shown = FALSE;
968
969 /* remove timer */
970 bwin->priv->fullscreen_timer_id = 0;
971 return FALSE;
972 }
973 else
974 /* keep timer */
975 return TRUE;
976 }
977
978 #define BWIN_WINDOW_FULLSCREEN_POPUP_THRESHOLD 15
979 #define BWIN_WINDOW_FULLSCREEN_POPUP_TIMER 5
980
981 static gboolean
fullscreen_motion_notify_cb(GtkWidget * widget,GdkEventMotion * event,G_GNUC_UNUSED gpointer user_data)982 fullscreen_motion_notify_cb (GtkWidget *widget, GdkEventMotion *event, G_GNUC_UNUSED gpointer user_data)
983 {
984 BrowserWindow *bwin = BROWSER_WINDOW (widget);
985 if (gtk_widget_get_window (widget) != event->window)
986 return FALSE;
987
988 if (event->y < BWIN_WINDOW_FULLSCREEN_POPUP_THRESHOLD) {
989 gtk_widget_show (bwin->priv->toolbar);
990 gtk_widget_show (bwin->priv->menubar);
991 bwin->priv->toolbar_shown = TRUE;
992 }
993
994 if (bwin->priv->toolbar_shown) {
995 /* reset toolbar hiding timer */
996 if (bwin->priv->fullscreen_timer_id)
997 g_source_remove (bwin->priv->fullscreen_timer_id);
998 bwin->priv->fullscreen_timer_id = g_timeout_add_seconds (BWIN_WINDOW_FULLSCREEN_POPUP_TIMER,
999 (GSourceFunc) toolbar_hide_timeout_cb,
1000 bwin);
1001 }
1002 return FALSE;
1003 }
1004
1005 gboolean
toolbar_enter_notify_cb(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEventCrossing * event,BrowserWindow * bwin)1006 toolbar_enter_notify_cb (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEventCrossing *event,
1007 BrowserWindow *bwin)
1008 {
1009 bwin->priv->cursor_in_toolbar = TRUE;
1010 return FALSE;
1011 }
1012
1013 gboolean
toolbar_leave_notify_cb(G_GNUC_UNUSED GtkWidget * widget,G_GNUC_UNUSED GdkEventCrossing * event,BrowserWindow * bwin)1014 toolbar_leave_notify_cb (G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED GdkEventCrossing *event, BrowserWindow *bwin)
1015 {
1016 bwin->priv->cursor_in_toolbar = FALSE;
1017 return FALSE;
1018 }
1019
1020 static void
window_fullscreen_cb(GtkToggleAction * action,BrowserWindow * bwin)1021 window_fullscreen_cb (GtkToggleAction *action, BrowserWindow *bwin)
1022 {
1023 if (gtk_toggle_action_get_active (action)) {
1024 gtk_window_fullscreen (GTK_WINDOW (bwin));
1025 browser_window_show_notice_printf (bwin, GTK_MESSAGE_INFO,
1026 "fullscreen-esc",
1027 "%s", _("Hit the Escape key to leave the fullscreen mode"));
1028 gtk_widget_hide (bwin->priv->toolbar);
1029 gtk_widget_hide (bwin->priv->menubar);
1030 bwin->priv->toolbar_shown = FALSE;
1031 bwin->priv->fullscreen_motion_sig_id = g_signal_connect (bwin, "motion-notify-event",
1032 G_CALLBACK (fullscreen_motion_notify_cb),
1033 NULL);
1034 g_signal_connect (bwin->priv->toolbar, "enter-notify-event",
1035 G_CALLBACK (toolbar_enter_notify_cb), bwin);
1036 g_signal_connect (bwin->priv->toolbar, "leave-notify-event",
1037 G_CALLBACK (toolbar_leave_notify_cb), bwin);
1038 g_signal_connect (bwin->priv->menubar, "enter-notify-event",
1039 G_CALLBACK (toolbar_enter_notify_cb), bwin);
1040 g_signal_connect (bwin->priv->menubar, "leave-notify-event",
1041 G_CALLBACK (toolbar_leave_notify_cb), bwin);
1042 }
1043 else {
1044 gtk_window_unfullscreen (GTK_WINDOW (bwin));
1045 g_signal_handler_disconnect (bwin, bwin->priv->fullscreen_motion_sig_id);
1046 bwin->priv->fullscreen_motion_sig_id = 0;
1047 g_signal_handlers_disconnect_by_func (bwin->priv->toolbar,
1048 G_CALLBACK (toolbar_enter_notify_cb), bwin);
1049 g_signal_handlers_disconnect_by_func (bwin->priv->toolbar,
1050 G_CALLBACK (toolbar_leave_notify_cb), bwin);
1051 g_signal_handlers_disconnect_by_func (bwin->priv->menubar,
1052 G_CALLBACK (toolbar_enter_notify_cb), bwin);
1053 g_signal_handlers_disconnect_by_func (bwin->priv->menubar,
1054 G_CALLBACK (toolbar_leave_notify_cb), bwin);
1055
1056 gtk_widget_show (bwin->priv->toolbar);
1057 gtk_widget_show (bwin->priv->menubar);
1058 bwin->priv->toolbar_shown = TRUE;
1059
1060 if (bwin->priv->fullscreen_timer_id) {
1061 g_source_remove (bwin->priv->fullscreen_timer_id);
1062 bwin->priv->fullscreen_timer_id = 0;
1063 }
1064 }
1065 }
1066
1067 static gboolean
key_press_event(GtkWidget * widget,GdkEventKey * event)1068 key_press_event (GtkWidget *widget, GdkEventKey *event)
1069 {
1070 if ((event->keyval == GDK_KEY_Escape) &&
1071 browser_window_is_fullscreen (BROWSER_WINDOW (widget))) {
1072 browser_window_set_fullscreen (BROWSER_WINDOW (widget), FALSE);
1073 return TRUE;
1074 }
1075
1076 /* parent class */
1077 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
1078 }
1079
1080 static gboolean
window_state_event(GtkWidget * widget,GdkEventWindowState * event)1081 window_state_event (GtkWidget *widget, GdkEventWindowState *event)
1082 {
1083 BrowserWindow *bwin = BROWSER_WINDOW (widget);
1084 gboolean (* window_state_event) (GtkWidget *, GdkEventWindowState *);
1085 window_state_event = GTK_WIDGET_CLASS (parent_class)->window_state_event;
1086
1087 /* calling parent's method */
1088 if (window_state_event)
1089 window_state_event (widget, event);
1090
1091 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
1092 gboolean fullscreen;
1093 GtkWidget *wid;
1094
1095 wid = gtk_ui_manager_get_widget (bwin->priv->ui_manager, "/ToolBar");
1096
1097 fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
1098 bwin->priv->fullscreen = fullscreen;
1099 if (fullscreen) {
1100 gtk_toolbar_set_style (GTK_TOOLBAR (wid), GTK_TOOLBAR_ICONS);
1101 browser_spinner_set_size (BROWSER_SPINNER (bwin->priv->spinner),
1102 GTK_ICON_SIZE_LARGE_TOOLBAR);
1103 }
1104 else {
1105 gtk_toolbar_set_style (GTK_TOOLBAR (wid), bwin->priv->toolbar_style);
1106 browser_spinner_set_size (BROWSER_SPINNER (bwin->priv->spinner),
1107 GTK_ICON_SIZE_SMALL_TOOLBAR);
1108 }
1109
1110 wid = gtk_ui_manager_get_widget (bwin->priv->ui_manager, "/MenuBar");
1111 if (fullscreen)
1112 gtk_widget_hide (wid);
1113 else
1114 gtk_widget_show (wid);
1115
1116 g_signal_emit (G_OBJECT (bwin), browser_window_signals[FULLSCREEN_CHANGED], 0, fullscreen);
1117 }
1118 return FALSE;
1119 }
1120
1121 static void
window_new_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)1122 window_new_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
1123 {
1124 BrowserWindow *nbwin;
1125 BrowserConnection *bcnc;
1126 bcnc = browser_window_get_connection (bwin);
1127 nbwin = browser_window_new (bcnc, NULL);
1128
1129 browser_core_take_window (nbwin);
1130 }
1131
1132 static void
window_new_with_cnc_cb(GtkAction * action,G_GNUC_UNUSED BrowserWindow * bwin)1133 window_new_with_cnc_cb (GtkAction *action, G_GNUC_UNUSED BrowserWindow *bwin)
1134 {
1135 BrowserWindow *nbwin;
1136 BrowserConnection *bcnc;
1137 bcnc = g_object_get_data (G_OBJECT (action), "bcnc");
1138 g_return_if_fail (BROWSER_IS_CONNECTION (bcnc));
1139
1140 nbwin = browser_window_new (bcnc, NULL);
1141
1142 browser_core_take_window (nbwin);
1143 }
1144
1145 static void
connection_open_cb(G_GNUC_UNUSED GtkAction * action,G_GNUC_UNUSED BrowserWindow * bwin)1146 connection_open_cb (G_GNUC_UNUSED GtkAction *action, G_GNUC_UNUSED BrowserWindow *bwin)
1147 {
1148 browser_connection_open (NULL);
1149 }
1150
1151 static void
connection_properties_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)1152 connection_properties_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
1153 {
1154 if (BROWSER_IS_VIRTUAL_CONNECTION (bwin->priv->bcnc)) {
1155 GtkWidget *win;
1156 BrowserVirtualConnectionSpecs *specs;
1157 gint res;
1158
1159 g_object_get (G_OBJECT (bwin->priv->bcnc), "specs", &specs, NULL);
1160 win = connection_binding_properties_new_edit (specs); /* @specs is not modified */
1161 gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (bwin));
1162 gtk_widget_show (win);
1163
1164 res = gtk_dialog_run (GTK_DIALOG (win));
1165 gtk_widget_hide (win);
1166 if (res == GTK_RESPONSE_OK) {
1167 GError *error = NULL;
1168 if (!browser_virtual_connection_modify_specs (BROWSER_VIRTUAL_CONNECTION (bwin->priv->bcnc),
1169 connection_binding_properties_get_specs (CONNECTION_BINDING_PROPERTIES (win)),
1170 &error)) {
1171 browser_show_error ((GtkWindow*) bwin,
1172 _("Error updating bound connection: %s"),
1173 error && error->message ? error->message : _("No detail"));
1174 g_clear_error (&error);
1175 }
1176
1177 /* update meta store */
1178 browser_connection_update_meta_data (bwin->priv->bcnc);
1179 }
1180 gtk_widget_destroy (win);
1181 }
1182 else {
1183 browser_connections_list_show (bwin->priv->bcnc);
1184 }
1185 }
1186
1187 static void
connection_bind_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)1188 connection_bind_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
1189 {
1190 GtkWidget *win;
1191 gint res;
1192
1193 win = connection_binding_properties_new_create (bwin->priv->bcnc);
1194 gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (bwin));
1195 gtk_widget_show (win);
1196
1197 res = gtk_dialog_run (GTK_DIALOG (win));
1198 gtk_widget_hide (win);
1199 if (res == GTK_RESPONSE_OK) {
1200 BrowserConnection *bcnc;
1201 GError *error = NULL;
1202 bcnc = browser_virtual_connection_new (connection_binding_properties_get_specs
1203 (CONNECTION_BINDING_PROPERTIES (win)), &error);
1204 if (bcnc) {
1205 BrowserWindow *bwin;
1206 bwin = browser_window_new (bcnc, NULL);
1207
1208 browser_core_take_window (bwin);
1209 browser_core_take_connection (bcnc);
1210 }
1211 else {
1212 browser_show_error ((GtkWindow*) bwin,
1213 _("Could not open binding connection: %s"),
1214 error && error->message ? error->message : _("No detail"));
1215 g_clear_error (&error);
1216 }
1217 }
1218 gtk_widget_destroy (win);
1219 }
1220
1221 static void
connection_list_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)1222 connection_list_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
1223 {
1224 browser_connections_list_show (bwin->priv->bcnc);
1225 }
1226
1227 static void
connection_meta_update_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)1228 connection_meta_update_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
1229 {
1230 browser_connection_update_meta_data (bwin->priv->bcnc);
1231 }
1232
1233 static void
about_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)1234 about_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
1235 {
1236 GdkPixbuf *icon;
1237 GtkWidget *dialog;
1238 const gchar *authors[] = {
1239 "Vivien Malerba <malerba@gnome-db.org> (current maintainer)",
1240 NULL
1241 };
1242 const gchar *documenters[] = {
1243 NULL
1244 };
1245 const gchar *translator_credits = "";
1246
1247 gchar *path;
1248 path = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, "pixmaps", "gda-browser.png", NULL);
1249 icon = gdk_pixbuf_new_from_file (path, NULL);
1250 g_free (path);
1251
1252 dialog = gtk_about_dialog_new ();
1253 gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG (dialog), _("Database browser"));
1254 gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (dialog), PACKAGE_VERSION);
1255 gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (dialog), "(C) 2009 - 2011 GNOME Foundation");
1256 gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (dialog), _("Database access services for the GNOME Desktop"));
1257 gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (dialog), "GNU General Public License");
1258 gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (dialog), "http://www.gnome-db.org");
1259 gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (dialog), authors);
1260 gtk_about_dialog_set_documenters (GTK_ABOUT_DIALOG (dialog), documenters);
1261 gtk_about_dialog_set_translator_credits (GTK_ABOUT_DIALOG (dialog), translator_credits);
1262 gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (dialog), icon);
1263 g_signal_connect (G_OBJECT (dialog), "response",
1264 G_CALLBACK (gtk_widget_destroy),
1265 dialog);
1266 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (bwin));
1267 gtk_widget_show (dialog);
1268 }
1269
1270 #ifdef HAVE_GDU
1271 void
manual_cb(G_GNUC_UNUSED GtkAction * action,BrowserWindow * bwin)1272 manual_cb (G_GNUC_UNUSED GtkAction *action, BrowserWindow *bwin)
1273 {
1274 browser_show_help (GTK_WINDOW (bwin), NULL);
1275 }
1276 #endif
1277
1278
1279 /**
1280 * browser_window_get_connection
1281 * @bwin: a #BrowserWindow
1282 *
1283 * Returns: the #BrowserConnection used in @bwin
1284 */
1285 BrowserConnection *
browser_window_get_connection(BrowserWindow * bwin)1286 browser_window_get_connection (BrowserWindow *bwin)
1287 {
1288 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), NULL);
1289 return bwin->priv->bcnc;
1290 }
1291
1292
1293 /*
1294 * perspective_data_new
1295 * @bwin: a #BrowserWindow in which the perspective will be
1296 * @factory: (allow-none): a #BrowserPerspectiveFactory, or %NULL
1297 *
1298 * Creates a new #PerspectiveData structure, it increases @bcnc's reference count.
1299 *
1300 * Returns: a new #PerspectiveData
1301 */
1302 static PerspectiveData *
perspective_data_new(BrowserWindow * bwin,BrowserPerspectiveFactory * factory)1303 perspective_data_new (BrowserWindow *bwin, BrowserPerspectiveFactory *factory)
1304 {
1305 PerspectiveData *pers;
1306
1307 pers = g_new0 (PerspectiveData, 1);
1308 pers->bwin = NULL;
1309 pers->factory = factory;
1310 if (!pers->factory)
1311 pers->factory = browser_core_get_default_factory ();
1312 pers->page_number = -1;
1313 g_assert (pers->factory);
1314 pers->perspective_widget = g_object_ref (pers->factory->perspective_create (bwin));
1315
1316 return pers;
1317 }
1318
1319 /*
1320 * perspective_data_free
1321 */
1322 static void
perspective_data_free(PerspectiveData * pers)1323 perspective_data_free (PerspectiveData *pers)
1324 {
1325 if (pers->perspective_widget)
1326 g_object_unref (pers->perspective_widget);
1327 if (pers->customized_actions)
1328 g_object_unref (pers->customized_actions);
1329 g_free (pers->customized_ui);
1330 g_free (pers);
1331 }
1332
1333 typedef struct {
1334 BrowserWindow *bwin;
1335 guint cid; /* statusbar context id */
1336 guint msgid; /* statusbar message id */
1337 } StatusData;
1338
1339 static gboolean
status_auto_pop_timeout(StatusData * sd)1340 status_auto_pop_timeout (StatusData *sd)
1341 {
1342 if (sd->bwin) {
1343 g_object_remove_weak_pointer (G_OBJECT (sd->bwin), (gpointer*) &(sd->bwin));
1344 gtk_statusbar_remove (GTK_STATUSBAR (sd->bwin->priv->statusbar), sd->cid, sd->msgid);
1345 }
1346 g_free (sd);
1347
1348 return FALSE; /* remove source */
1349 }
1350
1351 /**
1352 * browser_window_push_status
1353 * @bwin: a #BrowserWindow
1354 * @context: textual description of what context the new message is being used in
1355 * @text: textual message
1356 * @auto_clear: %TRUE if the message has to disappear after a while
1357 *
1358 * Pushes a new message onto @bwin's statusbar's stack.
1359 *
1360 * Returns: the message ID, see gtk_statusbar_push(), or %0 if @auto_clear is %TRUE
1361 */
1362 guint
browser_window_push_status(BrowserWindow * bwin,const gchar * context,const gchar * text,gboolean auto_clear)1363 browser_window_push_status (BrowserWindow *bwin, const gchar *context, const gchar *text, gboolean auto_clear)
1364 {
1365 guint cid;
1366 guint retval;
1367
1368 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), 0);
1369 g_return_val_if_fail (context, 0);
1370 g_return_val_if_fail (text, 0);
1371
1372 cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (bwin->priv->statusbar), context);
1373 retval = gtk_statusbar_push (GTK_STATUSBAR (bwin->priv->statusbar), cid, text);
1374 if (auto_clear) {
1375 StatusData *sd;
1376 sd = g_new0 (StatusData, 1);
1377 sd->bwin = bwin;
1378 g_object_add_weak_pointer (G_OBJECT (sd->bwin), (gpointer*) &(sd->bwin));
1379 sd->cid = cid;
1380 sd->msgid = retval;
1381 g_timeout_add_seconds (5, (GSourceFunc) status_auto_pop_timeout, sd);
1382 return 0;
1383 }
1384 else
1385 return retval;
1386 }
1387
1388 /**
1389 * browser_window_pop_status
1390 * @bwin: a #BrowserWindow
1391 * @context: textual description of what context the message is being used in
1392 *
1393 * Removes the first message in the @bwin's statusbar's stack with the given context.
1394 */
1395 void
browser_window_pop_status(BrowserWindow * bwin,const gchar * context)1396 browser_window_pop_status (BrowserWindow *bwin, const gchar *context)
1397 {
1398 guint cid;
1399
1400 g_return_if_fail (BROWSER_IS_WINDOW (bwin));
1401 g_return_if_fail (context);
1402
1403 cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (bwin->priv->statusbar), context);
1404 gtk_statusbar_pop (GTK_STATUSBAR (bwin->priv->statusbar), cid);
1405 }
1406
1407 /**
1408 * browser_window_show_notice_printf
1409 * @bwin: a #BrowserWindow
1410 * @context: textual description of what context the message is being used in
1411 * @format: the text to display
1412 *
1413 * Make @bwin display a notice
1414 */
1415 void
browser_window_show_notice_printf(BrowserWindow * bwin,GtkMessageType type,const gchar * context,const gchar * format,...)1416 browser_window_show_notice_printf (BrowserWindow *bwin, GtkMessageType type, const gchar *context,
1417 const gchar *format, ...)
1418 {
1419 va_list args;
1420 gchar sz[2048];
1421
1422 g_return_if_fail (BROWSER_IS_WINDOW (bwin));
1423
1424 /* build the message string */
1425 va_start (args, format);
1426 vsnprintf (sz, sizeof (sz), format, args);
1427 va_end (args);
1428 browser_window_show_notice (bwin, type, context, sz);
1429 }
1430
1431
1432 static void
info_bar_response_cb(GtkInfoBar * ibar,G_GNUC_UNUSED gint response,BrowserWindow * bwin)1433 info_bar_response_cb (GtkInfoBar *ibar, G_GNUC_UNUSED gint response, BrowserWindow *bwin)
1434 {
1435 bwin->priv->notif_widgets = g_slist_remove (bwin->priv->notif_widgets, ibar);
1436 gtk_widget_destroy ((GtkWidget*) ibar);
1437 }
1438
1439 /* hash table to remain which context notices have to be hidden: key=context, value=GINT_TO_POINTER (1) */
1440 static GHashTable *hidden_contexts = NULL;
1441 static void
hidden_contexts_foreach_save(const gchar * context,G_GNUC_UNUSED gint value,xmlNodePtr root)1442 hidden_contexts_foreach_save (const gchar *context, G_GNUC_UNUSED gint value, xmlNodePtr root)
1443 {
1444 xmlNewChild (root, NULL, BAD_CAST "hide-notice", BAD_CAST context);
1445 }
1446
1447 static void
hide_notice_toggled_cb(GtkToggleButton * toggle,gchar * context)1448 hide_notice_toggled_cb (GtkToggleButton *toggle, gchar *context)
1449 {
1450 g_assert (hidden_contexts);
1451 if (gtk_toggle_button_get_active (toggle))
1452 g_hash_table_insert (hidden_contexts, g_strdup (context), GINT_TO_POINTER (TRUE));
1453 else
1454 g_hash_table_remove (hidden_contexts, context);
1455
1456 /* save config */
1457 xmlDocPtr doc;
1458 xmlNodePtr root;
1459 xmlChar *xml_contents;
1460 gint size;
1461 doc = xmlNewDoc (BAD_CAST "1.0");
1462 root = xmlNewNode (NULL, BAD_CAST "gda-browser-preferences");
1463 xmlDocSetRootElement (doc, root);
1464 g_hash_table_foreach (hidden_contexts, (GHFunc) hidden_contexts_foreach_save, root);
1465 xmlDocDumpFormatMemory (doc, &xml_contents, &size, 1);
1466 xmlFreeDoc (doc);
1467
1468 /* save to disk */
1469 gchar *confdir, *conffile = NULL;
1470 GError *lerror = NULL;
1471 confdir = g_build_path (G_DIR_SEPARATOR_S, g_get_user_config_dir(), "gda-browser", NULL);
1472 if (!g_file_test (confdir, G_FILE_TEST_EXISTS)) {
1473 if (g_mkdir_with_parents (confdir, 0700)) {
1474 g_warning ("Can't create configuration directory '%s' to save preferences.",
1475 confdir);
1476 goto out;
1477 }
1478 }
1479 conffile = g_build_filename (confdir, "preferences.xml", NULL);
1480 if (! g_file_set_contents (conffile, (gchar *) xml_contents, size, &lerror)) {
1481 g_warning ("Can't save preferences file '%s': %s", conffile,
1482 lerror && lerror->message ? lerror->message : _("No detail"));
1483 g_clear_error (&lerror);
1484 }
1485
1486 out:
1487 xmlFree (xml_contents);
1488 g_free (confdir);
1489 g_free (conffile);
1490 }
1491
1492 static void
load_preferences(void)1493 load_preferences (void)
1494 {
1495 /* load preferences */
1496 xmlDocPtr doc;
1497 xmlNodePtr root, node;
1498 gchar *conffile;
1499 conffile = g_build_path (G_DIR_SEPARATOR_S, g_get_user_config_dir(),
1500 "gda-browser", "preferences.xml", NULL);
1501 if (!g_file_test (conffile, G_FILE_TEST_EXISTS)) {
1502 g_free (conffile);
1503 return;
1504 }
1505
1506 doc = xmlParseFile (conffile);
1507 if (!doc) {
1508 g_warning ("Error loading preferences from file '%s'", conffile);
1509 g_free (conffile);
1510 return;
1511 }
1512 g_free (conffile);
1513
1514 root = xmlDocGetRootElement (doc);
1515 for (node = root->children; node; node = node->next) {
1516 xmlChar *contents;
1517 if (strcmp ((gchar *) node->name, "hide-notice"))
1518 continue;
1519 contents = xmlNodeGetContent (node);
1520 if (contents) {
1521 g_hash_table_insert (hidden_contexts, g_strdup ((gchar*) contents),
1522 GINT_TO_POINTER (TRUE));
1523 xmlFree (contents);
1524 }
1525 }
1526 xmlFreeDoc (doc);
1527 }
1528
1529
1530 /**
1531 * browser_window_show_notice
1532 * @bwin: a #BrowserWindow
1533 * @context: textual description of what context the message is being used in
1534 * @text: the information's text
1535 *
1536 * Makes @bwin display a notice
1537 */
1538 void
browser_window_show_notice(BrowserWindow * bwin,GtkMessageType type,const gchar * context,const gchar * text)1539 browser_window_show_notice (BrowserWindow *bwin, GtkMessageType type, const gchar *context, const gchar *text)
1540 {
1541 g_return_if_fail (BROWSER_IS_WINDOW (bwin));
1542 gboolean hide = FALSE;
1543
1544 if ((type != GTK_MESSAGE_ERROR) && context) {
1545 if (!hidden_contexts) {
1546 hidden_contexts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1547 load_preferences ();
1548 }
1549 hide = GPOINTER_TO_INT (g_hash_table_lookup (hidden_contexts, context));
1550 }
1551
1552 if (hide) {
1553 gchar *ptr, *tmp;
1554 tmp = g_strdup (text);
1555 for (ptr = tmp; *ptr && (*ptr != '\n'); ptr++);
1556 if (*ptr) {
1557 *ptr = '.'; ptr++;
1558 *ptr = '.'; ptr++;
1559 *ptr = '.'; ptr++;
1560 *ptr = 0;
1561 }
1562 browser_window_push_status (bwin, "SupportNotice", tmp, TRUE);
1563 g_free (tmp);
1564 }
1565 else {
1566 if (bwin->priv->notif_widgets) {
1567 GSList *list;
1568 for (list = bwin->priv->notif_widgets; list; list = list->next) {
1569 const gchar *c1, *t1;
1570 c1 = g_object_get_data (G_OBJECT (list->data), "context");
1571 t1 = g_object_get_data (G_OBJECT (list->data), "text");
1572 if (((c1 && context && !strcmp (c1, context)) || (!c1 && !context)) &&
1573 ((t1 && text && !strcmp (t1, text)) || (!t1 && !text)))
1574 break;
1575 }
1576 if (list) {
1577 GtkWidget *wid;
1578 wid = GTK_WIDGET (list->data);
1579 g_object_ref ((GObject*) wid);
1580 gtk_container_remove (GTK_CONTAINER (bwin->priv->notif_box), wid);
1581 gtk_box_pack_end (GTK_BOX (bwin->priv->notif_box), wid, TRUE, TRUE, 0);
1582 g_object_unref ((GObject*) wid);
1583 return;
1584 }
1585 }
1586
1587 GtkWidget *cb = NULL;
1588 if (context && (type == GTK_MESSAGE_INFO)) {
1589 cb = gtk_check_button_new_with_label (_("Don't show this message again"));
1590 g_signal_connect_data (cb, "toggled",
1591 G_CALLBACK (hide_notice_toggled_cb), g_strdup (context),
1592 (GClosureNotify) g_free, 0);
1593 }
1594
1595 /* use a GtkInfoBar */
1596 GtkWidget *ibar, *content_area, *label;
1597
1598 ibar = gtk_info_bar_new_with_buttons (GTK_STOCK_CLOSE, 1, NULL);
1599 if (context)
1600 g_object_set_data_full (G_OBJECT (ibar), "context", g_strdup (context), g_free);
1601 if (text)
1602 g_object_set_data_full (G_OBJECT (ibar), "text", g_strdup (text), g_free);
1603 gtk_info_bar_set_message_type (GTK_INFO_BAR (ibar), type);
1604 label = gtk_label_new ("");
1605 gtk_label_set_markup (GTK_LABEL (label), text);
1606 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
1607 gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
1608 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (ibar));
1609 if (cb) {
1610 GtkWidget *box;
1611 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1612 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
1613 gtk_box_pack_start (GTK_BOX (box), cb, FALSE, FALSE, 0);
1614 gtk_container_add (GTK_CONTAINER (content_area), box);
1615 gtk_widget_show_all (box);
1616 }
1617 else {
1618 gtk_container_add (GTK_CONTAINER (content_area), label);
1619 gtk_widget_show (label);
1620 }
1621 g_signal_connect (ibar, "response",
1622 G_CALLBACK (info_bar_response_cb), bwin);
1623 gtk_box_pack_end (GTK_BOX (bwin->priv->notif_box), ibar, TRUE, TRUE, 0);
1624 bwin->priv->notif_widgets = g_slist_append (bwin->priv->notif_widgets, ibar);
1625 if (g_slist_length (bwin->priv->notif_widgets) > 2) {
1626 gtk_widget_destroy (GTK_WIDGET (bwin->priv->notif_widgets->data));
1627 bwin->priv->notif_widgets = g_slist_delete_link (bwin->priv->notif_widgets,
1628 bwin->priv->notif_widgets);
1629 }
1630 gtk_widget_show (ibar);
1631 }
1632 }
1633
1634
1635 /**
1636 * browser_window_customize_perspective_ui
1637 * @bwin: a #BrowserWindow
1638 * @bpers: the #BrowserPerspective concerned
1639 * @actions_group: (allow-none): a #GtkActionGroup object, or %NULL
1640 * @ui_info: (allow-none): a merge UI string, or %NULL. See gtk_ui_manager_add_ui_from_string()
1641 *
1642 * Customizes a UI specific to the @bpers perspective. Any
1643 * previous customization is removed, replaced by the new requested one.
1644 *
1645 * If @actions_group is %NULL then any it simply removes the customization.
1646 */
1647 void
browser_window_customize_perspective_ui(BrowserWindow * bwin,BrowserPerspective * bpers,GtkActionGroup * actions_group,const gchar * ui_info)1648 browser_window_customize_perspective_ui (BrowserWindow *bwin, BrowserPerspective *bpers,
1649 GtkActionGroup *actions_group,
1650 const gchar *ui_info)
1651 {
1652 PerspectiveData *pdata = NULL;
1653 GSList *list;
1654
1655 g_return_if_fail (BROWSER_IS_WINDOW (bwin));
1656 g_return_if_fail (IS_BROWSER_PERSPECTIVE (bpers));
1657
1658 for (list = bwin->priv->perspectives; list; list = list->next) {
1659 if (PERSPECTIVE_DATA (list->data)->perspective_widget == bpers) {
1660 pdata = PERSPECTIVE_DATA (list->data);
1661 break;
1662 }
1663 }
1664 if (! pdata)
1665 return;
1666
1667 /* cleanups */
1668 if (pdata->customized_merge_id) {
1669 gtk_ui_manager_remove_ui (bwin->priv->ui_manager, pdata->customized_merge_id);
1670 pdata->customized_merge_id = 0;
1671 }
1672 if (pdata->customized_actions) {
1673 gtk_ui_manager_remove_action_group (bwin->priv->ui_manager, pdata->customized_actions);
1674 g_object_unref (pdata->customized_actions);
1675 pdata->customized_actions = NULL;
1676 }
1677 g_free (pdata->customized_ui);
1678 pdata->customized_ui = NULL;
1679 gtk_ui_manager_ensure_update (bwin->priv->ui_manager);
1680
1681 if (actions_group) {
1682 g_return_if_fail (GTK_IS_ACTION_GROUP (actions_group));
1683 gtk_action_group_set_translation_domain (actions_group, GETTEXT_PACKAGE);
1684 gtk_ui_manager_insert_action_group (bwin->priv->ui_manager, actions_group, 0);
1685 pdata->customized_actions = g_object_ref (actions_group);
1686 }
1687 if (ui_info) {
1688 pdata->customized_ui = g_strdup (ui_info);
1689 pdata->customized_merge_id = gtk_ui_manager_add_ui_from_string (bwin->priv->ui_manager,
1690 pdata->customized_ui,
1691 -1, NULL);
1692 }
1693 }
1694
1695 /**
1696 * browser_window_change_perspective
1697 * @bwin: a #BrowserWindow
1698 * @perspective: the name of the perspective to change to
1699 *
1700 * Make @bwin switch to the perspective named @perspective
1701 *
1702 * Returns: a pointer to the #BrowserPerspective, or %NULL if not found
1703 */
1704 BrowserPerspective *
browser_window_change_perspective(BrowserWindow * bwin,const gchar * perspective)1705 browser_window_change_perspective (BrowserWindow *bwin, const gchar *perspective)
1706 {
1707 BrowserPerspectiveFactory *bpf;
1708 BrowserPerspective *bpers = NULL;
1709 PerspectiveData *current_pdata;
1710
1711 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), NULL);
1712 g_return_val_if_fail (perspective, NULL);
1713
1714 current_pdata = bwin->priv->current_perspective;
1715
1716 bpf = browser_core_get_factory (perspective);
1717 if (!bpf)
1718 return NULL;
1719 GList *actions, *list;
1720 actions = gtk_action_group_list_actions (bwin->priv->perspectives_actions);
1721 for (list = actions; list; list = list->next) {
1722 GtkAction *action = (GtkAction *) list->data;
1723 BrowserPerspectiveFactory *pf;
1724 pf = BROWSER_PERSPECTIVE_FACTORY (g_object_get_data (G_OBJECT (action), "pers"));
1725 if (pf == bpf) {
1726 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
1727 PerspectiveData *pdata = bwin->priv->current_perspective;
1728 if (pdata && ! g_ascii_strcasecmp (pdata->factory->perspective_name, perspective))
1729 bpers = pdata->perspective_widget;
1730 break;
1731 }
1732 }
1733 g_list_free (actions);
1734
1735 gchar *tmp;
1736 tmp = g_markup_printf_escaped (_("The current perspective has changed to the '%s' perspective, you "
1737 "can switch back to previous perspective through the "
1738 "'Perspective/%s' menu, or using the '%s' shortcut"),
1739 bwin->priv->current_perspective->factory->perspective_name,
1740 current_pdata->factory->perspective_name,
1741 current_pdata->factory->menu_shortcut);
1742
1743
1744 browser_window_show_notice (bwin, GTK_MESSAGE_INFO, "Perspective change", tmp);
1745 g_free (tmp);
1746
1747 return bpers;
1748 }
1749
1750 /**
1751 * browser_window_is_fullscreen
1752 * @bwin: a #BrowserWindow
1753 *
1754 * Returns: %TRUE if @bwin is fullscreen
1755 */
1756 gboolean
browser_window_is_fullscreen(BrowserWindow * bwin)1757 browser_window_is_fullscreen (BrowserWindow *bwin)
1758 {
1759 g_return_val_if_fail (BROWSER_IS_WINDOW (bwin), FALSE);
1760 return bwin->priv->fullscreen;
1761 }
1762
1763 /**
1764 * browser_window_set_fullscreen
1765 * @bwin: a #BrowserWindow
1766 * @fullscreen:
1767 *
1768 * Requires @bwin to be fullscreen if @fullscreen is %TRUE
1769 */
1770 void
browser_window_set_fullscreen(BrowserWindow * bwin,gboolean fullscreen)1771 browser_window_set_fullscreen (BrowserWindow *bwin, gboolean fullscreen)
1772 {
1773 GtkAction *action;
1774 g_return_if_fail (BROWSER_IS_WINDOW (bwin));
1775
1776 action = gtk_action_group_get_action (bwin->priv->agroup, "WindowFullScreen");
1777 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), fullscreen);
1778 }
1779