~ubuntu-branches/ubuntu/trusty/gq/trusty

« back to all changes in this revision

Viewing changes to src/gq-window.c

  • Committer: Bazaar Package Importer
  • Author(s): Barry deFreese
  • Date: 2009-10-25 23:34:56 UTC
  • mfrom: (1.1.4 upstream) (3.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20091025233456-i794n3yg2cff930j
Tags: 1.3.4-1
* QA upload.
  + Set maintainer to Debian QA Group <packages@qa.debian.org>.
* New upstream release. (Closes: #534705).
  + Does not segfault on amd64. (Closes: #444312).
  + Remove all existing patches and change patch system to quilt.
  + Replace dpatch build-dep with quilt.
* 01_desktop_file.diff - Remove encoding and bogus categories 
  from desktop file.
* Copy in config.{sub,guess} on configure, rm them on clean.
  + Add build-dep on autotools-dev.
* Make clean not ignore errors.
* Add copyright holders and version path to GPL (GPL-2).
* Update watch file to use SF redirector. (Closes: #449749).
* Bump debhelper build-dep and compat to 5.
* Bump Standards Version to 3.8.3.
  + Menu policy transition.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of GQ
 
2
 *
 
3
 * AUTHORS
 
4
 *     Sven Herzberg  <herzi@gnome-de.org>
 
5
 *
 
6
 * Copyright (C) 1998-2003 Bert Vermeulen
 
7
 * Copyright (C) 2002-2003 Peter Stamfest
 
8
 * Copyright (C) 2006  Sven Herzberg
 
9
 *
 
10
 * This program is released under the Gnu General Public License with
 
11
 * the additional exemption that compiling, linking, and/or using
 
12
 * OpenSSL is allowed.
 
13
 *
 
14
 * This program is free software; you can redistribute it and/or
 
15
 * modify it under the terms of the GNU General Public License as
 
16
 * published by the Free Software Foundation; either version 2 of the
 
17
 * License, or (at your option) any later version.
 
18
 *
 
19
 * This program is distributed in the hope that it will be useful,
 
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 * GNU General Public License for more details.
 
23
 *
 
24
 * You should have received a copy of the GNU General Public License
 
25
 * along with this program; if not, write to the Free Software
 
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
27
 * USA
 
28
 */
 
29
 
 
30
#include "gq-window.h"
 
31
 
 
32
#include <string.h>
 
33
 
 
34
#include <glib.h>
 
35
#include <glib/gi18n.h>
 
36
#include <gtk/gtk.h>
 
37
#include <gdk/gdkkeysyms.h>
 
38
 
 
39
#ifdef HAVE_CONFIG_H
 
40
# include <config.h>
 
41
#endif /* HAVE_CONFIG_H */
 
42
 
 
43
#include "common.h"
 
44
#include "gq-server-list.h"
 
45
#include "gq-tab-browse.h"
 
46
#ifdef HAVE_LDAP_STR2OBJECTCLASS
 
47
#    include "gq-tab-schema.h"
 
48
#endif
 
49
#include "gq-tab-search.h"
 
50
 
 
51
#include "configfile.h"
 
52
#include "COPYING.h"
 
53
#include "debug.h"
 
54
#include "errorchain.h"
 
55
#include "filter.h"
 
56
#include "gq-diff-tab.h"
 
57
#include "gq-input-form.h"
 
58
#include "gq-utilities.h"
 
59
#include "prefs.h"
 
60
#include "progress.h"
 
61
#include "state.h"
 
62
#include "template.h"
 
63
 
 
64
GqWindow mainwin;
 
65
 
 
66
static void create_about_window(GtkWindow* parent);
 
67
 
 
68
static void close_current_tab(GqWindow *win);
 
69
static void mainwin_destroyed(GqWindow *win);
 
70
static void switchpage_refocus(GtkNotebook *notebook, GtkNotebookPage *page,
 
71
                               int pagenum, GqWindow *win);
 
72
 
 
73
GqTab*
 
74
gq_window_get_last_tab(GqWindow const* self,
 
75
                       GType           type)
 
76
{
 
77
        gint i, n;
 
78
        g_return_val_if_fail(GQ_IS_WINDOW(self), NULL);
 
79
        g_return_val_if_fail(self->tab_history, NULL);
 
80
 
 
81
        n = gq_stack_get_n_elements(self->tab_history);
 
82
        for(i = 0; i < n; i++) {
 
83
                GqTab* tab = gq_stack_get_element(self->tab_history, i);
 
84
                if(G_TYPE_CHECK_INSTANCE_TYPE(tab, type)) {
 
85
                        return tab;
 
86
                }
 
87
        }
 
88
 
 
89
        return NULL;
 
90
}
 
91
 
 
92
 
 
93
void go_to_page(GqTab *tab)
 
94
{
 
95
     gtk_notebook_set_page(GTK_NOTEBOOK(mainwin.mainbook),
 
96
                           gtk_notebook_page_num(GTK_NOTEBOOK(mainwin.mainbook),
 
97
                                                 tab->content));
 
98
}
 
99
 
 
100
 
 
101
void
 
102
enter_last_of_mode(GqTab *tab)
 
103
{
 
104
        g_return_if_fail(mainwin.tab_history);
 
105
 
 
106
        gq_stack_raise(mainwin.tab_history, tab);
 
107
}
 
108
 
 
109
static gboolean
 
110
mainwin_restore_snapshot(GqWindow *win)
 
111
{
 
112
        struct pbar_win *pw = NULL;
 
113
        char tmp[32];
 
114
        gboolean created = FALSE;
 
115
        int i;
 
116
        GType type;
 
117
 
 
118
        /* Initialize Tab types */
 
119
        GQ_TYPE_TAB_BROWSE;
 
120
        GQ_TYPE_TAB_SCHEMA;
 
121
        GQ_TYPE_TAB_SEARCH;
 
122
        GQ_TYPE_DIFF_TAB;
 
123
 
 
124
     if (!config->restore_tabs) return FALSE;
 
125
     if (!exists_entity("mainwin.tabs")) return FALSE;
 
126
 
 
127
     pw = create_progress_bar_in_window(_("Restoring last GUI state"));
 
128
     update_progress(pw, _("Restoring tabs"));
 
129
 
 
130
     for (i = 0 ; ; i++) {
 
131
          g_snprintf(tmp, sizeof(tmp), "mainwin.tabs.%d", i);
 
132
          if (!exists_entity(tmp)) break;
 
133
          type = state_value_get_type(tmp, "type", G_TYPE_INVALID);
 
134
          if (type == G_TYPE_INVALID) {
 
135
                gint old_type = state_value_get_int(tmp, "type", 0);
 
136
 
 
137
                if(old_type) {
 
138
                        GType wrapper[] = {
 
139
                                G_TYPE_INVALID, // 0
 
140
                                GQ_TYPE_TAB_SEARCH,
 
141
                                GQ_TYPE_TAB_BROWSE,
 
142
                                GQ_TYPE_TAB_SCHEMA
 
143
                        };
 
144
                        type = wrapper[old_type];
 
145
                }
 
146
          }
 
147
 
 
148
          if(g_type_is_a(type, GQ_TYPE_TAB)) {
 
149
               GqTab *tab = new_modetab(win, type, TRUE);
 
150
               int error_ctx = error_new_context("", pw->win);
 
151
 
 
152
               if (GQ_TAB_GET_CLASS(tab)->restore_snapshot) {
 
153
                    GQ_TAB_GET_CLASS(tab)->restore_snapshot(error_ctx, tmp, tab, pw);
 
154
               }
 
155
 
 
156
               error_flush(error_ctx);
 
157
 
 
158
                created = TRUE;
 
159
          }
 
160
          update_progress(pw, NULL);
 
161
          if (pw->cancelled) break;
 
162
     }
 
163
 
 
164
     if (i > 0) {
 
165
          type = state_value_get_int("mainwin.tabs", "active", -1);
 
166
          gtk_notebook_set_page(GTK_NOTEBOOK(win->mainbook), type);
 
167
     }
 
168
 
 
169
     update_progress(pw, _("Restoring tabs"));
 
170
     free_progress(pw);
 
171
 
 
172
     return i > 0 && created;
 
173
}
 
174
 
 
175
static void
 
176
mainwin_save_snapshot(GqWindow *win)
 
177
{
 
178
     GqTab *tab = NULL;
 
179
     int i;
 
180
     char tmp[32];
 
181
 
 
182
     rm_value("mainwin.tabs");
 
183
 
 
184
     if (!config->restore_tabs) return;
 
185
 
 
186
     for( i = 0 ; (tab = mainwin_get_tab_nth(win, i)) != NULL ; i++) {
 
187
          g_snprintf(tmp, sizeof(tmp), "mainwin.tabs.%d", i);
 
188
          state_value_set_type(tmp, "type", G_OBJECT_TYPE(tab));
 
189
          if (GQ_TAB_GET_CLASS(tab)->save_snapshot) {
 
190
               int error_ctx =
 
191
                    error_new_context(_("Saving main window snapshot"), NULL);
 
192
               GQ_TAB_GET_CLASS(tab)->save_snapshot(error_ctx, tmp, tab);
 
193
               error_flush(error_ctx);
 
194
          }
 
195
     }
 
196
 
 
197
     state_value_set_int("mainwin.tabs", "active",
 
198
                         gtk_notebook_get_current_page(GTK_NOTEBOOK(win->mainbook)));
 
199
}
 
200
 
 
201
 
 
202
/* gtk2 checked (multiple destroy callbacks safety), confidence 0.7:
 
203
   cleanup_all_tabs semantics? */
 
204
static void
 
205
mainwin_destroyed(GqWindow *win)
 
206
{
 
207
     mainwin_save_snapshot(win);
 
208
     cleanup(win);
 
209
     gtk_main_quit();
 
210
}
 
211
 
 
212
void cleanup(GqWindow *win)
 
213
{
 
214
     cleanup_all_tabs(win);
 
215
}
 
216
 
 
217
static gboolean ctrl_b_hack(GtkWidget *widget, GdkEventKey *event, gpointer obj)
 
218
{
 
219
     if(event && event->type == GDK_KEY_PRESS &&
 
220
        event->state & GDK_CONTROL_MASK && event->keyval == GDK_b) {
 
221
          g_signal_emit_by_name(obj, "activate");
 
222
          g_signal_stop_emission_by_name(widget, "key_press_event");
 
223
          return(TRUE);
 
224
     }
 
225
 
 
226
     return(FALSE);
 
227
}
 
228
 
 
229
 
 
230
static gboolean ctrl_w_hack(GtkWidget *widget, GdkEventKey *event, gpointer obj)
 
231
{
 
232
     if(event && event->type == GDK_KEY_PRESS &&
 
233
        event->state & GDK_CONTROL_MASK && event->keyval == GDK_w) {
 
234
          g_signal_emit_by_name(obj, "activate");
 
235
          g_signal_stop_emission_by_name(widget, "key_press_event");
 
236
          return(TRUE);
 
237
     }
 
238
 
 
239
     return(FALSE);
 
240
}
 
241
 
 
242
static void new_modetab_search(GqWindow *win) 
 
243
{
 
244
     new_modetab(win, GQ_TYPE_TAB_SEARCH, TRUE);
 
245
}
 
246
 
 
247
static void new_modetab_browse(GqWindow *win) 
 
248
{
 
249
     new_modetab(win, GQ_TYPE_TAB_BROWSE, TRUE);
 
250
}
 
251
 
 
252
static void new_modetab_schema(GqWindow *win) 
 
253
{
 
254
     new_modetab(win, GQ_TYPE_TAB_SCHEMA, TRUE);
 
255
}
 
256
 
 
257
 
 
258
static GList *log_list = NULL;
 
259
static int log_list_len = 0;
 
260
 
 
261
static void
 
262
clear_message_history(void)
 
263
{
 
264
     if (log_list) {
 
265
          g_list_foreach(log_list, (GFunc) g_free, NULL);
 
266
          g_list_free(log_list);
 
267
          log_list = NULL;
 
268
     }
 
269
 
 
270
     if (mainwin.ml_text) {
 
271
          GtkTextIter start;
 
272
          GtkTextIter end;
 
273
          
 
274
          gtk_text_buffer_get_start_iter(mainwin.ml_buffer, &start);
 
275
          gtk_text_buffer_get_end_iter(mainwin.ml_buffer, &end);
 
276
 
 
277
          gtk_text_buffer_delete(mainwin.ml_buffer, &start, &end);
 
278
     }
 
279
}
 
280
 
 
281
 
 
282
void message_log_append(const char *buf)
 
283
{
 
284
     log_list = g_list_append(log_list, g_strdup(buf));
 
285
     log_list_len++;
 
286
 
 
287
     if (mainwin.ml_text) {
 
288
          GtkTextIter iter;
 
289
          gtk_text_buffer_get_end_iter(mainwin.ml_buffer, &iter);
 
290
          gtk_text_buffer_insert(mainwin.ml_buffer, &iter,
 
291
                                 buf, strlen(buf));
 
292
          gtk_text_buffer_insert(mainwin.ml_buffer, &iter, "\n", 1);
 
293
 
 
294
          gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(mainwin.ml_text),
 
295
                                       gtk_text_buffer_create_mark(mainwin.ml_buffer,
 
296
                                                                   NULL,
 
297
                                                                   &iter,
 
298
                                                                   FALSE),
 
299
                                       0.0,
 
300
                                       FALSE,
 
301
                                       0.0, 0.0);
 
302
     }
 
303
     while (log_list_len > MESSAGE_LOG_MAX) {
 
304
          g_free(log_list->data);
 
305
          log_list = g_list_remove(log_list, log_list->data);
 
306
          log_list_len--;
 
307
     }
 
308
}
 
309
 
 
310
static void
 
311
message_log_destroyed(GqWindow *win)
 
312
{
 
313
     win->ml_window = NULL;
 
314
     win->ml_text   = NULL;
 
315
     win->ml_buffer = NULL;
 
316
}
 
317
 
 
318
static void clear_clicked(void)
 
319
{
 
320
     clear_message_history();
 
321
}
 
322
 
 
323
static void message_log(GqWindow *win) 
 
324
{
 
325
     GtkWidget *window, *vbox0, *scrwin, *text, *bbox, *button;
 
326
     GtkTextBuffer *buffer;
 
327
     GtkTextIter iter;
 
328
     GList *I;
 
329
 
 
330
     g_assert(win);
 
331
 
 
332
     if (win->ml_window) {
 
333
          gtk_window_present(GTK_WINDOW(win->ml_window));
 
334
          return;
 
335
     }
 
336
 
 
337
     window = stateful_gtk_window_new(GTK_WINDOW_TOPLEVEL,
 
338
                                      "statusbar-log", 500, 350);
 
339
     win->ml_window = window;
 
340
 
 
341
     gtk_widget_realize(window);
 
342
 
 
343
        g_signal_connect_swapped(window, "destroy",
 
344
                                 G_CALLBACK(message_log_destroyed), win);
 
345
 
 
346
     g_signal_connect(window, "key_press_event",
 
347
                        G_CALLBACK(close_on_esc),
 
348
                        window);
 
349
 
 
350
/*      current_search_options_window = window; */
 
351
     gtk_window_set_title(GTK_WINDOW(window), _("Message Log"));
 
352
     gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
 
353
 
 
354
     vbox0 = gtk_vbox_new(FALSE, 0);
 
355
     gtk_container_border_width(GTK_CONTAINER(vbox0), 
 
356
                                CONTAINER_BORDER_WIDTH);
 
357
     gtk_widget_show(vbox0);
 
358
     gtk_container_add(GTK_CONTAINER(window), vbox0);
 
359
 
 
360
     /* scrolled window to hold the log */
 
361
     scrwin = gtk_scrolled_window_new(NULL, NULL);
 
362
     gtk_widget_show(scrwin);
 
363
     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
 
364
                                    GTK_POLICY_AUTOMATIC,
 
365
                                    GTK_POLICY_AUTOMATIC);
 
366
     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrwin),
 
367
                                         GTK_SHADOW_IN);
 
368
     gtk_box_pack_start(GTK_BOX(vbox0), scrwin, TRUE, TRUE, 0);
 
369
 
 
370
     text = gtk_text_view_new();
 
371
     buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
 
372
     win->ml_buffer = buffer;
 
373
 
 
374
     gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
 
375
     gtk_text_buffer_get_end_iter(buffer, &iter);
 
376
 
 
377
     win->ml_text = text;
 
378
 
 
379
     gtk_widget_show(text);
 
380
     gtk_container_add(GTK_CONTAINER(scrwin), text); 
 
381
 
 
382
     for (I = log_list ; I ; I = g_list_next(I) ) {
 
383
          gtk_text_buffer_insert(buffer, &iter,
 
384
                                 I->data, strlen(I->data));
 
385
          gtk_text_buffer_insert(buffer, &iter, "\n", 1);
 
386
     }
 
387
 
 
388
     gtk_text_buffer_get_end_iter(buffer, &iter);
 
389
     gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text),
 
