First cut at an applications manager
authorJ. Ali Harlow <ali@barnsbury.(none)>
Sat, 20 Feb 2010 12:11:02 +0000 (12:11 +0000)
committerJ. Ali Harlow <ali@barnsbury.(none)>
Sat, 20 Feb 2010 12:11:02 +0000 (12:11 +0000)
27 files changed:
Makefile.am
app-manager/Makefile.am [new file with mode: 0644]
app-manager/app-manager.c [new file with mode: 0644]
app-manager/app-manager.desktop [new file with mode: 0644]
app-manager/app-manager.h [new file with mode: 0644]
app-manager/app-manager.ui [new file with mode: 0644]
app-manager/applications.c [new file with mode: 0644]
app-manager/localmedia.c [new file with mode: 0644]
app-manager/localmedia.h [new file with mode: 0644]
app-manager/packagelist.c [new file with mode: 0644]
app-manager/plover-applications.svg [new file with mode: 0644]
app-manager/resources.rc.in [new file with mode: 0644]
configure.ac
plover-gtk/Makefile.am [new file with mode: 0644]
plover-gtk/error.c [new file with mode: 0644]
plover-gtk/error.h [new file with mode: 0644]
plover-gtk/package.c [new file with mode: 0644]
plover-gtk/package.h [new file with mode: 0644]
plover-gtk/packagefilestore.c [new file with mode: 0644]
plover-gtk/packagefilestore.h [new file with mode: 0644]
plover-gtk/packageset.c [new file with mode: 0644]
plover-gtk/packageset.h [new file with mode: 0644]
plover-gtk/packagestore.c [new file with mode: 0644]
plover-gtk/packagestore.h [new file with mode: 0644]
plover-gtk/plover-gtk.pc.in [new file with mode: 0644]
plover/Makefile.am
plover/import-yum.c

index 23ca042..c3475ed 100644 (file)
@@ -1 +1 @@
-SUBDIRS=plover setup update
+SUBDIRS=plover setup update plover-gtk app-manager
diff --git a/app-manager/Makefile.am b/app-manager/Makefile.am
new file mode 100644 (file)
index 0000000..d577425
--- /dev/null
@@ -0,0 +1,31 @@
+AM_CFLAGS=$(GUI_CFLAGS) -g -DPLOVER_DATADIR=\""$(pkgdatadir)"\" -I$(top_srcdir)
+LDADD=../plover/libplover.la ../plover-gtk/libplover-gtk.la $(GUI_LIBS)
+
+bin_PROGRAMS=app-manager
+app_manager_SOURCES=app-manager.c app-manager.h packagelist.c applications.c \
+       localmedia.c localmedia.h
+if HAVE_WINDRES
+app_manager_SOURCES+=resources.rc
+endif
+uidir=$(pkgdatadir)
+ui_DATA=app-manager.ui
+desktopdir=$(datadir)/applications
+desktop_DATA=app-manager.desktop
+scaleabledir=$(datadir)/icons/hicolor/scalable/apps
+scaleable_DATA=plover-applications.svg
+
+.rc.$(OBJEXT):
+       $(WINDRES) $< $@
+
+resources.$(OBJEXT):   plover-applications.ico
+
+plover-applications%.pnm:      plover-applications.svg
+       rsvg -w $* -h $* -f png $< temp.png
+       pngtopnm temp.png | pnmquant 256 > $@
+       $(RM) temp.png
+
+app-manager.ico:       plover-applications16.pnm \
+               plover-applications22.pnm plover-applications32.pnm
+       ppmtowinicon -output=$@ $^
+
+EXTRA_DIST=app-manager.desktop app-manager.ui plover-applications.svg
diff --git a/app-manager/app-manager.c b/app-manager/app-manager.c
new file mode 100644 (file)
index 0000000..e897c89
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <plover-gtk/packageset.h>
+#include "app-manager.h"
+#include "localmedia.h"
+
+#define LOGO_NAME      "plover-applications"
+
+GtkBuilder *ui;
+GtkTreeModel *installed,*applications,*location,*local_media;
+
+int main(int argc,char **argv)
+{
+    GError *err=0;
+    GtkWidget *w;
+    gchar *s,*contents;
+    gsize len;
+    PloverPackageSet *set;
+    GOptionEntry options[]={
+       {NULL}
+    };
+    if (!gtk_init_with_args(&argc,&argv,NULL,options,NULL,&err))
+    {
+       g_printerr("%s",err->message);
+       exit(0);
+    }
+    gtk_window_set_default_icon_name(LOGO_NAME);
+    ui=gtk_builder_new();
+    if (!g_file_get_contents("app-manager.ui",&contents,&len,&err) &&
+      g_error_matches(err,G_FILE_ERROR,G_FILE_ERROR_NOENT))
+    {
+       g_clear_error(&err);
+       s=g_build_filename(PLOVER_DATADIR,"app-manager.ui",NULL);
+       (void)g_file_get_contents(s,&contents,&len,&err);
+       g_free(s);
+    }
+    if (!err)
+    {
+       (void)gtk_builder_add_from_string(ui,contents,len,&err);
+       g_free(contents);
+    }
+    if (err)
+    {
+       g_error("%s",err->message);
+       exit(0);
+    }
+    gtk_builder_connect_signals(ui,NULL);
+    installed=GTK_TREE_MODEL(plover_package_store_new());
+    set=plover_package_set_new_from_installed("",NULL);
+    if (set)
+       plover_package_store_add_set(PLOVER_PACKAGE_STORE(installed),set);
+    applications=plover_applications_model_new(installed);
+    set_package_model(applications);
+    gtk_main();
+    g_object_unref(ui);
+    exit(0);
+}
+
+G_MODULE_EXPORT void
+  on_applications_toggled(GtkToggleToolButton *button,gpointer data)
+{
+    if (gtk_toggle_tool_button_get_active(button))
+    {
+       if (!applications)
+           applications=plover_applications_model_new(installed);
+       set_package_model(applications);
+    }
+}
+
+G_MODULE_EXPORT void
+  on_all_packages_toggled(GtkToggleToolButton *button,gpointer data)
+{
+    if (gtk_toggle_tool_button_get_active(button))
+       set_package_model(installed);
+}
+
+G_MODULE_EXPORT void
+  on_local_media_toggled(GtkToggleToolButton *button,gpointer data)
+{
+    if (gtk_toggle_tool_button_get_active(button))
+    {
+       if (!local_media)
+           local_media=plover_local_media_store_new();
+       set_package_model(local_media);
+    }
+}
+
+G_MODULE_EXPORT void
+  on_location_toggled(GtkToggleToolButton *button,gpointer data)
+{
+    if (gtk_toggle_tool_button_get_active(button))
+       set_package_model(location);
+}
+
+G_MODULE_EXPORT void on_open_location(GtkWidget *widget)
+{
+    GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
+    GtkWidget *dialog;
+    gchar *path,*name;
+    PloverPackageSet *set;
+    GSList *sets;
+    GError *err=NULL;
+    dialog=gtk_file_chooser_dialog_new("Open Location",GTK_WINDOW(w),
+      GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,GTK_STOCK_CANCEL,
+      GTK_RESPONSE_CANCEL,GTK_STOCK_OPEN,GTK_RESPONSE_ACCEPT,NULL);
+#if GTK_CHECK_VERSION(2,18,0)
+    gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dialog),FALSE);
+#endif
+    if (gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_ACCEPT)
+    {
+       path=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+       set=plover_package_set_new_from_repository(path,&err);
+       if (set)
+       {
+           if (!location)
+               location=GTK_TREE_MODEL(plover_package_store_new());
+           while((sets=
+             plover_package_store_get_sets(PLOVER_PACKAGE_STORE(location))))
+               plover_package_store_remove_set(PLOVER_PACKAGE_STORE(location),
+                 PLOVER_PACKAGE_SET(sets->data));
+           plover_package_store_add_set(PLOVER_PACKAGE_STORE(location),set);
+           g_object_unref(set);
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"LocationButton"));
+           name=g_filename_display_basename(path);
+           gtk_tool_button_set_label(GTK_TOOL_BUTTON(w),name);
+           g_free(name);
+           gtk_widget_show(w);
+           gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w),TRUE);
+       }
+       else
+       {
+           gtk_widget_destroy(dialog);
+           dialog=gtk_message_dialog_new(GTK_WINDOW(w),
+             GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,
+             GTK_BUTTONS_CLOSE,"Error loading repository '%s'",path);
+           gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
+             "%s",err->message);
+           gtk_dialog_run(GTK_DIALOG(dialog));
+           g_error_free(err);
+       }
+       g_free(path);
+    }
+    gtk_widget_destroy(dialog);
+}
+
+G_MODULE_EXPORT void on_scan_local_media(GtkWidget *widget)
+{
+    if (!local_media)
+       local_media=plover_local_media_store_new();
+    plover_local_media_store_scan(PLOVER_LOCAL_MEDIA_STORE(local_media));
+}
+
+G_MODULE_EXPORT void on_help_about(GtkWidget *widget)
+{
+    GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
+    gtk_show_about_dialog(GTK_WINDOW(w),"name",PACKAGE_NAME,
+      "version",PACKAGE_VERSION,"comments","Application Manager",
+      "copyright","Copyright © 2010 J. Ali Harlow","logo-icon-name",LOGO_NAME,
+      NULL);
+}
+
+G_MODULE_EXPORT void on_find_clicked(GtkButton *button)
+{
+    gchar *text;
+    GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"SearchEntry"));
+    text=g_strdup(gtk_entry_get_text(GTK_ENTRY(w)));
+    gtk_entry_set_text(GTK_ENTRY(w),"");
+    gtk_entry_set_text(GTK_ENTRY(w),text);
+    g_free(text);
+}
diff --git a/app-manager/app-manager.desktop b/app-manager/app-manager.desktop
new file mode 100644 (file)
index 0000000..1635ab9
--- /dev/null
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Encoding=UTF-8
+Name=Application Manager
+Comment=Manage applications
+Exec=app-manager
+Icon=plover-applications
+Terminal=false
+Type=Application
+Categories=GTK
diff --git a/app-manager/app-manager.h b/app-manager/app-manager.h
new file mode 100644 (file)
index 0000000..dca76f9
--- /dev/null
@@ -0,0 +1,7 @@
+#include <gtk/gtk.h>
+#include <plover-gtk/package.h>
+
+extern GtkBuilder *ui;
+GtkTreeModel *plover_applications_model_new(GtkTreeModel *installed);
+void set_package_model(GtkTreeModel *model);
+PloverPackage *get_active_package(void);
diff --git a/app-manager/app-manager.ui b/app-manager/app-manager.ui
new file mode 100644 (file)
index 0000000..c6b7f6b
--- /dev/null
@@ -0,0 +1,609 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkWindow" id="MainWindow">
+    <property name="visible">True</property>
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Application Manager</property>
+    <property name="default_width">600</property>
+    <property name="default_height">400</property>
+    <signal name="delete_event" handler="gtk_main_quit"/>
+    <child>
+      <object class="GtkVBox" id="vbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child>
+          <object class="GtkMenuBar" id="menubar1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <child>
+              <object class="GtkMenuItem" id="menuitem1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">_Package</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu1">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <object class="GtkImageMenuItem" id="imagemenuitem1">
+                        <property name="label">Open _Location...</property>
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="tooltip_text" translatable="yes">Open a package repository at a known location</property>
+                        <property name="use_underline">True</property>
+                        <property name="image">image1</property>
+                        <property name="use_stock">False</property>
+                        <accelerator key="l" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="on_open_location"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="menuitem5">
+                        <property name="label" translatable="yes">_Scan local media</property>
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="tooltip_text" translatable="yes">Scan local media for package repositories</property>
+                        <property name="use_underline">True</property>
+                        <property name="image">image2</property>
+                        <property name="use_stock">False</property>
+                        <signal name="activate" handler="on_scan_local_media"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkImageMenuItem" id="imagemenuitem5">
+                        <property name="label">gtk-quit</property>
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="tooltip_text" translatable="yes">Quit the application manager</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                        <accelerator key="q" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+                        <signal name="activate" handler="gtk_main_quit"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menuitem3">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">_View</property>
+                <property name="use_underline">True</property>
+                <child type="submenu">
+                  <object class="GtkMenu" id="menu2">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <object class="GtkRadioMenuItem" id="menuitem2">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="tooltip_text" translatable="yes">Show a list of files owned by the selected package</property>
+                        <property name="label" translatable="yes">_File list</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_as_radio">True</property>
+                        <signal name="toggled" handler="on_view_files_toggled"/>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioMenuItem" id="menuitem6">
+                        <property name="visible">True</property>
+                        <property name="tooltip_text" translatable="yes">Show the description etc., of the selected package</property>
+                        <property name="label" translatable="yes">Package _details</property>
+                        <property name="use_underline">True</property>
+                        <property name="active">True</property>
+                        <property name="draw_as_radio">True</property>
+                        <property name="group">menuitem2</property>
+                        <signal name="toggled" handler="on_view_details_toggled"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkMenuItem" id="menuitem4">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</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>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <object class="GtkImageMenuItem" id="imagemenuitem10">
+                        <property name="label">gtk-about</property>
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="tooltip_text" translatable="yes">Display details about the application manager</property>
+                        <property name="use_underline">True</property>
+                        <property name="use_stock">True</property>
+                        <signal name="activate" handler="on_help_about"/>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVPaned" id="vpaned2">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="orientation">vertical</property>
+            <property name="position">200</property>
+            <property name="position_set">True</property>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">6</property>
+                <property name="right_padding">6</property>
+                <child>
+                  <object class="GtkHPaned" id="hpaned1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="position_set">True</property>
+                    <child>
+                      <object class="GtkVBox" id="vbox2">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <object class="GtkHBox" id="hbox1">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkEntry" id="SearchEntry">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="invisible_char">&#x25CF;</property>
+                                <property name="activates_default">True</property>
+                                <property name="width_chars">10</property>
+                                <property name="caps_lock_warning">False</property>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkButton" id="button1">
+                                <property name="label">gtk-find</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="can_default">True</property>
+                                <property name="has_default">True</property>
+                                <property name="receives_default">True</property>
+                                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                <property name="use_stock">True</property>
+                                <signal name="clicked" handler="on_find_clicked"/>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="hbox4">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkVSeparator" id="vseparator1">
+                                <property name="visible">True</property>
+                                <property name="orientation">vertical</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkToolbar" id="toolbar1">
+                                <property name="visible">True</property>
+                                <property name="orientation">vertical</property>
+                                <property name="icon_size">2</property>
+                                <property name="icon_size_set">True</property>
+                                <child>
+                                  <object class="GtkRadioToolButton" id="toolbutton1">
+                                    <property name="visible">True</property>
+                                    <property name="tooltip_text" translatable="yes">Show installed applications</property>
+                                    <property name="label" translatable="yes">_Applications</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="icon_name">plover-applications</property>
+                                    <property name="active">True</property>
+                                    <signal name="toggled" handler="on_applications_toggled"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioToolButton" id="toolbutton2">
+                                    <property name="visible">True</property>
+                                    <property name="tooltip_text" translatable="yes">Show all installed packages</property>
+                                    <property name="label" translatable="yes">A_ll Packages</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="stock_id">gtk-index</property>
+                                    <property name="group">toolbutton1</property>
+                                    <signal name="toggled" handler="on_all_packages_toggled"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkSeparatorToolItem" id="toolbutton3">
+                                    <property name="visible">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioToolButton" id="toolbutton5">
+                                    <property name="visible">True</property>
+                                    <property name="tooltip_text" translatable="yes">Show packages in repositories on local media</property>
+                                    <property name="label" translatable="yes">Local _Media</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="stock_id">gtk-cdrom</property>
+                                    <property name="group">toolbutton1</property>
+                                    <signal name="toggled" handler="on_local_media_toggled"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioToolButton" id="LocationButton">
+                                    <property name="label" translatable="yes">Location</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="stock_id">gtk-directory</property>
+                                    <property name="group">toolbutton1</property>
+                                    <signal name="toggled" handler="on_location_toggled"/>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioToolButton" id="toolbutton4">
+                                    <property name="tooltip_text" translatable="yes">Show updates available for installed packages</property>
+                                    <property name="label" translatable="yes">_Updates</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="stock_id">gtk-execute</property>
+                                    <property name="group">toolbutton1</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="homogeneous">True</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkVSeparator" id="vseparator2">
+                                <property name="visible">True</property>
+                                <property name="orientation">vertical</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="resize">False</property>
+                        <property name="shrink">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkScrolledWindow" id="scrolledwindow2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="hscrollbar_policy">automatic</property>
+                        <property name="vscrollbar_policy">automatic</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkTreeView" id="Packages">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="resize">True</property>
+                        <property name="shrink">True</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">True</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment2">
+                <property name="visible">True</property>
+                <property name="left_padding">6</property>
+                <property name="right_padding">6</property>
+                <child>
+                  <object class="GtkHBox" id="ActivePackage">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <object class="GtkScrolledWindow" id="FilesScrolledWindow">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hscrollbar_policy">automatic</property>
+                        <property name="vscrollbar_policy">automatic</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkTreeView" id="Files">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkScrolledWindow" id="DescriptionScrolledWindow">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hscrollbar_policy">automatic</property>
+                        <property name="vscrollbar_policy">automatic</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkTextView" id="textview1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="pixels_above_lines">6</property>
+                            <property name="pixels_below_lines">6</property>
+                            <property name="editable">False</property>
+                            <property name="wrap_mode">word</property>
+                            <property name="left_margin">6</property>
+                            <property name="right_margin">6</property>
+                            <property name="buffer">description</property>
+                            <property name="accepts_tab">False</property>
+                          </object>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVBox" id="PackageDetails">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkAlignment" id="HomepageBox">
+                            <property name="visible">True</property>
+                            <property name="xscale">0</property>
+                            <property name="yscale">0</property>
+                            <child>
+                              <object class="GtkHBox" id="hbox3">
+                                <property name="visible">True</property>
+                                <child>
+                                  <object class="GtkImage" id="HomeImage">
+                                    <property name="visible">True</property>
+                                    <property name="stock">gtk-home</property>
+                                  </object>
+                                  <packing>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLinkButton" id="Homepage">
+                                    <property name="label" translatable="yes">www.gnome.org</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                    <property name="relief">none</property>
+                                    <property name="uri">http://www.city-occupational.co.uk/</property>
+                                  </object>
+                                  <packing>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkScrolledWindow" id="DetailsScrolledWindow">
+                            <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="GtkViewport" id="DetailsViewport">
+                                <property name="visible">True</property>
+                                <property name="resize_mode">queue</property>
+                                <child>
+                                  <object class="GtkAlignment" id="DetailsAlignment">
+                                    <property name="visible">True</property>
+                                    <property name="yalign">0</property>
+                                    <property name="yscale">0</property>
+                                    <child>
+                                      <object class="GtkTable" id="Details">
+                                        <property name="visible">True</property>
+                                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                        <property name="border_width">6</property>
+                                        <property name="n_rows">2</property>
+                                        <property name="n_columns">2</property>
+                                        <property name="column_spacing">6</property>
+                                        <property name="row_spacing">6</property>
+                                        <child>
+                                          <object class="GtkLabel" id="label6">
+                                            <property name="visible">True</property>
+                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                            <property name="xalign">0</property>
+                                            <property name="label" translatable="yes">Architecture:</property>
+                                            <property name="single_line_mode">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="x_options">GTK_FILL</property>
+                                            <property name="y_options"></property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="Architecture">
+                                            <property name="visible">True</property>
+                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                            <property name="xalign">0</property>
+                                            <property name="label" translatable="yes">i386</property>
+                                            <property name="selectable">True</property>
+                                            <property name="single_line_mode">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="left_attach">1</property>
+                                            <property name="right_attach">2</property>
+                                            <property name="x_options">GTK_FILL</property>
+                                            <property name="y_options"></property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="label4">
+                                            <property name="visible">True</property>
+                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                            <property name="xalign">0</property>
+                                            <property name="label" translatable="yes">License:</property>
+                                            <property name="single_line_mode">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="top_attach">1</property>
+                                            <property name="bottom_attach">2</property>
+                                            <property name="x_options">GTK_FILL</property>
+                                            <property name="y_options"></property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="License">
+                                            <property name="visible">True</property>
+                                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                                            <property name="xalign">0</property>
+                                            <property name="label" translatable="yes">LGPL</property>
+                                            <property name="selectable">True</property>
+                                            <property name="single_line_mode">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="left_attach">1</property>
+                                            <property name="right_attach">2</property>
+                                            <property name="top_attach">1</property>
+                                            <property name="bottom_attach">2</property>
+                                            <property name="x_options">GTK_FILL</property>
+                                            <property name="y_options"></property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="pack_type">end</property>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="resize">False</property>
+                <property name="shrink">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkStatusbar" id="statusbar1">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">2</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkTextBuffer" id="description"/>
+  <object class="GtkImage" id="image1">
+    <property name="visible">True</property>
+    <property name="stock">gtk-open</property>
+  </object>
+  <object class="GtkImage" id="image2">
+    <property name="visible">True</property>
+    <property name="stock">gtk-cdrom</property>
+  </object>
+</interface>
diff --git a/app-manager/applications.c b/app-manager/applications.c
new file mode 100644 (file)
index 0000000..6b72505
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <plover-gtk/packagestore.h>
+#include "app-manager.h"
+
+static gboolean plover_applications_visible_func(GtkTreeModel *model,
+  GtkTreeIter *iter,gpointer data)
+{
+    /* Visible if row is non-empty and package contains a .desktop file
+     * in /usr/share/applications
+     */
+    PloverPackage *package;
+    GtkTreeModel *file_store;
+    GtkTreeIter fi;
+    gchar *name,*dir;
+    gboolean visible=FALSE;
+    gtk_tree_model_get(model,iter,PLOVER_PACKAGE_STORE_OBJ_COLUMN,&package,-1);
+    if (package)
+    {
+       file_store=GTK_TREE_MODEL(plover_package_get_file_store(package));
+       if (gtk_tree_model_get_iter_first(file_store,&fi))
+       {
+           do
+           {
+               gtk_tree_model_get(file_store,&fi,
+                 PLOVER_PACKAGE_FILE_STORE_NAME_COLUMN,&name,-1);
+               dir=g_path_get_dirname(name);
+               if (!strcmp(dir,"/usr/share/applications") &&
+                 g_str_has_suffix(name,".desktop"))
+                   visible=TRUE;
+               g_free(dir);
+               g_free(name);
+           } while(!visible && gtk_tree_model_iter_next(file_store,&fi));
+       }
+    }
+    g_object_unref(package);
+    return visible;
+}
+
+GtkTreeModel *plover_applications_model_new(GtkTreeModel *installed)
+{
+    GtkTreeModel *model;
+    model=gtk_tree_model_filter_new(installed,NULL);
+    gtk_tree_model_filter_set_visible_func(model,
+      plover_applications_visible_func,NULL,NULL);
+    return model;
+}
diff --git a/app-manager/localmedia.c b/app-manager/localmedia.c
new file mode 100644 (file)
index 0000000..9f6a2d8
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+#include <plover-gtk/packagestore.h>
+#include "localmedia.h"
+
+G_DEFINE_TYPE(PloverLocalMediaStore,plover_local_media_store,
+  PLOVER_TYPE_PACKAGE_STORE);
+
+static void plover_local_media_store_dispose(GObject *obj)
+{
+    PloverLocalMediaStore *store=PLOVER_LOCAL_MEDIA_STORE(obj);
+    if (store->monitor)
+    {
+       g_object_unref(store->monitor);
+       store->monitor=NULL;
+    }
+    if (G_OBJECT_CLASS(plover_local_media_store_parent_class)->dispose)
+       G_OBJECT_CLASS(plover_local_media_store_parent_class)->dispose(obj);
+}
+
+static void
+  plover_local_media_store_class_init(PloverLocalMediaStoreClass *klass)
+{
+    GObjectClass *oclass=G_OBJECT_CLASS(klass);
+    oclass->dispose=plover_local_media_store_dispose;
+}
+
+GtkTreeModel *plover_local_media_store_new(void)
+{
+    return g_object_new(PLOVER_TYPE_LOCAL_MEDIA_STORE,NULL);
+}
+
+static void local_media_scan_mount(PloverLocalMediaStore *store,GMount *mount)
+{
+    GFile *root;
+    gchar *path;
+    PloverPackageSet *set;
+    root=g_mount_get_root(mount);
+    path=g_file_get_path(root);
+    if (path)
+    {
+       set=plover_package_set_new_from_repository(path,NULL);
+       if (set)
+       {
+           g_object_set_data(G_OBJECT(mount),"plover-local-media-set",set);
+           plover_package_store_add_set(PLOVER_PACKAGE_STORE(store),set);
+           g_object_ref(mount);
+       }
+       g_free(path);
+    }
+    g_object_unref(root);
+}
+
+static void local_media_mounted(GObject *source,GAsyncResult *res,gpointer data)
+{
+    GVolume *volume=G_VOLUME(source);
+    GMount *mount;
+    PloverLocalMediaStore *store=PLOVER_LOCAL_MEDIA_STORE(data);
+    if (g_volume_mount_finish(volume,res,NULL))
+    {
+       mount=g_volume_get_mount(volume);
+       if (mount)
+       {
+           local_media_scan_mount(store,mount);
+           g_object_unref(mount);
+       }
+    }
+    g_object_unref(volume);
+}
+
+static void local_media_scan_drive(PloverLocalMediaStore *store,GDrive *drive)
+{
+    GVolume *volume;
+    GMount *mount;
+    GList *volumes,*link;
+    if (g_drive_has_media(drive))
+    {
+       volumes=g_drive_get_volumes(drive);
+       for(link=volumes;link;link=link->next)
+       {
+           volume=G_VOLUME(link->data);
+           mount=g_volume_get_mount(volume);
+           if (mount)
+           {
+               local_media_scan_mount(store,mount);
+               g_object_unref(mount);
+           }
+           else if (!store->implicit_scan && g_volume_can_mount(volume))
+               g_volume_mount(volume,G_MOUNT_MOUNT_NONE,NULL,NULL,
+                 local_media_mounted,store);
+           g_object_unref(volume);
+       }
+       g_list_free(volumes);
+    }
+}
+
+static void local_media_polled(GObject *source,GAsyncResult *res,gpointer data)
+{
+    GDrive *drive=G_DRIVE(source);
+    PloverLocalMediaStore *store=PLOVER_LOCAL_MEDIA_STORE(data);
+    if (g_drive_poll_for_media_finish(drive,res,NULL))
+       local_media_scan_drive(store,drive);
+    g_object_unref(drive);
+}
+
+void plover_local_media_store_scan(PloverLocalMediaStore *store)
+{
+    GList *drives,*link;
+    GDrive *drive;
+    g_return_if_fail(PLOVER_IS_LOCAL_MEDIA_STORE(store));
+    drives=g_volume_monitor_get_connected_drives(store->monitor);
+    for(link=drives;link;link=link->next)
+    {
+       drive=G_DRIVE(link->data);
+       if (g_drive_is_media_removable(drive))
+       {
+           if (!g_drive_is_media_check_automatic(drive) &&
+             g_drive_can_poll_for_media(drive) ||
+             !g_drive_has_media(drive) && !store->implicit_scan)
+           {
+               g_object_ref(drive);
+               g_drive_poll_for_media(drive,NULL,local_media_polled,store);
+           }
+           else
+               local_media_scan_drive(store,drive);
+       }
+       g_object_unref(drive);
+    }
+    g_list_free(drives);
+}
+
+static void local_media_mount_added(GVolumeMonitor *volume_monitor,
+  GMount *mount,PloverLocalMediaStore *store)
+{
+    local_media_scan_mount(store,mount);
+}
+
+static void local_media_mount_removed(GVolumeMonitor *volume_monitor,
+  GMount *mount,PloverLocalMediaStore *store)
+{
+    PloverPackageSet *set=
+      g_object_get_data(G_OBJECT(mount),"plover-local-media-set");
+    if (set)
+    {
+       plover_package_store_remove_set(PLOVER_PACKAGE_STORE(store),set);
+       g_object_set_data(G_OBJECT(mount),"plover-local-media-set",NULL);
+       g_object_unref(set);
+       g_object_unref(mount);
+    }
+}
+
+static void local_media_mount_changed(GVolumeMonitor *volume_monitor,
+  GMount *mount,PloverLocalMediaStore *store)
+{
+    local_media_mount_removed(volume_monitor,mount,store);
+    local_media_mount_added(volume_monitor,mount,store);
+}
+
+static void plover_local_media_store_init(PloverLocalMediaStore *store)
+{
+    store->monitor=g_volume_monitor_get();
+    store->implicit_scan=TRUE;
+    plover_local_media_store_scan(store);
+    store->implicit_scan=FALSE;
+    g_signal_connect(store->monitor,"mount-added",
+      G_CALLBACK(local_media_mount_added),store);
+    g_signal_connect(store->monitor,"mount-changed",
+      G_CALLBACK(local_media_mount_changed),store);
+    g_signal_connect(store->monitor,"mount-removed",
+      G_CALLBACK(local_media_mount_removed),store);
+}
diff --git a/app-manager/localmedia.h b/app-manager/localmedia.h
new file mode 100644 (file)
index 0000000..7fc4484
--- /dev/null
@@ -0,0 +1,41 @@
+#include <glib-object.h>
+#include <plover-gtk/packagestore.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_LOCAL_MEDIA_STORE\
+                               plover_local_media_store_get_type()
+#define PLOVER_LOCAL_MEDIA_STORE(obj)\
+                               G_TYPE_CHECK_INSTANCE_CAST(obj,\
+                                 PLOVER_TYPE_LOCAL_MEDIA_STORE,\
+                                 PloverLocalMediaStore)
+#define PLOVER_LOCAL_MEDIA_STORE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_CAST(klass,\
+                                 PLOVER_TYPE_LOCAL_MEDIA_STORE,\
+                                 PloverLocalMediaStoreClass)
+#define PLOVER_IS_LOCAL_MEDIA_STORE(obj)\
+                               G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+                                 PLOVER_TYPE_LOCAL_MEDIA_STORE)
+#define PLOVER_IS_LOCAL_MEDIA_STORE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_TYPE(obj,\
+                                 PLOVER_TYPE_LOCAL_MEDIA_STORE)
+#define PLOVER_LOCAL_MEDIA_STORE_GET_CLASS(obj)\
+                               G_TYPE_INSTANCE_GET_CLASS(obj,\
+                                 PLOVER_TYPE_LOCAL_MEDIA_STORE,\
+                                 PloverLocalMediaStoreClass)
+
+typedef struct _PloverLocalMediaStore {
+    PloverPackageStore parent_instance;
+    GVolumeMonitor *monitor;
+    gboolean implicit_scan;
+} PloverLocalMediaStore;
+
+typedef struct _PloverLocalMediaStoreClass {
+    PloverPackageStoreClass parent_class;
+} PloverLocalMediaStoreClass;
+
+GType plover_local_media_store_get_type(void) G_GNUC_CONST;
+GtkTreeModel *plover_local_media_store_new(void);
+void plover_local_media_scan(PloverLocalMediaStore *store);
+
+G_END_DECLS
diff --git a/app-manager/packagelist.c b/app-manager/packagelist.c
new file mode 100644 (file)
index 0000000..6425f95
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <plover-gtk/package.h>
+#include <plover-gtk/packageset.h>
+#include <plover-gtk/packagestore.h>
+#include <plover-gtk/packagefilestore.h>
+#include "app-manager.h"
+
+GtkTreeView *view=NULL;
+PloverPackage *active=NULL;
+gboolean view_files=FALSE;
+
+void package_present(PloverPackage *package)
+{
+    gchar *s;
+    const char *text,*t;
+    GtkWidget *w;
+    GtkTextBuffer *buf;
+    buf=GTK_TEXT_BUFFER(gtk_builder_get_object(ui,"description"));
+    if (package)
+    {
+       s=g_strdup(plover_package_get_description(package));
+       g_strdelimit(s,"\t\n",' ');
+    }
+    else
+       s=g_strdup("");
+    gtk_text_buffer_set_text(buf,s,-1);
+    g_free(s);
+    w=GTK_WIDGET(gtk_builder_get_object(ui,"PackageDetails"));
+    if (!package)
+    {
+       gtk_widget_hide(w);
+       w=GTK_WIDGET(gtk_builder_get_object(ui,"FilesScrolledWindow"));
+       gtk_widget_hide(w);
+       w=GTK_WIDGET(gtk_builder_get_object(ui,"DescriptionScrolledWindow"));
+       gtk_widget_show(w);
+    }
+    else
+    {
+       if (view_files)
+           gtk_widget_hide(w);
+       else
+       {
+           gtk_widget_show(w);
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"HomepageBox"));
+           text=plover_package_get_URL(package);
+           if (!*text)
+               gtk_widget_hide(w);
+           else
+           {
+               gtk_widget_show(w);
+               w=GTK_WIDGET(gtk_builder_get_object(ui,"Homepage"));
+               gtk_link_button_set_uri(GTK_LINK_BUTTON(w),text);
+               t=strstr(text,"://");
+               if (t)
+                   t+=3;
+               if (t)
+                   s=strndup(t,strcspn(t,"/"));
+               else
+                   s=strdup(text);
+               gtk_button_set_label(GTK_BUTTON(w),s);
+               g_free(s);
+           }
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"Architecture"));
+           gtk_label_set_text(GTK_LABEL(w),plover_package_get_arch(package));
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"License"));
+           gtk_label_set_text(GTK_LABEL(w),
+             plover_package_get_license(package));
+       }
+       w=GTK_WIDGET(gtk_builder_get_object(ui,"FilesScrolledWindow"));
+       if (view_files)
+           gtk_widget_show(w);
+       else
+           gtk_widget_hide(w);
+       w=GTK_WIDGET(gtk_builder_get_object(ui,"DescriptionScrolledWindow"));
+       if (view_files)
+       {
+           gtk_widget_hide(w);
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"Files"));
+           gtk_tree_view_set_model(GTK_TREE_VIEW(w),
+             GTK_TREE_MODEL(plover_package_get_file_store(package)));
+       }
+       else
+       {
+           gtk_widget_show(w);
+           /* Without this, Gtk+ 2.18.6 just truncates long license tags */
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"DetailsScrolledWindow"));
+           gtk_widget_queue_resize(w);
+       }
+    }
+}
+
+void package_filelist_present(PloverPackage *package)
+{
+}
+
+static void package_selection_changed(GtkTreeSelection *selection)
+{
+    GtkTreeIter iter;
+    GtkTreeView *view;
+    GtkTreeModel *model;
+    if (active)
+       g_object_unref(active);
+    if (gtk_tree_selection_get_selected(selection,NULL,&iter))
+    {
+       view=gtk_tree_selection_get_tree_view(selection);
+       model=gtk_tree_view_get_model(view);
+       gtk_tree_model_get(model,&iter,PLOVER_PACKAGE_STORE_OBJ_COLUMN,&active,
+         -1);
+    }
+    else
+       active=NULL;
+    package_present(active);
+}
+
+static void package_activated(GtkTreeView *view,GtkTreePath *path,
+  GtkTreeViewColumn *column,gpointer data)
+{
+    GtkTreeIter iter;
+    GtkTreeModel *model=gtk_tree_view_get_model(view);
+    PloverPackage *package;
+    if (gtk_tree_model_get_iter(model,&iter,path))
+    {
+       gtk_tree_model_get(model,&iter,PLOVER_PACKAGE_STORE_OBJ_COLUMN,&package,
+         -1);
+       package_filelist_present(package);
+    }
+}
+
+static void package_cell_data_func(GtkTreeViewColumn *column,
+  GtkCellRenderer *cell,GtkTreeModel *model,GtkTreeIter *iter,gpointer data)
+{
+    gchar *markup;
+    gchar *summary,*name,*version;
+    gtk_tree_model_get(model,iter,PLOVER_PACKAGE_STORE_SUMMARY_COLUMN,&summary,
+      PLOVER_PACKAGE_STORE_NAME_COLUMN,&name,
+      PLOVER_PACKAGE_STORE_VERSION_COLUMN,&version,-1);
+    markup=g_strdup_printf("<b>%s</b>\n%s %s",summary,name,version,NULL);
+    g_free(summary);
+    g_free(name);
+    g_free(version);
+    g_object_set(cell,"markup",markup,NULL);
+    g_free(markup);
+}
+
+void set_package_model(GtkTreeModel *model)
+{
+    GtkWidget *w;
+    GtkTreeViewColumn *column;
+    GtkCellRenderer *renderer;
+    GtkTreeSelection *selection;
+    if (!view)
+    {
+       w=GTK_WIDGET(gtk_builder_get_object(ui,"Packages"));
+       if (w)
+       {
+           view=GTK_TREE_VIEW(w);
+#if 0
+           column=gtk_tree_view_column_new_with_attributes("Icon",
+             gtk_cell_renderer_pixbuf_new(),"pixbuf",
+             PLOVER_PACKAGE_FILE_STORE_ICON_COLUMN,NULL);
+           gtk_tree_view_append_column(GTK_TREE_VIEW(w),column);
+#endif
+           column=gtk_tree_view_column_new();
+           gtk_tree_view_column_set_title(column,"Summary");
+           renderer=gtk_cell_renderer_text_new();
+           gtk_tree_view_column_pack_start(column,renderer,FALSE);
+           gtk_tree_view_column_set_cell_data_func(column,renderer,
+             package_cell_data_func,NULL,NULL);
+           gtk_tree_view_append_column(view,column);
+           gtk_widget_show_all(w);
+           gtk_tree_view_set_headers_visible(view,FALSE);
+           w=GTK_WIDGET(gtk_builder_get_object(ui,"SearchEntry"));
+           gtk_tree_view_set_search_entry(view,GTK_ENTRY(w));
+           selection=gtk_tree_view_get_selection(view);
+           g_signal_connect(selection,"changed",
+             G_CALLBACK(package_selection_changed),NULL);
+           g_signal_connect(view,"row-activated",G_CALLBACK(package_activated),
+             NULL);
+       }
+       else
+           g_warning("Packages: no such widget in UI");
+       w=GTK_WIDGET(gtk_builder_get_object(ui,"Files"));
+       if (w)
+       {
+           column=gtk_tree_view_column_new_with_attributes("Name",
+             gtk_cell_renderer_text_new(),"text",
+             PLOVER_PACKAGE_FILE_STORE_NAME_COLUMN,NULL);
+           gtk_tree_view_append_column(GTK_TREE_VIEW(w),column);
+           gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w),FALSE);
+           gtk_widget_show_all(w);
+       }
+       else
+           g_warning("Files: no such widget in UI");
+    }
+    if (view)
+    {
+       gtk_tree_view_set_model(view,model);
+       gtk_tree_view_set_search_column(view,
+         PLOVER_PACKAGE_STORE_NAME_COLUMN);
+    }
+    package_present(NULL);
+}
+
+PloverPackage *get_active_package(void)
+{
+    return active;
+}
+
+G_MODULE_EXPORT void
+  on_view_files_toggled(GtkCheckMenuItem *menuitem,gpointer data)
+{
+    view_files=gtk_check_menu_item_get_active(menuitem);
+    package_present(active);
+}
+
+G_MODULE_EXPORT void
+  on_view_details_toggled(GtkCheckMenuItem *menuitem,gpointer data)
+{
+}
diff --git a/app-manager/plover-applications.svg b/app-manager/plover-applications.svg
new file mode 100644 (file)
index 0000000..07cfc18
--- /dev/null
@@ -0,0 +1,1108 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://web.resource.org/cc/"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   sodipodi:docname="applications-other.svg"
+   sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/categories"
+   inkscape:version="0.45"
+   sodipodi:version="0.32"
+   id="svg2963"
+   height="48px"
+   width="48px"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs3">
+    <linearGradient
+       id="linearGradient2394">
+      <stop
+         id="stop2396"
+         offset="0"
+         style="stop-color:#5c3566;stop-opacity:1" />
+      <stop
+         id="stop2398"
+         offset="1"
+         style="stop-color:#45284d;stop-opacity:1;" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient2384">
+      <stop
+         style="stop-color:#5c3566;stop-opacity:1;"
+         offset="0"
+         id="stop2386" />
+      <stop
+         style="stop-color:#43274b;stop-opacity:1;"
+         offset="1"
+         id="stop2388" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3938">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3940" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3942" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3919">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3921" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3923" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3887">
+      <stop
+         style="stop-color:#edd400;stop-opacity:1;"
+         offset="0"
+         id="stop3889" />
+      <stop
+         style="stop-color:#fce94f;stop-opacity:1"
+         offset="1"
+         id="stop3891" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3800">
+      <stop
+         id="stop3802"
+         offset="0"
+         style="stop-color:#babdb6;stop-opacity:1" />
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:1;"
+         offset="0.5"
+         id="stop3804" />
+      <stop
+         id="stop3806"
+         offset="1"
+         style="stop-color:#babdb6;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3792">
+      <stop
+         id="stop3794"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0.5"
+         id="stop3796" />
+      <stop
+         id="stop3798"
+         offset="1"
+         style="stop-color:#888a85;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3786"
+       inkscape:collect="always">
+      <stop
+         id="stop3788"
+         offset="0"
+         style="stop-color:#888a85;stop-opacity:1" />
+      <stop
+         id="stop3790"
+         offset="1"
+         style="stop-color:#2e3436;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3683">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3686" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop3688" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3666">
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:1;"
+         offset="0"
+         id="stop3668" />
+      <stop
+         style="stop-color:#e9b96e;stop-opacity:1"
+         offset="1"
+         id="stop3670" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3622">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3624" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3626" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3551"
+       inkscape:collect="always">
+      <stop
+         id="stop3553"
+         offset="0"
+         style="stop-color:#ffffff;stop-opacity:1;" />
+      <stop
+         id="stop3555"
+         offset="1"
+         style="stop-color:#888a85;stop-opacity:1" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3539">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3541" />
+      <stop
+         style="stop-color:#888a85;stop-opacity:1"
+         offset="1"
+         id="stop3543" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3517">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3519" />
+      <stop
+         style="stop-color:#eeeeec;stop-opacity:1"
+         offset="1"
+         id="stop3521" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3470">
+      <stop
+         style="stop-color:#f5e0be;stop-opacity:1"
+         offset="0"
+         id="stop3472" />
+      <stop
+         style="stop-color:#8ae234;stop-opacity:1"
+         offset="1"
+         id="stop3474" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3452">
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0"
+         id="stop3454" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:0;"
+         offset="1"
+         id="stop3456" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3270">
+      <stop
+         style="stop-color:#e9b96e;stop-opacity:1;"
+         offset="0"
+         id="stop3272" />
+      <stop
+         style="stop-color:#e9b96e;stop-opacity:0;"
+         offset="1"
+         id="stop3274" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3264">
+      <stop
+         style="stop-color:#e9b96e;stop-opacity:1"
+         offset="0"
+         id="stop3266" />
+      <stop
+         style="stop-color:#e9b96e;stop-opacity:0"
+         offset="1"
+         id="stop3268" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3251"
+       inkscape:collect="always">
+      <stop
+         id="stop3253"
+         offset="0"
+         style="stop-color:#8f5902;stop-opacity:1" />
+      <stop
+         id="stop3255"
+         offset="1"
+         style="stop-color:#8f5902;stop-opacity:0" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3243">
+      <stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop3245" />
+      <stop
+         style="stop-color:#000000;stop-opacity:0"
+         offset="1"
+         id="stop3247" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient3703">
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="0"
+         id="stop3705" />
+      <stop
+         id="stop3711"
+         offset="0.5"
+         style="stop-color:black;stop-opacity:1;" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop3707" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3681">
+      <stop
+         style="stop-color:black;stop-opacity:1;"
+         offset="0"
+         id="stop3683" />
+      <stop
+         style="stop-color:black;stop-opacity:0;"
+         offset="1"
+         id="stop3685" />
+    </linearGradient>
+    <linearGradient
+       id="linearGradient4210">
+      <stop
+         id="stop4212"
+         offset="0.0000000"
+         style="stop-color:#eaba6f;stop-opacity:1.0000000;" />
+      <stop
+         id="stop4214"
+         offset="1.0000000"
+         style="stop-color:#b97a1b;stop-opacity:1.0000000;" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3622"
+       id="linearGradient3645"
+       gradientUnits="userSpaceOnUse"
+       x1="48.25"
+       y1="33.75"
+       x2="50.5"
+       y2="48.125" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3666"
+       id="linearGradient3672"
+       x1="66.840225"
+       y1="18.675386"
+       x2="71.5625"
+       y2="40.005543"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-40,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3683"
+       id="linearGradient3690"
+       x1="18.9375"
+       y1="33.899853"
+       x2="18.9375"
+       y2="36.052185"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3270"
+       id="linearGradient3734"
+       gradientUnits="userSpaceOnUse"
+       x1="22.1875"
+       y1="20"
+       x2="22.1875"
+       y2="24.079771"
+       gradientTransform="translate(0,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3251"
+       id="linearGradient3736"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,-1,0,49)"
+       x1="10.74916"
+       y1="21.5"
+       x2="12.109532"
+       y2="21.5" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3264"
+       id="linearGradient3738"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1,0,0,-1,46.92613,49)"
+       x1="11.12416"
+       y1="21.5625"
+       x2="13.168094"
+       y2="21.5625" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3786"
+       id="radialGradient3740"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.22665,0,0,0.6587882,-4.355929,9.4385304)"
+       cx="19.21875"
+       cy="22.255209"
+       fx="19.21875"
+       fy="22.255209"
+       r="4.46875" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3452"
+       id="linearGradient3746"
+       gradientUnits="userSpaceOnUse"
+       x1="28.59375"
+       y1="20.875"
+       x2="38.53125"
+       y2="29.5" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3517"
+       id="linearGradient3750"
+       gradientUnits="userSpaceOnUse"
+       x1="2.0517766"
+       y1="23.775574"
+       x2="2.0517766"
+       y2="20.549225"
+       gradientTransform="translate(10,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3539"
+       id="linearGradient3752"
+       gradientUnits="userSpaceOnUse"
+       x1="12.8125"
+       y1="16.279297"
+       x2="12.8125"
+       y2="13.742194"
+       gradientTransform="translate(0,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3243"
+       id="linearGradient3756"
+       gradientUnits="userSpaceOnUse"
+       x1="20.78125"
+       y1="24.59375"
+       x2="20.8125"
+       y2="23.53125" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3681"
+       id="radialGradient3768"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.990017,0,0,1.1,32.1147,-5.15)"
+       cx="5"
+       cy="41.5"
+       fx="5"
+       fy="41.5"
+       r="5" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3681"
+       id="radialGradient3770"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.99001,0,0,1.1,-14.88523,-86.15)"
+       cx="5"
+       cy="41.5"
+       fx="5"
+       fy="41.5"
+       r="5" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3703"
+       id="linearGradient3772"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.179548,0,0,1,-4.219389,0)"
+       x1="17.554192"
+       y1="46.000275"
+       x2="17.554192"
+       y2="34.999718" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient4210"
+       id="linearGradient3779"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0018526,0,0,-1.3412436,-1.3825e-2,57.988076)"
+       x1="17.379599"
+       y1="20.096134"
+       x2="17.379599"
+       y2="37.446911" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3887"
+       id="linearGradient3893"
+       x1="13.89607"
+       y1="4.6658931"
+       x2="12.919692"
+       y2="13.139417"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3887"
+       id="linearGradient3917"
+       gradientUnits="userSpaceOnUse"
+       x1="13.89607"
+       y1="4.6658931"
+       x2="12.919692"
+       y2="13.139417" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3919"
+       id="linearGradient3925"
+       x1="10.8125"
+       y1="1.5625"
+       x2="16"
+       y2="26.4375"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3800"
+       id="linearGradient3934"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,-1,0,48)"
+       x1="27.616999"
+       y1="15.720971"
+       x2="35.25803"
+       y2="15.5" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3792"
+       id="radialGradient3936"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.3566902,0,0,0.7525334,-11.151648,1.0040626)"
+       cx="31.264236"
+       cy="12.943277"
+       fx="31.264236"
+       fy="12.943277"
+       r="4.5557737" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3938"
+       id="linearGradient3944"
+       x1="27.225912"
+       y1="15.13085"
+       x2="36.394157"
+       y2="19.403521"
+       gradientUnits="userSpaceOnUse" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3681"
+       id="radialGradient3341"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.990017,0,0,1.1,32.1147,-5.15)"
+       cx="5"
+       cy="41.5"
+       fx="5"
+       fy="41.5"
+       r="5" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3681"
+       id="radialGradient3343"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.99001,0,0,1.1,-14.88523,-86.15)"
+       cx="5"
+       cy="41.5"
+       fx="5"
+       fy="41.5"
+       r="5" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3703"
+       id="linearGradient3345"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.179548,0,0,1,-4.219389,0)"
+       x1="17.554192"
+       y1="46.000275"
+       x2="17.554192"
+       y2="34.999718" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3517"
+       id="linearGradient2379"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.9659258,0.258819,0.258819,-0.9659258,12.365949,46.030428)"
+       x1="2.0517766"
+       y1="23.775574"
+       x2="2.0517766"
+       y2="20.549225" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3551"
+       id="linearGradient2381"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(3,0)"
+       x1="12.5"
+       y1="16.248047"
+       x2="12.5"
+       y2="13.748305" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3517"
+       id="linearGradient2403"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(13,0)"
+       x1="2.0517766"
+       y1="23.775574"
+       x2="2.0517766"
+       y2="20.549225" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3539"
+       id="linearGradient2405"
+       gradientUnits="userSpaceOnUse"
+       x1="12.8125"
+       y1="16.279297"
+       x2="12.8125"
+       y2="13.742194"
+       gradientTransform="translate(3,0)" />
+    <radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3470"
+       id="radialGradient2439"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.4456279,0,0,1.2531601,-10.145615,-5.696102)"
+       cx="27.23303"
+       cy="22.5"
+       fx="27.23303"
+       fy="22.5"
+       r="7" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2384"
+       id="linearGradient2390"
+       x1="20.8125"
+       y1="15.28125"
+       x2="22.718748"
+       y2="24.59375"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2384"
+       id="linearGradient2392"
+       x1="10.5"
+       y1="19.836557"
+       x2="10.5"
+       y2="21.077166"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(0,1)" />
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient2394"
+       id="linearGradient2400"
+       x1="13.5625"
+       y1="19.84375"
+       x2="13.5625"
+       y2="21.3125"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-y="145"
+     inkscape:window-x="785"
+     inkscape:window-height="905"
+     inkscape:window-width="895"
+     stroke="#c17d11"
+     fill="#e9b96e"
+     inkscape:showpageshadow="false"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     showgrid="false"
+     inkscape:current-layer="layer1"
+     inkscape:cy="9.9678443"
+     inkscape:cx="30.274133"
+     inkscape:zoom="1"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     borderopacity="1"
+     bordercolor="#e0e0e0"
+     pagecolor="#ffffff"
+     id="base"
+     showguides="false"
+     inkscape:guide-bbox="true"
+     showborder="true"
+     gridspacingx="0.5px"
+     gridspacingy="0.5px"
+     gridempspacing="2"
+     inkscape:grid-points="false">
+    <sodipodi:guide
+       orientation="horizontal"
+       position="27.499825"
+       id="guide3495" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>Misc Stuff</dc:title>
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>Lapo Calamandrei</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:source />
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>stuff</rdf:li>
+            <rdf:li>box</rdf:li>
+            <rdf:li>misc</rdf:li>
+            <rdf:li>various</rdf:li>
+            <rdf:li>mess</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+        <dc:contributor>
+          <cc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </cc:Agent>
+        </dc:contributor>
+        <dc:date>2007-01-12</dc:date>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Reproduction" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/Distribution" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/Notice" />
+        <cc:permits
+           rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/ShareAlike" />
+        <cc:requires
+           rdf:resource="http://web.resource.org/cc/SourceCode" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:groupmode="layer"
+     inkscape:label="Layer 1"
+     id="layer1">
+    <g
+       id="g3760"
+       style="opacity:0.17241378"
+       transform="matrix(1,0,0,1.0909091,0,-2.181818)">
+      <rect
+         y="35"
+         x="37.064781"
+         height="11"
+         width="4.9352183"
+         id="rect3762"
+         style="opacity:1;fill:url(#radialGradient3768);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+      <rect
+         transform="scale(-1,-1)"
+         y="-46"
+         x="-9.9351835"
+         height="11"
+         width="4.9351835"
+         id="rect3764"
+         style="opacity:1;fill:url(#radialGradient3770);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+      <rect
+         y="35"
+         x="9.9351835"
+         height="11"
+         width="27.129599"
+         id="rect3766"
+         style="opacity:1;fill:url(#linearGradient3772);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+    </g>
+    <g
+       id="g3333"
+       style="opacity:0.29714286"
+       transform="matrix(1.02239,0,0,0.6818183,-0.5261638,14.343465)">
+      <rect
+         y="35"
+         x="37.064781"
+         height="11"
+         width="4.9352183"
+         id="rect3335"
+         style="opacity:1;fill:url(#radialGradient3341);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+      <rect
+         transform="scale(-1,-1)"
+         y="-46"
+         x="-9.9351835"
+         height="11"
+         width="4.9351835"
+         id="rect3337"
+         style="opacity:1;fill:url(#radialGradient3343);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+      <rect
+         y="35"
+         x="9.9351835"
+         height="11"
+         width="27.129599"
+         id="rect3339"
+         style="opacity:1;fill:url(#linearGradient3345);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1" />
+    </g>
+    <path
+       style="color:#000000;fill:url(#linearGradient3779);fill-opacity:1;fill-rule:nonzero;stroke:#a0670c;stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       d="M 11.78125,18.5 C 10.435791,18.5 9.719445,19.195548 9.34375,20.28125 L 7.46875,26.28125 L 6.5,34.5 L 7.46875,34.5 L 7.46875,41.09375 C 7.46875,42.431583 8.560792,43.500001 9.90625,43.5 L 37.0625,43.5 C 38.407959,43.5 39.499998,42.431582 39.5,41.09375 L 39.5,34.5 L 40.5,34.5 L 39.5,26.28125 L 37.5625,20.40625 C 37.090576,18.976725 36.157962,18.499999 34.8125,18.5 L 11.78125,18.5 z "
+       id="path3591"
+       sodipodi:nodetypes="ccccccccccccccc" />
+    <path
+       style="color:#000000;fill:url(#linearGradient3672);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       d="M 7.875,26.502816 L 7.03125,34 L 39.96875,34 L 39.09375,26.502816 L 7.875,26.502816 z "
+       id="path3651"
+       sodipodi:nodetypes="ccccc" />
+    <g
+       id="g3630"
+       style="opacity:0.69348659"
+       transform="translate(-40,1)">
+      <path
+         d="M 51.78125,18.5 C 51.28084,18.5 51.016779,18.620824 50.8125,18.78125 C 50.608221,18.941676 50.426448,19.174149 50.28125,19.59375 L 48.4375,25.53125 L 48.4375,25.59375 L 47.625,32.53125 C 48.103888,32.606958 48.459499,33.015253 48.46875,33.5 L 48.46875,40.09375 C 48.46875,40.887398 49.090187,41.500001 49.90625,41.5 L 77.0625,41.5 C 77.878564,41.5 78.499999,40.887399 78.5,40.09375 L 78.5,33.5 C 78.496071,32.993079 78.872044,32.563396 79.375,32.5 L 78.5,25.40625 L 76.625,19.71875 C 76.440137,19.158774 76.215378,18.90959 75.96875,18.75 C 75.722122,18.59041 75.367124,18.5 74.8125,18.5 L 51.78125,18.5 z "
+         id="path3606"
+         style="color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3645);stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+         inkscape:original="M 51.78125 17.5 C 50.435791 17.5 49.719445 18.195548 49.34375 19.28125 L 47.46875 25.28125 L 46.5 33.5 L 47.46875 33.5 L 47.46875 40.09375 C 47.46875 41.431583 48.560792 42.500001 49.90625 42.5 L 77.0625 42.5 C 78.407959 42.5 79.499998 41.431582 79.5 40.09375 L 79.5 33.5 L 80.5 33.5 L 79.5 25.28125 L 77.5625 19.40625 C 77.090576 17.976725 76.157962 17.499999 74.8125 17.5 L 51.78125 17.5 z "
+         inkscape:radius="-1"
+         sodipodi:type="inkscape:offset" />
+      <rect
+         ry="0.5"
+         rx="0.5"
+         y="32"
+         x="47"
+         height="1"
+         width="33"
+         id="rect3610"
+         style="opacity:1;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+    </g>
+    <path
+       style="opacity:0.35;color:#000000;fill:url(#linearGradient3690);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       d="M 7.96875,34 L 7.96875,41.09375 C 7.96875,42.159491 8.82549,43.000001 9.90625,43 L 37.0625,43 C 38.143262,43 38.999998,42.159491 39,41.09375 L 39,34 L 7.96875,34 z "
+       id="path3678"
+       sodipodi:nodetypes="ccccccc" />
+    <rect
+       style="opacity:1;color:#000000;fill:#a0670c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect3600"
+       width="33.0625"
+       height="1"
+       x="7"
+       y="34" />
+    <path
+       style="opacity:0.6;color:#000000;fill:url(#linearGradient3734);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       d="M 11.78125,20 C 11.367,20 11.234304,20.070411 11.125,20.15625 C 11.015696,20.242089 10.873873,20.423275 10.75,20.78125 L 9.125,26 L 37.8125,26 L 36.15625,20.96875 C 35.947593,20.450065 35.798273,20.282879 35.65625,20.1875 C 35.514227,20.092121 35.297418,20 34.8125,20 L 11.78125,20 z "
+       id="path3692" />
+    <path
+       style="opacity:0.6;color:#000000;fill:url(#linearGradient3736);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       d="M 11.78125,20 C 11.367,20 11.234304,20.070411 11.125,20.15625 C 11.015696,20.242089 10.873873,20.423275 10.75,20.78125 L 9.125,26 L 14,26 L 14,20 L 11.78125,20 z "
+       id="path3694" />
+    <g
+       id="g3899"
+       transform="translate(5,0)"
+       style="opacity:0.84000005">
+      <path
+         style="color:#000000;fill:url(#linearGradient3917);fill-opacity:1;fill-rule:nonzero;stroke:#c4a000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="M 11.5,2.5 L 16.5,2.5 L 16.391747,23.437502 L 11.5,23.500002 L 11.5,2.5 z "
+         id="path3901"
+         sodipodi:nodetypes="ccccc" />
+      <rect
+         y="3.5"
+         x="12.5"
+         height="19.000002"
+         width="3"
+         id="rect3903"
+         style="opacity:0.80459768;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3925);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <g
+         id="g3905">
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3907"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="6" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3909"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="9" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3911"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="12" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3913"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="15" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3915"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="18" />
+      </g>
+    </g>
+    <path
+       style="opacity:0.67049806;color:#000000;fill:url(#linearGradient3738);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       d="M 35.144876,20 C 35.559126,20 35.691822,20.070411 35.801126,20.15625 C 35.91043,20.242089 36.052253,20.423275 36.176126,20.78125 L 37.801126,26 L 32.926126,26 L 32.926126,20 L 35.144876,20 z "
+       id="path3696" />
+    <g
+       id="g3877"
+       transform="matrix(0.8660254,-0.4999999,0.4999999,0.8660254,-5.991941,14.452399)">
+      <path
+         style="color:#000000;fill:url(#linearGradient3893);fill-opacity:1;fill-rule:nonzero;stroke:#b89600;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="M 11.5,2.5 L 16.5,2.5 L 16.391747,23.437502 L 11.586278,20.663063 L 11.5,2.5 z "
+         id="rect3846"
+         sodipodi:nodetypes="ccccc" />
+      <path
+         style="opacity:0.87459765;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="M 12.5,3.5 L 15.5,3.5 L 15.5,22.500002 L 12.587921,21.035219 L 12.5,3.5 z "
+         id="rect3858"
+         sodipodi:nodetypes="ccccc" />
+      <g
+         id="g3870">
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3860"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="6" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3862"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="9" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3864"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="12" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3866"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="15" />
+        <rect
+           style="opacity:0.62068942;color:#000000;fill:#c4a000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="rect3868"
+           width="2"
+           height="1.0312499"
+           x="14"
+           y="18" />
+      </g>
+    </g>
+    <path
+       style="opacity:1;color:#000000;fill:url(#radialGradient3740);fill-opacity:1;fill-rule:nonzero;stroke:#2e3436;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       d="M 20.96875,22.5 C 18.778,22.5 17,23.844 17,25.5 C 17,25.851327 17.102984,26.186614 17.25,26.5 L 24.6875,26.5 C 24.834516,26.186614 24.9375,25.851327 24.9375,25.5 C 24.9375,23.844 23.159499,22.5 20.96875,22.5 z "
+       id="path3698" />
+    <g
+       id="g3927"
+       transform="matrix(0.9659258,0.258819,-0.258819,0.9659258,9.180442,-11.349362)">
+      <g
+         transform="translate(-2,20)"
+         id="g3700">
+        <path
+           id="path3702"
+           transform="translate(0,-20)"
+           d="M 32.5,6.5 C 30.292236,6.5 28.5,7.172 28.5,8 L 28.47473,26.250876 L 36.5,25.5 C 36.499786,18.95289 36.5,11.439678 36.5,8 C 36.5,7.172 34.707764,6.5 32.5,6.5 z "
+           style="opacity:1;color:#000000;fill:url(#linearGradient3934);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           sodipodi:nodetypes="ccccsc" />
+        <path
+           sodipodi:type="arc"
+           style="opacity:1;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient3936);stroke-width:1.11240149;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           id="path3704"
+           sodipodi:cx="32.504814"
+           sodipodi:cy="8.2694378"
+           sodipodi:rx="3.9995728"
+           sodipodi:ry="1.8561553"
+           d="M 36.504387 8.2694378 A 3.9995728 1.8561553 0 1 1  28.505241,8.2694378 A 3.9995728 1.8561553 0 1 1  36.504387 8.2694378 z"
+           transform="matrix(1,0,0,0.808122,0,-18.682714)" />
+        <path
+           style="opacity:0.52873565;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+           d="M 36.504387,-4.999999 C 36.504387,-4.171999 34.712578,-3.5 32.504814,-3.5 C 30.29705,-3.5 28.505241,-4.171999 28.505241,-4.999999"
+           id="path3706"
+           sodipodi:nodetypes="csc" />
+      </g>
+      <path
+         id="path3708"
+         d="M 30.5,7.5 C 29.496989,7.5 28.599735,7.661827 28.03125,7.875 C 27.765957,7.974481 27.579146,8.061242 27.5,8.125 L 27.5,25.5 L 33.5,25.5 C 33.499542,19.102534 33.499949,11.605311 33.5,8.125 C 33.420854,8.061242 33.234043,7.974481 32.96875,7.875 C 32.400265,7.661827 31.503011,7.5 30.5,7.5 z "
+         style="opacity:0.81226059;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3944);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+    </g>
+    <path
+       style="opacity:1;color:#000000;fill:#75507b;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2392);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       d="M 11.5,15.671875 L 10.5,21.5 L 10.5,26.5 L 14.5,26.5 L 14.5,15.671875 L 13.75,15.5 L 13,15.5 L 12.25,15.5 L 11.5,15.671875 z "
+       id="path3718"
+       sodipodi:nodetypes="ccccccccc" />
+    <path
+       style="color:#000000;fill:url(#linearGradient3750);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       d="M 12.25,16 L 11.9375,16.0625 L 11,21.5 L 11.015625,21.34375 L 11.015625,26.78125 L 13.015625,26.773437 L 13,21.498673 L 14,16.0625 L 13.75,16 L 13,16 L 12.25,16 z "
+       id="path3720"
+       sodipodi:nodetypes="ccccccccccc" />
+    <g
+       id="g2417"
+       transform="translate(0,1)">
+      <path
+         sodipodi:nodetypes="ccccccccc"
+         id="path2387"
+         d="M 14.5,14.671875 L 13.5,20.5 L 13.5,25.5 L 17.5,25.5 L 17.5,14.671875 L 16.75,14.5 L 16,14.5 L 15.25,14.5 L 14.5,14.671875 z "
+         style="opacity:1;color:#000000;fill:#5c3566;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2400);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         sodipodi:nodetypes="ccccccccccc"
+         id="path2391"
+         d="M 15.25,15 L 14.9375,15.0625 L 14,20.5 L 14.015625,20.34375 L 14.015625,25.78125 L 16.015625,25.773437 L 16,20.498673 L 17,15.0625 L 16.75,15 L 16,15 L 15.25,15 z "
+         style="color:#000000;fill:url(#linearGradient2403);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         sodipodi:nodetypes="cccccccc"
+         id="path2393"
+         d="M 15.25,15 L 14.9375,15.0625 L 14,20.5 L 16,20.498673 L 17,15.0625 L 16.75,15 L 16,15 L 15.25,15 z "
+         style="color:#000000;fill:url(#linearGradient2405);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path2395"
+         d="M 15.6875,17.5 L 15.3125,20.5 L 15.40625,25.78125 L 15.46875,20.5 L 15.6875,17.5 z "
+         style="opacity:0.31800764;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         id="path2397"
+         d="M 15.3125,15.03125 L 14.3125,20.5 L 14.40625,25.78125 L 14.46875,20.5 L 15.3125,15.03125 z "
+         style="opacity:0.26819925;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path2399"
+         d="M 15.15625,18.4375 L 14.875,20.5 L 14.984375,24.609375 L 15.03125,20.5 L 15.15625,18.4375 z "
+         style="opacity:0.51340996;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    </g>
+    <path
+       style="color:#000000;fill:url(#linearGradient3752);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       d="M 12.25,16 L 11.9375,16.0625 L 11,21.5 L 13,21.498673 L 14,16.0625 L 13.75,16 L 13,16 L 12.25,16 z "
+       id="path3722"
+       sodipodi:nodetypes="cccccccc" />
+    <path
+       style="opacity:0.31800764;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 12.6875,18.5 L 12.3125,21.5 L 12.40625,26.78125 L 12.46875,21.5 L 12.6875,18.5 z "
+       id="path3951"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       style="opacity:0.26819925;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 12.3125,16.03125 L 11.3125,21.5 L 11.40625,26.78125 L 11.46875,21.5 L 12.3125,16.03125 z "
+       id="path3948" />
+    <g
+       id="g2371"
+       transform="matrix(0.9659258,-0.258819,0.258819,0.9659258,-0.3160868,6.8029688)">
+      <path
+         style="opacity:1;color:#000000;fill:#75507b;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2390);stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="M 19.75,15 L 19.03125,15.1875 L 18.28125,15.40625 L 17.625,15.75 L 18.15625,21.65625 L 19.109375,25.09375 L 23.234375,25.09375 L 20.6875,15.6875 C 20.446816,14.967169 20.013567,14.985925 19.75,15 z "
+         transform="matrix(0.9659259,0.258819,-0.258819,0.9659259,1.5651722,-5.1030033)"
+         id="path3724"
+         sodipodi:nodetypes="ccccccccc" />
+      <path
+         style="color:#000000;fill:url(#linearGradient2379);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="M 20.125,15.46875 L 19.875,15.5 L 19.15625,15.6875 L 18.40625,15.875 L 18.125,16.03125 L 18.625,21.34375 L 19.71875,25.5 L 21.78125,25.5 L 20.71875,20.96875 L 20.125,15.46875 z "
+         transform="matrix(0.9659259,0.258819,-0.258819,0.9659259,1.5651722,-5.1030033)"
+         id="path3726" />
+      <path
+         sodipodi:nodetypes="cccccccc"
+         id="path3732"
+         d="M 15.25,15 L 14.9375,15.0625 L 14,20.5 L 16.163058,20.493836 L 17,15.0625 L 16.75,15 L 16,15 L 15.25,15 z "
+         style="color:#000000;fill:url(#linearGradient2381);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3955"
+         d="M 15.8125,17.78125 L 15.46875,20.5 L 15.549362,24.985096 L 15.625,20.5 L 15.8125,17.78125 z "
+         style="opacity:0.31800764;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3957"
+         d="M 14.573995,19.358831 L 14.3125,20.5 L 14.428658,22.196139 L 14.46875,20.5 L 14.573995,19.358831 z "
+         style="opacity:0.49425288;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3959"
+         d="M 15.802067,15.219871 L 14.875,20.5 L 14.984375,24.609375 L 15.03125,20.5 L 15.802067,15.219871 z "
+         style="opacity:0.31800764;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+    </g>
+    <path
+       style="opacity:0.51340996;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="M 12.15625,19.4375 L 11.875,21.5 L 11.984375,25.609375 L 12.03125,21.5 L 12.15625,19.4375 z "
+       id="path3953"
+       sodipodi:nodetypes="ccccc" />
+    <g
+       id="g2433"
+       transform="translate(0,1)">
+      <path
+         sodipodi:nodetypes="ccccccc"
+         id="path3710"
+         d="M 26.1875,19.5 C 25.248424,19.5 24.5,20.248425 24.5,21.1875 L 24.5,25.5 L 36.5,25.5 L 36.5,21.1875 C 36.5,20.248424 35.751576,19.5 34.8125,19.5 L 26.1875,19.5 z "
+         style="opacity:1;color:#000000;fill:#8ae234;fill-opacity:1;fill-rule:nonzero;stroke:#4e9a06;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <rect
+         y="22"
+         x="25"
+         height="4"
+         width="11"
+         id="rect3712"
+         style="opacity:0.62452105;color:#000000;fill:#c17d11;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+      <path
+         style="opacity:0.29501917;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3746);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         d="M 26.1875,20.5 C 25.786622,20.5 25.5,20.786623 25.5,21.1875 L 25.5,25.5 L 35.5,25.5 L 35.5,21.1875 C 35.5,20.786621 35.213379,20.5 34.8125,20.5 L 26.1875,20.5 z "
+         id="path3714"
+         sodipodi:nodetypes="ccccccc" />
+      <rect
+         ry="0"
+         rx="0"
+         y="22"
+         x="25"
+         height="1"
+         width="11"
+         id="rect3716"
+         style="opacity:1;color:#000000;fill:url(#radialGradient2439);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+    </g>
+    <rect
+       style="opacity:1;color:#000000;fill:#fcf3e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect3728"
+       width="31"
+       height="1.0883883"
+       x="8"
+       y="26"
+       rx="0.5"
+       ry="0.54419416" />
+    <path
+       sodipodi:type="inkscape:offset"
+       inkscape:radius="-0.5"
+       inkscape:original="M 11.78125 19 C 11.367 19 11.234304 19.070411 11.125 19.15625 C 11.015696 19.242089 10.873873 19.423275 10.75 19.78125 L 9.125 25 L 37.8125 25 L 36.15625 19.96875 C 35.947593 19.450065 35.798273 19.282879 35.65625 19.1875 C 35.514227 19.092121 35.297418 19 34.8125 19 L 11.78125 19 z "
+       style="opacity:0.15;color:#000000;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3756);stroke-width:1.00000083;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible"
+       id="path3730"
+       d="M 11.78125,19.5 C 11.602454,19.5 11.502305,19.52161 11.46875,19.53125 C 11.435195,19.54089 11.467082,19.539268 11.4375,19.5625 C 11.431757,19.56701 11.321106,19.641707 11.21875,19.9375 L 9.8125,24.5 L 37.125,24.5 L 35.6875,20.15625 L 35.6875,20.125 C 35.513562,19.703318 35.424965,19.627305 35.375,19.59375 C 35.304793,19.546601 35.234094,19.5 34.8125,19.5 L 11.78125,19.5 z "
+       transform="translate(0,1)" />
+  </g>
+</svg>
diff --git a/app-manager/resources.rc.in b/app-manager/resources.rc.in
new file mode 100644 (file)
index 0000000..470304c
--- /dev/null
@@ -0,0 +1,32 @@
+#include <winver.h>
+
+MAINICON ICON "app-manager.ico"
+
+VS_VERSION_INFO VERSIONINFO
+    FILEVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+      @PLOVER_MICRO_VERSION@,0
+    PRODUCTVERSION @PLOVER_MAJOR_VERSION@,@PLOVER_MINOR_VERSION@,
+      @PLOVER_MICRO_VERSION@,0
+    FILEOS VOS__WINDOWS32
+    FILETYPE VFT_APP
+    {
+       BLOCK "StringFileInfo"
+       {
+           BLOCK "080904B0"
+           {
+               VALUE "CompanyName","The plover development team"
+               VALUE "FileDescription","Application Manager"
+               VALUE "FileVersion","@PACKAGE_VERSION@"
+               VALUE "InternalName","app-manager"
+               VALUE "LegalCopyright",
+                 "Copyright © 2010 J. Ali Harlow et al"
+               VALUE "OriginalFilename","app-manager.exe"
+               VALUE "ProductName","plover"
+               VALUE "ProductVersion","@PACKAGE_VERSION@"
+           }
+       }
+       BLOCK "VarFileInfo"
+       {
+           VALUE "Translation",0x809,0x4B0
+       }
+    }
index a336c3e..854481e 100644 (file)
@@ -9,10 +9,14 @@ AC_CONFIG_HEADER([config.h])
 AC_CONFIG_FILES([Makefile
 plover/Makefile
 plover/plover.pc
+plover-gtk/Makefile
+plover-gtk/plover-gtk.pc
 setup/Makefile
 setup/resources.rc
 update/Makefile
 update/resources.rc
+app-manager/Makefile
+app-manager/resources.rc
 ])
 AM_INIT_AUTOMAKE(no-define)
 case $VERSION in
