removed libsoup support
[k8lowj.git] / src / offline.c
blob9b748196e5d5f2036b2fcc08c578b32a8220b907
1 /* logjam - a GTK client for LiveJournal.
2 * Copyright (C) 2000-2003 Evan Martin <evan@livejournal.com>
4 * vim: tabstop=4 shiftwidth=4 noexpandtab :
5 */
7 #include "gtk-all.h"
9 #include <string.h>
11 #include "util-gtk.h"
12 #ifdef HAVE_GTKHTML
13 #include "preview.h"
14 #endif
15 #include "journalstore.h"
16 #include "sync.h"
17 #include "spawn.h"
19 typedef struct {
20 GtkDialog dlg;
22 GtkWidget *cal, *searchentry, *searchcase;
23 GtkWidget *summary, *listbox, *list, *preview;
24 GdkPixbuf *pb_friends, *pb_private;
25 GtkListStore *store;
27 JournalStore *journalstore;
28 JamAccount *account;
30 int current_itemid; /* itemid of entry being previewed. useful to
31 pop back the calendar after some browsing */
32 } OfflineUI;
34 enum {
35 COL_ITEMID,
36 COL_DATE,
37 COL_SECURITY,
38 COL_SUMMARY
41 static GType offlineui_get_type(void);
42 #define OFFLINEUI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), offlineui_get_type(), OfflineUI))
44 //static const gint LJ_OFFLINE_JUMP_TO = 1;
45 #define LJ_OFFLINE_JUMP_TO 1
46 #define LJ_OFFLINE_COPY_URL 2
48 static void
49 update_marks(OfflineUI *oui) {
50 guint year, mon;
51 int day;
52 guint32 days;
54 gtk_calendar_get_date(GTK_CALENDAR(oui->cal), &year, &mon, NULL);
55 days = journal_store_get_month_entries(oui->journalstore, year, mon+1);
57 gtk_calendar_clear_marks(GTK_CALENDAR(oui->cal));
58 for (day = 1; day <= 31; day++) {
59 if (days & (1 << day))
60 gtk_calendar_mark_day(GTK_CALENDAR(oui->cal), day);
64 static void
65 month_changed_cb(GtkCalendar *calendar, OfflineUI *oui) {
66 update_marks(oui);
69 static void
70 get_entries_cb(int itemid, time_t etime, const char *summary, LJSecurity *sec, gpointer data) {
71 GtkTreeIter iter;
72 OfflineUI *oui = (OfflineUI*)data;
73 GdkPixbuf *pb;
75 switch (sec->type) {
76 case LJ_SECURITY_FRIENDS:
77 case LJ_SECURITY_CUSTOM:
78 pb = oui->pb_friends; break;
79 case LJ_SECURITY_PRIVATE:
80 pb = oui->pb_private; break;
81 default:
82 pb = NULL; /* public: no icon */
85 gtk_list_store_append(oui->store, &iter);
86 gtk_list_store_set(oui->store, &iter,
87 COL_ITEMID, itemid,
88 COL_DATE, etime,
89 COL_SECURITY, pb,
90 COL_SUMMARY, summary,
91 -1);
94 static void
95 load_day(OfflineUI *oui) {
96 guint year, mon, day;
97 gtk_calendar_get_date(GTK_CALENDAR(oui->cal), &year, &mon, &day);
98 if (oui->summary) {
99 gtk_widget_destroy(oui->summary);
100 oui->summary = NULL;
102 gtk_list_store_clear(oui->store);
103 journal_store_get_day_entries(oui->journalstore, year, mon+1, day,
104 get_entries_cb, oui);
107 static void
108 day_selected_cb(GtkCalendar *calendar, OfflineUI *oui) {
109 GtkTreeIter iter;
111 load_day(oui);
112 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(oui->store), &iter)) {
113 gtk_tree_selection_select_iter(
114 gtk_tree_view_get_selection(GTK_TREE_VIEW(oui->list)),
115 &iter);
119 static void
120 selection_changed_cb(GtkTreeSelection *ts, OfflineUI *oui) {
121 GtkTreeModel *model;
122 GtkTreeIter iter;
123 gboolean sensitive = gtk_tree_selection_get_selected(ts, &model, &iter);
125 gtk_dialog_set_response_sensitive(GTK_DIALOG(oui),
126 LJ_OFFLINE_JUMP_TO, sensitive);
127 gtk_dialog_set_response_sensitive(GTK_DIALOG(oui),
128 LJ_OFFLINE_COPY_URL, sensitive);
129 gtk_dialog_set_response_sensitive(GTK_DIALOG(oui),
130 GTK_RESPONSE_OK, sensitive);
133 static void
134 make_list(OfflineUI *oui) {
135 GtkCellRenderer *renderer;
136 GtkTreeViewColumn *column;
137 GtkTreeSelection *sel;
139 oui->store = gtk_list_store_new(4, G_TYPE_INT, G_TYPE_LONG, GDK_TYPE_PIXBUF, G_TYPE_STRING);
140 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(oui->store),
141 COL_DATE, GTK_SORT_ASCENDING);
142 oui->list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(oui->store));
143 g_object_unref(G_OBJECT(oui->store));
145 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(oui->list));
146 g_signal_connect(G_OBJECT(sel), "changed",
147 G_CALLBACK(selection_changed_cb), oui);
149 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(oui->list), FALSE);
151 column = gtk_tree_view_column_new();
152 gtk_tree_view_column_set_title(column, _("Summary"));
153 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
155 renderer = gtk_cell_renderer_pixbuf_new();
156 gtk_tree_view_column_pack_start(column, renderer, FALSE);
157 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", COL_SECURITY);
159 renderer = gtk_cell_renderer_text_new();
160 gtk_tree_view_column_pack_start(column, renderer, TRUE);
161 gtk_tree_view_column_add_attribute(column, renderer, "text", COL_SUMMARY);
163 gtk_tree_view_column_set_sort_column_id(column, COL_SUMMARY);
164 gtk_tree_view_append_column(GTK_TREE_VIEW(oui->list), column);
167 static int
168 get_selected_itemid(OfflineUI *oui) {
169 GtkTreeModel *model;
170 GtkTreeIter iter;
171 int itemid;
172 if (!gtk_tree_selection_get_selected(
173 gtk_tree_view_get_selection(GTK_TREE_VIEW(oui->list)),
174 &model, &iter))
175 return 0;
176 gtk_tree_model_get(model, &iter,
177 COL_ITEMID, &itemid,
178 -1);
179 return itemid;
182 static LJEntry*
183 load_selected(OfflineUI *oui) {
184 LJEntry *entry;
185 int itemid;
187 itemid = get_selected_itemid(oui);
188 if (!itemid)
189 return NULL;
190 entry = journal_store_get_entry(oui->journalstore, itemid);
191 if (!entry)
192 g_warning("unable to find entry %d\n", itemid);
193 return entry;
196 static void
197 select_entry(OfflineUI *oui, int itemid) {
198 time_t etime;
199 struct tm *etm;
200 guint year, mon, day;
201 GtkTreeIter iter;
202 GtkTreeModel *model = GTK_TREE_MODEL(oui->store);
203 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(oui->list));
204 int fitemid;
206 etime = journal_store_lookup_entry_time(oui->journalstore, itemid);
208 etm = gmtime(&etime);
209 gtk_calendar_get_date(GTK_CALENDAR(oui->cal), &year, &mon, &day);
211 gtk_calendar_freeze(GTK_CALENDAR(oui->cal));
212 g_signal_handlers_block_matched(oui->cal, G_SIGNAL_MATCH_DATA,
213 0, 0, NULL, NULL, oui);
215 /* the calendar gets confused in situations like switching into
216 * a 30-day month and have day 31 selected.
217 * so we move to the middle, switch months, and then move to the right place. */
218 if (day != etm->tm_mday)
219 gtk_calendar_select_day(GTK_CALENDAR(oui->cal), 15);
220 if (year != etm->tm_year+1900 || mon != etm->tm_mon)
221 gtk_calendar_select_month(GTK_CALENDAR(oui->cal),
222 etm->tm_mon, etm->tm_year+1900);
223 if (day != etm->tm_mday)
224 gtk_calendar_select_day(GTK_CALENDAR(oui->cal), etm->tm_mday);
226 if (day != etm->tm_mday)
227 load_day(oui);
228 if (year != etm->tm_year+1900 || mon != etm->tm_mon)
229 update_marks(oui);
231 g_signal_handlers_unblock_matched(oui->cal, G_SIGNAL_MATCH_DATA,
232 0, 0, NULL, NULL, oui);
233 gtk_calendar_thaw(GTK_CALENDAR(oui->cal));
235 if (gtk_tree_model_get_iter_first(model, &iter)) {
236 do {
237 gtk_tree_model_get(model, &iter, COL_ITEMID, &fitemid, -1);
238 if (fitemid == itemid) {
239 gtk_tree_selection_select_iter(sel, &iter);
240 break;
242 } while (gtk_tree_model_iter_next(model, &iter));
246 /* move the selection to the nearest next or previous item. The present
247 * selection need not be an actual entry. */
248 static void
249 move_relative(OfflineUI *oui, int dir) {
250 gboolean found = FALSE;
251 int itemid = get_selected_itemid(oui);
252 if (itemid) {
253 /* selection exists */
254 found = journal_store_find_relative(oui->journalstore, itemid, &itemid, dir, NULL);
255 } else {
256 /* some more cajoling necessary */
257 guint year, month, day;
258 struct tm when_tm = {0};
259 gtk_calendar_get_date(GTK_CALENDAR(oui->cal), &year, &month, &day);
260 when_tm.tm_year = year-1900;
261 when_tm.tm_mon = month;
262 when_tm.tm_mday = day;
263 found = journal_store_find_relative_by_time(oui->journalstore, lj_timegm(&when_tm), &itemid, dir, NULL);
265 if (found) select_entry(oui, itemid);
268 static void
269 prev_cb(GtkWidget *button, OfflineUI *oui) {
270 move_relative(oui, -1);
273 static void
274 next_cb(GtkWidget *button, OfflineUI *oui) {
275 move_relative(oui, 1);
278 static GtkWidget*
279 make_cal(OfflineUI *oui) {
280 GtkWidget *calbox, *bbox, *next, *prev;
282 calbox = gtk_vbox_new(FALSE, 6);
283 gtk_container_set_border_width(GTK_CONTAINER(calbox), 6);
285 oui->cal = gtk_calendar_new();
286 gtk_calendar_display_options(GTK_CALENDAR(oui->cal),
287 GTK_CALENDAR_SHOW_HEADING);
289 g_signal_connect(G_OBJECT(oui->cal), "month_changed",
290 G_CALLBACK(month_changed_cb), oui);
291 g_signal_connect(G_OBJECT(oui->cal), "day_selected",
292 G_CALLBACK(day_selected_cb), oui);
293 gtk_box_pack_start(GTK_BOX(calbox), oui->cal, FALSE, FALSE, 0);
295 bbox = gtk_hbutton_box_new();
296 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_EDGE);
297 gtk_box_set_spacing(GTK_BOX(bbox), 6);
298 prev = gtk_button_new_from_stock(GTK_STOCK_GO_BACK);
299 g_signal_connect(G_OBJECT(prev), "clicked",
300 G_CALLBACK(prev_cb), oui);
301 gtk_box_pack_start(GTK_BOX(bbox), prev, FALSE, FALSE, 0);
302 next = gtk_button_new_from_stock(GTK_STOCK_GO_FORWARD);
303 g_signal_connect(G_OBJECT(next), "clicked",
304 G_CALLBACK(next_cb), oui);
305 gtk_box_pack_start(GTK_BOX(bbox), next, FALSE, FALSE, 0);
307 gtk_box_pack_start(GTK_BOX(calbox), bbox, FALSE, FALSE, 0);
309 return calbox;
312 static gboolean
313 search_case_cb(const char *str, gpointer data) {
314 char *down;
315 gboolean ret;
316 if (!str) return FALSE;
317 down = g_utf8_strdown(str, -1);
318 ret = (strstr(down, data) != NULL);
319 g_free(down);
320 return ret;
323 static gboolean
324 search_cb(const char *str, gpointer data) {
325 return str && strstr(str, data) != NULL;
328 static void
329 find_cb(GtkWidget *button, OfflineUI *oui) {
330 const char *search;
331 char *summary;
333 search = gtk_entry_get_text(GTK_ENTRY(oui->searchentry));
335 gtk_list_store_clear(oui->store);
336 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oui->searchcase))) {
337 journal_store_scan(oui->journalstore,
338 search_cb, (gpointer)search,
339 get_entries_cb, oui);
340 } else {
341 char *lsearch = g_utf8_strdown(search, -1);
342 journal_store_scan(oui->journalstore,
343 search_case_cb, lsearch,
344 get_entries_cb, oui);
345 g_free(lsearch);
348 summary = g_strdup_printf(_("Search found %d entries:"),
349 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(oui->store), NULL));
350 if (!oui->summary) {
351 oui->summary = gtk_label_new(summary);
352 gtk_widget_show(oui->summary);
353 gtk_box_pack_start(GTK_BOX(oui->listbox), oui->summary,
354 FALSE, FALSE, 0);
355 } else {
356 gtk_label_set_text(GTK_LABEL(oui->summary), summary);
358 g_free(summary);
361 static GtkWidget*
362 make_search(OfflineUI *oui) {
363 GtkWidget *box, *l, *bbox, *button;
365 box = gtk_vbox_new(FALSE, 6);
366 gtk_container_set_border_width(GTK_CONTAINER(box), 6);
368 l = gtk_label_new_with_mnemonic(_("_Search:"));
369 gtk_misc_set_alignment(GTK_MISC(l), 0, 0.5);
370 gtk_box_pack_start(GTK_BOX(box), l, FALSE, FALSE, 0);
371 oui->searchentry = gtk_entry_new();
372 gtk_box_pack_start(GTK_BOX(box), oui->searchentry, FALSE, FALSE, 0);
373 gtk_label_set_mnemonic_widget(GTK_LABEL(l), oui->searchentry);
375 oui->searchcase = gtk_check_button_new_with_mnemonic(_("_Case sensitive"));
376 gtk_box_pack_start(GTK_BOX(box), oui->searchcase, FALSE, FALSE, 0);
378 bbox = gtk_hbutton_box_new();
379 gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
380 button = gtk_button_new_from_stock(GTK_STOCK_FIND);
381 g_signal_connect(G_OBJECT(button), "clicked",
382 G_CALLBACK(find_cb), oui);
383 g_signal_connect(G_OBJECT(oui->searchentry), "activate",
384 G_CALLBACK(find_cb), oui);
385 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
386 gtk_box_pack_start(GTK_BOX(box), bbox, FALSE, FALSE, 0);
388 return box;
391 static gboolean
392 check_entries(GtkWindow *parent, JamAccount *acc) {
393 GtkWidget *dlg;
394 int res;
396 dlg = gtk_message_dialog_new(parent, GTK_DIALOG_MODAL,
397 GTK_MESSAGE_INFO, GTK_BUTTONS_NONE,
398 _("LogJam has no offline entries for this journal. "
399 "You must first synchronize this journal to your local "
400 "storage before you can load entries from it."));
401 gtk_dialog_add_buttons(GTK_DIALOG(dlg),
402 _("_Synchronize"), GTK_RESPONSE_OK,
403 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
404 NULL);
405 res = gtk_dialog_run(GTK_DIALOG(dlg));
406 gtk_widget_destroy(dlg);
407 if (res == GTK_RESPONSE_OK)
408 return sync_run(JAM_ACCOUNT_LJ(acc), parent);
409 return FALSE;
412 #ifndef HAVE_GTKHTML
413 static void
414 content_update(OfflineUI *oui) {
415 LJEntry *entry;
416 GtkTextBuffer *buffer;
417 GtkTextIter start, end;
419 entry = load_selected(oui);
420 if (!entry)
421 return;
422 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(oui->preview));
423 gtk_text_buffer_get_bounds(buffer, &start, &end);
424 gtk_text_buffer_delete(buffer, &start, &end);
425 gtk_text_buffer_insert_at_cursor(buffer,
426 "(Note: this is not a real HTML preview because LogJam "
427 "was compiled without HTML support. This widget is in "
428 "here as a placeholder until we figure out what to put "
429 "here.)\n\n", -1);
430 gtk_text_buffer_insert_at_cursor(buffer, entry->event, -1);
432 lj_entry_free(entry);
434 #endif
436 static void
437 offlineui_init(GTypeInstance *instance, gpointer g_class) {
438 OfflineUI *oui = OFFLINEUI(instance);
439 GtkWidget *hbox, *vbox, *nb, *copy;
440 GtkTreeSelection *sel;
442 oui->pb_friends = gtk_widget_render_icon(GTK_WIDGET(oui),
443 "logjam-protected", GTK_ICON_SIZE_MENU, NULL);
444 oui->pb_private = gtk_widget_render_icon(GTK_WIDGET(oui),
445 "logjam-private", GTK_ICON_SIZE_MENU, NULL);
447 gtk_window_set_default_size(GTK_WINDOW(oui), 400, 500);
448 gtk_window_set_title(GTK_WINDOW(oui), _("Select Offline Entry"));
450 vbox = gtk_vbox_new(FALSE, 6);
451 hbox = gtk_hbox_new(FALSE, 6);
453 nb = gtk_notebook_new();
454 gtk_notebook_append_page(GTK_NOTEBOOK(nb), make_cal(oui),
455 gtk_label_new(_("Select by Date")));
456 gtk_notebook_append_page(GTK_NOTEBOOK(nb), make_search(oui),
457 gtk_label_new(_("Select by Search")));
459 gtk_box_pack_start(GTK_BOX(hbox), nb, FALSE, FALSE, 0);
461 make_list(oui);
462 oui->listbox = gtk_vbox_new(FALSE, 6);
463 gtk_box_pack_end(GTK_BOX(oui->listbox), scroll_wrap(oui->list),
464 TRUE, TRUE, 0);
465 gtk_box_pack_start(GTK_BOX(hbox), oui->listbox, TRUE, TRUE, 0);
467 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
469 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(oui->list));
470 #ifdef HAVE_GTKHTML
471 oui->preview = html_preview_new((GetEntryFunc)load_selected, oui);
472 gtk_box_pack_start(GTK_BOX(vbox), scroll_wrap(oui->preview), TRUE, TRUE, 0);
473 g_signal_connect_swapped(G_OBJECT(sel), "changed",
474 G_CALLBACK(preview_update), oui->preview);
475 #else
476 oui->preview = gtk_text_view_new();
477 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(oui->preview), GTK_WRAP_WORD);
478 gtk_text_view_set_editable(GTK_TEXT_VIEW(oui->preview), FALSE);
479 gtk_box_pack_start(GTK_BOX(vbox), scroll_wrap(oui->preview), TRUE, TRUE, 0);
480 g_signal_connect_swapped(G_OBJECT(sel), "changed",
481 G_CALLBACK(content_update), oui);
482 #endif
484 gtk_widget_show_all(vbox);
485 jam_dialog_set_contents(GTK_DIALOG(oui), vbox);
487 copy = gtk_button_new_from_stock(GTK_STOCK_COPY);
488 gtk_tooltips_set_tip(app.tooltips, copy,
489 _("Copy online entry URL to clipboard"),
490 _("Clicking here will place the URL of the entry currently "
491 "being previewed in your clipboard, so you can link to it."));
492 gtk_dialog_add_action_widget(GTK_DIALOG(oui),
493 copy, LJ_OFFLINE_COPY_URL);
494 gtk_widget_show(copy);
496 gtk_dialog_add_buttons(GTK_DIALOG(oui),
497 GTK_STOCK_JUMP_TO, LJ_OFFLINE_JUMP_TO,
498 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
499 GTK_STOCK_OK, GTK_RESPONSE_OK,
500 NULL);
501 /* let the selection-changed watcher update the button sensitivities. */
502 selection_changed_cb(gtk_tree_view_get_selection(GTK_TREE_VIEW(oui->list)),
503 oui);
504 geometry_tie(GTK_WIDGET(oui), GEOM_OFFLINE);
507 static void
508 offlineui_finalize(GObject *object) {
509 GObjectClass *parent_class;
510 OfflineUI *oui = OFFLINEUI(object);
512 journal_store_free(oui->journalstore);
513 g_object_unref(oui->pb_friends);
514 g_object_unref(oui->pb_private);
516 parent_class = g_type_class_peek_parent(G_OBJECT_GET_CLASS(object));
517 parent_class->finalize(object);
520 static void
521 offlineui_class_init(gpointer klass, gpointer class_data) {
522 GObjectClass *gclass = G_OBJECT_CLASS(klass);
524 gclass->finalize = offlineui_finalize;
527 static GType
528 offlineui_get_type(void) {
529 static GType new_type = 0;
530 if (!new_type) {
531 const GTypeInfo new_info = {
532 sizeof(GtkDialogClass),
533 NULL,
534 NULL,
535 (GClassInitFunc) offlineui_class_init,
536 NULL,
537 NULL,
538 sizeof(OfflineUI),
540 offlineui_init
542 new_type = g_type_register_static(GTK_TYPE_DIALOG,
543 "OfflineUI", &new_info, 0);
545 return new_type;
548 static GtkWidget*
549 offlineui_new(void) {
550 return GTK_WIDGET(g_object_new(offlineui_get_type(), NULL));
553 static gchar*
554 offline_current_entry_link(OfflineUI *oui) {
555 /*gint itemid, anum;*/
556 gchar *url;
557 JamAccount *acc = oui->account;
558 LJEntry *e = load_selected(oui);
560 if (e == NULL)
561 return NULL;
563 if (! JAM_ACCOUNT_IS_LJ(acc))
564 return NULL; // XXX: warning?
566 /* XXX: until 1721 closes
567 itemid = lj_entry_get_itemid(e);
568 anum = lj_entry_get_anum(e);
570 url = g_strdup_printf("%s/users/%s/%d.html",
571 jam_account_lj_get_server(acc)->url,
572 jam_account_lj_get_user(acc)->username,
573 itemid * 256 + anum); */
574 { // XXX: 1721
575 struct tm time;
576 lj_entry_get_time(e, &time);
577 url = g_strdup_printf("%s/users/%s/%04d/%02d/%02d/",
578 jam_account_lj_get_server(JAM_ACCOUNT_LJ(acc))->url,
579 jam_account_lj_get_user(JAM_ACCOUNT_LJ(acc))->username,
580 time.tm_year + 1900,
581 time.tm_mon + 1,
582 time.tm_mday);
585 return url;
588 static void
589 offline_jump_to_online(OfflineUI *oui) {
590 gchar *url = offline_current_entry_link(oui);
591 spawn_url(GTK_WINDOW(oui), url);
592 g_free(url);
595 static void
596 offline_copy_link(OfflineUI *oui) {
597 gchar *url = offline_current_entry_link(oui);
598 if (url && *url != '\0')
599 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
600 url, -1 /* determine length automatically */);
601 g_free(url);
604 LJEntry*
605 offline_dlg_run(GtkWindow *parent, JamAccount *acc) {
606 JournalStore *js = NULL;
607 GtkWidget *oui;
608 LJEntry *entry = NULL;
609 gboolean run = TRUE;
611 while (js == NULL) {
612 js = journal_store_open(acc, FALSE, NULL);
613 if (js == NULL)
614 if (!check_entries(parent, acc))
615 return NULL;
618 oui = offlineui_new();
619 OFFLINEUI(oui)->journalstore = js;
620 OFFLINEUI(oui)->account = acc;
621 month_changed_cb(GTK_CALENDAR(OFFLINEUI(oui)->cal), OFFLINEUI(oui));
622 day_selected_cb (GTK_CALENDAR(OFFLINEUI(oui)->cal), OFFLINEUI(oui));
623 gtk_window_set_transient_for(GTK_WINDOW(oui), parent);
625 while (run) {
626 switch (gtk_dialog_run(GTK_DIALOG(oui))) {
627 case LJ_OFFLINE_COPY_URL:
628 offline_copy_link(OFFLINEUI(oui));
629 break;
630 case LJ_OFFLINE_JUMP_TO:
631 offline_jump_to_online(OFFLINEUI(oui));
632 break;
633 case GTK_RESPONSE_OK:
634 entry = load_selected(OFFLINEUI(oui));
635 /* fallthrough */
636 default:
637 run = FALSE;
641 gtk_widget_destroy(oui);
643 return entry;