390
                                  gtk_text_buffer_create_mark(buffer, NULL,
 
391
                                                              &iter, FALSE),
 
392
                                  0.0,
 
393
                                  FALSE,
 
394
                                  0.0, 0.0);
 
395
 
 
396
     bbox = gtk_hbutton_box_new();
 
397
     gtk_widget_show(bbox);
 
398
 
 
399
     gtk_box_pack_end(GTK_BOX(vbox0), bbox, FALSE, FALSE, 3);
 
400
 
 
401
     button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
 
402
     gtk_widget_show(button);
 
403
     g_signal_connect_swapped(button, "clicked",
 
404
                               G_CALLBACK(gtk_widget_destroy),
 
405
                               window);
 
406
     gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, TRUE, 10);
 
407
 
 
408
     button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
 
409
     gtk_widget_show(button);
 
410
     g_signal_connect(button, "clicked",
 
411
                        G_CALLBACK(clear_clicked),
 
412
                        win);
 
413
     gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, TRUE, 10);
 
414
 
 
415
     GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
 
416
     gtk_widget_grab_default(button);
 
417
 
 
418
     gtk_widget_show(window);
 
419
}
 
420
 
 
421
/* Callback function called when a tab gets removed from the
 
422
   notebook. */
 
423
static void remove_tab(GtkContainer *notebook,
 
424
                       GtkWidget *content,
 
425
                       GqWindow *win)
 
426
{
 
427
     GqTab *old_tab = NULL;
 
428
     int i;
 
429
 
 
430
     old_tab = gtk_object_get_data(GTK_OBJECT(content), "tab");
 
431
     if (old_tab) {
 
432
             GqTab* tab;
 
433
          gq_stack_remove(win->tab_history, old_tab);
 
434
 
 
435
#warning "FIXME: just grab this one from the history"
 
436
          /* try to find another tab with the same mode so we can put that
 
437
             one into lastofmode... */
 
438
          for( i = 0 ; (tab = mainwin_get_tab_nth(win, i)) != NULL ; i++) {
 
439
               if (G_OBJECT_TYPE(tab) == G_OBJECT_TYPE(old_tab)) {
 
440
                    /* found one! */
 
441
                    enter_last_of_mode(tab);
 
442
                    break;
 
443
               }
 
444
          }
 
445
     }
 
446
 
 
447
     if (gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), 0) == NULL) {
 
448
          gtk_widget_destroy(win->mainwin);
 
449
     }
 
450
}
 
451
 
 
452
 
 
453
void mainwin_update_filter_menu(GqWindow *win)
 
454
{
 
455
     GList *menuitems = gtk_container_children(GTK_CONTAINER(win->filtermenu));
 
456
     GList *I;
 
457
 
 
458
     /* Filters | list of filters */
 
459
 
 
460
     if (menuitems) {
 
461
          for ( I = g_list_first(menuitems) ; I ; I = g_list_next(I) ) {
 
462
               GtkWidget *item = GTK_WIDGET(I->data);
 
463
               gpointer data = gtk_object_get_data(GTK_OBJECT(item), "filter");
 
464
 
 
465
               if (data) {
 
466
                    gtk_widget_destroy(item);
 
467
               }
 
468
          }
 
469
 
 
470
          g_list_free(menuitems);
 
471
     }
 
472
 
 
473
     for ( I = g_list_first(config->filters) ; I ; I = g_list_next(I) ) {
 
474
          struct gq_filter *filter;
 
475
          GtkWidget *menuitem;
 
476
 
 
477
          filter = (struct gq_filter *) I->data;
 
478
          menuitem = gtk_menu_item_new_with_label(filter->name);
 
479
 
 
480
          gtk_object_set_data(GTK_OBJECT(menuitem), "filter", filter);
 
481
          g_signal_connect_swapped(menuitem, "activate",
 
482
                                    G_CALLBACK(filter_selected),
 
483
                                    filter);
 
484
 
 
485
          gtk_container_add(GTK_CONTAINER(win->filtermenu), menuitem);
 
486
          gtk_widget_show(menuitem);
 
487
     }
 
488
}
 
489
 
 
490
static void
 
491
window_help_manual(GqWindow* window)
 
492
{
 
493
        GError* error = NULL;
 
494
        gdk_spawn_command_line_on_screen(gtk_widget_get_screen(window->mainwin),
 
495
                                         "yelp ghelp:gq-manual", &error);
 
496
        if(error) {
 
497
                // FIXME: show a nice error dialog
 
498
                g_warning(_("Couldn't open help document: %s"), error->message);
 
499
                g_error_free(error);
 
500
        }
 
501
}
 
502
 
 
503
void create_mainwin(GqWindow *win)
 
504
{
 
505
     GtkWidget *outer_vbox, *main_vbox, *menubar, *menuitem, *submenu;
 
506
     GtkWidget *File, *menuFile, *New, *Close, *ShowM, *Quit;
 
507
     GtkWidget *Search, *Browse, *Schema;
 
508
     GtkWidget *menuHelp, *Help, *About;
 
509
     GtkWidget *Filters, *menuFilters;
 
510
     GtkWidget *handlebox;
 
511
     GtkAccelGroup *accel_group;
 
512
 
 
513
     g_assert(win != NULL);
 
514
 
 
515
        win->tab_history = gq_stack_new();
 
516
     win->mainwin = stateful_gtk_window_new(GTK_WINDOW_TOPLEVEL,
 
517
                                            "mainwin", 770, 478);
 
518
 
 
519
     gtk_container_border_width(GTK_CONTAINER(win->mainwin), 0);
 
520
        g_signal_connect_swapped(win->mainwin, "destroy",
 
521
                                 G_CALLBACK(mainwin_destroyed), win);
 
522
     gtk_window_set_title(GTK_WINDOW(win->mainwin), _("GQ"));
 
523
     gtk_window_set_policy(GTK_WINDOW(win->mainwin), FALSE, TRUE, FALSE);
 
524
 
 
525
 
 
526
 
 
527
     outer_vbox = gtk_vbox_new(FALSE, 2);
 
528
     gtk_container_border_width(GTK_CONTAINER(outer_vbox), 0);
 
529
     gtk_widget_show(outer_vbox);
 
530
     gtk_container_add(GTK_CONTAINER(win->mainwin), outer_vbox);
 
531
 
 
532
     accel_group = gtk_accel_group_new();
 
533
 
 
534
     gtk_window_add_accel_group(GTK_WINDOW(win->mainwin), accel_group);
 
535
 
 
536
     handlebox = gtk_handle_box_new();
 
537
     gtk_widget_show(handlebox);
 
538
     gtk_box_pack_start(GTK_BOX(outer_vbox), handlebox, FALSE, TRUE, 0);
 
539
 
 
540
     menubar = gtk_menu_bar_new();
 
541
     gtk_widget_show(menubar);
 
542
     gtk_container_add(GTK_CONTAINER(handlebox), menubar);
 
543
 
 
544
     /* File menu */
 
545
     File = gq_menu_item_new_with_label(_("_File"));
 
546
     gtk_widget_show(File);
 
547
     gtk_container_add(GTK_CONTAINER(menubar), File);
 
548
 
 
549
     menuFile = gtk_menu_new();
 
550
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(File), menuFile);
 
