]> git.datanom.net - vfolder.git/blob - src/vfolder_prop.c
initial upload
[vfolder.git] / src / vfolder_prop.c
1 /*
2 * $Id: $
3 */
4 /* vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: */
5
6 /*
7 * Virtual folder plugin for claws-mail
8 *
9 * Claws Mail is Copyright (C) 1999-2012 by the Claws Mail Team
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 # include <config.h>
28 #endif
29
30 #include "gtk/gtk.h"
31 #include "glib.h"
32
33 #include "gettext.h"
34 #include "gtkutils.h"
35 #include "mainwindow.h"
36 #include "foldersel.h"
37 #include "alertpanel.h"
38
39 #include "vfolder_gtk.h"
40 #include "vfolder.h"
41 #include "vfolder_prop.h"
42
43 #define HEADERS N_("Message _Headers")
44 #define BODY N_("_Message body")
45 #define BOTH N_("_Both")
46
47 typedef struct {
48 GtkWidget* filter;
49 GtkWidget* frozen;
50 GtkWidget* deep_copy;
51 GtkWidget* source;
52 GtkWidget* label_btn;
53 GtkWidget* message_btn;
54 GtkWidget* both_btn;
55 } PropsDialog;
56
57 static void add_current_config(VFolderItem* item, PropsDialog* props) {
58 if (item->filter)
59 gtk_entry_set_text(GTK_ENTRY(props->filter), item->filter);
60 if (item->source) {
61 gchar* id = folder_item_get_identifier(item->source);
62 if (id) {
63 gtk_entry_set_text(GTK_ENTRY(props->source), id);
64 g_free(id);
65 }
66 }
67 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->frozen), item->frozen);
68 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->deep_copy), item->deep_copy);
69 switch (item->search) {
70 case SEARCH_BODY:
71 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->message_btn), TRUE);
72 case SEARCH_BOTH:
73 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->both_btn), TRUE);
74 case SEARCH_HEADERS:
75 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(props->label_btn), TRUE);
76 }
77 }
78
79 static gboolean is_source_widget(GtkWidget* widget) {
80 const gchar* name = gtk_widget_get_name(widget);
81
82 return (name && strcmp("source", name) == 0);
83 }
84
85 static void foldersel_cb(GtkWidget *widget, gpointer data) {
86 FolderItem *item;
87 gchar *item_id;
88 gint newpos = 0;
89 GtkWidget* entry = GTK_WIDGET(data);
90
91 item = foldersel_folder_sel(NULL, FOLDER_SEL_COPY, NULL, FALSE);
92 if (item && IS_VFOLDER_FOLDER_ITEM(item)) {
93 /* Cannot create virtual folder from virtual folder */
94 alertpanel_error(_("%s: Cannot create virtual folder from virtual folder"), item->name);
95 return;
96 }
97 else {
98 if (item && (item_id = folder_item_get_identifier(item)) != NULL) {
99 gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1);
100 gtk_editable_insert_text(GTK_EDITABLE(entry),
101 item_id, strlen(item_id), &newpos);
102 g_free(item_id);
103 }
104 debug_print("Source Folder: %s\n", gtk_entry_get_text(GTK_ENTRY(entry)));
105 }
106 }
107
108 static GtkWidget* vfolder_prop_row(GtkWidget* widget,
109 const gchar* label_markup,
110 gint width, gboolean center) {
111 GtkWidget* row = gtk_hbox_new(FALSE, 5);
112 GtkWidget* label = gtk_label_new(NULL);
113
114 gtk_widget_set_size_request(label, width, -1);
115 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), label_markup);
116 gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
117 gtk_box_pack_start(GTK_BOX(row), label, FALSE, FALSE, 5);
118 gtk_box_pack_start(GTK_BOX(row), widget, TRUE, FALSE, 5);
119
120 if (is_source_widget(widget)) {
121 GtkWidget* btn = gtk_button_new_from_stock(GTK_STOCK_OPEN);
122 g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(foldersel_cb), widget);
123 gtk_box_pack_start(GTK_BOX(row), btn, FALSE, FALSE, 5);
124 }
125
126 return row;
127 }
128
129 static gboolean vfolder_set_search_type(VFolderItem* item, GtkWidget* list) {
130 GSList *btn_list, *btns;
131 gboolean active = FALSE;
132 GtkToggleButton* btn = NULL;
133
134 btn_list = gtk_radio_button_get_group(GTK_RADIO_BUTTON(list));
135 for (btns = btn_list; btns && !active; btns = g_slist_next(btns)) {
136 btn = GTK_TOGGLE_BUTTON(btns->data);
137 active = gtk_toggle_button_get_active(btn);
138 }
139 if (active) {
140 const gchar* label = gtk_button_get_label(GTK_BUTTON(btn));
141 if (label) {
142 if (strcmp(BOTH, label) == 0) {
143 if (item->search != SEARCH_BOTH) {
144 item->search = SEARCH_BOTH;
145 return TRUE;
146 }
147 }
148 else if (strcmp(BODY, label) == 0) {
149 if (item->search != SEARCH_BODY) {
150 item->search = SEARCH_BODY;
151 return TRUE;
152 }
153 }
154 else {
155 if (item->search != SEARCH_HEADERS) {
156 item->search = SEARCH_HEADERS;
157 return TRUE;
158 }
159 }
160 }
161 }
162
163 return FALSE;
164 }
165 /*
166 static void vfolder_copy_msginfo_list(gpointer data, gpointer user_data) {
167 MsgInfo* msg = (MsgInfo *) data;
168 MsgInfo* new_msg;
169 VFolderItem* item = (VFolderItem *) user_data;
170
171 g_return_if_fail(msg != NULL);
172 g_return_if_fail(item != NULL);
173
174 new_msg = procmsg_msginfo_copy(msg);
175 item->msginfos = g_slist_prepend(item->msginfos, new_msg);
176 }
177 */
178 static gboolean vfolder_search_headers(MsgInfo* msg, GPatternSpec* pattern) {
179 return ((msg->cc && g_pattern_match_string(pattern, msg->cc)) ||
180 (msg->from && g_pattern_match_string(pattern, msg->from)) ||
181 (msg->fromname && g_pattern_match_string(pattern, msg->fromname)) ||
182 (msg->inreplyto && g_pattern_match_string(pattern, msg->inreplyto)) ||
183 (msg->subject && g_pattern_match_string(pattern, msg->subject)) ||
184 (msg->to && g_pattern_match_string(pattern, msg->to)));
185 }
186
187 static gboolean vfolder_search_body(MsgInfo* msg, GPatternSpec* pattern) {
188 gchar* body;
189 gboolean found = FALSE;
190
191 body = procmsg_get_message_file(msg);
192 if (body) {
193 found = g_pattern_match_string(pattern, body);
194 g_free(body);
195 }
196
197 return found;
198 }
199
200 static MsgInfoList* vfolder_filter_msgs_list(MsgInfoList* msgs, VFolderItem* item) {
201 MsgInfoList *list = NULL, *tmp;
202 GPatternSpec* pattern;
203 MsgInfo* msg;
204
205 if (!item || item->filter == NULL)
206 return list;
207
208 pattern = g_pattern_spec_new(item->filter);
209
210 for (tmp = msgs; tmp; tmp = g_slist_next(tmp)) {
211 msg = (MsgInfo *) tmp->data;
212 switch (item->search) {
213 case SEARCH_HEADERS:
214 if (vfolder_search_headers(msg, pattern))
215 list = g_slist_prepend(list, msg);
216 break;
217 case SEARCH_BODY:
218 if (vfolder_search_body(msg, pattern))
219 list = g_slist_prepend(list, msg);
220 break;
221 case SEARCH_BOTH:
222 if (vfolder_search_headers(msg, pattern)) {
223 list = g_slist_prepend(list, msg);
224 continue;
225 }
226 if (vfolder_search_body(msg, pattern))
227 list = g_slist_prepend(list, msg);
228 break;
229 }
230 }
231
232 g_pattern_spec_free(pattern);
233
234 return list;
235 }
236
237 static gboolean vfolder_create_msgs_list(VFolderItem* item, gboolean copy) {
238 MsgInfoList *msgs = NULL, *filtered = NULL;
239 gboolean ok = FALSE;
240 GSList* filelist = NULL;
241
242 if (item->filter && item->msg_filter_func) {
243 item->deep_copy = copy;
244 ok = TRUE;
245 msgs = folder_item_get_msg_list(item->source);
246 filtered = item->msg_filter_func(msgs, item);
247 if (filtered) {
248 filelist = procmsg_get_message_file_list(filtered);
249 if (filelist) {
250 gint n = folder_item_add_msgs(FOLDER_ITEM(item), filelist, FALSE);
251 FOLDER_ITEM(item)->last_num = n;
252 procmsg_message_file_list_free(filelist);
253 }
254 g_slist_free(filtered);
255 }
256 g_slist_free(msgs);
257 }
258 return ok;
259 }
260
261 void vfolder_set_msgs_filter(VFolderItem* vfolder_item) {
262 g_return_if_fail(vfolder_item != NULL);
263
264 vfolder_item->msg_filter_func = vfolder_filter_msgs_list;
265 }
266
267 gboolean vfolder_create_item_dialog(FolderItem* folder_item) {
268 gboolean created = FALSE;
269 VFolderItem* item = NULL;
270
271 g_return_val_if_fail(folder_item != NULL, created);
272 g_return_val_if_fail(IS_VFOLDER_FOLDER_ITEM(folder_item), created);
273
274 item = VFOLDER_ITEM(folder_item);
275 item->msg_filter_func = vfolder_filter_msgs_list;
276
277 if (vfolder_edit_item_dialog(item)) {
278 /* save properties */
279 if (FOLDER_ITEM_PROPS_OK != vfolder_folder_item_props_write(item))
280 created = FALSE;
281 else
282 created = TRUE;
283 }
284
285 return created;
286 }
287
288 gboolean vfolder_edit_item_dialog(VFolderItem* vfolder_item) {
289 gboolean ok = FALSE;
290 PropsDialog* props_dialog;
291 GtkWidget* dialog;
292 GtkWidget* content;
293 GtkWidget* row;
294 GtkWidget* box;
295 gint response;
296 gchar* name;
297 const gchar* str;
298 gboolean frozen, deep_copy;
299 FolderItem* source;
300 gchar* old_filter = NULL;
301
302 g_return_val_if_fail(vfolder_item != NULL, ok);
303
304 MainWindow *mainwin = mainwindow_get_mainwindow();
305 props_dialog = g_new0(PropsDialog, 1);
306 props_dialog->filter = gtk_entry_new();
307 props_dialog->frozen = gtk_check_button_new();
308 props_dialog->deep_copy = gtk_check_button_new();
309 props_dialog->source = gtk_entry_new();
310 props_dialog->label_btn =
311 gtk_radio_button_new_with_mnemonic(NULL, HEADERS);
312 props_dialog->message_btn =
313 gtk_radio_button_new_with_mnemonic_from_widget(
314 GTK_RADIO_BUTTON(props_dialog->label_btn), BODY);
315 props_dialog->both_btn =
316 gtk_radio_button_new_with_mnemonic_from_widget(
317 GTK_RADIO_BUTTON(props_dialog->label_btn), BOTH);
318 gtk_widget_set_name(props_dialog->source, "source");
319 add_current_config(vfolder_item, props_dialog);
320
321 dialog = gtk_dialog_new_with_buttons(
322 N_("Edit VFolder Properties"),
323 GTK_WINDOW(mainwin->window),
324 GTK_DIALOG_DESTROY_WITH_PARENT,
325 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
326 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
327 NULL);
328 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_REJECT);
329 content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
330
331 GtkWidget* vbox = gtk_vbox_new(FALSE, 5);
332
333 row = vfolder_prop_row(props_dialog->source, N_("_Source folder"), 110, FALSE);
334 gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 5);
335
336 GtkWidget* frame1 = gtk_frame_new(_("Message filter"));
337 GtkWidget* vbox1 = gtk_vbox_new(TRUE, 2);
338 gtk_container_add(GTK_CONTAINER(frame1), vbox1);
339
340 row = vfolder_prop_row(props_dialog->filter, N_("_Filter"), 110, FALSE);
341 gtk_box_pack_start(GTK_BOX(vbox1), row, FALSE, FALSE, 5);
342
343 box = gtk_hbox_new(TRUE, 2);
344 gtk_box_pack_start(GTK_BOX(box), props_dialog->label_btn, TRUE, TRUE, 2);
345 gtk_box_pack_start(GTK_BOX(box), props_dialog->message_btn, TRUE, TRUE, 2);
346 gtk_box_pack_start(GTK_BOX(box), props_dialog->both_btn, TRUE, TRUE, 2);
347 gtk_box_pack_start(GTK_BOX(vbox1), box, FALSE, FALSE, 5);
348
349 gtk_box_pack_start(GTK_BOX(vbox), frame1, FALSE, FALSE, 5);
350
351 row = vfolder_prop_row(props_dialog->frozen, N_("F_reeze content"), 110, TRUE);
352 gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 5);
353
354 row = vfolder_prop_row(props_dialog->deep_copy, N_("Co_py messages"), 110, TRUE);
355 gtk_box_pack_start(GTK_BOX(vbox), row, FALSE, FALSE, 5);
356
357 name = g_strconcat(FOLDER_ITEM(vfolder_item)->name, N_(": settings"), NULL);
358 GtkWidget* frame = gtk_frame_new(name);
359 g_free(name);
360 gtk_container_add(GTK_CONTAINER(frame), vbox);
361 gtk_widget_show_all(frame);
362
363 gtk_container_add(GTK_CONTAINER(content), frame);
364
365 response = gtk_dialog_run(GTK_DIALOG(dialog));
366 if (response == GTK_RESPONSE_ACCEPT) {
367 frozen = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(props_dialog->frozen));
368 deep_copy = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(props_dialog->deep_copy));
369
370 str = gtk_entry_get_text(GTK_ENTRY(props_dialog->filter));
371 if (str) {
372 old_filter = g_strdup(vfolder_item->filter);
373 if (strlen(str) == 0) {
374 if (vfolder_item->filter) {
375 g_free(vfolder_item->filter);
376 vfolder_item->filter = NULL;
377 ok = TRUE;
378 }
379 }
380 else {
381 if (!vfolder_item->filter || strcmp(vfolder_item->filter, str) != 0) {
382 g_free(vfolder_item->filter);
383 vfolder_item->filter = g_strdup(str);
384 ok = TRUE;
385 }
386 }
387 }
388 if (vfolder_set_search_type(vfolder_item, props_dialog->label_btn))
389 ok = TRUE;
390
391 str = gtk_entry_get_text(GTK_ENTRY(props_dialog->source));
392 if (str) {
393 source = folder_find_item_from_identifier(str);
394 if (source && (source->stype != F_NORMAL && source->stype != F_INBOX)) {
395 alertpanel_error(_("%s: Not suitable for virtual folders\n"
396 "Use only folder type: Normal or Inbox\n"), str);
397 g_free(vfolder_item->filter);
398 vfolder_item->filter = g_strdup(old_filter);
399 ok = FALSE;
400 goto error;
401 }
402
403 if (strlen(str) == 0) {
404 if (vfolder_item->source) {
405 vfolder_item->source = NULL;
406 folder_item_remove_all_msg(FOLDER_ITEM(vfolder_item));
407 ok = TRUE;
408 }
409 }
410 else {
411 folder_item_remove_all_msg(FOLDER_ITEM(vfolder_item));
412 gchar* id = (vfolder_item->source) ?
413 folder_item_get_identifier(vfolder_item->source) : NULL;
414 if (!id || strcmp(id, str) != 0)
415 vfolder_item->source = source;
416 if (vfolder_item->source) {
417 ok = vfolder_create_msgs_list(vfolder_item, deep_copy);
418 if (ok == FALSE) {
419 g_free(vfolder_item->filter);
420 vfolder_item->filter = g_strdup(old_filter);
421 goto error;
422 }
423 }
424 else {
425 g_free(vfolder_item->filter);
426 vfolder_item->filter = g_strdup(old_filter);
427 ok = FALSE;
428 goto error;
429 }
430 }
431 }
432
433 if (vfolder_item->frozen != frozen) {
434 vfolder_item->frozen = frozen;
435 ok = TRUE;
436 }
437
438 if (vfolder_item->deep_copy != deep_copy) {
439 vfolder_item->deep_copy = deep_copy;
440 ok = TRUE;
441 }
442
443 }
444
445 error:
446 gtk_widget_destroy(dialog);
447 g_free(props_dialog);
448 g_free(old_filter);
449
450 return ok;
451 }
This page took 0.134051 seconds and 6 git commands to generate.