summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am17
-rw-r--r--src/gnome-plist-editor.c377
-rw-r--r--src/gnome-plist-editor.ui353
-rw-r--r--src/plist-utils.c51
-rw-r--r--src/plist-utils.h29
5 files changed, 827 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..f5cf7a8
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
+bin_PROGRAMS = gnome-plist-editor
+
+gnome_plist_editor_SOURCES = \
+ gnome-plist-editor.c \
+ plist-utils.c
+
+gnome_plist_editor_CFLAGS = \
+ -Wl,--export-dynamic \
+ $(GLIB_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBPLIST_CFLAGS)
+
+gnome_plist_editor_LDADD = \
+ -lpthread \
+ $(GLIB_LIBS) \
+ $(GTK_LIBS) \
+ $(LIBPLIST_LIBS)
diff --git a/src/gnome-plist-editor.c b/src/gnome-plist-editor.c
new file mode 100644
index 0000000..858480c
--- /dev/null
+++ b/src/gnome-plist-editor.c
@@ -0,0 +1,377 @@
+/*
+ * gnome-plist-editor.c
+ *
+ * Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
+ *
+ * The code contained in this file is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either version
+ * 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+
+#include <plist/plist.h>
+#include "plist-utils.h"
+
+static struct AppState {
+ GtkWindow *main_window;
+ GtkTreeStore *document_tree_store;
+ GtkTreeView *document_tree_view;
+
+ plist_t root_node;
+ gboolean is_binary;
+} app;
+
+void main_window_destroy_cb(GtkWidget* widget, gpointer user_data) {
+ if (app.document_tree_store)
+ gtk_tree_store_clear(app.document_tree_store);
+
+ if (app.root_node)
+ plist_free(app.root_node);
+
+ gtk_main_quit();
+}
+
+void update_document_tree_view(plist_t node, GtkTreeIter *parent) {
+ GtkTreeStore *store = app.document_tree_store;
+ GtkTreeIter iter;
+ plist_t subnode = NULL;
+ plist_t value_node = NULL;
+ plist_type type;
+ plist_type value_type;
+
+ gtk_tree_store_append(store, &iter, parent);
+ gtk_tree_store_set(store, &iter,
+ 0, (gpointer)node,
+ -1);
+
+ /* check for root */
+ if (parent == NULL) {
+ value_node = node;
+ } else {
+ value_node = plist_get_next_sibling(node);
+ }
+ value_type = plist_get_node_type(value_node);
+
+ /* recurse through children */
+ for (
+ subnode = plist_get_first_child(value_node);
+ subnode != NULL;
+ subnode = plist_get_next_sibling(subnode)
+ ) {
+ type = plist_get_node_type(subnode);
+ if (type == PLIST_KEY) {
+ update_document_tree_view(subnode, &iter);
+ }
+ if (value_type == PLIST_ARRAY && (type != PLIST_DICT && type != PLIST_ARRAY)) {
+ update_document_tree_view(subnode, &iter);
+ }
+ }
+}
+
+static void open_plist_file(const char *filename) {
+ char *buffer = NULL;
+ gsize size = 0;
+ gsize bytes_read = 0;
+ GFile *file = NULL;
+ GFileInfo *fileinfo = NULL;
+ GFileInputStream *filestream = NULL;
+ GError *err = NULL;
+
+ file = g_file_new_for_path(filename);
+ filestream = g_file_read(file, NULL, &err);
+ if (!filestream) {
+ fprintf(stderr, "ERROR: opening %s: %s\n", file, err->message);
+ g_object_unref(file);
+ goto leave;
+ }
+
+ fileinfo = g_file_query_info(file,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL,
+ &err);
+
+ size = g_file_info_get_size(fileinfo);
+
+ /* read in the plist */
+ buffer = (char *)g_malloc(sizeof(char) * (size + 1));
+ g_input_stream_read_all(G_INPUT_STREAM(filestream),
+ buffer,
+ size,
+ &bytes_read,
+ NULL,
+ &err);
+
+ if (memcmp(buffer, "bplist00", 8) == 0) {
+ plist_from_bin(buffer, size, &app.root_node);
+ app.is_binary = TRUE;
+ } else {
+ plist_from_xml(buffer, size, &app.root_node);
+ app.is_binary = FALSE;
+ }
+
+ gtk_tree_store_clear(app.document_tree_store);
+ update_document_tree_view(app.root_node, NULL);
+ gtk_tree_view_expand_all(app.document_tree_view);
+
+ g_free(buffer);
+
+leave:
+ if (fileinfo)
+ g_object_unref(fileinfo);
+ if (filestream)
+ g_object_unref(filestream);
+ if (file)
+ g_object_unref(file);
+}
+
+void open_plist_cb(GtkWidget* item, gpointer user_data) {
+ GtkWidget *dialog;
+ GtkFileFilter *filter;
+
+ char *filename = NULL;
+
+ dialog = gtk_file_chooser_dialog_new ("Open Property List File",
+ app.main_window,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ /* add default filter */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, "All Files");
+ gtk_file_filter_add_pattern(filter, "*");
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+
+ /* add plist filter */
+ filter = gtk_file_filter_new();
+ gtk_file_filter_add_pattern(filter, "*.plist");
+ gtk_file_filter_set_name(filter, "Property List Files");
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
+
+ if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ open_plist_file(filename);
+ }
+
+ if (filename)
+ g_free (filename);
+
+ gtk_widget_destroy (dialog);
+}
+
+void about_menu_item_activate_cb(GtkMenuItem* item, gpointer user_data) {
+ gtk_show_about_dialog(app.main_window,
+ "program-name", "GNOME Property List Editor",
+ "logo-icon-name", "text-editor",
+ "website", "http://cgit.sukimashita.com/gnome-plist-editor.git/",
+ "website-label", "GIT Source Code Repository",
+ "version", PACKAGE_VERSION,
+ NULL);
+}
+
+typedef enum {
+ COL_KEY,
+ COL_TYPE,
+ COL_VALUE,
+ N_COLUMNS
+} col_type_t;
+
+void plist_cell_data_function (GtkTreeViewColumn *col,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ col_type_t col_type;
+ plist_t node;
+ plist_t value_node;
+ plist_t parent_node;
+ plist_type value_type;
+ char *text = NULL;
+
+ char *s = NULL;
+ double d;
+ uint8_t b;
+ uint64_t u = 0;
+
+ col_type = (col_type_t)GPOINTER_TO_INT(user_data);
+
+ gtk_tree_model_get(model, iter, 0, &node, -1);
+
+ parent_node = plist_get_parent(node);
+
+ if (parent_node == NULL) {
+ value_node = node;
+ }
+ else
+ {
+ value_node = plist_get_next_sibling(node);
+ }
+
+ if (plist_get_node_type(parent_node) == PLIST_ARRAY) {
+ if ((value_type != PLIST_DICT) && (value_type != PLIST_ARRAY)) {
+ value_node = node;
+ }
+ }
+ value_type = plist_get_node_type(value_node);
+
+ switch(col_type) {
+ case COL_KEY:
+ if (plist_get_parent(node) == NULL) {
+ text = "Root";
+ }
+ else
+ {
+ switch(plist_get_node_type(node)) {
+ case PLIST_KEY:
+ plist_get_key_val(node, &text);
+ break;
+ case PLIST_STRING:
+ plist_get_string_val(node, &text);
+ break;
+ case PLIST_UINT:
+ plist_get_uint_val(value_node, &u);
+ text = g_strdup_printf("%llu", (long long)u);
+ break;
+ default:
+ text = g_strdup_printf("Unhandled %d", plist_get_node_type(node));
+ break;
+ }
+ }
+ break;
+ case COL_TYPE:
+ switch(value_type) {
+ case PLIST_BOOLEAN:
+ text = "Boolean";
+ break;
+ case PLIST_UINT:
+ text = "Number";
+ break;
+ case PLIST_REAL:
+ text = "Float";
+ break;
+ case PLIST_STRING:
+ text = "String";
+ break;
+ case PLIST_DATA:
+ text = "Data";
+ break;
+ case PLIST_DATE:
+ text = "Date";
+ break;
+ case PLIST_ARRAY:
+ text = "Array";
+ break;
+ case PLIST_DICT:
+ text = "Dictionary";
+ break;
+ }
+ break;
+ case COL_VALUE:
+ g_object_set(renderer, "sensitive", TRUE, NULL);
+ switch(value_type) {
+ case PLIST_BOOLEAN:
+ plist_get_bool_val(value_node, &b);
+ text = (b ? "true" : "false");
+ break;
+ case PLIST_UINT:
+ plist_get_uint_val(value_node, &u);
+ text = g_strdup_printf("%llu", (long long)u);
+ break;
+ case PLIST_REAL:
+ plist_get_real_val(value_node, &d);
+ text = g_strdup_printf("%f", d);
+ break;
+ case PLIST_STRING:
+ plist_get_string_val(value_node, &text);
+ break;
+ case PLIST_DATA:
+ text = "FIXME: Parse Data";
+ break;
+ case PLIST_DATE:
+ text = "FIXME: Parse Dates";
+ break;
+ case PLIST_ARRAY:
+ case PLIST_DICT:
+ text = g_strdup_printf("(%d items)", plist_node_get_item_count(value_node));
+ g_object_set(renderer, "sensitive", FALSE, NULL);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ g_object_set(renderer, "text", text, NULL);
+}
+
+void setup_tree_view(GtkBuilder *gtk_builder) {
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell;
+
+ app.document_tree_view = GTK_TREE_VIEW(gtk_builder_get_object(gtk_builder, "document_tree_view"));
+ app.document_tree_store = GTK_TREE_STORE(gtk_builder_get_object(gtk_builder, "document_tree_store"));
+
+ /* key */
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(gtk_builder, "treeviewcolumn1"));
+ cell = GTK_CELL_RENDERER(gtk_builder_get_object(gtk_builder, "cellrenderertext1"));
+ gtk_tree_view_column_set_cell_data_func(column, cell, plist_cell_data_function, GINT_TO_POINTER(COL_KEY), NULL);
+
+ /* type */
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(gtk_builder, "treeviewcolumn2"));
+ cell = GTK_CELL_RENDERER(gtk_builder_get_object(gtk_builder, "cellrenderercombo1"));
+ gtk_tree_view_column_set_cell_data_func(column, cell, plist_cell_data_function, GINT_TO_POINTER(COL_TYPE), NULL);
+
+ /* value */
+ column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(gtk_builder, "treeviewcolumn3"));
+ cell = GTK_CELL_RENDERER(gtk_builder_get_object(gtk_builder, "cellrenderertext2"));
+ gtk_tree_view_column_set_cell_data_func(column, cell, plist_cell_data_function, GINT_TO_POINTER(COL_VALUE), NULL);
+}
+
+int main(int argc, char **argv) {
+ GtkBuilder *gtk_builder;
+
+ gtk_set_locale();
+
+ /* Initialize the widget set */
+ gtk_init (&argc, &argv);
+
+ /* Create the main window */
+ gtk_builder = gtk_builder_new();
+ gtk_builder_add_from_file(gtk_builder, "gnome-plist-editor.ui", NULL);
+ gtk_builder_connect_signals(gtk_builder, NULL);
+
+ app.main_window = GTK_WINDOW(gtk_builder_get_object(gtk_builder, "main_window"));
+ setup_tree_view(gtk_builder);
+
+ g_object_unref(G_OBJECT(gtk_builder));
+
+ /* Show the application window */
+ gtk_widget_show_all(GTK_WIDGET(app.main_window));
+
+ /* Enter the main event loop, and wait for user interaction */
+ gtk_main ();
+
+ return 0;
+}
+
diff --git a/src/gnome-plist-editor.ui b/src/gnome-plist-editor.ui
new file mode 100644
index 0000000..e7e125d
--- /dev/null
+++ b/src/gnome-plist-editor.ui
@@ -0,0 +1,353 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.16"/>
+ <!-- interface-naming-policy project-wide -->
+ <object class="GtkTreeStore" id="document_tree_store">
+ <columns>
+ <!-- column-name node -->
+ <column type="gpointer"/>
+ </columns>
+ </object>
+ <object class="GtkListStore" id="plist_type_list_store">
+ <columns>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Boolean</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Number</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Float</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">String</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Array</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Dictionary</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Date</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Data</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkWindow" id="main_window">
+ <property name="title" translatable="yes">Property List Editor</property>
+ <property name="window_position">center</property>
+ <property name="default_width">450</property>
+ <property name="default_height">350</property>
+ <property name="icon_name">text-editor</property>
+ <signal name="destroy" handler="main_window_destroy_cb"/>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuItem" id="menuitem1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem1">
+ <property name="label">gtk-new</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="open_plist_menu_item">
+ <property name="label">_Open...</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="image">image1</property>
+ <property name="use_stock">False</property>
+ <signal name="activate" handler="open_plist_cb"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem3">
+ <property name="label">gtk-save</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem4">
+ <property name="label">gtk-save-as</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem5">
+ <property name="label">gtk-quit</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="main_window_destroy_cb"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Edit</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem6">
+ <property name="label">gtk-cut</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem7">
+ <property name="label">gtk-copy</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem8">
+ <property name="label">gtk-paste</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImageMenuItem" id="imagemenuitem9">
+ <property name="label">gtk-delete</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_View</property>
+ <property name="use_underline">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuItem" id="menuitem4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+ <child type="submenu">
+ <object class="GtkMenu" id="menu3">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkImageMenuItem" id="about_menu_item">
+ <property name="label">gtk-about</property>
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="about_menu_item_activate_cb"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="toolbar_style">both</property>
+ <child>
+ <object class="GtkToolButton" id="new_plist_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">New</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-new</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="open_plist_button">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Open...</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-open</property>
+ <signal name="clicked" handler="open_plist_cb"/>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="save_plist_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">Save</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-save</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparatorToolItem" id="toolbutton1">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="add_sibling_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">Add Item</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">list-add</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolButton" id="delete_item_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="label" translatable="yes">Delete Item</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">list-remove</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <child>
+ <object class="GtkTreeView" id="document_tree_view">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">document_tree_store</property>
+ <property name="headers_clickable">False</property>
+ <property name="expander_column">treeviewcolumn1</property>
+ <property name="rules_hint">True</property>
+ <property name="search_column">8</property>
+ <property name="enable_grid_lines">horizontal</property>
+ <property name="tooltip_column">0</property>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <property name="resizable">True</property>
+ <property name="min_width">150</property>
+ <property name="title">Key</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext1"/>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn2">
+ <property name="min_width">100</property>
+ <property name="title">Type</property>
+ <child>
+ <object class="GtkCellRendererCombo" id="cellrenderercombo1">
+ <property name="editable">True</property>
+ <property name="model">plist_type_list_store</property>
+ <property name="text_column">0</property>
+ </object>
+ <attributes>
+ <attribute name="has-entry">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn3">
+ <property name="resizable">True</property>
+ <property name="title">Value</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext2"/>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-open</property>
+ <property name="icon-size">1</property>
+ </object>
+ <object class="GtkTextBuffer" id="document_text_buffer"/>
+</interface>
diff --git a/src/plist-utils.c b/src/plist-utils.c
new file mode 100644
index 0000000..fe63439
--- /dev/null
+++ b/src/plist-utils.c
@@ -0,0 +1,51 @@
+/*
+ * plist-utils.c
+ *
+ * Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
+ *
+ * The code contained in this file is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either version
+ * 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdlib.h>
+
+#include "plist-utils.h"
+
+int plist_node_get_item_count(plist_t node) {
+ plist_t child;
+ plist_type type = PLIST_KEY;
+ plist_type child_type;
+ int count = 0;
+
+ type = plist_get_node_type(node);
+
+ child = plist_get_first_child(node);
+ if (child == NULL)
+ return count;
+
+ for(child; child != NULL; child = plist_get_next_sibling(child)) {
+ if (type == PLIST_ARRAY) {
+ child_type = plist_get_node_type(child);
+ if ((child_type != PLIST_DICT) && (child_type != PLIST_ARRAY))
+ count++;
+ }
+ else if (plist_get_node_type(child) == PLIST_KEY) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
diff --git a/src/plist-utils.h b/src/plist-utils.h
new file mode 100644
index 0000000..0d55b14
--- /dev/null
+++ b/src/plist-utils.h
@@ -0,0 +1,29 @@
+/*
+ * plist-utils.h
+ *
+ * Copyright (C) 2009 Martin Szulecki <opensuse@sukimashita.com>
+ *
+ * The code contained in this file is free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either version
+ * 2.1 of the License, or (at your option) any later version.
+ *
+ * This file 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _PLIST_UTILS_H
+#define _PLIST_UTILS_H
+
+#include <plist/plist.h>
+
+int plist_node_get_item_count(plist_t node);
+
+#endif