551
 
 
552
     /* File | New */
 
553
     New = gq_menu_item_new_with_label(_("_New tab"));
 
554
     gtk_widget_show(New);
 
555
     gtk_container_add(GTK_CONTAINER(menuFile), New);
 
556
     submenu = gtk_menu_new();
 
557
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(New), submenu);
 
558
 
 
559
     /* File | New | Search */
 
560
     Search = gq_menu_item_new_with_label(_("_Search"));
 
561
     gtk_widget_show(Search);
 
562
     gtk_menu_append(GTK_MENU(submenu), Search);
 
563
     g_signal_connect_swapped(Search, "activate",
 
564
                               G_CALLBACK(new_modetab_search),
 
565
                               win);
 
566
     gtk_widget_add_accelerator(Search, "activate", accel_group, 'S',
 
567
                                GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
568
 
 
569
     /* File | New | Browse */
 
570
     Browse = gq_menu_item_new_with_label(_("_Browse"));
 
571
     gtk_widget_show(Browse);
 
572
     gtk_menu_append(GTK_MENU(submenu), Browse);
 
573
     g_signal_connect_swapped(Browse, "activate",
 
574
                               G_CALLBACK(new_modetab_browse),
 
575
                               win);
 
576
     gtk_widget_add_accelerator(Browse, "activate", accel_group, 'B',
 
577
                                GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
578
     /* ctrl-b is used by text widgets, so the searchterm textbox that
 
579
        always has focus in search mode blocks the above accelerator...*/
 
580
     g_signal_connect(win->mainwin, "key_press_event",
 
581
                        G_CALLBACK(ctrl_b_hack),
 
582
                        Browse);
 
583
 
 
584
     /* File | New | Schema */
 
585
     Schema = gq_menu_item_new_with_label(_("S_chema"));
 
586
     gtk_widget_show(Schema);
 
587
     gtk_menu_append(GTK_MENU(submenu), Schema);
 
588
     gtk_widget_add_accelerator(Schema, "activate", accel_group, 'Z',
 
589
                                GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
590
#ifdef HAVE_LDAP_STR2OBJECTCLASS
 
591
     g_signal_connect_swapped(Schema, "activate",
 
592
                               G_CALLBACK(new_modetab_schema),
 
593
                               win);
 
594
#else
 
595
     gtk_widget_set_sensitive(Schema, FALSE);
 
596
#endif
 
597
 
 
598
     /* File | Preferences */
 
599
     menuitem = gq_menu_item_new_with_label(_("_Preferences"));
 
600
     gtk_widget_show(menuitem);
 
601
     gtk_container_add(GTK_CONTAINER(menuFile), menuitem);
 
602
     g_signal_connect_swapped(menuitem, "activate",
 
603
                               G_CALLBACK(create_prefs_window),
 
604
                               win);
 
605
     gtk_widget_add_accelerator(menuitem, "activate", accel_group, 'P',
 
606
                                GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
607
 
 
608
     /* File | Close */
 
609
     Close = gq_menu_item_new_with_label(_("_Close tab"));
 
610
     gtk_widget_show(Close);
 
611
     gtk_container_add(GTK_CONTAINER(menuFile), Close);
 
612
     g_signal_connect_swapped(Close, "activate",
 
613
                               G_CALLBACK(close_current_tab),
 
614
                               win);
 
615
     gtk_widget_add_accelerator(Close, "activate", accel_group, 'W',
 
616
                                GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
617
     /* :-( */
 
618
     g_signal_connect(win->mainwin, "key_press_event",
 
619
                        G_CALLBACK(ctrl_w_hack),
 
620
                        Close);
 
621
 
 
622
     /* File | Quit */
 
623
     Quit = gq_menu_item_new_with_label(_("_Quit"));
 
624
     gtk_widget_show(Quit);
 
625
     gtk_container_add(GTK_CONTAINER(menuFile), Quit);
 
626
     g_signal_connect_swapped(Quit, "activate",
 
627
                               G_CALLBACK(gtk_widget_destroy),
 
628
                               win->mainwin);
 
629
     gtk_widget_add_accelerator(Quit, "activate", accel_group, 'Q',
 
630
                                GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
 
631
 
 
632
 
 
633
     /* Filters menu */
 
634
     Filters = gq_menu_item_new_with_label(_("F_ilters"));
 
635
     gtk_widget_show(Filters);
 
636
     gtk_container_add(GTK_CONTAINER(menubar), Filters);
 
637
 
 
638
     menuFilters = gtk_menu_new();
 
639
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(Filters), menuFilters);
 
640
     win->filtermenu = menuFilters;
 
641
 
 
642
     /* Filters | New */
 
643
     New = gq_menu_item_new_with_label(_("_New filter"));
 
644
     gtk_widget_show(New);
 
645
     gtk_container_add(GTK_CONTAINER(menuFilters), New);
 
646
     submenu = gtk_menu_new();
 
647
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(New), submenu);
 
648
 
 
649
     /* Filters | New | From Search tab */
 
650
     menuitem = gq_menu_item_new_with_label(_("From _Search tab"));
 
651
     gtk_widget_show(menuitem);
 
652
     gtk_menu_append(GTK_MENU(submenu), menuitem);
 
653
     g_signal_connect_swapped(menuitem, "activate",
 
654
                               G_CALLBACK(add_filter),
 
655
                               NULL);
 
656
 
 
657
     /* Filters | New | Filter Editor */
 
658
     menuitem = gq_menu_item_new_with_label(_("Filter _editor"));
 
659
     gtk_widget_show(menuitem);
 
660
     gtk_menu_append(GTK_MENU(submenu), menuitem);
 
661
     g_signal_connect_swapped(menuitem, "activate",
 
662
                               G_CALLBACK(add_new_filter_callback),
 
663
                               NULL);
 
664
 
 
665
     /* Filters | Edit Filters */
 
666
     menuitem = gq_menu_item_new_with_label(_("_Edit Filters"));
 
667
     gtk_widget_show(menuitem);
 
668
     gtk_container_add(GTK_CONTAINER(menuFilters), menuitem);
 
669
     g_signal_connect_swapped(menuitem, "activate",
 
670
                               G_CALLBACK(show_filters),
 
671
                               NULL);
 
672
 
 
673
     /* Filters separator */
 
674
     menuitem = gtk_menu_item_new();
 
675
     gtk_widget_show(menuitem);
 
676
     gtk_container_add(GTK_CONTAINER(menuFilters), menuitem);
 
677
 
 
678
     mainwin_update_filter_menu(win);
 
679
 
 
680
     /* Help menu */
 
681
     Help = gq_menu_item_new_with_label(_("_Help"));
 
682
     gtk_widget_show(Help);
 
683
     gtk_container_add(GTK_CONTAINER(menubar), Help);
 
684
 
 
685
     menuHelp = gtk_menu_new();
 
686
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(Help), menuHelp);
 
687
 
 
688
        Help = gtk_image_menu_item_new_with_mnemonic(_("_Manual"));
 
689
        gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(Help),
 
690
                                      gtk_image_new_from_stock(GTK_STOCK_HELP, GTK_ICON_SIZE_MENU));
 
691
        gtk_widget_show(Help);
 
692
        gtk_menu_shell_append(GTK_MENU_SHELL(menuHelp), Help);
 
693
        g_signal_connect_swapped(Help, "activate",
 
694
                                 G_CALLBACK(window_help_manual), win);
 
695
 
 
696
        Help = gtk_separator_menu_item_new();
 
697
        gtk_widget_show(Help);
 
698
        gtk_menu_shell_append(GTK_MENU_SHELL(menuHelp), Help);
 
699
 
 
700
     /* Help | Show Messages */
 
701
 
 
702
     ShowM = gq_menu_item_new_with_label(_("Show _Messages"));
 
703
     gtk_widget_show(ShowM);
 
704
     gtk_container_add(GTK_CONTAINER(menuHelp), ShowM);
 
705
     g_signal_connect_swapped(ShowM, "activate",
 
706
                               G_CALLBACK(message_log),
 
707
                               win);
 
708
 
 
709
     gtk_container_add(GTK_CONTAINER(menuHelp), gtk_separator_menu_item_new());
 
710
 
 
711
     /* Help | About */
 
712
     About = gq_menu_item_new_with_label(_("_About"));
 
713
     gtk_widget_show(About);
 
714
     gtk_container_add(GTK_CONTAINER(menuHelp), About);
 
715
     g_signal_connect_swapped(About, "activate",
 
716
                              G_CALLBACK(create_about_window), win->mainwin);
 
717
 
 
718
     main_vbox = gtk_vbox_new(FALSE, 2);
 
719
     gtk_container_border_width(GTK_CONTAINER(main_vbox), 4);
 
720
     gtk_widget_show(main_vbox);
 
721
     gtk_box_pack_start(GTK_BOX(outer_vbox), main_vbox, TRUE, TRUE, 1);
 
722
 
 
723
     win->mainbook = gtk_notebook_new();
 
724
        gtk_notebook_set_homogeneous_tabs(GTK_NOTEBOOK(win->mainbook), FALSE);
 
725
     gtk_widget_show(win->mainbook);
 
726
/*      GTK_WIDGET_UNSET_FLAGS(GTK_NOTEBOOK(mainbook), GTK_CAN_FOCUS); */
 
727
     gtk_box_pack_start(GTK_BOX(main_vbox), win->mainbook, TRUE, TRUE, 0);
 
728
 
 
729
     win->statusbar = gtk_statusbar_new();
 
730
     gtk_widget_show(win->statusbar);
 
731
 
 
732
     gtk_box_pack_end(GTK_BOX(outer_vbox), win->statusbar, FALSE, FALSE, 0);
 
733
     gtk_widget_set_sensitive(win->statusbar, TRUE);
 
734
     
 
735
     g_signal_connect(win->mainbook, "switch-page",
 
736
                        G_CALLBACK(switchpage_refocus), win);
 
737
     g_signal_connect(win->mainbook, "remove",
 
738
                        G_CALLBACK(remove_tab), win);
 
739
 
 
740
     gtk_widget_realize(win->mainwin);
 
741
 
 
742
     if (! mainwin_restore_snapshot(win)) {
 
743
          new_modetab(win, GQ_TYPE_TAB_SEARCH, TRUE);
 
744
          new_modetab(win, GQ_TYPE_TAB_BROWSE, FALSE);
 
745
          new_modetab(win, GQ_TYPE_TAB_SCHEMA, FALSE);
 
746
     }
 
747
 
 
748
     gtk_widget_show(win->mainwin);
 
749
}
 
750
 
 
751
GqTab *mainwin_get_tab_nth(GqWindow *win, int n)
 
752
{
 
753
     GtkWidget *content = 
 
754
          gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->mainbook), n);
 
755
     if (content == NULL) return NULL;
 
756
 
 
757
     return gtk_object_get_data(GTK_OBJECT(content), "tab");
 
758
}
 
759
 
 
760
GqTab *mainwin_get_current_tab(GtkWidget *notebook)
 
761
{
 
762
     int tabnum = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook));
 
763
     GtkWidget *content = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), 
 
764
                                                    tabnum);
 
765
     return gtk_object_get_data(GTK_OBJECT(content), "tab");
 
766
}
 
767
 
 
768
GqTab*
 
769
new_modetab(GqWindow* win,
 
770
            GType     mode,
 
771
            gboolean  has_focus)
 
772
{
 
773
        GtkWidget* tab_box;
 
774
        GtkWidget* tab_label;
 
775
        GtkWidget* tab_button;
 
776
        GtkWidget* tab_image;
 
777
        GtkWidget* focusbox;
 
778
        GqTab *tab;
 
779
 
 
780
        tab = g_object_new(mode, NULL);
 
781
        if(mode == GQ_TYPE_TAB_SEARCH) {
 
782
                tab_label = gq_label_new(_("_Search"));
 
783
        }
 
784
        else if(mode == GQ_TYPE_TAB_BROWSE) {
 
785
                tab_label = gq_label_new(_("_Browse"));
 
786
        }
 
787
        else if(G_OBJECT_TYPE(tab) == GQ_TYPE_DIFF_TAB) {
 
788
                tab_label = gq_label_new(_("C_ompare"));
 
789
        }
 
790
#ifdef HAVE_LDAP_STR2OBJECTCLASS
 
791
        else if(mode == GQ_TYPE_TAB_SCHEMA) {
 
792
                tab_label = gq_label_new(_("S_chema"));
 
793
        }
 
794
#endif
 
795
        else {
 
796
                g_warning("Invalid tab type %s", g_type_name(mode));
 
797
                return NULL;
 
798
        }
 
799
 
 
800
        tab_box = gtk_hbox_new(FALSE, 6);
 
801
        gtk_box_pack_start(GTK_BOX(tab_box), tab_label,
 
802
                           FALSE, FALSE, 0);
 
803
        tab_button = gtk_button_new();
 
804
        gtk_button_set_relief(GTK_BUTTON(tab_button), GTK_RELIEF_NONE);
 
805
        g_signal_connect_swapped(tab_button, "clicked",
 
806
                                 G_CALLBACK(gtk_widget_destroy), tab->content);
 
807
        gtk_box_pack_start(GTK_BOX(tab_box), tab_button,
 
808
                           FALSE, FALSE, 0);
 
809
        tab_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE,
 
810
                                             GTK_ICON_SIZE_MENU);
 
