/* * pamac-vala * * Copyright (C) 2017 Chris Cromer * Copyright (C) 2014-2017 Guillaume Benoit * * 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 get of the GNU General Public License * along with this program. If not, see . */ //using GIO const string VERSION = Constants.VERSION; namespace Pamac { class ActivableCellRendererPixbuf : Gtk.CellRendererPixbuf { public signal void activated (Gtk.TreePath path); public ActivableCellRendererPixbuf () { Object (); this.mode = Gtk.CellRendererMode.ACTIVATABLE; } public override bool activate (Gdk.Event event, Gtk.Widget widget, string path, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) { activated (new Gtk.TreePath.from_string (path)); return true; } } [GtkTemplate (ui = "/org/pamac/manager/interface/manager_window.ui")] class ManagerWindow : Gtk.ApplicationWindow { // icons Gdk.Pixbuf? installed_icon; Gdk.Pixbuf? uninstalled_icon; Gdk.Pixbuf? to_install_icon; Gdk.Pixbuf? to_reinstall_icon; Gdk.Pixbuf? to_remove_icon; Gdk.Pixbuf? to_upgrade_icon; Gdk.Pixbuf? installed_locked_icon; Gdk.Pixbuf? available_locked_icon; // manager objects [GtkChild] public unowned Gtk.Stack main_stack; [GtkChild] unowned Gtk.Button button_back; [GtkChild] unowned Gtk.MenuButton button_menu; #if ENABLE_HAMBURGER [GtkChild] unowned Gtk.ModelButton preferences_button; #else [GtkChild] unowned Gtk.HeaderBar headerbar; #endif [GtkChild] unowned Gtk.TreeView packages_treeview; [GtkChild] unowned Gtk.TreeViewColumn packages_state_column; #if DISABLE_AUR [GtkChild] unowned Gtk.ScrolledWindow aur_scrolledwindow; #else [GtkChild] unowned Gtk.TreeView aur_treeview; [GtkChild] unowned Gtk.TreeViewColumn aur_state_column; #endif [GtkChild] public unowned Gtk.Stack filters_stack; [GtkChild] unowned Gtk.StackSwitcher filters_stackswitcher; [GtkChild] unowned Gtk.SearchEntry search_entry; [GtkChild] unowned Gtk.TreeView search_treeview; [GtkChild] unowned Gtk.TreeView groups_treeview; [GtkChild] unowned Gtk.TreeView states_treeview; [GtkChild] unowned Gtk.TreeView repos_treeview; [GtkChild] unowned Gtk.Stack packages_stack; [GtkChild] unowned Gtk.StackSwitcher packages_stackswitcher; [GtkChild] unowned Gtk.Label updated_label; [GtkChild] unowned Gtk.Stack properties_stack; #if DISABLE_AUR #else [GtkChild] unowned Gtk.StackSwitcher properties_stackswitcher; #endif [GtkChild] unowned Gtk.Grid deps_grid; [GtkChild] unowned Gtk.Grid details_grid; [GtkChild] unowned Gtk.ScrolledWindow files_scrolledwindow; [GtkChild] unowned Gtk.Label name_label; [GtkChild] unowned Gtk.Label desc_label; [GtkChild] unowned Gtk.Label link_label; [GtkChild] unowned Gtk.Label licenses_label; [GtkChild] unowned Gtk.ToggleButton remove_togglebutton; [GtkChild] unowned Gtk.ToggleButton reinstall_togglebutton; [GtkChild] unowned Gtk.ToggleButton install_togglebutton; [GtkChild] unowned Gtk.TextView files_textview; [GtkChild] unowned Gtk.Box transaction_infobox; [GtkChild] unowned Gtk.Button details_button; [GtkChild] unowned Gtk.Button apply_button; [GtkChild] unowned Gtk.Button cancel_button; // menu Gtk.Menu right_click_menu; Gtk.MenuItem deselect_item; Gtk.MenuItem upgrade_item; Gtk.MenuItem install_item; Gtk.MenuItem remove_item; Gtk.MenuItem details_item; GLib.List selected_pkgs; #if DISABLE_AUR #else GLib.List selected_aur; #endif // liststores Gtk.ListStore search_list; Gtk.ListStore groups_list; Gtk.ListStore states_list; Gtk.ListStore repos_list; Gtk.ListStore packages_list; #if DISABLE_AUR #else Gtk.ListStore aur_list; #endif public Queue display_package_queue; string current_package_displayed; public Transaction transaction; delegate void TransactionAction (); bool refreshing; bool important_details; bool transaction_running; bool sysupgrade_running; bool generate_mirrors_list; bool waiting; bool force_refresh; uint search_entry_timeout_id; public ManagerWindow (Gtk.Application application) { Object (application: application, title: "Pamac"); #if ENABLE_HAMBURGER button_menu.toggled.connect (on_menu_button_toggled); #else headerbar.remove(button_menu); // connect the menu var action = new SimpleAction ("refreshdb", null); action.activate.connect (on_refresh_button_clicked); this.add_action (action); action = new SimpleAction ("viewhistory", null); action.activate.connect (on_history_button_clicked); this.add_action (action); action = new SimpleAction ("installlocal", null); action.activate.connect (on_local_button_clicked); this.add_action (action); action = new SimpleAction ("preferences", null); action.activate.connect (on_preferences_button_clicked); this.add_action (action); action = new SimpleAction ("about", null); action.activate.connect (on_about_button_clicked); this.add_action (action); #endif #if DISABLE_AUR packages_stack.remove (aur_scrolledwindow); packages_stackswitcher.visible = false; #else support_aur (false); aur_treeview.row_activated.connect (on_aur_treeview_row_activated); aur_treeview.button_press_event.connect (on_aur_treeview_button_press_event); aur_treeview.query_tooltip.connect (on_aur_treeview_query_tooltip); #endif button_back.visible = false; transaction_infobox.visible = false; refreshing = false; important_details = false; transaction_running = false; sysupgrade_running = false; generate_mirrors_list = false; this.title = dgettext (null, "Package Manager"); updated_label.set_markup ("%s".printf (dgettext (null, "Your system is up-to-date"))); while (Gtk.events_pending ()) { Gtk.main_iteration (); } right_click_menu = new Gtk.Menu (); deselect_item = new Gtk.MenuItem.with_label (dgettext (null, "Deselect")); deselect_item.activate.connect (on_deselect_item_activate); right_click_menu.append (deselect_item); upgrade_item = new Gtk.MenuItem.with_label (dgettext (null, "Upgrade")); upgrade_item.activate.connect (on_upgrade_item_activate); right_click_menu.append (upgrade_item); install_item = new Gtk.MenuItem.with_label (dgettext (null, "Install")); install_item.activate.connect (on_install_item_activate); right_click_menu.append (install_item); remove_item = new Gtk.MenuItem.with_label (dgettext (null, "Remove")); remove_item.activate.connect (on_remove_item_activate); right_click_menu.append (remove_item); var separator_item = new Gtk.SeparatorMenuItem (); right_click_menu.append (separator_item); details_item = new Gtk.MenuItem.with_label (dgettext (null, "Details")); details_item.activate.connect (on_details_item_activate); right_click_menu.append (details_item); right_click_menu.show_all (); search_list = new Gtk.ListStore (1, typeof (string)); search_treeview.set_model (search_list); groups_list = new Gtk.ListStore (1, typeof (string)); groups_treeview.set_model (groups_list); states_list = new Gtk.ListStore (1, typeof (string)); states_treeview.set_model (states_list); repos_list = new Gtk.ListStore (1, typeof (string)); repos_treeview.set_model (repos_list); packages_list = new Gtk.ListStore (7, typeof (uint), //origin typeof (string), //name typeof (string), //name+desc typeof (string), //version typeof (string), //repo typeof (uint64), //isize typeof (string)); //GLib.format (isize) packages_treeview.set_model (packages_list); // add custom cellrenderer to packages_treeview and aur_treewiew var packages_state_renderer = new ActivableCellRendererPixbuf (); packages_state_column.pack_start (packages_state_renderer, false); packages_state_column.set_cell_data_func (packages_state_renderer, (celllayout, cellrenderer, treemodel, treeiter) => { Gdk.Pixbuf pixbuf; uint origin; string pkgname; treemodel.get (treeiter, 0, out origin, 1, out pkgname); if (origin == 2) { //origin == Alpm.Package.From.LOCALDB if (unlikely (transaction.transaction_summary.contains (pkgname))) { pixbuf = installed_locked_icon; } else if (unlikely (transaction.should_hold (pkgname))) { pixbuf = installed_locked_icon; } else if (unlikely (transaction.to_install.contains (pkgname))) { pixbuf = to_reinstall_icon; } else if (unlikely (transaction.to_remove.contains (pkgname))) { pixbuf = to_remove_icon; } else { pixbuf = installed_icon; } } else if (unlikely (transaction.transaction_summary.contains (pkgname))) { pixbuf = available_locked_icon; } else if (unlikely (transaction.to_install.contains (pkgname))) { pixbuf = to_install_icon; } else if (unlikely (transaction.to_update.contains (pkgname))) { pixbuf = to_upgrade_icon; } else { pixbuf = uninstalled_icon; } cellrenderer.set ("pixbuf", pixbuf); }); packages_state_renderer.activated.connect (on_packages_state_icon_activated); #if DISABLE_AUR #else aur_list = new Gtk.ListStore (6, typeof (uint), //origin typeof (string), //name typeof (string), //name+desc typeof (string), //version typeof (double), //popularity typeof (string)); //populariy to string // sort packages by popularity by default aur_list.set_sort_column_id (4, Gtk.SortType.DESCENDING); aur_treeview.set_model (aur_list); // add custom cellrenderer to aur_treewiew var aur_state_renderer = new ActivableCellRendererPixbuf (); aur_state_column.pack_start (aur_state_renderer, false); aur_state_column.set_cell_data_func (aur_state_renderer, (celllayout, cellrenderer, treemodel, treeiter) => { Gdk.Pixbuf pixbuf; uint origin; string pkgname; treemodel.get (treeiter, 0, out origin, 1, out pkgname); if (filters_stack.visible_child_name == "updates") { if (unlikely (transaction.temporary_ignorepkgs.contains (pkgname))) { pixbuf = uninstalled_icon; } else { pixbuf = to_upgrade_icon; } } else if ((uint) origin == 2) { //origin == Alpm.Package.From.LOCALDB if (unlikely (transaction.transaction_summary.contains (pkgname))) { pixbuf = installed_locked_icon; } else if (unlikely (transaction.should_hold (pkgname))) { pixbuf = installed_locked_icon; } else if (unlikely (transaction.to_install.contains (pkgname))) { pixbuf = to_reinstall_icon; } else if (unlikely (transaction.to_remove.contains (pkgname))) { pixbuf = to_remove_icon; } else { pixbuf = installed_icon; } } else if (unlikely (transaction.to_build.contains (pkgname))) { pixbuf = to_install_icon; } else { pixbuf = uninstalled_icon; } cellrenderer.set ("pixbuf", pixbuf); }); aur_state_renderer.activated.connect (on_aur_state_icon_activated); #endif try { installed_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-installed-updated.png"); uninstalled_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-available.png"); to_install_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-install.png"); to_reinstall_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-reinstall.png"); to_remove_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-remove.png"); to_upgrade_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-upgrade.png"); installed_locked_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-installed-locked.png"); available_locked_icon = new Gdk.Pixbuf.from_resource ("/org/pamac/manager/pixmaps/package-available-locked.png"); } catch (GLib.Error e) { stderr.printf (e.message); } transaction = new Transaction (this as Gtk.ApplicationWindow); transaction.start_downloading.connect (on_start_downloading); transaction.stop_downloading.connect (on_stop_downloading); #if DISABLE_AUR #else transaction.start_building.connect (on_start_building); transaction.stop_building.connect (on_stop_building); #endif transaction.important_details_outpout.connect (on_important_details_outpout); transaction.finished.connect (on_transaction_finished); #if DISABLE_AUR #else transaction.save_pamac_config_finished.connect (on_save_pamac_config_finished); #endif transaction.set_pkgreason_finished.connect (on_set_pkgreason_finished); transaction.generate_mirrors_list.connect (on_generate_mirrors_list); transaction.run_preferences_dialog_finished.connect (on_run_preferences_dialog_finished); transaction.get_updates_finished.connect (on_get_updates_finished); // integrate progress box and term widget main_stack.add_named (transaction.term_window, "term"); transaction_infobox.pack_start (transaction.progress_box); #if DISABLE_AUR #else support_aur (transaction.enable_aur); #endif display_package_queue = new Queue (); main_stack.notify["visible-child"].connect (on_main_stack_visible_child_changed); filters_stack.notify["visible-child"].connect (on_filters_stack_visible_child_changed); packages_stack.notify["visible-child"].connect (on_packages_stack_visible_child_changed); properties_stack.notify["visible-child"].connect (on_properties_stack_visible_child_changed); Timeout.add (100, populate_window); } bool populate_window () { update_lists (); return false; } #if DISABLE_AUR #else void on_save_pamac_config_finished (bool recurse, uint64 refresh_period, bool no_update_hide_icon, bool enable_aur, bool search_aur, string aur_build_dir, bool check_aur_updates) { support_aur (transaction.enable_aur); } #endif void on_set_pkgreason_finished () { transaction.unlock (); transaction.refresh_handle (); refresh_packages_list (); if (main_stack.visible_child_name == "details") { if (transaction.get_installed_pkg (current_package_displayed).name != "" || transaction.get_sync_pkg (current_package_displayed).name != "") { display_package_properties (current_package_displayed); #if DISABLE_AUR #else } else { display_aur_properties (current_package_displayed); #endif } } } #if DISABLE_AUR #else void support_aur (bool enable_aur) { if (enable_aur) { packages_stackswitcher.visible = true; } else { packages_stackswitcher.visible = false; } } #endif void try_lock_and_run (TransactionAction action) { if (transaction.get_lock ()) { action (); } else { waiting = true; transaction.progress_box.action_label.label = dgettext (null, "Waiting for another package manager to quit") + "..."; transaction.start_progressbar_pulse (); cancel_button.sensitive = true; transaction_infobox.show_all (); Timeout.add (5000, () => { bool locked = transaction.get_lock (); if (locked) { waiting = false; transaction.stop_progressbar_pulse (); action (); } return !locked; }); } } void set_pendings_operations () { if (!transaction_running && !generate_mirrors_list && !refreshing && !sysupgrade_running) { if (filters_stack.visible_child_name == "updates") { uint64 total_dsize = 0; packages_list.foreach ((model, path, iter) => { string name; uint64 dsize; packages_list.get (iter, 1, out name, 5, out dsize); if (transaction.to_update.contains (name)) { total_dsize += dsize; } return false; }); if (total_dsize > 0) { transaction.progress_box.action_label.set_markup("%s: %s".printf (dgettext (null, "Total download size"), format_size (total_dsize))); } else { transaction.progress_box.action_label.label = ""; } if (!transaction_running && !generate_mirrors_list && !refreshing && !sysupgrade_running && (transaction.to_update.length > 0)) { apply_button.sensitive = true; } else { apply_button.sensitive = false; } cancel_button.sensitive = false; // fix an possible visibility issue transaction_infobox.show_all (); } else { #if DISABLE_AUR uint total_pending = transaction.to_install.length + transaction.to_remove.length; #else uint total_pending = transaction.to_install.length + transaction.to_remove.length + transaction.to_build.length; #endif if (total_pending == 0) { transaction.progress_box.action_label.label = ""; cancel_button.sensitive = false; apply_button.sensitive = false; if (important_details) { transaction_infobox.show_all (); } } else { string info = dngettext (null, "%u pending operation", "%u pending operations", total_pending).printf (total_pending); transaction.progress_box.action_label.label = info; cancel_button.sensitive = true; apply_button.sensitive = true; // fix an possible visibility issue transaction_infobox.show_all (); } } } } public void show_default_pkgs () { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); transaction.get_installed_pkgs.begin ((obj, res) => { populate_packages_list (transaction.get_installed_pkgs.end (res)); }); } void update_lists () { Gtk.TreeIter iter; Gtk.TreeSelection selection = repos_treeview.get_selection (); selection.changed.disconnect (on_repos_treeview_selection_changed); foreach (unowned string repo in transaction.get_repos_names ()) { repos_list.insert_with_values (null, -1, 0, repo); } repos_list.get_iter_first (out iter); selection.select_iter (iter); selection.changed.connect_after (on_repos_treeview_selection_changed); selection = groups_treeview.get_selection (); selection.changed.disconnect (on_groups_treeview_selection_changed); foreach (unowned string group in transaction.get_groups_names ()) { groups_list.insert_with_values (null, -1, 0, group); } groups_list.set_sort_column_id (0, Gtk.SortType.ASCENDING); groups_list.get_iter_first (out iter); selection.select_iter (iter); selection.changed.connect_after (on_groups_treeview_selection_changed); selection = states_treeview.get_selection (); selection.changed.disconnect (on_states_treeview_selection_changed); states_list.insert_with_values (null, -1, 0, dgettext (null, "Installed")); states_list.insert_with_values (null, -1, 0, dgettext (null, "Explicitly installed")); states_list.insert_with_values (null, -1, 0, dgettext (null, "Orphans")); states_list.insert_with_values (null, -1, 0, dgettext (null, "Foreign")); states_list.insert_with_values (null, -1, 0, dgettext (null, "Pending")); states_list.get_iter_first (out iter); selection.select_iter (iter); selection.changed.connect_after (on_states_treeview_selection_changed); } void on_mark_explicit_button_clicked (Gtk.Button button) { if (transaction.get_lock ()) { transaction.start_set_pkgreason (current_package_displayed, 0); //Alpm.Package.Reason.EXPLICIT } } Gtk.Widget populate_details_grid (string detail_type, string detail, Gtk.Widget? previous_widget) { var label = new Gtk.Label ("%s".printf (detail_type + ":")); label.use_markup = true; label.halign = Gtk.Align.START; details_grid.attach_next_to (label, previous_widget, Gtk.PositionType.BOTTOM); if (!transaction_running && !sysupgrade_running && detail_type == dgettext (null, "Install Reason") && detail == dgettext (null, "Installed as a dependency for another package")) { var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12); box.homogeneous = false; box.hexpand = true; var label2 = new Gtk.Label (detail); label2.halign = Gtk.Align.START; box.pack_start (label2, false); var mark_explicit_button = new Gtk.Button.with_label (dgettext (null, "Mark as explicitly installed")); mark_explicit_button.margin = 3; mark_explicit_button.clicked.connect (on_mark_explicit_button_clicked); box.pack_end (mark_explicit_button, false); details_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); } else { var label2 = new Gtk.Label (detail); label2.use_markup = true; label2.halign = Gtk.Align.START; details_grid.attach_next_to (label2, label, Gtk.PositionType.RIGHT); } return label as Gtk.Widget; } string find_install_button_dep_name (Gtk.Button button) { string dep_name = ""; Gtk.Container container = button.get_parent (); container.foreach ((widget) => { if (widget.name == "GtkButton") { var dep_button = widget as Gtk.Button; AlpmPackage pkg = transaction.find_sync_satisfier (dep_button.label); if (pkg.name != "") { dep_name = pkg.name; } } }); return dep_name; } void on_install_dep_button_toggled (Gtk.ToggleButton button) { string dep_name = find_install_button_dep_name (button); if (button.active) { button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); transaction.to_install.add (dep_name); } else { button.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); transaction.to_install.remove (dep_name); } set_pendings_operations (); } Gtk.Widget populate_dep_grid (string dep_type, string[] dep_list, Gtk.Widget? previous_widget, bool add_install_button = false) { var label = new Gtk.Label ("%s".printf (dep_type + ":")); label.use_markup = true; label.halign = Gtk.Align.START; label.valign = Gtk.Align.START; label.margin_top = 6; deps_grid.attach_next_to (label, previous_widget, Gtk.PositionType.BOTTOM); var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 3); box.hexpand = true; foreach (unowned string dep in dep_list) { if (add_install_button) { var box2 = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12); box2.homogeneous = false; var dep_button = new Gtk.Button.with_label (dep); dep_button.relief = Gtk.ReliefStyle.NONE; dep_button.clicked.connect (on_dep_button_clicked); box2.pack_start (dep_button, false); if (transaction.find_installed_satisfier (dep).name == "") { var install_dep_button = new Gtk.ToggleButton.with_label (dgettext (null, "Install")); install_dep_button.margin = 3; install_dep_button.toggled.connect (on_install_dep_button_toggled); box2.pack_end (install_dep_button, false); string dep_name = find_install_button_dep_name (install_dep_button); install_dep_button.active = (dep_name in transaction.to_install); } box.pack_start (box2); } else { var dep_button = new Gtk.Button.with_label (dep); dep_button.relief = Gtk.ReliefStyle.NONE; dep_button.halign = Gtk.Align.START; dep_button.clicked.connect (on_dep_button_clicked); box.pack_start (dep_button, false); } } deps_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); return label as Gtk.Widget; } void destroy_widget (Gtk.Widget widget) { widget.destroy (); } void set_package_details (string pkgname) { AlpmPackageDetails details = transaction.get_pkg_details (pkgname); // infos name_label.set_markup ("%s %s".printf (details.name, details.version)); desc_label.set_text (details.desc); string escaped_url = Markup.escape_text (details.url); link_label.set_markup ("%s".printf (escaped_url, escaped_url)); StringBuilder licenses = new StringBuilder (); licenses.append (dgettext (null, "Licenses")); licenses.append (":"); foreach (unowned string license in details.licenses) { licenses.append (" "); licenses.append (license); } licenses_label.set_text (licenses.str); if (details.origin == 2) { //Alpm.Package.From.LOCALDB install_togglebutton.visible = false; remove_togglebutton.visible = true; remove_togglebutton.active = transaction.to_remove.contains (details.name); reinstall_togglebutton.visible = false; AlpmPackage find_pkg = transaction.get_sync_pkg (details.name); if (find_pkg.name != "") { if (find_pkg.version == details.version) { reinstall_togglebutton.visible = true; reinstall_togglebutton.active = transaction.to_install.contains (details.name); } #if DISABLE_AUR #else } else { transaction.get_aur_details.begin (details.name, (obj, res) => { AURPackageDetails aur_details = transaction.get_aur_details.end (res); if (aur_details.name != "") { // always show reinstall button for VCS package if (aur_details.name.has_suffix ("-git") || aur_details.name.has_suffix ("-svn") || aur_details.name.has_suffix ("-bzr") || aur_details.name.has_suffix ("-hg") || aur_details.version == details.version) { reinstall_togglebutton.visible = true; reinstall_togglebutton.active = transaction.to_build.contains (details.name); } } }); #endif } } else if (details.origin == 3) { //Alpm.Package.From.SYNCDB remove_togglebutton.visible = false; reinstall_togglebutton.visible = false; install_togglebutton.visible = true; install_togglebutton.active = transaction.to_install.contains (details.name); } // details details_grid.foreach (destroy_widget); Gtk.Widget? previous_widget = null; if (details.repo != "") { previous_widget = populate_details_grid (dgettext (null, "Repository"), details.repo, previous_widget); } if (uint64.parse(details.downloadsize) > 0) { previous_widget = populate_details_grid (dgettext (null, "Download size"), GLib.format_size(uint64.parse(details.downloadsize)).to_string (), previous_widget); } if (uint64.parse(details.installsize) > 0) { previous_widget = populate_details_grid (dgettext (null, "Installed size"), GLib.format_size(uint64.parse(details.installsize)).to_string (), previous_widget); } if (details.groups.length > 0) { var label = new Gtk.Label ("%s".printf (dgettext (null, "Groups") + ":")); label.use_markup = true; label.halign = Gtk.Align.START; label.valign = Gtk.Align.START; details_grid.attach_next_to (label, previous_widget, Gtk.PositionType.BOTTOM); var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 6); foreach (unowned string name in details.groups) { var label2 = new Gtk.Label (name); label2.halign = Gtk.Align.START; box.pack_start (label2); } details_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); previous_widget = label as Gtk.Widget; } // make packager mail clickable string[] splitted = details.packager.split ("<", 2); string packager_name = splitted[0]; if (splitted.length > 1) { string packager_mail = splitted[1].split (">", 2)[0]; string packager_detail = "%s %s".printf (packager_name, packager_mail, packager_mail); previous_widget = populate_details_grid (dgettext (null, "Packager"), packager_detail, previous_widget); } else { previous_widget = populate_details_grid (dgettext (null, "Packager"), details.packager, previous_widget); } previous_widget = populate_details_grid (dgettext (null, "Build Date"), details.builddate, previous_widget); if (details.installdate != "") { previous_widget = populate_details_grid (dgettext (null, "Install Date"), details.installdate, previous_widget); } if (details.reason != "") { previous_widget = populate_details_grid (dgettext (null, "Install Reason"), details.reason, previous_widget); } if (details.has_signature != "") { previous_widget = populate_details_grid (dgettext (null, "Signatures"), details.has_signature, previous_widget); } if (details.backups.length > 0) { var label = new Gtk.Label ("%s".printf (dgettext (null, "Backup files") + ":")); label.use_markup = true; label.halign = Gtk.Align.START; label.valign = Gtk.Align.START; details_grid.attach_next_to (label, previous_widget, Gtk.PositionType.BOTTOM); var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12); foreach (unowned string name in details.backups) { var label2 = new Gtk.Label (name); label2.halign = Gtk.Align.START; box.pack_start (label2); } details_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); } details_grid.show_all (); // deps deps_grid.foreach (destroy_widget); previous_widget = null; if (details.depends.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Depends On"), details.depends, previous_widget); } if (details.optdepends.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Optional Dependencies"), details.optdepends, previous_widget, true); } if (details.requiredby.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Required By"), details.requiredby, previous_widget); } if (details.optionalfor.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Optional For"), details.optionalfor, previous_widget); } if (details.provides.length > 0) { var label = new Gtk.Label ("%s".printf (dgettext (null, "Provides") + ":")); label.use_markup = true; label.halign = Gtk.Align.START; label.valign = Gtk.Align.START; label.margin_top = 6; deps_grid.attach_next_to (label, previous_widget, Gtk.PositionType.BOTTOM); var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12); box.margin = 3; foreach (unowned string name in details.provides) { var label2 = new Gtk.Label (name); label2.halign = Gtk.Align.START; label2.margin_start = 12; box.pack_start (label2); } deps_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); previous_widget = label as Gtk.Widget; } if (details.replaces.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Replaces"), details.replaces, previous_widget); } if (details.conflicts.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Conflicts With"), details.conflicts, previous_widget); } deps_grid.show_all (); // files // will be populated on properties_stack switch if (properties_stack.visible_child_name == "files") { on_properties_stack_visible_child_changed (); } } #if DISABLE_AUR #else void set_aur_details (string pkgname) { name_label.set_text (""); desc_label.set_text (""); link_label.set_text (""); licenses_label.set_text (""); remove_togglebutton.visible = false; reinstall_togglebutton.visible = false; install_togglebutton.visible = false; properties_stackswitcher.visible = false; details_grid.foreach (destroy_widget); deps_grid.foreach (destroy_widget); this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); while (Gtk.events_pending ()) { Gtk.main_iteration (); } transaction.get_aur_details.begin (pkgname, (obj, res) => { AURPackageDetails details = transaction.get_aur_details.end (res); // infos name_label.set_markup ("%s %s".printf (details.name, details.version)); desc_label.set_text (details.desc); string aur_url = "http://aur.archlinux.org/packages/" + details.name; string escaped_url = Markup.escape_text (details.url); link_label.set_markup ("%s\n\n%s".printf (escaped_url, escaped_url, aur_url, aur_url)); StringBuilder licenses = new StringBuilder (); licenses.append (dgettext (null, "Licenses")); licenses.append (":"); foreach (unowned string license in details.licenses) { licenses.append (" "); licenses.append (license); } licenses_label.set_text (licenses.str); install_togglebutton.visible = true; install_togglebutton.active = transaction.to_build.contains (details.name); AlpmPackage pkg = transaction.get_installed_pkg (details.name); if (pkg.name != "") { remove_togglebutton.visible = true; remove_togglebutton.active = transaction.to_remove.contains (pkg.name); } // details properties_stackswitcher.visible = true; details_grid.foreach (destroy_widget); Gtk.Widget? previous_widget = null; if (details.packagebase != details.name) { previous_widget = populate_details_grid (dgettext (null, "Package Base"), details.packagebase, previous_widget); } if (details.maintainer != "") { previous_widget = populate_details_grid (dgettext (null, "Maintainer"), details.maintainer, previous_widget); } GLib.Time time = GLib.Time.local ((time_t) details.firstsubmitted); previous_widget = populate_details_grid (dgettext (null, "First Submitted"), time.format ("%a %d %b %Y %X %Z"), previous_widget); time = GLib.Time.local ((time_t) details.lastmodified); previous_widget = populate_details_grid (dgettext (null, "Last Modified"), time.format ("%a %d %b %Y %X %Z"), previous_widget); previous_widget = populate_details_grid (dgettext (null, "Votes"), details.numvotes.to_string (), previous_widget); if (details.outofdate != 0) { time = GLib.Time.local ((time_t) details.outofdate); previous_widget = populate_details_grid (dgettext (null, "Out of Date"), time.format ("%a %d %b %Y %X %Z"), previous_widget); } details_grid.show_all (); // deps previous_widget = null; if (details.depends.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Depends On"), details.depends, previous_widget); } if (details.makedepends.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Make Dependencies"), details.makedepends, previous_widget); } if (details.checkdepends.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Check Dependencies"), details.checkdepends, previous_widget); } if (details.optdepends.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Optional Dependencies"), details.optdepends, previous_widget); } if (details.provides.length > 0) { var label = new Gtk.Label ("%s".printf (dgettext (null, "Provides") + ":")); label.use_markup = true; label.halign = Gtk.Align.START; label.valign = Gtk.Align.START; label.margin_top = 6; deps_grid.attach_next_to (label, previous_widget, Gtk.PositionType.BOTTOM); var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12); box.margin = 3; foreach (unowned string name in details.provides) { var label2 = new Gtk.Label (name); label2.halign = Gtk.Align.START; label2.margin_start = 12; box.pack_start (label2); } deps_grid.attach_next_to (box, label, Gtk.PositionType.RIGHT); previous_widget = label as Gtk.Widget; } if (details.replaces.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Replaces"), details.replaces, previous_widget); } if (details.conflicts.length > 0) { previous_widget = populate_dep_grid (dgettext (null, "Conflicts With"), details.conflicts, previous_widget); } deps_grid.show_all (); this.get_window ().set_cursor (null); }); } #endif [GtkCallback] void on_install_togglebutton_toggled () { if (install_togglebutton.active) { install_togglebutton.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); if (transaction.get_pkg_origin (current_package_displayed) == 3) { //Alpm.Package.From.SYNCDB transaction.to_install.add (current_package_displayed); #if DISABLE_AUR #else } else { transaction.to_build.add (current_package_displayed); #endif } } else { install_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); if (transaction.to_install.remove (current_package_displayed)) { #if DISABLE_AUR #else } else { transaction.to_build.remove (current_package_displayed); #endif } } set_pendings_operations (); } [GtkCallback] void on_remove_togglebutton_toggled () { if (remove_togglebutton.active) { reinstall_togglebutton.active = false; reinstall_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); remove_togglebutton.get_style_context ().add_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); transaction.to_install.remove (current_package_displayed); transaction.to_remove.add (current_package_displayed); } else { remove_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); transaction.to_remove.remove (current_package_displayed); } set_pendings_operations (); } [GtkCallback] void on_reinstall_togglebutton_toggled () { if (reinstall_togglebutton.active) { remove_togglebutton.active = false; remove_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION); reinstall_togglebutton.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); transaction.to_remove.remove (current_package_displayed); AlpmPackage find_pkg = transaction.get_sync_pkg (current_package_displayed); if (find_pkg.name != "") { transaction.to_install.add (current_package_displayed); #if DISABLE_AUR #else } else { // availability in AUR was checked in set_package_details transaction.to_build.add (current_package_displayed); #endif } } else { reinstall_togglebutton.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); transaction.to_install.remove (current_package_displayed); #if DISABLE_AUR #else transaction.to_build.remove (current_package_displayed); #endif } set_pendings_operations (); } void populate_packages_list (AlpmPackage[] pkgs) { // populate liststore packages_treeview.freeze_notify (); packages_treeview.freeze_child_notify (); packages_list.clear (); foreach (unowned AlpmPackage pkg in pkgs) { string version; uint64 size; string size_str; if (filters_stack.visible_child_name == "updates") { version = "%s\n(%s)".printf (pkg.version, pkg.installed_version); size = pkg.download_size; size_str = pkg.download_size == 0 ? "" : GLib.format_size (pkg.download_size); } else { version = pkg.version; size = pkg.size; size_str = GLib.format_size (pkg.size); } packages_list.insert_with_values (null, -1, 0, pkg.origin, 1, pkg.name, 2, "%s\n%s".printf (pkg.name, Markup.escape_text (pkg.desc)), 3, version, 4, pkg.repo, 5, size, 6, size_str); } packages_treeview.thaw_child_notify (); packages_treeview.thaw_notify (); this.get_window ().set_cursor (null); } #if DISABLE_AUR #else void populate_aur_list (AURPackage[] pkgs) { // populate liststore aur_treeview.freeze_notify (); aur_treeview.freeze_child_notify (); aur_list.clear (); foreach (unowned AURPackage aur_pkg in pkgs) { string version; if (filters_stack.visible_child_name == "updates") { version = "%s\n(%s)".printf (aur_pkg.version, aur_pkg.installed_version); } else if (aur_pkg.installed_version == "") { version = aur_pkg.version; } else { version = aur_pkg.installed_version; } aur_list.insert_with_values (null, -1, 0, aur_pkg.installed_version == "" ? 0 : 2, //Alpm.Package.From.LOCALDB 1, aur_pkg.name, 2, "%s\n%s".printf (aur_pkg.name, Markup.escape_text (aur_pkg.desc)), 3, version, 4, aur_pkg.popularity, 5, "%.2f".printf (aur_pkg.popularity)); } aur_treeview.thaw_child_notify (); aur_treeview.thaw_notify (); this.get_window ().set_cursor (null); } #endif void refresh_packages_list () { switch (filters_stack.visible_child_name) { case "search": #if DISABLE_AUR #else aur_list.clear (); #endif filters_stack.visible = true; set_pendings_operations (); #if DISABLE_AUR #else packages_stackswitcher.visible = transaction.enable_aur; #endif if (packages_stack.visible_child_name == "updated") { packages_stack.visible_child_name = "repos"; } Gtk.TreeSelection selection = search_treeview.get_selection (); if (selection.get_selected (null, null)) { on_search_treeview_selection_changed (); } else { show_default_pkgs (); search_entry.grab_focus (); } break; case "groups": filters_stack.visible = true; set_pendings_operations (); packages_stack.visible_child_name = "repos"; packages_stackswitcher.visible = false; on_groups_treeview_selection_changed (); break; case "states": filters_stack.visible = true; set_pendings_operations (); packages_stack.visible_child_name = "repos"; packages_stackswitcher.visible = false; on_states_treeview_selection_changed (); break; case "repos": filters_stack.visible = true; set_pendings_operations (); packages_stack.visible_child_name = "repos"; packages_stackswitcher.visible = false; on_repos_treeview_selection_changed (); break; case "updates": packages_list.clear (); #if DISABLE_AUR #else aur_list.clear (); #endif var attention_val = GLib.Value (typeof (bool)); attention_val.set_boolean (false); filters_stack.child_set_property (filters_stack.get_child_by_name ("updates"), "needs-attention", attention_val); filters_stack.visible = false; packages_stack.visible_child_name = "repos"; packages_stackswitcher.visible = false; apply_button.visible = false; this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); transaction.start_get_updates (); break; default: break; } } void display_package_properties (string pkgname) { current_package_displayed = pkgname; files_scrolledwindow.visible = true; set_package_details (current_package_displayed); } #if DISABLE_AUR #else void display_aur_properties (string pkgname) { current_package_displayed = pkgname; files_scrolledwindow.visible = false; set_aur_details (current_package_displayed); } #endif [GtkCallback] void on_packages_treeview_row_activated (Gtk.TreeView treeview, Gtk.TreePath path, Gtk.TreeViewColumn column) { if (column.title == dgettext (null, "Name")) { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); while (Gtk.events_pending ()) { Gtk.main_iteration (); } main_stack.visible_child_name = "details"; Gtk.TreeIter iter; packages_list.get_iter (out iter, path); string pkgname; packages_list.get (iter, 1, out pkgname); display_package_properties (pkgname); this.get_window ().set_cursor (null); } } void on_dep_button_clicked (Gtk.Button button) { if (display_package_queue.find_custom (current_package_displayed, strcmp) == null) { display_package_queue.push_tail (current_package_displayed); } string depstring = button.label; // if depstring contains a version restriction search a satisfier directly if (">" in depstring || "=" in depstring || "<" in depstring) { var pkg = transaction.find_installed_satisfier (depstring); if (pkg.name != "") { display_package_properties (pkg.name); } else { pkg = transaction.find_sync_satisfier (depstring); if (pkg.name != "") { display_package_properties (pkg.name); } } } else { // just search for the name first to search for AUR after if (transaction.get_installed_pkg (depstring).name != "") { display_package_properties (depstring); } else if (transaction.get_sync_pkg (depstring).name != "") { display_package_properties (depstring); } else { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); while (Gtk.events_pending ()) { Gtk.main_iteration (); } #if DISABLE_AUR #else transaction.get_aur_details.begin (depstring, (obj, res) => { this.get_window ().set_cursor (null); if (transaction.get_aur_details.end (res).name != "") { display_aur_properties (depstring); } else { var pkg = transaction.find_installed_satisfier (depstring); if (pkg.name != "") { display_package_properties (pkg.name); } else { pkg = transaction.find_sync_satisfier (depstring); if (pkg.name != "") { display_package_properties (pkg.name); } } } }); #endif } } } void on_properties_stack_visible_child_changed () { switch (properties_stack.visible_child_name) { case "files": this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); while (Gtk.events_pending ()) { Gtk.main_iteration (); } string[] files = transaction.get_pkg_files (current_package_displayed); StringBuilder text = new StringBuilder (); foreach (unowned string file in files) { if (text.len > 0) { text.append ("\n"); } text.append (file); } files_textview.buffer.set_text (text.str, (int) text.len); this.get_window ().set_cursor (null); break; default: break; } } void on_packages_state_icon_activated (Gtk.TreePath path) { Gtk.TreeIter iter; packages_list.get_iter (out iter, path); uint origin; string pkgname; packages_list.get (iter, 0, out origin, 1, out pkgname); if (!transaction.transaction_summary.contains (pkgname)) { if (transaction.to_install.remove (pkgname)) { } else if (transaction.to_remove.remove (pkgname)) { } else { if (origin == 2) { //Alpm.Package.From.LOCALDB if (!transaction.should_hold (pkgname)) { transaction.to_remove.add (pkgname); } } else if (transaction.to_update.remove (pkgname)) { transaction.temporary_ignorepkgs.add (pkgname); } else if (transaction.temporary_ignorepkgs.remove (pkgname)) { transaction.to_update.add (pkgname); } else { transaction.to_install.add (pkgname); } } } packages_treeview.queue_draw (); set_pendings_operations (); } #if DISABLE_AUR #else void on_aur_treeview_row_activated (Gtk.TreeView treeview, Gtk.TreePath path, Gtk.TreeViewColumn column) { if (column.title == dgettext (null, "Name")) { main_stack.visible_child_name = "details"; Gtk.TreeIter iter; aur_list.get_iter (out iter, path); uint origin; string pkgname; aur_list.get (iter, 0, out origin, 1, out pkgname); if (filters_stack.visible_child_name == "updates") { display_aur_properties (pkgname); } else if (origin == 2) { //Alpm.Package.From.LOCALDB display_package_properties (pkgname); } else { display_aur_properties (pkgname); } } } void on_aur_state_icon_activated (Gtk.TreePath path) { Gtk.TreeIter iter; aur_list.get_iter (out iter, path); uint origin; string pkgname; aur_list.get (iter, 0, out origin, 1, out pkgname); if (filters_stack.visible_child_name == "updates") { if (transaction.to_update.remove (pkgname)) { transaction.temporary_ignorepkgs.add (pkgname); } else if (transaction.temporary_ignorepkgs.remove (pkgname)) { transaction.to_update.add (pkgname); } } else if (origin == 2) { //Alpm.Package.From.LOCALDB if (!transaction.transaction_summary.contains (pkgname)) { if (transaction.to_remove.remove (pkgname)) { } else if (!transaction.should_hold (pkgname)) { transaction.to_remove.add (pkgname); } } } else if (transaction.to_build.remove (pkgname)) { } else { transaction.to_build.add (pkgname); } set_pendings_operations (); } #endif [GtkCallback] public void on_button_back_clicked () { string? pkgname = display_package_queue.pop_tail (); if (pkgname != null) { AlpmPackage pkg = transaction.get_installed_pkg (pkgname); if (pkg.name == "") { pkg = transaction.get_sync_pkg (pkgname); #if DISABLE_AUR #else } if (pkg.name == "") { transaction.get_aur_details.begin (pkgname, (obj, res) => { if (transaction.get_aur_details.end (res).name != "") { display_aur_properties (pkgname); } else { pkg = transaction.find_installed_satisfier (pkgname); if (pkg.name == "") { pkg = transaction.find_sync_satisfier (pkgname); } if (pkg.name != "") { display_package_properties (pkgname); } } }); #endif } else { display_package_properties (pkgname); } } else { main_stack.visible_child_name = "browse"; } } void on_install_item_activate () { foreach (unowned string pkgname in selected_pkgs) { if (transaction.get_pkg_origin (pkgname) == 3) { //Alpm.Package.From.SYNCDB transaction.to_install.add (pkgname); } } #if DISABLE_AUR #else foreach (unowned string pkgname in selected_aur) { transaction.to_build.add (pkgname); } #endif set_pendings_operations (); } void on_details_item_activate () { // show details for the first selected package if (selected_pkgs.length () == 1) { display_package_properties (selected_pkgs.data); main_stack.visible_child_name = "details"; #if DISABLE_AUR #else } else if (selected_aur.length () == 1) { display_aur_properties (selected_aur.data); main_stack.visible_child_name = "details"; #endif } } void on_remove_item_activate () { foreach (unowned string pkgname in selected_pkgs) { transaction.to_install.remove (pkgname); if (!transaction.should_hold (pkgname)) { if (transaction.get_pkg_origin (pkgname) == 2) { //Alpm.Package.From.LOCALDB transaction.to_remove.add (pkgname); } } } set_pendings_operations (); } void on_deselect_item_activate () { foreach (unowned string pkgname in selected_pkgs) { if (transaction.to_install.remove (pkgname)) { } else if (transaction.to_update.remove (pkgname)) { transaction.temporary_ignorepkgs.add (pkgname); } else { transaction.to_remove.remove (pkgname); } } #if DISABLE_AUR #else foreach (unowned string pkgname in selected_aur) { if (transaction.to_build.remove (pkgname)) { } else { transaction.to_update.remove (pkgname); transaction.temporary_ignorepkgs.add (pkgname); } } #endif set_pendings_operations (); } void on_upgrade_item_activate () { foreach (unowned string pkgname in selected_pkgs) { transaction.temporary_ignorepkgs.remove (pkgname); transaction.to_update.add (pkgname); } #if DISABLE_AUR #else foreach (unowned string pkgname in selected_aur) { transaction.temporary_ignorepkgs.remove (pkgname); transaction.to_update.add (pkgname); } #endif set_pendings_operations (); } void on_packages_stack_visible_child_changed () { // do nothing if it we want to see pendings AUR operations switch (filters_stack.visible_child_name) { case "search": Gtk.TreeIter iter; Gtk.TreeSelection selection = search_treeview.get_selection (); if (selection.get_selected (null, out iter)) { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); while (Gtk.events_pending ()) { Gtk.main_iteration (); } string search_string; search_list.get (iter, 0, out search_string); switch (packages_stack.visible_child_name) { case "repos": transaction.search_pkgs.begin (search_string, (obj, res) => { // get custom sort by relevance packages_list.set_sort_column_id (Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0); populate_packages_list (transaction.search_pkgs.end (res)); }); break; #if DISABLE_AUR #else case "aur": transaction.search_in_aur.begin (search_string, (obj, res) => { populate_aur_list (transaction.search_in_aur.end (res)); }); break; #endif default: break; } } break; default: break; } #if DISABLE_AUR #else if (packages_stack.visible_child_name == "aur") { var attention_val = GLib.Value (typeof (bool)); attention_val.set_boolean (false); packages_stack.child_set_property (packages_stack.get_child_by_name ("aur"), "needs-attention", attention_val); } #endif } [GtkCallback] bool on_packages_treeview_button_press_event (Gdk.EventButton event) { // Check if right mouse button was clicked if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3) { Gtk.TreePath treepath; if (packages_treeview.get_path_at_pos ((int) event.x, (int) event.y, out treepath, null, null, null)) { packages_treeview.grab_focus (); Gtk.TreeSelection selection = packages_treeview.get_selection (); if (!selection.path_is_selected (treepath)) { selection.unselect_all (); selection.select_path (treepath); } GLib.List selected_paths = selection.get_selected_rows (null); selected_pkgs = new GLib.List (); #if DISABLE_AUR #else selected_aur = new GLib.List (); #endif deselect_item.sensitive = false; upgrade_item.sensitive = false; install_item.sensitive = false; remove_item.sensitive = false; if (selected_paths.length () == 1) { Gtk.TreePath path = selected_paths.data; Gtk.TreeIter iter; packages_list.get_iter (out iter, path); uint origin; string pkgname; string pkgversion; packages_list.get (iter, 0, out origin, 1, out pkgname, 3, out pkgversion); selected_pkgs.append (pkgname); details_item.sensitive = true; if (transaction.to_install.contains (pkgname) || transaction.to_remove.contains (pkgname) || transaction.to_update.contains (pkgname)) { deselect_item.sensitive = true; } else if (transaction.temporary_ignorepkgs.contains (pkgname)) { upgrade_item.sensitive = true; } else if (origin == 2) { //Alpm.Package.From.LOCALDB remove_item.sensitive = true; } else if (origin == 3) { //Alpm.Package.From.SYNCDB install_item.sensitive = true; } } else { details_item.sensitive = false; foreach (unowned Gtk.TreePath path in selected_paths) { Gtk.TreeIter iter; packages_list.get_iter (out iter, path); uint origin; string pkgname; packages_list.get (iter, 0, out origin, 1, out pkgname); selected_pkgs.append (pkgname); if (!deselect_item.sensitive) { if (transaction.to_install.contains (pkgname) || transaction.to_remove.contains (pkgname) || transaction.to_update.contains (pkgname)) { deselect_item.sensitive = true; } } if (origin == 3) { //Alpm.Package.From.SYNCDB if (transaction.temporary_ignorepkgs.contains (pkgname)) { upgrade_item.sensitive = true; } else { install_item.sensitive = true; } } if (origin == 2) { //Alpm.Package.From.LOCALDB remove_item.sensitive = true; } } } right_click_menu.popup_at_pointer (event); return true; } } return false; } [GtkCallback] bool on_packages_treeview_query_tooltip (int x, int y, bool keyboard_tooltip, Gtk.Tooltip tooltip) { Gtk.TreePath path; Gtk.TreeIter iter; if (packages_treeview.get_tooltip_context (ref x, ref y, keyboard_tooltip, null, out path, out iter)) { string desc; packages_list.get (iter, 2, out desc); tooltip.set_markup (desc); packages_treeview.set_tooltip_row (tooltip, path); return true; } return false; } #if DISABLE_AUR #else bool on_aur_treeview_button_press_event (Gdk.EventButton event) { aur_treeview.grab_focus (); // Check if right mouse button was clicked if (event.type == Gdk.EventType.BUTTON_PRESS && event.button == 3) { Gtk.TreePath? treepath; Gtk.TreeSelection selection = aur_treeview.get_selection (); if (aur_treeview.get_path_at_pos ((int) event.x, (int) event.y, out treepath, null, null, null)) { if (!selection.path_is_selected (treepath)) { selection.unselect_all (); selection.select_path (treepath); } GLib.List selected_paths = selection.get_selected_rows (null); selected_pkgs = new GLib.List (); selected_aur = new GLib.List (); deselect_item.sensitive = false; upgrade_item.sensitive = false; install_item.sensitive = false; remove_item.sensitive = false; if (selected_paths.length () == 1) { details_item.sensitive = true; } else { details_item.sensitive = false; } foreach (unowned Gtk.TreePath path in selected_paths) { Gtk.TreeIter iter; aur_list.get_iter (out iter, path); string pkgname; aur_list.get (iter, 1, out pkgname); AlpmPackage pkg = transaction.get_installed_pkg (pkgname); if (pkg.name != "") { selected_pkgs.append (pkgname); // there is for sure a pkg to remove if (filters_stack.visible_child_name == "search" && !transaction.to_remove.contains (pkgname) && !transaction.to_build.contains (pkgname) && !transaction.to_update.contains (pkgname)) { remove_item.sensitive = true; } } else { selected_aur.append (pkgname); } } foreach (unowned string pkgname in selected_aur) { if (transaction.to_remove.contains (pkgname) || transaction.to_build.contains (pkgname)) { deselect_item.sensitive = true; } else { install_item.sensitive = true; } } foreach (unowned string pkgname in selected_pkgs) { if (transaction.to_remove.contains (pkgname) || transaction.to_update.contains (pkgname)) { deselect_item.sensitive = true; } else if (transaction.temporary_ignorepkgs.contains (pkgname)) { upgrade_item.sensitive = true; } } right_click_menu.popup_at_pointer (event); return true; } } return false; } bool on_aur_treeview_query_tooltip (int x, int y, bool keyboard_tooltip, Gtk.Tooltip tooltip) { Gtk.TreePath path; Gtk.TreeIter iter; if (aur_treeview.get_tooltip_context (ref x, ref y, keyboard_tooltip, null, out path, out iter)) { string desc; aur_list.get (iter, 2, out desc); tooltip.set_markup (desc); aur_treeview.set_tooltip_row (tooltip, path); return true; } return false; } #endif [GtkCallback] void on_search_entry_activate () { string search_string = search_entry.get_text ().strip (); if (search_string != "") { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); Gtk.TreeModel model; Gtk.TreeIter iter; Gtk.TreeSelection selection = search_treeview.get_selection (); // add search string in search_list if needed bool found = false; // check if search string is already selected in search list if (selection.get_selected (out model, out iter)) { string selected_string; model.get (iter, 0, out selected_string); if (selected_string == search_string) { on_search_treeview_selection_changed (); found = true; } } // check if search string exists in search list if (!found) { search_list.foreach ((_model, _path, _iter) => { string line; _model.get (_iter, 0, out line); if (line == search_string) { found = true; // we select the iter in search_list // it will populate the list with the selection changed signal selection.select_iter (_iter); } return found; }); } if (!found) { search_list.insert_with_values (out iter, -1, 0, search_string); // we select the iter in search_list // it will populate the list with the selection changed signal selection.select_iter (iter); } } } bool search_entry_timeout_callback () { on_search_entry_activate (); search_entry_timeout_id = 0; return false; } [GtkCallback] void on_search_entry_changed () { if (search_entry.get_text ().strip () != "") { if (search_entry_timeout_id != 0) { Source.remove (search_entry_timeout_id); } search_entry_timeout_id = Timeout.add (750, search_entry_timeout_callback); } } [GtkCallback] void on_search_treeview_selection_changed () { Gtk.TreeIter iter; Gtk.TreeSelection selection = search_treeview.get_selection (); if (selection.get_selected (null, out iter)) { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); string search_string; search_list.get (iter, 0, out search_string); // change search entry text to the selected one search_entry.changed.disconnect (on_search_entry_changed); search_entry.set_text (search_string); search_entry.changed.connect (on_search_entry_changed); Timeout.add (200, () => { search_entry.grab_focus_without_selecting (); return false; }); search_entry.set_position (-1); switch (packages_stack.visible_child_name) { case "repos": transaction.search_pkgs.begin (search_string, (obj, res) => { var pkgs = transaction.search_pkgs.end (res); // get custom sort by relevance packages_list.set_sort_column_id (Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0); populate_packages_list (pkgs); #if DISABLE_AUR #else if (transaction.search_aur) { if (pkgs.length == 0) { transaction.search_in_aur.begin (search_string, (obj, res) => { if (transaction.search_in_aur.end (res).length != 0) { packages_stack.visible_child_name = "aur"; } }); } else { transaction.search_in_aur.begin (search_string, (obj, res) => { if (transaction.search_in_aur.end (res).length != 0) { var attention_val = GLib.Value (typeof (bool)); attention_val.set_boolean (true); packages_stack.child_set_property (packages_stack.get_child_by_name ("aur"), "needs-attention", attention_val); } }); } } #endif }); #if DISABLE_AUR #else aur_list.clear (); #endif break; #if DISABLE_AUR #else case "aur": transaction.search_in_aur.begin (search_string, (obj, res) => { populate_aur_list (transaction.search_in_aur.end (res)); }); packages_list.clear (); break; #endif default: break; } } } [GtkCallback] void on_groups_treeview_selection_changed () { Gtk.TreeIter iter; Gtk.TreeSelection selection = groups_treeview.get_selection (); if (selection.get_selected (null, out iter)) { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); string group_name; groups_list.get (iter, 0, out group_name); transaction.get_group_pkgs.begin (group_name, (obj, res) => { populate_packages_list (transaction.get_group_pkgs.end (res)); }); } } [GtkCallback] void on_states_treeview_selection_changed () { Gtk.TreeIter iter; Gtk.TreeSelection selection = states_treeview.get_selection (); if (selection.get_selected (null, out iter)) { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); packages_stackswitcher.visible = false; string state; states_list.get (iter, 0, out state); if (state == dgettext (null, "Installed")) { transaction.get_installed_pkgs.begin ((obj, res) => { populate_packages_list (transaction.get_installed_pkgs.end (res)); }); } else if (state == dgettext (null, "Explicitly installed")) { transaction.get_explicitly_installed_pkgs.begin ((obj, res) => { populate_packages_list (transaction.get_explicitly_installed_pkgs.end (res)); }); } else if (state == dgettext (null, "Orphans")) { transaction.get_orphans.begin ((obj, res) => { populate_packages_list (transaction.get_orphans.end (res)); }); } else if (state == dgettext (null, "Foreign")) { transaction.get_foreign_pkgs.begin ((obj, res) => { populate_packages_list (transaction.get_foreign_pkgs.end (res)); }); } else if (state == dgettext (null, "Pending")) { AlpmPackage[] pkgs = {}; foreach (unowned string pkgname in transaction.to_install) { AlpmPackage pkg = transaction.get_installed_pkg (pkgname); if (pkg.name == "") { pkg = transaction.get_sync_pkg (pkgname); } if (pkg.name != "") { pkgs += pkg; } } foreach (unowned string pkgname in transaction.to_remove) { AlpmPackage pkg = transaction.get_installed_pkg (pkgname); if (pkg.name != "") { pkgs += pkg; } } populate_packages_list (pkgs); #if DISABLE_AUR #else if (transaction.to_build.length != 0) { packages_stackswitcher.visible = true; AURPackage[] aur_pkgs = {}; foreach (unowned string pkgname in transaction.to_build) { transaction.get_aur_details.begin (pkgname, (obj, res) => { AURPackageDetails details_pkg = transaction.get_aur_details.end (res); if (details_pkg.name != "") { var aur_pkg = AURPackage () { name = details_pkg.name, version = details_pkg.version, desc = details_pkg.desc, popularity = details_pkg.popularity }; aur_pkgs += aur_pkg; populate_aur_list (aur_pkgs); if (aur_pkgs.length > 0 ) { if (pkgs.length == 0) { packages_stack.visible_child_name = "aur"; } else { var attention_val = GLib.Value (typeof (bool)); attention_val.set_boolean (true); packages_stack.child_set_property (packages_stack.get_child_by_name ("aur"), "needs-attention", attention_val); } } } }); } } #endif } } } [GtkCallback] void on_repos_treeview_selection_changed () { Gtk.TreeIter iter; Gtk.TreeSelection selection = repos_treeview.get_selection (); if (selection.get_selected (null, out iter)) { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); string repo; repos_list.get (iter, 0, out repo); transaction.get_repo_pkgs.begin (repo, (obj, res) => { populate_packages_list (transaction.get_repo_pkgs.end (res)); }); } } void on_main_stack_visible_child_changed () { switch (main_stack.visible_child_name) { case "browse": button_back.visible = false; filters_stackswitcher.visible = true; details_button.sensitive = true; break; case "details": button_back.visible = true; filters_stackswitcher.visible = false; details_button.sensitive = true; break; case "term": filters_stackswitcher.visible = false; button_back.visible = true; details_button.get_style_context ().remove_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); details_button.sensitive = false; break; default: break; } } void on_filters_stack_visible_child_changed () { refresh_packages_list (); } #if ENABLE_HAMBURGER void on_menu_button_toggled () { preferences_button.sensitive = !(transaction_running || sysupgrade_running); } #endif [GtkCallback] void on_history_button_clicked () { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); while (Gtk.events_pending ()) { Gtk.main_iteration (); } var file = GLib.File.new_for_path ("/var/log/pacman.log"); if (!file.query_exists ()) { stderr.printf ("File '%s' doesn't exist.\n", file.get_path ()); } else { StringBuilder text = new StringBuilder (); try { // Open file for reading and wrap returned FileInputStream into a // DataInputStream, so we can read line by line var dis = new DataInputStream (file.read ()); string line; // Read lines until end of file (null) is reached while ((line = dis.read_line ()) != null) { // construct text in reverse order text.prepend (line + "\n"); } } catch (GLib.Error e) { stderr.printf ("%s\n", e.message); } var history_dialog = new HistoryDialog (this); history_dialog.textview.buffer.set_text (text.str, (int) text.len); this.get_window ().set_cursor (null); history_dialog.show (); history_dialog.response.connect (() => { history_dialog.destroy (); }); while (Gtk.events_pending ()) { Gtk.main_iteration (); } } } [GtkCallback] void on_local_button_clicked () { Gtk.FileChooserDialog chooser = new Gtk.FileChooserDialog ( dgettext (null, "Install Local Packages"), this, Gtk.FileChooserAction.OPEN, dgettext (null, "_Cancel"), Gtk.ResponseType.CANCEL, dgettext (null, "_Open"),Gtk.ResponseType.ACCEPT); chooser.window_position = Gtk.WindowPosition.CENTER_ON_PARENT; chooser.icon_name = "system-software-install"; chooser.select_multiple = true; chooser.local_only = false; chooser.create_folders = false; Gtk.FileFilter package_filter = new Gtk.FileFilter (); package_filter.set_filter_name (dgettext (null, "Alpm Package")); package_filter.add_pattern ("*.pkg.tar.xz"); chooser.add_filter (package_filter); if (chooser.run () == Gtk.ResponseType.ACCEPT) { SList packages_paths = chooser.get_filenames (); if (packages_paths.length () != 0) { foreach (unowned string path in packages_paths) { transaction.to_load.add (path); } chooser.destroy (); try_lock_and_run (run_transaction); } } else { chooser.destroy (); while (Gtk.events_pending ()) { Gtk.main_iteration (); } } } [GtkCallback] void on_preferences_button_clicked () { if (transaction.get_lock ()) { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); transaction.run_preferences_dialog (); } else { transaction.display_error (dgettext (null, "Waiting for another package manager to quit"), {}); } } void on_run_preferences_dialog_finished () { transaction.unlock (); if (filters_stack.visible_child_name == "updates") { transaction.start_get_updates (); } else { this.get_window ().set_cursor (null); } } [GtkCallback] void on_about_button_clicked () { Gtk.show_about_dialog ( this, "program_name", "Pamac", "icon_name", "system-software-install", "logo_icon_name", "system-software-install", "comments", dgettext (null, "A Gtk3 frontend for libalpm"), "copyright", "Copyright © 2017-2019 Chris Cromer\nCopyright © 2017 Guillaume Benoit", "version", VERSION, "license_type", Gtk.License.GPL_3_0, "website", "https://git.cromer.cl/cromer/pamac-classic"); } [GtkCallback] void on_details_button_clicked () { important_details = false; if (transaction_running || sysupgrade_running) { main_stack.visible_child_name = "term"; } else { #if DISABLE_AUR uint total_pending = transaction.to_install.length + transaction.to_remove.length; #else uint total_pending = transaction.to_install.length + transaction.to_remove.length + transaction.to_build.length; #endif if (total_pending == 0) { main_stack.visible_child_name = "term"; } else { main_stack.visible_child_name = "browse"; filters_stack.notify["visible-child"].disconnect (on_filters_stack_visible_child_changed); filters_stack.visible_child_name = "states"; filters_stack.notify["visible-child"].connect (on_filters_stack_visible_child_changed); Gtk.TreeIter iter; // show "Pending" in states_list // "Pending" is at indice 4 states_list.get_iter (out iter, new Gtk.TreePath.from_indices (4)); Gtk.TreeSelection selection = states_treeview.get_selection (); selection.changed.disconnect (on_states_treeview_selection_changed); selection.select_iter (iter); selection.changed.connect_after (on_states_treeview_selection_changed); refresh_packages_list (); } } } [GtkCallback] void on_apply_button_clicked () { if (filters_stack.visible_child_name == "updates") { force_refresh = false; refreshing = true; try_lock_and_run (run_refresh); } else { try_lock_and_run (run_transaction); } } void run_transaction () { transaction_running = true; apply_button.sensitive = false; cancel_button.sensitive = false; transaction_infobox.show_all (); transaction.run (); } void run_sysupgrade () { sysupgrade_running = true; apply_button.sensitive = false; cancel_button.sensitive = false; transaction.sysupgrade (false); } [GtkCallback] void on_cancel_button_clicked () { if (waiting) { waiting = false; transaction.stop_progressbar_pulse (); transaction.to_load.remove_all (); transaction.unlock (); set_pendings_operations (); } else if (transaction_running) { transaction_running = false; transaction.cancel (); } else if (refreshing) { refreshing = false; transaction.cancel (); } else if (sysupgrade_running) { sysupgrade_running = false; transaction.cancel (); #if DISABLE_AUR #else transaction.to_build.remove_all (); #endif } else { transaction.clear_lists (); set_pendings_operations (); refresh_packages_list (); if (main_stack.visible_child_name == "details") { if (transaction.get_installed_pkg (current_package_displayed).name != "" || transaction.get_sync_pkg (current_package_displayed).name != "") { display_package_properties (current_package_displayed); #if DISABLE_AUR #else } else { display_aur_properties (current_package_displayed); #endif } } while (Gtk.events_pending ()) { Gtk.main_iteration (); } } } [GtkCallback] void on_refresh_button_clicked () { force_refresh = true; try_lock_and_run (run_refresh); } void run_refresh () { this.get_window ().set_cursor (new Gdk.Cursor.for_display (Gdk.Display.get_default (), Gdk.CursorType.WATCH)); apply_button.sensitive = false; cancel_button.sensitive = true; transaction_infobox.show_all (); transaction.start_refresh (force_refresh); } void on_get_updates_finished (Updates updates) { if (filters_stack.visible_child_name == "updates") { transaction.to_update.remove_all (); packages_stackswitcher.visible = false; #if DISABLE_AUR if ((updates.repos_updates.length) == 0) { #else if ((updates.repos_updates.length + updates.aur_updates.length) == 0) { #endif filters_stack.visible = false; if (!refreshing && !transaction_running && !sysupgrade_running) { transaction_infobox.visible = false; } packages_stack.visible_child_name = "updated"; this.get_window ().set_cursor (null); } else { if (updates.repos_updates.length > 0) { foreach (unowned AlpmPackage pkg in updates.repos_updates) { if (!transaction.temporary_ignorepkgs.contains (pkg.name)) { transaction.to_update.add (pkg.name); } } populate_packages_list (updates.repos_updates); } #if DISABLE_AUR #else if (updates.aur_updates.length > 0) { packages_stackswitcher.visible = true; foreach (unowned AURPackage pkg in updates.aur_updates) { if (!transaction.temporary_ignorepkgs.contains (pkg.name)) { transaction.to_update.add (pkg.name); } } populate_aur_list (updates.aur_updates); if (updates.repos_updates.length == 0) { packages_stack.visible_child_name = "aur"; } } #endif set_pendings_operations (); } } #if DISABLE_AUR else if ((updates.repos_updates.length) > 0) { #else else if ((updates.repos_updates.length + updates.aur_updates.length) > 0) { #endif this.get_window ().set_cursor (null); var attention_val = GLib.Value (typeof (bool)); attention_val.set_boolean (true); filters_stack.child_set_property (filters_stack.get_child_by_name ("updates"), "needs-attention", attention_val); } } void on_start_downloading () { cancel_button.sensitive = true; } void on_stop_downloading () { cancel_button.sensitive = false; } #if DISABLE_AUR #else void on_start_building () { cancel_button.sensitive = true; } void on_stop_building () { cancel_button.sensitive = false; } #endif void on_important_details_outpout (bool must_show) { if (must_show) { main_stack.visible_child_name = "term"; button_back.visible = false; } else if (main_stack.visible_child_name != "term") { important_details = true; details_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); } } void on_generate_mirrors_list () { generate_mirrors_list = true; apply_button.sensitive = false; transaction_infobox.show_all (); } void on_transaction_finished (bool success) { transaction.refresh_handle (); if (main_stack.visible_child_name == "details") { if (transaction.get_installed_pkg (current_package_displayed).name != "" || transaction.get_sync_pkg (current_package_displayed).name != "") { display_package_properties (current_package_displayed); #if DISABLE_AUR #else } else { display_aur_properties (current_package_displayed); #endif } } else if (main_stack.visible_child_name == "term") { button_back.visible = true; } transaction.to_load.remove_all (); if (refreshing) { refreshing = false; run_sysupgrade (); } else if (sysupgrade_running) { sysupgrade_running = false; #if DISABLE_AUR #else transaction.to_build.remove_all (); #endif transaction.unlock (); refresh_packages_list (); } else { transaction_running = false; generate_mirrors_list = false; transaction.unlock (); refresh_packages_list (); } set_pendings_operations (); } } }