⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 maintreeview.cc

📁 About: Paco (pacKAGE oRGANIZER) is a simple, yet powerful tool to aid package management when insta
💻 CC
字号:
//=======================================================================// MainTreeView.cc//-----------------------------------------------------------------------// This file is part of the package paco// Copyright (C) 2004-2007 David Rosal <david.3r@gmail.com>// For more information visit http://paco.sourceforge.net//=======================================================================#include "config.h"#include "globals.h"#include "Lock.h"#include "Config.h"#include "PkgSet.h"#include "Pkg.h"#include "util.h"#include "MainTreeView.h"#include "MainWindow.h"#include <gtkmm/cellrendererprogress.h>#include <gtkmm/stock.h>#include <gtkmm/menu.h>#include <gtkmm/liststore.h>#include <gtkmm/uimanager.h>#include <gtkmm/actiongroup.h>#include <sstream>using Glib::ustring;using std::string;using std::vector;using std::for_each;using sigc::mem_fun;using sigc::bind;using namespace Gpaco;//--------//// public ////--------//MainTreeView::MainTreeView():	Gtk::TreeView(),	mPkgSet(),	mColumns(),	mpModel(Gtk::ListStore::create(mColumns)),	mpMenu(NULL),	mpUIManager(Gtk::UIManager::create()),	mpActionFiles(Gtk::Action::create("Files", Gtk::Stock::JUSTIFY_FILL,		"View _files")),	mpActionInfo(Gtk::Action::create("Info", Gtk::Stock::INFO,		"_Information")),	mpActionRemove(Gtk::Action::create("Remove", Gtk::Stock::DELETE,		"_Remove...")),	mpActionPackage(Gtk::Action::create("Package", Gtk::Stock::EXECUTE,		"Create _package...")),	mpActionUpdate(Gtk::Action::create("Update", Gtk::Stock::REFRESH,		"_Update...")),	mpActionUnlog(Gtk::Action::create("Unlog", Gtk::Stock::REMOVE,		"Remove from _database...")){	(get_selection())->set_mode(Gtk::SELECTION_MULTIPLE);	show();	// so that we can set the visibility of its children in addColumn()	addColumn(mColumns.mIcon, "", &MainTreeView::iconSortFunc);	addColumn(mColumns.mName, "Name", &MainTreeView::nameSortFunc);	addColumn(mColumns.mSizeInst, "Size",		&MainTreeView::sizeInstSortFunc, &MainTreeView::sizeCellFunc, 1.);	addColumn(mColumns.mSizeMiss, "Size Miss",		&MainTreeView::sizeMissSortFunc, &MainTreeView::sizeCellFunc, 1.);	addProgressColumn(mColumns.mSizePercent, "Size %",		&MainTreeView::sizePercentSortFunc);	addColumn(mColumns.mDate, "Date",		&MainTreeView::dateSortFunc, &MainTreeView::dateCellFunc);	addColumn(mColumns.mFilesInst, "Files",		&MainTreeView::filesInstSortFunc, NULL, 1.);	addColumn(mColumns.mFilesMiss, "Files Miss",		&MainTreeView::filesMissSortFunc, NULL, 1.);	addProgressColumn(mColumns.mFilesPercent, "Files %",		&MainTreeView::filesPercentSortFunc);	addColumn(mColumns.mSummary, "Summary", &MainTreeView::summarySortFunc);	// Populate the tree model	for (PkgSet::iterator p = mPkgSet.begin(); p != mPkgSet.end(); ++p)		*this += *p;	set_model(mpModel);	// Build the popup menu	Glib::RefPtr<Gtk::ActionGroup> pActionGroup(Gtk::ActionGroup::create());	pActionGroup->add(mpActionFiles, bind<int>		(mem_fun(*this, &MainTreeView::onPkgWindow), TAB_FILES));	pActionGroup->add(mpActionInfo, bind<int>		(mem_fun(*this, &MainTreeView::onPkgWindow), TAB_INFO));	pActionGroup->add(mpActionRemove, bind<int>		(mem_fun(*this, &MainTreeView::onPkgWindow), TAB_REMOVE));	pActionGroup->add(mpActionPackage, bind<int>		(mem_fun(*this, &MainTreeView::onPkgWindow), TAB_PACKAGE));	pActionGroup->add(mpActionUpdate, mem_fun(*this, &MainTreeView::onUpdate));	pActionGroup->add(mpActionUnlog, mem_fun(*this, &MainTreeView::onUnlog));	mpUIManager->insert_action_group(pActionGroup);	mpUIManager->add_ui_from_string(		"<ui>"		"	<popup name='PopupMenu'>"		"		<menuitem action='Files'/>"		"		<menuitem action='Info'/>"		"		<menuitem action='Remove'/>"		"		<menuitem action='Package'/>"		"		<separator/>"		"		<menuitem action='Update'/>"		"		<menuitem action='Unlog'/>"		"	</popup>"		"</ui>");		mpMenu = dynamic_cast<Gtk::Menu*>(mpUIManager->get_widget("/PopupMenu"));	Glib::signal_timeout().connect(mem_fun		(*this, &MainTreeView::rewriteRows), 128);}// [virtual]MainTreeView::~MainTreeView(){ }void MainTreeView::refresh(){	mpModel->foreach(mem_fun(*this, &MainTreeView::rowChanged));	for_each(mPkgSet.begin(), mPkgSet.end(), std::mem_fun(&Pkg::refreshFilesTab));}void MainTreeView::switchRules(){	set_rules_hint(!get_rules_hint());	Config::rules(get_rules_hint());	for_each(mPkgSet.begin(), mPkgSet.end(), std::mem_fun(&Pkg::switchRules));}// Add newly logged packagesvoid MainTreeView::addNewPackages(){	Lock lock;	Glib::Dir dir(Config::logdir());	for (Glib::Dir::iterator d = dir.begin(); d != dir.end(); ++d) {		if (!mPkgSet.hasPkg(*d)) {			try {				Pkg* pkg = new Pkg(*d);				mPkgSet += pkg;				*this += pkg;			}			catch (...) { }		}	}}void MainTreeView::onUpdateDataBase(){	g_assert(Config::logdirWritable());	updatePkgs(mPkgSet);	addNewPackages();}//---------//// private ////---------//void MainTreeView::markUnloggedPackages(){	for (PkgSet::iterator p = mPkgSet.begin(); p != mPkgSet.end(); ++p) {		if (access((*p)->log().c_str(), F_OK) < 0)			(*p)->changed(true);	}}bool MainTreeView::rewriteRow(iterator const& it){	Pkg* pkg = (*it)[mColumns.mPkg];	g_assert(pkg != NULL);	if (!pkg->changed())		return false;	else if (!pkg->window() && access(pkg->log().c_str(), F_OK) < 0) {		*this -= pkg;		mPkgSet -= pkg;		return true;	}	else {		writeRow(*pkg, it);		pkg->changed(false);	}		return false;}bool MainTreeView::rewriteRows(){	if (!Lock::locked())		mpModel->foreach_iter(mem_fun(*this, &MainTreeView::rewriteRow));	return true;}void MainTreeView::writeRow(Pkg& pkg, iterator const& it){	(*it)[mColumns.mPkg] = &pkg;	if (pkg.icon()) {		(*it)[mColumns.mIcon] = pkg.icon()->scale_simple(			CELL_HEIGHT, CELL_HEIGHT, Gdk::INTERP_BILINEAR);	}	(*it)[mColumns.mName]			= pkg.name();	(*it)[mColumns.mSizeInst]		= pkg.sizeInst();	(*it)[mColumns.mSizeMiss]		= pkg.sizeMiss();	(*it)[mColumns.mSizePercent]	= pkg.sizePercent();	(*it)[mColumns.mDate]			= pkg.date();	(*it)[mColumns.mFilesInst]		= pkg.filesInst();	(*it)[mColumns.mFilesMiss]		= pkg.filesMiss();	(*it)[mColumns.mFilesPercent]	= pkg.filesPercent();	(*it)[mColumns.mSummary]		= pkg.summary();}//// Add a new package to the tree view//MainTreeView& MainTreeView::operator+=(Pkg* pkg){	g_assert(pkg != NULL);	writeRow(*pkg, mpModel->append());	return *this;}//// Remove the row of a package from the view.//MainTreeView& MainTreeView::operator-=(Pkg* pkg){	g_assert(pkg != NULL);	iterator it;	if (getIter(*pkg, it))		mpModel->erase(it);	return *this;}void MainTreeView::onPkgWindow(int tab){	vector<Pkg*> pkgs = getSelectedPkgs();	if (pkgs.size() == 1)		(*(pkgs.begin()))->presentWindow(tab);}void MainTreeView::onUpdate(){	vector<Pkg*> pkgs = getSelectedPkgs();	updatePkgs(pkgs);}void MainTreeView::updatePkgs(vector<Pkg*>& pkgs){	if (pkgs.empty())		return;	Lock lock;	gpMainWindow->progressBar().show();	// Update the packages in the main window	float cnt = 0;	for (PkgSet::iterator p = pkgs.begin(); p != pkgs.end(); ++p) {		if (!gpMainWindow->is_visible())			return;		(*p)->update();		gpMainWindow->progressBar().set_fraction(++cnt / pkgs.size());		refreshMainLoop();	}	gpMainWindow->progressBar().hide();}//// Unlog the selected packages//void MainTreeView::onUnlog(){	if (Lock::locked() || !Config::logdirWritable())		return;		Lock lock;	vector<Pkg*> pkgs = getSelectedPkgs();	g_assert(pkgs.empty() == false);	vector<Pkg*>::iterator p = pkgs.begin();	std::ostringstream msg;		if (pkgs.size() == 1)		msg << "Remove " << (*p)->name() << " from the database ?\n";	else {		msg << "Remove the following packages from the database ?\n\n";		guint cnt = 0;		for ( ; p != pkgs.end() && cnt < 16; ++p, ++cnt)			msg << "\t" << (*p)->name() << "\n";		if (pkgs.size() > cnt)			msg << "\t... (" << pkgs.size() - cnt << " more packages)\n";	}	if (!questionDialog(NULL, msg.str()))		return;	for (p = pkgs.begin(); p != pkgs.end(); ++p) {		if (access((*p)->log().c_str(), F_OK) || !unlink((*p)->log().c_str())) {			if ((*p)->window())				(*p)->deleteWindow();			(*p)->changed(true);		}		else {			errorDialog(NULL, "unlink(" + (*p)->log() + "): " + Glib::strerror(errno));			break;		}	}}//// Get the curently selected packages//vector<Pkg*> MainTreeView::getSelectedPkgs(){	vector<Gtk::TreeModel::Path> rows = (get_selection())->get_selected_rows();	vector<Gtk::TreeModel::Path>::iterator p;	vector<Pkg*> pkgs;		for (p = rows.begin(); p != rows.end(); ++p) {		Pkg* pkg = (*(mpModel->get_iter(*p)))[mColumns.mPkg];		g_assert(pkg != NULL);		pkgs.push_back(pkg);	}	return pkgs;}//// Try to get the iter of a package. Return true on success.//bool MainTreeView::getIter(Pkg const& pkg, iterator& it){	Gtk::TreeModel::Children child = mpModel->children();	for (it = child.begin(); it != child.end(); ++it) {		if (&pkg == (*it)[mColumns.mPkg])			return true;	}	return false;}void MainTreeView::popupMenu(int rows, GdkEventButton* e){	mpActionFiles->set_sensitive(rows == 1);	mpActionInfo->set_sensitive(rows == 1);	mpActionRemove->set_sensitive(rows == 1 && Config::logdirWritable());	mpActionPackage->set_sensitive(rows == 1);	mpActionUpdate->set_sensitive(!Lock::locked() && Config::logdirWritable());	mpActionUnlog->set_sensitive(!Lock::locked() && Config::logdirWritable());	mpMenu->popup(e->button, e->time);}// [virtual]bool MainTreeView::on_button_press_event(GdkEventButton* e){	bool ret = true;	// Double click on the left mouse button	if (e->type == GDK_2BUTTON_PRESS && e->button == 1) {		ret = Gtk::TreeView::on_button_press_event(e);		onPkgWindow(TAB_FILES);	}	// Single click on the right mouse button	else if (e->type == GDK_BUTTON_PRESS && e->button == 3) {		int rows = (get_selection())->count_selected_rows();		if (!rows) {			ret = Gtk::TreeView::on_button_press_event(e);			rows = 1;		}		popupMenu(rows, e);	}	else		ret = Gtk::TreeView::on_button_press_event(e);	return ret;}// [virtual]bool MainTreeView::on_key_press_event(GdkEventKey* e){	bool done = false;	int rows = (get_selection())->count_selected_rows();	if (rows) {		switch (e->keyval) {			case GDK_Delete:				onUnlog();				done = true;				break;			case GDK_Return:				onPkgWindow(TAB_FILES);				done = true;		}	}	return done ? true : Gtk::TreeView::on_key_press_event(e);}void MainTreeView::sizeCellFunc(Gtk::CellRenderer* pCell, iterator const&){	Gtk::CellRendererText* pCellText =		dynamic_cast<Gtk::CellRendererText*>(pCell);	ustring txt(pCellText->property_text());	ustring newText(Paco::sizeStr(Config::sizeUnit(), Paco::str2num<long>(txt)));	switch (Config::sizeUnit()) {		case Paco::KILOBYTE: newText += 'k'; break;		case Paco::MEGABYTE: newText += 'M';	}	pCellText->property_text() = newText;}void MainTreeView::dateCellFunc(Gtk::CellRenderer* pCell, iterator const& it){    int date = (*it)[mColumns.mDate];    struct tm* t = NULL;    time_t __time = (time_t)date;	char txt[64] = " ";	if (date && (t = localtime(&__time))) {		ustring fmt = "%d-%b-%Y";		if (Config::hour())			fmt += "  %H:%M";		strftime(txt, sizeof(txt) - 1, fmt.c_str(), t);	}		(dynamic_cast<Gtk::CellRendererText*>(pCell))->property_text() = txt;}void MainTreeView::addProgressColumn(	Gtk::TreeModelColumn<float> const& col,										ustring const& title,										SortFunc sortFunc)	// = NULL{   	Gtk::CellRendererProgress* pCell = new Gtk::CellRendererProgress;	int id = append_column(title, *pCell) - 1;    g_assert(id >= 0);	Gtk::TreeViewColumn* pCol = get_column(id);	g_assert(pCol != NULL);	pCell->set_fixed_size(PROGRESS_CELL_WIDTH, CELL_HEIGHT);	pCol->set_sort_column(id);	pCol->set_visible(false);	pCol->set_resizable(true);    #if GLIBMM_PROPERTIES_ENABLED	pCol->add_attribute(pCell->property_value(), col);#else	pCol->add_attribute(*pCell, "value", col);#endif	if (sortFunc)		mpModel->set_sort_func(id, mem_fun(*this, sortFunc));}template <typename T>void MainTreeView::addColumn(	Gtk::TreeModelColumn<T> const& col,								ustring const& title,								SortFunc sortFunc,								CellFunc cellFunc,								gfloat xalign /* = 0. */){   	int id = append_column(title, col) - 1;	g_assert(id >= 0);	Gtk::TreeViewColumn* pCol = get_column(id);	g_assert(pCol != NULL);	pCol->set_sort_column(id);	pCol->set_visible(false);	pCol->set_resizable(id != COL_ICON);	pCol->set_alignment(xalign);	Gtk::CellRenderer* pCell = pCol->get_first_cell_renderer();	pCell->set_fixed_size(-1, CELL_HEIGHT);	pCell->property_xalign() = xalign;    	if (sortFunc)		mpModel->set_sort_func(id, mem_fun(*this, sortFunc));	if (cellFunc)		pCol->set_cell_data_func(*pCell, mem_fun(*this, cellFunc));}int MainTreeView::summarySortFunc(iterator const& a, iterator const& b){	ustring aStr = (*a)[mColumns.mSummary];	ustring bStr = (*b)[mColumns.mSummary];	return aStr.lowercase() < bStr.lowercase() ? -1 : 1;}int MainTreeView::dateSortFunc(iterator const& a, iterator const& b){	return (*a)[mColumns.mDate] < (*b)[mColumns.mDate] ? -1 : 1;}int MainTreeView::filesInstSortFunc(iterator const& a, iterator const& b){	return (*a)[mColumns.mFilesInst] < (*b)[mColumns.mFilesInst] ? -1 : 1;}int MainTreeView::filesMissSortFunc(iterator const& a, iterator const& b){	return (*a)[mColumns.mFilesMiss] < (*b)[mColumns.mFilesMiss] ? -1 : 1;}int MainTreeView::sizeInstSortFunc(iterator const& a, iterator const& b){	return (*a)[mColumns.mSizeInst] < (*b)[mColumns.mSizeInst] ? -1 : 1;}int MainTreeView::sizeMissSortFunc(iterator const& a, iterator const& b){	return (*a)[mColumns.mSizeMiss] < (*b)[mColumns.mSizeMiss] ? -1 : 1;}int MainTreeView::sizePercentSortFunc(iterator const& a, iterator const& b){	return (*a)[mColumns.mSizePercent] < (*b)[mColumns.mSizePercent] ? -1 : 1;}int MainTreeView::filesPercentSortFunc(iterator const& a, iterator const& b){	return (*a)[mColumns.mFilesPercent] < (*b)[mColumns.mFilesPercent] ? -1 : 1;}int MainTreeView::nameSortFunc(iterator const& a, iterator const& b){	ustring aStr = (*a)[mColumns.mName];	ustring bStr = (*b)[mColumns.mName];	return aStr.lowercase() < bStr.lowercase() ? -1 : 1;}int MainTreeView::iconSortFunc(iterator const& a, iterator const&){	Glib::RefPtr<Gdk::Pixbuf> pixbuf = (*a)[mColumns.mIcon];	return pixbuf ? -1 : 1;}bool MainTreeView::rowChanged(	Gtk::TreeModel::Path const& path,								iterator const& it){	mpModel->row_changed(path, it);	return false;}//----------------------------------//// class MainTreeView::ModelColumns ////----------------------------------//MainTreeView::ModelColumns::ModelColumns(){	add(mPkg),	add(mIcon);	add(mName);	add(mSizeInst);	add(mSizeMiss);	add(mSizePercent);	add(mDate);	add(mFilesInst);	add(mFilesMiss);	add(mFilesPercent);	add(mSummary);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -