Logo Search packages:      
Sourcecode: xacobeo version File versions  Download package

main.c

//
// Sample program that displays an XML file in a GtkTextView.
// 
// Copyright (C) 2008 Emmanuel Rodriguez
//
// This program is free software; you can redistribute it and/or modify it under
// the same terms as Perl itself, either Perl version 5.8.8 or, at your option,
// any later version of Perl 5 you may have available.
//
//

#include "code.h"
#include "logger.h"
#include <glib/gprintf.h>

#include <libxml/parser.h>
#include <libxml/parserInternals.h>

#define TAG(name, ...) gtk_text_buffer_create_tag(buffer, name, __VA_ARGS__, NULL)


static void               my_create_buffer_tags (GtkTextBuffer *buffer);
static void               my_create_widgets     (GtkTextView **textview, GtkTreeView **treeview);
static GtkTreeViewColumn* my_add_text_column    (GtkTreeView *treeview, DomModelColumnsEnum field, const gchar *title, gint width);
static GtkWidget*         my_create_textview    (void);
static GtkWidget*         my_create_treeview    (void);
static GtkWidget*         my_wrap_in_scrolls    (GtkWidget *widget);
static xmlDoc*            my_parse_document     (const gchar *filename);


int main (int argc, char **argv) {

      gboolean no_xml    = FALSE;
      gboolean no_source = FALSE;
      gboolean no_dom    = FALSE;
      gboolean quit      = FALSE;

      // Parse the arguments
      gtk_init(&argc, &argv);

      GOptionEntry entries[] = {
            { "no-xml",    'X', 0, G_OPTION_ARG_NONE, &no_xml,    "Don't load the XML document", NULL },
            { "no-source", 'S', 0, G_OPTION_ARG_NONE, &no_source, "Don't show the XML source", NULL },
            { "no-dom",    'D', 0, G_OPTION_ARG_NONE, &no_dom,    "Don't show the DOM tree", NULL },
            { "quit",      'q', 0, G_OPTION_ARG_NONE, &quit,      "Quit as soon as the proram is ready", NULL },
            { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL  },
      };

      GError *error = NULL;
      GOptionContext *context = g_option_context_new("- memory profiling");
      g_option_context_add_main_entries(context, entries, NULL);
      g_option_context_add_group(context, gtk_get_option_group(TRUE));
      if (!g_option_context_parse(context, &argc, &argv, &error)) {
            ERROR("option parsing failed: %s", error->message);
            g_error_free(error);
            return 1;
      }

      if (argc < 1) {
            ERROR("Usage: %s file\n", argv[0]);
            return 1;
      }
      char *filename = argv[1];


      // Load the XML document
      DEBUG("Reading file %s", filename);
      xmlDoc *document = !no_xml ? my_parse_document(filename) : NULL;
      if (!no_xml && document == NULL) {
            ERROR("Failed to parse %s", filename);
            return 1;
      }
      INFO("Read file %s", filename);


      // Render the XML document
      GtkTextView *textview = NULL;
      GtkTreeView *treeview = NULL;
      
      my_create_widgets(&textview, &treeview);
      
      // Fill the TextView (it's faster to remove the buffer and to put it back)
      GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview);
      gtk_text_view_set_buffer(textview, NULL);
      if (!no_source) xacobeo_populate_gtk_text_buffer(buffer, (xmlNode *) document, NULL);
      gtk_text_view_set_buffer(textview, buffer);

      // Scroll to the beginning of the text
      GtkTextIter iter;
      gtk_text_buffer_get_start_iter(buffer, &iter);
      gtk_text_view_scroll_to_iter(textview, &iter, 0.0, FALSE, 0.0, 0.0); 
      
      GtkTreeStore *store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
      gtk_tree_view_set_model(treeview, NULL);
      gtk_tree_store_clear(store);
      if (!no_dom) xacobeo_populate_gtk_tree_store(store, (xmlNode *) document, NULL);
      gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));

      INFO("Freeing XML document");
      if (document) xmlFreeDoc(document);
      

      // If we just want to time the execution time we don't need an event loop
      if (!quit) {
            // Main event loop
            INFO("Starting main loop");
            gtk_main();
      }

      INFO("Cleaning XML parser");
      xmlCleanupParser();

      INFO("End of program");
      return 0;
}



//
// Creates the main widgets and prepares them for displaying. This function
// returns the GtkTextView casted as a GtkWidget.
//
static void my_create_widgets (GtkTextView **ptr_textview, GtkTreeView **ptr_treeview) {
      
      // The main widgets
      GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      GtkWidget *textview = my_create_textview();
      GtkWidget *treeview = my_create_treeview();

      
      // Pack the widgets together
      GtkWidget *pane = gtk_hpaned_new();
      gtk_paned_set_position(GTK_PANED(pane), 200);
      gtk_paned_add1(GTK_PANED(pane), my_wrap_in_scrolls(treeview));
      gtk_paned_add2(GTK_PANED(pane), my_wrap_in_scrolls(textview));

      gtk_container_add(GTK_CONTAINER(window), pane);
      gtk_widget_show_all(window);
      
      
      // Connect the signals
      g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL);


      // Set the return values
      *ptr_textview = GTK_TEXT_VIEW(textview);
      *ptr_treeview = GTK_TREE_VIEW(treeview);
}



//
// Creates the text view and sets its model (text buffer)
//
static GtkWidget* my_create_textview (void) {
      // Prepare the text view
      GtkTextTagTable *table = gtk_text_tag_table_new();
      GtkTextBuffer *buffer = gtk_text_buffer_new(table);
      GtkWidget *textview = gtk_text_view_new_with_buffer(buffer);

      my_create_buffer_tags(buffer);

      gtk_widget_set_size_request(textview, 600, 400);
      gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), FALSE);
      gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textview), FALSE);
      
      return textview;
}



//
// Creates the tree view and sets its model (tree store)
//
static GtkWidget* my_create_treeview (void) {
      // Prepre the tree view
      GtkWidget *treeview = gtk_tree_view_new();
      GtkTreeStore *store = gtk_tree_store_new(5,
            G_TYPE_STRING, 
            G_TYPE_STRING,
            G_TYPE_STRING,
            G_TYPE_STRING,
            G_TYPE_STRING
      );
      gtk_tree_view_set_model(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(store));
      gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), TRUE);
      
      
      
      // Element name
      GtkTreeViewColumn *column = my_add_text_column(
            GTK_TREE_VIEW(treeview),
            DOM_COL_ELEMENT_NAME,
            "Element",
            150
      );

      // Icon
      GtkCellRenderer *cell = gtk_cell_renderer_pixbuf_new();
      gtk_tree_view_column_pack_end(column, cell, FALSE);
      gtk_tree_view_column_set_attributes(column, cell, "stock-id", DOM_COL_ICON, NULL);
      
      // XML::ID
      my_add_text_column(GTK_TREE_VIEW(treeview), DOM_COL_ID_NAME, "ID name", 75);
      my_add_text_column(GTK_TREE_VIEW(treeview), DOM_COL_ID_VALUE, "ID value", 75);

      return treeview;
}


static GtkTreeViewColumn* my_add_text_column (GtkTreeView *treeview, DomModelColumnsEnum field, const gchar *title, gint width) {
      GtkCellRenderer *cell = gtk_cell_renderer_text_new();
      GtkTreeViewColumn *column = gtk_tree_view_column_new();
      gtk_tree_view_column_pack_end(column, cell, TRUE);
      
      gtk_tree_view_column_set_title(column, title);
      gtk_tree_view_column_set_resizable(column, TRUE);
      gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
      gtk_tree_view_column_set_fixed_width(column, width);
      gtk_tree_view_column_set_attributes(column, cell, "text", field, NULL);

      gtk_tree_view_append_column(treeview, column);
      
      return column;
}


