PageRenderTime 28ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/debr/debr-validate.c

https://code.google.com/p/gebr/
C | 474 lines | 324 code | 67 blank | 83 comment | 26 complexity | f0c3fdddd448ceefb12a8878e71348f2 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0
  1. /* DeBR - GeBR Designer
  2. * Copyright (C) 2007-2009 GeBR core team (http://www.gebrproject.com/)
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <regex.h>
  21. #include <glib/gi18n.h>
  22. #include <libgebr/date.h>
  23. #include <libgebr/gui/gebr-gui-utils.h>
  24. #include "debr-validate.h"
  25. #include "debr.h"
  26. #include "debr-callbacks.h"
  27. #include <debr-help.h>
  28. static void validate_free(struct validate *validate);
  29. static gboolean validate_get_selected(GtkTreeIter * iter, gboolean warn_unselected);
  30. static void validate_clicked(void);
  31. void validate_setup_ui(void)
  32. {
  33. GtkWidget *hpanel;
  34. GtkWidget *scrolled_window;
  35. GtkWidget *frame;
  36. GtkTreeViewColumn *col;
  37. GtkCellRenderer *renderer;
  38. hpanel = gtk_hpaned_new();
  39. debr.ui_validate.widget = hpanel;
  40. /*
  41. * Left side
  42. */
  43. frame = gtk_frame_new("");
  44. gtk_paned_pack1(GTK_PANED(hpanel), frame, FALSE, FALSE);
  45. debr.ui_validate.list_store = gtk_list_store_new(VALIDATE_N_COLUMN,
  46. GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER);
  47. scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  48. gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC,
  49. GTK_POLICY_AUTOMATIC);
  50. gtk_container_add(GTK_CONTAINER(frame), scrolled_window);
  51. debr.ui_validate.tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(debr.ui_validate.list_store));
  52. gtk_container_add(GTK_CONTAINER(scrolled_window), debr.ui_validate.tree_view);
  53. gtk_widget_set_size_request(GTK_WIDGET(scrolled_window), 180, 30);
  54. gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(debr.ui_validate.tree_view), FALSE);
  55. gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(debr.ui_validate.tree_view)),
  56. GTK_SELECTION_MULTIPLE);
  57. g_signal_connect(GTK_OBJECT(debr.ui_validate.tree_view), "cursor-changed", G_CALLBACK(validate_clicked), NULL);
  58. renderer = gtk_cell_renderer_pixbuf_new();
  59. col = gtk_tree_view_column_new_with_attributes("", renderer, NULL);
  60. gtk_tree_view_append_column(GTK_TREE_VIEW(debr.ui_validate.tree_view), col);
  61. gtk_tree_view_column_add_attribute(col, renderer, "pixbuf", VALIDATE_ICON);
  62. renderer = gtk_cell_renderer_text_new();
  63. col = gtk_tree_view_column_new_with_attributes("", renderer, NULL);
  64. gtk_tree_view_append_column(GTK_TREE_VIEW(debr.ui_validate.tree_view), col);
  65. gtk_tree_view_column_add_attribute(col, renderer, "text", VALIDATE_FILENAME);
  66. /*
  67. * Right side
  68. */
  69. debr.ui_validate.text_view_vbox = gtk_vbox_new(FALSE, 0);
  70. gtk_paned_pack2(GTK_PANED(hpanel), debr.ui_validate.text_view_vbox, TRUE, TRUE);
  71. gtk_widget_show_all(debr.ui_validate.widget);
  72. }
  73. static void validate_append_text(struct validate *validate, const gchar * format, ...);
  74. static void validate_append_text_emph(struct validate *validate, const gchar * format, ...);
  75. static void validate_append_text_error(struct validate *validate, gint failed_flags, const gchar *program_path,
  76. const gchar *parameter_path, GebrValidateCaseName, const gchar * format, ...);
  77. void validate_menu(GtkTreeIter * iter)
  78. {
  79. struct validate *validate;
  80. GtkWidget *scrolled_window;
  81. GtkWidget *text_view;
  82. GtkTextBuffer *text_buffer;
  83. gboolean updated = FALSE;
  84. gdouble scroll_hvalue = 0;
  85. gdouble scroll_vvalue = 0;
  86. gtk_tree_model_get(GTK_TREE_MODEL(debr.ui_menu.model), iter, MENU_VALIDATE_POINTER, &validate, -1);
  87. if (validate != NULL) {
  88. updated = TRUE;
  89. validate->menu_iter = *iter;
  90. scroll_hvalue = gtk_adjustment_get_value(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(validate->widget)));
  91. scroll_vvalue = gtk_adjustment_get_value(gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(validate->widget)));
  92. gtk_text_buffer_set_text(validate->text_buffer, "", 0);
  93. goto out;
  94. }
  95. scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  96. gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC,
  97. GTK_POLICY_AUTOMATIC);
  98. gtk_box_pack_end(GTK_BOX(debr.ui_validate.text_view_vbox), scrolled_window, TRUE, TRUE, 0);
  99. text_buffer = gtk_text_buffer_new(NULL);
  100. text_view = gtk_text_view_new_with_buffer(text_buffer);
  101. gtk_widget_show(text_view);
  102. gtk_container_add(GTK_CONTAINER(scrolled_window), text_view);
  103. g_object_set(G_OBJECT(text_view), "editable", FALSE, "cursor-visible", FALSE, NULL);
  104. PangoFontDescription *font = pango_font_description_new();
  105. pango_font_description_set_family(font, "monospace");
  106. gtk_widget_modify_font(text_view, font);
  107. pango_font_description_free(font);
  108. GebrGeoXmlValidateOperations operations;
  109. operations.append_text = (void(*)(gpointer,const gchar*,...))validate_append_text;
  110. operations.append_text_emph = (void(*)(gpointer,const gchar*,...))validate_append_text_emph;
  111. operations.append_text_error = NULL;
  112. operations.append_text_error_with_paths = (void(*)(gpointer, gint, const gchar *, const gchar *, GebrValidateCaseName, const gchar *,
  113. ...))validate_append_text_error;
  114. GebrGeoXmlValidateOptions options;
  115. options.all = TRUE;
  116. options.ehelp = -1;
  117. validate = g_new(struct validate, 1);
  118. validate->widget = scrolled_window;
  119. validate->text_view = text_view;
  120. validate->text_buffer = text_buffer;
  121. validate->menu_iter = *iter;
  122. validate->geoxml_validate = gebr_geoxml_validate_new(validate, operations, options);
  123. gtk_list_store_append(debr.ui_validate.list_store, &validate->iter);
  124. out:
  125. gtk_tree_store_set(debr.ui_menu.model, iter, MENU_VALIDATE_NEED_UPDATE, FALSE,
  126. MENU_VALIDATE_POINTER, validate, -1);
  127. GebrGeoXmlFlow * menu = menu_get_xml_pointer(iter);
  128. gint error_count = gebr_geoxml_validate_report_menu(validate->geoxml_validate, menu);
  129. gtk_list_store_set(debr.ui_validate.list_store, &validate->iter,
  130. VALIDATE_ICON, !error_count ? debr.pixmaps.stock_apply : debr.pixmaps.stock_warning,
  131. VALIDATE_FILENAME, gebr_geoxml_document_get_filename(GEBR_GEOXML_DOCUMENT(menu)),
  132. VALIDATE_POINTER, validate, -1);
  133. validate_set_selected(&validate->iter);
  134. if (updated) {
  135. gtk_adjustment_set_value(gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(validate->widget)), scroll_hvalue);
  136. gtk_adjustment_set_value(gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(validate->widget)), scroll_vvalue);
  137. }
  138. }
  139. void validate_close(void)
  140. {
  141. GtkTreeIter iter;
  142. gebr_gui_gtk_tree_view_foreach_selected(&iter, debr.ui_validate.tree_view)
  143. validate_close_iter(&iter);
  144. }
  145. void validate_close_iter(GtkTreeIter *iter)
  146. {
  147. struct validate *validate;
  148. gtk_tree_model_get(GTK_TREE_MODEL(debr.ui_validate.list_store), iter, VALIDATE_POINTER, &validate, -1);
  149. gtk_tree_store_set(debr.ui_menu.model, &validate->menu_iter,
  150. MENU_VALIDATE_POINTER, NULL,
  151. MENU_VALIDATE_NEED_UPDATE, TRUE,
  152. -1);
  153. validate_free(validate);
  154. }
  155. void validate_set_selected(GtkTreeIter * iter)
  156. {
  157. gebr_gui_gtk_tree_view_select_iter(GTK_TREE_VIEW(debr.ui_validate.tree_view), iter);
  158. }
  159. void validate_clear(void)
  160. {
  161. GtkTreeIter iter;
  162. gebr_gui_gtk_tree_model_foreach(iter, GTK_TREE_MODEL(debr.ui_validate.list_store))
  163. validate_close_iter(&iter);
  164. }
  165. GtkWidget *validate_image_warning_new(void)
  166. {
  167. return gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_SMALL_TOOLBAR);
  168. }
  169. void validate_image_set_warning(GtkWidget * image, const gchar *markup)
  170. {
  171. g_object_set(G_OBJECT(image), "visible", markup != NULL ? TRUE : FALSE, NULL);
  172. gtk_widget_set_tooltip_markup(image, markup);
  173. }
  174. void validate_image_set_check_help(GtkWidget * image, const gchar *help)
  175. {
  176. if (strlen(help) <= 2)
  177. validate_image_set_warning(image, _("Help is empty"));
  178. else
  179. validate_image_set_warning(image, NULL);
  180. }
  181. void validate_image_set_check_category_list(GtkWidget * image, GebrGeoXmlFlow * menu)
  182. {
  183. GebrGeoXmlSequence *sequence;
  184. gebr_geoxml_flow_get_category(menu, &sequence, 0);
  185. if (sequence == NULL)
  186. validate_image_set_warning(image, _("No category is set"));
  187. else
  188. validate_image_set_warning(image, NULL);
  189. }
  190. void validate_image_set_check_enum_option_list(GtkWidget * image, GebrGeoXmlProgramParameter * enum_parameter)
  191. {
  192. GebrGeoXmlSequence *sequence;
  193. gebr_geoxml_program_parameter_get_enum_option(enum_parameter, &sequence, 0);
  194. if (sequence == NULL)
  195. validate_image_set_warning(image, _("No option is set"));
  196. else
  197. validate_image_set_warning(image, NULL);
  198. }
  199. /**
  200. * \internal
  201. * Frees \p validate its iter and interface.
  202. */
  203. static void validate_free(struct validate *validate)
  204. {
  205. gtk_list_store_remove(debr.ui_validate.list_store, &validate->iter);
  206. gtk_widget_destroy(validate->widget);
  207. gebr_geoxml_validate_free(validate->geoxml_validate);
  208. g_free(validate);
  209. }
  210. /**
  211. * \internal
  212. * Show selected menu report.
  213. */
  214. static gboolean validate_get_selected(GtkTreeIter * iter, gboolean warn_unselected)
  215. {
  216. if (gebr_gui_gtk_tree_view_get_selected(GTK_TREE_VIEW(debr.ui_validate.tree_view), iter) == FALSE) {
  217. if (warn_unselected)
  218. debr_message(GEBR_LOG_ERROR, _("No menu selected"));
  219. return FALSE;
  220. }
  221. return TRUE;
  222. }
  223. /**
  224. * \internal
  225. * Show selected menu report.
  226. */
  227. static void validate_clicked(void)
  228. {
  229. GtkTreeIter iter;
  230. struct validate *validate;
  231. if (!validate_get_selected(&iter, FALSE))
  232. return;
  233. gtk_tree_model_get(GTK_TREE_MODEL(debr.ui_validate.list_store), &iter, VALIDATE_POINTER, &validate, -1);
  234. gtk_container_forall(GTK_CONTAINER(debr.ui_validate.text_view_vbox), (GtkCallback) gtk_widget_hide, NULL);
  235. gtk_widget_show(validate->widget);
  236. }
  237. /**
  238. * \internal
  239. */
  240. static void
  241. validate_insert_text_valist(struct validate *validate, GtkTextTag * text_tag, GtkTextIter * iter, const gchar * format, va_list argp)
  242. {
  243. if (format == NULL)
  244. return;
  245. gchar *string;
  246. string = g_strdup_vprintf(format, argp);
  247. gtk_text_buffer_insert_with_tags(validate->text_buffer, iter, string, -1, text_tag, NULL);
  248. g_free(string);
  249. }
  250. /**
  251. * \internal
  252. * Appends text to \p validate's text buffer applying \p text_tag to it.
  253. *
  254. * \param text_tag A GtkTextTag determining the style for \p format.
  255. * \param format Text to be inserted, in printf-like format.
  256. * \param argp List of arguments for \p format.
  257. *
  258. * \see validate_append_text
  259. */
  260. static void
  261. validate_append_text_valist(struct validate *validate, GtkTextTag * text_tag, const gchar * format, va_list argp)
  262. {
  263. GtkTextIter iter;
  264. gtk_text_buffer_get_end_iter(validate->text_buffer, &iter);
  265. validate_insert_text_valist(validate, text_tag, &iter, format, argp);
  266. }
  267. /**
  268. * \internal
  269. * Appends \p format to \p validate's text buffer, applying \p text_tag to it.
  270. *
  271. * \see validate_append_text_valist
  272. */
  273. static void validate_append_text_with_tag(struct validate *validate, GtkTextTag * text_tag, const gchar * format, ...)
  274. {
  275. va_list argp;
  276. va_start(argp, format);
  277. validate_append_text_valist(validate, text_tag, format, argp);
  278. va_end(argp);
  279. }
  280. /**
  281. * \internal
  282. */
  283. static void validate_parse_link_click_callback(GtkTextView * text_view, GtkTextTag * link_tag, const gchar * url,
  284. struct validate *validate)
  285. {
  286. GtkTreeIter menu_iter;
  287. gint validate_case;
  288. validate_case = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(link_tag), "validate_case"));
  289. if (!menu_get_selected(&menu_iter, FALSE) ||
  290. !gebr_gui_gtk_tree_model_iter_equal_to(GTK_TREE_MODEL(debr.ui_menu.model), &menu_iter,
  291. &validate->menu_iter))
  292. menu_select_iter(&validate->menu_iter);
  293. gchar *program_path = g_object_get_data(G_OBJECT(link_tag), "program_path_string");
  294. gchar *parameter_path = g_object_get_data(G_OBJECT(link_tag), "parameter_path_string");
  295. gboolean ret = FALSE;
  296. if (program_path != NULL) {
  297. menu_select_program_and_paramater(program_path, parameter_path);
  298. if (parameter_path != NULL)
  299. ret = on_parameter_properties_activate();
  300. else
  301. if (validate_case == GEBR_VALIDATE_CASE_HELP)
  302. debr_help_edit(GEBR_GEOXML_OBJECT(debr.program));
  303. else
  304. ret = on_program_properties_activate();
  305. } else
  306. if (validate_case == GEBR_VALIDATE_CASE_HELP)
  307. debr_help_edit(GEBR_GEOXML_OBJECT(debr.menu));
  308. else
  309. ret = on_menu_properties_activate();
  310. if (ret)
  311. validate_menu(&validate->menu_iter);
  312. }
  313. /**
  314. * \internal
  315. * Appends text to \p validate's text buffer referencing \p url.
  316. */
  317. static GtkTextTag *
  318. validate_append_link(struct validate *validate, const gchar *text, const gchar *url)
  319. {
  320. GtkTextTag *tag;
  321. tag = gebr_gui_gtk_text_view_create_link_tag(GTK_TEXT_VIEW(validate->text_view), url,
  322. (GebrGuiGtkTextViewLinkClickCallback)validate_parse_link_click_callback, validate);
  323. validate_append_text_with_tag(validate, tag, text);
  324. return tag;
  325. }
  326. /**
  327. * \internal
  328. * Appends \p text into validate log with pair of style/values, as seen in #GtkTextTag properties.
  329. *
  330. * \see GtkTextTag
  331. */
  332. static GtkTextTag *
  333. validate_append_text_with_property_list(struct validate *validate, const gchar * text,
  334. const gchar * first_property_name, ...)
  335. {
  336. GtkTextTag *text_tag;
  337. va_list argp;
  338. text_tag = gtk_text_tag_new(NULL);
  339. gtk_text_tag_table_add(gtk_text_buffer_get_tag_table(validate->text_buffer), text_tag);
  340. va_start(argp, first_property_name);
  341. g_object_set_valist(G_OBJECT(text_tag), first_property_name, argp);
  342. va_end(argp);
  343. validate_append_text_with_tag(validate, text_tag, text);
  344. return text_tag;
  345. }
  346. /**
  347. * \internal
  348. * Appends emphasized text in validate log, with printf-like \p format.
  349. *
  350. * \see validate_append_text
  351. */
  352. static void validate_append_text_emph(struct validate *validate, const gchar * format, ...)
  353. {
  354. gchar *string;
  355. va_list argp;
  356. va_start(argp, format);
  357. string = g_strdup_vprintf(format, argp);
  358. validate_append_text_with_property_list(validate, string, "weight", PANGO_WEIGHT_BOLD, NULL);
  359. va_end(argp);
  360. g_free(string);
  361. }
  362. /**
  363. * \internal
  364. * Appends text in validate log, with printf-like \p format.
  365. */
  366. static void validate_append_text(struct validate *validate, const gchar * format, ...)
  367. {
  368. gchar *string;
  369. va_list argp;
  370. va_start(argp, format);
  371. string = g_strdup_vprintf(format, argp);
  372. validate_append_text_with_tag(validate, NULL, "%s", string);
  373. va_end(argp);
  374. g_free(string);
  375. }
  376. /**
  377. * \internal
  378. * Appends \p format into \p validate buffer, indicating error (by setting the text color to red).
  379. * If \p fix_flags in non-zero then add a fix link after text.
  380. * If \p edit_id is non-zero the add an edit link after text.
  381. */
  382. static void validate_append_text_error(struct validate *validate, gint failed_flags, const gchar *program_path,
  383. const gchar *parameter_path, GebrValidateCaseName validate_case, const gchar * format, ...)
  384. {
  385. GtkTextTag *text_tag;
  386. gchar *string;
  387. va_list argp;
  388. va_start(argp, format);
  389. string = g_strdup_vprintf(format, argp);
  390. text_tag = validate_append_text_with_property_list(validate, string, "foreground", "#ff0000", NULL);
  391. va_end(argp);
  392. g_free(string);
  393. /* error tooltip */
  394. gchar *error_msg = gebr_validate_flags_failed_msg(failed_flags);
  395. gebr_gui_gtk_text_view_set_tooltip_on_tag(GTK_TEXT_VIEW(validate->text_view), text_tag, error_msg);
  396. g_free(error_msg);
  397. GtkTextTag *link_tag;
  398. validate_append_text(validate, " ");
  399. link_tag = validate_append_link(validate, _("Edit"), "");
  400. gchar *tmp = g_strdup(program_path);
  401. g_object_set_data(G_OBJECT(link_tag), "program_path_string", tmp);
  402. g_object_set_data(G_OBJECT(link_tag), "validate_case", GINT_TO_POINTER(validate_case));
  403. gebr_gui_g_object_set_free_parent(link_tag, tmp);
  404. tmp = g_strdup(parameter_path);
  405. g_object_set_data(G_OBJECT(link_tag), "parameter_path_string", tmp);
  406. gebr_gui_g_object_set_free_parent(link_tag, tmp);
  407. }