@@ -43,12 +47,19 @@ esac
 #   increment CURRENT and set AGE and REVISION to 0.
 # - If the interface is the same as the previous version, increment REVISION.
 #
-LT_CURRENT=0
-LT_REVISION=1
-LT_AGE=0
-AC_SUBST(LT_CURRENT)
-AC_SUBST(LT_REVISION)
-AC_SUBST(LT_AGE)
+lt_current=0
+lt_revision=1
+lt_age=0
+LIBPLOVER_LT_VERSION_INFO="$lt_current:$lt_revision:$lt_age"
+AC_SUBST(LIBPLOVER_LT_VERSION_INFO)
+
+# and likewise for plover-gtk.
+#
+lt_current=0
+lt_revision=0
+lt_age=0
+PLOVER_GTK_LT_VERSION_INFO="$lt_current:$lt_revision:$lt_age"
+AC_SUBST(PLOVER_GTK_LT_VERSION_INFO)
 
 ##################################################
 # Checks for programs.
@@ -75,10 +86,21 @@ AC_HEADER_STDC
 PKG_CHECK_MODULES(RAZOR,[razor >= 0.2],[:],[RAZOR_LIBS=-lrazor])
 PKG_CHECK_MODULES(EXPAT,[expat],[:],[EXPAT_LIBS=-lexpat])
 PKG_CHECK_MODULES(ZLIB,[zlib],[:],[ZLIB_LIBS=-lz])
