/* Evolution calendar - Search bar widget for calendar views * * Copyright (C) 2001 Ximian, Inc. * * Author: Federico Mena-Quintero * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * 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. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cal-search-bar.h" #include "e-util/e-util.h" #include "e-util/e-error.h" #include "e-util/e-util-private.h" typedef struct CALSearchBarItem { ESearchBarItem search; const char *image; } CALSearchBarItem; static ESearchBarItem calendar_search_items[] = { E_FILTERBAR_ADVANCED, {NULL, 0, 0}, E_FILTERBAR_SAVE, E_FILTERBAR_EDIT, {NULL, -1, 0} }; /* IDs and option items for the ESearchBar */ enum { SEARCH_SUMMARY_CONTAINS, SEARCH_DESCRIPTION_CONTAINS, SEARCH_ANY_FIELD_CONTAINS, SEARCH_CATEGORY_IS, SEARCH_COMMENT_CONTAINS, SEARCH_LOCATION_CONTAINS, SEARCH_ATTENDEE_CONTAINS }; /* Comments are disabled because they are kind of useless right now, see bug 33247 */ static ESearchBarItem search_option_items[] = { { N_("Summary contains"), SEARCH_SUMMARY_CONTAINS, ESB_ITEMTYPE_RADIO }, { N_("Description contains"), SEARCH_DESCRIPTION_CONTAINS, ESB_ITEMTYPE_RADIO }, { N_("Category is"), SEARCH_CATEGORY_IS, ESB_ITEMTYPE_RADIO }, { N_("Comment contains"), SEARCH_COMMENT_CONTAINS, ESB_ITEMTYPE_RADIO }, { N_("Location contains"), SEARCH_LOCATION_CONTAINS, ESB_ITEMTYPE_RADIO }, { N_("Any field contains"), SEARCH_ANY_FIELD_CONTAINS, ESB_ITEMTYPE_RADIO }, }; /* IDs for the categories suboptions */ typedef enum { CATEGORIES_ALL, CATEGORIES_UNMATCHED, LAST_FIELD } common_search_options; typedef enum { N_DAY_TASK = LAST_FIELD, ACTIVE_TASK, OVERDUE_TASK, COMPLETED_TASK, TASK_WITH_ATTACHMENT, TASK_LAST_FIELD } task_search_options; typedef enum { ACTIVE_APPONTMENT = LAST_FIELD, N_DAY_APPOINTMENT, CAL_LAST_FIELD } cal_search_options; /* We add 2 to the offset to include the separators used to differenciate the quick search queries. */ #define CATEGORIES_TASKS_OFFSET (TASK_LAST_FIELD + 2) #define CATEGORIES_MEMOS_OFFSET (LAST_FIELD + 1) #define CATEGORIES_CALENDAR_OFFSET (CAL_LAST_FIELD + 2) /* Private part of the CalSearchBar structure */ struct CalSearchBarPrivate { /* Array of categories */ GPtrArray *categories; RuleContext *search_context; FilterRule *search_rule; guint32 view_flag; time_t start; time_t end; }; static void cal_search_bar_destroy (GtkObject *object); static void cal_search_bar_search_activated (ESearchBar *search); /* Signal IDs */ enum { SEXP_CHANGED, CATEGORY_CHANGED, LAST_SIGNAL }; static guint cal_search_bar_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (CalSearchBar, cal_search_bar, E_FILTER_BAR_TYPE) /* Class initialization function for the calendar search bar */ static void cal_search_bar_class_init (CalSearchBarClass *klass) { GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); ESearchBarClass *search_bar_class = E_SEARCH_BAR_CLASS (klass); cal_search_bar_signals[SEXP_CHANGED] = gtk_signal_new ("sexp_changed", GTK_RUN_FIRST, G_TYPE_FROM_CLASS (object_class), GTK_SIGNAL_OFFSET (CalSearchBarClass, sexp_changed), gtk_marshal_NONE__STRING, GTK_TYPE_NONE, 1, GTK_TYPE_STRING); cal_search_bar_signals[CATEGORY_CHANGED] = gtk_signal_new ("category_changed", GTK_RUN_FIRST, G_TYPE_FROM_CLASS (object_class), GTK_SIGNAL_OFFSET (CalSearchBarClass, category_changed), gtk_marshal_NONE__STRING, GTK_TYPE_NONE, 1, GTK_TYPE_STRING); klass->sexp_changed = NULL; klass->category_changed = NULL; search_bar_class->search_activated = cal_search_bar_search_activated; object_class->destroy = cal_search_bar_destroy; } /* Object initialization function for the calendar search bar */ static void cal_search_bar_init (CalSearchBar *cal_search) { CalSearchBarPrivate *priv; priv = g_new (CalSearchBarPrivate, 1); cal_search->priv = priv; priv->categories = g_ptr_array_new (); g_ptr_array_set_size (priv->categories, 0); priv->start = -1; priv->end = -1; } /* Frees an array of categories */ static void free_categories (GPtrArray *categories) { int i; for (i = 0; i < categories->len; i++) { if (categories->pdata[i] == NULL) continue; g_free (categories->pdata[i]); } g_ptr_array_free (categories, TRUE); } /* Destroy handler for the calendar search bar */ static void cal_search_bar_destroy (GtkObject *object) { CalSearchBar *cal_search; CalSearchBarPrivate *priv; g_return_if_fail (object != NULL); g_return_if_fail (IS_CAL_SEARCH_BAR (object)); cal_search = CAL_SEARCH_BAR (object); priv = cal_search->priv; if (priv) { if (priv->categories) { free_categories (priv->categories); priv->categories = NULL; } if (priv->search_rule) { g_object_unref (priv->search_rule); priv->search_rule = NULL; } /* FIXME if (priv->search_context) { g_object_unref (priv->search_context); priv->search_context = NULL; }*/ g_free (priv); cal_search->priv = NULL; } if (GTK_OBJECT_CLASS (cal_search_bar_parent_class)->destroy) (* GTK_OBJECT_CLASS (cal_search_bar_parent_class)->destroy) (object); } /* Emits the "sexp_changed" signal for the calendar search bar */ static void notify_sexp_changed (CalSearchBar *cal_search, const char *sexp) { gtk_signal_emit (GTK_OBJECT (cal_search), cal_search_bar_signals[SEXP_CHANGED], sexp); } /* Returns the string of the currently selected category, NULL for "Unmatched" and "All */ static const char * get_current_category (CalSearchBar *cal_search) { CalSearchBarPrivate *priv; gint viewid, i = -1; priv = cal_search->priv; g_return_val_if_fail (priv->categories != NULL, NULL); viewid = e_search_bar_get_viewitem_id (E_SEARCH_BAR (cal_search)); if (viewid == CATEGORIES_ALL || viewid == CATEGORIES_UNMATCHED) return NULL; if (priv->view_flag == CAL_SEARCH_TASKS_DEFAULT) i = viewid - CATEGORIES_TASKS_OFFSET; else if (priv->view_flag == CAL_SEARCH_MEMOS_DEFAULT) i = viewid - CATEGORIES_MEMOS_OFFSET; else if (priv->view_flag == CAL_SEARCH_CALENDAR_DEFAULT) i = viewid - CATEGORIES_CALENDAR_OFFSET; if (i >= 0 && i < priv->categories->len) return priv->categories->pdata[i]; else return NULL; } /* Returns a sexp for the selected category in the drop-down menu. The "All" * option is returned as (const char *) 1, and the "Unfiled" option is returned * as NULL. */ static char * get_show_option_sexp (CalSearchBar *cal_search) { CalSearchBarPrivate *priv ; gint viewid ; char *start, *end, *due, *ret = NULL; const char *category = NULL ; time_t start_range, end_range; priv = cal_search->priv; viewid = e_search_bar_get_viewitem_id (E_SEARCH_BAR (cal_search)); if (viewid == CATEGORIES_UNMATCHED) return g_strdup ("(has-categories? #f)"); /* Unfiled items */ else if (viewid == CATEGORIES_ALL) return NULL; /* All items */ switch (priv->view_flag) { case CAL_SEARCH_TASKS_DEFAULT: if (viewid == N_DAY_TASK) { start_range = time(NULL); end_range = time_add_day(start_range, 7); start = isodate_from_time_t (start_range); due = isodate_from_time_t (end_range); ret = g_strdup_printf ("(due-in-time-range? (make-time \"%s\")" " (make-time \"%s\"))", start, due); g_free (start); g_free (due); return ret; } else if (viewid == ACTIVE_TASK) { /* Shows the tasks due for an year from now which are not completed yet*/ start_range = time(NULL); end_range = time_add_day(start_range, 365); start = isodate_from_time_t (start_range); due = isodate_from_time_t (end_range); ret = g_strdup_printf ("(and (due-in-time-range? (make-time \"%s\")" " (make-time \"%s\")) (not (is-completed?)))", start, due); g_free (start); g_free (due); return ret; } else if (viewid == OVERDUE_TASK) { /* Shows the tasks which are overdue from lower limit 1970 to the current time */ start_range = 0; end_range = time (NULL); start = isodate_from_time_t (start_range); due = isodate_from_time_t (end_range); ret = g_strdup_printf ("(and (due-in-time-range? (make-time \"%s\")" " (make-time \"%s\")) (not (is-completed?)))", start, due); g_free (start); g_free (due); return ret; } else if (viewid == COMPLETED_TASK) return g_strdup ("(is-completed?)"); else if (viewid == TASK_WITH_ATTACHMENT) return g_strdup ("(has-attachments?)"); break; case CAL_SEARCH_CALENDAR_DEFAULT: if (viewid == ACTIVE_APPONTMENT) { /* Shows next one year's Appointments */ start_range = time (NULL); end_range = time_add_day (start_range, 365); start = isodate_from_time_t (start_range); end = isodate_from_time_t (end_range); ret = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\")" " (make-time \"%s\"))", start, end); cal_search->priv->start = start_range; cal_search->priv->end = end_range; g_free (start); g_free (end); return ret; } else if (viewid == N_DAY_APPOINTMENT) { start_range = time (NULL); end_range = time_add_day (start_range, 7); start = isodate_from_time_t (start_range); end = isodate_from_time_t (end_range); ret = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\")" " (make-time \"%s\"))", start, end); cal_search->priv->start = start_range; cal_search->priv->end = end_range; g_free (start); g_free (end); return ret; } break; default: break; } category = get_current_category (cal_search); if (category != NULL) return g_strdup_printf ("(has-categories? \"%s\")", category); else return NULL; } /* Sets the query string to be (contains? "field" "text") */ static void notify_e_cal_view_contains (CalSearchBar *cal_search, const char *field, const char *view) { char *text = NULL; char *sexp = " "; text = e_search_bar_get_text (E_SEARCH_BAR (cal_search)); if (!text) return; /* This is an error in the UTF8 conversion, not an empty string! */ if (text && *text) { sexp = g_strdup_printf ("(contains? \"%s\" \"%s\")", field, text); g_free (text); } else sexp = g_strdup ("(contains? \"summary\" \"\")"); /* Show all */ /* Apply the selected view on search */ if (view && *view){ sexp = g_strconcat ("(and ",sexp, view, ")", NULL); } notify_sexp_changed (cal_search, sexp); g_free (sexp); } #if 0 /* Sets the query string to the appropriate match for categories */ static void notify_category_is (CalSearchBar *cal_search) { char *sexp; sexp = get_show_option_sexp (cal_search); if (!sexp) notify_sexp_changed (cal_search, "#t"); /* Match all */ else notify_sexp_changed (cal_search, sexp); if (sexp) g_free (sexp); } #endif /* Creates a new query from the values in the widgets and notifies upstream */ static void regen_query (CalSearchBar *cal_search) { int id; char *show_option_sexp = NULL; char *sexp = NULL; GString *out = NULL; EFilterBar *efb = (EFilterBar *) cal_search; /* Fetch the data from the ESearchBar's entry widgets */ id = e_search_bar_get_item_id (E_SEARCH_BAR (cal_search)); cal_search->priv->start = -1; cal_search->priv->end = -1; /* Get the selected view */ show_option_sexp = get_show_option_sexp (cal_search); /* Generate the different types of queries */ switch (id) { case SEARCH_ANY_FIELD_CONTAINS: notify_e_cal_view_contains (cal_search, "any", show_option_sexp); break; case SEARCH_SUMMARY_CONTAINS: notify_e_cal_view_contains (cal_search, "summary", show_option_sexp); break; case SEARCH_DESCRIPTION_CONTAINS: notify_e_cal_view_contains (cal_search, "description", show_option_sexp); break; case SEARCH_COMMENT_CONTAINS: notify_e_cal_view_contains (cal_search, "comment", show_option_sexp); break; case SEARCH_LOCATION_CONTAINS: notify_e_cal_view_contains (cal_search, "location", show_option_sexp); break; case SEARCH_ATTENDEE_CONTAINS: notify_e_cal_view_contains (cal_search, "attendee", show_option_sexp); break; case E_FILTERBAR_ADVANCED_ID: out = g_string_new (""); filter_rule_build_code (efb->current_query, out); if (show_option_sexp && *show_option_sexp) sexp = g_strconcat ("(and ", out->str, show_option_sexp, ")", NULL); notify_sexp_changed (cal_search, sexp ? sexp : out->str); g_string_free (out, TRUE); g_free(sexp); break; default: g_return_if_reached (); } g_free (show_option_sexp); } #if 0 static void regen_view_query (CalSearchBar *cal_search) { const char *category; notify_category_is (cal_search); category = cal_search_bar_get_category (cal_search); gtk_signal_emit (GTK_OBJECT (cal_search), cal_search_bar_signals[CATEGORY_CHANGED], category); } #endif /* search_activated handler for the calendar search bar */ static void cal_search_bar_search_activated (ESearchBar *search) { CalSearchBar *cal_search; cal_search = CAL_SEARCH_BAR (search); regen_query (cal_search); } static GtkWidget * generate_viewoption_menu (CALSearchBarItem *subitems) { GtkWidget *menu, *menu_item; gint i = 0; menu = gtk_menu_new (); for (i = 0; subitems[i].search.id != -1; ++i) { if (subitems[i].search.text) { char *str = NULL; str = e_str_without_underscores (subitems[i].search.text); menu_item = gtk_image_menu_item_new_with_label (str); /* if (subitems[i].image) gtk_image_menu_item_set_image (menu_item, e_icon_factory_get_image (subitems[i].image, E_ICON_SIZE_MENU));*/ g_free (str); } else { menu_item = gtk_menu_item_new (); gtk_widget_set_sensitive (menu_item, FALSE); } g_object_set_data (G_OBJECT (menu_item), "EsbItemId", GINT_TO_POINTER (subitems[i].search.id)); gtk_widget_show (menu_item); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); } return menu; } static void setup_category_options (CalSearchBar *cal_search, CALSearchBarItem *subitems, gint index, gint offset) { CalSearchBarPrivate *priv; gint i; priv = cal_search->priv; if (priv->categories->len > 0) { subitems[index].search.text = NULL; /* separator */ subitems[index].search.id = 0; subitems[index].image = NULL; for (i = 0; i < priv->categories->len; i++) { const char *category; category = priv->categories->pdata[i] ? priv->categories->pdata [i] : ""; /* The search.text field should not be free'd */ subitems[i + offset].search.text = (char *) category; subitems[i + offset].search.id = i + offset; subitems[i + offset].image = e_categories_get_icon_file_for (category); } index = i + offset; } subitems[index].search.id = -1; /* terminator */ subitems[index].search.text = NULL; subitems[index].image = NULL; } /* Creates the suboptions menu for the ESearchBar with the list of categories */ static void make_suboptions (CalSearchBar *cal_search) { CalSearchBarPrivate *priv; CALSearchBarItem *subitems = NULL; GtkWidget *menu; priv = cal_search->priv; g_return_if_fail (priv->categories != NULL); /* Categories plus "all", "unmatched", separator, terminator */ /* All, unmatched, separator */ if (priv->view_flag == CAL_SEARCH_TASKS_DEFAULT) { subitems = g_new (CALSearchBarItem, priv->categories->len + CATEGORIES_TASKS_OFFSET + 1); subitems[0].search.text = _("Any Category"); subitems[0].search.id = CATEGORIES_ALL; subitems[0].image = NULL; subitems[1].search.text = _("Unmatched"); subitems[1].search.id = CATEGORIES_UNMATCHED; subitems[1].image = NULL; subitems[2].search.text = NULL; subitems[2].search.id = 0; subitems[2].image = NULL; subitems[3].search.text = _("Next 7 Days' Tasks"); subitems[3].search.id = N_DAY_TASK; subitems[3].image = NULL; subitems[4].search.text = _("Active Tasks"); subitems[4].search.id = ACTIVE_TASK; subitems[4].image = NULL; subitems[5].search.text = _("Overdue Tasks"); subitems[5].search.id = OVERDUE_TASK; subitems[5].image = NULL; subitems[6].search.text = _("Completed Tasks"); subitems[6].search.id = COMPLETED_TASK; subitems[6].image = NULL; subitems[7].search.text = _("Tasks with Attachments"); subitems[7].search.id = TASK_WITH_ATTACHMENT; subitems[7].image = NULL; /* All the other items */ setup_category_options (cal_search, subitems, 8, CATEGORIES_TASKS_OFFSET); menu = generate_viewoption_menu (subitems); e_search_bar_set_viewoption_menu ((ESearchBar *)cal_search, menu); } else if (priv->view_flag == CAL_SEARCH_MEMOS_DEFAULT) { subitems = g_new (CALSearchBarItem, priv->categories->len + CATEGORIES_MEMOS_OFFSET + 1); /* All, unmatched, separator */ subitems[0].search.text = _("Any Category"); subitems[0].search.id = CATEGORIES_ALL; subitems[0].image = NULL; subitems[1].search.text = _("Unmatched"); subitems[1].search.id = CATEGORIES_UNMATCHED; subitems[1].image = NULL; /* All the other items */ setup_category_options (cal_search, subitems, 2, CATEGORIES_MEMOS_OFFSET); menu = generate_viewoption_menu (subitems); e_search_bar_set_viewoption_menu ((ESearchBar *)cal_search, menu); } else if (priv->view_flag == CAL_SEARCH_CALENDAR_DEFAULT) { subitems = g_new (CALSearchBarItem, priv->categories->len + CATEGORIES_CALENDAR_OFFSET + 1); /* All, unmatched, separator */ subitems[0].search.text = _("Any Category"); subitems[0].search.id = CATEGORIES_ALL; subitems[0].image = NULL; subitems[1].search.text = _("Unmatched"); subitems[1].search.id = CATEGORIES_UNMATCHED; subitems[1].image = NULL; subitems[2].search.text = NULL; subitems[2].search.id = 0; subitems[2].image = NULL; subitems[3].search.text = _("Active Appointments"); subitems[3].search.id = ACTIVE_APPONTMENT; subitems[3].image = NULL; subitems[4].search.text = _("Next 7 Days' Appointments"); subitems[4].search.id = N_DAY_APPOINTMENT; subitems[4].image = NULL; /* All the other items */ setup_category_options (cal_search, subitems, 5, CATEGORIES_CALENDAR_OFFSET); menu = generate_viewoption_menu (subitems); e_search_bar_set_viewoption_menu ((ESearchBar *)cal_search, menu); } if(subitems != NULL) g_free (subitems); } static void search_menu_activated (ESearchBar *esb, int id) { if (id == E_FILTERBAR_ADVANCED_ID) e_search_bar_set_item_id (esb, id); } /** * cal_search_bar_construct: * @cal_search: A calendar search bar. * @flags: bitfield of items to appear in the search menu * * Constructs a calendar search bar by binding its menu and option items. * * Return value: The same value as @cal_search. **/ CalSearchBar * cal_search_bar_construct (CalSearchBar *cal_search, guint32 flags) { ESearchBarItem *items; guint32 bit = 0x1; int i, j; char *xmlfile = NULL; char *userfile = NULL; FilterPart *part; RuleContext *search_context; FilterRule *search_rule; g_return_val_if_fail (IS_CAL_SEARCH_BAR (cal_search), NULL); items = g_alloca ((G_N_ELEMENTS (search_option_items) + 1) * sizeof (ESearchBarItem)); for (i = 0, j = 0; i < G_N_ELEMENTS (search_option_items); i++, bit <<= 1) { if ((flags & bit) != 0) { items[j].text = search_option_items[i].text; items[j].id = search_option_items[i].id; items[j].type = search_option_items[i].type; j++; } } items[j].text = NULL; items[j].id = -1; search_context = rule_context_new (); cal_search->priv->view_flag = flags; rule_context_add_part_set (search_context, "partset", filter_part_get_type (), rule_context_add_part, rule_context_next_part); rule_context_add_rule_set (search_context, "ruleset", filter_rule_get_type (), rule_context_add_rule, rule_context_next_rule); if (flags == CAL_SEARCH_MEMOS_DEFAULT) { userfile = g_build_filename (g_get_home_dir (), ".evolution", "memos", "searches.xml", NULL); xmlfile = g_build_filename (SEARCH_RULE_DIR, "memotypes.xml", NULL); } else if (flags == CAL_SEARCH_TASKS_DEFAULT) { userfile = g_build_filename (g_get_home_dir (), ".evolution", "tasks", "searches.xml", NULL); xmlfile = g_build_filename (SEARCH_RULE_DIR, "tasktypes.xml", NULL); } else { userfile = g_build_filename (g_get_home_dir (), ".evolution", "calendar", "searches.xml", NULL); xmlfile = g_build_filename (SEARCH_RULE_DIR, "caltypes.xml", NULL); } g_object_set_data_full (G_OBJECT (search_context), "user", userfile, g_free); g_object_set_data_full (G_OBJECT (search_context), "system", xmlfile, g_free); rule_context_load (search_context, xmlfile, userfile); search_rule = filter_rule_new (); part = rule_context_next_part (search_context, NULL); if (part == NULL) g_warning ("Could not load calendar search; no parts."); else filter_rule_add_part (search_rule, filter_part_clone (part)); e_filter_bar_new_construct (search_context, xmlfile, userfile, NULL, cal_search, (EFilterBar*) cal_search ); e_search_bar_set_menu ((ESearchBar *) cal_search, calendar_search_items); g_signal_connect ((ESearchBar *) cal_search, "menu_activated", G_CALLBACK (search_menu_activated), cal_search); make_suboptions (cal_search); cal_search->priv->search_rule = search_rule; cal_search->priv->search_context = search_context; g_free (xmlfile); g_free (userfile); return cal_search; } /** * cal_search_bar_new: * flags: bitfield of items to appear in the search menu * * creates a new calendar search bar. * * return value: a newly-created calendar search bar. you should connect to the * "sexp_changed" signal to monitor changes in the generated sexps. **/ GtkWidget * cal_search_bar_new (guint32 flags) { CalSearchBar *cal_search; cal_search = g_object_new (TYPE_CAL_SEARCH_BAR, NULL); return GTK_WIDGET (cal_search_bar_construct (cal_search, flags)); } /* Used from qsort() */ static int compare_categories_cb (const void *a, const void *b) { const char **ca, **cb; ca = (const char **) a; cb = (const char **) b; /* FIXME: should use some utf8 strcoll() thingy */ return strcmp (*ca, *cb); } /* Creates a sorted array of categories based on the original one; copies the * string values. */ static GPtrArray * sort_categories (GPtrArray *categories) { GPtrArray *c; int i; c = g_ptr_array_new (); g_ptr_array_set_size (c, categories->len); for (i = 0; i < categories->len; i++) c->pdata[i] = g_strdup (categories->pdata[i]); qsort (c->pdata, c->len, sizeof (gpointer), compare_categories_cb); return c; } /** * cal_search_bar_set_categories: * @cal_search: A calendar search bar. * @categories: Array of pointers to strings for the category names. * * Sets the list of categories that are to be shown in the drop-down list * of a calendar search bar. The search bar will automatically add an item * for "unfiled" components, that is, those that have no categories assigned * to them. **/ void cal_search_bar_set_categories (CalSearchBar *cal_search, GPtrArray *categories) { CalSearchBarPrivate *priv; g_return_if_fail (IS_CAL_SEARCH_BAR (cal_search)); g_return_if_fail (categories != NULL); priv = cal_search->priv; g_return_if_fail (priv->categories != NULL); free_categories (priv->categories); priv->categories = sort_categories (categories); make_suboptions (cal_search); } /** * cal_search_bar_get_category: * @cal_search: A calendar search bar. * * Queries the currently selected category name in a calendar search bar. * If "All" or "Unfiled" are selected, this function will return NULL. * * Return value: Name of the selected category, or NULL if there is no * selected category. **/ const char * cal_search_bar_get_category (CalSearchBar *cal_search) { const char *category; category = get_current_category (cal_search); return category; } void cal_search_bar_get_time_range (CalSearchBar *cal_search, time_t *start, time_t *end) { CalSearchBarPrivate *priv; g_return_if_fail (IS_CAL_SEARCH_BAR (cal_search)); priv = cal_search->priv; *start = priv->start; *end = priv->end; } 2010-02-0715-45/+15 * - Mark BROKEN on 6.X everywhere and on 7.X amd64pav2010-02-061-0/+8 * - update to jpeg-8dinoex2010-02-0516-6/+16 * - Update my e-mail address in the ports I maintain.avilla2010-01-271-1/+1 * The FreeBSD KDE team is pleased to announce Qt-4.6.1 for FreeBSD.makc2010-01-223-17/+21 * - speech-dispatcher: try fix building on FreeBSD < 8.0fluffy2010-01-188-1/+301 * - Add speech-dispatcherfluffy2010-01-0816-0/+426 * Update to 2.28.3ahze2010-01-042-4/+4 * Update to 2.28.2.kwm2009-12-193-4/+22 * Update to 2.28.2.marcus2009-12-182-4/+4 * The FreeBSD KDE is please to announce the release of KDE 4.3.4,miwi2009-12-025-15/+15 * Presenting GNOME 2.28.1 for FreeBSD. The official release notes for thismarcus2009-11-2924-129/+245 * The KDE FreeBSD team is proud to announce the release of KDE 4.3.3miwi2009-11-2710-25/+15 * - Update to Qt-4.5miwi2009-11-272-6/+0 * - Mark MAKE_JOBS_UNSAFEpav2009-11-201-0/+1 * The FreeBSD KDE is please to announce the release of KDE 4.3.1,tabthorpe2009-09-025-15/+15 * - Switch SourceForge ports to the new File Release System: categories startin...amdmi32009-08-221-1/+1 * Fix the plist when doxygen is installed.marcus2009-08-161-0/+11 * Mk/bsd.kde4.mk:makc2009-08-105-15/+0 * The KDE FreeBSD team is proud to announce the release of KDE 4.3.0miwi2009-08-0515-30/+35 * - s/MAKE_JOBS_SAVE/MAKE_JOBS_SAFEmiwi2009-08-051-1/+1 * - Update Qt4 to 4.5.2miwi2009-08-052-3/+4 * -Repocopy devel/libtool15 -> libtool22 and libltdl15 -> libltdl22.mezz2009-08-033-3/+3 * Update to 0.15.8.marcus2009-08-022-4/+4 * - bump all port that indirectly depends on libjpeg and have not yet been bump...dinoex2009-07-3115-5/+15 * Update to 0.15.7.marcus2009-07-073-4/+7 * Update to 2.26.3.avl2009-07-032-4/+4 * Update to 2.26.3.avl2009-07-013-4/+7 * Fix build with custom LOCALBASEitetcu2009-06-171-0/+2 * - Assign all unmaintained ruby ports to ruby@,stas2009-06-161-1/+1 * The KDE FreeBSD team is pleased to announce KDE 4.2.4, the last bugfixmiwi2009-06-035-15/+15 * . add linux-f10 ports to the rank of CONFLICTS for linux-fc4 ports;bsam2009-06-031-2/+2 * . add CONFLICTS to linux-f8 infrastructure ports;bsam2009-06-031-0/+3 * Here are new Linux Fedora 10 infrastructure ports.bsam2009-06-024-20/+24 * Update to 2.26.2.marcus2009-05-196-8/+50 * Update KDE ports to 4.2.3makc2009-05-105-15/+15 * Update to 4.10.1.marcus2009-05-103-4/+23 * mark as MAKE_JOBS_UNSAFEmakc2009-04-255-5/+5 * Presenting GNOME 2.26.1 for FreeBSD.kwm2009-04-244-10/+10 * Update to 0.15.6.marcus2009-04-122-4/+4 * Presenting GNOME 2.26 for FreeBSD. Seemarcus2009-04-1023-53/+219 * The KDE FreeBSD team is proud to announce the release of KDE 4.2.2miwi2009-04-0210-20/+20 * Here are new Linux Fedora 8 infrastructure ports.bsam2009-04-017-44/+75 * Finish repocopies of new linux-f8 infrastructure ports:bsam2009-04-011-1/+3 * bump PORTREVISION after cmake updatemakc2009-03-255-0/+5 * Release these ports into wild. I don't have time for these ports anymore. I ammezz2009-03-191-1/+1 * Update to 0.15.5.marcus2009-03-153-4/+7 * Update KDE to 4.2.1.makc2009-03-095-15/+15 * Update to 0.0.9.mva2009-03-082-4/+4 * Update to 0.4.25.marcus2009-02-232-4/+4 * Update to 2.24.4.kwm2009-02-213-7/+7 * Updated my mail address to use @FreeBSD.org now.mva2009-02-202-2/+2 * The KDE FreeBSD team is proud to announce the release of KDE 4.2.0miwi2009-02-0915-690/+1580 * - Update to 0.0.8beech2009-02-082-4/+4 * Update to 0.4.23.marcus2009-02-042-4/+4 * - Use GNOME macro instead of ${MASTER_SITE_GNOME}, removearaujo2009-02-026-12/+6 * Fix build after X.org 7.4 merge.flz2009-01-251-0/+2 * In preparation for adding new linux (Fedora 8) infrastructure ports all linuxbsam2009-01-223-21/+3 * kde@freebsd team is pleased to announce KDE 4.1.4, the last bugfix release in...makc2009-01-1410-20/+20 * kde@freebsd team is pleased to announce the update for Qt4 ports.makc2009-01-141-3/+3 * Update to 2.24.3.marcus2009-01-132-4/+4 * Update to 2.24.3.marcus2009-01-132-4/+4 * Remove these ports as they have been absorbed into other ports in GNOME 2.24.marcus2009-01-107-185/+0 * Presenting GNOME 2.24 for FreeBSD.marcus2009-01-1026-223/+479 * Bump PORTREVISION's after OpenLDAP update.delphij2009-01-061-1/+1 * - Update to 0.0.7miwi2008-12-253-7/+14 * linux_base-(fc6|f7|f8) have glib2 by itself. Don't depend uponume2008-11-293-0/+15 * Update to 0.4.22.mezz2008-11-202-7/+6 * The KDE FreeBSD team is proud to announce the release of KDE 4.1.1miwi2008-09-035-15/+15 * The KDE FreeBSD team is proud to announce the releasemiwi2008-08-291-3/+3 * Update CONFIGURE_ARGS for how we pass CONFIGURE_TARGET to configure script.rafan2008-08-211-1/+0 * The KDE FreeBSD team is proud to announce the releasemiwi2008-08-182-4/+3 * The KDE FreeBSD team is proud to announce the release of KDE 4.1.0miwi2008-08-1021-7190/+2766 * - File was rerolled to add missing example filemiwi2008-08-063-4/+8 * - Update to 0.0.6miwi2008-08-063-15/+20 * - Update to qt 4.4.1miwi2008-08-052-15/+16 * Update to 0.4.21.marcus2008-08-052-4/+4 * - Remove USE_GCC where it can be satisfied with base compiler on followingpav2008-07-251-1/+0 * - Update to 0.16.0.20080706, it's more than 0.17 RC1.mezz2008-07-071-2/+1 * Update to 2.22.3.mezz2008-07-013-5/+6 * Update to 2.22.3.mezz2008-07-013-5/+7 * Update to 1.22.3.marcus2008-07-012-5/+5 * Update to 0.4.20.marcus2008-06-182-5/+4 * Bump portrevision due to upgrade of devel/gettext.edwin2008-06-062-2/+2 * Bump portrevision due to upgrade of devel/gettext.edwin2008-06-0621-7/+21 * Fix typos.olgeni2008-06-051-1/+1 * Update to 2.22.2.mezz2008-05-272-4/+4 * Update to 2.22.2.mezz2008-05-274-14/+14 * -De-bashism and remove bash dependency. [1]mezz2008-05-062-6/+33 * - Remove unneeded dependency from gtk12/gtk20 [1]miwi2008-04-2010-16/+14 * Update to 0.4.19ahze2008-04-182-4/+4 * Update to 4.7.3.marcus2008-04-082-4/+4 * Update to 4.7.2.marcus2008-04-083-4/+8 * Update to 2.22.1ahze2008-04-083-4/+10 * Update to 1.22.1ahze2008-04-075-8/+11 * Update to 2.22.1.marcus2008-04-073-4/+5 * - Remove USE_XLIB/USE_X_PREFIX/USE_XPM in favor of USE_XORGmiwi2008-03-251-1/+0 * The FreeBSD GNOME team is proud to annunce the release of GNOME 2.22.0 formarcus2008-03-2422-51/+314 * - Update to 0.6.9jadawin2008-03-172-6/+9 * Update to Qt 4.3.4lofi2008-03-141-3/+3 * YASR ("Yet Another Screen Reader") is an attempt at a lightweight,alepulver2008-02-175-0/+89