Statistics
| Revision:

root / src / query_search.c @ 1490

History | View | Annotate | Download (31.5 kB)

1 1 hiro
/*
2 1 hiro
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 928 hiro
 * Copyright (C) 1999-2006 Hiroyuki Yamamoto
4 1 hiro
 *
5 1 hiro
 * This program is free software; you can redistribute it and/or modify
6 1 hiro
 * it under the terms of the GNU General Public License as published by
7 1 hiro
 * the Free Software Foundation; either version 2 of the License, or
8 1 hiro
 * (at your option) any later version.
9 1 hiro
 *
10 1 hiro
 * This program is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 1 hiro
 * GNU General Public License for more details.
14 1 hiro
 *
15 1 hiro
 * You should have received a copy of the GNU General Public License
16 1 hiro
 * along with this program; if not, write to the Free Software
17 1 hiro
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 1 hiro
 */
19 1 hiro
20 1 hiro
#ifdef HAVE_CONFIG_H
21 1 hiro
#  include "config.h"
22 1 hiro
#endif
23 1 hiro
24 1 hiro
#include "defs.h"
25 1 hiro
26 1 hiro
#include <glib.h>
27 92 hiro
#include <glib/gi18n.h>
28 1 hiro
#include <gdk/gdkkeysyms.h>
29 1 hiro
#include <gtk/gtkwidget.h>
30 1 hiro
#include <gtk/gtkwindow.h>
31 1 hiro
#include <gtk/gtkvbox.h>
32 1 hiro
#include <gtk/gtktable.h>
33 1 hiro
#include <gtk/gtkoptionmenu.h>
34 1 hiro
#include <gtk/gtklabel.h>
35 1 hiro
#include <gtk/gtkentry.h>
36 1 hiro
#include <gtk/gtkhbox.h>
37 1 hiro
#include <gtk/gtkcheckbutton.h>
38 1 hiro
#include <gtk/gtkhbbox.h>
39 1 hiro
#include <gtk/gtkbutton.h>
40 237 hiro
#include <gtk/gtkmenuitem.h>
41 237 hiro
#include <gtk/gtkstock.h>
42 241 hiro
#include <gtk/gtktreemodel.h>
43 836 hiro
#include <gtk/gtkliststore.h>
44 836 hiro
#include <gtk/gtktreeview.h>
45 241 hiro
#include <gtk/gtktreeselection.h>
46 836 hiro
#include <gtk/gtkcellrenderertext.h>
47 1 hiro
#include <stdio.h>
48 1 hiro
#include <stdlib.h>
49 1 hiro
#include <string.h>
50 1 hiro
51 934 hiro
#include "query_search.h"
52 1 hiro
#include "summaryview.h"
53 1 hiro
#include "messageview.h"
54 1 hiro
#include "mainwindow.h"
55 836 hiro
#include "folderview.h"
56 1 hiro
#include "menu.h"
57 1 hiro
#include "utils.h"
58 1 hiro
#include "gtkutils.h"
59 1 hiro
#include "manage_window.h"
60 1 hiro
#include "alertpanel.h"
61 836 hiro
#include "foldersel.h"
62 848 hiro
#include "statusbar.h"
63 836 hiro
#include "procmsg.h"
64 836 hiro
#include "procheader.h"
65 836 hiro
#include "folder.h"
66 836 hiro
#include "filter.h"
67 836 hiro
#include "prefs_filter.h"
68 836 hiro
#include "prefs_filter_edit.h"
69 1 hiro
70 836 hiro
enum
71 836 hiro
{
72 836 hiro
        COL_FOLDER,
73 836 hiro
        COL_SUBJECT,
74 836 hiro
        COL_FROM,
75 836 hiro
        COL_DATE,
76 836 hiro
        COL_MSGINFO,
77 836 hiro
        N_COLS
78 836 hiro
};
79 836 hiro
80 934 hiro
static struct QuerySearchWindow {
81 271 hiro
        GtkWidget *window;
82 1 hiro
83 271 hiro
        GtkWidget *bool_optmenu;
84 1 hiro
85 836 hiro
        FilterCondEdit *cond_edit;
86 271 hiro
87 836 hiro
        GtkWidget *folder_entry;
88 836 hiro
        GtkWidget *folder_btn;
89 836 hiro
90 836 hiro
        GtkWidget *subfolder_checkbtn;
91 271 hiro
        GtkWidget *case_checkbtn;
92 271 hiro
93 836 hiro
        GtkWidget *treeview;
94 836 hiro
        GtkListStore *store;
95 836 hiro
96 836 hiro
        GtkWidget *status_label;
97 836 hiro
98 271 hiro
        GtkWidget *clear_btn;
99 836 hiro
        GtkWidget *search_btn;
100 836 hiro
        GtkWidget *save_btn;
101 406 hiro
        GtkWidget *close_btn;
102 271 hiro
103 836 hiro
        FilterRule *rule;
104 836 hiro
        gboolean requires_full_headers;
105 836 hiro
106 928 hiro
        gboolean exclude_trash;
107 928 hiro
108 836 hiro
        gboolean on_search;
109 836 hiro
        gboolean cancelled;
110 271 hiro
} search_window;
111 271 hiro
112 836 hiro
typedef struct {
113 836 hiro
        GtkWidget *window;
114 836 hiro
115 836 hiro
        GtkWidget *folder_entry;
116 836 hiro
        GtkWidget *name_entry;
117 836 hiro
118 876 hiro
        GtkWidget *ok_btn;
119 876 hiro
        GtkWidget *cancel_btn;
120 876 hiro
121 836 hiro
        gboolean cancelled;
122 836 hiro
        gboolean finished;
123 934 hiro
} QuerySearchSaveDialog;
124 836 hiro
125 934 hiro
static void query_search_create        (void);
126 271 hiro
127 934 hiro
static FilterRule *query_search_dialog_to_rule        (const gchar        *name,
128 934 hiro
                                                 FolderItem    **item);
129 271 hiro
130 934 hiro
static void query_search_query                        (void);
131 934 hiro
static void query_search_folder                        (FolderItem        *item);
132 836 hiro
133 934 hiro
static gboolean query_search_recursive_func        (GNode                *node,
134 836 hiro
                                                 gpointer         data);
135 836 hiro
136 934 hiro
static void query_search_append_msg        (MsgInfo        *msginfo);
137 934 hiro
static void query_search_clear_list        (void);
138 836 hiro
139 934 hiro
static void query_search_hbox_added        (CondHBox        *hbox);
140 836 hiro
141 836 hiro
static void row_activated                (GtkTreeView                *treeview,
142 836 hiro
                                         GtkTreePath                *path,
143 836 hiro
                                         GtkTreeViewColumn        *column,
144 836 hiro
                                         gpointer                 data);
145 836 hiro
146 836 hiro
static gboolean row_selected                (GtkTreeSelection        *selection,
147 836 hiro
                                         GtkTreeModel                *model,
148 836 hiro
                                         GtkTreePath                *path,
149 836 hiro
                                         gboolean                 cur_selected,
150 836 hiro
                                         gpointer                 data);
151 836 hiro
152 934 hiro
static void query_search_clear        (GtkButton        *button,
153 271 hiro
                                         gpointer         data);
154 934 hiro
static void query_select_folder        (GtkButton        *button,
155 271 hiro
                                         gpointer         data);
156 934 hiro
static void query_search_clicked        (GtkButton        *button,
157 271 hiro
                                         gpointer         data);
158 934 hiro
static void query_search_save                (GtkButton        *button,
159 271 hiro
                                         gpointer         data);
160 934 hiro
static void query_search_close                (GtkButton        *button,
161 836 hiro
                                         gpointer         data);
162 271 hiro
163 934 hiro
static void query_search_entry_activated(GtkWidget        *widget,
164 934 hiro
                                         gpointer         data);