+PKG_CHECK_MODULES(GIO,[gio-2.0])
+PKG_CHECK_MODULES(GTK,[gtk+-2.0])
+PKG_CHECK_MODULES(GMODULE_EXPORT,[gmodule-export-2.0])
 LIBPLOVER_CFLAGS="$RAZOR_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS"
 LIBPLOVER_LIBS="$RAZOR_LIBS $EXPAT_LIBS $ZLIB_LIBS"
 AC_SUBST(LIBPLOVER_CFLAGS)
 AC_SUBST(LIBPLOVER_LIBS)
+PLOVER_GTK_CFLAGS="$GTK_CFLAGS $RAZOR_CFLAGS"
+PLOVER_GTK_LIBS="$GTK_LIBS $RAZOR_LIBS"
+AC_SUBST(PLOVER_GTK_CFLAGS)
+AC_SUBST(PLOVER_GTK_LIBS)
+GUI_CFLAGS="$GMODULE_EXPORT_CFLAGS $GIO_CFLAGS $PLOVER_GTK_CFLAGS $LIBPLOVER_CFLAGS"
+GUI_LIBS="$GMODULE_EXPORT_LIBS $GIO_LIBS $PLOVER_GTK_LIBS $LIBPLOVER_LIBS"
+AC_SUBST(GUI_CFLAGS)
+AC_SUBST(GUI_LIBS)
 save_PKG_CONFIG="$PKG_CONFIG"
 PKG_CONFIG="$PKG_CONFIG --static"
 PKG_CHECK_MODULES(SETUP,[whelk])
diff --git a/plover-gtk/Makefile.am b/plover-gtk/Makefile.am
new file mode 100644 (file)
index 0000000..4d41f41
--- /dev/null
@@ -0,0 +1,15 @@
+AM_CFLAGS=-g $(PLOVER_GTK_CFLAGS)
+LIBS=$(PLOVER_GTK_LIBS)
+INCLUDES=-I$(top_srcdir)
+LDFLAGS=-no-undefined -version-info $(PLOVER_GTK_LT_VERSION_INFO)
+
+pkginclude_HEADERS=error.h package.h packageset.h packagestore.h \
+               packagefilestore.h
+
+lib_LTLIBRARIES=libplover-gtk.la
+libplover_gtk_la_SOURCES=$(pkginclude_HEADERS) \
+               error.c package.c packageset.c packagestore.c \
+               packagefilestore.c
+
+pkgconfigdir=$(libdir)/pkgconfig
+pkgconfig_DATA=plover-gtk.pc
diff --git a/plover-gtk/error.c b/plover-gtk/error.c
new file mode 100644 (file)
index 0000000..237d39a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <glib.h>
+
+GQuark plover_razor_error_quark(void)
+{
+    static GQuark quark=0;
+    if (!quark)
+       quark=g_quark_from_static_string("plover-razor-error-quark");
+    return quark;
+}
+
diff --git a/plover-gtk/error.h b/plover-gtk/error.h
new file mode 100644 (file)
index 0000000..9e7800f
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __PLOVER_ERROR_H__
+#define __PLOVER_ERROR_H__
+
+#define PLOVER_RAZOR_ERROR     plover_razor_error_quark()
+
+typedef enum {
+    PLOVER_RAZOR_ERROR_FAILED
+} PloverRazorError;
+
+#endif /* __PLOVER_ERROR_H__ */
+
diff --git a/plover-gtk/package.c b/plover-gtk/package.c
new file mode 100644 (file)
index 0000000..e3ea09e
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib-object.h>
+#include <razor.h>
+#include "plover-gtk/package.h"
+
+G_DEFINE_TYPE(PloverPackage,plover_package,G_TYPE_OBJECT);
+
+typedef struct _PloverPackagePrivate {
+    struct razor_set *set;
+    struct razor_package *pkg;
+    PloverPackageFileStore *file_store;
+} PloverPackagePrivate;
+
+#define PLOVER_PACKAGE_GET_PRIVATE(obj)\
+                               G_TYPE_INSTANCE_GET_PRIVATE(obj,\
+                                 PLOVER_TYPE_PACKAGE,PloverPackagePrivate)
+
+enum {
+    CHANGED=0,
+    N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+static void plover_package_dispose(GObject *obj)
+{
+    PloverPackagePrivate *priv=PLOVER_PACKAGE_GET_PRIVATE(obj);
+    if (priv->file_store)
+    {
+       g_object_unref(priv->file_store);
+       priv->file_store=NULL;
+    }
+    if (G_OBJECT_CLASS(plover_package_parent_class)->dispose)
+       G_OBJECT_CLASS(plover_package_parent_class)->dispose(obj);
+}
+
+static void plover_package_class_init(PloverPackageClass *klass)
+{
+    GObjectClass *oclass=G_OBJECT_CLASS(klass);
+    oclass->dispose=plover_package_dispose;
+    g_type_class_add_private(klass,sizeof(PloverPackagePrivate));
+    signals[CHANGED]=g_signal_newv("changed",
+      G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
+      g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
+}
+
+static void plover_package_init(PloverPackage *package)
+{
+}
+
+PloverPackage *plover_package_new(struct razor_set *set,
+  struct razor_package *pkg)
+{
+    PloverPackage *package;
+    PloverPackagePrivate *priv;
+    package=g_object_new(PLOVER_TYPE_PACKAGE,NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    priv->set=set;
+    priv->pkg=pkg;
+    return package;
+}
+
+const char *plover_package_get_name(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    const char *name;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_NAME,&name,
+      RAZOR_DETAIL_LAST);
+    return name;
+}
+
+const char *plover_package_get_summary(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    const char *summary;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_SUMMARY,&summary,
+      RAZOR_DETAIL_LAST);
+    return summary;
+}
+
+const char *plover_package_get_version(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    const char *version;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_VERSION,&version,
+      RAZOR_DETAIL_LAST);
+    return version;
+}
+
+const char *plover_package_get_license(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    const char *license;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_LICENSE,&license,
+      RAZOR_DETAIL_LAST);
+    return license;
+}
+
+const char *plover_package_get_arch(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    const char *arch;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_ARCH,&arch,
+      RAZOR_DETAIL_LAST);
+    return arch;
+}
+
+const char *plover_package_get_description(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    const char *description;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_DESCRIPTION,
+      &description,RAZOR_DETAIL_LAST);
+    return description;
+}
+
+const char *plover_package_get_URL(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    const char *URL;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    razor_package_get_details(priv->set,priv->pkg,RAZOR_DETAIL_URL,&URL,
+      RAZOR_DETAIL_LAST);
+    return URL;
+}
+
+GdkPixbuf *plover_package_get_icon(PloverPackage *package)
+{
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    return NULL;
+}
+
+PloverPackageFileStore *plover_package_get_file_store(PloverPackage *package)
+{
+    PloverPackagePrivate *priv;
+    struct razor_file_iterator *iter;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE(package),NULL);
+    priv=PLOVER_PACKAGE_GET_PRIVATE(package);
+    if (!priv->file_store)
+    {
+       iter=razor_file_iterator_create(priv->set,priv->pkg,0);
+       priv->file_store=plover_package_file_store_new(iter);
+       razor_file_iterator_destroy(iter);
+    }
+    return priv->file_store;
+}
diff --git a/plover-gtk/package.h b/plover-gtk/package.h
new file mode 100644 (file)
index 0000000..23bbff5
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __PLOVER_PACKAGE_H__
+#define __PLOVER_PACKAGE_H__
+
+#include <razor.h>
+#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <plover-gtk/packageset.h>
+#include <plover-gtk/packagefilestore.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_PACKAGE    plover_package_get_type()
+#define PLOVER_PACKAGE(obj)    G_TYPE_CHECK_INSTANCE_CAST(obj,\
+                                 PLOVER_TYPE_PACKAGE,PloverPackage)
+#define PLOVER_PACKAGE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_CAST(klass,\
+                                 PLOVER_TYPE_PACKAGE,PloverPackageClass)
+#define PLOVER_IS_PACKAGE(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE)
+#define PLOVER_IS_PACKAGE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE)
+#define PLOVER_PACKAGE_GET_CLASS(obj)\
+                               G_TYPE_INSTANCE_GET_CLASS(obj,\
+                                 PLOVER_TYPE_PACKAGE,PloverPackageClass)
+
+typedef struct _PloverPackage {
+    GObject parent_instance;
+} PloverPackage;
+
+typedef struct _PloverPackageClass {
+    GObjectClass parent_class;
+} PloverPackageClass;
+
+GType plover_package_get_type(void) G_GNUC_CONST;
+PloverPackage *plover_package_new(struct razor_set *set,
+  struct razor_package *pkg);
+const char *plover_package_get_name(PloverPackage *package);
+const char *plover_package_get_summary(PloverPackage *package);
+const char *plover_package_get_version(PloverPackage *package);
+const char *plover_package_get_license(PloverPackage *package);
+const char *plover_package_get_arch(PloverPackage *package);
+const char *plover_package_get_description(PloverPackage *package);
+const char *plover_package_get_URL(PloverPackage *package);
+GdkPixbuf *plover_package_get_icon(PloverPackage *package);
+PloverPackageFileStore *plover_package_get_file_store(PloverPackage *package);
+
+G_END_DECLS
+
+#endif /* __PLOVER_PACKAGE_H__ */
diff --git a/plover-gtk/packagefilestore.c b/plover-gtk/packagefilestore.c
new file mode 100644 (file)
index 0000000..d119555
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "plover-gtk/packagefilestore.h"
+
+#define VALID_ITER(iter,store) ((iter) && (iter)->user_data && \
+       PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(store)->stamp==(iter)->stamp && \
+       !g_sequence_iter_is_end((iter)->user_data) && \
+       g_sequence_iter_get_sequence((iter)->user_data)== \
+       PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(store)->seq)
+
+static GType column_types[PLOVER_PACKAGE_FILE_STORE_NO_COLUMNS];
+
+static void plover_package_file_store_tree_model_init(GtkTreeModelIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(PloverPackageFileStore,plover_package_file_store,
+  G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
+  plover_package_file_store_tree_model_init));
+
+typedef struct _PloverPackageFileStorePrivate {
+    GSequence *seq;
+    int stamp;
+} PloverPackageFileStorePrivate;
+
+#define PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(obj)\
+                               G_TYPE_INSTANCE_GET_PRIVATE(obj,\
+                                 PLOVER_TYPE_PACKAGE_FILE_STORE,\
+                                 PloverPackageFileStorePrivate)
+
+static void plover_package_file_store_finalize(GObject *obj)
+{
+    PloverPackageFileStorePrivate *priv=
+      PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(obj);
+    g_sequence_free(priv->seq);
+    if (G_OBJECT_CLASS(plover_package_file_store_parent_class)->finalize)
+       G_OBJECT_CLASS(plover_package_file_store_parent_class)->finalize(obj);
+}
+
+static void
+  plover_package_file_store_class_init(PloverPackageFileStoreClass *klass)
+{
+    GObjectClass *oclass=G_OBJECT_CLASS(klass);
+    oclass->finalize=plover_package_file_store_finalize;
+    g_type_class_add_private(klass,sizeof(PloverPackageFileStorePrivate));
+    column_types[PLOVER_PACKAGE_FILE_STORE_NAME_COLUMN]=G_TYPE_STRING;
+}
+
+static GtkTreeModelFlags
+plover_package_file_store_get_flags(GtkTreeModel *tree_model)
+{
+    return GTK_TREE_MODEL_ITERS_PERSIST|GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint plover_package_file_store_get_n_columns(GtkTreeModel *tree_model)
+{
+    return PLOVER_PACKAGE_FILE_STORE_NO_COLUMNS;
+}
+
+static GType
+  plover_package_file_store_get_column_type(GtkTreeModel *tree_model,gint indx)
+{
+    PloverPackageFileStore *store=(PloverPackageFileStore *)tree_model;
+    g_return_val_if_fail(indx>=0 && indx<PLOVER_PACKAGE_FILE_STORE_NO_COLUMNS,
+      G_TYPE_INVALID);
+    return column_types[indx];
+}
+
+static gboolean plover_package_file_store_get_iter(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreePath *path)
+{
+    int i;
+    PloverPackageFileStorePrivate *priv;
+    PloverPackageFileStore *store=(PloverPackageFileStore *)tree_model;
+    priv=PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(store);
+    i=gtk_tree_path_get_indices(path)[0];
+    if (i>=g_sequence_get_length(priv->seq))
+       return FALSE;
+    iter->stamp=priv->stamp;
+    iter->user_data=g_sequence_get_iter_at_pos(priv->seq,i);
+    return TRUE;
+}
+
+static GtkTreePath *
+  plover_package_file_store_get_path(GtkTreeModel *tree_model,GtkTreeIter *iter)
+{
+    GtkTreePath *path;
+    g_return_val_if_fail(VALID_ITER(iter,tree_model),NULL);
+    if (g_sequence_iter_is_end(iter->user_data))
+       return NULL;
+    path=gtk_tree_path_new();
+    gtk_tree_path_append_index(path,
+      g_sequence_iter_get_position(iter->user_data));
+    return path;
+}
+
+static void plover_package_file_store_get_value(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,gint column,GValue *value)
+{
+    PloverPackageFileStore *store=(PloverPackageFileStore *)tree_model;
+    char *name;
+    g_return_if_fail(column>=0 && column<PLOVER_PACKAGE_FILE_STORE_NO_COLUMNS);
+    g_return_if_fail(VALID_ITER(iter,store));
+    name=g_sequence_get(iter->user_data);
+    g_value_init(value,column_types[column]);
+    switch((PloverPackageFileStoreColumn)column)
+    {
+       case PLOVER_PACKAGE_FILE_STORE_NAME_COLUMN:
+           g_value_set_string(value,name);
+           break;
+    }
+}
+
+static gboolean plover_package_file_store_iter_next(GtkTreeModel *tree_model,
+  GtkTreeIter *iter)
+{
+    g_return_val_if_fail(VALID_ITER(iter,tree_model),FALSE);
+    iter->user_data=g_sequence_iter_next(iter->user_data);
+    return !g_sequence_iter_is_end(iter->user_data);
+}
+
+static gboolean
+  plover_package_file_store_iter_children(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreeIter *parent)
+{
+    PloverPackageFileStorePrivate *priv;
+    PloverPackageFileStore *store=(PloverPackageFileStore *)tree_model;
+    priv=PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(tree_model);
+    /* this is a list, nodes have no children */
+    if (parent)
+       return FALSE;
+    if (g_sequence_get_length(priv->seq)>0)
+    {
+       iter->stamp=priv->stamp;
+       iter->user_data=g_sequence_get_begin_iter(priv->seq);
+       return TRUE;
+    }
+    else
+       return FALSE;
+}
+
+static gboolean
+  plover_package_file_store_iter_has_child(GtkTreeModel *tree_model,
+  GtkTreeIter *iter)
+{
+    return FALSE;
+}
+
+static gint plover_package_file_store_iter_n_children(GtkTreeModel *tree_model,
+  GtkTreeIter *iter)
+{
+    PloverPackageFileStorePrivate *priv;
+    PloverPackageFileStore *store=(PloverPackageFileStore *)tree_model;
+    priv=PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(tree_model);
+    if (!iter)
+       return g_sequence_get_length(priv->seq);
+    g_return_val_if_fail(VALID_ITER(iter,tree_model),-1);
+    return 0;
+}
+
+static gboolean
+  plover_package_file_store_iter_nth_child(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreeIter *parent,gint n)
+{
+    PloverPackageFileStorePrivate *priv;
+    PloverPackageFileStore *store=(PloverPackageFileStore *)tree_model;
+    priv=PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(tree_model);
+    GSequenceIter *child;
+    if (parent)
+       return FALSE;
+    child=g_sequence_get_iter_at_pos(priv->seq,n);
+    if (g_sequence_iter_is_end(child))
+       return FALSE;
+    iter->stamp=priv->stamp;
+    iter->user_data=child;
+    return TRUE;
+}
+
+static gboolean plover_package_file_store_iter_parent(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreeIter *child)
+{
+    return FALSE;
+}
+
+static void plover_package_file_store_tree_model_init(GtkTreeModelIface *iface)
+{
+    iface->get_flags=plover_package_file_store_get_flags;
+    iface->get_n_columns=plover_package_file_store_get_n_columns;
+    iface->get_column_type=plover_package_file_store_get_column_type;
+    iface->get_iter=plover_package_file_store_get_iter;
+    iface->get_path=plover_package_file_store_get_path;
+    iface->get_value=plover_package_file_store_get_value;
+    iface->iter_next=plover_package_file_store_iter_next;
+    iface->iter_children=plover_package_file_store_iter_children;
+    iface->iter_has_child=plover_package_file_store_iter_has_child;
+    iface->iter_n_children=plover_package_file_store_iter_n_children;
+    iface->iter_nth_child=plover_package_file_store_iter_nth_child;
+    iface->iter_parent=plover_package_file_store_iter_parent;
+}
+
+static void plover_package_file_store_init(PloverPackageFileStore *store)
+{
+    PloverPackageFileStorePrivate *priv;
+    priv=PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(store);
+    priv->seq=g_sequence_new(g_free);
+    priv->stamp=g_random_int();
+}
+
+PloverPackageFileStore *
+  plover_package_file_store_new(struct razor_file_iterator *files)
+{
+    const char *name;
+    GSequenceIter *si;
+    GtkTreeIter ti;
+    GtkTreePath *path;
+    gint *indices;
+    PloverPackageFileStore *store;
+    PloverPackageFileStorePrivate *priv;
+    store=g_object_new(PLOVER_TYPE_PACKAGE_FILE_STORE,NULL);
+    priv=PLOVER_PACKAGE_FILE_STORE_GET_PRIVATE(store);
+    path=gtk_tree_path_new();
+    gtk_tree_path_append_index(path,0);
+    indices=gtk_tree_path_get_indices(path);
+    while(razor_file_iterator_next(files,&name))
+    {
+       si=g_sequence_insert_sorted(priv->seq,g_strdup(name),g_strcmp0,NULL);
+       *indices=g_sequence_iter_get_position(si);
+       ti.stamp=priv->stamp;
+       ti.user_data=si;
+       gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti);
+    }
+    gtk_tree_path_free(path);
+    return store;
+}
diff --git a/plover-gtk/packagefilestore.h b/plover-gtk/packagefilestore.h
new file mode 100644 (file)
index 0000000..65c27c6
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef __PLOVER_PACKAGE_FILE_STORE_H__
+#define __PLOVER_PACKAGE_FILE_STORE_H__
+
+#include <glib-object.h>
+#include <razor.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_PACKAGE_FILE_STORE\
+                               plover_package_file_store_get_type()
+#define PLOVER_PACKAGE_FILE_STORE(obj)\
+                               G_TYPE_CHECK_INSTANCE_CAST(obj,\
+                                 PLOVER_TYPE_PACKAGE_FILE_STORE,\
+                                 PloverPackageFileStore)
+#define PLOVER_PACKAGE_FILE_STORE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_CAST(klass,\
+                                 PLOVER_TYPE_PACKAGE_FILE_STORE,\
+                                 PloverPackageFileStoreClass)
+#define PLOVER_IS_PACKAGE_FILE_STORE(obj)\
+                               G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE_FILE_STORE)
+#define PLOVER_IS_PACKAGE_FILE_STORE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE_FILE_STORE)
+#define PLOVER_PACKAGE_FILE_STORE_GET_CLASS(obj)\
+                               G_TYPE_INSTANCE_GET_CLASS(obj,\
+                                 PLOVER_TYPE_PACKAGE_FILE_STORE,\
+                                 PloverPackageFileStoreClass)
+
+typedef enum
+{
+    PLOVER_PACKAGE_FILE_STORE_NAME_COLUMN,
+    PLOVER_PACKAGE_FILE_STORE_NO_COLUMNS
+} PloverPackageFileStoreColumn;
+
+typedef struct _PloverPackageFileStore {
+    GObject parent_instance;
+} PloverPackageFileStore;
+
+typedef struct _PloverPackageFileStoreClass {
+    GObjectClass parent_class;
+} PloverPackageFileStoreClass;
+
+GType plover_package_file_store_get_type(void) G_GNUC_CONST;
+PloverPackageFileStore *
+  plover_package_file_store_new(struct razor_file_iterator *files);
+
+G_END_DECLS
+
+#endif /* __PLOVER_PACKAGE_FILE_STORE_H__ */
diff --git a/plover-gtk/packageset.c b/plover-gtk/packageset.c
new file mode 100644 (file)
index 0000000..29b65aa
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <glib-object.h>
+#include <razor.h>
+#include "plover/plover.h"
+#include "plover-gtk/error.h"
+#include "plover-gtk/packageset.h"
+#include "plover-gtk/package.h"
+
+G_DEFINE_TYPE(PloverPackageSet,plover_package_set,G_TYPE_OBJECT);
+
+typedef struct _PloverPackageSetPrivate {
+    struct razor_root *root;
+    struct razor_set *set;
+    GSList *packages;
+} PloverPackageSetPrivate;
+
+#define PLOVER_PACKAGE_SET_GET_PRIVATE(obj)\
+                               G_TYPE_INSTANCE_GET_PRIVATE(obj,\
+                                 PLOVER_TYPE_PACKAGE_SET,\
+                                 PloverPackageSetPrivate)
+
+enum {
+    CHANGED=0,
+    N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+static void plover_package_set_finalize(GObject *obj)
+{
+    PloverPackageSetPrivate *priv=PLOVER_PACKAGE_SET_GET_PRIVATE(obj);
+    if (priv->root)
+    {
+       /* priv->set, if set, is owned by priv->root and should not
+        * be destroyed.
+        */
+       razor_root_close(priv->root);
+    }
+    else if (priv->set)
+       razor_set_destroy(priv->set);
+    if (G_OBJECT_CLASS(plover_package_set_parent_class)->finalize)
+       G_OBJECT_CLASS(plover_package_set_parent_class)->finalize(obj);
+}
+
+static void plover_package_set_dispose(GObject *obj)
+{
+    PloverPackageSetPrivate *priv=PLOVER_PACKAGE_SET_GET_PRIVATE(obj);
+    if (G_OBJECT_CLASS(plover_package_set_parent_class)->dispose)
+       G_OBJECT_CLASS(plover_package_set_parent_class)->dispose(obj);
+}
+
+static void plover_package_set_class_init(PloverPackageSetClass *klass)
+{
+    GObjectClass *oclass=G_OBJECT_CLASS(klass);
+    oclass->finalize=plover_package_set_finalize;
+    oclass->dispose=plover_package_set_dispose;
+    g_type_class_add_private(klass,sizeof(PloverPackageSetPrivate));
+    signals[CHANGED]=g_signal_newv("changed",
+      G_TYPE_FROM_CLASS(klass),G_SIGNAL_RUN_LAST,NULL,NULL,NULL,
+      g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0,NULL);
+}
+
+static void plover_package_set_init(PloverPackageSet *set)
+{
+}
+
+PloverPackageSet *plover_package_set_new(void)
+{
+    return g_object_new(PLOVER_TYPE_PACKAGE_SET,NULL);
+}
+
+PloverPackageSet *plover_package_set_new_from_installed(const char *root,
+  GError **err)
+{
+    PloverPackageSet *set;
+    PloverPackageSetPrivate *priv;
+    set=plover_package_set_new();
+    priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+    priv->root=razor_root_open(root);
+    if (!priv->root)
+    {
+       g_set_error(err,PLOVER_RAZOR_ERROR,PLOVER_RAZOR_ERROR_FAILED,
+         "Failed to open %s as razor root",root);
+       g_object_unref(set);
+       return NULL;
+    }
+    priv->set=razor_root_get_system_set(priv->root);
+    if (!priv->set)
+    {
+       g_set_error(err,PLOVER_RAZOR_ERROR,PLOVER_RAZOR_ERROR_FAILED,
+         "Failed to get system set from %s",root);
+       g_object_unref(set);
+       return NULL;
+    }
+    return set;
+}
+
+PloverPackageSet *plover_package_set_new_from_repository(const char *base,
+  GError **err)
+{
+    int fd;
+    gchar *s;
+    PloverPackageSet *set;
+    PloverPackageSetPrivate *priv;
+    set=plover_package_set_new();
+    priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+    fd=open(".",O_RDONLY);
+    s=g_build_filename(base,"repodata",NULL);
+    if (chdir(s)<0)
+    {
+       g_set_error(err,G_FILE_ERROR,g_file_error_from_errno(errno),
+         "%s: %s",s,g_strerror(errno));
+       g_object_unref(set);
+       return NULL;
+    }
+    g_free(s);
+    priv->set=plover_razor_set_create_from_yum("..");
+    fchdir(fd);
+    close(fd);
+    if (!priv->set)
+    {
+       g_set_error(err,PLOVER_RAZOR_ERROR,PLOVER_RAZOR_ERROR_FAILED,
+         "Failed to create package set from repository %s",base);
+       g_object_unref(set);
+       return NULL;
+    }
+    return set;
+}
+
+GSList *plover_package_set_get_packages(PloverPackageSet *set)
+{
+    struct razor_package_iterator *iter;
+    struct razor_package *pkg;
+    PloverPackageSetPrivate *priv;
+    PloverPackage *package;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
+    priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
+    if (priv->set && !priv->packages)
+    {
+       iter=razor_package_iterator_create(priv->set);
+       while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_LAST))
+       {
+           package=plover_package_new(priv->set,pkg);
+           priv->packages=g_slist_prepend(priv->packages,package);
+       }
+       razor_package_iterator_destroy(iter);
+    }
+    return priv->packages;
+}
diff --git a/plover-gtk/packageset.h b/plover-gtk/packageset.h
new file mode 100644 (file)
index 0000000..e3e8ecf
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef __PLOVER_PACKAGE_SET_H__
+#define __PLOVER_PACKAGE_SET_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_PACKAGE_SET        plover_package_set_get_type()
+#define PLOVER_PACKAGE_SET(obj)        G_TYPE_CHECK_INSTANCE_CAST(obj,\
+                                 PLOVER_TYPE_PACKAGE_SET,PloverPackageSet)
+#define PLOVER_PACKAGE_SET_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_CAST(klass,\
+                                 PLOVER_TYPE_PACKAGE_SET,\
+                                 PloverPackageSetClass)
+#define PLOVER_IS_PACKAGE_SET(obj)\
+                               G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE_SET)
+#define PLOVER_IS_PACKAGE_SET_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE_SET)
+#define PLOVER_PACKAGE_SET_GET_CLASS(obj)\
+                               G_TYPE_INSTANCE_GET_CLASS(obj,\
+                                 PLOVER_TYPE_PACKAGE_SET,\
+                                 PloverPackageSetClass)
+
+typedef struct _PloverPackageSet {
+    GObject parent_instance;
+} PloverPackageSet;
+
+typedef struct _PloverPackageSetClass {
+    GObjectClass parent_class;
+} PloverPackageSetClass;
+
+GType plover_package_set_get_type(void) G_GNUC_CONST;
+PloverPackageSet *plover_package_set_new(void);
+PloverPackageSet *plover_package_set_new_from_installed(const char *root,
+  GError **err);
+PloverPackageSet *plover_package_set_new_from_repository(const char *base,
+  GError **err);
+GSList *plover_package_set_get_packages(PloverPackageSet *set);
+
+G_END_DECLS
+
+#endif /* __PLOVER_PACKAGE_SET_H__ */
diff --git a/plover-gtk/packagestore.c b/plover-gtk/packagestore.c
new file mode 100644 (file)
index 0000000..408964c
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
+ * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <string.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <razor.h>
+#include "plover/plover.h"
+#include "plover-gtk/package.h"
+#include "plover-gtk/packagestore.h"
+
+#define VALID_ITER(iter,store) ((iter) && (iter)->user_data && \
+       PLOVER_PACKAGE_STORE_GET_PRIVATE(store)->stamp==(iter)->stamp && \
+       !g_sequence_iter_is_end((iter)->user_data) && \
+       g_sequence_iter_get_sequence((iter)->user_data)== \
+       PLOVER_PACKAGE_STORE_GET_PRIVATE(store)->seq)
+
+static GType column_types[PLOVER_PACKAGE_STORE_NO_COLUMNS];
+
+static void plover_package_store_tree_model_init(GtkTreeModelIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(PloverPackageStore,plover_package_store,G_TYPE_OBJECT,
+  G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
+  plover_package_store_tree_model_init));
+
+typedef struct _PloverPackageStorePrivate {
+    GSList *sets;
+    GSequence *seq;
+    int stamp;
+} PloverPackageStorePrivate;
+
+#define PLOVER_PACKAGE_STORE_GET_PRIVATE(obj)\
+                               G_TYPE_INSTANCE_GET_PRIVATE(obj,\
+                                 PLOVER_TYPE_PACKAGE_STORE,\
+                                 PloverPackageStorePrivate)
+
+static void plover_package_store_finalize(GObject *obj)
+{
+    PloverPackageStorePrivate *priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(obj);
+    g_sequence_free(priv->seq);
+    if (G_OBJECT_CLASS(plover_package_store_parent_class)->finalize)
+       G_OBJECT_CLASS(plover_package_store_parent_class)->finalize(obj);
+}
+
+static void plover_package_store_dispose(GObject *obj)
+{
+    PloverPackageStorePrivate *priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(obj);
+    g_slist_foreach(priv->sets,(GFunc)g_object_unref,NULL);
+    g_slist_free(priv->sets);
+    priv->sets=NULL;
+    g_sequence_free(priv->seq);
+    priv->seq=g_sequence_new(NULL);
+    if (G_OBJECT_CLASS(plover_package_store_parent_class)->dispose)
+       G_OBJECT_CLASS(plover_package_store_parent_class)->dispose(obj);
+}
+
+static void plover_package_store_class_init(PloverPackageStoreClass *klass)
+{
+    GObjectClass *oclass=G_OBJECT_CLASS(klass);
+    oclass->finalize=plover_package_store_finalize;
+    oclass->dispose=plover_package_store_dispose;
+    g_type_class_add_private(klass,sizeof(PloverPackageStorePrivate));
+    column_types[PLOVER_PACKAGE_STORE_OBJ_COLUMN]=PLOVER_TYPE_PACKAGE;
+    column_types[PLOVER_PACKAGE_STORE_INSTALLED_COLUMN]=G_TYPE_BOOLEAN;
+    column_types[PLOVER_PACKAGE_STORE_ICON_COLUMN]=GDK_TYPE_PIXBUF;
+    column_types[PLOVER_PACKAGE_STORE_NAME_COLUMN]=G_TYPE_STRING;
+    column_types[PLOVER_PACKAGE_STORE_VERSION_COLUMN]=G_TYPE_STRING;
+    column_types[PLOVER_PACKAGE_STORE_SUMMARY_COLUMN]=G_TYPE_STRING;
+}
+
+static GtkTreeModelFlags
+plover_package_store_get_flags(GtkTreeModel *tree_model)
+{
+    return GTK_TREE_MODEL_ITERS_PERSIST|GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint plover_package_store_get_n_columns(GtkTreeModel *tree_model)
+{
+    return PLOVER_PACKAGE_STORE_NO_COLUMNS;
+}
+
+static GType
+  plover_package_store_get_column_type(GtkTreeModel *tree_model,gint indx)
+{
+    PloverPackageStore *store=(PloverPackageStore *)tree_model;
+    g_return_val_if_fail(indx>=0 && indx<PLOVER_PACKAGE_STORE_NO_COLUMNS,
+      G_TYPE_INVALID);
+    return column_types[indx];
+}
+
+static gboolean plover_package_store_get_iter(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreePath *path)
+{
+    int i;
+    PloverPackageStorePrivate *priv;
+    PloverPackageStore *store=(PloverPackageStore *)tree_model;
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
+    i=gtk_tree_path_get_indices(path)[0];
+    if (i>=g_sequence_get_length(priv->seq))
+       return FALSE;
+    iter->stamp=priv->stamp;
+    iter->user_data=g_sequence_get_iter_at_pos(priv->seq,i);
+    return TRUE;
+}
+
+static GtkTreePath *
+  plover_package_store_get_path(GtkTreeModel *tree_model,GtkTreeIter *iter)
+{
+    GtkTreePath *path;
+    g_return_val_if_fail(VALID_ITER(iter,tree_model),NULL);
+    if (g_sequence_iter_is_end(iter->user_data))
+       return NULL;
+    path=gtk_tree_path_new();
+    gtk_tree_path_append_index(path,
+      g_sequence_iter_get_position(iter->user_data));
+    return path;
+}
+
+static void plover_package_store_get_value(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,gint column,GValue *value)
+{
+    PloverPackageStore *store=(PloverPackageStore *)tree_model;
+    PloverPackage *package;
+    g_return_if_fail(column>=0 && column<PLOVER_PACKAGE_STORE_NO_COLUMNS);
+    g_return_if_fail(VALID_ITER(iter,store));
+    package=g_sequence_get(iter->user_data);
+    g_value_init(value,column_types[column]);
+    switch((PloverPackageStoreColumn)column)
+    {
+       case PLOVER_PACKAGE_STORE_OBJ_COLUMN:
+           g_value_set_object(value,package);
+           break;
+       case PLOVER_PACKAGE_STORE_INSTALLED_COLUMN:
+           break;
+       case PLOVER_PACKAGE_STORE_ICON_COLUMN:
+           g_value_set_object(value,plover_package_get_icon(package));
+           break;
+       case PLOVER_PACKAGE_STORE_NAME_COLUMN:
+           g_value_set_string(value,plover_package_get_name(package));
+           break;
+       case PLOVER_PACKAGE_STORE_VERSION_COLUMN:
+           g_value_set_string(value,plover_package_get_version(package));
+           break;
+       case PLOVER_PACKAGE_STORE_SUMMARY_COLUMN:
+           g_value_set_string(value,plover_package_get_summary(package));
+           break;
+    }
+}
+
+static gboolean
+  plover_package_store_iter_next(GtkTreeModel *tree_model,GtkTreeIter *iter)
+{
+    g_return_val_if_fail(VALID_ITER(iter,tree_model),FALSE);
+    iter->user_data=g_sequence_iter_next(iter->user_data);
+    return !g_sequence_iter_is_end(iter->user_data);
+}
+
+static gboolean plover_package_store_iter_children(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreeIter *parent)
+{
+    PloverPackageStorePrivate *priv;
+    PloverPackageStore *store=(PloverPackageStore *)tree_model;
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(tree_model);
+    /* this is a list, nodes have no children */
+    if (parent)
+       return FALSE;
+    if (g_sequence_get_length(priv->seq)>0)
+    {
+       iter->stamp=priv->stamp;
+       iter->user_data=g_sequence_get_begin_iter(priv->seq);
+       return TRUE;
+    }
+    else
+       return FALSE;
+}
+
+static gboolean plover_package_store_iter_has_child(GtkTreeModel *tree_model,
+  GtkTreeIter *iter)
+{
+    return FALSE;
+}
+
+static gint plover_package_store_iter_n_children(GtkTreeModel *tree_model,
+  GtkTreeIter *iter)
+{
+    PloverPackageStorePrivate *priv;
+    PloverPackageStore *store=(PloverPackageStore *)tree_model;
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(tree_model);
+    if (!iter)
+       return g_sequence_get_length(priv->seq);
+    g_return_val_if_fail(VALID_ITER(iter,tree_model),-1);
+    return 0;
+}
+
+static gboolean plover_package_store_iter_nth_child(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreeIter *parent,gint n)
+{
+    PloverPackageStorePrivate *priv;
+    PloverPackageStore *store=(PloverPackageStore *)tree_model;
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(tree_model);
+    GSequenceIter *child;
+    if (parent)
+       return FALSE;
+    child=g_sequence_get_iter_at_pos(priv->seq,n);
+    if (g_sequence_iter_is_end(child))
+       return FALSE;
+    iter->stamp=priv->stamp;
+    iter->user_data=child;
+    return TRUE;
+}
+
+static gboolean plover_package_store_iter_parent(GtkTreeModel *tree_model,
+  GtkTreeIter *iter,GtkTreeIter *child)
+{
+    return FALSE;
+}
+
+static void plover_package_store_tree_model_init(GtkTreeModelIface *iface)
+{
+    iface->get_flags=plover_package_store_get_flags;
+    iface->get_n_columns=plover_package_store_get_n_columns;
+    iface->get_column_type=plover_package_store_get_column_type;
+    iface->get_iter=plover_package_store_get_iter;
+    iface->get_path=plover_package_store_get_path;
+    iface->get_value=plover_package_store_get_value;
+    iface->iter_next=plover_package_store_iter_next;
+    iface->iter_children=plover_package_store_iter_children;
+    iface->iter_has_child=plover_package_store_iter_has_child;
+    iface->iter_n_children=plover_package_store_iter_n_children;
+    iface->iter_nth_child=plover_package_store_iter_nth_child;
+    iface->iter_parent=plover_package_store_iter_parent;
+}
+
+static void plover_package_store_init(PloverPackageStore *store)
+{
+    PloverPackageStorePrivate *priv;
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
+    priv->seq=g_sequence_new(NULL);
+    priv->stamp=g_random_int();
+}
+
+PloverPackageStore *plover_package_store_new(void)
+{
+    return g_object_new(PLOVER_TYPE_PACKAGE_STORE,NULL);
+}
+
+GSList *plover_package_store_get_sets(PloverPackageStore *store)
+{
+    PloverPackageStorePrivate *priv;
+    g_return_val_if_fail(PLOVER_IS_PACKAGE_STORE(store),NULL);
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
+    return priv->sets;
+}
+
+static gint
+  plover__package_compar(gconstpointer a,gconstpointer b,gpointer user_data)
+{
+    PloverPackage *pa=PLOVER_PACKAGE(a);
+    PloverPackage *pb=PLOVER_PACKAGE(b);
+    return strcmp(plover_package_get_name(pa),plover_package_get_name(pb));
+}
+
+void plover_package_store_add_set(PloverPackageStore *store,
+  PloverPackageSet *set)
+{
+    GSList *packages,*link;
+    GSequenceIter *si;
+    GtkTreeIter ti;
+    GtkTreePath *path;
+    gint *indices;
+    PloverPackageStorePrivate *priv;
+    g_return_if_fail(PLOVER_IS_PACKAGE_STORE(store));
+    g_return_if_fail(PLOVER_IS_PACKAGE_SET(set));
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
+    g_return_if_fail(g_slist_find(priv->sets,set) == NULL);
+    g_object_ref(set);
+    path=gtk_tree_path_new();
+    gtk_tree_path_append_index(path,0);
+    indices=gtk_tree_path_get_indices(path);
+    packages=plover_package_set_get_packages(set);
+    for(link=packages;link;link=link->next)
+    {
+       si=g_sequence_insert_sorted(priv->seq,link->data,
+         plover__package_compar,NULL);
+       *indices=g_sequence_iter_get_position(si);
+       ti.stamp=priv->stamp;
+       ti.user_data=si;
+       gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti);
+    }
+    gtk_tree_path_free(path);
+    priv->sets=g_slist_prepend(priv->sets,set);
+}
+
+void plover_package_store_remove_set(PloverPackageStore *store,
+  PloverPackageSet *set)
+{
+    GSList *packages,*link;
+    GSequence *seq;
+    GSequenceIter *iter,*prev,*remove;
+    GtkTreePath *path;
+    gint *indices;
+    PloverPackageStorePrivate *priv;
+    g_return_if_fail(PLOVER_IS_PACKAGE_STORE(store));
+    g_return_if_fail(PLOVER_IS_PACKAGE_SET(set));
+    priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
+    g_return_if_fail(g_slist_find(priv->sets,set) != NULL);
+    seq=g_sequence_new(NULL);
+    path=gtk_tree_path_new();
+    gtk_tree_path_append_index(path,0);
+    indices=gtk_tree_path_get_indices(path);
+    packages=plover_package_set_get_packages(set);
+    for(link=packages;link;link=link->next)
+       g_sequence_insert_sorted(seq,link->data,plover__package_compar,NULL);
+    prev=NULL;
+    iter=g_sequence_get_begin_iter(priv->seq);
+    remove=g_sequence_get_begin_iter(seq);
+    while(!g_sequence_iter_is_end(iter) && !g_sequence_iter_is_end(remove))
+    {
+       if (g_sequence_get(iter)==g_sequence_get(remove))
+       {
+           *indices=g_sequence_iter_get_position(iter);
+           g_sequence_remove(iter);
+           remove=g_sequence_iter_next(remove);
+           gtk_tree_model_row_deleted(GTK_TREE_MODEL(store),path);
+       }
+       else
+           prev=iter;
+       if (prev)
+           iter=g_sequence_iter_next(prev);
+       else
+           iter=g_sequence_get_begin_iter(priv->seq);
+    }
+    gtk_tree_path_free(path);
+    g_sequence_free(seq);
+    priv->sets=g_slist_remove(priv->sets,set);
+    g_object_unref(set);
+    priv->stamp++;
+}
diff --git a/plover-gtk/packagestore.h b/plover-gtk/packagestore.h
new file mode 100644 (file)
index 0000000..78691a9
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef __PLOVER_PACKAGE_STORE_H__
+#define __PLOVER_PACKAGE_STORE_H__
+
+#include <glib-object.h>
+#include <plover-gtk/packageset.h>
+
+G_BEGIN_DECLS
+
+#define PLOVER_TYPE_PACKAGE_STORE\
+                               plover_package_store_get_type()
+#define PLOVER_PACKAGE_STORE(obj)\
+                               G_TYPE_CHECK_INSTANCE_CAST(obj,\
+                                 PLOVER_TYPE_PACKAGE_STORE,PloverPackageStore)
+#define PLOVER_PACKAGE_STORE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_CAST(klass,\
+                                 PLOVER_TYPE_PACKAGE_STORE,\
+                                 PloverPackageStoreClass)
+#define PLOVER_IS_PACKAGE_STORE(obj)\
+                               G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE_STORE)
+#define PLOVER_IS_PACKAGE_STORE_CLASS(klass)\
+                               G_TYPE_CHECK_CLASS_TYPE(obj,\
+                                 PLOVER_TYPE_PACKAGE_STORE)
+#define PLOVER_PACKAGE_STORE_GET_CLASS(obj)\
+                               G_TYPE_INSTANCE_GET_CLASS(obj,\
+                                 PLOVER_TYPE_PACKAGE_STORE,\
+                                 PloverPackageStoreClass)
+
+typedef enum
+{
+    PLOVER_PACKAGE_STORE_OBJ_COLUMN,
+    PLOVER_PACKAGE_STORE_INSTALLED_COLUMN,
+    PLOVER_PACKAGE_STORE_ICON_COLUMN,
+    PLOVER_PACKAGE_STORE_NAME_COLUMN,
+    PLOVER_PACKAGE_STORE_VERSION_COLUMN,
+    PLOVER_PACKAGE_STORE_SUMMARY_COLUMN,
+    PLOVER_PACKAGE_STORE_NO_COLUMNS
+} PloverPackageStoreColumn;
+
+typedef struct _PloverPackageStore {
+    GObject parent_instance;
+} PloverPackageStore;
+
+typedef struct _PloverPackageStoreClass {
+    GObjectClass parent_class;
+} PloverPackageStoreClass;
+
+GType plover_package_store_get_type(void) G_GNUC_CONST;
+PloverPackageStore *plover_package_store_new(void);
+GSList *plover_package_store_get_sets(PloverPackageStore *store);
+void plover_package_store_add_set(PloverPackageStore *store,
+  PloverPackageSet *set);
+void plover_package_store_remove_set(PloverPackageStore *store,
+  PloverPackageSet *set);
+
+G_END_DECLS
+
+#endif /* __PLOVER_PACKAGE_STORE_H__ */
diff --git a/plover-gtk/plover-gtk.pc.in b/plover-gtk/plover-gtk.pc.in
new file mode 100644 (file)
index 0000000..f1bd8a4
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: plover-gtk
+Description: Plover Gtk+ objects
+Version: @VERSION@
+Requires: plover gtk+-2.0
+Libs: -L${libdir} -lplover-gtk
+Cflags: -I${includedir}
index 38c3cd3..1a05feb 100644 (file)
@@ -1,13 +1,12 @@
 AM_CFLAGS=-g $(LIBPLOVER_CFLAGS)
 LIBS=$(LIBPLOVER_LIBS)
 INCLUDES=-I$(top_srcdir)
