fixed some clang warnings
[k8lowj.git] / src / jamview.c
blob519c1ca50b69bc201fcb22ff2b18717410a9d6bd
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Gaal Yahas <gaal@forum2.org>
3 */
4 #include "gtk-all.h"
5 #include "util-gtk.h"
7 #ifdef HAVE_GTKSPELL
8 # include <gtkspell/gtkspell.h>
9 #endif /* HAVE_GTKSPELL */
11 #include "datesel.h"
12 #include "jamdoc.h"
13 #include "jamview.h"
14 #include "marshalers.h"
15 #include "music.h"
16 #include "security.h"
17 #include "undo.h"
20 #define KEY_PICTUREKEYWORD "logjam-picturekeyword"
22 enum {
23 META_TOGGLE,
24 LAST_SIGNAL
28 static guint signals[LAST_SIGNAL] = { 0 };
31 struct _JamView {
32 GtkVBox box;
34 GtkWidget *subjectbar;
35 GtkWidget *subject, *security;
37 GtkWidget *moodpicbar;
38 GtkWidget *moodbox, *moodbutton, *moodcombo;
39 GtkWidget *picbox, *pic;
41 GtkWidget *musicbar;
42 GtkWidget *musicbutton, *music;
44 GtkWidget *locationbar;
45 GtkWidget *location;
47 GtkWidget *tagsbar;
48 GtkWidget *tags;
50 GtkWidget *entry;
52 GtkWidget *optionbar;
53 GtkWidget *preformatted;
54 GtkWidget *datesel;
55 GtkWidget *commentsbox, *comments, *screeningbox, *screening;
57 GtkSizeGroup *sizegroup;
58 UndoMgr *undomgr;
59 JamAccount *account;
60 JamDoc *doc;
64 struct _JamViewClass {
65 GtkVBoxClass parent_class;
66 void (*meta_toggle) (JamView *view, JamViewMeta meta);
70 static void show_meta (JamView *view, JamViewMeta meta) {
71 if (jam_view_get_meta_visible(view, meta)) return;
72 jam_view_toggle_meta(view, meta, TRUE);
73 g_signal_emit_by_name(view, "meta_toggle", meta, TRUE);
77 static void subject_add (JamView *view) {
78 /* subject is always visible. */
79 view->subjectbar = gtk_hbox_new(FALSE, 12);
80 view->subject = gtk_entry_new();
81 gtk_box_pack_start(GTK_BOX(view->subjectbar), labelled_box_new_sg(_("_Subject:"), view->subject, view->sizegroup), TRUE, TRUE, 0);
82 gtk_box_pack_start(GTK_BOX(view), view->subjectbar, FALSE, FALSE, 0);
86 static void subject_load (JamView *view) {
87 const char *subject = jam_doc_get_subject(view->doc);
88 gtk_entry_set_text(GTK_ENTRY(view->subject), (subject ? subject : ""));
92 static void subject_store (JamView *view) {
93 const char *subject = gtk_entry_get_text(GTK_ENTRY(view->subject));
94 if (subject[0] == 0) subject = NULL;
95 jam_doc_set_subject(view->doc, subject);
99 static void security_add (JamView *view) {
100 view->security = secmgr_new(TRUE);
101 secmgr_set_account(SECMGR(view->security), JAM_ACCOUNT_LJ(view->account));
102 gtk_widget_show(view->security);
103 gtk_box_pack_start(GTK_BOX(view->subjectbar), view->security, FALSE, FALSE, 0);
104 gtk_box_reorder_child(GTK_BOX(view->subjectbar), view->security, 1);
108 static void security_remove (JamView *view) {
109 LJSecurity sec = { 0 };
110 jam_doc_set_security(view->doc, &sec);
111 gtk_widget_destroy(view->security);
112 view->security = NULL;
116 static gboolean security_visible (JamView *view) {
117 return view->security != NULL;
121 static void security_account_changed (JamView *view) {
122 /* security shouldn't even be around for non-lj accounts, so the downcast to
123 * account_lj is ok. */
124 secmgr_set_account(SECMGR(view->security), JAM_ACCOUNT_LJ(view->account));
128 static void security_load (JamView *view) {
129 LJSecurity sec = jam_doc_get_security(view->doc);
130 if (sec.type != LJ_SECURITY_PUBLIC) show_meta(view, JAM_VIEW_SECURITY);
131 if (security_visible(view)) secmgr_security_set_force(SECMGR(view->security), &sec);
135 static void security_store (JamView *view) {
136 LJSecurity sec;
137 secmgr_security_get(SECMGR(view->security), &sec);
138 jam_doc_set_security(view->doc, &sec);
142 static void datesel_add (JamView *view) {
143 view->datesel = datesel_new();
144 gtk_box_pack_start(GTK_BOX(view->subjectbar), view->datesel, FALSE, FALSE, 0);
145 gtk_widget_show_all(view->datesel);
149 static void datesel_remove (JamView *view) {
150 jam_doc_set_time(view->doc, NULL);
151 gtk_widget_destroy(view->datesel);
152 view->datesel = NULL;
156 static gboolean datesel_visible (JamView *view) {
157 return (view->datesel != NULL);
161 static void datesel_load (JamView *view) {
162 struct tm vtm = { 0 };
163 gboolean backdated;
164 jam_doc_get_time(view->doc, &vtm);
165 backdated = jam_doc_get_backdated(view->doc);
166 if (vtm.tm_year > 0 || backdated) show_meta(view, JAM_VIEW_DATESEL);
167 if (datesel_visible(view)) {
168 datesel_set_tm(DATESEL(view->datesel), &vtm);
169 datesel_set_backdated(DATESEL(view->datesel), backdated);
174 static void datesel_store(JamView *view) {
175 struct tm vtm = { 0 };
176 datesel_get_tm(DATESEL(view->datesel), &vtm);
177 jam_doc_set_time(view->doc, &vtm);
178 jam_doc_set_backdated(view->doc, datesel_get_backdated(DATESEL(view->datesel)));
182 static void moodpic_add (JamView *view) {
183 if (view->moodpicbar) return;
184 view->moodpicbar = gtk_hbox_new(FALSE, 12);
185 gtk_box_pack_start(GTK_BOX(view), view->moodpicbar, FALSE, FALSE, 0);
186 gtk_box_reorder_child(GTK_BOX(view), view->moodpicbar, 1);
187 gtk_widget_show(view->moodpicbar);
191 static void moodpic_remove (JamView *view) {
192 if (!view->moodpicbar) return;
193 if (view->moodbox || view->pic) return;
194 gtk_widget_destroy(view->moodpicbar);
195 view->moodpicbar = NULL;
199 static void mood_populate (JamView *view) {
200 if (JAM_ACCOUNT_IS_LJ(view->account)) {
201 /* load moods. */
202 LJServer *server = jam_host_lj_get_server(JAM_HOST_LJ(jam_account_get_host(view->account)));
203 LJMood *m;
204 char *text;
205 GList *strings = NULL;
206 GSList *l;
207 text = gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(view->moodcombo)->entry), 0, -1);
208 for (l = server->moods; l; l = l->next) {
209 m = l->data;
210 strings = g_list_insert_sorted(strings, m->name, (GCompareFunc) g_ascii_strcasecmp);
212 if (strings) gtk_combo_set_popdown_strings(GTK_COMBO(view->moodcombo), strings);
213 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(view->moodcombo)->entry), text);
214 g_free(text);
219 static void mood_add (JamView *view) {
220 moodpic_add(view);
222 view->moodbutton = gtk_button_new_with_label(_("Mood"));
223 gtk_size_group_add_widget(view->sizegroup, view->moodbutton);
225 view->moodcombo = gtk_combo_new();
226 gtk_widget_set_usize(GTK_COMBO(view->moodcombo)->entry, 100, -1);
227 mood_populate(view);
229 view->moodbox = gtk_hbox_new(FALSE, 12);
230 gtk_box_pack_start(GTK_BOX(view->moodbox), view->moodbutton, FALSE, FALSE, 0);
231 gtk_box_pack_start(GTK_BOX(view->moodbox), view->moodcombo, TRUE, TRUE, 0);
233 view->moodbox = labelled_box_new_sg(_("_Mood:"), view->moodcombo, view->sizegroup), gtk_widget_show_all(view->moodbox);
234 gtk_box_pack_start(GTK_BOX(view->moodpicbar), view->moodbox, TRUE, TRUE, 0);
235 if (view->pic) gtk_box_reorder_child(GTK_BOX(view->moodpicbar), view->moodbox, 0);
239 static void mood_remove (JamView *view) {
240 jam_doc_set_mood(view->doc, NULL);
241 gtk_widget_destroy(view->moodbox);
242 view->moodbox = view->moodbutton = view->moodcombo = NULL;
243 moodpic_remove(view);
247 static gboolean mood_visible (JamView *view) {
248 return (view->moodbox != NULL);
252 static void mood_account_changed (JamView *view) {
253 mood_populate(view);
257 static void mood_load (JamView *view) {
258 const char *mood = jam_doc_get_mood(view->doc);
259 if (mood) show_meta(view, JAM_VIEW_MOOD);
260 if (mood_visible(view)) gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(view->moodcombo)->entry), (mood ? mood : ""));
264 static void mood_store (JamView *view) {
265 const char *mood = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(view->moodcombo)->entry));
266 /* XXX temporary: set moodid based on mood string. */
267 int id = lj_mood_id_from_name(jam_host_lj_get_server(JAM_HOST_LJ(jam_account_get_host(view->account))), mood);
268 jam_doc_set_mood(view->doc, mood);
269 if (id < 0) id = 0;
270 jam_doc_set_moodid(view->doc, id);
274 static void picture_populate (JamView *view) {
275 GtkWidget *menu;
276 GtkWidget *item;
277 GSList *l;
278 LJUser *user = jam_account_lj_get_user(JAM_ACCOUNT_LJ(view->account));
279 menu = gtk_menu_new();
280 item = gtk_menu_item_new_with_label(_("[default]"));
281 gtk_widget_show(item);
282 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
283 for (l = user->pickws; l; l = l->next) {
284 item = gtk_menu_item_new_with_label(l->data);
285 g_object_set_data(G_OBJECT(item), KEY_PICTUREKEYWORD, l->data);
286 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
287 gtk_widget_show(item);
289 gtk_option_menu_set_menu(GTK_OPTION_MENU(view->pic), menu);
293 static void picture_add (JamView *view) {
294 moodpic_add(view);
295 view->pic = gtk_option_menu_new();
296 picture_populate(view);
297 view->picbox = labelled_box_new_sg(_("_Picture:"), view->pic, view->sizegroup);
298 gtk_box_pack_start(GTK_BOX(view->moodpicbar), view->picbox, FALSE, FALSE, 0);
299 gtk_widget_show_all(view->picbox);
303 static void picture_remove (JamView *view) {
304 jam_doc_set_picture(view->doc, NULL);
305 gtk_widget_destroy(view->picbox);
306 view->picbox = view->pic = NULL;
307 moodpic_remove(view);
311 static gboolean picture_visible (JamView *view) {
312 return (view->picbox != NULL);
316 static void picture_account_changed (JamView *view) {
317 picture_populate(view);
321 static void picture_load (JamView *view) {
322 const char *pic = jam_doc_get_picture(view->doc);
323 GSList *l;
324 int sel = 0;
325 LJUser *user = jam_account_lj_get_user(JAM_ACCOUNT_LJ(view->account));
326 if (pic) {
327 for (l = user->pickws, sel = 1; l; l = l->next, ++sel) if (strcmp(pic, l->data) == 0) break;
328 if (l == NULL) sel = 0;
330 if (sel) show_meta(view, JAM_VIEW_PIC);
331 if (picture_visible(view)) gtk_option_menu_set_history(GTK_OPTION_MENU(view->pic), sel);
335 static void picture_store (JamView *view) {
336 int sel = gtk_option_menu_get_history(GTK_OPTION_MENU(view->pic));
337 LJUser *user = jam_account_lj_get_user(JAM_ACCOUNT_LJ(view->account));
338 const char *pickw = NULL;
339 if (sel > 0) pickw = g_slist_nth(user->pickws, sel-1)->data;
340 jam_doc_set_picture(view->doc, pickw);
344 static void music_refresh_cb (JamView *view) {
345 GError *err = NULL;
346 gchar *music = music_detect(&err);
347 if (music) {
348 gtk_entry_set_text(GTK_ENTRY(view->music), music);
349 g_free(music);
350 } else if (err) {
351 GtkWindow *toplevel;
352 toplevel = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view)));
353 jam_warning(toplevel, _("Error detecting music: %s"), err->message);
354 g_error_free(err);
359 static void music_add (JamView *view) {
360 view->music = gtk_entry_new();
361 view->musicbar = labelled_box_new_sg(_("_Music:"), view->music, view->sizegroup);
362 if (music_can_detect(NULL)) {
363 GtkWidget *refresh = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
364 g_signal_connect_swapped(G_OBJECT(refresh), "clicked", G_CALLBACK(music_refresh_cb), view);
365 gtk_box_pack_start(GTK_BOX(view->musicbar), refresh, FALSE, FALSE, 0);
367 gtk_box_pack_start(GTK_BOX(view), view->musicbar, FALSE, FALSE, 0);
368 gtk_box_reorder_child(GTK_BOX(view), view->musicbar, view->moodpicbar ? 2 : 1);
369 gtk_widget_show_all(view->musicbar);
373 static void music_remove (JamView *view) {
374 jam_doc_set_music(view->doc, NULL);
375 gtk_widget_destroy(view->musicbar);
376 view->musicbar = view->music = NULL;
380 static gboolean music_visible (JamView *view) {
381 return (view->musicbar != NULL);
385 static void music_load (JamView *view) {
386 const char *music = jam_doc_get_music(view->doc);
387 if (music) show_meta(view, JAM_VIEW_MUSIC);
388 if (music_visible(view)) gtk_entry_set_text(GTK_ENTRY(view->music), (music ? music : ""));
392 static void music_store (JamView *view) {
393 const char *music = gtk_entry_get_text(GTK_ENTRY(view->music));
394 if (music[0] == 0) music = NULL;
395 jam_doc_set_music(view->doc, music);
399 static void location_add (JamView *view) {
400 view->location = gtk_entry_new();
401 view->locationbar = labelled_box_new_sg(_("_Location:"), view->location, view->sizegroup);
402 gtk_box_pack_start(GTK_BOX(view), view->locationbar, FALSE, FALSE, 0);
403 gtk_box_reorder_child(GTK_BOX(view), view->locationbar, (view->moodpicbar ? 2 : 1));
404 gtk_widget_show_all(view->locationbar);
408 static void location_remove (JamView *view) {
409 jam_doc_set_location(view->doc, NULL);
410 gtk_widget_destroy(view->locationbar);
411 view->locationbar = view->location = NULL;
415 static gboolean location_visible (JamView *view) {
416 return (view->locationbar != NULL);
420 static void location_load (JamView *view) {
421 const char *location = jam_doc_get_location(view->doc);
422 if (location) show_meta(view, JAM_VIEW_LOCATION);
423 if (location_visible(view)) gtk_entry_set_text(GTK_ENTRY(view->location), (location ? location : ""));
427 static void location_store (JamView *view) {
428 const char *location = gtk_entry_get_text(GTK_ENTRY(view->location));
429 if (location[0] == 0) location = NULL;
430 jam_doc_set_location(view->doc, location);
434 static void tags_add (JamView *view) {
435 view->tags = gtk_entry_new();
436 view->tagsbar = labelled_box_new_sg(_("_Tags:"), view->tags, view->sizegroup);
437 gtk_box_pack_start(GTK_BOX(view), view->tagsbar, FALSE, FALSE, 0);
438 gtk_box_reorder_child(GTK_BOX(view), view->tagsbar, (view->musicbar ? 2 : 1));
439 gtk_widget_show_all(view->tagsbar);
443 static void tags_remove (JamView *view) {
444 jam_doc_set_taglist(view->doc, NULL);
445 gtk_widget_destroy(view->tagsbar);
446 view->tagsbar = view->tags = NULL;
450 static gboolean tags_visible (JamView *view) {
451 return (view->tagsbar != NULL);
455 static void tags_load (JamView *view) {
456 const char *tags = jam_doc_get_taglist(view->doc);
457 if (tags) show_meta(view, JAM_VIEW_TAGS);
458 if (tags_visible(view)) gtk_entry_set_text(GTK_ENTRY(view->tags), (tags ? tags : ""));
462 static void tags_store (JamView *view) {
463 const char *tags = gtk_entry_get_text(GTK_ENTRY(view->tags));
464 if (tags[0] == 0) tags = NULL;
465 jam_doc_set_taglist(view->doc, tags);
469 static void option_add (JamView *view) {
470 if (view->optionbar) return;
471 view->optionbar = gtk_hbox_new(FALSE, 12);
472 gtk_box_pack_end(GTK_BOX(view), view->optionbar, FALSE, FALSE, 0);
473 gtk_widget_show(view->optionbar);
477 static void option_remove (JamView *view) {
478 if (!view->optionbar) return;
479 if (view->preformatted || view->datesel || view->commentsbox || view->screeningbox) return;
480 gtk_widget_destroy(view->optionbar);
481 view->optionbar = NULL;
484 static void preformatted_add (JamView *view) {
485 option_add(view);
486 view->preformatted = gtk_check_button_new_with_mnemonic(_("_Preformatted"));
487 gtk_box_pack_start(GTK_BOX(view->optionbar), view->preformatted, FALSE, FALSE, 0);
488 gtk_widget_show_all(view->preformatted);
492 static void preformatted_remove (JamView *view) {
493 jam_doc_set_preformatted(view->doc, FALSE);
494 gtk_widget_destroy(view->preformatted);
495 view->preformatted = NULL;
496 option_remove(view);
500 static gboolean preformatted_visible (JamView *view) {
501 return (view->preformatted != NULL);
505 static void preformatted_load (JamView *view) {
506 gboolean pre = jam_doc_get_preformatted(view->doc);
507 if (pre) show_meta(view, JAM_VIEW_PREFORMATTED);
508 if (preformatted_visible(view)) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(view->preformatted), pre);
512 static void preformatted_store (JamView *view) {
513 jam_doc_set_preformatted(view->doc, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(view->preformatted)));
516 static void comments_add (JamView *view) {
517 GtkWidget *menu, *item;
518 static const char *items[] = {
519 N_("Default"),
520 N_("Don't Email"),
521 N_("Disable")
523 int i;
525 option_add(view);
526 view->comments = gtk_option_menu_new();
528 menu = gtk_menu_new();
529 for (i = 0; i < sizeof(items)/sizeof(items[0]); ++i) {
530 item = gtk_menu_item_new_with_label(_(items[i]));
531 gtk_widget_show(item);
532 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
534 gtk_option_menu_set_menu(GTK_OPTION_MENU(view->comments), menu);
536 view->commentsbox = labelled_box_new(_("_Comments:"), view->comments);
537 gtk_box_pack_start(GTK_BOX(view->optionbar), view->commentsbox, FALSE, FALSE, 0);
538 gtk_widget_show_all(view->commentsbox);
542 static void comments_remove (JamView *view) {
543 jam_doc_set_comments(view->doc, LJ_COMMENTS_DEFAULT);
544 gtk_widget_destroy(view->commentsbox);
545 view->commentsbox = view->comments = NULL;
546 option_remove(view);
550 static gboolean comments_visible (JamView *view) {
551 return (view->commentsbox != NULL);
555 static void comments_load (JamView *view) {
556 LJCommentsType type = jam_doc_get_comments(view->doc);
557 if (type != LJ_COMMENTS_DEFAULT) show_meta(view, JAM_VIEW_COMMENTS);
558 if (comments_visible(view)) gtk_option_menu_set_history(GTK_OPTION_MENU(view->comments), type);
562 static void comments_store (JamView *view) {
563 LJCommentsType type = gtk_option_menu_get_history(GTK_OPTION_MENU(view->comments));
564 jam_doc_set_comments(view->doc, type);
568 static void screening_add(JamView *view) {
569 GtkWidget *menu, *item;
570 static const char *items[] = {
571 N_("Default"),
572 N_("None"),
573 N_("Anonymous Only"),
574 N_("Non-Friends"),
575 N_("All")
577 int i;
579 option_add(view);
580 view->screening = gtk_option_menu_new();
582 menu = gtk_menu_new();
583 for (i = 0; i < sizeof(items)/sizeof(items[0]); ++i) {
584 item = gtk_menu_item_new_with_label(_(items[i]));
585 gtk_widget_show(item);
586 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
588 gtk_option_menu_set_menu(GTK_OPTION_MENU(view->screening), menu);
590 view->screeningbox = labelled_box_new(_("Scr_eening:"), view->screening);
591 gtk_box_pack_end(GTK_BOX(view->optionbar), view->screeningbox, FALSE, FALSE, 0);
592 gtk_widget_show_all(view->screeningbox);
596 static void screening_remove (JamView *view) {
597 jam_doc_set_screening(view->doc, LJ_SCREENING_DEFAULT);
598 gtk_widget_destroy(view->screeningbox);
599 view->screeningbox = view->screening = NULL;
600 option_remove(view);
604 static gboolean screening_visible (JamView *view) {
605 return (view->screeningbox != NULL);
609 static void screening_load (JamView *view) {
610 LJScreeningType type = jam_doc_get_screening(view->doc);
611 if (type != LJ_SCREENING_DEFAULT) show_meta(view, JAM_VIEW_SCREENING);
612 if (screening_visible(view)) gtk_option_menu_set_history(GTK_OPTION_MENU(view->screening), type);
616 static void screening_store (JamView *view) {
617 LJScreeningType type = gtk_option_menu_get_history(GTK_OPTION_MENU(view->screening));
618 jam_doc_set_screening(view->doc, type);
622 static const struct {
623 const char *name;
624 gboolean lj_only;
626 /* standard for all. */
627 void (*add) (JamView *view);
628 void (*remove) (JamView *view);
629 gboolean (*visible) (JamView *view);
631 void (*load) (JamView *view);
632 void (*store) (JamView *view);
634 /* only defined if it matters when the account changes. */
635 void (*account_changed) (JamView *view);
636 } metas[] = {
637 /* these must match JamViewMeta in jamview.h. */
638 #define STD(x) x##_add, x##_remove, x##_visible, x##_load, x##_store
640 "subject", TRUE, NULL, NULL, NULL, subject_load, subject_store, NULL}, {
641 "security", TRUE, STD(security), security_account_changed}, {
642 "mood", TRUE, STD(mood), mood_account_changed}, {
643 "picture", TRUE, STD(picture), picture_account_changed}, {
644 "music", TRUE, STD(music), NULL}, {
645 "location", TRUE, STD(location), NULL}, {
646 "tags", TRUE, STD(tags), NULL}, {
647 "preformatted", TRUE, STD(preformatted), NULL}, {
648 "datesel", TRUE, STD(datesel), NULL}, {
649 "comments", TRUE, STD(comments), NULL}, {
650 "screening", TRUE, STD(screening), NULL}, {
655 gboolean jam_view_get_meta_visible (JamView *view, JamViewMeta meta) {
656 if (!metas[meta].visible) return TRUE;
657 return metas[meta].visible(view);
661 void jam_view_toggle_meta (JamView *view, JamViewMeta meta, gboolean show) {
662 if (show == metas[meta].visible(view)) return;
663 if (show) metas[meta].add(view); else metas[meta].remove(view);
667 const char *jam_view_meta_to_name (JamViewMeta meta) {
668 return metas[meta].name;
672 gboolean jam_view_meta_from_name (const char *name, JamViewMeta *meta) {
673 for (int i = 0; i <= JAM_VIEW_META_LAST; ++i) {
674 if (strcmp(metas[i].name, name) == 0) {
675 *meta = i;
676 return TRUE;
679 return FALSE;
683 void jam_view_emit_conf (JamView *view) {
684 for (int i = JAM_VIEW_META_FIRST; i <= JAM_VIEW_META_LAST; ++i) {
685 g_signal_emit_by_name(view, "meta_toggle", i, metas[i].visible(view));
690 static void jam_view_load_conf (JamView *view) {
691 for (int meta = JAM_VIEW_META_FIRST; meta <= JAM_VIEW_META_LAST; meta++) {
692 if (conf.options.showmeta[meta] && !metas[meta].visible(view)) {
693 if (JAM_ACCOUNT_IS_LJ(view->account) || !metas[meta].lj_only) {
694 jam_view_toggle_meta(view, meta, TRUE);
695 g_signal_emit_by_name(view, "meta_toggle", meta, TRUE);
697 } else if (!conf.options.showmeta[meta] && metas[meta].visible(view)) {
698 jam_view_toggle_meta(view, meta, FALSE);
699 g_signal_emit_by_name(view, "meta_toggle", meta, FALSE);
705 static void jam_view_class_init (JamViewClass *viewclass) {
706 signals[META_TOGGLE] = g_signal_new("meta_toggle",
707 G_OBJECT_CLASS_TYPE(viewclass),
708 G_SIGNAL_RUN_LAST,
709 G_STRUCT_OFFSET(JamViewClass, meta_toggle),
710 NULL, NULL, logjam_marshal_VOID__INT_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_BOOLEAN);
714 static void undo_cb (JamView *view) {
715 if (undomgr_can_undo(view->undomgr)) undomgr_undo(view->undomgr);
719 static void redo_cb (JamView *view) {
720 if (undomgr_can_redo(view->undomgr)) undomgr_redo(view->undomgr);
724 static void populate_entry_popup (GtkTextView *text, GtkMenu *menu, JamView *view) {
725 GtkWidget *menu_item;
727 g_return_if_fail(menu != NULL);
728 g_return_if_fail(GTK_IS_MENU_SHELL(menu));
730 menu_item = gtk_separator_menu_item_new();
731 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menu_item);
732 gtk_widget_show(menu_item);
734 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_REDO, NULL);
735 gtk_widget_set_sensitive(menu_item, undomgr_can_redo(view->undomgr));
736 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(redo_cb), view);
737 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menu_item);
738 gtk_widget_show(menu_item);
740 menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_UNDO, NULL);
741 gtk_widget_set_sensitive(menu_item, undomgr_can_undo(view->undomgr));
742 g_signal_connect_swapped(G_OBJECT(menu_item), "activate", G_CALLBACK(undo_cb), view);
743 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), menu_item);
744 gtk_widget_show(menu_item);
748 static void jam_view_init (JamView *view) {
749 gtk_box_set_spacing(GTK_BOX(view), 6);
751 view->entry = gtk_text_view_new();
752 view->undomgr = UNDOMGR(undomgr_new());
754 gtk_text_view_set_editable(GTK_TEXT_VIEW(view->entry), TRUE);
755 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view->entry), GTK_WRAP_WORD);
756 g_signal_connect(G_OBJECT(view->entry), "populate-popup", G_CALLBACK(populate_entry_popup), view);
757 if (conf.uifont) jam_widget_set_font(view->entry, conf.uifont);
759 undomgr_attach(UNDOMGR(view->undomgr), view->entry);
761 view->sizegroup = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
763 subject_add(view);
764 jam_view_load_conf(view);
765 gtk_box_pack_start(GTK_BOX(view), scroll_wrap(view->entry), TRUE, TRUE, 0);
769 GtkWidget *jam_view_new (JamDoc *doc) {
770 JamView *view = JAM_VIEW(g_object_new(jam_view_get_type(), NULL));
771 jam_view_set_doc(view, doc);
772 return GTK_WIDGET(view);
776 GObject *jam_view_get_undomgr (JamView *view) {
777 return G_OBJECT(view->undomgr);
781 static void jam_view_account_changed (JamView *view) {
782 view->account = jam_doc_get_account(view->doc);
783 /* notify all visible meta views that the account
784 * has changed, and hide those that shouldn't be shown. */
785 for (int i = JAM_VIEW_META_FIRST; i <= JAM_VIEW_META_LAST; ++i) {
786 if (!metas[i].visible(view)) continue;
787 if (!JAM_ACCOUNT_IS_LJ(view->account) && metas[i].lj_only) {
788 jam_view_toggle_meta(view, i, FALSE);
789 } else {
790 if (metas[i].account_changed && metas[i].visible(view)) metas[i].account_changed(view);
796 static void jam_view_load_doc(JamView *view) {
797 /* if the current account type doesn't support some meta views,
798 * they should've already been hidden by _account_changed. */
799 for (int i = 0; i < JAM_VIEW_META_COUNT; ++i) {
800 if (!metas[i].lj_only || JAM_ACCOUNT_IS_LJ(view->account)) metas[i].load(view);
805 static void jam_view_store_doc (JamView *view) {
806 GtkTextBuffer *buffer;
807 GtkTextIter start, end;
808 char *event;
810 for (int i = 0; i < JAM_VIEW_META_COUNT; ++i) if (jam_view_get_meta_visible(view, i) && metas[i].store) metas[i].store(view);
812 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view->entry));
813 gtk_text_buffer_get_bounds(buffer, &start, &end);
814 event = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
816 jam_doc_set_event(view->doc, event);
817 g_free(event);
821 void jam_view_set_doc (JamView *view, JamDoc *doc) {
822 view->doc = doc;
823 undomgr_detach(view->undomgr, view->entry);
824 if (view->account != jam_doc_get_account(doc)) jam_view_account_changed(view);
825 g_signal_connect_swapped(G_OBJECT(doc), "notify::account", G_CALLBACK(jam_view_account_changed), view);
826 g_signal_connect_swapped(G_OBJECT(doc), "update_doc", G_CALLBACK(jam_view_store_doc), view);
827 g_signal_connect_swapped(G_OBJECT(doc), "entry_changed", G_CALLBACK(jam_view_load_doc), view);
828 jam_view_load_conf(view);
829 jam_view_load_doc(view);
830 /* XXX: gtkspell gets confused if you detach its document,
831 * so we detach the spell checker completely, then reattach
832 * it at the end. */
833 #ifdef HAVE_GTKSPELL
834 if (conf.options.usespellcheck && view->entry) {
835 GtkSpell *spell;
836 spell = gtkspell_get_from_text_view(GTK_TEXT_VIEW(view->entry));
837 if (spell)
838 gtkspell_detach(spell);
840 #endif /* HAVE_GTKSPELL */
841 gtk_text_view_set_buffer(GTK_TEXT_VIEW(view->entry), jam_doc_get_text_buffer(doc));
842 #ifdef HAVE_GTKSPELL
843 if (conf.options.usespellcheck) {
844 GError *err = NULL;
845 if (gtkspell_new_attach(GTK_TEXT_VIEW(view->entry), conf.spell_language, &err) == NULL) {
846 jam_warning(NULL, _("GtkSpell error: %s"), err->message); // XXX GTK_WINDOW(view->jw),
847 g_error_free(err);
850 #endif /* HAVE_GTKSPELL */
851 undomgr_attach(view->undomgr, view->entry);
855 void jam_view_settings_changed (JamView *view) {
856 #if 0
858 XXX make this work
859 #ifdef HAVE_GTKSPELL
860 if (conf.options.usespellcheck != hadspell) {
861 GtkSpell *spell;
862 if (conf.options.usespellcheck) {
863 GError *err = NULL;
864 if (gtkspell_new_attach(GTK_TEXT_VIEW(fetcheentry(jw)), conf.spell_language, &err) == NULL) {
865 jam_warning(GTK_WINDOW(jw), _("GtkSpell error: %s"), err->message);
866 conf.options.usespellcheck = FALSE;
867 g_error_free(err);
869 } else {
870 spell = gtkspell_get_from_text_view(GTK_TEXT_VIEW(fetcheentry(jw)));
871 if (spell)
872 gtkspell_detach(spell);
875 #endif
877 #endif
878 if (conf.uifont) jam_widget_set_font(view->entry, conf.uifont);
879 if (view->musicbar) {
880 /* There are many cleaner ways to add/remove the Refresh button when
881 * the music preference has changed, but this works fine. */
882 music_remove(view);
883 music_add(view);
888 GType jam_view_get_type (void) {
889 static GType new_type = 0;
890 if (!new_type) {
891 const GTypeInfo new_info = {
892 sizeof(JamViewClass),
893 NULL,
894 NULL,
895 (GClassInitFunc) jam_view_class_init,
896 NULL,
897 NULL,
898 sizeof(JamView),
900 (GInstanceInitFunc) jam_view_init,
902 new_type = g_type_register_static(GTK_TYPE_VBOX, "JamView", &new_info, 0);
904 return new_type;