app-manager/packagelist.c
author J. Ali Harlow <ali@juiblex.co.uk>
Tue Apr 25 17:41:00 2023 +0100 (2023-04-25)
changeset 109 2947214c450e
parent 24 2b9f54d14cc2
permissions -rw-r--r--
Partial fix for #5537
     1 /*
     2  * Copyright (C) 2010  J. Ali Harlow <ali@juiblex.co.uk>
     3  *
     4  * This program is free software; you can redistribute it and/or modify
     5  * it under the terms of the GNU General Public License as published by
     6  * the Free Software Foundation; either version 2 of the License, or
     7  * (at your option) any later version.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License along
    15  * with this program; if not, write to the Free Software Foundation, Inc.,
    16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    17  */
    18 
    19 #include "config.h"
    20 #include <stdlib.h>
    21 #include <string.h>
    22 #include <gtk/gtk.h>
    23 #include <plover/plover.h>
    24 #include <plover/package.h>
    25 #include <plover/packageset.h>
    26 #include <plover/yumrepository.h>
    27 #include <plover-gtk/packagestore.h>
    28 #include <plover-gtk/packagefilestore.h>
    29 #include "app-manager.h"
    30 
    31 GtkTreeView *view=NULL;
    32 PloverPackage *active=NULL;
    33 gboolean view_files=FALSE;
    34 
    35 void package_present(PloverPackage *package)
    36 {
    37     gchar *s,*prefix,*prefix_path;
    38     const char *text,*t;
    39     char *multiple_prefixes="multiple";
    40     GError *tmp_err=NULL;
    41     GSList *sets,*repositories,*lnk;
    42     GtkWidget *w;
    43     GtkTextBuffer *buf;
    44     GtkTreeModel *model;
    45     struct comps *comps;
    46     PloverPackageSet *set;
    47     PloverPackageFileStore *store;
    48     PloverRepository *repository;
    49     buf=GTK_TEXT_BUFFER(gtk_builder_get_object(ui,"description"));
    50     if (package)
    51     {
    52 	s=g_strdup(plover_package_get_description(package));
    53 	g_strdelimit(s,"\t\n",' ');
    54     }
    55     else
    56     {
    57 	model=gtk_tree_view_get_model(view);
    58 	while(model &&
    59 	  (GTK_IS_TREE_MODEL_FILTER(model) || GTK_IS_TREE_MODEL_SORT(model)))
    60 	{
    61 	    if (GTK_IS_TREE_MODEL_FILTER(model))
    62 		model=
    63 		  gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
    64 	    else
    65 		model=gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model));
    66 	}
    67 	repositories=NULL;
    68 	prefix=NULL;
    69 	if (model && PLOVER_IS_PACKAGE_STORE(model))
    70 	{
    71 	    sets=plover_package_store_get_sets(PLOVER_PACKAGE_STORE(model));
    72 	    for(lnk=sets;lnk;lnk=lnk->next)
    73 	    {
    74 		set=lnk->data;
    75 		repository=plover_package_set_get_repository(set);
    76 		if (repository && !g_slist_find(repositories,repository))
    77 		    repositories=g_slist_prepend(repositories,repository);
    78 		t=plover_package_set_guess_prefix(set,tmp_err?NULL:&tmp_err);
    79 		if (!t)
    80 		    continue;
    81 		if (!prefix)
    82 		    prefix=g_strdup(t);
    83 		else if (prefix!=multiple_prefixes && strcmp(prefix,t))
    84 		{
    85 		    g_free(prefix);
    86 		    prefix=multiple_prefixes;
    87 		}
    88 	    }
    89 	    if (prefix==multiple_prefixes)
    90 		s=g_strdup("Multiple install prefixes");
    91 	    else if (repositories)
    92 	    {
    93 		if (prefix!=multiple_prefixes)
    94 		    g_free(prefix);
    95 		prefix=NULL;
    96 		for(lnk=repositories;lnk;lnk=lnk->next)
    97 		{
    98 		    repository=lnk->data;
    99 		    if (PLOVER_IS_YUM_REPOSITORY(repository))
   100 		    {
   101 			comps=plover_yum_repository_get_comps(
   102 			  PLOVER_YUM_REPOSITORY(repository),NULL);
   103 			t=plover_comps_get_default_prefix(comps);
   104 			if (!prefix)
   105 			    prefix=g_strdup(t);
   106 			else if (prefix!=multiple_prefixes && strcmp(prefix,t))
   107 			{
   108 			    g_free(prefix);
   109 			    prefix=multiple_prefixes;
   110 			}
   111 		    }
   112 		}
   113 		if (prefix==multiple_prefixes)
   114 		    s=g_strdup("Repositories intended to be installed to "
   115 		      "multiple destinations");
   116 		else if (prefix)
   117 		{
   118 		    prefix_path=razor_path_from_uri(prefix,NULL);
   119 		    s=g_strdup_printf("Repository intended to be installed to: "
   120 		      "%s",prefix_path?prefix_path:prefix);
   121 		    g_free(prefix_path);
   122 		}
   123 		else
   124 		    s=g_strdup("Repository with no default "
   125 		      "install destination");
   126 	    }
   127 	    else if (prefix)
   128 	    {
   129 		prefix_path=razor_path_from_uri(prefix,NULL);
   130 		s=g_strdup_printf("Installed in: %s",
   131 		  prefix_path?prefix_path:prefix);
   132 		g_free(prefix_path);
   133 	    }
   134 	    else if (sets)
   135 		s=g_strdup("No common installation destination found");
   136 	    else
   137 		s=g_strdup("Empty package store");
   138 	    if (prefix!=multiple_prefixes)
   139 		g_free(prefix);
   140 	    g_slist_free(repositories);
   141 	    g_clear_error(&tmp_err);
   142 	}
   143 	else if (model)
   144 	    s=g_strdup_printf("Unsupported package list container (%s)",
   145 	      G_OBJECT_TYPE_NAME(model));
   146 	else
   147 	    s=g_strdup("No Package list container");
   148     }
   149     gtk_text_buffer_set_text(buf,s,-1);
   150     g_free(s);
   151     w=GTK_WIDGET(gtk_builder_get_object(ui,"PackageDetails"));
   152     if (!package)
   153     {
   154 	gtk_widget_hide(w);
   155 	w=GTK_WIDGET(gtk_builder_get_object(ui,"FilesScrolledWindow"));
   156 	gtk_widget_hide(w);
   157 	w=GTK_WIDGET(gtk_builder_get_object(ui,"DescriptionScrolledWindow"));
   158 	gtk_widget_show(w);
   159     }
   160     else
   161     {
   162 	if (view_files)
   163 	    gtk_widget_hide(w);
   164 	else
   165 	{
   166 	    gtk_widget_show(w);
   167 	    w=GTK_WIDGET(gtk_builder_get_object(ui,"HomepageBox"));
   168 	    text=plover_package_get_URL(package);
   169 	    if (!*text)
   170 		gtk_widget_hide(w);
   171 	    else
   172 	    {
   173 		gtk_widget_show(w);
   174 		w=GTK_WIDGET(gtk_builder_get_object(ui,"Homepage"));
   175 		gtk_link_button_set_uri(GTK_LINK_BUTTON(w),text);
   176 		t=strstr(text,"://");
   177 		if (t)
   178 		    t+=3;
   179 		if (t)
   180 		    s=g_strndup(t,strcspn(t,"/"));
   181 		else
   182 		    s=g_strdup(text);
   183 		gtk_button_set_label(GTK_BUTTON(w),s);
   184 		g_free(s);
   185 	    }
   186 	    w=GTK_WIDGET(gtk_builder_get_object(ui,"Architecture"));
   187 	    gtk_label_set_text(GTK_LABEL(w),plover_package_get_arch(package));
   188 	    w=GTK_WIDGET(gtk_builder_get_object(ui,"License"));
   189 	    gtk_label_set_text(GTK_LABEL(w),
   190 	      plover_package_get_license(package));
   191 	}
   192 	w=GTK_WIDGET(gtk_builder_get_object(ui,"FilesScrolledWindow"));
   193 	if (view_files)
   194 	    gtk_widget_show(w);
   195 	else
   196 	    gtk_widget_hide(w);
   197 	w=GTK_WIDGET(gtk_builder_get_object(ui,"DescriptionScrolledWindow"));
   198 	if (view_files)
   199 	{
   200 	    gtk_widget_hide(w);
   201 	    w=GTK_WIDGET(gtk_builder_get_object(ui,"Files"));
   202 	    store=plover_package_file_store_new_from_package(package);
   203 	    gtk_tree_view_set_model(GTK_TREE_VIEW(w),GTK_TREE_MODEL(store));
   204 	    g_object_unref(store);
   205 	}
   206 	else
   207 	{
   208 	    gtk_widget_show(w);
   209 	    /* Without this, Gtk+ 2.18.6 just truncates long license tags */
   210 	    w=GTK_WIDGET(gtk_builder_get_object(ui,"DetailsScrolledWindow"));
   211 	    gtk_widget_queue_resize(w);
   212 	}
   213     }
   214 }
   215 
   216 void package_filelist_present(PloverPackage *package)
   217 {
   218 }
   219 
   220 static void package_selection_changed(GtkTreeSelection *selection)
   221 {
   222     GtkTreeIter iter;
   223     GtkTreeView *view;
   224     GtkTreeModel *model;
   225     if (active)
   226 	g_object_unref(active);
   227     if (gtk_tree_selection_get_selected(selection,NULL,&iter))
   228     {
   229 	view=gtk_tree_selection_get_tree_view(selection);
   230 	model=gtk_tree_view_get_model(view);
   231 	gtk_tree_model_get(model,&iter,PLOVER_PACKAGE_STORE_OBJ_COLUMN,&active,
   232 	  -1);
   233     }
   234     else
   235 	active=NULL;
   236     package_present(active);
   237 }
   238 
   239 static void package_activated(GtkTreeView *view,GtkTreePath *path,
   240   GtkTreeViewColumn *column,gpointer data)
   241 {
   242     GtkTreeIter iter;
   243     GtkTreeModel *model=gtk_tree_view_get_model(view);
   244     PloverPackage *package;
   245     if (gtk_tree_model_get_iter(model,&iter,path))
   246     {
   247 	gtk_tree_model_get(model,&iter,PLOVER_PACKAGE_STORE_OBJ_COLUMN,&package,
   248 	  -1);
   249 	package_filelist_present(package);
   250     }
   251 }
   252 
   253 static void package_inserted(GtkTreeModel *tree_model,GtkTreePath *path,
   254   GtkTreeIter *iter,gpointer data)
   255 {
   256     gchar *s;
   257     s=gtk_tree_path_to_string(path);
   258     g_message("package_inserted(%s): %sactive package",
   259       s,active?"":"no ");
   260     g_free(s);
   261     if (!active)
   262 	package_present(NULL);
   263 }
   264 
   265 static void package_deleted(GtkTreeModel *tree_model,GtkTreePath *path,
   266   gpointer data)
   267 {
   268     /*
   269      * If the deleted package was the active one, then selection-changed
   270      * will be emitted which will handle that case.
   271      */
   272     gchar *s;
   273     s=gtk_tree_path_to_string(path);
   274     g_message("package_deleted(%s): %sactive package",s,active?"":"no ");
   275     g_free(s);
   276     if (!active)
   277 	package_present(NULL);
   278 }
   279 
   280 static void package_cell_data_func(GtkTreeViewColumn *column,
   281   GtkCellRenderer *cell,GtkTreeModel *model,GtkTreeIter *iter,gpointer data)
   282 {
   283     gchar *markup;
   284     gchar *summary,*name,*version;
   285     g_return_if_fail(GTK_IS_TREE_MODEL(model));
   286     gtk_tree_model_get(model,iter,PLOVER_PACKAGE_STORE_SUMMARY_COLUMN,&summary,
   287       PLOVER_PACKAGE_STORE_NAME_COLUMN,&name,
   288       PLOVER_PACKAGE_STORE_VERSION_COLUMN,&version,-1);
   289     markup=g_markup_printf_escaped("<b>%s</b>\n%s %s",summary,name,version);
   290     g_free(summary);
   291     g_free(name);
   292     g_free(version);
   293     g_object_set(cell,"markup",markup,NULL);
   294     g_free(markup);
   295 }
   296 
   297 void set_package_model(GtkTreeModel *model)
   298 {
   299     GtkWidget *w;
   300     GtkTreeModel *old_model;
   301     GtkTreeViewColumn *column;
   302     GtkCellRenderer *renderer;
   303     GtkTreeSelection *selection;
   304     if (view)
   305     {
   306 	old_model=gtk_tree_view_get_model(view);
   307 	if (old_model)
   308 	{
   309 	    g_signal_handlers_disconnect_by_func(old_model,
   310 	      G_CALLBACK(package_inserted),NULL);
   311 	    g_signal_handlers_disconnect_by_func(old_model,
   312 	      G_CALLBACK(package_deleted),NULL);
   313 	}
   314     }
   315     if (!view)
   316     {
   317 	w=GTK_WIDGET(gtk_builder_get_object(ui,"Packages"));
   318 	if (w)
   319 	{
   320 	    view=GTK_TREE_VIEW(w);
   321 #if 0
   322 	    column=gtk_tree_view_column_new_with_attributes("Icon",
   323 	      gtk_cell_renderer_pixbuf_new(),"pixbuf",
   324 	      PLOVER_PACKAGE_FILE_STORE_ICON_COLUMN,NULL);
   325 	    gtk_tree_view_append_column(GTK_TREE_VIEW(w),column);
   326 #endif
   327 	    column=gtk_tree_view_column_new();
   328 	    gtk_tree_view_column_set_title(column,"Summary");
   329 	    renderer=gtk_cell_renderer_text_new();
   330 	    gtk_tree_view_column_pack_start(column,renderer,FALSE);
   331 	    gtk_tree_view_column_set_cell_data_func(column,renderer,
   332 	      package_cell_data_func,NULL,NULL);
   333 	    gtk_tree_view_append_column(view,column);
   334 	    gtk_widget_show_all(w);
   335 	    gtk_tree_view_set_headers_visible(view,FALSE);
   336 	    w=GTK_WIDGET(gtk_builder_get_object(ui,"SearchEntry"));
   337 	    gtk_tree_view_set_search_entry(view,GTK_ENTRY(w));
   338 	    selection=gtk_tree_view_get_selection(view);
   339 	    g_signal_connect(selection,"changed",
   340 	      G_CALLBACK(package_selection_changed),NULL);
   341 	    g_signal_connect(view,"row-activated",G_CALLBACK(package_activated),
   342 	      NULL);
   343 	}
   344 	else
   345 	    g_warning("Packages: no such widget in UI");
   346 	w=GTK_WIDGET(gtk_builder_get_object(ui,"Files"));
   347 	if (w)
   348 	{
   349 	    column=gtk_tree_view_column_new_with_attributes("Name",
   350 	      gtk_cell_renderer_text_new(),"text",
   351 	      PLOVER_PACKAGE_FILE_STORE_NAME_COLUMN,NULL);
   352 	    gtk_tree_view_append_column(GTK_TREE_VIEW(w),column);
   353 	    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w),FALSE);
   354 	    gtk_widget_show_all(w);
   355 	}
   356 	else
   357 	    g_warning("Files: no such widget in UI");
   358     }
   359     if (view)
   360     {
   361 	g_warning("set_package_model: Calling gtk_tree_view_set_model()");
   362 	gtk_tree_view_set_model(view,model);
   363 	g_warning("set_package_model: gtk_tree_view_set_model() returns");
   364 	gtk_tree_view_set_search_column(view,
   365 	  PLOVER_PACKAGE_STORE_NAME_COLUMN);
   366 	if (model)
   367 	{
   368 	    g_signal_connect(model,"row-inserted",G_CALLBACK(package_inserted),
   369 	      NULL);
   370 	    g_signal_connect(model,"row-deleted",G_CALLBACK(package_deleted),
   371 	      NULL);
   372 	}
   373     }
   374     package_present(NULL);
   375 }
   376 
   377 PloverPackage *get_active_package(void)
   378 {
   379     return active;
   380 }
   381 
   382 G_MODULE_EXPORT void
   383   on_view_files_toggled(GtkCheckMenuItem *menuitem,gpointer data)
   384 {
   385     view_files=gtk_check_menu_item_get_active(menuitem);
   386     package_present(active);
   387 }
   388 
   389 G_MODULE_EXPORT void
   390   on_view_details_toggled(GtkCheckMenuItem *menuitem,gpointer data)
   391 {
   392 }