-LDFLAGS=-no-undefined \
-       -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
-
-lib_LTLIBRARIES=libplover.la
-libplover_la_SOURCES=plover.h util.c import-yum.c razor.c comps.c
+LDFLAGS=-no-undefined -version-info $(LIBPLOVER_LT_VERSION_INFO)
 
 pkginclude_HEADERS=plover.h
 
+lib_LTLIBRARIES=libplover.la
+libplover_la_SOURCES=$(pkginclude_HEADERS) util.c import-yum.c razor.c comps.c
+
 pkgconfigdir=$(libdir)/pkgconfig
 pkgconfig_DATA=plover.pc
index d6c0c5e..e572273 100644 (file)
@@ -98,6 +98,9 @@ yum_primary_start_element(void *data, const char *name, const char **atts)
                        if (strcmp(atts[i], "packages") == 0)
                                ctx->total = atoi(atts[i + 1]);
                }
+       } else if (strcmp(name, "package") == 0) {
+               *ctx->name=*ctx->arch=*ctx->summary=*ctx->description='\0';
+               *ctx->url=*ctx->license='\0';
        } else if (strcmp(name, "name") == 0) {
                ctx->state = YUM_STATE_PACKAGE_NAME;
                ctx->p = ctx->name;
@@ -216,9 +219,6 @@ yum_primary_end_element (void *data, const char *name)
 
                XML_StopParser(ctx->current_parser, XML_TRUE);
                ctx->current_parser = ctx->filelists_parser;
-
-               printf("\rimporting %d/%d", ++ctx->current, ctx->total);
-               fflush(stdout);
        }
 }
 
@@ -360,6 +360,5 @@ plover_razor_set_create_from_yum(const char *base)
        gzclose(primary);
        gzclose(filelists);
 
-       printf ("\nsaving\n");
        return razor_importer_finish(ctx.importer);
 }