new frontend - FUSE
[mediadatabase.git] / gtk / search.c
blobdddd33ba87fd3eabef472704d9d67d27231298c7
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * $Id: search.c,v 1.6 2005/02/19 13:39:20 nedko Exp $
6 * DESCRIPTION:
7 *
9 * NOTES:
12 *****************************************************************************/
14 #include <limits.h>
15 #include <stdlib.h>
16 #include <time.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <gtk/gtk.h>
21 /* ULLONG_MAX should come from limits.h but doesn't */
22 #if !defined(ULLONG_MAX) && defined(ULONG_LONG_MAX)
23 # define ULLONG_MAX ULONG_LONG_MAX
24 #endif
26 #include "../result.h"
27 #include "../libdb/libdb.h"
28 #include "../libfrontend/db.h"
29 #include "common.h"
30 #include "search.h"
31 #include "helper.h"
32 #include "path.h"
33 #include "glade.h"
35 enum
37 COL_ICON,
38 COL_NAME,
39 COL_SIZE,
40 COL_TIME,
41 COL_MEDIAID,
42 COL_MEDIAICON,
43 COL_MEDIANAME,
44 COL_MEDIALOCATION,
45 NUM_COLS
48 #define KEY_PREFIX "mediadatabase_file_search_"
49 #define KEY_FILENAME KEY_PREFIX "filename"
50 #define KEY_FILENAME_PMM KEY_PREFIX "filename_pmm"
51 #define KEY_PATH KEY_PREFIX "path"
52 #define KEY_PATH_PMM KEY_PREFIX "path_pmm"
53 #define KEY_MIN_SIZE KEY_PREFIX "min_size"
54 #define KEY_MIN_SIZE_UNITS KEY_PREFIX "min_size_units"
55 #define KEY_MAX_SIZE KEY_PREFIX "max_size"
56 #define KEY_MAX_SIZE_UNITS KEY_PREFIX "max_size_units"
57 #define KEY_PMM KEY_PREFIX "pmm"
58 #define KEY_STORE KEY_PREFIX "store"
60 void
61 SearchCallback(
62 void *pUserContext,
63 mediadb_uint nMediaID,
64 mediadb_mediatype nMediaType,
65 const char *pszMediaName,
66 const char *pszMediaLocation,
67 const char *pszPath,
68 const char *pszName,
69 mediadb_filetype Filetype,
70 mediadb_uint nSize,
71 mediadb_uint nTime)
73 struct tm tm;
74 GdkPixbuf * pIcon;
75 GdkPixbuf * pMediaIcon;
76 time_t time = nTime;
77 GtkTreeIter Iter;
78 char strTime[26];
79 GError * error = NULL;
80 char * pszIcon;
81 char strSize[MAX_SIZE_DESCRIPTION];
82 char *pszFullPath;
83 gchar * pszIconFullname;
85 pszFullPath = g_malloc(strlen(pszPath)+strlen(pszName)+1);
86 sprintf(pszFullPath, "%s%s", pszPath, pszName);
88 localtime_r(&time, &tm);
89 sprintf(strTime,
90 "%u-%02u-%02u %02u:%02u:%02u",
91 1900+tm.tm_year,
92 1+tm.tm_mon,
93 tm.tm_mday,
94 tm.tm_hour,
95 tm.tm_min,
96 tm.tm_sec);
98 get_size_description(nSize, strSize);
100 pIcon = NULL;
102 if (Filetype == MEDIADB_FILETYPE_DIR)
104 pszIcon = "icon_folder.png";
106 else
108 pszIcon = "icon_unknown.png";
111 pszIconFullname = path_get_data_filename(pszIcon);
112 if (pszIconFullname != NULL)
114 pIcon = gdk_pixbuf_new_from_file(pszIconFullname, &error);
115 if (error)
117 g_warning("Could not load icon: %s\n", error->message);
118 g_error_free(error);
119 error = NULL;
122 g_free(pszIconFullname);
124 else
126 g_warning("Could not find icon %s\n", pszIcon);
129 pszIcon = "icon_cd.png";
131 pszIconFullname = path_get_data_filename(pszIcon);
132 if (pszIconFullname != NULL)
134 pMediaIcon = gdk_pixbuf_new_from_file(pszIconFullname, &error);
135 if (error)
137 g_warning("Could not load icon: %s\n", error->message);
138 g_error_free(error);
139 error = NULL;
142 g_free(pszIconFullname);
144 else
146 g_warning("Could not find icon %s\n", pszIcon);
149 gtk_list_store_append(
150 GTK_LIST_STORE(
151 g_object_get_data(
152 G_OBJECT(pUserContext),
153 KEY_STORE)),
154 &Iter);
156 gtk_list_store_set(
157 GTK_LIST_STORE(
158 g_object_get_data(
159 G_OBJECT(pUserContext),
160 KEY_STORE)),
161 &Iter,
162 COL_ICON, pIcon,
163 COL_NAME, pszFullPath,
164 COL_SIZE, (Filetype == MEDIADB_FILETYPE_DIR)?NULL:strSize,
165 COL_TIME, strTime,
166 COL_MEDIAID, (unsigned int)nMediaID,
167 COL_MEDIAICON, pMediaIcon,
168 COL_MEDIANAME, pszMediaName,
169 COL_MEDIALOCATION, pszMediaLocation,
170 -1);
172 g_free(pszFullPath);
175 void
176 DoSearch(
177 GtkEntry *pEntry,
178 gpointer pUserData)
180 GtkWidget *pDialog;
181 const char *pszFilename;
182 gint nFilenamePMMIndex;
183 const char *pszPath;
184 gint nPathPMMIndex;
185 const char *pszMinSize;
186 gint nMinSizeUnits;
187 const char *pszMaxSize;
188 gint nMaxSizeUnits;
189 const struct mediadb_pattern_match_method *pPMM;
190 mediadb_uint nMinSize;
191 mediadb_uint nMaxSize;
192 char *pchEnd;
193 mediadb_result r;
195 pPMM = (const struct mediadb_pattern_match_method *)g_object_get_data(
196 G_OBJECT(pUserData),
197 KEY_PMM);
199 pszFilename = gtk_entry_get_text(
200 GTK_ENTRY(
201 g_object_get_data(
202 G_OBJECT(pUserData),
203 KEY_FILENAME)));
205 nFilenamePMMIndex = gtk_combo_box_get_active(
206 GTK_COMBO_BOX(
207 g_object_get_data(
208 G_OBJECT(pUserData),
209 KEY_FILENAME_PMM)));
211 pszPath = gtk_entry_get_text(
212 GTK_ENTRY(
213 g_object_get_data(
214 G_OBJECT(pUserData),
215 KEY_PATH)));
217 nPathPMMIndex = gtk_combo_box_get_active(
218 GTK_COMBO_BOX(
219 g_object_get_data(
220 G_OBJECT(pUserData),
221 KEY_PATH_PMM)));
223 pszMinSize = gtk_entry_get_text(
224 GTK_ENTRY(
225 g_object_get_data(
226 G_OBJECT(pUserData),
227 KEY_MIN_SIZE)));
229 nMinSizeUnits = gtk_combo_box_get_active(
230 GTK_COMBO_BOX(
231 g_object_get_data(
232 G_OBJECT(pUserData),
233 KEY_MIN_SIZE_UNITS)));
235 pszMaxSize = gtk_entry_get_text(
236 GTK_ENTRY(
237 g_object_get_data(
238 G_OBJECT(pUserData),
239 KEY_MAX_SIZE)));
241 nMaxSizeUnits = gtk_combo_box_get_active(
242 GTK_COMBO_BOX(
243 g_object_get_data(
244 G_OBJECT(pUserData),
245 KEY_MAX_SIZE_UNITS)));
247 /* We better handle such thing in backend
248 if (*pszFilename == 0 &&
249 *pszPath == 0 &&
250 *pszMinSize == 0 &&
251 *pszMaxSize == 0)
253 pDialog = gtk_message_dialog_new(
254 GTK_WINDOW(pUserData),
255 GTK_DIALOG_DESTROY_WITH_PARENT,
256 GTK_MESSAGE_ERROR,
257 GTK_BUTTONS_CLOSE,
258 "No search criteria ...\n");
260 gtk_dialog_run(GTK_DIALOG(pDialog));
261 gtk_widget_destroy(pDialog);
263 return;
267 if (*pszMinSize &&
268 *pszMaxSize &&
269 nMinSizeUnits > nMaxSizeUnits)
271 pDialog = gtk_message_dialog_new(
272 GTK_WINDOW(pUserData),
273 GTK_DIALOG_DESTROY_WITH_PARENT,
274 GTK_MESSAGE_ERROR,
275 GTK_BUTTONS_CLOSE,
276 "Min size units (%s) are bigger than max size units (%s).",
277 g_arrSizeUnits[nMinSizeUnits].pszUnitsName,
278 g_arrSizeUnits[nMaxSizeUnits].pszUnitsName);
280 gtk_dialog_run(GTK_DIALOG(pDialog));
281 gtk_widget_destroy(pDialog);
283 return;
286 if (*pszMinSize)
288 nMinSize = strtoull(pszMinSize, &pchEnd, 10);
289 if (nMinSize == 0 || nMinSize == ULLONG_MAX || *pchEnd)
291 pDialog = gtk_message_dialog_new(
292 GTK_WINDOW(pUserData),
293 GTK_DIALOG_DESTROY_WITH_PARENT,
294 GTK_MESSAGE_ERROR,
295 GTK_BUTTONS_CLOSE,
296 "Cannot convert \"%s\" to decimal integer number.",
297 pszMinSize);
299 gtk_dialog_run(GTK_DIALOG(pDialog));
300 gtk_widget_destroy(pDialog);
302 return;
305 if (ULLONG_MAX / g_arrSizeUnits[nMinSizeUnits].nUnitSize < nMinSize)
307 pDialog = gtk_message_dialog_new(
308 GTK_WINDOW(pUserData),
309 GTK_DIALOG_DESTROY_WITH_PARENT,
310 GTK_MESSAGE_ERROR,
311 GTK_BUTTONS_CLOSE,
312 "%llu %s is too large number.",
313 nMinSize,
314 g_arrSizeUnits[nMinSizeUnits].pszUnitsName);
316 gtk_dialog_run(GTK_DIALOG(pDialog));
317 gtk_widget_destroy(pDialog);
319 return;
322 nMinSize = nMinSize * g_arrSizeUnits[nMinSizeUnits].nUnitSize;
325 if (*pszMaxSize)
327 nMaxSize = strtoull(pszMaxSize, &pchEnd, 10);
328 if (nMaxSize == 0 || nMaxSize == ULLONG_MAX || *pchEnd)
330 pDialog = gtk_message_dialog_new(
331 GTK_WINDOW(pUserData),
332 GTK_DIALOG_DESTROY_WITH_PARENT,
333 GTK_MESSAGE_ERROR,
334 GTK_BUTTONS_CLOSE,
335 "Cannot convert \"%s\" to decimal integer number.",
336 pszMaxSize);
338 gtk_dialog_run(GTK_DIALOG(pDialog));
339 gtk_widget_destroy(pDialog);
341 return;
344 if (ULLONG_MAX / g_arrSizeUnits[nMaxSizeUnits].nUnitSize < nMaxSize)
346 pDialog = gtk_message_dialog_new(
347 GTK_WINDOW(pUserData),
348 GTK_DIALOG_DESTROY_WITH_PARENT,
349 GTK_MESSAGE_ERROR,
350 GTK_BUTTONS_CLOSE,
351 "%llu %s is too large number.",
352 nMaxSize,
353 g_arrSizeUnits[nMaxSizeUnits].pszUnitsName);
355 gtk_dialog_run(GTK_DIALOG(pDialog));
356 gtk_widget_destroy(pDialog);
358 return;
361 nMaxSize = nMaxSize * g_arrSizeUnits[nMaxSizeUnits].nUnitSize;
364 pDialog = gtk_message_dialog_new(
365 GTK_WINDOW(pUserData),
366 GTK_DIALOG_DESTROY_WITH_PARENT,
367 GTK_MESSAGE_INFO,
368 GTK_BUTTONS_CLOSE,
369 "Searching ...\n"
370 "%s%s%s%s%s"
371 "%s%s%s%s%s"
372 "%s%s%s%s%s"
373 "%s%s%s%s%s",
374 *pszFilename?"Filename \"":"",
375 *pszFilename?pszFilename:"",
376 *pszFilename?"\" - ":"",
377 *pszFilename?pPMM[nFilenamePMMIndex].pszDescription:"",
378 *pszFilename?"\n":"",
379 *pszPath?"Path \"":"",
380 *pszPath?pszPath:"",
381 *pszPath?"\" - ":"",
382 *pszPath?pPMM[nPathPMMIndex].pszDescription:"",
383 *pszPath?"\n":"",
384 *pszMinSize?"Min size ":"",
385 *pszMinSize?pszMinSize:"",
386 *pszMinSize?" ":"",
387 *pszMinSize?g_arrSizeUnits[nMinSizeUnits].pszUnitsName:"",
388 *pszMinSize?"\n":"",
389 *pszMaxSize?"Max size ":"",
390 *pszMaxSize?pszMaxSize:"",
391 *pszMaxSize?" ":"",
392 *pszMaxSize?g_arrSizeUnits[nMaxSizeUnits].pszUnitsName:"",
393 *pszMaxSize?"\n":"");
395 gtk_dialog_run(GTK_DIALOG(pDialog));
396 gtk_widget_destroy(pDialog);
398 gtk_list_store_clear(
399 GTK_LIST_STORE(
400 g_object_get_data(
401 G_OBJECT(pUserData),
402 KEY_STORE)));
404 r = mediadb_files_search(
405 g_hDB,
406 *pszFilename?pPMM[nFilenamePMMIndex].nID:MEDIADB_PMM_NULL,
407 *pszFilename?pszFilename:NULL,
408 *pszPath?pPMM[nPathPMMIndex].nID:MEDIADB_PMM_NULL,
409 *pszPath?pszPath:NULL,
410 *pszMinSize?&nMinSize:NULL,
411 *pszMaxSize?&nMaxSize:NULL,
412 SearchCallback,
413 pUserData);
414 if (MEDIADB_IS_ERROR(r))
416 display_error_message_mediadb(GTK_WINDOW(pUserData));
417 return;
421 void
422 ShowSearchWindow()
424 GtkWidget *pSearchWindow;
425 GtkWidget *pChild;
426 GtkCellRenderer * pRendererText;
427 GtkCellRenderer * pRendererPixbuf;
428 GtkTreeViewColumn * pColumn;
429 GtkListStore *pListStore;
430 const struct mediadb_pattern_match_method *pPMM;
431 mediadb_result r;
432 unsigned int i, j;
434 r = mediadb_get_pattern_match_methods(
435 g_hDB,
436 &pPMM);
437 if (MEDIADB_IS_ERROR(r))
439 display_error_message_mediadb(GTK_WINDOW(pMainWindow));
440 return;
443 pSearchWindow = construct_glade_widget("search_window");
445 g_object_set_data(G_OBJECT(pSearchWindow), KEY_PMM, (gpointer)pPMM);
448 pChild = get_glade_widget_child(pSearchWindow, "search_window_filename_entry");
450 g_signal_connect(
451 pChild,
452 "activate",
453 (GCallback)DoSearch,
454 pSearchWindow);
456 g_object_set_data(G_OBJECT(pSearchWindow), KEY_FILENAME, pChild);
460 pChild = get_glade_widget_child(pSearchWindow, "search_window_filename_pmm");
461 setup_text_combo(pChild);
463 i = 0;
465 while (pPMM[i].nID != MEDIADB_PMM_NULL)
467 gtk_combo_box_append_text(GTK_COMBO_BOX(pChild), pPMM[i].pszName);
468 i++;
471 gtk_combo_box_set_active(GTK_COMBO_BOX(pChild), 0);
473 g_object_set_data(G_OBJECT(pSearchWindow), KEY_FILENAME_PMM, pChild);
477 pChild = get_glade_widget_child(pSearchWindow, "search_window_path_entry");
479 g_signal_connect(
480 pChild,
481 "activate",
482 (GCallback)DoSearch,
483 pSearchWindow);
485 g_object_set_data(G_OBJECT(pSearchWindow), KEY_PATH, pChild);
489 pChild = get_glade_widget_child(pSearchWindow, "search_window_path_pmm");
490 setup_text_combo(pChild);
492 i = 0;
494 while (pPMM[i].nID != MEDIADB_PMM_NULL)
496 gtk_combo_box_append_text(GTK_COMBO_BOX(pChild), pPMM[i].pszName);
497 i++;
500 gtk_combo_box_set_active(GTK_COMBO_BOX(pChild), 0);
502 g_object_set_data(G_OBJECT(pSearchWindow), KEY_PATH_PMM, pChild);
506 pChild = get_glade_widget_child(pSearchWindow, "search_window_min_size_entry");
508 g_signal_connect(
509 pChild,
510 "activate",
511 (GCallback)DoSearch,
512 pSearchWindow);
514 g_object_set_data(G_OBJECT(pSearchWindow), KEY_MIN_SIZE, pChild);
518 pChild = get_glade_widget_child(pSearchWindow, "search_window_min_size_units");
519 setup_text_combo(pChild);
521 i = j = 0;
523 while (g_arrSizeUnits[i].nUnitSize != 0)
525 if (i == 1)
527 /* Second entry should be kilobytes */
528 j = i;
531 gtk_combo_box_append_text(GTK_COMBO_BOX(pChild), g_arrSizeUnits[i].pszUnitsName);
533 i++;
536 gtk_combo_box_set_active(GTK_COMBO_BOX(pChild), j);
538 g_object_set_data(G_OBJECT(pSearchWindow), KEY_MIN_SIZE_UNITS, pChild);
542 pChild = get_glade_widget_child(pSearchWindow, "search_window_max_size_entry");
544 g_signal_connect(
545 pChild,
546 "activate",
547 (GCallback)DoSearch,
548 pSearchWindow);
550 g_object_set_data(G_OBJECT(pSearchWindow), KEY_MAX_SIZE, pChild);
554 pChild = get_glade_widget_child(pSearchWindow, "search_window_max_size_units");
555 setup_text_combo(pChild);
557 i = j = 0;
559 while (g_arrSizeUnits[i].nUnitSize != 0)
561 if (i == 1)
563 /* Second entry should be kilobytes */
564 j = i;
567 gtk_combo_box_append_text(GTK_COMBO_BOX(pChild), g_arrSizeUnits[i].pszUnitsName);
569 i++;
572 gtk_combo_box_set_active(GTK_COMBO_BOX(pChild), j);
574 g_object_set_data(G_OBJECT(pSearchWindow), KEY_MAX_SIZE_UNITS, pChild);
578 pChild = get_glade_widget_child(pSearchWindow, "search_window_button_find");
580 g_signal_connect(
581 pChild,
582 "clicked",
583 (GCallback)DoSearch,
584 pSearchWindow);
587 /* Tree view setup */
588 pChild = get_glade_widget_child(pSearchWindow, "treeview");
590 pRendererText = gtk_cell_renderer_text_new();
591 pRendererPixbuf = gtk_cell_renderer_pixbuf_new();
593 /* --- Column #1 --- */
595 pColumn = gtk_tree_view_column_new();
596 gtk_tree_view_column_set_title(pColumn, "Name");
598 gtk_tree_view_column_pack_start(pColumn, pRendererPixbuf, FALSE);
599 gtk_tree_view_column_set_attributes(pColumn, pRendererPixbuf,
600 "pixbuf", COL_ICON,
601 NULL);
603 gtk_tree_view_column_pack_start(pColumn, pRendererText, TRUE);
604 gtk_tree_view_column_set_attributes(pColumn,
605 pRendererText,
606 "text", COL_NAME,
607 NULL);
609 gtk_tree_view_append_column(
610 GTK_TREE_VIEW(pChild),
611 pColumn);
613 /* --- Column #2 --- */
615 pColumn = gtk_tree_view_column_new_with_attributes(
616 "Size",
617 pRendererText,
618 "text", COL_SIZE,
619 NULL);
621 gtk_tree_view_append_column(
622 GTK_TREE_VIEW(pChild),
623 pColumn);
625 /* --- Column #3 --- */
627 pColumn = gtk_tree_view_column_new_with_attributes(
628 "Time",
629 pRendererText,
630 "text", COL_TIME,
631 NULL);
633 gtk_tree_view_append_column(
634 GTK_TREE_VIEW(pChild),
635 pColumn);
637 /* --- Column #4 --- */
639 pColumn = gtk_tree_view_column_new_with_attributes(
640 "MediaID",
641 pRendererText,
642 "text", COL_MEDIAID,
643 NULL);
645 gtk_tree_view_append_column(
646 GTK_TREE_VIEW(pChild),
647 pColumn);
649 /* --- Column #5 --- */
651 pColumn = gtk_tree_view_column_new();
653 gtk_tree_view_column_set_title(
654 pColumn,
655 "MediaName");
657 gtk_tree_view_column_pack_start(
658 pColumn,
659 pRendererPixbuf,
660 FALSE);
662 gtk_tree_view_column_set_attributes(
663 pColumn,
664 pRendererPixbuf,
665 "pixbuf",
666 COL_MEDIAICON,
667 NULL);
669 gtk_tree_view_column_pack_end(
670 pColumn,
671 pRendererText,
672 TRUE);
674 gtk_tree_view_column_set_attributes(
675 pColumn,
676 pRendererText,
677 "text", COL_MEDIANAME,
678 NULL);
680 gtk_tree_view_append_column(
681 GTK_TREE_VIEW(pChild),
682 pColumn);
684 /* --- Column #6 --- */
686 pColumn = gtk_tree_view_column_new_with_attributes(
687 "Location",
688 pRendererText,
689 "text", COL_MEDIALOCATION,
690 NULL);
692 gtk_tree_view_append_column(
693 GTK_TREE_VIEW(pChild),
694 pColumn);
696 /* Create the store */
697 pListStore = gtk_list_store_new(
698 NUM_COLS,
699 GDK_TYPE_PIXBUF, /* COL_ICON */
700 G_TYPE_STRING, /* COL_NAME */
701 G_TYPE_STRING, /* COL_SIZE */
702 G_TYPE_STRING, /* COL_TIME */
703 G_TYPE_UINT, /* COL_MEDIAID */
704 GDK_TYPE_PIXBUF, /* COL_MEDIAICON */
705 G_TYPE_STRING, /* COL_MEDIANAME */
706 G_TYPE_STRING); /* COL_MEDIALOCATION */
708 /* Set model */
709 gtk_tree_view_set_model(GTK_TREE_VIEW(pChild), GTK_TREE_MODEL(pListStore));
711 g_object_set_data(G_OBJECT(pSearchWindow), KEY_STORE, pListStore);
713 gtk_widget_show_all(pSearchWindow);
716 /*****************************************************************************
718 * Modifications log:
720 * !!! WARNING !!! Following lines are automatically updated by the CVS system.
722 * $Log: search.c,v $
723 * Revision 1.6 2005/02/19 13:39:20 nedko
724 * Switch search window to glade.
726 * Revision 1.5 2005/02/18 02:12:08 nedko
727 * Use path module to access project specific data files.
729 * Revision 1.4 2004/09/18 21:34:59 nedko
730 * Return media name, media type and media location when searching files.
732 * Revision 1.3 2004/09/01 05:05:43 nedko
733 * Search partitially works.
735 * Revision 1.2 2004/09/01 00:56:43 nedko
736 * Refine look.
737 * Attach callback for search action.
739 * Revision 1.1 2004/08/31 22:40:15 nedko
740 * Partitally implemented search feature.
742 *****************************************************************************/