[gnome-boxes] Be more friendly to user on deletion of boxes
- From: Zeeshan Ali Khattak <zeeshanak src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-boxes] Be more friendly to user on deletion of boxes
- Date: Fri, 16 Dec 2011 23:16:26 +0000 (UTC)
commit 1185a276c3c6f5e6c4a7c91fbdbc8da3a6145c24
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date: Thu Dec 15 15:08:04 2011 +0200
Be more friendly to user on deletion of boxes
On deletion of a box by the user:
- Hide the box immediately but don't delete it yet.
- Display a notification with an 'Undo' button.
- Delete the box if user doesn't hit the 'Undo' button or ignores the
notification for 6 seconds. Otherwise, add it back to the view.
https://bugzilla.gnome.org/show_bug.cgi?id=666334
data/gtk-style.css | 4 ++
src/Makefile.am | 1 +
src/app.vala | 41 ++++++++++++++---
src/notificationbar.vala | 108 ++++++++++++++++++++++++++++++++++++++++++++++
src/selectionbar.vala | 3 +-
5 files changed, 148 insertions(+), 9 deletions(-)
---
diff --git a/data/gtk-style.css b/data/gtk-style.css
index 5286f2e..ff83949 100644
--- a/data/gtk-style.css
+++ b/data/gtk-style.css
@@ -142,6 +142,10 @@
border-width: 0;
}
+GtkInfoBar {
+ -GtkInfoBar-action-area-border: 0;
+}
+
BoxesMenuBox .menuitem {
background-color: @boxes_bg2_color;
border-radius: 15;
diff --git a/src/Makefile.am b/src/Makefile.am
index 4d529a5..9f203cc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -63,6 +63,7 @@ gnome_boxes_SOURCES = \
winxp-installer.vala \
wizard-source.vala \
wizard.vala \
+ notificationbar.vala \
$(NULL)
gnome_boxes_LDADD = $(BOXES_LIBS)
diff --git a/src/app.vala b/src/app.vala
index 6a1e9fe..df93bd2 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -28,6 +28,7 @@ private class Boxes.App: Boxes.UI {
public Clutter.Box box; // the whole app box
public CollectionItem current_item; // current object/vm manipulated
public Topbar topbar;
+ public Notificationbar notificationbar;
public Sidebar sidebar;
public Selectionbar selectionbar;
public uint duration;
@@ -249,11 +250,18 @@ private class Boxes.App: Boxes.UI {
sidebar = new Sidebar (this);
view = new CollectionView (this, sidebar.category);
topbar = new Topbar (this);
+ notificationbar = new Notificationbar (this);
+ notificationbar.actor.add_constraint (new Clutter.AlignConstraint (view.actor, AlignAxis.X_AXIS, 0.5f));
+ var yconstraint = new Clutter.BindConstraint (topbar.actor, BindCoordinate.Y, topbar.height);
+ notificationbar.actor.add_constraint (yconstraint);
+ topbar.actor.notify["height"].connect (() => {
+ yconstraint.set_offset (topbar.height);
+ });
selectionbar = new Selectionbar (this);
selectionbar.actor.add_constraint (new Clutter.AlignConstraint (view.actor, AlignAxis.X_AXIS, 0.5f));
- var yconstraint = new Clutter.BindConstraint (view.actor, BindCoordinate.Y,
- view.actor.height - selectionbar.spacing);
+ yconstraint = new Clutter.BindConstraint (view.actor, BindCoordinate.Y,
+ view.actor.height - selectionbar.spacing);
selectionbar.actor.add_constraint (yconstraint);
view.actor.notify["height"].connect (() => {
yconstraint.set_offset (view.actor.height - selectionbar.spacing);
@@ -349,13 +357,32 @@ private class Boxes.App: Boxes.UI {
owned get { return view.get_selected_items (); }
}
- public void remove_item (CollectionItem item) {
- var machine = item as Machine;
+ public void remove_selected_items () {
+ var selected_items = view.get_selected_items ();
+ var num_selected = selected_items.length ();
+ if (num_selected == 0)
+ return;
+
+ var message = (num_selected == 1) ? _("Box '%s' has been deleted").printf (selected_items.data.name) :
+ _("%u boxes have been deleted").printf (num_selected);
+ foreach (var item in selected_items)
+ view.remove_item (item);
- if (machine != null)
- machine.delete ();
+ Notificationbar.ActionFunc undo = () => {
+ foreach (var selected in selected_items)
+ view.add_item (selected);
+ };
+
+ Notificationbar.IgnoreFunc really_remove = () => {
+ foreach (var selected in selected_items) {
+ var machine = selected as Machine;
+
+ if (machine != null)
+ machine.delete ();
+ }
+ };
- view.remove_item (item);
+ notificationbar.display (Gtk.Stock.UNDO, message, (owned) undo, (owned) really_remove);
}
private bool on_key_pressed (Widget widget, Gdk.EventKey event) {
diff --git a/src/notificationbar.vala b/src/notificationbar.vala
new file mode 100644
index 0000000..2fce919
--- /dev/null
+++ b/src/notificationbar.vala
@@ -0,0 +1,108 @@
+// This file is part of GNOME Boxes. License: LGPLv2+
+using Gtk;
+
+private class Boxes.Notificationbar: GLib.Object {
+ public Clutter.Actor actor { get; private set; }
+ public static const float spacing = 60.0f;
+
+ public delegate void ActionFunc ();
+ public delegate void IgnoreFunc ();
+
+ private App app;
+ private InfoBar info_bar;
+ private Label label;
+ private Button action_button;
+
+ private uint timeout_id;
+ private ulong response_id;
+
+ public Notificationbar (App app) {
+ this.app = app;
+
+ setup_action_notify ();
+ }
+
+ public void display (string action_label,
+ string action_message,
+ owned ActionFunc action_func,
+ owned IgnoreFunc? ignore_func = null) {
+ action_button.label = action_label;
+ label.label = action_message;
+
+ // Replace running notification, if any
+ if (timeout_id != 0) {
+ Source.remove (timeout_id);
+ info_bar.disconnect (response_id);
+ }
+
+ timeout_id = Timeout.add_seconds (6, () => {
+ info_bar.response (ResponseType.CANCEL);
+
+ return false;
+ });
+
+ response_id = info_bar.response.connect ((response) => {
+ hide ();
+
+ Source.remove (timeout_id);
+ info_bar.disconnect (response_id);
+ timeout_id = 0;
+ response_id = 0;
+
+ if (response == ResponseType.OK)
+ action_func ();
+ else {
+ if (ignore_func != null)
+ ignore_func ();
+ }
+ });
+
+ show ();
+ }
+
+ private void setup_action_notify () {
+ info_bar = new InfoBar ();
+ info_bar.get_style_context ().add_class ("osd");
+ info_bar.spacing = 120;
+ info_bar.margin = 5;
+
+ label = new Label ("");
+ var content_area = info_bar.get_content_area () as Container;
+ content_area.add (label);
+
+ action_button = new Button ();
+ info_bar.add_action_widget (action_button, ResponseType.OK);
+ action_button.use_stock = true;
+
+ var image = new Image.from_icon_name ("window-close-symbolic", IconSize.BUTTON);
+ var close_button = new Button ();
+ close_button.image = image;
+ info_bar.add_action_widget (close_button, ResponseType.CANCEL);
+ close_button.relief = ReliefStyle.NONE;
+ close_button.halign = Align.START;
+
+ var button_box = info_bar.get_action_area () as ButtonBox;
+ button_box.orientation = Orientation.HORIZONTAL;
+ button_box.set_child_non_homogeneous (close_button, true);
+ info_bar.set_message_type (MessageType.INFO);
+
+ info_bar.show_all ();
+
+ actor = new GtkClutter.Actor.with_contents (info_bar);
+ app.stage.add (actor);
+ actor.hide ();
+ actor.scale_y = 0f;
+ }
+
+ private void show () {
+ actor.show ();
+ actor.queue_redraw ();
+ actor.animate (Clutter.AnimationMode.LINEAR, app.duration, "scale-y", 1f);
+ }
+
+ private void hide () {
+ var animation = actor.animate (Clutter.AnimationMode.LINEAR, app.duration, "scale-y", 0f);
+ animation.completed.connect (() => { actor.hide (); });
+ }
+}
+
diff --git a/src/selectionbar.vala b/src/selectionbar.vala
index 0597d5d..524f4e6 100644
--- a/src/selectionbar.vala
+++ b/src/selectionbar.vala
@@ -41,8 +41,7 @@ private class Boxes.Selectionbar: GLib.Object {
toolbar.insert (remove_btn, 2);
remove_btn.icon_name = "edit-delete-symbolic";
remove_btn.clicked.connect (() => {
- foreach (var item in app.selected_items)
- app.remove_item (item);
+ app.remove_selected_items ();
});
toolbar.show_all ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]