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