plover-gtk/packagestore.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Jul 16 11:07:18 2016 +0100 (2016-07-16)
changeset 61 31fb35727621
parent 24 2b9f54d14cc2
child 109 2947214c450e
permissions -rw-r--r--
Support parallel installations. The idea is that for CAD screener, we want
to be able to install this on the same machine as a standard AVOT setup
(most notably for John's laptop). To allow for the possibility of a second
application that might have the same requirements, we add the concept of
vendor-specific distributions. Thus we can have one distribution for CAD
screener and one for The Next Big Thing. It doesn't seem trivial to have
both CAD screener and AVOT under the same vendor tag so we'll have to have
AVOT under "City Occupational" and CAD screener under "City Occupational Ltd"
or some such kludge.

Most of this is done although we are very short of test cases (in particular
we don't test that it's actually possible to install CAD screener in parallel
with AVOT or to update either of them once installed, which is fundamental).

We also have a lot of baggage left over, including an intercept of razor_set.
The problem that this was introduced to debug has been fixed but it looks
like there are a number of memory leaks which it might be useful to help
track down so it has been left in place for now.

There is still a lot of confusion in plover between path-based and URI-based
API. We should review the API, decide what we want and have a general clear up.

There is also confusion as to the purpose of RAZOR_ROOT (and meaning; path or
URI). This is not used at all in librazor (although it is used in razor.exe).
Ideally we shouldn't use it in plover or plover-gtk either although again, we
might want to support it or an equivalent in (some of) the various executables.

Work that would still to nice to do for CAD screener:

- uninstall (ideally as an installed program that hooks into Add/Remove programs
but even re-running the installer would be acceptable).
- xz support (smaller packages).
- repomd.xml and xml:base (would be needed for an Internet installer).
- graphical installer.
     1 /*
     2  * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
     3  * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #include "config.h"
    21 #include <stdlib.h>
    22 #include <string.h>
    23 #include <glib-object.h>
    24 #include <gtk/gtk.h>
    25 #include <razor.h>
    26 #include "plover/plover.h"
    27 #include "plover/package.h"
    28 #include "plover-gtk/packagestore.h"
    29 
    30 #define VALID_ITER(iter,store) ((iter) && (iter)->user_data && \
    31 	PLOVER_PACKAGE_STORE_GET_PRIVATE(store)->stamp==(iter)->stamp && \
    32 	!g_sequence_iter_is_end((iter)->user_data) && \
    33 	g_sequence_iter_get_sequence((iter)->user_data)== \
    34 	PLOVER_PACKAGE_STORE_GET_PRIVATE(store)->seq)
    35 
    36 static GType column_types[PLOVER_PACKAGE_STORE_NO_COLUMNS];
    37 
    38 static void plover_package_store_tree_model_init(GtkTreeModelIface *iface);
    39 
    40 G_DEFINE_TYPE_WITH_CODE(PloverPackageStore,plover_package_store,G_TYPE_OBJECT,
    41   G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
    42   plover_package_store_tree_model_init));
    43 
    44 typedef struct _PloverPackageStorePrivate {
    45     GSList *sets;
    46     GSequence *seq;
    47     int stamp;
    48 } PloverPackageStorePrivate;
    49 
    50 #define PLOVER_PACKAGE_STORE_GET_PRIVATE(obj)\
    51 				G_TYPE_INSTANCE_GET_PRIVATE(obj,\
    52 				  PLOVER_TYPE_PACKAGE_STORE,\
    53 				  PloverPackageStorePrivate)
    54 
    55 static void plover_package_store_finalize(GObject *obj)
    56 {
    57     PloverPackageStorePrivate *priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(obj);
    58     g_sequence_free(priv->seq);
    59     if (G_OBJECT_CLASS(plover_package_store_parent_class)->finalize)
    60 	G_OBJECT_CLASS(plover_package_store_parent_class)->finalize(obj);
    61 }
    62 
    63 static void plover_package_store_dispose(GObject *obj)
    64 {
    65     PloverPackageStorePrivate *priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(obj);
    66     g_slist_foreach(priv->sets,(GFunc)g_object_unref,NULL);
    67     g_slist_free(priv->sets);
    68     priv->sets=NULL;
    69     g_sequence_free(priv->seq);
    70     priv->seq=g_sequence_new(NULL);
    71     if (G_OBJECT_CLASS(plover_package_store_parent_class)->dispose)
    72 	G_OBJECT_CLASS(plover_package_store_parent_class)->dispose(obj);
    73 }
    74 
    75 static void plover_package_store_class_init(PloverPackageStoreClass *klass)
    76 {
    77     GObjectClass *oclass=G_OBJECT_CLASS(klass);
    78     oclass->finalize=plover_package_store_finalize;
    79     oclass->dispose=plover_package_store_dispose;
    80     g_type_class_add_private(klass,sizeof(PloverPackageStorePrivate));
    81     column_types[PLOVER_PACKAGE_STORE_OBJ_COLUMN]=PLOVER_TYPE_PACKAGE;
    82     column_types[PLOVER_PACKAGE_STORE_INSTALLED_COLUMN]=G_TYPE_BOOLEAN;
    83     column_types[PLOVER_PACKAGE_STORE_ICON_COLUMN]=GDK_TYPE_PIXBUF;
    84     column_types[PLOVER_PACKAGE_STORE_NAME_COLUMN]=G_TYPE_STRING;
    85     column_types[PLOVER_PACKAGE_STORE_VERSION_COLUMN]=G_TYPE_STRING;
    86     column_types[PLOVER_PACKAGE_STORE_SUMMARY_COLUMN]=G_TYPE_STRING;
    87 }
    88 
    89 static GtkTreeModelFlags
    90 plover_package_store_get_flags(GtkTreeModel *tree_model)
    91 {
    92     return GTK_TREE_MODEL_ITERS_PERSIST|GTK_TREE_MODEL_LIST_ONLY;
    93 }
    94 
    95 static gint plover_package_store_get_n_columns(GtkTreeModel *tree_model)
    96 {
    97     return PLOVER_PACKAGE_STORE_NO_COLUMNS;
    98 }
    99 
   100 static GType
   101   plover_package_store_get_column_type(GtkTreeModel *tree_model,gint indx)
   102 {
   103     g_return_val_if_fail(indx>=0 && indx<PLOVER_PACKAGE_STORE_NO_COLUMNS,
   104       G_TYPE_INVALID);
   105     return column_types[indx];
   106 }
   107 
   108 static gboolean plover_package_store_get_iter(GtkTreeModel *tree_model,
   109   GtkTreeIter *iter,GtkTreePath *path)
   110 {
   111     int i;
   112     PloverPackageStorePrivate *priv;
   113     PloverPackageStore *store=(PloverPackageStore *)tree_model;
   114     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
   115     i=gtk_tree_path_get_indices(path)[0];
   116     if (i>=g_sequence_get_length(priv->seq))
   117 	return FALSE;
   118     iter->stamp=priv->stamp;
   119     iter->user_data=g_sequence_get_iter_at_pos(priv->seq,i);
   120     return TRUE;
   121 }
   122 
   123 static GtkTreePath *
   124   plover_package_store_get_path(GtkTreeModel *tree_model,GtkTreeIter *iter)
   125 {
   126     GtkTreePath *path;
   127     g_return_val_if_fail(VALID_ITER(iter,tree_model),NULL);
   128     if (g_sequence_iter_is_end(iter->user_data))
   129 	return NULL;
   130     path=gtk_tree_path_new();
   131     gtk_tree_path_append_index(path,
   132       g_sequence_iter_get_position(iter->user_data));
   133     return path;
   134 }
   135 
   136 static void plover_package_store_get_value(GtkTreeModel *tree_model,
   137   GtkTreeIter *iter,gint column,GValue *value)
   138 {
   139     gchar *s;
   140     const char *summary;
   141     PloverPackageStore *store=(PloverPackageStore *)tree_model;
   142     PloverPackage *package;
   143     GInputStream *stream;
   144     GdkPixbuf *icon;
   145     g_return_if_fail(column>=0 && column<PLOVER_PACKAGE_STORE_NO_COLUMNS);
   146     g_return_if_fail(VALID_ITER(iter,store));
   147     package=PLOVER_PACKAGE(g_sequence_get(iter->user_data));
   148     g_value_init(value,column_types[column]);
   149     switch((PloverPackageStoreColumn)column)
   150     {
   151 	case PLOVER_PACKAGE_STORE_OBJ_COLUMN:
   152 	    g_value_set_object(value,package);
   153 	    break;
   154 	case PLOVER_PACKAGE_STORE_INSTALLED_COLUMN:
   155 	    break;
   156 	case PLOVER_PACKAGE_STORE_ICON_COLUMN:
   157 	    stream=plover_package_read_icon(package,NULL);
   158 	    if (stream)
   159 	    {
   160 		icon=gdk_pixbuf_new_from_stream(stream,NULL,NULL);
   161 		g_object_unref(stream);
   162 	    }
   163 	    else
   164 		icon=NULL;
   165 	    g_value_set_object(value,icon);
   166 	    break;
   167 	case PLOVER_PACKAGE_STORE_NAME_COLUMN:
   168 	    g_value_set_string(value,plover_package_get_name(package));
   169 	    break;
   170 	case PLOVER_PACKAGE_STORE_VERSION_COLUMN:
   171 	    g_value_set_string(value,plover_package_get_version(package));
   172 	    break;
   173 	case PLOVER_PACKAGE_STORE_SUMMARY_COLUMN:
   174 	    summary=plover_package_get_summary(package);
   175 	    if (*summary)
   176 		g_value_set_string(value,summary);
   177 	    else
   178 	    {
   179 		s=g_strconcat("The ",plover_package_get_name(package),
   180 		  " package",NULL);
   181 		g_value_set_string(value,s);
   182 		g_free(s);
   183 	    }
   184 	    break;
   185 	case PLOVER_PACKAGE_STORE_NO_COLUMNS:
   186 	    /* Quieten compiler warning */
   187 	    break;
   188     }
   189 }
   190 
   191 static gboolean
   192   plover_package_store_iter_next(GtkTreeModel *tree_model,GtkTreeIter *iter)
   193 {
   194     g_return_val_if_fail(VALID_ITER(iter,tree_model),FALSE);
   195     iter->user_data=g_sequence_iter_next(iter->user_data);
   196     return !g_sequence_iter_is_end(iter->user_data);
   197 }
   198 
   199 static gboolean plover_package_store_iter_children(GtkTreeModel *tree_model,
   200   GtkTreeIter *iter,GtkTreeIter *parent)
   201 {
   202     PloverPackageStorePrivate *priv;
   203     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(tree_model);
   204     /* this is a list, nodes have no children */
   205     if (parent)
   206 	return FALSE;
   207     if (g_sequence_get_length(priv->seq)>0)
   208     {
   209 	iter->stamp=priv->stamp;
   210 	iter->user_data=g_sequence_get_begin_iter(priv->seq);
   211 	return TRUE;
   212     }
   213     else
   214 	return FALSE;
   215 }
   216 
   217 static gboolean plover_package_store_iter_has_child(GtkTreeModel *tree_model,
   218   GtkTreeIter *iter)
   219 {
   220     return FALSE;
   221 }
   222 
   223 static gint plover_package_store_iter_n_children(GtkTreeModel *tree_model,
   224   GtkTreeIter *iter)
   225 {
   226     PloverPackageStorePrivate *priv;
   227     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(tree_model);
   228     if (!iter)
   229 	return g_sequence_get_length(priv->seq);
   230     g_return_val_if_fail(VALID_ITER(iter,tree_model),-1);
   231     return 0;
   232 }
   233 
   234 static gboolean plover_package_store_iter_nth_child(GtkTreeModel *tree_model,
   235   GtkTreeIter *iter,GtkTreeIter *parent,gint n)
   236 {
   237     PloverPackageStorePrivate *priv;
   238     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(tree_model);
   239     GSequenceIter *child;
   240     if (parent)
   241 	return FALSE;
   242     child=g_sequence_get_iter_at_pos(priv->seq,n);
   243     if (g_sequence_iter_is_end(child))
   244 	return FALSE;
   245     iter->stamp=priv->stamp;
   246     iter->user_data=child;
   247     return TRUE;
   248 }
   249 
   250 static gboolean plover_package_store_iter_parent(GtkTreeModel *tree_model,
   251   GtkTreeIter *iter,GtkTreeIter *child)
   252 {
   253     return FALSE;
   254 }
   255 
   256 static void plover_package_store_tree_model_init(GtkTreeModelIface *iface)
   257 {
   258     iface->get_flags=plover_package_store_get_flags;
   259     iface->get_n_columns=plover_package_store_get_n_columns;
   260     iface->get_column_type=plover_package_store_get_column_type;
   261     iface->get_iter=plover_package_store_get_iter;
   262     iface->get_path=plover_package_store_get_path;
   263     iface->get_value=plover_package_store_get_value;
   264     iface->iter_next=plover_package_store_iter_next;
   265     iface->iter_children=plover_package_store_iter_children;
   266     iface->iter_has_child=plover_package_store_iter_has_child;
   267     iface->iter_n_children=plover_package_store_iter_n_children;
   268     iface->iter_nth_child=plover_package_store_iter_nth_child;
   269     iface->iter_parent=plover_package_store_iter_parent;
   270 }
   271 
   272 static void plover_package_store_init(PloverPackageStore *store)
   273 {
   274     PloverPackageStorePrivate *priv;
   275     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
   276     priv->seq=g_sequence_new(NULL);
   277     priv->stamp=g_random_int();
   278 }
   279 
   280 PloverPackageStore *plover_package_store_new(void)
   281 {
   282     return g_object_new(PLOVER_TYPE_PACKAGE_STORE,NULL);
   283 }
   284 
   285 GSList *plover_package_store_get_sets(PloverPackageStore *store)
   286 {
   287     PloverPackageStorePrivate *priv;
   288     g_return_val_if_fail(PLOVER_IS_PACKAGE_STORE(store),NULL);
   289     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
   290     return priv->sets;
   291 }
   292 
   293 static gint
   294   plover__package_compar(gconstpointer a,gconstpointer b,gpointer user_data)
   295 {
   296     PloverPackage *pa=PLOVER_PACKAGE(a);
   297     PloverPackage *pb=PLOVER_PACKAGE(b);
   298     return strcmp(plover_package_get_name(pa),plover_package_get_name(pb));
   299 }
   300 
   301 void plover_package_store_add_set(PloverPackageStore *store,
   302   PloverPackageSet *set)
   303 {
   304     GSList *packages,*link;
   305     GSequenceIter *si;
   306     GtkTreeIter ti;
   307     GtkTreePath *path;
   308     gint *indices;
   309     PloverPackageStorePrivate *priv;
   310     g_return_if_fail(PLOVER_IS_PACKAGE_STORE(store));
   311     g_return_if_fail(PLOVER_IS_PACKAGE_SET(set));
   312     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
   313     g_return_if_fail(g_slist_find(priv->sets,set) == NULL);
   314     g_object_ref(set);
   315     path=gtk_tree_path_new();
   316     gtk_tree_path_append_index(path,0);
   317     indices=gtk_tree_path_get_indices(path);
   318     packages=plover_package_set_get_packages(set);
   319     for(link=packages;link;link=link->next)
   320     {
   321 	si=g_sequence_insert_sorted(priv->seq,link->data,
   322 	  plover__package_compar,NULL);
   323 	*indices=g_sequence_iter_get_position(si);
   324 	ti.stamp=priv->stamp;
   325 	ti.user_data=si;
   326 	gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti);
   327     }
   328     gtk_tree_path_free(path);
   329     priv->sets=g_slist_prepend(priv->sets,set);
   330 }
   331 
   332 void plover_package_store_remove_set(PloverPackageStore *store,
   333   PloverPackageSet *set)
   334 {
   335     GSList *packages,*link;
   336     GSequence *seq;
   337     GSequenceIter *iter,*prev,*remove;
   338     GtkTreePath *path;
   339     gint *indices;
   340     PloverPackageStorePrivate *priv;
   341     g_return_if_fail(PLOVER_IS_PACKAGE_STORE(store));
   342     g_return_if_fail(PLOVER_IS_PACKAGE_SET(set));
   343     priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
   344     g_return_if_fail(g_slist_find(priv->sets,set) != NULL);
   345     seq=g_sequence_new(NULL);
   346     path=gtk_tree_path_new();
   347     gtk_tree_path_append_index(path,0);
   348     indices=gtk_tree_path_get_indices(path);
   349     packages=plover_package_set_get_packages(set);
   350     for(link=packages;link;link=link->next)
   351 	g_sequence_insert_sorted(seq,link->data,plover__package_compar,NULL);
   352     prev=NULL;
   353     iter=g_sequence_get_begin_iter(priv->seq);
   354     remove=g_sequence_get_begin_iter(seq);
   355     while(!g_sequence_iter_is_end(iter) && !g_sequence_iter_is_end(remove))
   356     {
   357 	if (g_sequence_get(iter)==g_sequence_get(remove))
   358 	{
   359 	    *indices=g_sequence_iter_get_position(iter);
   360 	    g_sequence_remove(iter);
   361 	    remove=g_sequence_iter_next(remove);
   362 	    gtk_tree_model_row_deleted(GTK_TREE_MODEL(store),path);
   363 	}
   364 	else
   365 	    prev=iter;
   366 	if (prev)
   367 	    iter=g_sequence_iter_next(prev);
   368 	else
   369 	    iter=g_sequence_get_begin_iter(priv->seq);
   370     }
   371     gtk_tree_path_free(path);
   372     g_sequence_free(seq);
   373     priv->sets=g_slist_remove(priv->sets,set);
   374     g_object_unref(set);
   375     priv->stamp++;
   376 }