165 271 hiro
166 934 hiro
static gint query_search_deleted        (GtkWidget        *widget,
167 836 hiro
                                         GdkEventAny        *event,
168 836 hiro
                                         gpointer         data);
169 271 hiro
static gboolean key_pressed                (GtkWidget        *widget,
170 271 hiro
                                         GdkEventKey        *event,
171 271 hiro
                                         gpointer         data);
172 271 hiro
173 1041 hiro
static gint query_search_cmp_by_folder        (GtkTreeModel        *model,
174 1041 hiro
                                         GtkTreeIter        *a,
175 1041 hiro
                                         GtkTreeIter        *b,
176 1041 hiro
                                         gpointer         data);
177 1041 hiro
static gint query_search_cmp_by_subject        (GtkTreeModel        *model,
178 1041 hiro
                                         GtkTreeIter        *a,
179 1041 hiro
                                         GtkTreeIter        *b,
180 1041 hiro
                                         gpointer         data);
181 1041 hiro
static gint query_search_cmp_by_from        (GtkTreeModel        *model,
182 1041 hiro
                                         GtkTreeIter        *a,
183 1041 hiro
                                         GtkTreeIter        *b,
184 1041 hiro
                                         gpointer         data);
185 1041 hiro
static gint query_search_cmp_by_date        (GtkTreeModel        *model,
186 1041 hiro
                                         GtkTreeIter        *a,
187 1041 hiro
                                         GtkTreeIter        *b,
188 1041 hiro
                                         gpointer         data);
189 271 hiro
190 1041 hiro
191 934 hiro
void query_search(FolderItem *item)
192 1 hiro
{
193 836 hiro
        gchar *id;
194 836 hiro
195 271 hiro
        if (!search_window.window)
196 934 hiro
                query_search_create();
197 1 hiro
        else
198 869 hiro
                gtk_window_present(GTK_WINDOW(search_window.window));
199 1 hiro
200 848 hiro
        if (item && item->stype != F_VIRTUAL) {
201 836 hiro
                id = folder_item_get_identifier(item);
202 836 hiro
                gtk_entry_set_text(GTK_ENTRY(search_window.folder_entry), id);
203 836 hiro
                g_free(id);
204 836 hiro
        } else
205 836 hiro
                gtk_entry_set_text(GTK_ENTRY(search_window.folder_entry), "");
206 836 hiro
207 836 hiro
        gtk_widget_grab_focus(search_window.search_btn);
208 271 hiro
        gtk_widget_show(search_window.window);
209 1 hiro
}
210 1 hiro
211 934 hiro
static void query_search_create(void)
212 1 hiro
{
213 271 hiro
        GtkWidget *window;
214 1 hiro
        GtkWidget *vbox1;
215 1 hiro
        GtkWidget *bool_hbox;
216 271 hiro
        GtkWidget *bool_optmenu;
217 1 hiro
        GtkWidget *bool_menu;
218 1 hiro
        GtkWidget *menuitem;
219 271 hiro
        GtkWidget *clear_btn;
220 836 hiro
        GtkWidget *search_btn;
221 271 hiro
222 836 hiro
        GtkWidget *scrolledwin;
223 836 hiro
        FilterCondEdit *cond_edit;
224 836 hiro
        CondHBox *cond_hbox;
225 271 hiro
226 836 hiro
        GtkWidget *folder_hbox;
227 836 hiro
        GtkWidget *folder_label;
228 836 hiro
        GtkWidget *folder_entry;
229 836 hiro
        GtkWidget *folder_btn;
230 836 hiro
231 1 hiro
        GtkWidget *checkbtn_hbox;
232 836 hiro
        GtkWidget *subfolder_checkbtn;
233 271 hiro
        GtkWidget *case_checkbtn;
234 271 hiro
235 836 hiro
        GtkWidget *treeview;
236 836 hiro
        GtkListStore *store;
237 836 hiro
        GtkTreeViewColumn *column;
238 836 hiro
        GtkCellRenderer *renderer;
239 836 hiro
        GtkTreeSelection *selection;
240 836 hiro
241 1 hiro
        GtkWidget *confirm_area;
242 836 hiro
243 836 hiro
        GtkWidget *status_label;
244 836 hiro
245 837 hiro
        GtkWidget *btn_hbox;
246 836 hiro
        GtkWidget *hbbox;
247 836 hiro
        GtkWidget *save_btn;
248 406 hiro
        GtkWidget *close_btn;
249 1 hiro
250 1 hiro
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
251 1 hiro
        gtk_window_set_title(GTK_WINDOW (window), _("Search messages"));
252 836 hiro
        gtk_widget_set_size_request(window, 600, -1);
253 1 hiro
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, TRUE);
254 1 hiro
        gtk_container_set_border_width(GTK_CONTAINER (window), 8);
255 1 hiro
        g_signal_connect(G_OBJECT(window), "delete_event",
256 934 hiro
                         G_CALLBACK(query_search_deleted), NULL);
257 1 hiro
        g_signal_connect(G_OBJECT(window), "key_press_event",
258 1 hiro
                         G_CALLBACK(key_pressed), NULL);
259 1 hiro
        MANAGE_WINDOW_SIGNALS_CONNECT(window);
260 1 hiro
261 836 hiro
        vbox1 = gtk_vbox_new (FALSE, 6);
262 1 hiro
        gtk_widget_show (vbox1);
263 1 hiro
        gtk_container_add (GTK_CONTAINER (window), vbox1);
264 1 hiro
265 836 hiro
        bool_hbox = gtk_hbox_new(FALSE, 12);
266 1 hiro
        gtk_widget_show(bool_hbox);
267 1 hiro
        gtk_box_pack_start(GTK_BOX(vbox1), bool_hbox, FALSE, FALSE, 0);
268 1 hiro
269 1 hiro
        bool_optmenu = gtk_option_menu_new();
270 1 hiro
        gtk_widget_show(bool_optmenu);
271 1 hiro
        gtk_box_pack_start(GTK_BOX(bool_hbox), bool_optmenu, FALSE, FALSE, 0);
272 1 hiro
273 1 hiro
        bool_menu = gtk_menu_new();
274 836 hiro
        MENUITEM_ADD(bool_menu, menuitem, _("Match any of the following"),
275 836 hiro
                     FLT_OR);
276 836 hiro
        MENUITEM_ADD(bool_menu, menuitem, _("Match all of the following"),
277 836 hiro
                     FLT_AND);
278 1 hiro
        gtk_option_menu_set_menu(GTK_OPTION_MENU(bool_optmenu), bool_menu);
279 1 hiro
280 836 hiro
        hbbox = gtk_hbutton_box_new();
281 836 hiro
        gtk_widget_show(hbbox);
282 836 hiro
        gtk_button_box_set_layout(GTK_BUTTON_BOX(hbbox), GTK_BUTTONBOX_END);
283 836 hiro
        gtk_box_set_spacing(GTK_BOX(hbbox), 6);
284 836 hiro
        gtk_box_pack_end(GTK_BOX(bool_hbox), hbbox, FALSE, FALSE, 0);
285 836 hiro
286 271 hiro
        clear_btn = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
287 271 hiro
        gtk_widget_show(clear_btn);
288 836 hiro
        gtk_box_pack_start(GTK_BOX(hbbox), clear_btn, FALSE, FALSE, 0);
289 271 hiro
290 836 hiro
        search_btn = gtk_button_new_from_stock(GTK_STOCK_FIND);
291 836 hiro
        GTK_WIDGET_SET_FLAGS(search_btn, GTK_CAN_DEFAULT);
292 836 hiro
        gtk_widget_show(search_btn);
293 836 hiro
        gtk_box_pack_start(GTK_BOX(hbbox), search_btn, FALSE, FALSE, 0);
294 836 hiro
        gtk_widget_grab_default(search_btn);
295 1 hiro
296 836 hiro
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
297 836 hiro
        gtk_widget_show(scrolledwin);