811
        gtk_container_add(GTK_CONTAINER(tab_button), tab_image);
 
812
        gtk_widget_show_all(tab_box);
 
813
 
 
814
#warning "FIXME: GET THIS ONLY CLEANER"
 
815
        gtk_object_set_data(GTK_OBJECT(tab->content), "tab", tab);
 
816
 
 
817
     tab->win = win;
 
818
 
 
819
        gq_stack_push(win->tab_history, tab);
 
820
     gtk_notebook_append_page(GTK_NOTEBOOK(win->mainbook), 
 
821
                              tab->content,
 
822
                                 tab_box);
 
823
 
 
824
     if(has_focus) {
 
825
          enter_last_of_mode(tab);
 
826
 
 
827
          gtk_notebook_set_page(GTK_NOTEBOOK(win->mainbook), -1);
 
828
 
 
829
          focusbox = tab->focus;
 
830
          if(focusbox)
 
831
               gtk_widget_grab_focus(focusbox);
 
832
     }
 
833
     return tab;
 
834
}
 
835
 
 
836
 
 
837
static void
 
838
switchpage_refocus(GtkNotebook    * notebook G_GNUC_UNUSED,
 
839
                   GtkNotebookPage* page     G_GNUC_UNUSED,
 
840
                   int              pagenum,
 
841
                   GqWindow       * win)
 
