diff options
author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:56 -0300 |
---|---|---|
committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:56 -0300 |
commit | 754b5d1114f096778e483f8a6f3a5dc333225e26 (patch) | |
tree | 30911ec9da4cfd2f5572c27f7288fcbfa4cd212d /shell/report.c | |
parent | 35c2857da302ab8b3c308052f2cd1674fb4141a6 (diff) | |
parent | 5f01c706267c595de92406a32e7f31ef5056c2d0 (diff) |
Update upstream source from tag 'upstream/2.0.3pre'
Update to upstream version '2.0.3pre'
with Debian dir 6683980bf6b5c02f6847fd56765833301f75f4f3
Diffstat (limited to 'shell/report.c')
-rw-r--r-- | shell/report.c | 1284 |
1 files changed, 1284 insertions, 0 deletions
diff --git a/shell/report.c b/shell/report.c new file mode 100644 index 00000000..25b73beb --- /dev/null +++ b/shell/report.c @@ -0,0 +1,1284 @@ +/* + * HardInfo - Displays System Information + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> + * + * 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, version 2 or later. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <report.h> +#include <stdio.h> +#include <string.h> +#include <shell.h> +#include <iconcache.h> +#include <hardinfo.h> +#include <config.h> +#include "uri_handler.h" + +static ReportDialog *report_dialog_new(GtkTreeModel * model, + GtkWidget * parent); +static void set_all_active(ReportDialog * rd, gboolean setting); + +static FileTypes file_types[] = { + {"HTML (*.html)", "text/html", ".html", report_context_html_new}, + {"Plain Text (*.txt)", "text/plain", ".txt", report_context_text_new}, + {"Shell Dump (*.txt)", "text/plain", ".txt", report_context_shell_new}, + {NULL, NULL, NULL, NULL} +}; + +/* virtual functions */ +void report_header(ReportContext * ctx) +{ ctx->header(ctx); } + +void report_footer(ReportContext * ctx) +{ ctx->footer(ctx); } + +void report_title(ReportContext * ctx, gchar * text) +{ ctx->title(ctx, text); } + +void report_subtitle(ReportContext * ctx, gchar * text) +{ ctx->subtitle(ctx, text); } + +void report_subsubtitle(ReportContext * ctx, gchar * text) +{ ctx->subsubtitle(ctx, text); } + +void report_key_value(ReportContext * ctx, gchar *key, gchar *value, gsize longest_key) +{ ctx->keyvalue(ctx, key, value, longest_key); } + +void report_details_start(ReportContext *ctx, gchar *key, gchar *value, gsize longest_key) +{ ctx->details_start(ctx, key, value, longest_key); } + +void report_details_section(ReportContext *ctx, gchar *label) +{ ctx->details_section(ctx, label); } + +void report_details_keyvalue(ReportContext *ctx, gchar *key, gchar *value, gsize longest_key) +{ ctx->details_keyvalue(ctx, key, value, longest_key); } + +void report_details_end(ReportContext *ctx) +{ ctx->details_end(ctx); } +/* end virtual functions */ + +gint report_get_visible_columns(ReportContext *ctx) +{ + gint columns; + + /* Column count starts at two, since we always have at least + two columns visible. */ + columns = 2; + + /* Either the Progress column or the Value column is available at + the same time. So we don't count them. */ + + if (ctx->columns & REPORT_COL_EXTRA1) + columns++; + + if (ctx->columns & REPORT_COL_EXTRA2) + columns++; + + return columns; +} + +gchar *icon_name_css_id(const gchar *file) { + gchar *safe = g_strdup_printf("icon-%s", file); + gchar *p = safe; + while(*p) { + if (!isalnum(*p)) + *p = '-'; + p++; + } + return safe; +} + +gchar *make_icon_css(const gchar *file) { + if (!file || *file == 0) + return g_strdup(""); + gchar *ret = NULL; + gchar *path = g_build_filename(params.path_data, "pixmaps", file, NULL); + gchar *contents = NULL; + gsize length = 0; + if ( g_file_get_contents(path, &contents, &length, NULL) ) { + gchar *css_class = icon_name_css_id(file); + const char *ctype = "image/png"; + if (g_str_has_suffix(file, ".svg") ) + ctype = "image/svg+xml"; + gchar *b64data = g_base64_encode(contents, length); + ret = g_strdup_printf( + ".%s\n" + "{ background: url(data:%s;base64,%s) no-repeat;\n" + " background-size: cover; }\n", + css_class ? css_class : "", + ctype, b64data ); + g_free(b64data); + g_free(css_class); + } + g_free(contents); + g_free(path); + return ret ? ret : g_strdup(""); +} + +void cache_icon(ReportContext *ctx, const gchar *file) { + if (!ctx->icon_data) return; + if (!g_hash_table_lookup(ctx->icon_data, file) ) + g_hash_table_insert(ctx->icon_data, g_strdup(file), make_icon_css(file)); +} + +void report_context_configure(ReportContext * ctx, GKeyFile * keyfile) +{ + gchar **keys; + const gchar *group = "$ShellParam$"; + + if (ctx->icon_refs) { + g_hash_table_remove_all(ctx->icon_refs); + ctx->icon_refs = NULL; + } + ctx->icon_refs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + keys = g_key_file_get_keys(keyfile, group, NULL, NULL); + if (keys) { + gint i = 0; + + for (; keys[i]; i++) { + gchar *key = keys[i]; + + if (g_str_equal(key, "ShowColumnHeaders")) { + ctx->show_column_headers = g_key_file_get_boolean(keyfile, group, key, NULL); + } else if (g_str_has_prefix(key, "ColumnTitle")) { + gchar *value, *title = strchr(key, '$'); + + if (!title) { + DEBUG("couldn't find column title"); + break; + } + title++; + if (!*title) { + DEBUG("title is empty"); + break; + } + + value = g_key_file_get_value(keyfile, group, key, NULL); + if (g_str_equal(title, "Extra1")) { + ctx->columns |= REPORT_COL_EXTRA1; + } else if (g_str_equal(title, "Extra2")) { + ctx->columns |= REPORT_COL_EXTRA2; + } else if (g_str_equal(title, "Value")) { + ctx->columns |= REPORT_COL_VALUE; + } else if (g_str_equal(title, "TextValue")) { + ctx->columns |= REPORT_COL_TEXTVALUE; + } else if (g_str_equal(title, "Progress")) { + ctx->columns |= REPORT_COL_PROGRESS; + } + + g_hash_table_replace(ctx->column_titles, + g_strdup(title), g_strdup(value)); + } else if (g_str_equal(key, "ViewType")) { + if (g_key_file_get_integer(keyfile, group, "ViewType", NULL) == SHELL_VIEW_PROGRESS) { + ctx->columns &= ~REPORT_COL_VALUE; + ctx->columns |= REPORT_COL_PROGRESS; + } + } else if (g_str_has_prefix(key, "Icon$")) { + gchar *ikey = g_utf8_strchr(key, -1, '$'); + gchar *tag = key_mi_tag(ikey); + gchar *icon = g_key_file_get_value(keyfile, group, key, NULL); + cache_icon(ctx, icon); + g_hash_table_insert(ctx->icon_refs, tag, icon); + } + } + + g_strfreev(keys); + } + +} + +static void report_html_details_start(ReportContext *ctx, gchar *key, gchar *value, gsize longest_key) { + guint cols = report_get_visible_columns(ctx); + report_key_value(ctx, key, value, longest_key); + ctx->parent_columns = ctx->columns; + ctx->columns = REPORT_COL_VALUE; + ctx->output = h_strdup_cprintf("<tr><td colspan=\"%d\"><table class=\"details\">\n", ctx->output, cols); +} + +static void report_html_details_end(ReportContext *ctx) { + ctx->output = h_strdup_cprintf("</table></td></tr>\n", ctx->output); + ctx->columns = ctx->parent_columns; + ctx->parent_columns = 0; +} + +void report_details(ReportContext *ctx, gchar *key, gchar *value, gchar *details, gsize longest_key) +{ + GKeyFile *key_file = g_key_file_new(); + gchar **groups; + gint i; + + report_details_start(ctx, key, value, longest_key); + ctx->in_details = TRUE; + + g_key_file_load_from_data(key_file, details, strlen(details), 0, NULL); + groups = g_key_file_get_groups(key_file, NULL); + + for (i = 0; groups[i]; i++) { + gchar *group, *tmpgroup; + gchar **keys; + gint j; + + if (groups[i][0] == '$') { + continue; + } + + group = groups[i]; + + tmpgroup = g_strdup(group); + strend(group, '#'); + + report_subsubtitle(ctx, group); + + keys = g_key_file_get_keys(key_file, tmpgroup, NULL, NULL); + + gsize longest_key = 0; + for (j = 0; keys[j]; j++) { + gchar *lbl; + key_get_components(keys[j], NULL, NULL, NULL, &lbl, NULL, TRUE); + longest_key = MAX(longest_key, strlen(lbl)); + g_free(lbl); + } + + for (j = 0; keys[j]; j++) { + gchar *key = keys[j]; + gchar *raw_value, *value; + + raw_value = g_key_file_get_value(key_file, tmpgroup, key, NULL); + value = g_strcompress(raw_value); /* un-escape \n, \t, etc */ + + if (g_utf8_validate(key, -1, NULL) && g_utf8_validate(value, -1, NULL)) { + strend(key, '#'); + + if (g_str_equal(value, "...")) { + g_free(value); + if (!(value = ctx->entry->fieldfunc(key))) { + value = g_strdup("..."); + } + } + + report_key_value(ctx, key, value, longest_key); + + } + + g_free(value); + g_free(raw_value); + } + + g_strfreev(keys); + g_free(tmpgroup); + } + + g_strfreev(groups); + g_key_file_free(key_file); + + ctx->in_details = FALSE; + report_details_end(ctx); +} + +static void report_table_shell_dump(ReportContext *ctx, gchar *key_file_str, int level) +{ + gchar *text, *p, *next_nl, *eq, *indent; + gchar *key, *value; + + indent = g_strnfill(level * 4, ' '); + + if (key_file_str) { + p = text = g_strdup(key_file_str); + while(next_nl = strchr(p, '\n')) { + *next_nl = 0; + eq = strchr(p, '='); + if (*p != '[' && eq) { + *eq = 0; + key = p; value = eq + 1; + + ctx->output = h_strdup_cprintf("%s%s=%s\n", ctx->output, indent, key, value); + if (key_wants_details(key) || params.force_all_details) { + gchar *mi_tag = key_mi_tag(key); + gchar *mi_data = ctx->entry->morefunc(mi_tag); /*const*/ + + if (mi_data) + report_table_shell_dump(ctx, mi_data, level + 1); + + g_free(mi_tag); + } + + } else + ctx->output = h_strdup_cprintf("%s%s\n", ctx->output, indent, p); + p = next_nl + 1; + } + } + g_free(text); + g_free(indent); + return; +} + +void report_table(ReportContext * ctx, gchar * text) +{ + GKeyFile *key_file = NULL; + gchar **groups; + gint i; + + if (ctx->format == REPORT_FORMAT_SHELL) { + report_table_shell_dump(ctx, text, 0); + return; + } + + key_file = g_key_file_new(); + + /* make only "Value" column visible ("Key" column is always visible) */ + ctx->columns = REPORT_COL_VALUE; + ctx->show_column_headers = FALSE; + + /**/ + g_key_file_load_from_data(key_file, text, strlen(text), 0, NULL); + groups = g_key_file_get_groups(key_file, NULL); + + for (i = 0; groups[i]; i++) { + if (groups[i][0] == '$') { + report_context_configure(ctx, key_file); + break; + } + } + + for (i = 0; groups[i]; i++) { + gchar *group, *tmpgroup; + gchar **keys; + gint j; + + if (groups[i][0] == '$') { + continue; + } + + group = groups[i]; + + tmpgroup = g_strdup(group); + strend(group, '#'); + + report_subsubtitle(ctx, group); + + keys = g_key_file_get_keys(key_file, tmpgroup, NULL, NULL); + + gsize longest_key = 0; + for (j = 0; keys[j]; j++) { + gchar *lbl; + key_get_components(keys[j], NULL, NULL, NULL, &lbl, NULL, TRUE); + longest_key = MAX(longest_key, strlen(lbl)); + g_free(lbl); + } + + for (j = 0; keys[j]; j++) { + gchar *key = keys[j]; + gchar *raw_value, *value; + + raw_value = g_key_file_get_value(key_file, tmpgroup, key, NULL); + value = g_strcompress(raw_value); /* un-escape \n, \t, etc */ + + if (g_utf8_validate(key, -1, NULL) && g_utf8_validate(value, -1, NULL)) { + strend(key, '#'); + + if (g_str_equal(value, "...")) { + g_free(value); + if (!(value = ctx->entry->fieldfunc(key))) { + value = g_strdup("..."); + } + } + + if ( key_is_flagged(key) ) { + gchar *mi_tag = key_mi_tag(key); + gchar *mi_data = NULL; /*const*/ + + if (key_wants_details(key) || params.force_all_details) + mi_data = ctx->entry->morefunc(mi_tag); + + if (mi_data) + report_details(ctx, key, value, mi_data, longest_key); + else + report_key_value(ctx, key, value, longest_key); + + g_free(mi_tag); + } else { + report_key_value(ctx, key, value, longest_key); + } + + } + + g_free(value); + g_free(raw_value); + } + + g_strfreev(keys); + + g_free(tmpgroup); + } + + g_strfreev(groups); + g_key_file_free(key_file); +} + +static void report_html_header(ReportContext * ctx) +{ + g_free(ctx->output); + + ctx->output = + g_strdup_printf + ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Final//EN\">\n" + "<html><head>\n" "<title>HardInfo (%s) System Report</title>\n" + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" + "<style>\n" " body { background: #fff }\n" + " .title { font: bold 130%% serif; color: #0066FF; padding: 30px 0 10px 0 }\n" + " .stitle { font: bold 100%% sans-serif; color: #0044DD; padding: 0 0 0 0; }\n" + " .sstitle{ font: bold 80%% serif; color: #000000; background: #efefef }\n" + " .field { font: 80%% sans-serif; color: #000000; padding: 2px; }\n" + " .value { font: 80%% sans-serif; color: #505050 }\n" + " .hilight { font: bold 110%% sans-serif; color: #000000; background: #ffff66 }\n" + " table.details { margin-left: 50px; }\n" + " td.icon { width: 1.2em; padding-left: 1.2em; }\n" + " td.icon img { width: 1.2em; }\n" + " td.icon div { display: block; box-sizing: border-box; -moz-box-sizing: border-box;\n" + " width: 1.2em; height: 1.2em; background-position: right; }\n" + " td.icon_subtitle div { display: block; box-sizing: border-box; -moz-box-sizing: border-box;\n" + " width: 1.8em; height: 1.8em; background-position: right; }\n" + "</style>\n" "</head><body>\n", + VERSION); +} + +static void report_html_footer(ReportContext * ctx) +{ + ctx->output = h_strconcat(ctx->output, "</table>", NULL); + ctx->output = h_strconcat(ctx->output, "<style>\n", NULL); + GList *l = NULL, *keys = g_hash_table_get_keys(ctx->icon_data); + for(l = keys; l; l = l->next) { + gchar *data = g_hash_table_lookup(ctx->icon_data, (gchar*)l->data); + if (data) + ctx->output = h_strconcat(ctx->output, data, NULL); + } + g_list_free(keys); + ctx->output = h_strconcat(ctx->output, "</style>\n", NULL); + ctx->output = h_strconcat(ctx->output, "</html>", NULL); +} + +static void report_html_title(ReportContext * ctx, gchar * text) +{ + if (!ctx->first_table) { + ctx->output = h_strdup_cprintf("</table>", ctx->output); + } + + ctx->output = h_strdup_cprintf("<h1 class=\"title\">%s</h1>", ctx->output, text); +} + +static void report_html_subtitle(ReportContext * ctx, gchar * text) +{ + gint columns = report_get_visible_columns(ctx); + + if (!ctx->first_table) { + ctx->output = h_strdup_cprintf("</table>", ctx->output); + } else { + ctx->first_table = FALSE; + } + + gchar *icon = NULL; + if (ctx->entry->icon_file) { + gchar *icon_class = icon_name_css_id(ctx->entry->icon_file); + icon = g_strdup_printf("<div class=\"%s\"></div>", icon_class); + g_free(icon_class); + } else { + icon = g_strdup(""); + } + + ctx->output = h_strdup_cprintf("<table><tr><td class=\"icon_subtitle\">%s</td><td colspan=\"%d\" class=\"stit" + "le\">%s</td></tr>\n", + ctx->output, + icon, + columns, + text); + g_free(icon); +} + +static void report_html_subsubtitle(ReportContext * ctx, gchar * text) +{ + gint columns = report_get_visible_columns(ctx); + + ctx->output = h_strdup_cprintf("<tr><td colspan=\"%d\" class=\"ssti" + "tle\">%s</td></tr>\n", + ctx->output, + columns+1, + text); +} + +static void +report_html_key_value(ReportContext * ctx, gchar *key, gchar *value, gsize longest_key) +{ + gint columns = report_get_visible_columns(ctx); + gchar **values; + gint i, mc; + + gboolean highlight = key_is_highlighted(key); + gchar *tag = key_mi_tag(key); + gchar *icon = tag ? (gchar*)g_hash_table_lookup(ctx->icon_refs, tag) : NULL; + g_free(tag); + /* icon from the table is const, so can be re-used without free */ + if (icon) { + gchar *icon_class = icon_name_css_id(icon); + icon = g_strdup_printf("<div class=\"%s\"></div>", icon_class); + g_free(icon_class); + } else + icon = g_strdup(""); + + gchar *name = (gchar*)key_get_name(key); + + if (columns == 2) { + ctx->output = h_strdup_cprintf("<tr%s><td class=\"icon\">%s</td><td class=\"field\">%s</td>" + "<td class=\"value\">%s</td></tr>\n", + ctx->output, + highlight ? " class=\"hilight\"" : "", + icon, name, value); + } else { + values = g_strsplit(value, "|", columns); + mc = g_strv_length(values) - 1; + + ctx->output = h_strdup_cprintf("\n<tr%s>\n<td class=\"icon\">%s</td><td class=\"field\">%s</td>", ctx->output, highlight ? " class=\"hilight\"" : "", icon, name); + + for (i = mc; i >= 0; i--) { + ctx->output = h_strdup_cprintf("<td class=\"value\">%s</td>", + ctx->output, + values[i]); + } + + ctx->output = h_strdup_cprintf("</tr>\n", ctx->output); + + g_strfreev(values); + } + g_free(icon); +} + +static void report_text_header(ReportContext * ctx) +{ + g_free(ctx->output); + + ctx->output = g_strdup(""); +} + +static void report_text_footer(ReportContext * ctx) +{ +} + +static void report_text_title(ReportContext * ctx, gchar * text) +{ + gchar *str = (gchar *) ctx->output; + int i = strlen(text); + + str = h_strdup_cprintf("\n%s\n", str, text); + for (; i; i--) + str = h_strconcat(str, "*", NULL); + + str = h_strconcat(str, "\n\n", NULL); + ctx->output = str; +} + +static void report_text_subtitle(ReportContext * ctx, gchar * text) +{ + gchar *str = ctx->output; + int i = strlen(text); + + str = h_strdup_cprintf("\n%s\n", str, text); + for (; i; i--) + str = h_strconcat(str, "-", NULL); + + str = h_strconcat(str, "\n\n", NULL); + ctx->output = str; +} + +static void report_text_subsubtitle(ReportContext * ctx, gchar * text) +{ + gchar indent[10] = " "; + if (!ctx->in_details) + indent[0] = 0; + ctx->output = h_strdup_cprintf("%s-%s-\n", ctx->output, indent, text); +} + +static void +report_text_key_value(ReportContext * ctx, gchar *key, gchar *value, gsize longest_key) +{ + gint columns = report_get_visible_columns(ctx); + gchar **values; + gint i, mc, field_width = MAX(10, longest_key); + gchar indent[10] = " "; + if (!ctx->in_details) + indent[0] = 0; + gchar field_spacer[51]; + for(i = 0; i < 49; i++) + field_spacer[i] = ' '; + field_width = MIN(50, field_width); + field_spacer[field_width] = 0; + + gboolean highlight = key_is_highlighted(key); + gboolean multiline = (value && strlen(value) && strchr(value, '\n')); + gchar *name = (gchar*)key_get_name(key); + gchar *pf = g_strdup_printf("%s%s", indent, highlight ? "* " : " "); + gchar *rjname = g_strdup(field_spacer); + if (strlen(name) > strlen(rjname)) + name[strlen(rjname)] = 0; + strcpy(rjname + strlen(rjname) - strlen(name), name); + + if (columns == 2 || ctx->in_details) { + if (strlen(value)) { + if (multiline) { + gchar **lines = g_strsplit(value, "\n", 0); + for(i=0; lines[i]; i++) { + if (i == 0) + ctx->output = h_strdup_cprintf("%s%s : %s\n", ctx->output, pf, rjname, lines[i]); + else + ctx->output = h_strdup_cprintf("%s%s %s\n", ctx->output, pf, field_spacer, lines[i]); + } + g_strfreev(lines); + } else { + ctx->output = h_strdup_cprintf("%s%s : %s\n", ctx->output, pf, rjname, value); + } + } else + ctx->output = h_strdup_cprintf("%s%s\n", ctx->output, pf, rjname); + } else { + values = g_strsplit(value, "|", columns); + mc = g_strv_length(values) - 1; + + ctx->output = h_strdup_cprintf("%s%s", ctx->output, pf, rjname); + + for (i = mc; i >= 0; i--) { + ctx->output = h_strdup_cprintf("\t%s", + ctx->output, + values[i]); + } + + ctx->output = h_strdup_cprintf("\n", ctx->output); + + g_strfreev(values); + } + g_free(pf); +} + +static GSList *report_create_module_list_from_dialog(ReportDialog * rd) +{ + ShellModule *module; + GSList *modules = NULL; + GtkTreeModel *model = rd->model; + GtkTreeIter iter; + + gtk_tree_model_get_iter_first(model, &iter); + do { + gboolean selected; + gchar *name; + + gtk_tree_model_get(model, &iter, TREE_COL_SEL, &selected, -1); + if (!selected) + continue; + + module = g_new0(ShellModule, 1); + + gtk_tree_model_get(model, &iter, TREE_COL_NAME, &name, -1); + module->name = name; + module->entries = NULL; + + if (gtk_tree_model_iter_has_child(model, &iter)) { + ShellModuleEntry *entry; + + gint children = gtk_tree_model_iter_n_children(model, &iter); + gint i; + + for (i = 0; i < children; i++) { + GtkTreeIter child; + + gtk_tree_model_iter_nth_child(model, &child, &iter, i); + + gtk_tree_model_get(model, &child, TREE_COL_SEL, &selected, + -1); + if (!selected) + continue; + + gtk_tree_model_get(model, &child, TREE_COL_MODULE_ENTRY, &entry, + -1); + module->entries = g_slist_append(module->entries, entry); + } + } + + modules = g_slist_append(modules, module); + } while (gtk_tree_model_iter_next(rd->model, &iter)); + + return modules; +} + +static void +report_create_inner_from_module_list(ReportContext * ctx, GSList * modules) +{ + for (; modules; modules = modules->next) { + ShellModule *module = (ShellModule *) modules->data; + GSList *entries; + + if (!params.gui_running && !params.quiet) + fprintf(stderr, "\033[40;32m%s\033[0m\n", module->name); + + report_title(ctx, module->name); + + for (entries = module->entries; entries; entries = entries->next) { + ShellModuleEntry *entry = (ShellModuleEntry *) entries->data; + if (entry->flags & MODULE_FLAG_HIDE) continue; + + if (!params.gui_running && !params.quiet) + fprintf(stderr, "\033[2K\033[40;32;1m %s\033[0m\n", + entry->name); + + if (entry->icon_file) + cache_icon(ctx, entry->icon_file); + + ctx->entry = entry; + report_subtitle(ctx, entry->name); + module_entry_scan(entry); + report_table(ctx, module_entry_function(entry)); + } + } +} + +void report_module_list_free(GSList * modules) +{ + GSList *m; + + for (m = modules; m; m = m->next) { + ShellModule *module = (ShellModule *) m->data; + + g_slist_free(module->entries); + } + + g_slist_free(modules); +} + +static gchar *report_get_filename(void) +{ + GtkWidget *dialog; + gchar *filename = NULL; + +#if GTK_CHECK_VERSION(3, 0, 0) + dialog = gtk_file_chooser_dialog_new(_("Save File"), + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + _("_Cancel"), + GTK_RESPONSE_CANCEL, + _("_Save"), + GTK_RESPONSE_ACCEPT, NULL); +#else + dialog = gtk_file_chooser_dialog_new(_("Save File"), + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, + GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, + GTK_RESPONSE_ACCEPT, NULL); +#endif + + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), + "hardinfo_report"); + + file_chooser_add_filters(dialog, file_types); + file_chooser_open_expander(dialog); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + gchar *ext = file_chooser_get_extension(dialog, file_types); + filename = file_chooser_build_filename(dialog, ext); + } + gtk_widget_destroy(dialog); + return filename; +} + +ReportContext *report_context_html_new() +{ + ReportContext *ctx; + + ctx = g_new0(ReportContext, 1); + ctx->header = report_html_header; + ctx->footer = report_html_footer; + ctx->title = report_html_title; + ctx->subtitle = report_html_subtitle; + ctx->subsubtitle = report_html_subsubtitle; + ctx->keyvalue = report_html_key_value; + + ctx->details_start = report_html_details_start; + ctx->details_section = report_html_subsubtitle; + ctx->details_keyvalue = report_html_key_value; + ctx->details_end = report_html_details_end; + + ctx->output = g_strdup(""); + ctx->format = REPORT_FORMAT_HTML; + + ctx->column_titles = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + ctx->first_table = TRUE; + + ctx->icon_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + return ctx; +} + +ReportContext *report_context_text_new() +{ + ReportContext *ctx; + + ctx = g_new0(ReportContext, 1); + ctx->header = report_text_header; + ctx->footer = report_text_footer; + ctx->title = report_text_title; + ctx->subtitle = report_text_subtitle; + ctx->subsubtitle = report_text_subsubtitle; + ctx->keyvalue = report_text_key_value; + + ctx->details_start = report_text_key_value; + ctx->details_section = report_text_subsubtitle; + ctx->details_keyvalue = report_text_key_value; + ctx->details_end = report_text_footer; /* nothing */ + + ctx->output = g_strdup(""); + ctx->format = REPORT_FORMAT_TEXT; + + ctx->column_titles = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + ctx->first_table = TRUE; + + return ctx; +} + +ReportContext *report_context_shell_new() +{ + ReportContext *ctx; + + ctx = g_new0(ReportContext, 1); + ctx->header = report_text_header; + ctx->footer = report_text_footer; + + ctx->title = report_text_title; + ctx->subtitle = report_text_subtitle; + /* special format handled in report_table(), + * doesn't need the others. */ + + ctx->output = g_strdup(""); + ctx->format = REPORT_FORMAT_SHELL; + + ctx->column_titles = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + ctx->first_table = TRUE; + + return ctx; +} + +void report_context_free(ReportContext * ctx) +{ + g_hash_table_destroy(ctx->column_titles); + if(ctx->icon_refs) + g_hash_table_destroy(ctx->icon_refs); + if(ctx->icon_data) + g_hash_table_destroy(ctx->icon_data); + g_free(ctx->output); + g_free(ctx); +} + +void report_create_from_module_list(ReportContext * ctx, GSList * modules) +{ + if (ctx->format == REPORT_FORMAT_HTML) + params.fmt_opts = FMT_OPT_HTML; + + report_header(ctx); + + report_create_inner_from_module_list(ctx, modules); + report_module_list_free(modules); + + report_footer(ctx); +} + +gchar *report_create_from_module_list_format(GSList * modules, + ReportFormat format) +{ + ReportContext *(*create_context) (); + ReportContext *ctx; + gchar *retval; + + if (format >= N_REPORT_FORMAT) + return NULL; + + create_context = file_types[format].data; + if (!create_context) + return NULL; + + ctx = create_context(); + + report_create_from_module_list(ctx, modules); + retval = g_strdup(ctx->output); + + report_context_free(ctx); + + return retval; +} + +static gboolean report_generate(ReportDialog * rd) +{ + GSList *modules; + ReportContext *ctx; + ReportContext *(*create_context) (); + gchar *file; + FILE *stream; + + int old_fmt_opts = params.fmt_opts; + params.fmt_opts = FMT_OPT_NONE; + + if (!(file = report_get_filename())) + return FALSE; + + if (!(stream = fopen(file, "w+"))) { + g_free(file); + return FALSE; + } + + create_context = file_types_get_data_by_name(file_types, file); + + if (!create_context) { + g_warning(_("Cannot create ReportContext. Programming bug?")); + g_free(file); + fclose(stream); + params.fmt_opts = old_fmt_opts; + return FALSE; + } + + ctx = create_context(); + modules = report_create_module_list_from_dialog(rd); + + report_create_from_module_list(ctx, modules); + fputs(ctx->output, stream); + fclose(stream); + + if (ctx->format == REPORT_FORMAT_HTML) { + GtkWidget *dialog; + dialog = gtk_message_dialog_new(NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_NONE, + _("Open the report with your web browser?")); +#if GTK_CHECK_VERSION(3, 0, 0) + gtk_dialog_add_buttons(GTK_DIALOG(dialog), + _("_No"), GTK_RESPONSE_REJECT, + _("_Open"), GTK_RESPONSE_ACCEPT, NULL); +#else + gtk_dialog_add_buttons(GTK_DIALOG(dialog), + GTK_STOCK_NO, GTK_RESPONSE_REJECT, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); +#endif + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + gchar *temp; + + temp = g_strdup_printf("file://%s", file); + uri_open(temp); + + g_free(temp); + } + + gtk_widget_destroy(dialog); + } + + report_context_free(ctx); + g_free(file); + + params.fmt_opts = old_fmt_opts; + return TRUE; +} + +void report_dialog_show(GtkTreeModel * model, GtkWidget * parent) +{ + gboolean success; + ReportDialog *rd = report_dialog_new(model, parent); + + if (gtk_dialog_run(GTK_DIALOG(rd->dialog)) == GTK_RESPONSE_ACCEPT) { + shell_status_update(_("Generating report...")); + gtk_widget_hide(rd->dialog); + shell_view_set_enabled(FALSE); + shell_status_set_enabled(TRUE); + + success = report_generate(rd); + + shell_status_set_enabled(FALSE); + + if (success) + shell_status_update(_("Report saved.")); + else + shell_status_update(_("Error while creating the report.")); + } + + set_all_active(rd, FALSE); + gtk_widget_destroy(rd->dialog); + g_free(rd); +} + +static void +set_children_active(GtkTreeModel * model, GtkTreeIter * iter, + gboolean setting) +{ + if (gtk_tree_model_iter_has_child(model, iter)) { + gint children = gtk_tree_model_iter_n_children(model, iter); + + gtk_tree_store_set(GTK_TREE_STORE(model), iter, TREE_COL_SEL, + setting, -1); + + for (children--; children >= 0; children--) { + GtkTreeIter child; + + gtk_tree_model_iter_nth_child(model, &child, iter, children); + gtk_tree_store_set(GTK_TREE_STORE(model), &child, TREE_COL_SEL, + setting, -1); + } + } +} + +static void set_all_active(ReportDialog * rd, gboolean setting) +{ + GtkTreeIter iter; + GtkTreeModel *model = rd->model; + + gtk_tree_model_get_iter_first(model, &iter); + + do { + set_children_active(model, &iter, setting); + } while (gtk_tree_model_iter_next(model, &iter)); +} + +static void report_dialog_sel_none(GtkWidget * widget, ReportDialog * rd) +{ + set_all_active(rd, FALSE); +} + +static void report_dialog_sel_all(GtkWidget * widget, ReportDialog * rd) +{ + set_all_active(rd, TRUE); +} + +static void +report_dialog_sel_toggle(GtkCellRendererToggle * cellrenderertoggle, + gchar * path_str, ReportDialog * rd) +{ + GtkTreeModel *model = rd->model; + GtkTreeIter iter; + GtkTreePath *path = gtk_tree_path_new_from_string(path_str); + gboolean active; + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, TREE_COL_SEL, &active, -1); + + active = !active; + gtk_tree_store_set(GTK_TREE_STORE(model), &iter, TREE_COL_SEL, active, + -1); + set_children_active(model, &iter, active); + + if (active) { + GtkTreeIter parent; + + if (gtk_tree_model_iter_parent(model, &parent, &iter)) { + gtk_tree_store_set(GTK_TREE_STORE(model), &parent, + TREE_COL_SEL, active, -1); + } + } + + gtk_tree_path_free(path); +} + +static ReportDialog + * report_dialog_new(GtkTreeModel * model, GtkWidget * parent) +{ + ReportDialog *rd; + GtkWidget *dialog; + GtkWidget *dialog1_vbox; + GtkWidget *scrolledwindow2; + GtkWidget *treeview2; + GtkWidget *vbuttonbox3; + GtkWidget *button3; + GtkWidget *button6; + GtkWidget *dialog1_action_area; + GtkWidget *button8; + GtkWidget *button7; + GtkWidget *label; + GtkWidget *hbox; + + GtkTreeViewColumn *column; + GtkCellRenderer *cr_text, *cr_pbuf, *cr_toggle; + + rd = g_new0(ReportDialog, 1); + + dialog = gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(dialog), _("Generate Report")); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); + gtk_window_set_default_size(GTK_WINDOW(dialog), 420, 260); + gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent)); + gtk_window_set_position(GTK_WINDOW(dialog), + GTK_WIN_POS_CENTER_ON_PARENT); + gtk_window_set_type_hint(GTK_WINDOW(dialog), + GDK_WINDOW_TYPE_HINT_DIALOG); + +#if GTK_CHECK_VERSION(2, 14, 0) + dialog1_vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); +#else + dialog1_vbox = GTK_DIALOG(dialog)->vbox; +#endif + gtk_box_set_spacing(GTK_BOX(dialog1_vbox), 5); + gtk_container_set_border_width(GTK_CONTAINER(dialog1_vbox), 4); + gtk_widget_show(dialog1_vbox); + +#if GTK_CHECK_VERSION(3, 0, 0) + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); +#else + hbox = gtk_hbox_new(FALSE, 5); +#endif + gtk_box_pack_start(GTK_BOX(dialog1_vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new(_("<big><b>Generate Report</b></big>\n" + "Please choose the information that you wish " + "to view in your report:")); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_label_set_use_markup(GTK_LABEL(label), TRUE); +#if GTK_CHECK_VERSION(3, 0, 0) + gtk_widget_set_valign(label, GTK_ALIGN_CENTER); +#else + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); +#endif + + gtk_box_pack_start(GTK_BOX(hbox), + icon_cache_get_image("report-large.png"), + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0); + gtk_widget_show_all(hbox); + +#if GTK_CHECK_VERSION(3, 0, 0) + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); +#else + hbox = gtk_hbox_new(FALSE, 5); +#endif + gtk_box_pack_start(GTK_BOX(dialog1_vbox), hbox, TRUE, TRUE, 0); + gtk_widget_show(hbox); + + scrolledwindow2 = gtk_scrolled_window_new(NULL, NULL); + gtk_widget_show(scrolledwindow2); + gtk_box_pack_start(GTK_BOX(hbox), scrolledwindow2, TRUE, TRUE, + 0); + gtk_widget_set_size_request(scrolledwindow2, -1, 200); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow2), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW + (scrolledwindow2), GTK_SHADOW_IN); + + treeview2 = gtk_tree_view_new_with_model(model); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview2), FALSE); + gtk_widget_show(treeview2); + gtk_container_add(GTK_CONTAINER(scrolledwindow2), treeview2); + + column = gtk_tree_view_column_new(); + gtk_tree_view_append_column(GTK_TREE_VIEW(treeview2), column); + + cr_toggle = gtk_cell_renderer_toggle_new(); + gtk_tree_view_column_pack_start(column, cr_toggle, FALSE); + g_signal_connect(cr_toggle, "toggled", + G_CALLBACK(report_dialog_sel_toggle), rd); + gtk_tree_view_column_add_attribute(column, cr_toggle, "active", + TREE_COL_SEL); + + cr_pbuf = gtk_cell_renderer_pixbuf_new(); + gtk_tree_view_column_pack_start(column, cr_pbuf, FALSE); + gtk_tree_view_column_add_attribute(column, cr_pbuf, "pixbuf", + TREE_COL_PBUF); + + cr_text = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(column, cr_text, TRUE); + gtk_tree_view_column_add_attribute(column, cr_text, "markup", + TREE_COL_NAME); + +#if GTK_CHECK_VERSION(3, 0, 0) + vbuttonbox3 = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); +#else + vbuttonbox3 = gtk_vbutton_box_new(); +#endif + gtk_widget_show(vbuttonbox3); + gtk_box_pack_start(GTK_BOX(hbox), vbuttonbox3, FALSE, TRUE, 0); + gtk_box_set_spacing(GTK_BOX(vbuttonbox3), 5); + gtk_button_box_set_layout(GTK_BUTTON_BOX(vbuttonbox3), + GTK_BUTTONBOX_START); + + button3 = gtk_button_new_with_mnemonic(_("Select _None")); + gtk_widget_show(button3); + gtk_container_add(GTK_CONTAINER(vbuttonbox3), button3); +#if GTK_CHECK_VERSION(2, 18, 0) + gtk_widget_set_can_default(button3, TRUE); +#else + GTK_WIDGET_SET_FLAGS(button3, GTK_CAN_DEFAULT); +#endif + g_signal_connect(button3, "clicked", + G_CALLBACK(report_dialog_sel_none), rd); + + button6 = gtk_button_new_with_mnemonic(_("Select _All")); + gtk_widget_show(button6); + gtk_container_add(GTK_CONTAINER(vbuttonbox3), button6); +#if GTK_CHECK_VERSION(2, 18, 0) + gtk_widget_set_can_default(button6, TRUE); +#else + GTK_WIDGET_SET_FLAGS(button6, GTK_CAN_DEFAULT); +#endif + g_signal_connect(button6, "clicked", G_CALLBACK(report_dialog_sel_all), + rd); + +#if GTK_CHECK_VERSION(2, 14, 0) +/* TODO:GTK3 + * [https://developer.gnome.org/gtk3/stable/GtkDialog.html#gtk-dialog-get-action-area] + * gtk_dialog_get_action_area has been deprecated since version 3.12 and should not be used in newly-written code. + * Direct access to the action area is discouraged; use gtk_dialog_add_button(), etc. + */ + dialog1_action_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); +#else + dialog1_action_area = GTK_DIALOG(dialog)->action_area; +#endif + gtk_widget_show(dialog1_action_area); + gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog1_action_area), + GTK_BUTTONBOX_END); + + button8 = gtk_button_new_with_mnemonic(_("_Cancel")); + gtk_widget_show(button8); + gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button8, + GTK_RESPONSE_CANCEL); +#if GTK_CHECK_VERSION(2, 18, 0) + gtk_widget_set_can_default(button8, TRUE); +#else + GTK_WIDGET_SET_FLAGS(button8, GTK_CAN_DEFAULT); +#endif + + button7 = gtk_button_new_with_mnemonic(_("_Generate")); + gtk_widget_show(button7); + gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button7, + GTK_RESPONSE_ACCEPT); +#if GTK_CHECK_VERSION(2, 18, 0) + gtk_widget_set_can_default(button7, TRUE); +#else + GTK_WIDGET_SET_FLAGS(button7, GTK_CAN_DEFAULT); +#endif + + rd->dialog = dialog; + rd->btn_cancel = button8; + rd->btn_generate = button7; + rd->btn_sel_all = button6; + rd->btn_sel_none = button3; + rd->treeview = treeview2; + rd->model = model; + + gtk_tree_view_collapse_all(GTK_TREE_VIEW(treeview2)); + set_all_active(rd, TRUE); + + return rd; +} |