/* * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford * Copyright (C) 2010 J. Ali Harlow * * 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 #include #include #include #include #include "plover/plover.h" #include "plover/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) { g_return_val_if_fail(indx>=0 && indx=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) { gchar *s; const char *summary; PloverPackageStore *store=(PloverPackageStore *)tree_model; PloverPackage *package; GInputStream *stream; GdkPixbuf *icon; g_return_if_fail(column>=0 && columnuser_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: stream=plover_package_read_icon(package,NULL); if (stream) { icon=gdk_pixbuf_new_from_stream(stream,NULL,NULL); g_object_unref(stream); } else icon=NULL; g_value_set_object(value,icon); 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: summary=plover_package_get_summary(package); if (*summary) g_value_set_string(value,summary); else { s=g_strconcat("The ",plover_package_get_name(package), " package",NULL); g_value_set_string(value,s); g_free(s); } break; case PLOVER_PACKAGE_STORE_NO_COLUMNS: /* Quieten compiler warning */ 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; 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; 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; 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)); } static gint plover__sequence_iter_compar(gconstpointer a,gconstpointer b) { GSequenceIter *sia=(GSequenceIter *)a; GSequenceIter *sib=(GSequenceIter *)b; return g_sequence_iter_get_position(sia)-g_sequence_iter_get_position(sib); } void plover_package_store_add_set(PloverPackageStore *store, PloverPackageSet *set) { GSList *packages,*lnk; GSequenceIter *si; GtkTreeIter ti; GtkTreePath *path; 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); /* * This is a little complicated because we don't want to * emit row-inserted until we have actually added set to * the list of sets. On the other hand, we don't want to * add set to the list of sets until all the packages it * contains have been added to the sequence. * Thus, this two phase implementation. * However, this introduces an addition complication in * that the original row numbers are no longer valid as * we keep inserting rows. GSequenceIter should deal with * this, but it seems to be giving us problems. Just go * with the simple solution. * Finally, the positions of the result have to be * published in increasing order to avoid confusing * subscribers. */ packages=plover_package_set_get_packages(set); for(lnk=packages;lnk;lnk=lnk->next) g_sequence_insert_sorted(priv->seq,lnk->data, plover__package_compar,NULL); priv->sets=g_slist_prepend(priv->sets,set); priv->stamp++; path=gtk_tree_path_new(); gtk_tree_path_append_index(path,0); si=g_sequence_get_begin_iter(priv->seq); while(!g_sequence_iter_is_end(si)) { if (g_slist_find(packages,g_sequence_get(si))) { ti.stamp=priv->stamp; ti.user_data=si; gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti); } si=g_sequence_iter_next(si); gtk_tree_path_next(path); } gtk_tree_path_free(path); } 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++; }