1 /*
2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2004-2015 the Claws Mail team
4 * Copyright (C) 2014-2015 Charles Lehner
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #include "claws-features.h"
24 #endif
25
26 #include <gtk/gtk.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29
30 #include "defs.h"
31 #include "gtk/gtkutils.h"
32 #include "gtk/combobox.h"
33 #include "gtk/manage_window.h"
34 #include "alertpanel.h"
35 #include "undo.h"
36 #include "menu.h"
37 #include "utils.h"
38 #include "prefs.h"
39 #include "prefs_common.h"
40 #include "account.h"
41 #include "mainwindow.h"
42 #include "message_search.h"
43 #include "managesieve.h"
44 #include "sieve_manager.h"
45 #include "sieve_editor.h"
46
47 GSList *editors = NULL;
48
49 static void sieve_editor_destroy(SieveEditorPage *page);
50
51 void sieve_editor_set_position(void *obj, gint pos);
52 gboolean sieve_editor_search_string(void *obj,
53 const gchar *str, gboolean case_sens);
54 gboolean sieve_editor_search_string_backward(void *obj,
55 const gchar *str, gboolean case_sens);
56 static void sieve_editor_save_cb(GtkAction *action, SieveEditorPage *page);
57 static void sieve_editor_check_cb(GtkAction *action, SieveEditorPage *page);
58 static void sieve_editor_changed_cb(GtkTextBuffer *, SieveEditorPage *page);
59 static void sieve_editor_revert_cb(GtkAction *action, SieveEditorPage *page);
60 static void sieve_editor_close_cb(GtkAction *action, SieveEditorPage *page);
61 static void sieve_editor_undo_cb(GtkAction *action, SieveEditorPage *page);
62 static void sieve_editor_redo_cb(GtkAction *action, SieveEditorPage *page);
63 static void sieve_editor_cut_cb(GtkAction *action, SieveEditorPage *page);
64 static void sieve_editor_copy_cb(GtkAction *action, SieveEditorPage *page);
65 static void sieve_editor_paste_cb(GtkAction *action, SieveEditorPage *page);
66 static void sieve_editor_allsel_cb(GtkAction *action, SieveEditorPage *page);
67 static void sieve_editor_find_cb(GtkAction *action, SieveEditorPage *page);
68 static void sieve_editor_set_modified(SieveEditorPage *page,
69 gboolean modified);
70
71 static SearchInterface search_interface = {
72 .set_position = sieve_editor_set_position,
73 .search_string_backward = sieve_editor_search_string_backward,
74 .search_string = sieve_editor_search_string,
75 };
76
77 static GtkActionEntry sieve_editor_entries[] =
78 {
79 {"Menu", NULL, "Menu", NULL, NULL, NULL },
80 /* menus */
81 {"Filter", NULL, N_("_Filter"), NULL, NULL, NULL },
82 {"Edit", NULL, N_("_Edit"), NULL, NULL, NULL },
83 /* Filter menu */
84
85 {"Filter/Save", NULL, N_("_Save"), "<control>S", NULL, G_CALLBACK(sieve_editor_save_cb) },
86 {"Filter/CheckSyntax", NULL, N_("Chec_k Syntax"), "<control>K", NULL, G_CALLBACK(sieve_editor_check_cb) },
87 {"Filter/Revert", NULL, N_("Re_vert"), NULL, NULL, G_CALLBACK(sieve_editor_revert_cb) },
88 {"Filter/Close", NULL, N_("_Close"), "<control>W", NULL, G_CALLBACK(sieve_editor_close_cb) },
89
90 /* Edit menu */
91 {"Edit/Undo", NULL, N_("_Undo"), "<control>Z", NULL, G_CALLBACK(sieve_editor_undo_cb) },
92 {"Edit/Redo", NULL, N_("_Redo"), "<control>Y", NULL, G_CALLBACK(sieve_editor_redo_cb) },
93 /* {"Edit/---", NULL, "---", NULL, NULL, NULL }, */
94
95 {"Edit/Cut", NULL, N_("Cu_t"), "<control>X", NULL, G_CALLBACK(sieve_editor_cut_cb) },
96 {"Edit/Copy", NULL, N_("_Copy"), "<control>C", NULL, G_CALLBACK(sieve_editor_copy_cb) },
97 {"Edit/Paste", NULL, N_("_Paste"), "<control>V", NULL, G_CALLBACK(sieve_editor_paste_cb) },
98
99 {"Edit/SelectAll", NULL, N_("Select _all"), "<control>A", NULL, G_CALLBACK(sieve_editor_allsel_cb) },
100
101 {"Edit/---", NULL, "---", NULL, NULL, NULL },
102 {"Edit/Find", NULL, N_("_Find"), "<control>F", NULL, G_CALLBACK(sieve_editor_find_cb) },
103 };
104
105
sieve_editors_close()106 void sieve_editors_close()
107 {
108 if (editors) {
109 GSList *list = editors;
110 editors = NULL;
111 g_slist_free_full(list, (GDestroyNotify)sieve_editor_close);
112 }
113 }
114
sieve_editor_append_text(SieveEditorPage * page,gchar * text,gint len)115 void sieve_editor_append_text(SieveEditorPage *page, gchar *text, gint len)
116 {
117 GtkTextBuffer *buffer;
118 GtkTextIter iter;
119
120 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
121
122 g_signal_handlers_block_by_func(G_OBJECT(buffer),
123 G_CALLBACK(sieve_editor_changed_cb), page);
124
125 undo_block(page->undostruct);
126 gtk_text_buffer_get_end_iter(buffer, &iter);
127 gtk_text_buffer_insert(buffer, &iter, text, len);
128 undo_unblock(page->undostruct);
129
130 g_signal_handlers_unblock_by_func(G_OBJECT(buffer),
131 G_CALLBACK(sieve_editor_changed_cb), page);
132 }
133
sieve_editor_get_text(SieveEditorPage * page,gchar ** text)134 static gint sieve_editor_get_text(SieveEditorPage *page, gchar **text)
135 {
136 GtkTextBuffer *buffer;
137 GtkTextIter start, end;
138
139 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
140 gtk_text_buffer_get_start_iter(buffer, &start);
141 gtk_text_buffer_get_end_iter(buffer, &end);
142 *text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE);
143 /* return length in bytes */
144 return strlen(*text);
145 }
146
sieve_editor_set_status(SieveEditorPage * page,const gchar * status)147 static void sieve_editor_set_status(SieveEditorPage *page, const gchar *status)
148 {
149 gtk_label_set_text(GTK_LABEL(page->status_text), status);
150 }
151
sieve_editor_set_status_icon(SieveEditorPage * page,const gchar * img_id)152 static void sieve_editor_set_status_icon(SieveEditorPage *page, const gchar *img_id)
153 {
154 GtkImage *img = GTK_IMAGE(page->status_icon);
155 if (img_id)
156 gtk_image_set_from_stock(img, img_id, GTK_ICON_SIZE_BUTTON);
157 else
158 gtk_image_clear(img);
159 }
160
sieve_editor_append_status(SieveEditorPage * page,const gchar * new_status)161 static void sieve_editor_append_status(SieveEditorPage *page,
162 const gchar *new_status)
163 {
164 GtkLabel *label = GTK_LABEL(page->status_text);
165 const gchar *prev_status = gtk_label_get_text(label);
166 const gchar *sep = prev_status && prev_status[0] ? "\n" : "";
167 gchar *status = g_strconcat(prev_status, sep, new_status, NULL);
168 gtk_label_set_text(label, status);
169 g_free(status);
170 }
171
172 /* Update the status icon and text from a response. */
sieve_editor_update_status(SieveEditorPage * page,SieveResult * result)173 static void sieve_editor_update_status(SieveEditorPage *page,
174 SieveResult *result)
175 {
176 if (result->has_status) {
177 /* set status icon */
178 sieve_editor_set_status_icon(page,
179 result->success ? GTK_STOCK_DIALOG_INFO : GTK_STOCK_DIALOG_ERROR);
180 /* clear status text */
181 sieve_editor_set_status(page, "");
182 }
183 if (result->description) {
184 /* append to status */
185 sieve_editor_append_status(page, result->description);
186 }
187 }
188
189 /* Edit Menu */
190
sieve_editor_undo_cb(GtkAction * action,SieveEditorPage * page)191 static void sieve_editor_undo_cb(GtkAction *action, SieveEditorPage *page)
192 {
193 undo_undo(page->undostruct);
194 }
195
sieve_editor_redo_cb(GtkAction * action,SieveEditorPage * page)196 static void sieve_editor_redo_cb(GtkAction *action, SieveEditorPage *page)
197 {
198 undo_redo(page->undostruct);
199 }
200
sieve_editor_cut_cb(GtkAction * action,SieveEditorPage * page)201 static void sieve_editor_cut_cb(GtkAction *action, SieveEditorPage *page)
202 {
203 GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
204 GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
205 gtk_text_buffer_cut_clipboard(buf, clipboard, TRUE);
206 }
207
sieve_editor_copy_cb(GtkAction * action,SieveEditorPage * page)208 static void sieve_editor_copy_cb(GtkAction *action, SieveEditorPage *page)
209 {
210 GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
211 GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
212 gtk_text_buffer_copy_clipboard(buf, clipboard);
213 }
214
sieve_editor_paste_cb(GtkAction * action,SieveEditorPage * page)215 static void sieve_editor_paste_cb(GtkAction *action, SieveEditorPage *page)
216 {
217 if (!gtk_widget_has_focus(page->text))
218 return;
219
220 GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
221 GtkClipboard *clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
222 gchar *contents = gtk_clipboard_wait_for_text(clipboard);
223 GtkTextMark *start_mark = gtk_text_buffer_get_insert(buf);
224 GtkTextIter start_iter;
225
226 undo_paste_clipboard(GTK_TEXT_VIEW(page->text), page->undostruct);
227 gtk_text_buffer_delete_selection(buf, FALSE, TRUE);
228
229 gtk_text_buffer_get_iter_at_mark(buf, &start_iter, start_mark);
230 gtk_text_buffer_insert(buf, &start_iter, contents, strlen(contents));
231 }
232
233
sieve_editor_allsel_cb(GtkAction * action,SieveEditorPage * page)234 static void sieve_editor_allsel_cb(GtkAction *action, SieveEditorPage *page)
235 {
236 GtkTextIter start, end;
237 GtkTextBuffer *buffer;
238
239 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
240 gtk_text_buffer_get_start_iter(buffer, &start);
241 gtk_text_buffer_get_end_iter(buffer, &end);
242 gtk_text_buffer_select_range(buffer, &start, &end);
243 }
244
245 /* Search */
246
sieve_editor_set_position(void * obj,gint pos)247 void sieve_editor_set_position(void *obj, gint pos)
248 {
249 SieveEditorPage *page = (SieveEditorPage *)obj;
250 GtkTextView *text = GTK_TEXT_VIEW(page->text);
251
252 gtkut_text_view_set_position(text, pos);
253 }
254
sieve_editor_search_string(void * obj,const gchar * str,gboolean case_sens)255 gboolean sieve_editor_search_string(void *obj,
256 const gchar *str, gboolean case_sens)
257 {
258 SieveEditorPage *page = (SieveEditorPage *)obj;
259 GtkTextView *text = GTK_TEXT_VIEW(page->text);
260
261 return gtkut_text_view_search_string(text, str, case_sens);
262 }
263
sieve_editor_search_string_backward(void * obj,const gchar * str,gboolean case_sens)264 gboolean sieve_editor_search_string_backward(void *obj,
265 const gchar *str, gboolean case_sens)
266 {
267 SieveEditorPage *page = (SieveEditorPage *)obj;
268 GtkTextView *text = GTK_TEXT_VIEW(page->text);
269
270 return gtkut_text_view_search_string_backward(text, str, case_sens);
271 }
272
sieve_editor_search(SieveEditorPage * page)273 static void sieve_editor_search(SieveEditorPage *page)
274 {
275 message_search_other(&search_interface, page);
276 }
277
278 /* Actions */
279
got_data_reverting(SieveSession * session,gboolean abort,gchar * contents,SieveEditorPage * page)280 static void got_data_reverting(SieveSession *session, gboolean abort,
281 gchar *contents,
282 SieveEditorPage *page)
283 {
284 if (abort)
285 return;
286 if (contents == NULL) {
287 /* end of data */
288 undo_unblock(page->undostruct);
289 gtk_widget_set_sensitive(page->text, TRUE);
290 sieve_editor_set_status(page, "");
291 sieve_editor_set_modified(page, FALSE);
292 return;
293 }
294 if (contents == (void *)-1) {
295 /* error */
296 sieve_editor_set_status(page, _("Unable to get script contents"));
297 sieve_editor_set_status_icon(page, GTK_STOCK_DIALOG_ERROR);
298 return;
299 }
300
301 if (page->first_line) {
302 GtkTextIter start, end;
303 GtkTextBuffer *buffer;
304
305 page->first_line = FALSE;
306
307 /* delete previous data */
308 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text));
309 gtk_text_buffer_get_start_iter(buffer, &start);
310 gtk_text_buffer_get_end_iter(buffer, &end);
311 gtk_text_buffer_delete(buffer, &start, &end);
312
313 /* append data */
314 gtk_text_buffer_insert(buffer, &end, contents, strlen(contents));
315 } else {
316 sieve_editor_append_text(page, contents, strlen(contents));
317 }
318 }
319
sieve_editor_revert(SieveEditorPage * page)320 static void sieve_editor_revert(SieveEditorPage *page)
321 {
322 undo_block(page->undostruct);
323 page->first_line = TRUE;
324 gtk_widget_set_sensitive(page->text, FALSE);
325 sieve_editor_set_status(page, _("Reverting..."));
326 sieve_editor_set_status_icon(page, NULL);
327 sieve_session_get_script(page->session, page->script_name,
328 (sieve_session_data_cb_fn)got_data_reverting, page);
329 }
330
sieve_editor_revert_cb(GtkAction * action,SieveEditorPage * page)331 static void sieve_editor_revert_cb(GtkAction *action, SieveEditorPage *page)
332 {
333 if (!page->modified ||
334 alertpanel(_("Revert script"),
335 _("This script has been modified. Revert the unsaved changes?"),
336 _("_Revert"), NULL, GTK_STOCK_CANCEL, ALERTFOCUS_FIRST) == G_ALERTDEFAULT)
337 sieve_editor_revert(page);
338 }
339
got_data_saved(SieveSession * session,gboolean abort,SieveResult * result,SieveEditorPage * page)340 static void got_data_saved(SieveSession *session, gboolean abort,
341 SieveResult *result, SieveEditorPage *page)
342 {
343 if (abort)
344 return;
345 if (result->has_status && result->success) {
346 sieve_editor_set_modified(page, FALSE);
347 if (page->closing) {
348 sieve_editor_close(page);
349 return;
350 }
351 /* use nice status message if there are no warnings */
352 if (result->code == SIEVE_CODE_NONE) {
353 result->description = _("Script saved successfully.");
354 }
355
356 if (page->is_new) {
357 /* notify manager windows of newly created script */
358 page->is_new = FALSE;
359 sieve_manager_script_created(session,
360 page->script_name);
361 }
362 }
363 sieve_editor_update_status(page, result);
364 }
365
sieve_editor_save(SieveEditorPage * page)366 static void sieve_editor_save(SieveEditorPage *page)
367 {
368 gchar *text;
369 gint len = sieve_editor_get_text(page, &text);
370 sieve_editor_set_status(page, _("Saving..."));
371 sieve_editor_set_status_icon(page, NULL);
372 sieve_session_put_script(page->session, page->script_name, len, text,
373 (sieve_session_data_cb_fn)got_data_saved, page);
374 g_free(text);
375 }
376
sieve_editor_save_cb(GtkAction * action,SieveEditorPage * page)377 static void sieve_editor_save_cb(GtkAction *action, SieveEditorPage *page)
378 {
379 sieve_editor_save(page);
380 }
381
sieve_editor_find_cb(GtkAction * action,SieveEditorPage * page)382 static void sieve_editor_find_cb(GtkAction *action, SieveEditorPage *page)
383 {
384 sieve_editor_search(page);
385 }
386
got_data_checked(SieveSession * session,gboolean abort,SieveResult * result,SieveEditorPage * page)387 static void got_data_checked(SieveSession *session, gboolean abort,
388 SieveResult *result, SieveEditorPage *page)
389 {
390 if (abort)
391 return;
392 sieve_editor_update_status(page, result);
393 }
394
sieve_editor_check_cb(GtkAction * action,SieveEditorPage * page)395 static void sieve_editor_check_cb(GtkAction *action, SieveEditorPage *page)
396 {
397 gchar *text;
398 gint len = sieve_editor_get_text(page, &text);
399 sieve_editor_set_status(page, _("Checking syntax..."));
400 sieve_editor_set_status_icon(page, NULL);
401 sieve_session_check_script(page->session, len, text,
402 (sieve_session_data_cb_fn)got_data_checked, page);
403 g_free(text);
404 }
405
sieve_editor_changed_cb(GtkTextBuffer * textbuf,SieveEditorPage * page)406 static void sieve_editor_changed_cb(GtkTextBuffer *textbuf,
407 SieveEditorPage *page)
408 {
409 if (!page->modified) {
410 sieve_editor_set_modified(page, TRUE);
411 }
412 }
413
sieve_editor_destroy(SieveEditorPage * page)414 static void sieve_editor_destroy(SieveEditorPage *page)
415 {
416 gtk_widget_destroy(page->window);
417 undo_destroy(page->undostruct);
418 g_free(page->script_name);
419 g_free(page);
420 }
421
sieve_editor_close(SieveEditorPage * page)422 void sieve_editor_close(SieveEditorPage *page)
423 {
424 editors = g_slist_remove(editors, (gconstpointer)page);
425 sieve_editor_destroy(page);
426 sieve_sessions_discard_callbacks(page);
427 }
428
sieve_editor_confirm_close(SieveEditorPage * page)429 static gboolean sieve_editor_confirm_close(SieveEditorPage *page)
430 {
431 if (page->modified) {
432 switch (alertpanel(_("Save changes"),
433 _("This script has been modified. Save the latest changes?"),
434 _("_Discard"), _("_Save"), GTK_STOCK_CANCEL,
435 ALERTFOCUS_SECOND)) {
436 case G_ALERTDEFAULT:
437 return TRUE;
438 case G_ALERTALTERNATE:
439 page->closing = TRUE;
440 sieve_editor_save(page);
441 return FALSE;
442 default:
443 return FALSE;
444 }
445 }
446 return TRUE;
447 }
448
sieve_editor_close_cb(GtkAction * action,SieveEditorPage * page)449 static void sieve_editor_close_cb(GtkAction *action, SieveEditorPage *page)
450 {
451 if (sieve_editor_confirm_close(page)) {
452 sieve_editor_close(page);
453 }
454 }
455
sieve_editor_delete_cb(GtkWidget * widget,GdkEventAny * event,SieveEditorPage * page)456 static gint sieve_editor_delete_cb(GtkWidget *widget, GdkEventAny *event,
457 SieveEditorPage *page)
458 {
459 sieve_editor_close_cb(NULL, page);
460 return TRUE;
461 }
462
463 /**
464 * sieve_editor_undo_state_changed:
465 *
466 * Change the sensivity of the menuentries undo and redo
467 **/
sieve_editor_undo_state_changed(UndoMain * undostruct,gint undo_state,gint redo_state,gpointer data)468 static void sieve_editor_undo_state_changed(UndoMain *undostruct,
469 gint undo_state, gint redo_state, gpointer data)
470 {
471 SieveEditorPage *page = (SieveEditorPage *)data;
472
473 switch (undo_state) {
474 case UNDO_STATE_TRUE:
475 if (!undostruct->undo_state) {
476 undostruct->undo_state = TRUE;
477 cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Undo", TRUE);
478 }
479 break;
480 case UNDO_STATE_FALSE:
481 if (undostruct->undo_state) {
482 undostruct->undo_state = FALSE;
483 cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Undo", FALSE);
484 }
485 break;
486 case UNDO_STATE_UNCHANGED:
487 break;
488 case UNDO_STATE_REFRESH:
489 cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Undo", undostruct->undo_state);
490 break;
491 default:
492 g_warning("Undo state not recognized");
493 break;
494 }
495
496 switch (redo_state) {
497 case UNDO_STATE_TRUE:
498 if (!undostruct->redo_state) {
499 undostruct->redo_state = TRUE;
500 cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Redo", TRUE);
501 }
502 break;
503 case UNDO_STATE_FALSE:
504 if (undostruct->redo_state) {
505 undostruct->redo_state = FALSE;
506 cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Redo", FALSE);
507 }
508 break;
509 case UNDO_STATE_UNCHANGED:
510 break;
511 case UNDO_STATE_REFRESH:
512 cm_menu_set_sensitive_full(page->ui_manager, "Menu/Edit/Redo", undostruct->redo_state);
513 break;
514 default:
515 g_warning("Redo state not recognized");
516 break;
517 }
518 }
519
520
sieve_editor_new(SieveSession * session,gchar * script_name)521 SieveEditorPage *sieve_editor_new(SieveSession *session, gchar *script_name)
522 {
523 SieveEditorPage *page;
524 GtkUIManager *ui_manager;
525 UndoMain *undostruct;
526 GtkWidget *window;
527 GtkWidget *menubar;
528 GtkWidget *vbox, *hbox, *hbox1;
529 GtkWidget *scrolledwin;
530 GtkWidget *text;
531 GtkTextBuffer *buffer;
532 GtkWidget *check_btn, *save_btn, *close_btn;
533 GtkWidget *status_text;
534 GtkWidget *status_icon;
535
536 page = g_new0(SieveEditorPage, 1);
537
538 /* window */
539 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "sieveeditor");
540 gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
541 MANAGE_WINDOW_SIGNALS_CONNECT (window);
542 g_signal_connect(G_OBJECT(window), "delete_event",
543 G_CALLBACK(sieve_editor_delete_cb), page);
544
545 vbox = gtk_vbox_new(FALSE, 0);
546 gtk_container_add(GTK_CONTAINER(window), vbox);
547
548 ui_manager = gtk_ui_manager_new();
549 cm_menu_create_action_group_full(ui_manager,
550 "Menu", sieve_editor_entries, G_N_ELEMENTS(sieve_editor_entries),
551 page);
552
553 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Menu", NULL, GTK_UI_MANAGER_MENUBAR)
554
555 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Filter", "Filter", GTK_UI_MANAGER_MENU)
556 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu", "Edit", "Edit", GTK_UI_MANAGER_MENU)
557
558 /* Filter menu */
559 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "Save", "Filter/Save", GTK_UI_MANAGER_MENUITEM)
560 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "CheckSyntax", "Filter/CheckSyntax", GTK_UI_MANAGER_MENUITEM)
561 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "Revert", "Filter/Revert", GTK_UI_MANAGER_MENUITEM)
562 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Filter", "Close", "Filter/Close", GTK_UI_MANAGER_MENUITEM)
563
564 /* Edit menu */
565 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Undo", "Edit/Undo", GTK_UI_MANAGER_MENUITEM)
566 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Redo", "Edit/Redo", GTK_UI_MANAGER_MENUITEM)
567 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator1", "Edit/---", GTK_UI_MANAGER_SEPARATOR)
568
569 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Cut", "Edit/Cut", GTK_UI_MANAGER_MENUITEM)
570 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Copy", "Edit/Copy", GTK_UI_MANAGER_MENUITEM)
571 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Paste", "Edit/Paste", GTK_UI_MANAGER_MENUITEM)
572
573 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "SelectAll", "Edit/SelectAll", GTK_UI_MANAGER_MENUITEM)
574
575 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Separator2", "Edit/---", GTK_UI_MANAGER_SEPARATOR)
576
577 MENUITEM_ADDUI_MANAGER(ui_manager, "/Menu/Edit", "Find", "Edit/Find", GTK_UI_MANAGER_MENUITEM)
578
579 menubar = gtk_ui_manager_get_widget(ui_manager, "/Menu");
580
581 gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager));
582 gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, TRUE, 0);
583
584 cm_menu_set_sensitive_full(ui_manager, "Menu/Edit/Undo", FALSE);
585 cm_menu_set_sensitive_full(ui_manager, "Menu/Edit/Redo", FALSE);
586
587 /* text */
588 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
589 gtk_widget_set_size_request (scrolledwin, 660, 408);
590 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
591 GTK_POLICY_AUTOMATIC,
592 GTK_POLICY_AUTOMATIC);
593 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
594 GTK_SHADOW_IN);
595 gtk_box_pack_start(GTK_BOX(vbox), scrolledwin, TRUE, TRUE, 0);
596
597 text = gtk_text_view_new();
598 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD_CHAR);
599 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), TRUE);
600 gtk_container_add(GTK_CONTAINER(scrolledwin), text);
601
602 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
603 g_signal_connect(G_OBJECT(buffer), "changed",
604 G_CALLBACK(sieve_editor_changed_cb), page);
605
606 /* set text font */
607 if (prefs_common_get_prefs()->textfont) {
608 PangoFontDescription *font_desc;
609
610 font_desc = pango_font_description_from_string
611 (prefs_common_get_prefs()->textfont);
612 if (font_desc) {
613 gtk_widget_modify_font(text, font_desc);
614 pango_font_description_free(font_desc);
615 }
616 }
617
618 hbox = gtk_hbox_new (FALSE, 8);
619 gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
620 gtk_container_set_border_width (GTK_CONTAINER (hbox), 8);
621
622 /* status */
623 status_icon = gtk_image_new ();
624 gtk_box_pack_start (GTK_BOX (hbox), status_icon, FALSE, FALSE, 0);
625 status_text = gtk_label_new ("");
626 gtk_box_pack_start (GTK_BOX (hbox), status_text, FALSE, FALSE, 0);
627 gtk_label_set_justify (GTK_LABEL (status_text), GTK_JUSTIFY_LEFT);
628
629 /* buttons */
630 gtkut_stock_with_text_button_set_create(&hbox1,
631 &close_btn, GTK_STOCK_CANCEL, _("_Close"),
632 &check_btn, GTK_STOCK_OK, _("Chec_k Syntax"),
633 &save_btn, GTK_STOCK_SAVE, _("_Save"));
634 gtk_box_pack_end (GTK_BOX (hbox), hbox1, FALSE, FALSE, 0);
635 gtk_widget_grab_default (save_btn);
636 g_signal_connect (G_OBJECT (close_btn), "clicked",
637 G_CALLBACK (sieve_editor_close_cb), page);
638 g_signal_connect (G_OBJECT (check_btn), "clicked",
639 G_CALLBACK (sieve_editor_check_cb), page);
640 g_signal_connect (G_OBJECT (save_btn), "clicked",
641 G_CALLBACK (sieve_editor_save_cb), page);
642
643 undostruct = undo_init(text);
644 undo_set_change_state_func(undostruct, &sieve_editor_undo_state_changed,
645 page);
646
647 page->window = window;
648 page->ui_manager = ui_manager;
649 page->text = text;
650 page->undostruct = undostruct;
651 page->session = session;
652 page->script_name = script_name;
653 page->status_text = status_text;
654 page->status_icon = status_icon;
655
656 editors = g_slist_prepend(editors, page);
657
658 sieve_editor_set_modified(page, FALSE);
659
660 return page;
661 }
662
sieve_editor_get(SieveSession * session,gchar * script_name)663 SieveEditorPage *sieve_editor_get(SieveSession *session, gchar *script_name)
664 {
665 GSList *item;
666 SieveEditorPage *page;
667 for (item = editors; item; item = item->next) {
668 page = (SieveEditorPage *)item->data;
669 if (page->session == session &&
670 strcmp(script_name, page->script_name) == 0)
671 return page;
672 }
673 return NULL;
674 }
675
sieve_editor_present(SieveEditorPage * page)676 void sieve_editor_present(SieveEditorPage *page)
677 {
678 gtk_window_present(GTK_WINDOW(page->window));
679 }
680
sieve_editor_show(SieveEditorPage * page)681 void sieve_editor_show(SieveEditorPage *page)
682 {
683 gtk_widget_show_all(GTK_WIDGET(page->window));
684 }
685
sieve_editor_set_modified(SieveEditorPage * page,gboolean modified)686 static void sieve_editor_set_modified(SieveEditorPage *page,
687 gboolean modified)
688 {
689 gchar *title;
690
691 page->modified = modified;
692 cm_menu_set_sensitive_full(page->ui_manager, "Menu/Filter/Revert",
693 modified);
694
695 title = g_strdup_printf(_("%s - Sieve Filter%s"), page->script_name,
696 modified ? _(" [Edited]") : "");
697 gtk_window_set_title (GTK_WINDOW (page->window), title);
698 g_free(title);
699
700 if (modified) {
701 sieve_editor_set_status(page, "");
702 sieve_editor_set_status_icon(page, NULL);
703 }
704 }
705
got_data_loading(SieveSession * session,gboolean aborted,gchar * contents,SieveEditorPage * page)706 static void got_data_loading(SieveSession *session, gboolean aborted,
707 gchar *contents, SieveEditorPage *page)
708 {
709 if (aborted)
710 return;
711 if (contents == NULL) {
712 /* end of data */
713 sieve_editor_set_status(page, "");
714 return;
715 }
716 if (contents == (void *)-1) {
717 /* error */
718 if (page->first_line) {
719 /* no data. show error in manager window */
720 if (page->on_load_error)
721 page->on_load_error(session, page->on_load_error_data);
722 } else {
723 /* partial failure. show error in editor window */
724 sieve_editor_set_status(page, _("Unable to get script contents"));
725 sieve_editor_set_status_icon(page, GTK_STOCK_DIALOG_ERROR);
726 }
727 return;
728 }
729
730 if (page->first_line) {
731 page->first_line = FALSE;
732 sieve_editor_show(page);
733 }
734 sieve_editor_append_text(page, contents, strlen(contents));
735 }
736
737 /* load the script for this editor */
sieve_editor_load(SieveEditorPage * page,sieve_session_cb_fn on_load_error,gpointer load_error_data)738 void sieve_editor_load(SieveEditorPage *page,
739 sieve_session_cb_fn on_load_error, gpointer load_error_data)
740 {
741 page->first_line = TRUE;
742 page->on_load_error = on_load_error;
743 page->on_load_error_data = load_error_data;
744 sieve_editor_set_status(page, _("Loading..."));
745 sieve_editor_set_status_icon(page, NULL);
746 sieve_session_get_script(page->session, page->script_name,
747 (sieve_session_data_cb_fn)got_data_loading, page);
748 }
749