1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Gaal Yahas <gaal@forum2.org>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
10 #include <gtkspell/gtkspell.h>
11 #endif /* HAVE_GTKSPELL */
18 #include "marshalers.h"
21 #define KEY_PICTUREKEYWORD "logjam-picturekeyword"
28 static guint signals
[LAST_SIGNAL
] = { 0 };
33 GtkWidget
*subjectbar
;
34 GtkWidget
*subject
, *security
;
36 GtkWidget
*moodpicbar
;
37 GtkWidget
*moodbox
, *moodbutton
, *moodcombo
;
38 GtkWidget
*picbox
, *pic
;
41 GtkWidget
*musicbutton
, *music
;
43 GtkWidget
*locationbar
;
52 GtkWidget
*preformatted
;
54 GtkWidget
*commentsbox
, *comments
, *screeningbox
, *screening
;
56 GtkSizeGroup
*sizegroup
;
62 struct _JamViewClass
{
63 GtkVBoxClass parent_class
;
64 void (*meta_toggle
)(JamView
*view
, JamViewMeta meta
);
68 show_meta(JamView
*view
, JamViewMeta meta
) {
69 if (jam_view_get_meta_visible(view
, meta
))
71 jam_view_toggle_meta(view
, meta
, TRUE
);
72 g_signal_emit_by_name(view
, "meta_toggle", meta
, TRUE
);
76 subject_add(JamView
*view
) {
77 /* subject is always visible. */
78 view
->subjectbar
= gtk_hbox_new(FALSE
, 12);
80 view
->subject
= gtk_entry_new();
81 gtk_box_pack_start(GTK_BOX(view
->subjectbar
),
82 labelled_box_new_sg(_("_Subject:"), view
->subject
, view
->sizegroup
),
85 gtk_box_pack_start(GTK_BOX(view
), view
->subjectbar
, FALSE
, FALSE
, 0);
88 subject_load(JamView
*view
) {
89 const char *subject
= jam_doc_get_subject(view
->doc
);
90 gtk_entry_set_text(GTK_ENTRY(view
->subject
), subject
? subject
: "");
93 subject_store(JamView
*view
) {
94 const char *subject
= gtk_entry_get_text(GTK_ENTRY(view
->subject
));
95 if (subject
[0] == 0) subject
= NULL
;
96 jam_doc_set_subject(view
->doc
, subject
);
100 security_add(JamView
*view
) {
101 view
->security
= secmgr_new(TRUE
);
102 secmgr_set_account(SECMGR(view
->security
), JAM_ACCOUNT_LJ(view
->account
));
103 gtk_widget_show(view
->security
);
104 gtk_box_pack_start(GTK_BOX(view
->subjectbar
), view
->security
, FALSE
, FALSE
, 0);
105 gtk_box_reorder_child(GTK_BOX(view
->subjectbar
), view
->security
, 1);
108 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
;
115 security_visible(JamView
*view
) {
116 return view
->security
!= NULL
;
119 security_account_changed(JamView
*view
) {
120 /* security shouldn't even be around for non-lj accounts, so the downcast to
121 * account_lj is ok. */
122 secmgr_set_account(SECMGR(view
->security
), JAM_ACCOUNT_LJ(view
->account
));
125 security_load(JamView
*view
) {
126 LJSecurity sec
= jam_doc_get_security(view
->doc
);
127 if (sec
.type
!= LJ_SECURITY_PUBLIC
)
128 show_meta(view
, JAM_VIEW_SECURITY
);
129 if (security_visible(view
))
130 secmgr_security_set_force(SECMGR(view
->security
), &sec
);
133 security_store(JamView
*view
) {
135 secmgr_security_get(SECMGR(view
->security
), &sec
);
136 jam_doc_set_security(view
->doc
, &sec
);
140 datesel_add(JamView
*view
) {
141 view
->datesel
= datesel_new();
142 gtk_box_pack_start(GTK_BOX(view
->subjectbar
), view
->datesel
, FALSE
, FALSE
, 0);
143 gtk_widget_show_all(view
->datesel
);
146 datesel_remove(JamView
*view
) {
147 jam_doc_set_time(view
->doc
, NULL
);
148 gtk_widget_destroy(view
->datesel
);
149 view
->datesel
= NULL
;
152 datesel_visible(JamView
*view
) {
153 return view
->datesel
!= NULL
;
156 datesel_load(JamView
*view
) {
159 jam_doc_get_time(view
->doc
, &vtm
);
160 backdated
= jam_doc_get_backdated(view
->doc
);
161 if (vtm
.tm_year
> 0 || backdated
)
162 show_meta(view
, JAM_VIEW_DATESEL
);
163 if (datesel_visible(view
)) {
164 datesel_set_tm(DATESEL(view
->datesel
), &vtm
);
165 datesel_set_backdated(DATESEL(view
->datesel
), backdated
);
169 datesel_store(JamView
*view
) {
171 datesel_get_tm(DATESEL(view
->datesel
), &vtm
);
172 jam_doc_set_time(view
->doc
, &vtm
);
173 jam_doc_set_backdated(view
->doc
,
174 datesel_get_backdated(DATESEL(view
->datesel
)));
179 moodpic_add(JamView
*view
) {
180 if (view
->moodpicbar
)
182 view
->moodpicbar
= gtk_hbox_new(FALSE
, 12);
183 gtk_box_pack_start(GTK_BOX(view
), view
->moodpicbar
, FALSE
, FALSE
, 0);
184 gtk_box_reorder_child(GTK_BOX(view
), view
->moodpicbar
, 1);
185 gtk_widget_show(view
->moodpicbar
);
188 moodpic_remove(JamView
*view
) {
189 if (!view
->moodpicbar
)
191 if (view
->moodbox
|| view
->pic
)
193 gtk_widget_destroy(view
->moodpicbar
);
194 view
->moodpicbar
= NULL
;
198 mood_populate(JamView
*view
) {
199 if (JAM_ACCOUNT_IS_LJ(view
->account
)) {
201 LJServer
*server
= jam_host_lj_get_server(JAM_HOST_LJ(jam_account_get_host(view
->account
)));
204 GList
*strings
= NULL
;
207 text
= gtk_editable_get_chars(GTK_EDITABLE(GTK_COMBO(view
->moodcombo
)->entry
), 0, -1);
209 for (l
= server
->moods
; l
; l
= l
->next
) {
211 strings
= g_list_insert_sorted(strings
, m
->name
,
212 (GCompareFunc
)g_ascii_strcasecmp
);
215 gtk_combo_set_popdown_strings(GTK_COMBO(view
->moodcombo
), strings
);
217 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(view
->moodcombo
)->entry
), text
);
222 mood_add(JamView
*view
) {
225 /*view->moodbutton = gtk_button_new_with_label(_("Mood"));
226 gtk_size_group_add_widget(view->sizegroup, view->moodbutton);*/
228 view
->moodcombo
= gtk_combo_new();
229 gtk_widget_set_usize(GTK_COMBO(view
->moodcombo
)->entry
, 100, -1);
232 /*view->moodbox = gtk_hbox_new(FALSE, 12);
233 gtk_box_pack_start(GTK_BOX(view->moodbox), view->moodbutton, FALSE, FALSE, 0);
234 gtk_box_pack_start(GTK_BOX(view->moodbox), view->moodcombo, TRUE, TRUE, 0);*/
235 view
->moodbox
= labelled_box_new_sg(_("_Mood:"), view
->moodcombo
, view
->sizegroup
),
236 gtk_widget_show_all(view
->moodbox
);
238 gtk_box_pack_start(GTK_BOX(view
->moodpicbar
), view
->moodbox
, TRUE
, TRUE
, 0);
240 gtk_box_reorder_child(GTK_BOX(view
->moodpicbar
), view
->moodbox
, 0);
243 mood_remove(JamView
*view
) {
244 jam_doc_set_mood(view
->doc
, NULL
);
245 gtk_widget_destroy(view
->moodbox
);
246 view
->moodbox
= view
->moodbutton
= view
->moodcombo
= NULL
;
247 moodpic_remove(view
);
250 mood_visible(JamView
*view
) {
251 return view
->moodbox
!= NULL
;
254 mood_account_changed(JamView
*view
) {
258 mood_load(JamView
*view
) {
259 const char *mood
= jam_doc_get_mood(view
->doc
);
261 show_meta(view
, JAM_VIEW_MOOD
);
262 if (mood_visible(view
))
263 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(view
->moodcombo
)->entry
),
267 mood_store(JamView
*view
) {
268 const char *mood
= gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(view
->moodcombo
)->entry
));
269 /* XXX temporary: set moodid based on mood string. */
270 int id
= lj_mood_id_from_name(
271 jam_host_lj_get_server(JAM_HOST_LJ(jam_account_get_host(view
->account
))),
274 jam_doc_set_mood(view
->doc
, mood
);
276 jam_doc_set_moodid(view
->doc
, id
);
280 picture_populate(JamView
*view
) {
284 LJUser
*user
= jam_account_lj_get_user(JAM_ACCOUNT_LJ(view
->account
));
286 menu
= gtk_menu_new();
287 item
= gtk_menu_item_new_with_label(_("[default]"));
288 gtk_widget_show(item
);
289 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
291 for (l
= user
->pickws
; l
; l
= l
->next
) {
292 item
= gtk_menu_item_new_with_label(l
->data
);
293 g_object_set_data(G_OBJECT(item
), KEY_PICTUREKEYWORD
, l
->data
);
294 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
295 gtk_widget_show(item
);
298 gtk_option_menu_set_menu(GTK_OPTION_MENU(view
->pic
), menu
);
301 picture_add(JamView
*view
) {
303 view
->pic
= gtk_option_menu_new();
304 picture_populate(view
);
305 view
->picbox
= labelled_box_new_sg(_("_Picture:"), view
->pic
, view
->sizegroup
);
306 gtk_box_pack_start(GTK_BOX(view
->moodpicbar
), view
->picbox
, FALSE
, FALSE
, 0);
307 gtk_widget_show_all(view
->picbox
);
310 picture_remove(JamView
*view
) {
311 jam_doc_set_picture(view
->doc
, NULL
);
312 gtk_widget_destroy(view
->picbox
);
313 view
->picbox
= view
->pic
= NULL
;
314 moodpic_remove(view
);
317 picture_visible(JamView
*view
) {
318 return view
->picbox
!= NULL
;
321 picture_account_changed(JamView
*view
) {
322 picture_populate(view
);
325 picture_load(JamView
*view
) {
326 const char *pic
= jam_doc_get_picture(view
->doc
);
329 LJUser
*user
= jam_account_lj_get_user(JAM_ACCOUNT_LJ(view
->account
));
332 for (l
= user
->pickws
, sel
= 1; l
; l
= l
->next
, sel
++) {
333 if (strcmp(pic
, l
->data
) == 0)
336 if (l
== NULL
) sel
= 0;
339 show_meta(view
, JAM_VIEW_PIC
);
340 if (picture_visible(view
))
341 gtk_option_menu_set_history(GTK_OPTION_MENU(view
->pic
), sel
);
345 picture_store(JamView
*view
) {
346 int sel
= gtk_option_menu_get_history(GTK_OPTION_MENU(view
->pic
));
347 LJUser
*user
= jam_account_lj_get_user(JAM_ACCOUNT_LJ(view
->account
));
348 const char *pickw
= NULL
;
351 pickw
= g_slist_nth(user
->pickws
, sel
-1)->data
;
353 jam_doc_set_picture(view
->doc
, pickw
);
357 music_refresh_cb(JamView
*view
) {
359 gchar
*music
= music_detect(&err
);
362 gtk_entry_set_text(GTK_ENTRY(view
->music
), music
);
366 toplevel
= GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view
)));
367 jam_warning(toplevel
, _("Error detecting music: %s"), err
->message
);
373 music_add(JamView
*view
) {
374 view
->music
= gtk_entry_new();
375 view
->musicbar
= labelled_box_new_sg(_("_Music:"), view
->music
, view
->sizegroup
);
376 if (music_can_detect(NULL
)) {
377 GtkWidget
*refresh
= gtk_button_new_from_stock(GTK_STOCK_REFRESH
);
378 g_signal_connect_swapped(G_OBJECT(refresh
), "clicked",
379 G_CALLBACK(music_refresh_cb
), view
);
380 gtk_box_pack_start(GTK_BOX(view
->musicbar
),
381 refresh
, FALSE
, FALSE
, 0);
383 gtk_box_pack_start(GTK_BOX(view
), view
->musicbar
, FALSE
, FALSE
, 0);
384 gtk_box_reorder_child(GTK_BOX(view
), view
->musicbar
, view
->moodpicbar
? 2 : 1);
385 gtk_widget_show_all(view
->musicbar
);
388 music_remove(JamView
*view
) {
389 jam_doc_set_music(view
->doc
, NULL
);
390 gtk_widget_destroy(view
->musicbar
);
391 view
->musicbar
= view
->music
= NULL
;
394 music_visible(JamView
*view
) {
395 return view
->musicbar
!= NULL
;
398 music_load(JamView
*view
) {
399 const char *music
= jam_doc_get_music(view
->doc
);
401 show_meta(view
, JAM_VIEW_MUSIC
);
402 if (music_visible(view
))
403 gtk_entry_set_text(GTK_ENTRY(view
->music
), music
? music
: "");
406 music_store(JamView
*view
) {
407 const char *music
= gtk_entry_get_text(GTK_ENTRY(view
->music
));
408 if (music
[0] == 0) music
= NULL
;
409 jam_doc_set_music(view
->doc
, music
);
413 location_add(JamView
*view
) {
414 view
->location
= gtk_entry_new();
415 view
->locationbar
= labelled_box_new_sg(_("_Location:"), view
->location
, view
->sizegroup
);
416 gtk_box_pack_start(GTK_BOX(view
), view
->locationbar
, FALSE
, FALSE
, 0);
417 gtk_box_reorder_child(GTK_BOX(view
), view
->locationbar
, view
->moodpicbar
? 2 : 1);
418 gtk_widget_show_all(view
->locationbar
);
421 location_remove(JamView
*view
) {
422 jam_doc_set_location(view
->doc
, NULL
);
423 gtk_widget_destroy(view
->locationbar
);
424 view
->locationbar
= view
->location
= NULL
;
427 location_visible(JamView
*view
) {
428 return view
->locationbar
!= NULL
;
431 location_load(JamView
*view
) {
432 const char *location
= jam_doc_get_location(view
->doc
);
434 show_meta(view
, JAM_VIEW_LOCATION
);
435 if (location_visible(view
))
436 gtk_entry_set_text(GTK_ENTRY(view
->location
), location
? location
: "");
439 location_store(JamView
*view
) {
440 const char *location
= gtk_entry_get_text(GTK_ENTRY(view
->location
));
441 if (location
[0] == 0) location
= NULL
;
442 jam_doc_set_location(view
->doc
, location
);
446 tags_add(JamView
*view
) {
447 view
->tags
= gtk_entry_new();
448 view
->tagsbar
= labelled_box_new_sg(_("_Tags:"), view
->tags
, view
->sizegroup
);
449 gtk_box_pack_start(GTK_BOX(view
), view
->tagsbar
, FALSE
, FALSE
, 0);
450 gtk_box_reorder_child(GTK_BOX(view
), view
->tagsbar
, view
->musicbar
? 2 : 1);
451 gtk_widget_show_all(view
->tagsbar
);
454 tags_remove(JamView
*view
) {
455 jam_doc_set_taglist(view
->doc
, NULL
);
456 gtk_widget_destroy(view
->tagsbar
);
457 view
->tagsbar
= view
->tags
= NULL
;
460 tags_visible(JamView
*view
) {
461 return view
->tagsbar
!= NULL
;
464 tags_load(JamView
*view
) {
465 const char *tags
= jam_doc_get_taglist(view
->doc
);
467 show_meta(view
, JAM_VIEW_TAGS
);
468 if (tags_visible(view
))
469 gtk_entry_set_text(GTK_ENTRY(view
->tags
), tags
? tags
: "");
472 tags_store(JamView
*view
) {
473 const char *tags
= gtk_entry_get_text(GTK_ENTRY(view
->tags
));
474 if (tags
[0] == 0) tags
= NULL
;
475 jam_doc_set_taglist(view
->doc
, tags
);
480 option_add(JamView
*view
) {
483 view
->optionbar
= gtk_hbox_new(FALSE
, 12);
484 gtk_box_pack_end(GTK_BOX(view
), view
->optionbar
, FALSE
, FALSE
, 0);
485 gtk_widget_show(view
->optionbar
);
488 option_remove(JamView
*view
) {
489 if (!view
->optionbar
)
491 if (view
->preformatted
|| view
->datesel
|| view
->commentsbox
|| view
->screeningbox
)
493 gtk_widget_destroy(view
->optionbar
);
494 view
->optionbar
= NULL
;
498 preformatted_add(JamView
*view
) {
500 view
->preformatted
= gtk_check_button_new_with_mnemonic(_("_Preformatted"));
501 gtk_box_pack_start(GTK_BOX(view
->optionbar
), view
->preformatted
, FALSE
, FALSE
, 0);
502 gtk_widget_show_all(view
->preformatted
);
505 preformatted_remove(JamView
*view
) {
506 jam_doc_set_preformatted(view
->doc
, FALSE
);
507 gtk_widget_destroy(view
->preformatted
);
508 view
->preformatted
= NULL
;
512 preformatted_visible(JamView
*view
) {
513 return view
->preformatted
!= NULL
;
516 preformatted_load(JamView
*view
) {
517 gboolean pre
= jam_doc_get_preformatted(view
->doc
);
519 show_meta(view
, JAM_VIEW_PREFORMATTED
);
520 if (preformatted_visible(view
))
521 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(view
->preformatted
),
525 preformatted_store(JamView
*view
) {
526 jam_doc_set_preformatted(view
->doc
,
527 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(view
->preformatted
)));
531 comments_add(JamView
*view
) {
532 GtkWidget
*menu
, *item
;
533 static const char * items
[] = {
541 view
->comments
= gtk_option_menu_new();
543 menu
= gtk_menu_new();
544 for (i
= 0; i
< sizeof(items
)/sizeof(char*); i
++) {
545 item
= gtk_menu_item_new_with_label(_(items
[i
]));
546 gtk_widget_show(item
);
547 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
549 gtk_option_menu_set_menu(GTK_OPTION_MENU(view
->comments
), menu
);
551 view
->commentsbox
= labelled_box_new(_("_Comments:"), view
->comments
);
552 gtk_box_pack_start(GTK_BOX(view
->optionbar
), view
->commentsbox
, FALSE
, FALSE
, 0);
553 gtk_widget_show_all(view
->commentsbox
);
556 comments_remove(JamView
*view
) {
557 jam_doc_set_comments(view
->doc
, LJ_COMMENTS_DEFAULT
);
558 gtk_widget_destroy(view
->commentsbox
);
559 view
->commentsbox
= view
->comments
= NULL
;
563 comments_visible(JamView
*view
) {
564 return view
->commentsbox
!= NULL
;
567 comments_load(JamView
*view
) {
568 LJCommentsType type
= jam_doc_get_comments(view
->doc
);
569 if (type
!= LJ_COMMENTS_DEFAULT
)
570 show_meta(view
, JAM_VIEW_COMMENTS
);
571 if (comments_visible(view
))
572 gtk_option_menu_set_history(GTK_OPTION_MENU(view
->comments
), type
);
575 comments_store(JamView
*view
) {
576 LJCommentsType type
= gtk_option_menu_get_history(GTK_OPTION_MENU(view
->comments
));
577 jam_doc_set_comments(view
->doc
, type
);
581 screening_add(JamView
*view
) {
582 GtkWidget
*menu
, *item
;
583 static const char * items
[] = {
586 N_("Anonymous Only"),
593 view
->screening
= gtk_option_menu_new();
595 menu
= gtk_menu_new();
596 for (i
= 0; i
< sizeof(items
)/sizeof(char*); i
++) {
597 item
= gtk_menu_item_new_with_label(_(items
[i
]));
598 gtk_widget_show(item
);
599 gtk_menu_shell_append(GTK_MENU_SHELL(menu
), item
);
601 gtk_option_menu_set_menu(GTK_OPTION_MENU(view
->screening
), menu
);
603 view
->screeningbox
= labelled_box_new(_("Scr_eening:"), view
->screening
);
604 gtk_box_pack_end(GTK_BOX(view
->optionbar
), view
->screeningbox
, FALSE
,FALSE
, 0);
605 gtk_widget_show_all(view
->screeningbox
);
608 screening_remove(JamView
*view
) {
609 jam_doc_set_screening(view
->doc
, LJ_SCREENING_DEFAULT
);
610 gtk_widget_destroy(view
->screeningbox
);
611 view
->screeningbox
= view
->screening
= NULL
;
615 screening_visible(JamView
*view
) {
616 return view
->screeningbox
!= NULL
;
619 screening_load(JamView
*view
) {
620 LJScreeningType type
= jam_doc_get_screening(view
->doc
);
621 if (type
!= LJ_SCREENING_DEFAULT
)
622 show_meta(view
, JAM_VIEW_SCREENING
);
623 if (screening_visible(view
))
624 gtk_option_menu_set_history(GTK_OPTION_MENU(view
->screening
), type
);
627 screening_store(JamView
*view
) {
628 LJCommentsType type
= gtk_option_menu_get_history(GTK_OPTION_MENU(view
->screening
));
629 jam_doc_set_screening(view
->doc
, type
);
636 /* standard for all. */
637 void (*add
)(JamView
*view
);
638 void (*remove
)(JamView
*view
);
639 gboolean (*visible
)(JamView
*view
);
641 void (*load
)(JamView
*view
);
642 void (*store
)(JamView
*view
);
644 /* only defined if it matters when the account changes. */
645 void (*account_changed
)(JamView
*view
);
647 /* these must match JamViewMeta in jamview.h. */
648 #define STD(x) x##_add, x##_remove, x##_visible, x##_load, x##_store
649 { "subject", TRUE
, NULL
, NULL
, NULL
, subject_load
, subject_store
, NULL
},
650 { "security", TRUE
, STD(security
), security_account_changed
},
651 { "mood", TRUE
, STD(mood
), mood_account_changed
},
652 { "picture", TRUE
, STD(picture
), picture_account_changed
},
653 { "music", TRUE
, STD(music
), NULL
},
654 { "location", TRUE
, STD(location
), NULL
},
655 { "tags", TRUE
, STD(tags
), NULL
},
656 { "preformatted", TRUE
, STD(preformatted
), NULL
},
657 { "datesel", TRUE
, STD(datesel
), NULL
},
658 { "comments", TRUE
, STD(comments
), NULL
},
659 { "screening", TRUE
, STD(screening
), NULL
},
664 jam_view_get_meta_visible(JamView
*view
, JamViewMeta meta
) {
665 if (!metas
[meta
].visible
) return TRUE
;
666 return metas
[meta
].visible(view
);
670 jam_view_toggle_meta(JamView
*view
, JamViewMeta meta
, gboolean show
) {
671 if (show
== metas
[meta
].visible(view
)) return;
672 if (show
) metas
[meta
].add(view
);
673 else metas
[meta
].remove(view
);
677 jam_view_meta_to_name(JamViewMeta meta
) {
678 return metas
[meta
].name
;
682 jam_view_meta_from_name(const char *name
, JamViewMeta
*meta
) {
684 for (i
= 0; i
<= JAM_VIEW_META_LAST
; i
++) {
685 if (strcmp(metas
[i
].name
, name
) == 0) {
694 jam_view_emit_conf(JamView
*view
) {
696 for (i
= JAM_VIEW_META_FIRST
; i
<= JAM_VIEW_META_LAST
; i
++)
697 g_signal_emit_by_name(view
, "meta_toggle", i
, metas
[i
].visible(view
));
701 jam_view_load_conf(JamView
*view
) {
703 for (meta
= JAM_VIEW_META_FIRST
; meta
<= JAM_VIEW_META_LAST
; meta
++) {
704 if (conf
.options
.showmeta
[meta
] && !metas
[meta
].visible(view
)) {
705 if (JAM_ACCOUNT_IS_LJ(view
->account
) || !metas
[meta
].lj_only
) {
706 jam_view_toggle_meta(view
, meta
, TRUE
);
707 g_signal_emit_by_name(view
, "meta_toggle", meta
, TRUE
);
709 } else if (!conf
.options
.showmeta
[meta
] && metas
[meta
].visible(view
)) {
710 jam_view_toggle_meta(view
, meta
, FALSE
);
711 g_signal_emit_by_name(view
, "meta_toggle", meta
, FALSE
);
717 jam_view_class_init(JamViewClass
*viewclass
) {
718 signals
[META_TOGGLE
] = g_signal_new("meta_toggle",
719 G_OBJECT_CLASS_TYPE(viewclass
),
721 G_STRUCT_OFFSET(JamViewClass
, meta_toggle
),
723 logjam_marshal_VOID__INT_BOOLEAN
,
724 G_TYPE_NONE
, 2, G_TYPE_INT
, G_TYPE_BOOLEAN
);
728 undo_cb(JamView
*view
) {
729 if (undomgr_can_undo(view
->undomgr
))
730 undomgr_undo(view
->undomgr
);
733 redo_cb(JamView
*view
) {
734 if (undomgr_can_redo(view
->undomgr
))
735 undomgr_redo(view
->undomgr
);
739 populate_entry_popup(GtkTextView
*text
, GtkMenu
*menu
, JamView
*view
) {
740 GtkWidget
*menu_item
;
742 g_return_if_fail(menu
!= NULL
);
743 g_return_if_fail(GTK_IS_MENU_SHELL(menu
));
745 menu_item
= gtk_separator_menu_item_new();
746 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), menu_item
);
747 gtk_widget_show(menu_item
);
749 menu_item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_REDO
, NULL
);
750 gtk_widget_set_sensitive(menu_item
,
751 undomgr_can_redo(view
->undomgr
));
752 g_signal_connect_swapped(G_OBJECT(menu_item
), "activate",
753 G_CALLBACK(redo_cb
), view
);
754 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), menu_item
);
755 gtk_widget_show(menu_item
);
757 menu_item
= gtk_image_menu_item_new_from_stock(GTK_STOCK_UNDO
, NULL
);
758 gtk_widget_set_sensitive(menu_item
,
759 undomgr_can_undo(view
->undomgr
));
760 g_signal_connect_swapped(G_OBJECT(menu_item
), "activate",
761 G_CALLBACK(undo_cb
), view
);
762 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu
), menu_item
);
763 gtk_widget_show(menu_item
);
767 jam_view_init(JamView
*view
) {
768 gtk_box_set_spacing(GTK_BOX(view
), 6);
770 view
->entry
= gtk_text_view_new();
771 view
->undomgr
= UNDOMGR(undomgr_new());
773 gtk_text_view_set_editable(GTK_TEXT_VIEW(view
->entry
), TRUE
);
774 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view
->entry
), GTK_WRAP_WORD
);
775 g_signal_connect(G_OBJECT(view
->entry
), "populate-popup",
776 G_CALLBACK(populate_entry_popup
), view
);
778 jam_widget_set_font(view
->entry
, conf
.uifont
);
780 undomgr_attach(UNDOMGR(view
->undomgr
), view
->entry
);
782 view
->sizegroup
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
785 jam_view_load_conf(view
);
786 gtk_box_pack_start(GTK_BOX(view
), scroll_wrap(view
->entry
),
791 jam_view_new(JamDoc
*doc
) {
792 JamView
*view
= JAM_VIEW(g_object_new(jam_view_get_type(), NULL
));
794 jam_view_set_doc(view
, doc
);
796 return GTK_WIDGET(view
);
800 jam_view_get_undomgr(JamView
*view
) {
801 return G_OBJECT(view
->undomgr
);
805 jam_view_account_changed(JamView
*view
) {
808 view
->account
= jam_doc_get_account(view
->doc
);
810 /* notify all visible meta views that the account
811 * has changed, and hide those that shouldn't be shown. */
812 for (i
= JAM_VIEW_META_FIRST
; i
<= JAM_VIEW_META_LAST
; i
++) {
813 if (!metas
[i
].visible(view
))
815 if (!JAM_ACCOUNT_IS_LJ(view
->account
) && metas
[i
].lj_only
) {
816 jam_view_toggle_meta(view
, i
, FALSE
);
818 if (metas
[i
].account_changed
&& metas
[i
].visible(view
))
819 metas
[i
].account_changed(view
);
825 jam_view_load_doc(JamView
*view
) {
827 /* if the current account type doesn't support some meta views,
828 * they should've already been hidden by _account_changed. */
829 for (i
= 0; i
< JAM_VIEW_META_COUNT
; i
++) {
830 if (!metas
[i
].lj_only
|| JAM_ACCOUNT_IS_LJ(view
->account
))
836 jam_view_store_doc(JamView
*view
) {
837 GtkTextBuffer
*buffer
;
838 GtkTextIter start
, end
;
842 for (i
= 0; i
< JAM_VIEW_META_COUNT
; i
++) {
843 if (jam_view_get_meta_visible(view
, i
)) {
845 metas
[i
].store(view
);
849 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(view
->entry
));
850 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
851 event
= gtk_text_buffer_get_text(buffer
, &start
, &end
, TRUE
);
853 jam_doc_set_event(view
->doc
, event
);
858 jam_view_set_doc(JamView
*view
, JamDoc
*doc
) {
861 undomgr_detach(view
->undomgr
, view
->entry
);
863 if (view
->account
!= jam_doc_get_account(doc
))
864 jam_view_account_changed(view
);
865 g_signal_connect_swapped(G_OBJECT(doc
), "notify::account",
866 G_CALLBACK(jam_view_account_changed
), view
);
867 g_signal_connect_swapped(G_OBJECT(doc
), "update_doc",
868 G_CALLBACK(jam_view_store_doc
), view
);
869 g_signal_connect_swapped(G_OBJECT(doc
), "entry_changed",
870 G_CALLBACK(jam_view_load_doc
), view
);
872 jam_view_load_conf(view
);
873 jam_view_load_doc(view
);
875 /* XXX: gtkspell gets confused if you detach its document,
876 * so we detach the spell checker completely, then reattach
879 if (conf
.options
.usespellcheck
&& view
->entry
) {
881 spell
= gtkspell_get_from_text_view(GTK_TEXT_VIEW(view
->entry
));
883 gtkspell_detach(spell
);
885 #endif /* HAVE_GTKSPELL */
887 gtk_text_view_set_buffer(GTK_TEXT_VIEW(view
->entry
),
888 jam_doc_get_text_buffer(doc
));
891 if (conf
.options
.usespellcheck
) {
893 if (gtkspell_new_attach(GTK_TEXT_VIEW(view
->entry
),
894 conf
.spell_language
, &err
) == NULL
) {
895 jam_warning(NULL
, // XXX GTK_WINDOW(view->jw),
896 _("GtkSpell error: %s"), err
->message
);
900 #endif /* HAVE_GTKSPELL */
902 undomgr_attach(view
->undomgr
, view
->entry
);
906 jam_view_settings_changed(JamView
*view
) {
910 if (conf
.options
.usespellcheck
!= hadspell
) {
912 if (conf
.options
.usespellcheck
) {
914 if (gtkspell_new_attach(GTK_TEXT_VIEW(fetcheentry(jw
)), conf
.spell_language
, &err
) == NULL
) {
915 jam_warning(GTK_WINDOW(jw
),
916 _("GtkSpell error: %s"), err
->message
);
917 conf
.options
.usespellcheck
= FALSE
;
921 spell
= gtkspell_get_from_text_view(GTK_TEXT_VIEW(fetcheentry(jw
)));
923 gtkspell_detach(spell
);
929 jam_widget_set_font(view
->entry
, conf
.uifont
);
931 if (view
->musicbar
) {
932 /* There are many cleaner ways to add/remove the Refresh button when
933 * the music preference has changed, but this works fine. */
940 jam_view_get_type(void) {
941 static GType new_type
= 0;
943 const GTypeInfo new_info
= {
944 sizeof(JamViewClass
),
947 (GClassInitFunc
) jam_view_class_init
,
952 (GInstanceInitFunc
) jam_view_init
,
954 new_type
= g_type_register_static(GTK_TYPE_VBOX
,
955 "JamView", &new_info
, 0);