842
{
 
843
     GtkWidget *focusbox;
 
844
     GqTab *tab;
 
845
 
 
846
     tab = mainwin_get_tab_nth(win, pagenum);
 
847
     if(!tab)
 
848
          return;
 
849
 
 
850
     /* retrieve mode, store this pane as the last one used for this mode */
 
851
     enter_last_of_mode(tab);
 
852
 
 
853
     focusbox = tab->focus;
 
854
     if(focusbox) {
 
855
          gtk_widget_grab_focus(focusbox);
 
856
          gtk_editable_select_region(GTK_EDITABLE(focusbox), 0, -1);
 
857
     }
 
858
}
 
859
 
 
860
 
 
861
void cleanup_all_tabs(GqWindow *win)
 
862
{
 
863
     /* don't waste time refocusing on disappearing tabs */
 
864
     g_signal_handlers_disconnect_by_func(win->mainbook,
 
865
                                   G_CALLBACK(switchpage_refocus), win);
 
866
}
 
867
 
 
868
 
 
869
static void close_current_tab(GqWindow *win)
 
870
{
 
871
     int tabnum;
 
872
     GtkWidget *content;
 
873
 
 
874
     tabnum = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->mainbook));
 
875
     content = gtk_notebook_get_nth_page(GTK_NOTEBOOK(win->mainbook), tabnum);
 
876
     /* for whatever reason: gtk_notebook_remove_page does not call
 
877
        the remove signal on the notebook. I consider this to be a GTK
 
878
        bug */
 
879
 
 
880
/*      gtk_notebook_remove_page(GTK_NOTEBOOK(win->mainbook), tabnum); */
 
881
 
 
882
     gtk_widget_destroy(content);
 
883
}
 
884
 
 
885
void update_serverlist(GqWindow *win)
 
886
{
 
887
        GqTab *tab;
 
888
        int i;
 
889
 
 
890
        for(i = 0 ; (tab = mainwin_get_tab_nth(win, i)) != NULL ; i++) {
 
891
#warning "FIXME: make this a generic update function for tabs"
 
892
                if(GQ_IS_TAB_BROWSE(tab)) {
 
893
                        update_browse_serverlist(tab);
 
894
                }
 
895
                else if(GQ_IS_TAB_SCHEMA(tab)) {
 
896
                        update_schema_serverlist(tab);
 
897
                }
 
898
        }
 
899
}
 
900
 
 
901
static void
 
902
about_dialog_activate_uri(GtkAboutDialog* dialog,
 
903
                          gchar const   * uri,
 
904
                          gpointer        data G_GNUC_UNUSED)
 
905
{
 
906
        gchar* shell_uri = g_shell_quote(uri);
 
907
        gchar* command = g_strdup_printf("gnome-open %s", shell_uri);
 
908
        gdk_spawn_command_line_on_screen(gtk_widget_get_screen(GTK_WIDGET(dialog)),
 
909
                                         command, NULL);
 
910
        g_free(command);
 
911
        g_free(shell_uri);
 
912
}
 
913
 
 
914
static void
 
915
create_about_window(GtkWindow* parent) {
 
916
        static gchar const* authors[] = {
 
917
                "Bert Vermeulen",
 
918
                "Peter Stamfest",
 
919
                "David Malcom",
 
920
                "Sven Herzberg (current maintainer)",
 
921
                NULL
 
922
        };
 
923
        GdkPixbuf* logo = gdk_pixbuf_new_from_file(PACKAGE_PREFIX "/share/pixmaps/gq/gq.xpm", NULL);
 
924
        gtk_about_dialog_set_url_hook(about_dialog_activate_uri, NULL, NULL);
 
925
        gtk_show_about_dialog(parent,
 
926
                              // "artists", NULL,
 
927
                              "authors", authors,
 
928
                              "comments", _("The gentleman's LDAP client"),
 
929
                              "copyright", _("Copyright (C) 1998-2003 Bert Vermeulen\n"
 
930
                                             "Copyright (C) 2002-2003 Peter Stamfest\n"
 
931
                                             "Copyright (C) 2006 Sven Herzberg"),
 
932
                              // documenters
 
933
                              "license", license,
 
934
                              "logo", logo,
 
935
                              "name", _("GQ LDAP Client"),
 
936
                              "translator-credits", _("translator-credits"),
 
937
                              "version", VERSION,
 
938
                              "website", "http://www.gq-project.org/",
 
939
                              "website-label", _("GQ Website"),
 
940
                              NULL);
 
941
        if(logo) {
 
942
                g_object_unref(logo);
 
943
        }
 
944
}
 
945