PageRenderTime 41ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/gnome-search/search-string.c

http://github.com/mchochlov/Gnucash
C | 385 lines | 278 code | 69 blank | 38 comment | 15 complexity | 5aa63b3ede63373418b5f4c7868ceab5 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Copyright (C) 2002 Derek Atkins
  3. *
  4. * Authors: Derek Atkins <warlord@MIT.EDU>
  5. *
  6. * Copyright (c) 2006 David Hampton <hampton@employees.org>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public
  19. * License along with this program; if not, write to the
  20. * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  21. * Boston, MA 02110-1301, USA.
  22. */
  23. #ifdef HAVE_CONFIG_H
  24. #include <config.h>
  25. #endif
  26. #include <gtk/gtk.h>
  27. #include <glib/gi18n.h>
  28. #include <string.h>
  29. #include <sys/types.h>
  30. #include <regex.h>
  31. #include "search-string.h"
  32. #include "search-core-utils.h"
  33. #include "qof.h"
  34. #define d(x)
  35. static void editable_enters (GNCSearchCoreType *fe);
  36. static void grab_focus (GNCSearchCoreType *fe);
  37. static GNCSearchCoreType *gncs_clone(GNCSearchCoreType *fe);
  38. static gboolean gncs_validate (GNCSearchCoreType *fe);
  39. static GtkWidget *gncs_get_widget(GNCSearchCoreType *fe);
  40. static QofQueryPredData* gncs_get_predicate (GNCSearchCoreType *fe);
  41. static void gnc_search_string_class_init (GNCSearchStringClass *class);
  42. static void gnc_search_string_init (GNCSearchString *gspaper);
  43. static void gnc_search_string_finalize (GObject *obj);
  44. typedef struct _GNCSearchStringPrivate GNCSearchStringPrivate;
  45. struct _GNCSearchStringPrivate
  46. {
  47. GtkWidget *entry;
  48. };
  49. #define _PRIVATE(o) \
  50. (G_TYPE_INSTANCE_GET_PRIVATE ((o), GNC_TYPE_SEARCH_STRING, GNCSearchStringPrivate))
  51. static GNCSearchCoreTypeClass *parent_class;
  52. GType
  53. gnc_search_string_get_type (void)
  54. {
  55. static GType type = 0;
  56. if (!type)
  57. {
  58. GTypeInfo type_info =
  59. {
  60. sizeof(GNCSearchStringClass), /* class_size */
  61. NULL, /* base_init */
  62. NULL, /* base_finalize */
  63. (GClassInitFunc)gnc_search_string_class_init,
  64. NULL, /* class_finalize */
  65. NULL, /* class_data */
  66. sizeof(GNCSearchString), /* */
  67. 0, /* n_preallocs */
  68. (GInstanceInitFunc)gnc_search_string_init,
  69. };
  70. type = g_type_register_static (GNC_TYPE_SEARCH_CORE_TYPE,
  71. "GNCSearchString",
  72. &type_info, 0);
  73. }
  74. return type;
  75. }
  76. static void
  77. gnc_search_string_class_init (GNCSearchStringClass *class)
  78. {
  79. GObjectClass *object_class;
  80. GNCSearchCoreTypeClass *gnc_search_core_type = (GNCSearchCoreTypeClass *)class;
  81. object_class = G_OBJECT_CLASS (class);
  82. parent_class = g_type_class_peek_parent (class);
  83. object_class->finalize = gnc_search_string_finalize;
  84. /* override methods */
  85. gnc_search_core_type->editable_enters = editable_enters;
  86. gnc_search_core_type->grab_focus = grab_focus;
  87. gnc_search_core_type->validate = gncs_validate;
  88. gnc_search_core_type->get_widget = gncs_get_widget;
  89. gnc_search_core_type->get_predicate = gncs_get_predicate;
  90. gnc_search_core_type->clone = gncs_clone;
  91. g_type_class_add_private(class, sizeof(GNCSearchStringPrivate));
  92. }
  93. static void
  94. gnc_search_string_init (GNCSearchString *o)
  95. {
  96. o->value = NULL;
  97. o->how = SEARCH_STRING_CONTAINS;
  98. o->ign_case = TRUE;
  99. }
  100. static void
  101. gnc_search_string_finalize (GObject *obj)
  102. {
  103. GNCSearchString *o = (GNCSearchString *)obj;
  104. g_assert (IS_GNCSEARCH_STRING (o));
  105. g_free (o->value);
  106. G_OBJECT_CLASS (parent_class)->finalize(obj);
  107. }
  108. /**
  109. * gnc_search_string_new:
  110. *
  111. * Create a new GNCSearchString object.
  112. *
  113. * Return value: A new #GNCSearchString object.
  114. **/
  115. GNCSearchString *
  116. gnc_search_string_new (void)
  117. {
  118. GNCSearchString *o = g_object_new(GNC_TYPE_SEARCH_STRING, NULL);
  119. return o;
  120. }
  121. void
  122. gnc_search_string_set_value (GNCSearchString *fi, const char *value)
  123. {
  124. g_return_if_fail (fi);
  125. g_return_if_fail (IS_GNCSEARCH_STRING (fi));
  126. if (fi->value)
  127. g_free (fi->value);
  128. fi->value = g_strdup (value);
  129. }
  130. void
  131. gnc_search_string_set_how (GNCSearchString *fi, GNCSearchString_Type how)
  132. {
  133. g_return_if_fail (fi);
  134. g_return_if_fail (IS_GNCSEARCH_STRING (fi));
  135. fi->how = how;
  136. }
  137. void
  138. gnc_search_string_set_case (GNCSearchString *fi, gboolean ignore_case)
  139. {
  140. g_return_if_fail (fi);
  141. g_return_if_fail (IS_GNCSEARCH_STRING (fi));
  142. fi->ign_case = ignore_case;
  143. }
  144. static gboolean
  145. gncs_validate (GNCSearchCoreType *fe)
  146. {
  147. GNCSearchString *fi = (GNCSearchString *)fe;
  148. gboolean valid = TRUE;
  149. g_return_val_if_fail (fi, FALSE);
  150. g_return_val_if_fail (IS_GNCSEARCH_STRING (fi), FALSE);
  151. if (!fi->value || *(fi->value) == '\0')
  152. {
  153. GtkWidget *dialog;
  154. dialog = gtk_message_dialog_new (NULL,
  155. GTK_DIALOG_MODAL,
  156. GTK_MESSAGE_ERROR,
  157. GTK_BUTTONS_OK,
  158. "%s",
  159. _("You need to enter some search text."));
  160. gtk_dialog_run (GTK_DIALOG (dialog));
  161. gtk_widget_destroy(dialog);
  162. return FALSE;
  163. }
  164. if (fi->how == SEARCH_STRING_MATCHES_REGEX ||
  165. fi->how == SEARCH_STRING_NOT_MATCHES_REGEX)
  166. {
  167. regex_t regexpat; /* regex patern */
  168. gint regerr;
  169. int flags = REG_EXTENDED;
  170. if (fi->ign_case)
  171. flags |= REG_ICASE;
  172. regerr = regcomp (&regexpat, fi->value, flags);
  173. if (regerr)
  174. {
  175. GtkWidget *dialog;
  176. gchar *regmsg, *errmsg;
  177. size_t reglen;
  178. /* regerror gets called twice to get the full error string
  179. length to do proper posix error reporting */
  180. reglen = regerror (regerr, &regexpat, 0, 0);
  181. regmsg = g_malloc0 (reglen + 1);
  182. regerror (regerr, &regexpat, regmsg, reglen);
  183. errmsg = g_strdup_printf (_("Error in regular expression '%s':\n%s"),
  184. fi->value, regmsg);
  185. g_free (regmsg);
  186. dialog = gtk_message_dialog_new (NULL,
  187. GTK_DIALOG_MODAL,
  188. GTK_MESSAGE_ERROR,
  189. GTK_BUTTONS_OK,
  190. "%s", errmsg);
  191. gtk_dialog_run (GTK_DIALOG (dialog));
  192. gtk_widget_destroy(dialog);
  193. g_free (errmsg);
  194. valid = FALSE;
  195. }
  196. regfree (&regexpat);
  197. }
  198. return valid;
  199. }
  200. static void
  201. toggle_changed (GtkToggleButton *button, GNCSearchString *fe)
  202. {
  203. fe->ign_case = !gtk_toggle_button_get_active (button);
  204. }
  205. static void
  206. entry_changed (GtkEntry *entry, GNCSearchString *fe)
  207. {
  208. const char *new;
  209. new = gtk_entry_get_text(entry);
  210. gnc_search_string_set_value (fe, new);
  211. }
  212. static GtkWidget *
  213. make_menu (GNCSearchCoreType *fe)
  214. {
  215. GNCSearchString *fi = (GNCSearchString *)fe;
  216. GtkComboBox *combo;
  217. combo = GTK_COMBO_BOX(gnc_combo_box_new_search());
  218. gnc_combo_box_search_add(combo, _("contains"), SEARCH_STRING_CONTAINS);
  219. gnc_combo_box_search_add(combo, _("matches regex"),
  220. SEARCH_STRING_MATCHES_REGEX);
  221. gnc_combo_box_search_add(combo, _("does not match regex"),
  222. SEARCH_STRING_NOT_MATCHES_REGEX);
  223. gnc_combo_box_search_changed(combo, &fi->how);
  224. gnc_combo_box_search_set_active(combo, fi->how ? fi->how : SEARCH_STRING_CONTAINS);
  225. return GTK_WIDGET(combo);
  226. }
  227. static void
  228. grab_focus (GNCSearchCoreType *fe)
  229. {
  230. GNCSearchString *fi = (GNCSearchString *)fe;
  231. GNCSearchStringPrivate *priv;
  232. g_return_if_fail (fi);
  233. g_return_if_fail (IS_GNCSEARCH_STRING (fi));
  234. priv = _PRIVATE(fi);
  235. if (priv->entry)
  236. gtk_widget_grab_focus (priv->entry);
  237. }
  238. static void
  239. editable_enters (GNCSearchCoreType *fe)
  240. {
  241. GNCSearchString *fi = (GNCSearchString *)fe;
  242. GNCSearchStringPrivate *priv;
  243. g_return_if_fail (fi);
  244. g_return_if_fail (IS_GNCSEARCH_STRING (fi));
  245. priv = _PRIVATE(fi);
  246. if (priv->entry)
  247. gtk_entry_set_activates_default(GTK_ENTRY (priv->entry), TRUE);
  248. }
  249. static GtkWidget *
  250. gncs_get_widget (GNCSearchCoreType *fe)
  251. {
  252. GtkWidget *entry, *toggle, *menu, *box;
  253. GNCSearchString *fi = (GNCSearchString *)fe;
  254. GNCSearchStringPrivate *priv;
  255. g_return_val_if_fail (fi, NULL);
  256. g_return_val_if_fail (IS_GNCSEARCH_STRING (fi), NULL);
  257. priv = _PRIVATE(fi);
  258. box = gtk_hbox_new (FALSE, 3);
  259. /* Build and connect the option menu */
  260. menu = make_menu (fe);
  261. gtk_box_pack_start (GTK_BOX (box), menu, FALSE, FALSE, 3);
  262. /* Build and connect the entry window */
  263. entry = gtk_entry_new ();
  264. if (fi->value)
  265. gtk_entry_set_text (GTK_ENTRY (entry), fi->value);
  266. g_signal_connect (G_OBJECT (entry), "changed", G_CALLBACK (entry_changed), fe);
  267. gtk_box_pack_start (GTK_BOX (box), entry, FALSE, FALSE, 3);
  268. priv->entry = entry;
  269. /* Build and connect the case-sensitive check button; defaults to off */
  270. toggle = gtk_check_button_new_with_label (_("Match case"));
  271. g_signal_connect (G_OBJECT(toggle), "toggled", G_CALLBACK (toggle_changed), fe);
  272. gtk_box_pack_start (GTK_BOX (box), toggle, FALSE, FALSE, 3);
  273. /* And return the box */
  274. return box;
  275. }
  276. static QofQueryPredData* gncs_get_predicate (GNCSearchCoreType *fe)
  277. {
  278. GNCSearchString *ss = (GNCSearchString *)fe;
  279. QofQueryCompare how;
  280. QofStringMatch options = QOF_STRING_MATCH_NORMAL;
  281. gboolean is_regex = FALSE;
  282. g_return_val_if_fail (ss, NULL);
  283. g_return_val_if_fail (IS_GNCSEARCH_STRING (ss), NULL);
  284. switch (ss->how)
  285. {
  286. case SEARCH_STRING_MATCHES_REGEX:
  287. is_regex = TRUE;
  288. /* FALLTHROUGH */
  289. case SEARCH_STRING_CONTAINS:
  290. how = QOF_COMPARE_EQUAL;
  291. break;
  292. case SEARCH_STRING_NOT_MATCHES_REGEX:
  293. is_regex = TRUE;
  294. /* FALLTHROUGH */
  295. case SEARCH_STRING_NOT_CONTAINS:
  296. how = QOF_COMPARE_NEQ;
  297. break;
  298. default:
  299. g_warning ("invalid string choice: %d", ss->how);
  300. return NULL;
  301. }
  302. if (ss->ign_case)
  303. options = QOF_STRING_MATCH_CASEINSENSITIVE;
  304. return qof_query_string_predicate (how, ss->value, options, is_regex);
  305. }
  306. static GNCSearchCoreType *gncs_clone(GNCSearchCoreType *fe)
  307. {
  308. GNCSearchString *se, *fse = (GNCSearchString *)fe;
  309. g_return_val_if_fail (fse, NULL);
  310. g_return_val_if_fail (IS_GNCSEARCH_STRING (fse), NULL);
  311. se = gnc_search_string_new ();
  312. gnc_search_string_set_value (se, fse->value);
  313. gnc_search_string_set_how (se, fse->how);
  314. gnc_search_string_set_case (se, fse->ign_case);
  315. return (GNCSearchCoreType *)se;
  316. }