298 836 hiro
        gtk_box_pack_start(GTK_BOX(vbox1), scrolledwin, FALSE, FALSE, 0);
299 836 hiro
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
300 836 hiro
                                       GTK_POLICY_AUTOMATIC,
301 836 hiro
                                       GTK_POLICY_AUTOMATIC);
302 836 hiro
        gtk_widget_set_size_request(scrolledwin, -1, 120);
303 1 hiro
304 836 hiro
        cond_edit = prefs_filter_edit_cond_edit_create();
305 934 hiro
        cond_edit->add_hbox = query_search_hbox_added;
306 836 hiro
        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwin),
307 836 hiro
                                              cond_edit->cond_vbox);
308 836 hiro
        prefs_filter_set_header_list(NULL);
309 836 hiro
        prefs_filter_edit_set_header_list(cond_edit, NULL);
310 836 hiro
        cond_hbox = prefs_filter_edit_cond_hbox_create(cond_edit);
311 836 hiro
        prefs_filter_edit_set_cond_hbox_widgets(cond_hbox, PF_COND_HEADER);
312 836 hiro
        prefs_filter_edit_insert_cond_hbox(cond_edit, cond_hbox, -1);
313 836 hiro
        if (cond_edit->add_hbox)
314 836 hiro
                cond_edit->add_hbox(cond_hbox);
315 1 hiro
316 836 hiro
        folder_hbox = gtk_hbox_new (FALSE, 8);
317 836 hiro
        gtk_widget_show (folder_hbox);
318 836 hiro
        gtk_box_pack_start (GTK_BOX (vbox1), folder_hbox, FALSE, FALSE, 0);
319 1 hiro
320 836 hiro
        folder_label = gtk_label_new (_("Folder:"));
321 836 hiro
        gtk_widget_show (folder_label);
322 836 hiro
        gtk_box_pack_start (GTK_BOX (folder_hbox), folder_label,
323 836 hiro
                            FALSE, FALSE, 0);
324 1 hiro
325 836 hiro
        folder_entry = gtk_entry_new ();
326 836 hiro
        gtk_widget_show (folder_entry);
327 836 hiro
        gtk_box_pack_start (GTK_BOX (folder_hbox), folder_entry, TRUE, TRUE, 0);
328 1 hiro
329 836 hiro
        folder_btn = gtk_button_new_with_label("...");
330 836 hiro
        gtk_widget_show (folder_btn);
331 836 hiro
        gtk_box_pack_start (GTK_BOX (folder_hbox), folder_btn, FALSE, FALSE, 0);
332 1 hiro
333 836 hiro
        checkbtn_hbox = gtk_hbox_new (FALSE, 12);
334 836 hiro
        gtk_widget_show (checkbtn_hbox);
335 836 hiro
        gtk_box_pack_start (GTK_BOX (vbox1), checkbtn_hbox, FALSE, FALSE, 0);
336 1 hiro
337 836 hiro
        subfolder_checkbtn =
338 836 hiro
                gtk_check_button_new_with_label (_("Search subfolders"));
339 836 hiro
        gtk_widget_show (subfolder_checkbtn);
340 836 hiro
        gtk_box_pack_start (GTK_BOX (checkbtn_hbox), subfolder_checkbtn,
341 836 hiro
                            FALSE, FALSE, 0);
342 1 hiro
343 1 hiro
        case_checkbtn = gtk_check_button_new_with_label (_("Case sensitive"));
344 1 hiro
        gtk_widget_show (case_checkbtn);
345 1 hiro
        gtk_box_pack_start (GTK_BOX (checkbtn_hbox), case_checkbtn,
346 1 hiro
                            FALSE, FALSE, 0);
347 1 hiro
348 836 hiro
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
349 836 hiro
        gtk_box_pack_start(GTK_BOX(vbox1), scrolledwin, TRUE, TRUE, 0);
350 836 hiro
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
351 836 hiro
                                       GTK_POLICY_AUTOMATIC,
352 836 hiro
                                       GTK_POLICY_AUTOMATIC);
353 836 hiro
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
354 836 hiro
                                            GTK_SHADOW_IN);
355 836 hiro
        gtk_widget_set_size_request(scrolledwin, -1, 150);
356 1 hiro
357 836 hiro
        store = gtk_list_store_new(N_COLS,
358 836 hiro
                                   G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
359 836 hiro
                                   G_TYPE_STRING, G_TYPE_POINTER);
360 836 hiro
        treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
361 836 hiro
        g_object_unref(store);
362 836 hiro
        gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
363 836 hiro
        g_signal_connect(G_OBJECT(treeview), "row-activated",
364 836 hiro
                         G_CALLBACK(row_activated), NULL);
365 406 hiro
366 1041 hiro
        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_FOLDER,
367 1041 hiro
                                        query_search_cmp_by_folder, NULL, NULL);
368 1041 hiro
        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_SUBJECT,
369 1041 hiro
                                        query_search_cmp_by_subject,
370 1041 hiro
                                        NULL, NULL);
371 1041 hiro
        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_FROM,
372 1041 hiro
                                        query_search_cmp_by_from, NULL, NULL);
373 1041 hiro
        gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_DATE,
374 1041 hiro
                                        query_search_cmp_by_date, NULL, NULL);
375 1041 hiro
376 836 hiro
        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
377 836 hiro
        gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
378 836 hiro
        gtk_tree_selection_set_select_function(selection, row_selected,
379 836 hiro
                                               NULL, NULL);
380 1 hiro
381 836 hiro
        gtk_container_add(GTK_CONTAINER(scrolledwin), treeview);
382 271 hiro
383 836 hiro
#define APPEND_COLUMN(label, col, width)                                \
384 836 hiro
{                                                                        \
385 836 hiro
        renderer = gtk_cell_renderer_text_new();                        \
386 836 hiro
        column = gtk_tree_view_column_new_with_attributes                \
387 836 hiro
                (label, renderer, "text", col, NULL);                        \
388 836 hiro
        gtk_tree_view_column_set_resizable(column, TRUE);                \
389 836 hiro
        if (width) {                                                        \
390 836 hiro
                gtk_tree_view_column_set_sizing                                \
391 836 hiro
                        (column, GTK_TREE_VIEW_COLUMN_FIXED);                \
392 836 hiro
                gtk_tree_view_column_set_fixed_width(column, width);        \
393 836 hiro
        }                                                                \
394 1041 hiro
        gtk_tree_view_column_set_sort_column_id(column, col);                \
395 836 hiro
        gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);        \
396 836 hiro
}
397 271 hiro
398 836 hiro
        APPEND_COLUMN(_("Folder"), COL_FOLDER, 0);
399 836 hiro
        APPEND_COLUMN(_("Subject"), COL_SUBJECT, 200);
400 836 hiro
        APPEND_COLUMN(_("From"), COL_FROM, 180);
401 836 hiro
        APPEND_COLUMN(_("Date"), COL_DATE, 0);
402 1 hiro
403 836 hiro
        gtk_widget_show_all(scrolledwin);
404 836 hiro
405 836 hiro
        confirm_area = gtk_hbox_new(FALSE, 12);
406 836 hiro
        gtk_widget_show(confirm_area);
407 836 hiro
        gtk_box_pack_start(GTK_BOX(vbox1), confirm_area, FALSE, FALSE, 0);
408 836 hiro
409 836 hiro
        status_label = gtk_label_new("");
410 836 hiro
        gtk_widget_show(status_label);
411 836 hiro
        gtk_box_pack_start(GTK_BOX(confirm_area), status_label,
412 836 hiro
                           FALSE, FALSE, 0);
413 836 hiro
414 837 hiro
        btn_hbox = gtk_hbox_new(FALSE, 6);
415 837 hiro
        gtk_widget_show(btn_hbox);
416 837 hiro
        gtk_box_pack_end(GTK_BOX(confirm_area), btn_hbox, FALSE, FALSE, 0);
417 837 hiro
418 837 hiro
        gtkut_stock_button_set_create(&hbbox, &close_btn, GTK_STOCK_CLOSE,
419 837 hiro
                                      NULL, NULL, NULL, NULL);
420 836 hiro
        gtk_widget_show(hbbox);
421 837 hiro
        gtk_box_pack_end(GTK_BOX(btn_hbox), hbbox, FALSE, FALSE, 0);
422 836 hiro
423 836 hiro
        save_btn = gtk_button_new_with_mnemonic(_("_Save as search folder"));
424 836 hiro
        gtk_widget_show(save_btn);
425 837 hiro
        gtk_box_pack_end(GTK_BOX(btn_hbox), save_btn, FALSE, FALSE, 0);
426 836 hiro
427 1 hiro
        g_signal_connect(G_OBJECT(clear_btn), "clicked",
428 934 hiro
                         G_CALLBACK(query_search_clear), NULL);
429 836 hiro
        g_signal_connect(G_OBJECT(folder_btn), "clicked",
430 934 hiro
                         G_CALLBACK(query_select_folder), NULL);
431 836 hiro
        g_signal_connect(G_OBJECT(search_btn), "clicked",
432 934 hiro
                         G_CALLBACK(query_search_clicked), NULL);
433 836 hiro
        g_signal_connect(G_OBJECT(save_btn), "clicked",
434 934 hiro
                         G_CALLBACK(query_search_save), NULL);
435 836 hiro
        g_signal_connect(G_OBJECT(close_btn), "clicked",
436 934 hiro
                         G_CALLBACK(query_search_close), NULL);
437 271 hiro
438 271 hiro
        search_window.window = window;
439 271 hiro
        search_window.bool_optmenu = bool_optmenu;
440 836 hiro
441 836 hiro
        search_window.cond_edit = cond_edit;
442 836 hiro
443 836 hiro
        search_window.folder_entry = folder_entry;
444 836 hiro
        search_window.folder_btn = folder_btn;
445 836 hiro
        search_window.subfolder_checkbtn = subfolder_checkbtn;
446 271 hiro
        search_window.case_checkbtn = case_checkbtn;
447 836 hiro
448 836 hiro
        search_window.treeview = treeview;
449 836 hiro
        search_window.store = store;
450 836 hiro
451 836 hiro
        search_window.status_label = status_label;
452 836 hiro
453 271 hiro
        search_window.clear_btn = clear_btn;
454 836 hiro
        search_window.search_btn = search_btn;
455 836 hiro
        search_window.save_btn  = save_btn;
456 406 hiro
        search_window.close_btn = close_btn;
457 1 hiro
}
458 1 hiro
459 934 hiro
static FilterRule *query_search_dialog_to_rule(const gchar *name,
460 836 hiro
                                                 FolderItem **item)
461 1 hiro
{
462 836 hiro
        const gchar *id;
463 836 hiro
        FolderItem *item_;
464 836 hiro
        FilterBoolOp bool_op = FLT_OR;
465 836 hiro
        gboolean recursive;
466 1 hiro
        gboolean case_sens;
467 874 hiro
        GSList *cond_list;
468 836 hiro
        FilterRule *rule;
469 1 hiro
470 836 hiro
        id = gtk_entry_get_text(GTK_ENTRY(search_window.folder_entry));
471 836 hiro
        item_ = folder_find_item_from_identifier(id);
472 836 hiro
        if (!item_)
473 836 hiro
                return NULL;
474 836 hiro
        if (item)
475 836 hiro
                *item = item_;
476 1 hiro
477 836 hiro
        bool_op = menu_get_option_menu_active_index
478 271 hiro
                (GTK_OPTION_MENU(search_window.bool_optmenu));
479 836 hiro
        recursive = gtk_toggle_button_get_active
480 836 hiro
                (GTK_TOGGLE_BUTTON(search_window.subfolder_checkbtn));
481 1 hiro
        case_sens = gtk_toggle_button_get_active
482 271 hiro
                (GTK_TOGGLE_BUTTON(search_window.case_checkbtn));
483 1 hiro
484 874 hiro
        cond_list = prefs_filter_edit_cond_edit_to_list(search_window.cond_edit,
485 874 hiro
                                                        case_sens);
486 836 hiro
        if (!cond_list)
487 836 hiro
                return NULL;
488 836 hiro
489 836 hiro
        rule = filter_rule_new(name, bool_op, cond_list, NULL);
490 836 hiro
        rule->target_folder = g_strdup(id);
491 836 hiro
        rule->recursive = recursive;
492 836 hiro
493 836 hiro
        return rule;
494 836 hiro
}
495 836 hiro
496 934 hiro
static void query_search_query(void)
497 836 hiro
{
498 836 hiro
        FolderItem *item;
499 836 hiro
500 836 hiro
        if (search_window.on_search)
501 836 hiro
                return;
502 836 hiro
503 836 hiro
        search_window.on_search = TRUE;
504 836 hiro
505 934 hiro
        search_window.rule = query_search_dialog_to_rule("Query rule", &item);
506 836 hiro
        if (!search_window.rule) {
507 836 hiro
                search_window.on_search = FALSE;
508 836 hiro
                return;
509 1 hiro
        }
510 836 hiro
        search_window.requires_full_headers =
511 836 hiro
                filter_rule_requires_full_headers(search_window.rule);
512 1 hiro
513 928 hiro
        if (search_window.rule->recursive) {
514 928 hiro
                if (item->stype == F_TRASH)
515 928 hiro
                        search_window.exclude_trash = FALSE;
516 928 hiro
                else
517 928 hiro
                        search_window.exclude_trash = TRUE;
518 928 hiro
        } else
519 928 hiro
                search_window.exclude_trash = FALSE;
520 928 hiro
521 836 hiro
        search_window.cancelled = FALSE;
522 1 hiro
523 1041 hiro
        gtk_widget_set_sensitive(search_window.clear_btn, FALSE);
524 836 hiro
        gtk_button_set_label(GTK_BUTTON(search_window.search_btn),
525 836 hiro
                             GTK_STOCK_STOP);
526 934 hiro
        query_search_clear_list();
527 1 hiro
528 836 hiro
        if (search_window.rule->recursive)
529 836 hiro
                g_node_traverse(item->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
530 934 hiro
                                query_search_recursive_func, NULL);
531 836 hiro
        else
532 934 hiro
                query_search_folder(item);
533 1 hiro
534 836 hiro
        filter_rule_free(search_window.rule);
535 836 hiro
        search_window.rule = NULL;
536 836 hiro
        search_window.requires_full_headers = FALSE;
537 928 hiro
        search_window.exclude_trash = FALSE;
538 1 hiro
539 1041 hiro
        gtk_widget_set_sensitive(search_window.clear_btn, TRUE);
540 836 hiro
        gtk_button_set_label(GTK_BUTTON(search_window.search_btn),
541 836 hiro
                             GTK_STOCK_FIND);
542 836 hiro
        gtk_label_set_text(GTK_LABEL(search_window.status_label), _("Done."));
543 848 hiro
        statusbar_pop_all();
544 1 hiro
545 836 hiro
        if (search_window.cancelled)
546 836 hiro
                debug_print("* query search cancelled.\n");
547 836 hiro
        debug_print("query search finished.\n");
548 1 hiro
549 836 hiro
        search_window.on_search = FALSE;
550 836 hiro
        search_window.cancelled = FALSE;
551 836 hiro
}
552 1 hiro
553 934 hiro
static void query_search_folder(FolderItem *item)
554 836 hiro
{
555 836 hiro
        gchar *folder_name, *str;
556 836 hiro
        GSList *mlist;
557 836 hiro
        FilterInfo fltinfo;
558 836 hiro
        GSList *cur;
559 836 hiro
        gint count = 1, total;
560 836 hiro
        GTimeVal tv_prev, tv_cur;
561 836 hiro
562 848 hiro
        if (!item->path || item->stype == F_VIRTUAL)
563 836 hiro
                return;
564 836 hiro
565 836 hiro
        folder_name = g_path_get_basename(item->path);
566 836 hiro
        str = g_strdup_printf(_("Searching %s ..."), folder_name);
567 836 hiro
        gtk_label_set_text(GTK_LABEL(search_window.status_label), str);
568 836 hiro
        g_free(str);
569 836 hiro
        g_get_current_time(&tv_prev);
570 836 hiro
        ui_update();
571 836 hiro
572 836 hiro
        if (search_window.cancelled) {
573 836 hiro
                g_free(folder_name);
574 836 hiro
                return;
575 836 hiro
        }
576 836 hiro
577 836 hiro
        mlist = folder_item_get_msg_list(item, TRUE);
578 836 hiro
        total = g_slist_length(mlist);
579 836 hiro
580 836 hiro
        memset(&fltinfo, 0, sizeof(FilterInfo));
581 836 hiro
582 836 hiro
        debug_print("requires_full_headers: %d\n",
583 836 hiro
                    search_window.requires_full_headers);
584 836 hiro
        debug_print("start query search: %s\n", item->path ? item->path : "");
585 836 hiro
586 836 hiro
        for (cur = mlist; cur != NULL; cur = cur->next) {
587 836 hiro
                MsgInfo *msginfo = (MsgInfo *)cur->data;
588 836 hiro
                GSList *hlist;
589 836 hiro
590 836 hiro
                g_get_current_time(&tv_cur);
591 836 hiro
                if (tv_cur.tv_sec > tv_prev.tv_sec ||
592 836 hiro
                    tv_cur.tv_usec - tv_prev.tv_usec >
593 836 hiro
                    PROGRESS_UPDATE_INTERVAL * 1000) {
594 836 hiro
                        str = g_strdup_printf(_("Searching %s (%d / %d)..."),
595 836 hiro
                                              folder_name, count, total);
596 836 hiro
                        gtk_label_set_text
597 836 hiro
                                (GTK_LABEL(search_window.status_label), str);
598 836 hiro
                        g_free(str);
599 836 hiro
                        ui_update();
600 836 hiro
                        tv_prev = tv_cur;
601 1 hiro
                }
602 836 hiro
                ++count;
603 1 hiro
604 836 hiro
                if (search_window.cancelled)
605 836 hiro
                        break;
606 836 hiro
607 836 hiro
                fltinfo.flags = msginfo->flags;
608 836 hiro
                if (search_window.requires_full_headers) {
609 836 hiro
                        gchar *file;
610 836 hiro
611 836 hiro
                        file = procmsg_get_message_file(msginfo);
612 836 hiro
                        hlist = procheader_get_header_list_from_file(file);
613 836 hiro
                        g_free(file);
614 836 hiro
                } else
615 836 hiro
                        hlist = procheader_get_header_list_from_msginfo
616 836 hiro
                                (msginfo);
617 836 hiro
                if (!hlist)
618 836 hiro
                        continue;
619 836 hiro
620 836 hiro
                if (filter_match_rule(search_window.rule, msginfo, hlist,
621 836 hiro
                                      &fltinfo)) {
622 934 hiro
                        query_search_append_msg(msginfo);
623 836 hiro
                        cur->data = NULL;
624 1 hiro
                }
625 1 hiro
626 836 hiro
                procheader_header_list_destroy(hlist);
627 1 hiro
        }
628 1 hiro
629 836 hiro
        procmsg_msg_list_free(mlist);
630 836 hiro
        g_free(folder_name);
631 836 hiro
}
632 1 hiro
633 934 hiro
static gboolean query_search_recursive_func(GNode *node, gpointer data)
634 836 hiro
{
635 836 hiro
        FolderItem *item;
636 836 hiro
637 836 hiro
        g_return_val_if_fail(node->data != NULL, FALSE);
638 836 hiro
639 836 hiro
        item = FOLDER_ITEM(node->data);
640 836 hiro
641 836 hiro
        if (!item->path)
642 836 hiro
                return FALSE;
643 928 hiro
        if (search_window.exclude_trash && item->stype == F_TRASH)
644 928 hiro
                return FALSE;
645 836 hiro
646 934 hiro
        query_search_folder(item);
647 836 hiro
648 836 hiro
        if (search_window.cancelled)
649 836 hiro
                return TRUE;
650 836 hiro
651 836 hiro
        return FALSE;
652 1 hiro
}
653 1 hiro
654 934 hiro
static void query_search_append_msg(MsgInfo *msginfo)
655 836 hiro
{
656 836 hiro
        GtkListStore *store = search_window.store;
657 836 hiro
        GtkTreeIter iter;
658 836 hiro
        gchar *folder;
659 836 hiro
        gchar date_buf[80];
660 836 hiro
        const gchar *subject, *from, *date;
661 836 hiro
        gchar *id;
662 836 hiro
663 836 hiro
        id = folder_item_get_identifier(msginfo->folder);
664 836 hiro
        folder = g_path_get_basename(id);
665 836 hiro
        g_free(id);
666 836 hiro
        subject = msginfo->subject ? msginfo->subject : _("(No Subject)");
667 836 hiro
        from = msginfo->from ? msginfo->from : _("(No From)");
668 836 hiro
        if (msginfo->date_t) {
669 836 hiro
                procheader_date_get_localtime(date_buf, sizeof(date_buf),
670 836 hiro
                                              msginfo->date_t);
671 836 hiro
                date = date_buf;
672 836 hiro
        } else if (msginfo->date)
673 836 hiro
                date = msginfo->date;
674 836 hiro
        else
675 836 hiro
                date = _("(No Date)");
676 836 hiro
677 836 hiro
        gtk_list_store_append(store, &iter);
678 836 hiro
        gtk_list_store_set(store, &iter,
679 836 hiro
                           COL_FOLDER, folder,
680 836 hiro
                           COL_SUBJECT, subject,
681 836 hiro
                           COL_FROM, from,
682 836 hiro
                           COL_DATE, date,
683 836 hiro
                           COL_MSGINFO, msginfo,
684 836 hiro
                           -1);
685 836 hiro
686 836 hiro
        g_free(folder);
687 836 hiro
}
688 836 hiro
689 934 hiro
static void query_search_clear_list(void)
690 836 hiro
{
691 836 hiro
        GtkTreeIter iter;
692 836 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(search_window.store);
693 836 hiro
        MsgInfo *msginfo;
694 836 hiro
695 1041 hiro
        gtkut_tree_sortable_unset_sort_column_id
696 1041 hiro
                (GTK_TREE_SORTABLE(search_window.store));
697 1041 hiro
698 836 hiro
        if (!gtk_tree_model_get_iter_first(model, &iter))
699 836 hiro
                return;
700 836 hiro
701 836 hiro
        do {
702 836 hiro
                gtk_tree_model_get(model, &iter, COL_MSGINFO, &msginfo, -1);
703 836 hiro
                procmsg_msginfo_free(msginfo);
704 836 hiro
        } while (gtk_tree_model_iter_next(model, &iter));
705 836 hiro
706 836 hiro
        gtk_list_store_clear(search_window.store);
707 836 hiro
}
708 836 hiro
709 934 hiro
static void query_search_hbox_added(CondHBox *hbox)
710 836 hiro
{
711 836 hiro
        g_signal_connect(hbox->key_entry, "activate",
712 934 hiro
                         G_CALLBACK(query_search_entry_activated), NULL);
713 836 hiro
}
714 836 hiro
715 836 hiro
static void row_activated(GtkTreeView *treeview, GtkTreePath *path,
716 836 hiro
                          GtkTreeViewColumn *column, gpointer data)
717 836 hiro
{
718 836 hiro
        GtkTreeIter iter;
719 836 hiro
        GtkTreeModel *model = GTK_TREE_MODEL(search_window.store);
720 836 hiro
        MsgInfo *msginfo;
721 836 hiro
        MessageView *msgview;
722 836 hiro
723 836 hiro
        if (!gtk_tree_model_get_iter(model, &iter, path))
724 836 hiro
                return;
725 836 hiro
726 836 hiro
        gtk_tree_model_get(model, &iter, COL_MSGINFO, &msginfo, -1);
727 852 hiro
        if (!summary_select_by_msginfo(main_window_get()->summaryview,
728 852 hiro
                                       msginfo)) {
729 852 hiro
                msgview = messageview_create_with_new_window();
730 852 hiro
                messageview_show(msgview, msginfo, FALSE);
731 852 hiro
        }
732 836 hiro
}
733 836 hiro
734 836 hiro
static gboolean row_selected(GtkTreeSelection *selection,
735 836 hiro
                             GtkTreeModel *model, GtkTreePath *path,
736 836 hiro
                             gboolean cur_selected, gpointer data)
737 836 hiro
{
738 836 hiro
        return TRUE;
739 836 hiro
}
740 836 hiro
741 934 hiro
static void query_search_clear(GtkButton *button, gpointer data)
742 1 hiro
{
743 836 hiro
        CondHBox *cond_hbox;
744 836 hiro
745 1041 hiro
        if (search_window.on_search)
746 1041 hiro
                return;
747 1041 hiro
748 836 hiro
        prefs_filter_edit_clear_cond_edit(search_window.cond_edit);
749 836 hiro
        prefs_filter_set_header_list(NULL);
750 836 hiro
        prefs_filter_edit_set_header_list(search_window.cond_edit, NULL);
751 836 hiro
        cond_hbox = prefs_filter_edit_cond_hbox_create(search_window.cond_edit);
752 836 hiro
        prefs_filter_edit_set_cond_hbox_widgets(cond_hbox, PF_COND_HEADER);
753 836 hiro
        prefs_filter_edit_insert_cond_hbox
754 836 hiro
                (search_window.cond_edit, cond_hbox, -1);
755 836 hiro
        if (search_window.cond_edit->add_hbox)
756 836 hiro
                search_window.cond_edit->add_hbox(cond_hbox);
757 836 hiro
758 836 hiro
        gtk_label_set_text(GTK_LABEL(search_window.status_label), "");
759 836 hiro
760 934 hiro
        query_search_clear_list();
761 1 hiro
}
762 1 hiro
763 934 hiro
static void query_select_folder(GtkButton *button, gpointer data)
764 271 hiro
{
765 836 hiro
        FolderItem *item;
766 836 hiro
        gchar *id;
767 836 hiro
768 836 hiro
        item = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL);
769 848 hiro
        if (!item || item->stype == F_VIRTUAL)
770 836 hiro
                return;
771 836 hiro
772 836 hiro
        id = folder_item_get_identifier(item);
773 836 hiro
        if (id) {
774 836 hiro
                gtk_entry_set_text(GTK_ENTRY(search_window.folder_entry), id);
775 836 hiro
                g_free(id);
776 836 hiro
        }
777 271 hiro
}
778 271 hiro
779 934 hiro
static void query_search_clicked(GtkButton *button, gpointer data)
780 271 hiro
{
781 836 hiro
        if (search_window.on_search)
782 836 hiro
                search_window.cancelled = TRUE;
783 836 hiro
        else
784 934 hiro
                query_search_query();
785 271 hiro
}
786 271 hiro
787 934 hiro
static gint query_search_save_dialog_deleted(GtkWidget *widget,
788 934 hiro
                                             GdkEventAny *event, gpointer data)
789 271 hiro
{
790 934 hiro
        QuerySearchSaveDialog *dialog = (QuerySearchSaveDialog *)data;
791 836 hiro
792 836 hiro
        dialog->cancelled = TRUE;
793 836 hiro
        dialog->finished = TRUE;
794 836 hiro
        return TRUE;
795 271 hiro
}
796 271 hiro
797 934 hiro
static gint query_search_save_dialog_key_pressed(GtkWidget *widget,
798 836 hiro
                                                   GdkEventKey *event,
799 836 hiro
                                                   gpointer data)
800 1 hiro
{
801 934 hiro
        QuerySearchSaveDialog *dialog = (QuerySearchSaveDialog *)data;
802 836 hiro
803 836 hiro
        if (event && event->keyval == GDK_Escape) {
804 836 hiro
                dialog->cancelled = TRUE;
805 836 hiro
                dialog->finished = TRUE;
806 836 hiro
        }
807 836 hiro
        return FALSE;
808 1 hiro
}
809 1 hiro
810 934 hiro
static void query_search_save_dialog_select_folder(GtkButton *button,
811 934 hiro
                                                   gpointer data)
812 1 hiro
{
813 934 hiro
        QuerySearchSaveDialog *dialog = (QuerySearchSaveDialog *)data;
814 836 hiro
        FolderItem *item;
815 836 hiro
        gchar *id;
816 836 hiro
817 836 hiro
        item = foldersel_folder_sel(NULL, FOLDER_SEL_ALL, NULL);
818 848 hiro
        if (!item || item->no_sub || item->stype == F_VIRTUAL)
819 836 hiro
                return;
820 836 hiro
821 836 hiro
        id = folder_item_get_identifier(item);
822 836 hiro
        if (id) {
823 836 hiro
                gtk_entry_set_text(GTK_ENTRY(dialog->folder_entry), id);
824 836 hiro
                g_free(id);
825 836 hiro
        }
826 1 hiro
}
827 1 hiro
828 934 hiro
static void query_search_save_activated(GtkEditable *editable, gpointer data)
829 876 hiro
{
830 934 hiro
        QuerySearchSaveDialog *dialog = (QuerySearchSaveDialog *)data;
831 876 hiro
832 876 hiro
        gtk_button_clicked(GTK_BUTTON(dialog->ok_btn));
833 876 hiro
}
834 876 hiro
835 934 hiro
static void query_search_save_ok(GtkButton *button, gpointer data)
836 1 hiro
{
837 934 hiro
        QuerySearchSaveDialog *dialog = (QuerySearchSaveDialog *)data;
838 836 hiro
839 836 hiro
        dialog->finished = TRUE;
840 1 hiro
}
841 1 hiro
842 934 hiro
static void query_search_save_cancel(GtkButton *button, gpointer data)
843 1 hiro
{
844 934 hiro
        QuerySearchSaveDialog *dialog = (QuerySearchSaveDialog *)data;
845 836 hiro
846 836 hiro
        dialog->cancelled = TRUE;
847 836 hiro
        dialog->finished = TRUE;
848 1 hiro
}
849 1 hiro
850 934 hiro
static QuerySearchSaveDialog *query_search_save_dialog_create(void)
851 836 hiro
{
852 934 hiro
        QuerySearchSaveDialog *dialog;
853 836 hiro
        GtkWidget *window;
854 836 hiro
        GtkWidget *vbox;
855 836 hiro
        GtkWidget *hbox;
856 836 hiro
        GtkWidget *label;
857 836 hiro
        GtkWidget *folder_entry;
858 836 hiro
        GtkWidget *folder_btn;
859 836 hiro
        GtkWidget *name_entry;
860 836 hiro
861 836 hiro
        GtkWidget *confirm_area;
862 836 hiro
        GtkWidget *hbbox;
863 836 hiro
        GtkWidget *cancel_btn;
864 836 hiro
        GtkWidget *ok_btn;
865 836 hiro
866 934 hiro
        dialog = g_new0(QuerySearchSaveDialog, 1);
867 836 hiro
868 836 hiro
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
869 836 hiro
        gtk_window_set_title(GTK_WINDOW(window), _("Save as search folder"));
870 836 hiro
        gtk_widget_set_size_request(window, 400, -1);
871 836 hiro
        gtk_container_set_border_width(GTK_CONTAINER(window), 8);
872 836 hiro
        gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
873 836 hiro
        gtk_window_set_modal(GTK_WINDOW(window), TRUE);
874 836 hiro
        gtk_window_set_policy(GTK_WINDOW(window), FALSE, TRUE, FALSE);
875 836 hiro
        g_signal_connect(G_OBJECT(window), "delete_event",
876 934 hiro
                         G_CALLBACK(query_search_save_dialog_deleted),
877 836 hiro
                         dialog);
878 836 hiro
        g_signal_connect(G_OBJECT(window), "key_press_event",
879 934 hiro
                         G_CALLBACK(query_search_save_dialog_key_pressed),
880 836 hiro
                         dialog);
881 836 hiro
        MANAGE_WINDOW_SIGNALS_CONNECT(window);
882 836 hiro
        manage_window_set_transient(GTK_WINDOW(window));
883 836 hiro
884 836 hiro
        vbox = gtk_vbox_new(FALSE, 8);
885 836 hiro
        gtk_container_add(GTK_CONTAINER(window), vbox);
886 836 hiro
887 836 hiro
        hbox = gtk_hbox_new(FALSE, 8);
888 836 hiro
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
889 836 hiro
890 836 hiro
        label = gtk_label_new(_("Location:"));
891 836 hiro
        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
892 836 hiro
893 836 hiro
        folder_entry = gtk_entry_new();
894 836 hiro
        gtk_box_pack_start(GTK_BOX(hbox), folder_entry, TRUE, TRUE, 0);
895 836 hiro
896 836 hiro
        folder_btn = gtk_button_new_with_label("...");
897 836 hiro
        gtk_box_pack_start(GTK_BOX(hbox), folder_btn, FALSE, FALSE, 0);
898 836 hiro
        g_signal_connect(G_OBJECT(folder_btn), "clicked",
899 934 hiro
                         G_CALLBACK(query_search_save_dialog_select_folder),
900 836 hiro
                         dialog);
901 836 hiro
902 836 hiro
        hbox = gtk_hbox_new(FALSE, 8);
903 836 hiro
        gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
904 836 hiro
905 836 hiro
        label = gtk_label_new(_("Folder name:"));
906 836 hiro
        gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
907 836 hiro
908 836 hiro
        name_entry = gtk_entry_new();
909 836 hiro
        gtk_box_pack_start(GTK_BOX(hbox), name_entry, TRUE, TRUE, 0);
910 876 hiro
        g_signal_connect(G_OBJECT(name_entry), "activate",
911 934 hiro
                         G_CALLBACK(query_search_save_activated), dialog);
912 836 hiro
913 836 hiro
        confirm_area = gtk_hbox_new(FALSE, 12);
914 836 hiro
        gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
915 836 hiro
916 836 hiro
        gtkut_stock_button_set_create(&hbbox,
917 836 hiro
                                      &ok_btn, GTK_STOCK_OK,
918 836 hiro
                                      &cancel_btn, GTK_STOCK_CANCEL,
919 836 hiro
                                      NULL, NULL);
920 836 hiro
        gtk_box_pack_end(GTK_BOX(confirm_area), hbbox, FALSE, FALSE, 0);
921 837 hiro
        GTK_WIDGET_SET_FLAGS(ok_btn, GTK_CAN_DEFAULT);
922 837 hiro
        gtk_widget_grab_default(ok_btn);
923 836 hiro
        g_signal_connect(G_OBJECT(ok_btn), "clicked",
924 934 hiro
                         G_CALLBACK(query_search_save_ok), dialog);
925 836 hiro
        g_signal_connect(G_OBJECT(cancel_btn), "clicked",
926 934 hiro
                         G_CALLBACK(query_search_save_cancel), dialog);
927 836 hiro
928 837 hiro
        gtk_widget_grab_focus(name_entry);
929 837 hiro
930 836 hiro
        gtk_widget_show_all(window);
931 836 hiro
932 836 hiro
        dialog->window = window;
933 836 hiro
        dialog->folder_entry = folder_entry;
934 836 hiro
        dialog->name_entry = name_entry;
935 876 hiro
        dialog->ok_btn = ok_btn;
936 876 hiro
        dialog->cancel_btn = cancel_btn;
937 836 hiro
        dialog->cancelled = FALSE;
938 836 hiro
        dialog->finished = FALSE;
939 836 hiro
940 836 hiro
        return dialog;
941 836 hiro
}
942 836 hiro
943 934 hiro
static void query_search_save_dialog_destroy(QuerySearchSaveDialog *dialog)
944 836 hiro
{
945 836 hiro
        gtk_widget_destroy(dialog->window);
946 836 hiro
        g_free(dialog);
947 836 hiro
}
948 836 hiro
949 934 hiro
static FolderItem *query_search_create_vfolder(FolderItem *parent,
950 934 hiro
                                               const gchar *name)
951 836 hiro
{
952 836 hiro
        gchar *path;
953 836 hiro
        gchar *fs_name;
954 836 hiro
        gchar *fullpath;
955 836 hiro
        FolderItem *item;
956 836 hiro
957 836 hiro
        g_return_val_if_fail(parent != NULL, NULL);
958 836 hiro
        g_return_val_if_fail(name != NULL, NULL);
959 836 hiro
960 836 hiro
        path = folder_item_get_path(parent);
961 836 hiro
        fs_name = g_filename_from_utf8(name, -1, NULL, NULL, NULL);
962 836 hiro
        fullpath = g_strconcat(path, G_DIR_SEPARATOR_S,
963 836 hiro
                               fs_name ? fs_name : name, NULL);
964 836 hiro
        g_free(fs_name);
965 836 hiro
        g_free(path);
966 836 hiro
967 836 hiro
        if (make_dir_hier(fullpath) < 0) {
968 836 hiro
                g_free(fullpath);
969 836 hiro
                return NULL;
970 836 hiro
        }
971 836 hiro
972 836 hiro
        if (parent->path)
973 836 hiro
                path = g_strconcat(parent->path, G_DIR_SEPARATOR_S, name, NULL);
974 836 hiro
        else
975 836 hiro
                path = g_strdup(name);
976 836 hiro
977 836 hiro
        item = folder_item_new(name, path);
978 836 hiro
        item->stype = F_VIRTUAL;
979 848 hiro
        item->no_sub = TRUE;
980 836 hiro
        folder_item_append(parent, item);
981 836 hiro
982 836 hiro
        g_free(path);
983 836 hiro
984 836 hiro
        return item;
985 836 hiro
}
986 836 hiro
987 934 hiro
static void query_search_vfolder_update_rule(FolderItem *item)
988 836 hiro
{
989 836 hiro
        GSList list;
990 836 hiro
        FilterRule *rule;
991 836 hiro
        gchar *file;
992 836 hiro
        gchar *path;
993 836 hiro
994 934 hiro
        rule = query_search_dialog_to_rule(item->name, NULL);
995 836 hiro
        list.data = rule;
996 836 hiro
        list.next = NULL;
997 836 hiro
998 836 hiro
        path = folder_item_get_path(item);
999 836 hiro
        file = g_strconcat(path, G_DIR_SEPARATOR_S, FILTER_LIST, NULL);
1000 836 hiro
        filter_write_file(&list, file);
1001 836 hiro
        g_free(file);
1002 836 hiro
        g_free(path);
1003 836 hiro
1004 836 hiro
        filter_rule_free(rule);
1005 836 hiro
}
1006 836 hiro
1007 934 hiro
static void query_search_save(GtkButton *button, gpointer data)
1008 836 hiro
{
1009 934 hiro
        QuerySearchSaveDialog *dialog;
1010 837 hiro
        const gchar *id, *name;
1011 837 hiro
        FolderItem *parent, *item;
1012 836 hiro
1013 934 hiro
        dialog = query_search_save_dialog_create();
1014 837 hiro
        id = gtk_entry_get_text(GTK_ENTRY(search_window.folder_entry));
1015 837 hiro
        if (id && *id)
1016 837 hiro
                gtk_entry_set_text(GTK_ENTRY(dialog->folder_entry), id);
1017 836 hiro
1018 836 hiro
        while (!dialog->finished)
1019 836 hiro
                gtk_main_iteration();
1020 836 hiro
1021 837 hiro
        if (dialog->cancelled) {
1022 934 hiro
                query_search_save_dialog_destroy(dialog);
1023 837 hiro
                return;
1024 837 hiro
        }
1025 836 hiro
1026 837 hiro
        id = gtk_entry_get_text(GTK_ENTRY(dialog->folder_entry));
1027 837 hiro
        parent = folder_find_item_from_identifier(id);
1028 837 hiro
        name = gtk_entry_get_text(GTK_ENTRY(dialog->name_entry));
1029 837 hiro
        if (parent && name && *name) {
1030 837 hiro
                if (folder_find_child_item_by_name(parent, name)) {
1031 837 hiro
                        alertpanel_error(_("The folder `%s' already exists."),
1032 836 hiro
                                         name);
1033 837 hiro
                } else {
1034 934 hiro
                        item = query_search_create_vfolder(parent, name);
1035 837 hiro
                        if (item) {
1036 934 hiro
                                query_search_vfolder_update_rule(item);
1037 837 hiro
                                folderview_append_item(folderview_get(),
1038 837 hiro
                                                       NULL, item, TRUE);
1039 837 hiro
                                folder_write_list();
1040 836 hiro
                        }
1041 836 hiro
                }
1042 836 hiro
        }
1043 836 hiro
1044 934 hiro
        query_search_save_dialog_destroy(dialog);
1045 836 hiro
}
1046 836 hiro
1047 934 hiro
static void query_search_close(GtkButton *button, gpointer data)
1048 836 hiro
{
1049 836 hiro
        if (search_window.on_search)
1050 836 hiro
                search_window.cancelled = TRUE;
1051 836 hiro
        gtk_widget_hide(search_window.window);
1052 836 hiro
}
1053 836 hiro
1054 934 hiro
static void query_search_entry_activated(GtkWidget *widget, gpointer data)
1055 836 hiro
{
1056 836 hiro
        gtk_button_clicked(GTK_BUTTON(search_window.search_btn));
1057 836 hiro
}
1058 836 hiro
1059 934 hiro
static gint query_search_deleted(GtkWidget *widget, GdkEventAny *event,
1060 934 hiro
                                 gpointer data)
