Commit e5919980 authored by Petr Štětka's avatar Petr Štětka
Browse files

Add multiselect support in storage.

parent 7ceace35
......@@ -7,11 +7,11 @@ New GNOME Usage!
- [x] Memory usage
- [x] Network usage
- [x] Search in processes
- [ ] Multiselection in storage
- [ ] UI for file operations errors (as duplicate file, not enough space, permission...)
- [ ] Notification for file operations and rollback
- [ ] UI for show progress about file operations
- [ ] Notification for file operations with undo action
- [ ] Storage support for more users (multiuser system)
- [ ] Application section in storage
- [ ] Application in storage
- [ ] Power view (Design?)
- [ ] Disk usage (What library we can use?)
- [ ] Data view - 0%
......
......@@ -12,6 +12,7 @@ src/network-sub-view.vala
src/performance-view.vala
src/power-view.vala
src/process-dialog.vala
src/storage-actionbar.vala
src/storage-analyzer.vala
src/storage-item.vala
src/storage-row.vala
......
......@@ -79,7 +79,8 @@ namespace Usage
translator_credits: _("translator-credits"),
website: "https://wiki.gnome.org/Apps/Usage",
website_label: _("Websites"),
version: Config.VERSION,
version: Config.VERSION, //messon
//version: Constants.VERSION, //autovala
license_type: License.GPL_3_0);
}
......
public static int main (string[] args)
{
// messon
Intl.bindtextdomain(Config.GETTEXT_PACKAGE, Config.GNOMELOCALEDIR);
Intl.setlocale(LocaleCategory.ALL, "");
Intl.textdomain(Config.GETTEXT_PACKAGE);
Intl.bind_textdomain_codeset(Config.GETTEXT_PACKAGE, "utf-8");
//Autovala
/*Intl.bindtextdomain(Constants.GETTEXT_PACKAGE, Path.build_filename(Constants.DATADIR,"locale"));
Intl.setlocale(LocaleCategory.ALL, "");
Intl.textdomain(Constants.GETTEXT_PACKAGE);
Intl.bind_textdomain_codeset(Constants.GETTEXT_PACKAGE, "utf-8");*/
var application = new Usage.Application();
return application.run(args);
}
......@@ -15,11 +15,20 @@ namespace Usage
private bool active_performance_search_btn = false;
private Gtk.Button? storage_back_button;
private Gtk.Button? storage_rescan_button;
private Gtk.Button? storage_select_button;
private Gtk.Button? storage_cancel_button;
private Gtk.MenuButton? storage_selection_menu;
private bool show_storage_back_btn = false;
private bool show_storage_rescan_btn = false;
private bool show_storage_select_btn = false;
private string title_text = "";
private HeaderBarMode mode;
const GLib.ActionEntry[] select_action_entries = {
{ "select-all", select_all },
{ "select-none", select_none },
};
public HeaderBar(Gtk.Stack stack)
{
mode = HeaderBarMode.PERFORMANCE;
......@@ -45,8 +54,13 @@ namespace Usage
case HeaderBarMode.STORAGE:
remove_widget(storage_back_button);
remove_widget(storage_rescan_button);
remove_widget(storage_select_button);
remove_widget(storage_cancel_button);
storage_rescan_button = null;
storage_back_button = null;
storage_select_button = null;
storage_select_button = null;
storage_cancel_button = null;
break;
case HeaderBarMode.POWER:
break;
......@@ -83,15 +97,29 @@ namespace Usage
storage_rescan_button = new Gtk.Button.from_icon_name("view-refresh-symbolic");
storage_rescan_button.clicked.connect(() => {
show_stack_switcher();
show_storage_select_button(false);
show_storage_rescan_button(false);
show_storage_back_button(false);
(GLib.Application.get_default() as Application).get_storage_analyzer().create_cache.begin(true);
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().reload();
});
storage_select_button = new Gtk.Button.from_icon_name("emblem-ok-symbolic");
storage_select_button.clicked.connect(() => {
show_storage_selection_mode(true);
});
show_storage_select_button(show_storage_select_btn);
show_storage_rescan_button(show_storage_rescan_btn);
storage_cancel_button = new Gtk.Button.with_label(_("Cancel"));
storage_cancel_button.clicked.connect(() => {
show_storage_selection_mode(false);
});
pack_start(storage_back_button);
pack_end(storage_select_button);
pack_end(storage_rescan_button);
pack_end(storage_cancel_button);
break;
case HeaderBarMode.POWER:
show_stack_switcher();
......@@ -100,10 +128,15 @@ namespace Usage
this.mode = mode;
}
private void remove_widget(Gtk.Widget? widget)
public void change_selected_items(uint count)
{
if(widget != null)
remove(widget);
if(storage_selection_menu != null)
{
if(count > 0)
storage_selection_menu.label = ngettext ("%u selected", "%u selected", count).printf (count);
else
storage_selection_menu.label = _("Click on items to select them");
}
}
public HeaderBarMode get_mode()
......@@ -159,6 +192,22 @@ namespace Usage
}
}
public void show_storage_select_button(bool show)
{
if(show)
{
if(storage_select_button != null)
storage_select_button.show();
show_storage_select_btn = true;
}
else
{
if(storage_select_button != null)
storage_select_button.hide();
show_storage_select_btn = false;
}
}
public void action_on_search()
{
switch(mode)
......@@ -172,5 +221,76 @@ namespace Usage
break;
}
}
public void show_storage_selection_mode(bool show)
{
if(show)
{
show_storage_rescan_button(false);
show_storage_select_button(false);
storage_back_button.hide();
storage_cancel_button.show();
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).show_action_bar(true);
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().set_select_mode(true);
var menu = new GLib.Menu ();
var item = new GLib.MenuItem (_("Select all"), "headerbar.select-all");
item.set_attribute("accel", "s", "<Primary>a");
menu.append_item(item);
item = new GLib.MenuItem (_("Select None"), "headerbar.select-none");
menu.append_item(item);
storage_selection_menu = new Gtk.MenuButton();
storage_selection_menu.get_style_context().add_class("selection-menu");
storage_selection_menu.set_menu_model(menu);
var action_group = new GLib.SimpleActionGroup ();
action_group.add_action_entries (select_action_entries, this);
storage_selection_menu.get_popover().insert_action_group ("headerbar", action_group);
storage_selection_menu.show();
set_custom_title(storage_selection_menu);
change_selected_items(0);
this.get_style_context().add_class("selection-mode");
this.show_close_button = false;
}
else
{
if(show_storage_back_btn)
storage_back_button.show();
show_storage_rescan_button(true);
show_storage_select_button(true);
storage_cancel_button.hide();
storage_selection_menu = null;
if(title_text == "")
show_stack_switcher();
else
show_title();
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).show_action_bar(false);
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().set_select_mode(false);
this.get_style_context().remove_class("selection-mode");
this.show_close_button = true;
}
}
private void select_all()
{
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().select_all_rows();
}
private void select_none()
{
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().unselect_all_rows();
}
private void remove_widget(Gtk.Widget? widget)
{
if(widget != null)
remove(widget);
}
}
}
\ No newline at end of file
......@@ -31,6 +31,7 @@ vala_sources = [
'process-row.vala',
'process.vala',
'settings.vala',
'storage-actionbar.vala',
'storage-analyzer.vala',
'storage-graph.vala',
'storage-item.vala',
......
namespace Usage
{
public class StorageActionBar : Gtk.ActionBar
{
private Gtk.Button move_to_button;
private Gtk.Button delete_button;
private Gtk.Button move_to_trash_button;
private Gtk.Button empty_folder_button;
private Gtk.Button restore_button;
private Gtk.Button delete_from_trash_button;
public StorageActionBar()
{
//common
move_to_button = new Gtk.Button.with_label(_("Move to"));
move_to_button.clicked.connect(move_to_clicked);
delete_button = new Gtk.Button.with_label(_("Delete"));
delete_button.clicked.connect(delete_clicked);
delete_button.get_style_context().add_class ("destructive-action");
move_to_trash_button = new Gtk.Button.with_label(_("Move to Trash"));
move_to_trash_button.clicked.connect(move_to_trash_clicked);
this.pack_start(move_to_button);
this.pack_end(delete_button);
this.pack_end(move_to_trash_button);
//root
empty_folder_button = new Gtk.Button.with_label(_("Empty folder"));
empty_folder_button.clicked.connect(empty_folder_clicked);
this.pack_end(empty_folder_button);
//trash
restore_button = new Gtk.Button.with_label(_("Restore"));
restore_button.clicked.connect(restore_clicked);
delete_from_trash_button = new Gtk.Button.with_label(_("Delete from Trash"));
delete_from_trash_button.clicked.connect(delete_from_trash_clicked);
delete_from_trash_button.get_style_context().add_class ("destructive-action");
this.pack_start(restore_button);
this.pack_end(delete_from_trash_button);
hide_all();
}
public void show_common()
{
hide_all();
move_to_button.visible = true;
delete_button.visible = true;
move_to_trash_button.visible = true;
}
public void show_root()
{
hide_all();
empty_folder_button.visible = true;
}
public void show_trash()
{
hide_all();
restore_button.visible = true;
delete_from_trash_button.visible = true;
}
public void hide_all()
{
move_to_button.set_visible(false);
delete_button.set_visible(false);
move_to_trash_button.set_visible(false);
empty_folder_button.set_visible(false);
restore_button.set_visible(false);
delete_from_trash_button.set_visible(false);
}
public void set_sensitive_all(bool sensitive)
{
move_to_button.set_sensitive(sensitive);
delete_button.set_sensitive(sensitive);
move_to_trash_button.set_sensitive(sensitive);
empty_folder_button.set_sensitive(sensitive);
restore_button.set_sensitive(sensitive);
delete_from_trash_button.set_sensitive(sensitive);
}
private void move_to_clicked()
{
Gtk.FileChooserDialog chooser = new Gtk.FileChooserDialog (
_("Select destination folder"), (GLib.Application.get_default() as Application).get_window(), Gtk.FileChooserAction.SELECT_FOLDER,
_("Cancel"),
Gtk.ResponseType.CANCEL,
_("Select"),
Gtk.ResponseType.ACCEPT);
chooser.destroy_with_parent = true;
Gtk.FileFilter filter = new Gtk.FileFilter();
filter.add_custom(Gtk.FileFilterFlags.FILENAME, (filter_info) => {
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
if(filter_info.filename == storage_row.get_item_path())
return false;
}
return true;
});
chooser.set_filter(filter);
StorageRow storage_row = (StorageRow) ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_row();
chooser.set_filename(storage_row.get_item_path());
chooser.show();
if(chooser.run() == Gtk.ResponseType.ACCEPT)
{
Timeout.add(0, () => {
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow actual_storage_row = (StorageRow) row;
string destination = chooser.get_file().get_parse_name() + "/" + Path.get_basename(actual_storage_row.get_item_path());
var storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
storage_analyzer.move_file.begin(File.new_for_path(actual_storage_row.get_item_path()), File.new_for_path(destination), () => {
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().refresh();
});
}
hide_selection_mode();
return false;
});
}
chooser.destroy();
}
private void delete_clicked()
{
string files = "";
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
if(files != "")
files += ", ";
files += storage_row.get_item_name();
}
var dialog = new Gtk.MessageDialog ((GLib.Application.get_default() as Application).get_window(), Gtk.DialogFlags.MODAL,
Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, _("Are you sure you want to permanently delete this items %s?").printf(files));
dialog.secondary_text = _("If you delete these items, they will be permanently lost.");
if(dialog.run() == Gtk.ResponseType.OK)
{
Timeout.add(0, () => {
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
var storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
storage_analyzer.delete_file.begin(storage_row.get_item_path(), () => {
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().refresh();
});
}
hide_selection_mode();
return false;
});
}
dialog.destroy();
}
private void move_to_trash_clicked()
{
Timeout.add(0, () => {
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
var storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
storage_analyzer.trash_file.begin(storage_row.get_item_path(), () => {
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().refresh();
});
}
hide_selection_mode();
return false;
});
}
private void empty_folder_clicked()
{
Timeout.add(0, () => {
string folders = "";
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
if(storage_row.get_item_type() == StorageItemType.TRASH)
{
var dialog = new Gtk.MessageDialog ((GLib.Application.get_default() as Application).get_window(), Gtk.DialogFlags.MODAL,
Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, _("Empty all items from Trash?"));
dialog.secondary_text = _("All items in the Trash will be permanently deleted.");
if(dialog.run() == Gtk.ResponseType.OK)
{
var storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
storage_analyzer.wipe_trash.begin(() => {
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().refresh();
});
}
dialog.destroy();
}
else
{
if(folders != "")
folders += ", ";
folders += storage_row.get_item_name();
}
}
if(folders != "")
{
var dialog = new Gtk.MessageDialog ((GLib.Application.get_default() as Application).get_window(), Gtk.DialogFlags.MODAL,
Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, _("Empty all items from %s?").printf(folders));
dialog.secondary_text = _("All items in the %s will be moved to the Trash.").printf(folders);
if(dialog.run() == Gtk.ResponseType.OK)
{
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
var storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
storage_analyzer.wipe_folder.begin(storage_row.get_item_path(), () => {
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().refresh();
});
}
}
dialog.destroy();
}
hide_selection_mode();
return false;
});
}
private void restore_clicked()
{
Timeout.add(0, () => {
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
var storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
storage_analyzer.restore_trash_file.begin(storage_row.get_item_path(), () => {
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().refresh();
});
}
hide_selection_mode();
return false;
});
}
private void delete_from_trash_clicked()
{
Timeout.add(0, () => {
foreach (Gtk.ListBoxRow row in ((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().get_selected_rows())
{
StorageRow storage_row = (StorageRow) row;
var storage_analyzer = (GLib.Application.get_default() as Application).get_storage_analyzer();
storage_analyzer.delete_trash_file.begin(storage_row.get_item_path(), () => {
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_storage_list_box().refresh();
});
}
hide_selection_mode();
return false;
});
}
private void hide_selection_mode()
{
(GLib.Application.get_default() as Application).get_window().get_header_bar().show_storage_selection_mode(false);
}
}
}
\ No newline at end of file
......@@ -760,7 +760,7 @@ namespace Usage
GTop.get_fsusage(out root, mountdir);
Storage storage = Storage();
storage.free = root.bfree * root.block_size; //TODO bavail or bfree
storage.free = root.bfree * root.block_size;
storage.total = root.blocks * root.block_size;
storage.used = storage.total - storage.free;
storage.name = (string) entries[i].devname;
......
......@@ -26,6 +26,7 @@ namespace Usage
bind_model(model, on_row_created);
row_activated.connect(on_row_activated);
selected_rows_changed.connect(on_selected_rows_changed);
path_history = new List<string>();
name_history = new List<string>();
......@@ -75,6 +76,10 @@ namespace Usage
{
(GLib.Application.get_default() as Application).get_window().get_header_bar().set_title_text(actual_name);
(GLib.Application.get_default() as Application).get_window().get_header_bar().show_title();
if(actual_parent_type == StorageItemType.TRASHFILE || actual_parent_type == StorageItemType.TRASHSUBFILE)
(GLib.Application.get_default() as Application).get_window().get_header_bar().show_storage_select_button(false);
else
(GLib.Application.get_default() as Application).get_window().get_header_bar().show_storage_select_button(true);
}
}
......@@ -96,6 +101,9 @@ namespace Usage
}
header_bar.show_storage_rescan_button(true);
if(actual_parent_type != StorageItemType.TRASHFILE && actual_parent_type != StorageItemType.TRASHSUBFILE)
(GLib.Application.get_default() as Application).get_window().get_header_bar().show_storage_select_button(true);
loaded();
this.show();
model.remove_all();
......@@ -114,6 +122,79 @@ namespace Usage
load(actual_path, actual_parent_type);
}
public void set_select_mode(bool select_mode)
{
if(select_mode)
{
set_selection_mode (Gtk.SelectionMode.MULTIPLE);
this.forall ((child) => {
var row = child as StorageRow;
if (row == null)
return;
row.set_show_check_button(true);
});
if(root)
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_action_bar().show_root();
else if(actual_parent_type == StorageItemType.TRASH)
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_action_bar().show_trash();
else if(actual_parent_type != StorageItemType.TRASHFILE && actual_parent_type != StorageItemType.TRASHSUBFILE)
((StorageView) (GLib.Application.get_default() as Application).get_window().get_views()[2]).get_action_bar().show_common();
on_selected_rows_changed();
}
else
{
set_selection_mode (Gtk.SelectionMode.NONE);
this.forall ((child) => {
var row = child as StorageRow;
if (row == null)
return;
row.set_show_check_button(false);
});
}
}
public bool get_select_mode()
{
if(get_selection_mode() == Gtk.SelectionMode.MULTIPLE)
return true;
else
return false;