//
// Wraps the a widget with scroll bars.
//
static GtkWidget* my_wrap_in_scrolls (GtkWidget *widget) {
      GtkWidget *scrolls = gtk_scrolled_window_new(NULL, NULL);
      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolls), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
      gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolls), GTK_SHADOW_OUT);
      gtk_container_add(GTK_CONTAINER(scrolls), widget);
      return scrolls;
}



//
// Creates the markup rules to use for displaying XML.
//
static void my_create_buffer_tags (GtkTextBuffer *buffer) {

      TAG("result_count", 
            "family",      "Courier 10 Pitch",
            "background",  "#EDE9E3",
            "foreground",  "black",
            "style",       PANGO_STYLE_ITALIC,
            "weight",      PANGO_WEIGHT_LIGHT
      );
      
      TAG("boolean", 
                  "family",      "Courier 10 Pitch",
                  "foreground",  "black",
                  "weight",      PANGO_WEIGHT_BOLD
      );
      
      TAG("number", 
                  "family",      "Courier 10 Pitch",
                  "foreground",  "black",
                  "weight",      PANGO_WEIGHT_BOLD
      );

      TAG("attribute_name", 
            "foreground",  "red"
      );

      TAG("attribute_value", 
            "foreground",  "blue"
      );
      
      TAG("comment", 
            "foreground",  "#008000",
            "style",       PANGO_STYLE_ITALIC,
            "weight",      PANGO_WEIGHT_LIGHT
      );
      
      TAG("dtd", 
            "foreground",  "#558CBA",
            "style",       PANGO_STYLE_ITALIC
      );
      
      TAG("element", 
            "foreground",  "#800080",
            "weight",      PANGO_WEIGHT_BOLD
      );
      
      TAG("pi", 
            "foreground",  "#558CBA",
            "style",       PANGO_STYLE_ITALIC
      );
      
      TAG("pi_data", 
            "foreground",  "red",
            "style",       PANGO_STYLE_ITALIC
      );
      
      TAG("syntax", 
            "foreground",  "black",
            "weight",      PANGO_WEIGHT_BOLD
      );
      
      TAG("text", 
            "foreground",  "black"
      );
      
      TAG("literal", 
            "foreground",  "black"
      );
      
      TAG("cdata", 
            "foreground",  "red",
            "weight",      PANGO_WEIGHT_BOLD
      );
      
      TAG("cdata_content", 
            "foreground",  "purple",
            "weight",      PANGO_WEIGHT_BOLD,
            "style",       PANGO_STYLE_ITALIC,
            "weight",      PANGO_WEIGHT_LIGHT
      );
      
      TAG("namespace_name", 
            "foreground",  "red",
            "style",       PANGO_STYLE_ITALIC,
            "weight",      PANGO_WEIGHT_LIGHT
      );
      
      TAG("namespace_uri", 
            "foreground",  "blue",
            "style",       PANGO_STYLE_ITALIC,
            "weight",      PANGO_WEIGHT_LIGHT
      );
      
      TAG("entity_ref", 
            "foreground",  "red",
            "weight",      PANGO_WEIGHT_BOLD
      );
}


//
// Parses the XML document. Returns an XML document if the parsing was
// successful otherwise NULL.
//
// The document has to be     freed with xmlFreeDoc();
//
static xmlDoc* my_parse_document (const gchar *filename) {

      // Construct a parser contenxt
      xmlParserCtxt *parserCtxt = xmlCreateFileParserCtxt(filename);
      parserCtxt->loadsubset = XML_DETECT_IDS;
      
      // Parse the document
      xmlDoc *document = NULL;
      if (xmlParseDocument(parserCtxt) == 0) {
            document = parserCtxt->myDoc;
            parserCtxt->myDoc = NULL;
      }

      xmlFreeParserCtxt(parserCtxt);
      return document;
}

Generated by  Doxygen 1.6.0   Back to index