+/*
+ * Copyright (C) 2006 John Ellis
+ * Copyright (C) 2008 - 2016 The Geeqie Team
+ *
+ * Author: John Ellis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "pan-view-search.h"
+
+#include "image.h"
+#include "pan-calendar.h"
+#include "pan-item.h"
+#include "pan-util.h"
+#include "pan-view.h"
+#include "ui_tabcomp.h"
+
+static void pan_search_status(PanWindow *pw, const gchar *text)
+{
+ gtk_label_set_text(GTK_LABEL(pw->search_label), (text) ? text : "");
+}
+
+static gint pan_search_by_path(PanWindow *pw, const gchar *path)
+{
+ PanItem *pi;
+ GList *list;
+ GList *found;
+ PanItemType type;
+ gchar *buf;
+
+ type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
+
+ list = pan_item_find_by_path(pw, type, path, FALSE, FALSE);
+ if (!list) return FALSE;
+
+ found = g_list_find(list, pw->click_pi);
+ if (found && found->next)
+ {
+ found = found->next;
+ pi = found->data;
+ }
+ else
+ {
+ pi = list->data;
+ }
+
+ pan_info_update(pw, pi);
+ image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5);
+
+ buf = g_strdup_printf("%s ( %d / %d )",
+ (path[0] == G_DIR_SEPARATOR) ? _("path found") : _("filename found"),
+ g_list_index(list, pi) + 1,
+ g_list_length(list));
+ pan_search_status(pw, buf);
+ g_free(buf);
+
+ g_list_free(list);
+
+ return TRUE;
+}
+
+static gboolean pan_search_by_partial(PanWindow *pw, const gchar *text)
+{
+ PanItem *pi;
+ GList *list;
+ GList *found;
+ PanItemType type;
+ gchar *buf;
+
+ type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
+
+ list = pan_item_find_by_path(pw, type, text, TRUE, FALSE);
+ if (!list) list = pan_item_find_by_path(pw, type, text, FALSE, TRUE);
+ if (!list)
+ {
+ gchar *needle;
+
+ needle = g_utf8_strdown(text, -1);
+ list = pan_item_find_by_path(pw, type, needle, TRUE, TRUE);
+ g_free(needle);
+ }
+ if (!list) return FALSE;
+
+ found = g_list_find(list, pw->click_pi);
+ if (found && found->next)
+ {
+ found = found->next;
+ pi = found->data;
+ }
+ else
+ {
+ pi = list->data;
+ }
+
+ pan_info_update(pw, pi);
+ image_scroll_to_point(pw->imd, pi->x + pi->width / 2, pi->y + pi->height / 2, 0.5, 0.5);
+
+ buf = g_strdup_printf("%s ( %d / %d )",
+ _("partial match"),
+ g_list_index(list, pi) + 1,
+ g_list_length(list));
+ pan_search_status(pw, buf);
+ g_free(buf);
+
+ g_list_free(list);
+
+ return TRUE;
+}
+
+static gboolean valid_date_separator(gchar c)
+{
+ return (c == '/' || c == '-' || c == ' ' || c == '.' || c == ',');
+}
+
+static GList *pan_search_by_date_val(PanWindow *pw, PanItemType type,
+ gint year, gint month, gint day,
+ const gchar *key)
+{
+ GList *list = NULL;
+ GList *work;
+
+ work = g_list_last(pw->list_static);
+ while (work)
+ {
+ PanItem *pi;
+
+ pi = work->data;
+ work = work->prev;
+
+ if (pi->fd && (pi->type == type || type == PAN_ITEM_NONE) &&
+ ((!key && !pi->key) || (key && pi->key && strcmp(key, pi->key) == 0)))
+ {
+ struct tm *tl;
+
+ tl = localtime(&pi->fd->date);
+ if (tl)
+ {
+ gint match;
+
+ match = (tl->tm_year == year - 1900);
+ if (match && month >= 0) match = (tl->tm_mon == month - 1);
+ if (match && day > 0) match = (tl->tm_mday == day);
+
+ if (match) list = g_list_prepend(list, pi);
+ }
+ }
+ }
+
+ return g_list_reverse(list);
+}
+
+static gboolean pan_search_by_date(PanWindow *pw, const gchar *text)
+{
+ PanItem *pi = NULL;
+ GList *list = NULL;
+ GList *found;
+ gint year;
+ gint month = -1;
+ gint day = -1;
+ gchar *ptr;
+ gchar *mptr;
+ struct tm *lt;
+ time_t t;
+ gchar *message;
+ gchar *buf;
+ gchar *buf_count;
+
+ if (!text) return FALSE;
+
+ ptr = (gchar *)text;
+ while (*ptr != '\0')
+ {
+ if (!g_unichar_isdigit(*ptr) && !valid_date_separator(*ptr)) return FALSE;
+ ptr++;
+ }
+
+ t = time(NULL);
+ if (t == -1) return FALSE;
+ lt = localtime(&t);
+ if (!lt) return FALSE;
+
+ if (valid_date_separator(*text))
+ {
+ year = -1;
+ mptr = (gchar *)text;
+ }
+ else
+ {
+ year = (gint)strtol(text, &mptr, 10);
+ if (mptr == text) return FALSE;
+ }
+
+ if (*mptr != '\0' && valid_date_separator(*mptr))
+ {
+ gchar *dptr;
+
+ mptr++;
+ month = strtol(mptr, &dptr, 10);
+ if (dptr == mptr)
+ {
+ if (valid_date_separator(*dptr))
+ {
+ month = lt->tm_mon + 1;
+ dptr++;
+ }
+ else
+ {
+ month = -1;
+ }
+ }
+ if (dptr != mptr && *dptr != '\0' && valid_date_separator(*dptr))
+ {
+ gchar *eptr;
+ dptr++;
+ day = strtol(dptr, &eptr, 10);
+ if (dptr == eptr)
+ {
+ day = lt->tm_mday;
+ }
+ }
+ }
+
+ if (year == -1)
+ {
+ year = lt->tm_year + 1900;
+ }
+ else if (year < 100)
+ {
+ if (year > 70)
+ year+= 1900;
+ else
+ year+= 2000;
+ }
+
+ if (year < 1970 ||
+ month < -1 || month == 0 || month > 12 ||
+ day < -1 || day == 0 || day > 31) return FALSE;
+
+ t = pan_date_to_time(year, month, day);
+ if (t < 0) return FALSE;
+
+ if (pw->layout == PAN_LAYOUT_CALENDAR)
+ {
+ list = pan_search_by_date_val(pw, PAN_ITEM_BOX, year, month, day, "day");
+ }
+ else
+ {
+ PanItemType type;
+
+ type = (pw->size > PAN_IMAGE_SIZE_THUMB_LARGE) ? PAN_ITEM_IMAGE : PAN_ITEM_THUMB;
+ list = pan_search_by_date_val(pw, type, year, month, day, NULL);
+ }
+
+ if (list)
+ {
+ found = g_list_find(list, pw->search_pi);
+ if (found && found->next)
+ {
+ found = found->next;
+ pi = found->data;
+ }
+ else
+ {
+ pi = list->data;
+ }
+ }
+
+ pw->search_pi = pi;
+
+ if (pw->layout == PAN_LAYOUT_CALENDAR && pi && pi->type == PAN_ITEM_BOX)
+ {
+ pan_info_update(pw, NULL);
+ pan_calendar_update(pw, pi);
+ image_scroll_to_point(pw->imd,
+ pi->x + pi->width / 2,
+ pi->y + pi->height / 2, 0.5, 0.5);
+ }
+ else if (pi)
+ {
+ pan_info_update(pw, pi);
+ image_scroll_to_point(pw->imd,
+ pi->x - PAN_BOX_BORDER * 5 / 2,
+ pi->y, 0.0, 0.5);
+ }
+
+ if (month > 0)
+ {
+ buf = pan_date_value_string(t, PAN_DATE_LENGTH_MONTH);
+ if (day > 0)
+ {
+ gchar *tmp;
+ tmp = buf;
+ buf = g_strdup_printf("%d %s", day, tmp);
+ g_free(tmp);
+ }
+ }
+ else
+ {
+ buf = pan_date_value_string(t, PAN_DATE_LENGTH_YEAR);
+ }
+
+ if (pi)
+ {
+ buf_count = g_strdup_printf("( %d / %d )",
+ g_list_index(list, pi) + 1,
+ g_list_length(list));
+ }
+ else
+ {
+ buf_count = g_strdup_printf("(%s)", _("no match"));
+ }
+
+ message = g_strdup_printf("%s %s %s", _("Date:"), buf, buf_count);
+ g_free(buf);
+ g_free(buf_count);
+ pan_search_status(pw, message);
+ g_free(message);
+
+ g_list_free(list);
+
+ return TRUE;
+}
+
+void pan_search_activate_cb(const gchar *text, gpointer data)
+{
+ PanWindow *pw = data;
+
+ if (!text) return;
+
+ tab_completion_append_to_history(pw->search_entry, text);
+
+ if (pan_search_by_path(pw, text)) return;
+
+ if ((pw->layout == PAN_LAYOUT_TIMELINE ||
+ pw->layout == PAN_LAYOUT_CALENDAR) &&
+ pan_search_by_date(pw, text))
+ {
+ return;
+ }
+
+ if (pan_search_by_partial(pw, text)) return;
+
+ pan_search_status(pw, _("no match"));
+}
+
+void pan_search_activate(PanWindow *pw)
+{
+ gchar *text;
+
+ text = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->search_entry)));
+ pan_search_activate_cb(text, pw);
+ g_free(text);
+}
+
+void pan_search_toggle_cb(GtkWidget *button, gpointer data)
+{
+ PanWindow *pw = data;
+ gboolean visible;
+
+ visible = gtk_widget_get_visible(pw->search_box);
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == visible) return;
+
+ if (visible)
+ {
+ gtk_widget_hide(pw->search_box);
+ gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE);
+ }
+ else
+ {
+ gtk_widget_show(pw->search_box);
+ gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+ gtk_widget_grab_focus(pw->search_entry);
+ }
+}
+
+void pan_search_toggle_visible(PanWindow *pw, gboolean enable)
+{
+ if (pw->fs) return;
+
+ if (enable)
+ {
+ if (gtk_widget_get_visible(pw->search_box))
+ {
+ gtk_widget_grab_focus(pw->search_entry);
+ }
+ else
+ {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), TRUE);
+ }
+ }
+ else
+ {
+ if (gtk_widget_get_visible(pw->search_entry))
+ {
+ if (gtk_widget_has_focus(pw->search_entry))
+ {
+ gtk_widget_grab_focus(GTK_WIDGET(pw->imd->widget));
+ }
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), FALSE);
+ }
+ }
+}