1061 836 hiro
{
1062 836 hiro
        gtk_button_clicked(GTK_BUTTON(search_window.close_btn));
1063 836 hiro
        return TRUE;
1064 836 hiro
}
1065 836 hiro
1066 1 hiro
static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
1067 1 hiro
                            gpointer data)
1068 1 hiro
{
1069 836 hiro
        if (event && event->keyval == GDK_Escape) {
1070 836 hiro
                if (search_window.on_search)
1071 836 hiro
                        gtk_button_clicked
1072 836 hiro
                                (GTK_BUTTON(search_window.search_btn));
1073 836 hiro
                else
1074 836 hiro
                        gtk_button_clicked(GTK_BUTTON(search_window.close_btn));
1075 836 hiro
                return TRUE;
1076 836 hiro
        }
1077 1 hiro
        return FALSE;
1078 1 hiro
}
1079 1041 hiro
1080 1041 hiro
static gint query_search_cmp_by_folder(GtkTreeModel *model,
1081 1041 hiro
                                       GtkTreeIter *a, GtkTreeIter *b,
1082 1041 hiro
                                       gpointer data)
1083 1041 hiro
{
1084 1041 hiro
        gchar *folder_a = NULL, *folder_b = NULL;
1085 1041 hiro
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1086 1041 hiro
        gint ret;
1087 1041 hiro
1088 1041 hiro
        gtk_tree_model_get(model, a, COL_FOLDER, &folder_a, COL_MSGINFO,
1089 1041 hiro
                           &msginfo_a, -1);
1090 1041 hiro
        gtk_tree_model_get(model, b, COL_FOLDER, &folder_b, COL_MSGINFO,
1091 1041 hiro
                           &msginfo_b, -1);
1092 1041 hiro
1093 1041 hiro
        if (!folder_a || !folder_b || !msginfo_a || !msginfo_b)
1094 1041 hiro
                return 0;
1095 1041 hiro
1096 1041 hiro
        ret = g_ascii_strcasecmp(folder_a, folder_b);
1097 1041 hiro
        return (ret != 0) ? ret : (msginfo_a->date_t - msginfo_b->date_t);
1098 1041 hiro
}
1099 1041 hiro
1100 1041 hiro
static gint query_search_cmp_by_subject(GtkTreeModel *model,
1101 1041 hiro
                                        GtkTreeIter *a, GtkTreeIter *b,
1102 1041 hiro
                                        gpointer data)
1103 1041 hiro
{
1104 1041 hiro
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1105 1041 hiro
        gint ret;
1106 1041 hiro
1107 1041 hiro
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1108 1041 hiro
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1109 1041 hiro
1110 1041 hiro
        if (!msginfo_a || !msginfo_b)
1111 1041 hiro
                return 0;
1112 1041 hiro
1113 1041 hiro
        if (!msginfo_a->subject)
1114 1041 hiro
                return -(msginfo_b->subject != NULL);
1115 1041 hiro
        if (!msginfo_b->subject)
1116 1041 hiro
                return (msginfo_a->subject != NULL);
1117 1041 hiro
1118 1041 hiro
        ret = subject_compare_for_sort(msginfo_a->subject, msginfo_b->subject);
1119 1041 hiro
        return (ret != 0) ? ret : (msginfo_a->date_t - msginfo_b->date_t);
1120 1041 hiro
}
1121 1041 hiro
1122 1041 hiro
static gint query_search_cmp_by_from(GtkTreeModel *model,
1123 1041 hiro
                                     GtkTreeIter *a, GtkTreeIter *b,
1124 1041 hiro
                                     gpointer data)
1125 1041 hiro
{
1126 1041 hiro
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1127 1041 hiro
        gint ret;
1128 1041 hiro
1129 1041 hiro
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1130 1041 hiro
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1131 1041 hiro
1132 1041 hiro
        if (!msginfo_a || !msginfo_b)
1133 1041 hiro
                return 0;
1134 1041 hiro
1135 1041 hiro
        if (!msginfo_a->fromname)
1136 1041 hiro
                return -(msginfo_b->fromname != NULL);
1137 1041 hiro
        if (!msginfo_b->fromname)
1138 1041 hiro
                return (msginfo_a->fromname != NULL);
1139 1041 hiro
1140 1041 hiro
        ret = g_ascii_strcasecmp(msginfo_a->fromname, msginfo_b->fromname);
1141 1041 hiro
        return (ret != 0) ? ret : (msginfo_a->date_t - msginfo_b->date_t);
1142 1041 hiro
}
1143 1041 hiro
1144 1041 hiro
static gint query_search_cmp_by_date(GtkTreeModel *model,
1145 1041 hiro
                                     GtkTreeIter *a, GtkTreeIter *b,
1146 1041 hiro
                                     gpointer data)
1147 1041 hiro
{
1148 1041 hiro
        MsgInfo *msginfo_a = NULL, *msginfo_b = NULL;
1149 1041 hiro
1150 1041 hiro
        gtk_tree_model_get(model, a, COL_MSGINFO, &msginfo_a, -1);
1151 1041 hiro
        gtk_tree_model_get(model, b, COL_MSGINFO, &msginfo_b, -1);
1152 1041 hiro
1153 1041 hiro
        if (!msginfo_a || !msginfo_b)
1154 1041 hiro
                return 0;
1155 1041 hiro
1156 1041 hiro
        return msginfo_a->date_t - msginfo_b->date_t;
1157 1041 hiro
}