📄 search.c
字号:
/* * GQview * (C) 2005 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#include "gqview.h"#include "search.h"#include "bar_info.h"#include "cache.h"#include "collect.h"#include "collect-table.h"#include "dnd.h"#include "dupe.h"#include "image-load.h"#include "info.h"#include "editors.h"#include "img-view.h"#include "filelist.h"#include "layout_image.h"#include "menu.h"#include "print.h"#include "thumb.h"#include "utilops.h"#include "ui_bookmark.h"#include "ui_fileops.h"#include "ui_menu.h"#include "ui_misc.h"#include "ui_spinner.h"#include "ui_tabcomp.h"#include "ui_tree_edit.h"#include <gdk/gdkkeysyms.h> /* for keyboard values */#define DEF_SEARCH_WIDTH 700#define DEF_SEARCH_HEIGHT 450#define SEARCH_BUFFER_MATCH_LOAD 20#define SEARCH_BUFFER_MATCH_HIT 5#define SEARCH_BUFFER_MATCH_MISS 1#define SEARCH_BUFFER_FLUSH_SIZE 99typedef enum { SEARCH_MATCH_NONE, SEARCH_MATCH_EQUAL, SEARCH_MATCH_CONTAINS, SEARCH_MATCH_UNDER, SEARCH_MATCH_OVER, SEARCH_MATCH_BETWEEN, SEARCH_MATCH_ALL, SEARCH_MATCH_ANY} MatchType;enum { SEARCH_COLUMN_POINTER = 0, SEARCH_COLUMN_RANK, SEARCH_COLUMN_THUMB, SEARCH_COLUMN_NAME, SEARCH_COLUMN_SIZE, SEARCH_COLUMN_DATE, SEARCH_COLUMN_DIMENSIONS, SEARCH_COLUMN_PATH, SEARCH_COLUMN_COUNT /* total columns */};typedef struct _SearchData SearchData;struct _SearchData{ GtkWidget *window; GtkWidget *button_thumbs; GtkWidget *label_status; GtkWidget *label_progress; GtkWidget *button_start; GtkWidget *button_stop; GtkWidget *spinner; GtkWidget *box_search; GtkWidget *menu_path; GtkWidget *path_entry; GtkWidget *check_recurse; GtkWidget *result_view; GtkWidget *check_name; GtkWidget *menu_name; GtkWidget *entry_name; GtkWidget *check_name_match_case; GtkWidget *check_size; GtkWidget *menu_size; GtkWidget *spin_size; GtkWidget *spin_size_end; GtkWidget *check_date; GtkWidget *menu_date; GtkWidget *date_sel; GtkWidget *date_sel_end; GtkWidget *check_dimensions; GtkWidget *menu_dimensions; GtkWidget *spin_width; GtkWidget *spin_height; GtkWidget *spin_width_end; GtkWidget *spin_height_end; GtkWidget *check_similarity; GtkWidget *spin_similarity; GtkWidget *entry_similarity; GtkWidget *check_keywords; GtkWidget *menu_keywords; GtkWidget *entry_keywords; gchar *search_path; gint search_path_recurse; gchar *search_name; gint search_name_match_case; gint64 search_size; gint64 search_size_end; gint search_date_y; gint search_date_m; gint search_date_d; gint search_date_end_y; gint search_date_end_m; gint search_date_end_d; gint search_width; gint search_height; gint search_width_end; gint search_height_end; gint search_similarity; gchar *search_similarity_path; CacheData *search_similarity_cd; GList *search_keyword_list; MatchType search_type; MatchType match_name; MatchType match_size; MatchType match_date; MatchType match_dimensions; MatchType match_keywords; gboolean match_name_enable; gboolean match_size_enable; gboolean match_date_enable; gboolean match_dimensions_enable; gboolean match_similarity_enable; gboolean match_keywords_enable; GList *search_folder_list; GList *search_done_list; GList *search_file_list; GList *search_buffer_list; gint search_count; gint search_total; gint search_buffer_count; gint search_idle_id; gint update_idle_id; ImageLoader *img_loader; CacheData *img_cd; FileData *click_fd; ThumbLoader *thumb_loader; gint thumb_enable; FileData *thumb_fd;};typedef struct _MatchFileData MatchFileData;struct _MatchFileData{ FileData fd; gint width; gint height; gint rank;};typedef struct _MatchList MatchList;struct _MatchList{ const gchar *text; const MatchType type;};static const MatchList text_search_menu_path[] = { { N_("folder"), SEARCH_MATCH_NONE }, { N_("comments"), SEARCH_MATCH_ALL }, { N_("results"), SEARCH_MATCH_CONTAINS }};static const MatchList text_search_menu_name[] = { { N_("contains"), SEARCH_MATCH_CONTAINS }, { N_("is"), SEARCH_MATCH_EQUAL }};static const MatchList text_search_menu_size[] = { { N_("equal to"), SEARCH_MATCH_EQUAL }, { N_("less than"), SEARCH_MATCH_UNDER }, { N_("greater than"), SEARCH_MATCH_OVER }, { N_("between"), SEARCH_MATCH_BETWEEN }};static const MatchList text_search_menu_date[] = { { N_("equal to"), SEARCH_MATCH_EQUAL }, { N_("before"), SEARCH_MATCH_UNDER }, { N_("after"), SEARCH_MATCH_OVER }, { N_("between"), SEARCH_MATCH_BETWEEN }};static const MatchList text_search_menu_keyword[] = { { N_("match all"), SEARCH_MATCH_ALL }, { N_("match any"), SEARCH_MATCH_ANY }, { N_("exclude"), SEARCH_MATCH_NONE }};static GList *search_window_list = NULL;static gint search_result_selection_count(SearchData *sd, gint64 *bytes);static gint search_result_count(SearchData *sd, gint64 *bytes);static void search_window_close(SearchData *sd);/* *------------------------------------------------------------------- * utils *------------------------------------------------------------------- */static time_t convert_dmy_to_time(gint day, gint month, gint year){ struct tm lt; lt.tm_sec = 0; lt.tm_min = 0; lt.tm_hour = 0; lt.tm_mday = day; lt.tm_mon = month - 1; lt.tm_year = year - 1900; lt.tm_isdst = 0; return mktime(<);}static void search_status_update(SearchData *sd){ gchar *buf; gint t; gint s; gint64 t_bytes; gint64 s_bytes; gchar *tt; gchar *ts; t = search_result_count(sd, &t_bytes); s = search_result_selection_count(sd, &s_bytes); if (s > 0) { tt = text_from_size_abrev(t_bytes); ts = text_from_size_abrev(s_bytes); buf = g_strdup_printf(_("%s, %d files (%s, %d)"), tt, t, ts, s); g_free(tt); g_free(ts); } else { tt = text_from_size_abrev(t_bytes); buf = g_strdup_printf(_("%s, %d files"), tt, t); g_free(tt); } gtk_label_set_text(GTK_LABEL(sd->label_status), buf); g_free(buf);}static void search_progress_update(SearchData *sd, gint search, gdouble thumbs){ if (search || thumbs >= 0.0) { gchar *buf; const gchar *message; if (search && (sd->search_folder_list || sd->search_file_list)) message = _("Searching..."); else if (thumbs >= 0.0) message = _("Loading thumbs..."); else message = ""; buf = g_strdup_printf("%s(%d / %d)", message, sd->search_count, sd->search_total); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->label_progress), buf); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sd->label_progress), (thumbs >= 0.0) ? thumbs : 0.0); g_free(buf); } else { gtk_progress_bar_set_text(GTK_PROGRESS_BAR(sd->label_progress), ""); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(sd->label_progress), 0.0); }}/* *------------------------------------------------------------------- * result list *------------------------------------------------------------------- */static gint search_result_find_row(SearchData *sd, FileData *fd, GtkTreeIter *iter){ GtkTreeModel *store; gint valid; gint n = 0; store = gtk_tree_view_get_model(GTK_TREE_VIEW(sd->result_view)); valid = gtk_tree_model_get_iter_first(store, iter); while (valid) { FileData *fd_n; n++; gtk_tree_model_get(store, iter, SEARCH_COLUMN_POINTER, &fd_n, -1); if (fd_n == fd) return n; valid = gtk_tree_model_iter_next(store, iter); } return -1;}static gint search_result_row_selected(SearchData *sd, FileData *fd){ GtkTreeModel *store; GtkTreeSelection *selection; GList *slist; GList *work; gint found = FALSE; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(sd->result_view)); slist = gtk_tree_selection_get_selected_rows(selection, &store); work = slist; while (!found && work) { GtkTreePath *tpath = work->data; FileData *fd_n; GtkTreeIter iter; gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, SEARCH_COLUMN_POINTER, &fd_n, -1); if (fd_n == fd) found = TRUE; work = work->next; } g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); g_list_free(slist); return found;}static gint search_result_selection_util(SearchData *sd, gint64 *bytes, GList **list){ GtkTreeModel *store; GtkTreeSelection *selection; GList *slist; GList *work; gint n = 0; gint64 total = 0; GList *plist = NULL; store = gtk_tree_view_get_model(GTK_TREE_VIEW(sd->result_view)); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(sd->result_view)); slist = gtk_tree_selection_get_selected_rows(selection, &store); work = slist; while (work) { n++; if (bytes || list) { GtkTreePath *tpath = work->data; FileData *fd; GtkTreeIter iter; gtk_tree_model_get_iter(store, &iter, tpath); gtk_tree_model_get(store, &iter, SEARCH_COLUMN_POINTER, &fd, -1); total += fd->size; if (list) plist = g_list_prepend(plist, g_strdup(fd->path)); } work = work->next; } g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL); g_list_free(slist); if (bytes) *bytes = total; if (list) *list = g_list_reverse(plist); return n;}static GList *search_result_selection_list(SearchData *sd){ GList *list; search_result_selection_util(sd, NULL, &list); return list;}static gint search_result_selection_count(SearchData *sd, gint64 *bytes){ return search_result_selection_util(sd, bytes, NULL);}static gint search_result_util(SearchData *sd, gint64 *bytes, GList **list){ GtkTreeModel *store; GtkTreeIter iter; gint valid; gint n = 0; gint64 total = 0; GList *plist = NULL; store = gtk_tree_view_get_model(GTK_TREE_VIEW(sd->result_view)); valid = gtk_tree_model_get_iter_first(store, &iter); while (valid) { n++; if (bytes || list) { FileData *fd; gtk_tree_model_get(store, &iter, SEARCH_COLUMN_POINTER, &fd, -1); total += fd->size; if (list) plist = g_list_prepend(plist, g_strdup(fd->path)); } valid = gtk_tree_model_iter_next(store, &iter); } if (bytes) *bytes = total; if (list) *list = g_list_reverse(plist); return n;}static GList *search_result_get_path_list(SearchData *sd){ GList *list = NULL; search_result_util(sd, NULL, &list); return list;}static gint search_result_count(SearchData *sd, gint64 *bytes){ return search_result_util(sd, bytes, NULL);}static void search_result_append(SearchData *sd, MatchFileData *mfd){ FileData *fd; GtkListStore *store; GtkTreeIter iter; gchar *text_size; gchar *text_dim = NULL; fd = (FileData *)mfd; if (!fd) return; text_size = text_from_size(fd->size); if (mfd->width > 0 && mfd->height > 0) text_dim = g_strdup_printf("%d x %d", mfd->width, mfd->height); store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(sd->result_view))); gtk_list_store_append(store, &iter); gtk_list_store_set(store, &iter, SEARCH_COLUMN_POINTER, fd, SEARCH_COLUMN_RANK, mfd->rank, SEARCH_COLUMN_THUMB, fd->pixbuf, SEARCH_COLUMN_NAME, fd->name, SEARCH_COLUMN_SIZE, text_size, SEARCH_COLUMN_DATE, text_from_time(fd->date), SEARCH_COLUMN_DIMENSIONS, text_dim, SEARCH_COLUMN_PATH, fd->path, -1); g_free(text_size); g_free(text_dim);}static GList *search_result_refine_list(SearchData *sd){ GList *list = NULL; GtkTreeModel *store; GtkTreeIter iter; gint valid; store = gtk_tree_view_get_model(GTK_TREE_VIEW(sd->result_view)); valid = gtk_tree_model_get_iter_first(store, &iter); while (valid) { FileData *fd; gtk_tree_model_get(store, &iter, SEARCH_COLUMN_POINTER, &fd, -1); list = g_list_prepend(list, fd); valid = gtk_tree_model_iter_next(store, &iter); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -