1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Gaal Yahas <gaal@forum2.org>
8 # include <gtkspell/gtkspell.h>
9 #endif /* HAVE_GTKSPELL */
14 #include "marshalers.h"
20 #define KEY_PICTUREKEYWORD "logjam-picturekeyword"
28 static guint signals
[LAST_SIGNAL
] = { 0 };
34 GtkWidget
*subjectbar
;
35 GtkWidget
*subject
, *security
;
37 GtkWidget
*moodpicbar
;
38 GtkWidget
*moodbox
, *moodbutton
, *moodcombo
;
39 GtkWidget
*picbox
, *pic
;
42 GtkWidget
*musicbutton
, *music
;
44 GtkWidget
*locationbar
;
53 GtkWidget
*preformatted
;
55 GtkWidget
*commentsbox
, *comments
, *screeningbox
, *screening
;
57 GtkSizeGroup
*sizegroup
;
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
) {
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 };
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
)) {
202 LJServer
*server
= jam_host_lj_get_server(JAM_HOST_LJ(jam_account_get_host(view
->account
)));
205 GList
*strings
= NULL
;
207 text
= gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(view
->moodcombo
)->entry
), 0, -1);
208 for (l
= server
->moods
; l
; l
= l
->next
) {
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
);
219 static void mood_add (JamView
*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);
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
) {
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
);
270 jam_doc_set_moodid(view
->doc
, id
);
274 static void picture_populate (JamView
*view
) {
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
) {
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
);
325 LJUser
*user
= jam_account_lj_get_user(JAM_ACCOUNT_LJ(view
->account
));
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
) {
346 gchar
*music
= music_detect(&err
);
348 gtk_entry_set_text(GTK_ENTRY(view
->music
), music
);
352 toplevel
= GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view
)));
353 jam_warning(toplevel
, _("Error detecting music: %s"), err
->message
);
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
) {
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
;
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
[] = {
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
;
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
[] = {
573 N_("Anonymous Only"),
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
;
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 {
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
);
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) {
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
),
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
);
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
);
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
;
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
);
821 void jam_view_set_doc (JamView
*view
, JamDoc
*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
834 if (conf
.options
.usespellcheck
&& view
->entry
) {
836 spell
= gtkspell_get_from_text_view(GTK_TEXT_VIEW(view
->entry
));
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
));
843 if (conf
.options
.usespellcheck
) {
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),
850 #endif /* HAVE_GTKSPELL */
851 undomgr_attach(view
->undomgr
, view
->entry
);
855 void jam_view_settings_changed (JamView
*view
) {
860 if (conf.options.usespellcheck != hadspell) {
862 if (conf.options.usespellcheck) {
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;
870 spell = gtkspell_get_from_text_view(GTK_TEXT_VIEW(fetcheentry(jw)));
872 gtkspell_detach(spell);
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. */
888 GType
jam_view_get_type (void) {
889 static GType new_type
= 0;
891 const GTypeInfo new_info
= {
892 sizeof(JamViewClass
),
895 (GClassInitFunc
) jam_view_class_init
,
900 (GInstanceInitFunc
) jam_view_init
,
902 new_type
= g_type_register_static(GTK_TYPE_VBOX
, "JamView", &new_info
, 0);