// pkg_item.cc // // Copyright 1999-2005, 2007 Daniel Burrows // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. // // Definitions of stuff in pkg_item.h #include "aptitude.h" #include #include #include #include #include #include "edit_pkg_hier.h" #include "pkg_columnizer.h" #include "pkg_item.h" #include "ui.h" #include "view_changelog.h" #include "vs_progress.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const char *confirm_str=N_("Yes, I am aware this is a very bad idea"); static void try_delete_essential(wstring s, const pkgCache::PkgIterator pkg, bool purge) { if(s==transcode(_(confirm_str))) { undo_group *grp=new apt_undo_group; (*apt_cache_file)->mark_delete(pkg, purge, false, grp); if(grp->empty()) delete grp; else apt_undos->add_item(grp); } } static void confirm_delete_essential(const pkgCache::PkgIterator &pkg, bool purge) { eassert((pkg->Flags&pkgCache::Flag::Essential)==pkgCache::Flag::Essential || (pkg->Flags&pkgCache::Flag::Important)==pkgCache::Flag::Important); fragment *f=wrapbox(fragf(_("%s is an essential package!%n%nAre you sure you want to remove it?%nType '%s' if you are."), pkg.Name(), _(confirm_str))); vs_widget_ref w=vs_dialog_string(f, L"", arg(sigc::bind(sigc::ptr_fun(try_delete_essential), pkg, purge)), NULL, NULL, NULL, style_attrs_flip(A_REVERSE)); w->show_all(); popup_widget(w); } pkg_item::pkg_item(const pkgCache::PkgIterator &_package, sigc::signal2 *sig) :package(_package), info_signal(sig) { highlighted_changed.connect(sigc::mem_fun(this, &pkg_item::do_highlighted_changed)); } void pkg_item::do_highlighted_changed(bool highlighted) { if(highlighted) { if(info_signal) (*info_signal)(package, visible_version()); } else { if(info_signal) (*info_signal)(pkgCache::PkgIterator(), pkgCache::VerIterator(*apt_cache_file)); } } void pkg_item::do_select(undo_group *undo) { (*apt_cache_file)->mark_install(package, aptcfg->FindB(PACKAGE "::Auto-Install", true), false, undo); } void pkg_item::select(undo_group *undo) { if(aptcfg->FindB(PACKAGE "::UI::New-Package-Commands", true)) do_select(undo); else if(!(*apt_cache_file)[package].Delete()) do_select(undo); else do_hold(undo); } void pkg_item::do_hold(undo_group *undo) // Sets an explicit hold state. { (*apt_cache_file)->mark_keep(package, false, true, undo); } void pkg_item::hold(undo_group *undo) // Sets an /explicit/ hold state. May be useful for, eg, saying that the // current package version (which is the newest) should be kept even if/when // a newer version becomes available. { if(aptcfg->FindB(PACKAGE "::UI::New-Package-Commands", true)) do_hold(undo); else // Toggle the held state. (*apt_cache_file)->mark_keep(package, false, (*apt_cache_file)->get_ext_state(package).selection_state!=pkgCache::State::Hold, undo); } void pkg_item::keep(undo_group *undo) { // Keep, don't hold, the package. (*apt_cache_file)->mark_keep(package, false, false, undo); } void pkg_item::do_remove(undo_group *undo) { if((package->Flags&pkgCache::Flag::Essential)==pkgCache::Flag::Essential || (package->Flags&pkgCache::Flag::Important)==pkgCache::Flag::Important) confirm_delete_essential(package, false); else (*apt_cache_file)->mark_delete(package, false, false, undo); } void pkg_item::remove(undo_group *undo) { if(aptcfg->FindB(PACKAGE "::UI::New-Package-Commands", true)) do_remove(undo); else if(!(*apt_cache_file)[package].Install() && !((*apt_cache_file)[package].iFlags&pkgDepCache::ReInstall)) do_remove(undo); else { if((*apt_cache_file)[package].iFlags&pkgDepCache::ReInstall) (*apt_cache_file)->mark_keep(package, false, false, undo); else (*apt_cache_file)->mark_keep(package, false, (*apt_cache_file)[package].Status==1, undo); } } // No "do_purge" because purge was always idempotent. void pkg_item::purge(undo_group *undo) { if((package->Flags&pkgCache::Flag::Essential)==pkgCache::Flag::Essential || (package->Flags&pkgCache::Flag::Important)==pkgCache::Flag::Important) confirm_delete_essential(package, false); else (*apt_cache_file)->mark_delete(package, true, false, undo); } void pkg_item::reinstall(undo_group *undo) { if(!package.CurrentVer().end()) (*apt_cache_file)->mark_install(package, aptcfg->FindB(PACKAGE "::Auto-Install", true), true, undo); } void pkg_item::forbid_upgrade(undo_group *undo) { pkgCache::VerIterator curver=package.CurrentVer(); pkgCache::VerIterator candver=(*apt_cache_file)[package].CandidateVerIter(*apt_cache_file); if(!curver.end() && !candver.end() && curver!=candver) (*apt_cache_file)->forbid_upgrade(package, candver.VerStr(), undo); } void pkg_item::set_auto(bool isauto, undo_group *undo) { (*apt_cache_file)->mark_auto_installed(package, isauto, undo); } void pkg_item::show_information() { char buf[512]="Foo"; snprintf(buf, 512, _("Information about %s"), package.Name()); string menulabel(buf); snprintf(buf, 512, _("%s info"), package.Name()); string tablabel(buf); vs_widget_ref w=make_info_screen(package, visible_version()); // what to use as the menu description? insert_main_widget(w, menulabel, "", tablabel); } void pkg_item::show_changelog() { view_changelog(visible_version()); } style pkg_item::get_highlight_style() { return vs_treeitem::get_normal_style() + pkg_style(package, true); } style pkg_item::get_normal_style() { return vs_treeitem::get_normal_style() + pkg_style(package, false); } #define MAYBE_HIGHLIGHTED(x) (highlighted ? (x "Highlighted") : (x)) style pkg_item::pkg_style(pkgCache::PkgIterator package, bool highlighted) { if(package.VersionList().end()) { bool present_now=false, present_inst=false; for(pkgCache::PrvIterator i=package.ProvidesList(); !i.end(); i++) { if(!i.OwnerPkg().CurrentVer().end()) present_now=true; if(!(*apt_cache_file)[i.OwnerPkg()].InstVerIter(*apt_cache_file).end()) present_inst=true; if(present_now && present_inst) break; } if(present_now && present_inst) return get_style(MAYBE_HIGHLIGHTED("PkgIsInstalled")); else if(present_now) return get_style(MAYBE_HIGHLIGHTED("PkgToRemove")); else if(present_inst) return get_style(MAYBE_HIGHLIGHTED("PkgToInstall")); else return get_style(MAYBE_HIGHLIGHTED("PkgNotInstalled")); } else { pkgDepCache::StateCache &state=(*apt_cache_file)[package]; if(!state.InstBroken() && (state.NewInstall() || (state.iFlags&pkgDepCache::ReInstall))) return get_style(MAYBE_HIGHLIGHTED("PkgToInstall")); else if(state.Status!=2 && // Not being upgraded (*apt_cache_file)->get_ext_state(package).selection_state==pkgCache::State::Hold // Flagged for hold && !state.InstBroken()) // Not currently broken. return get_style(MAYBE_HIGHLIGHTED("PkgToHold")); else if(state.Delete()) return get_style(MAYBE_HIGHLIGHTED("PkgToRemove")); else if(state.InstBroken()) return get_style(MAYBE_HIGHLIGHTED("PkgBroken")); else if(state.Upgrade()) return get_style(MAYBE_HIGHLIGHTED("PkgToUpgrade")); else if(state.Downgrade()) return get_style(MAYBE_HIGHLIGHTED("PkgToDowngrade")); else if(package.CurrentVer().end()) return get_style(MAYBE_HIGHLIGHTED("PkgNotInstalled")); else return get_style(MAYBE_HIGHLIGHTED("PkgIsInstalled")); } } void pkg_item::paint(vs_tree *win, int y, bool hierarchical, const style &st) { int basex=hierarchical?2*get_depth():0; int width, height; win->getmaxyx(height, width); pkg_columnizer::setup_columns(); empty_column_parameters p; wstring disp=pkg_columnizer(package, visible_version(), pkg_columnizer::get_columns(), basex).layout_columns(width, p); win->mvaddnstr(y, 0, disp.c_str(), width); } bool pkg_item::dispatch_key(const key &k, vs_tree *owner) { if(bindings->key_matches(k, "Versions")) { char buf[512]; snprintf(buf, 512, _("Available versions of %s"), package.Name()); string menulabel(buf); snprintf(buf, 512, _("%s versions"), package.Name()); string tablabel(buf); vs_widget_ref w=make_ver_screen(package); insert_main_widget(w, menulabel, "", tablabel); } else if(bindings->key_matches(k, "Dependencies")) { if(!visible_version().end()) { char buf[512]; snprintf(buf, 512, _("Dependencies of %s"), package.Name()); string menulabel(buf); snprintf(buf, 512, _("%s deps"), package.Name()); string tablabel(buf); vs_widget_ref w=make_dep_screen(package, visible_version()); insert_main_widget(w, menulabel, "", tablabel); w->show(); } } else if(bindings->key_matches(k, "ReverseDependencies")) { char buf[512]; snprintf(buf, 512, _("Packages depending on %s"), package.Name()); string menulabel(buf); snprintf(buf, 512, _("%s reverse deps"), package.Name()); string tablabel(buf); vs_widget_ref w=make_dep_screen(package, visible_version(), true); insert_main_widget(w, menulabel, "", tablabel); } else if(bindings->key_matches(k, "InfoScreen")) show_information(); else if(bindings->key_matches(k, "Changelog") && !visible_version().end()) show_changelog(); else if(bindings->key_matches(k, "InstallSingle")) { if((*apt_cache_file)[package].CandidateVerIter(*apt_cache_file).end()) return true; undo_group *grp=new apt_undo_group; (*apt_cache_file)->mark_single_install(package, grp); if(!grp->empty()) apt_undos->add_item(grp); else delete grp; } else if(bindings->key_matches(k, "ForbidUpgrade")) { undo_group *grp=new apt_undo_group; forbid_upgrade(grp); if(!grp->empty()) apt_undos->add_item(grp); else delete grp; } else if(bindings->key_matches(k, "BugReport")) { // Try to report a bug on the package. (ew quoting ew) string cmd=string("reportbug '")+package.Name()+"'"; // Default to reporting a bug on the current version. pkgCache::VerIterator ver=package.CurrentVer(); if(ver.end()) ver=visible_version(); if(ver.end()) ver=package.VersionList(); if(!ver.end()) cmd+=string(" -V '")+ver.VerStr()+"'"; vscreen_suspend(); printf(_("Reporting a bug in %s:\n"), package.Name()); system(cmd.c_str()); vscreen_resume(); } else if(bindings->key_matches(k, "DpkgReconfigure")) // Don't bother with my internal su-to-root stuff here, since I don't // need to touch the package lists in the subprocess. { // Try to do *something*. const char *sucmd=NULL; if(getuid()==0) sucmd="dpkg-reconfigure '%s'"; else if(access("/usr/sbin/su-to-root", X_OK)==0) sucmd="/usr/sbin/su-to-root -c \"/usr/sbin/dpkg-reconfigure '%s'\""; else if(access("/bin/su", X_OK)==0) sucmd="/bin/su -c \"/usr/sbin/dpkg-reconfigure '%s'\""; else popup_widget(vs_dialog_ok(text_fragment(_("You are not root and I cannot find any way to become root. To reconfigure this package, install the menu package, the login package, or run aptitude as root.")))); if(sucmd) { vscreen_suspend(); apt_cache_file->ReleaseLock(); printf(_("Reconfiguring %s\n"), package.Name()); char buf[512]; if(sucmd) { snprintf(buf, 512, sucmd, package.Name()); system(buf); cerr<<_("Press return to continue.\n"); getchar(); vscreen_resume(); } vs_progress_ref p = gen_progress_bar(); apt_reload_cache(p.unsafe_get_ref(), true); p->destroy(); } } else if(bindings->key_matches(k, "EditHier")) { vs_hier_editor_ref e=vs_hier_editor::create(); e->set_package(package, visible_version()); // FIXME: better title add_main_widget(e, _("Hierarchy editor"), "", _("Hierarchy Editor")); e->connect_key("Quit", &global_bindings, sigc::mem_fun(*e.unsafe_get_ref(), &vscreen_widget::destroy)); } else return pkg_tree_node::dispatch_key(k, owner); return true; } void pkg_item::dispatch_mouse(short id, int x, mmask_t bstate, vs_tree *owner) { if(bstate & (BUTTON1_DOUBLE_CLICKED | BUTTON2_DOUBLE_CLICKED | BUTTON3_DOUBLE_CLICKED | BUTTON4_DOUBLE_CLICKED | BUTTON1_TRIPLE_CLICKED | BUTTON2_TRIPLE_CLICKED | BUTTON3_TRIPLE_CLICKED | BUTTON4_TRIPLE_CLICKED)) show_information(); } bool pkg_item::matches(const string &s) const { return pkg_matches(s, package, visible_version(), *apt_cache_file, *apt_package_records); } pkgCache::VerIterator pkg_item::visible_version(const pkgCache::PkgIterator &pkg) { pkgDepCache::StateCache &state=(*apt_cache_file)[pkg]; pkgCache::VerIterator candver=state.CandidateVerIter(*apt_cache_file); if(!candver.end()) return candver; else if(pkg.CurrentVer().end() && state.Install()) return state.InstVerIter(*apt_cache_file); // Return the to-be-installed version else return pkg.CurrentVer(); } const wchar_t *pkg_item::tag() { // FIXME: ew static wstring pkgname; pkgname=transcode(package.Name(), "ASCII"); return pkgname.c_str(); } const wchar_t *pkg_item::label() { // FIXME: ew static wstring pkgname; pkgname=transcode(package.Name(), "ASCII"); return pkgname.c_str(); } const pkgCache::PkgIterator &pkg_item::get_package() const { return package; } pkgCache::VerIterator pkg_item::visible_version() const { return visible_version(package); } //////////////////////// Menu redirections: ///////////////////////////// bool pkg_item::package_forbid_enabled() { return true; } bool pkg_item::package_forbid() { undo_group *grp=new apt_undo_group; forbid_upgrade(grp); if(!grp->empty()) apt_undos->add_item(grp); else delete grp; package_states_changed(); return true; } bool pkg_item::package_changelog_enabled() { return true; } bool pkg_item::package_changelog() { show_changelog(); return true; } bool pkg_item::package_information_enabled() { return true; } bool pkg_item::package_information() { show_information(); return true; }