Commit fcb3a76f authored by Kalev Lember's avatar Kalev Lember

Add a dialog to confirm upgrade removals

https://bugzilla.redhat.com/show_bug.cgi?id=1336530
parent 538ba840
......@@ -25,6 +25,7 @@ src/gs-main.c
src/gs-page.c
src/gs-plugin-loader.c
src/gs-popular-tile.c
[type: gettext/glade]src/gs-removal-dialog.ui
src/gs-review-dialog.c
[type: gettext/glade]src/gs-review-dialog.ui
[type: gettext/glade]src/gs-review-histogram.ui
......
......@@ -59,6 +59,7 @@ UI_FILES = \
gs-info-bar.ui \
gs-menus.ui \
gs-popular-tile.ui \
gs-removal-dialog.ui \
gs-review-dialog.ui \
gs-review-histogram.ui \
gs-review-row.ui \
......@@ -195,6 +196,8 @@ gnome_software_SOURCES = \
gs-plugin-vfuncs.h \
gs-progress-button.c \
gs-progress-button.h \
gs-removal-dialog.c \
gs-removal-dialog.h \
gs-review.c \
gs-review.h \
gs-review-bar.c \
......
......@@ -14,6 +14,7 @@
<file preprocess="xml-stripblanks">gs-history-dialog.ui</file>
<file preprocess="xml-stripblanks">gs-info-bar.ui</file>
<file preprocess="xml-stripblanks">gs-popular-tile.ui</file>
<file preprocess="xml-stripblanks">gs-removal-dialog.ui</file>
<file preprocess="xml-stripblanks">gs-review-dialog.ui</file>
<file preprocess="xml-stripblanks">gs-review-histogram.ui</file>
<file preprocess="xml-stripblanks">gs-review-row.ui</file>
......
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2016 Kalev Lember <klember@redhat.com>
*
* Licensed under the GNU General Public License Version 2
*
* 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 "gs-removal-dialog.h"
#include <glib/gi18n.h>
#include <gtk/gtk.h>
struct _GsRemovalDialog
{
GtkMessageDialog parent_instance;
GtkWidget *listbox;
GtkWidget *scrolledwindow;
};
G_DEFINE_TYPE (GsRemovalDialog, gs_removal_dialog, GTK_TYPE_MESSAGE_DIALOG)
static void
list_header_func (GtkListBoxRow *row,
GtkListBoxRow *before,
gpointer user_data)
{
GtkWidget *header = NULL;
if (before != NULL)
header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_list_box_row_set_header (row, header);
}
static gint
list_sort_func (GtkListBoxRow *a,
GtkListBoxRow *b,
gpointer user_data)
{
GObject *o1 = G_OBJECT (gtk_bin_get_child (GTK_BIN (a)));
GObject *o2 = G_OBJECT (gtk_bin_get_child (GTK_BIN (b)));
const gchar *key1 = g_object_get_data (o1, "sort");
const gchar *key2 = g_object_get_data (o2, "sort");
return g_strcmp0 (key1, key2);
}
static void
add_app (GtkListBox *listbox, GsApp *app)
{
GtkWidget *box;
GtkWidget *widget;
GtkWidget *row;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_bottom (box, 12);
gtk_widget_set_margin_end (box, 12);
widget = gtk_label_new (gs_app_get_name (app));
gtk_widget_set_halign (widget, GTK_ALIGN_START);
gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
g_object_set_data_full (G_OBJECT (box),
"sort",
g_utf8_casefold (gs_app_get_name (app), -1),
g_free);
gtk_list_box_prepend (listbox, box);
gtk_widget_show (widget);
gtk_widget_show (box);
row = gtk_widget_get_parent (box);
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
}
static void
insert_details_widget (GtkMessageDialog *dialog, GtkWidget *widget)
{
GList *children, *l;
GtkWidget *message_area;
message_area = gtk_message_dialog_get_message_area (dialog);
g_assert (GTK_IS_BOX (message_area));
/* find all label children and set the width chars properties */
children = gtk_container_get_children (GTK_CONTAINER (message_area));
for (l = children; l != NULL; l = l->next) {
if (!GTK_IS_LABEL (l->data))
continue;
gtk_label_set_width_chars (GTK_LABEL (l->data), 40);
gtk_label_set_max_width_chars (GTK_LABEL (l->data), 40);
}
gtk_container_add (GTK_CONTAINER (message_area), widget);
}
void
gs_removal_dialog_show_upgrade_removals (GsRemovalDialog *self,
GsApp *upgrade)
{
GPtrArray *removals;
guint i;
g_autofree gchar *name_version = NULL;
name_version = g_strdup_printf ("%s %s",
gs_app_get_name (upgrade),
gs_app_get_version (upgrade));
/* TRANSLATORS: This is a text displayed during a distro upgrade. %s
will be replaced by the name and version of distro, e.g. 'Fedora 23'. */
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (self),
_("Some of the currently installed software is not compatible with %s. "
"If you continue, the following will be automatically removed during the upgrade:"),
name_version);
removals = gs_app_get_related (upgrade);
for (i = 0; i < removals->len; i++) {
GsApp *app = g_ptr_array_index (removals, i);
g_autofree gchar *tmp = NULL;
if (gs_app_get_state (app) != AS_APP_STATE_UNAVAILABLE)
continue;
tmp = gs_app_to_string (app);
g_debug ("removal %d: %s", i, tmp);
add_app (GTK_LIST_BOX (self->listbox), app);
}
}
static void
gs_removal_dialog_init (GsRemovalDialog *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
insert_details_widget (GTK_MESSAGE_DIALOG (self), self->scrolledwindow);
gtk_list_box_set_header_func (GTK_LIST_BOX (self->listbox),
list_header_func,
self,
NULL);
gtk_list_box_set_sort_func (GTK_LIST_BOX (self->listbox),
list_sort_func,
self, NULL);
}
static void
gs_removal_dialog_class_init (GsRemovalDialogClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-removal-dialog.ui");
gtk_widget_class_bind_template_child (widget_class, GsRemovalDialog, listbox);
gtk_widget_class_bind_template_child (widget_class, GsRemovalDialog, scrolledwindow);
}
GtkWidget *
gs_removal_dialog_new (void)
{
GsRemovalDialog *dialog;
dialog = g_object_new (GS_TYPE_REMOVAL_DIALOG,
NULL);
return GTK_WIDGET (dialog);
}
/* vim: set noexpandtab: */
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
* Copyright (C) 2016 Kalev Lember <klember@redhat.com>
*
* Licensed under the GNU General Public License Version 2
*
* 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.
*/
#ifndef GS_REMOVAL_DIALOG_H
#define GS_REMOVAL_DIALOG_H
#include <gtk/gtk.h>
#include "gs-app.h"
G_BEGIN_DECLS
#define GS_TYPE_REMOVAL_DIALOG (gs_removal_dialog_get_type ())
G_DECLARE_FINAL_TYPE (GsRemovalDialog, gs_removal_dialog, GS, REMOVAL_DIALOG, GtkMessageDialog)
GtkWidget *gs_removal_dialog_new (void);
void gs_removal_dialog_show_upgrade_removals (GsRemovalDialog *self,
GsApp *upgrade);
G_END_DECLS
#endif /* GS_REMOVAL_DIALOG_H */
/* vim: set noexpandtab: */
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="min_content_height">160</property>
<property name="hscrollbar_policy">never</property>
<property name="vscrollbar_policy">automatic</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkFrame" id="frame">
<property name="visible">True</property>
<property name="shadow_type">in</property>
<property name="halign">fill</property>
<property name="valign">start</property>
<child>
<object class="GtkListBox" id="listbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="selection_mode">none</property>
</object>
</child>
</object>
</child>
</object>
<template class="GsRemovalDialog" parent="GtkMessageDialog">
<property name="text" translatable="yes">Incompatible Software</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<child type="action">
<object class="GtkButton" id="button_cancel">
<property name="visible">True</property>
<property name="label" translatable="yes">_Cancel</property>
<property name="use_underline">True</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="button_continue">
<property name="visible">True</property>
<property name="label" translatable="yes">_Continue</property>
<property name="use_underline">True</property>
<property name="can_default">True</property>
<property name="receives_default">True</property>
</object>
</child>
<action-widgets>
<action-widget response="accept" default="true">button_continue</action-widget>
<action-widget response="cancel">button_cancel</action-widget>
</action-widgets>
</template>
</interface>
......@@ -29,6 +29,7 @@
#include "gs-common.h"
#include "gs-app-private.h"
#include "gs-app-row.h"
#include "gs-removal-dialog.h"
#include "gs-update-dialog.h"
#include "gs-update-list.h"
#include "gs-update-monitor.h"
......@@ -580,6 +581,7 @@ gs_shell_updates_load (GsShellUpdates *self)
/* don't refresh every each time */
if ((self->result_flags & GS_SHELL_UPDATES_FLAG_HAS_UPGRADES) == 0) {
refine_flags |= GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPGRADE_REMOVED;
gs_plugin_loader_get_distro_upgrades_async (self->plugin_loader,
refine_flags,
self->cancellable,
......@@ -1106,24 +1108,86 @@ upgrade_trigger_finished_cb (GObject *source,
self);
}
static void
trigger_upgrade (GsShellUpdates *self)
{
GsApp *upgrade;
upgrade = gs_upgrade_banner_get_app (GS_UPGRADE_BANNER (self->upgrade_banner));
if (upgrade == NULL) {
g_warning ("no upgrade available to install");
return;
}
gs_plugin_loader_app_action_async (self->plugin_loader,
upgrade,
GS_PLUGIN_LOADER_ACTION_UPGRADE_TRIGGER,
self->cancellable,
upgrade_trigger_finished_cb,
self);
}
static void
gs_shell_updates_upgrade_confirm_cb (GtkDialog *dialog,
GtkResponseType response_type,
GsShellUpdates *self)
{
/* unmap the dialog */
gtk_widget_destroy (GTK_WIDGET (dialog));
switch (response_type) {
case GTK_RESPONSE_ACCEPT:
g_debug ("agreed to upgrade removing apps");
trigger_upgrade (self);
break;
case GTK_RESPONSE_CANCEL:
g_debug ("cancelled removal dialog");
break;
case GTK_RESPONSE_DELETE_EVENT:
break;
default:
g_assert_not_reached ();
}
}
static void
gs_shell_updates_upgrade_install_cb (GsUpgradeBanner *upgrade_banner,
GsShellUpdates *self)
{
GsApp *app;
GPtrArray *removals;
GsApp *upgrade;
GtkWidget *dialog;
guint cnt = 0;
guint i;
app = gs_upgrade_banner_get_app (upgrade_banner);
if (app == NULL) {
upgrade = gs_upgrade_banner_get_app (GS_UPGRADE_BANNER (self->upgrade_banner));
if (upgrade == NULL) {
g_warning ("no upgrade available to install");
return;
}
gs_plugin_loader_app_action_async (self->plugin_loader,
app,
GS_PLUGIN_LOADER_ACTION_UPGRADE_TRIGGER,
self->cancellable,
upgrade_trigger_finished_cb,
self);
/* count the removals */
removals = gs_app_get_related (upgrade);
for (i = 0; i < removals->len; i++) {
GsApp *app = g_ptr_array_index (removals, i);
if (gs_app_get_state (app) != AS_APP_STATE_UNAVAILABLE)
continue;
cnt++;
}
if (cnt == 0) {
/* no need for a removal confirmation dialog */
trigger_upgrade (self);
return;
}
dialog = gs_removal_dialog_new ();
g_signal_connect (dialog, "response",
G_CALLBACK (gs_shell_updates_upgrade_confirm_cb),
self);
gs_removal_dialog_show_upgrade_removals (GS_REMOVAL_DIALOG (dialog),
upgrade);
gs_shell_modal_dialog_present (self->shell, GTK_DIALOG (dialog));
}
static void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment