/** -*- Mode: C++; tab-width: 4 -*-
 * vim: sw=4 ts=4:
 *
 * Gnome Apt menu code
 *
 * 	(C) 1998 Havoc Pennington <hp@pobox.com>
 * 	    2002, 2003 Filip Van Raemdonck <mechanix@debian.org>
 *
 * 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * 	$Id$
 *
 **/

#include <apt-pkg/error.h>

#include "cachecontrol.h"
#include "drawtree.h"
#include "gaptpixbuf.h"
#include "menus.h"
#include "pkgtree.h"
#include "pkgutil.h"
#include "preferences.h"
#include "sources.h"

#define GNOME_APT_LOGO "/usr/share/pixmaps/gnome-apt.png"

// Columns
static void name_column_cb         (GtkWidget* w, gpointer data);
static void status_column_cb       (GtkWidget* w, gpointer data);
static void installed_column_cb    (GtkWidget* w, gpointer data);
static void available_column_cb    (GtkWidget* w, gpointer data);
static void section_column_cb      (GtkWidget* w, gpointer data);
static void priority_column_cb     (GtkWidget* w, gpointer data);
static void description_column_cb  (GtkWidget* w, gpointer data);

static void set_order_cb (GtkWidget*, gpointer);
static void set_grouping_cb (GtkWidget*, gpointer);
static void set_color_marker_cb (GtkWidget*, gpointer);

// File
static void apt_prefs_cb   (GtkWidget* w, gpointer data);
static void sources_cb (GtkWidget*, gpointer);
static void exit_cb        (GtkWidget* w, gpointer data);

// Actions
static void update_cb      (GtkWidget* w, gpointer data);
static void complete_run_cb (GtkWidget* w, gpointer data);
static void upgrade_cb      (GtkWidget* w, gpointer data);
static void smart_upgrade_cb(GtkWidget* w, gpointer data);
static void fix_broken_cb   (GtkWidget* w, gpointer data);

/* Package */
static void install_pkg_cb     (GtkWidget* w, gpointer data);
static void configure_pkg_cb   (GtkWidget* w, gpointer data);
static void upgrade_pkg_cb     (GtkWidget* w, gpointer data);
static void purge_pkg_cb       (GtkWidget* w, gpointer data);
static void remove_pkg_cb      (GtkWidget* w, gpointer data);
static void keep_pkg_cb        (GtkWidget* w, gpointer data);

/* View */
static void details_cb      (GtkWidget* w, gpointer data);
static void pending_cb (GtkWidget*, gpointer);

// Advanced
static void export_cb      (GtkWidget* w, gpointer data);
static void import_cb      (GtkWidget* w, gpointer data);
static void bug_cb         (GtkWidget* w, gpointer data);

// Help
static void about_cb       (GtkWidget* w, gpointer data);
static void icons_cb       (GtkWidget* w, gpointer data);

static GnomeUIInfo columns_menu[] = {
#define COLUMNS_NAME 0
	{ GNOME_APP_UI_TOGGLEITEM, N_("Package name"),
	      N_("Whether to show the package name column"),
	      (gpointer) name_column_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLUMNS_CURRENT 1
	{ GNOME_APP_UI_TOGGLEITEM, N_("Installed version"),
	      N_("Whether to show the installed version column"),
	      (gpointer) installed_column_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLUMNS_AVAILABLE 2
	{ GNOME_APP_UI_TOGGLEITEM, N_("Available version"),
	      N_("Whether to show the available version column"),
	      (gpointer) available_column_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLUMNS_SECTION 3
	{ GNOME_APP_UI_TOGGLEITEM, N_("Package section"),
	      N_("Whether to show the package section column"),
	      (gpointer) section_column_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLUMNS_PRIORITY 4
	{ GNOME_APP_UI_TOGGLEITEM, N_("Package priority"),
	      N_("Whether to show the package priority column"),
	      (gpointer) priority_column_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLUMNS_STATUS 5
	{ GNOME_APP_UI_TOGGLEITEM, N_("Package status"),
	      N_("Whether to show the package status column"),
	      (gpointer) status_column_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLUMNS_DESCRIPTION 6
	{ GNOME_APP_UI_TOGGLEITEM, N_("Description"),
	      N_("Whether to show the package description column"),
	      (gpointer) description_column_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },

	GNOMEUIINFO_END
};

static GnomeUIInfo order_items[] = {
#define ORDERS_NONE 0
	{ GNOME_APP_UI_ITEM, N_("Don't sort"),
	      N_("Show packages in random order"),
	      (gpointer) set_order_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define ORDERS_ALPHA 1
	{ GNOME_APP_UI_ITEM, N_("Sort alphabetically"),
	      N_("Order packages alphabetically"),
	      (gpointer) set_order_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define ORDERS_SECTION 2
	{ GNOME_APP_UI_ITEM, N_("Sort by section"),
	      N_("Order packages by the section they are in"),
	      (gpointer) set_order_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define ORDERS_STATUS 3
	{ GNOME_APP_UI_ITEM, N_("Sort by status"),
	      N_("Order packages by the status they have"),
	      (gpointer) set_order_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define ORDERS_PRIORITY 4
	{ GNOME_APP_UI_ITEM, N_("Sort by priority"),
	      N_("Order packages by priority they have"),
	      (gpointer) set_order_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },

	GNOMEUIINFO_END
};

static GnomeUIInfo order_menu[] = {
  GNOMEUIINFO_RADIOLIST(order_items),
  GNOMEUIINFO_END
};

static GnomeUIInfo group_items[] = {
#define GROUP_NONE 0
	{ GNOME_APP_UI_ITEM, N_("Don't group"),
	      N_("Group all packages together"),
	      (gpointer) set_grouping_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define GROUP_ALPHA 1
	{ GNOME_APP_UI_ITEM, N_("Group alphabetically"),
	      N_("Group packages by their first letter"),
	      (gpointer) set_grouping_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define GROUP_SECTION 2
	{ GNOME_APP_UI_ITEM, N_("Group by section"),
	      N_("Group packages from the same section"),
	      (gpointer) set_grouping_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define GROUP_STATUS 3
	{ GNOME_APP_UI_ITEM, N_("Group by status"),
	      N_("Group packages with the same status"),
	      (gpointer) set_grouping_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define GROUP_PRIORITY 4
	{ GNOME_APP_UI_ITEM, N_("Group by priority"),
	      N_("Group packages with the same priority"),
	      (gpointer) set_grouping_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },

	GNOMEUIINFO_END
};

static GnomeUIInfo group_menu[] = {
  GNOMEUIINFO_RADIOLIST(group_items),
  GNOMEUIINFO_END
};

static GnomeUIInfo marker_menu[] = {
#define COLMARK_BROKEN 0
	{ GNOME_APP_UI_TOGGLEITEM, N_("Mark broken packages (red)"),
	      N_("Whether to mark packages which are broken in red"),
	      (gpointer) set_color_marker_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLMARK_ORPHAN 1
	{ GNOME_APP_UI_TOGGLEITEM, N_("Mark orphaned packages (green)"),
	      N_("Whether to mark packages which are broken in green"),
	      (gpointer) set_color_marker_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
	      (GdkModifierType) 0, NULL },
#define COLMARK_END 2
	GNOMEUIINFO_END
};

static GnomeUIInfo view_menu[] = {
	{ GNOME_APP_UI_ITEM, N_("Package details"),
	      N_("Display package information in a separate window"),
		(gpointer) details_cb, NULL, NULL,
		GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_BOOK_OPEN, 'D',
		(GdkModifierType) GDK_CONTROL_MASK, NULL },
	{ GNOME_APP_UI_ITEM, N_("Pending changes"),
		N_("Show what actions would be performed when completing the install run"),
		(gpointer) pending_cb, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL,
		'\0', (GdkModifierType) 0, NULL },

	GNOMEUIINFO_SUBTREE (N_("Columns"), columns_menu),
	GNOMEUIINFO_SUBTREE (N_("Sort order"), order_menu),
	GNOMEUIINFO_SUBTREE (N_("Categories"), group_menu),
	GNOMEUIINFO_SUBTREE (N_("Color markers"), marker_menu),

  GNOMEUIINFO_END
};


static GnomeUIInfo file_menu[] = {
	GNOMEUIINFO_MENU_PREFERENCES_ITEM (G_CALLBACK (apt_prefs_cb), NULL),
	GNOMEUIINFO_ITEM_STOCK (N_("_Repository lists"), N_("Tell GNOME Apt where to look for packages"),
	      G_CALLBACK (sources_cb), GTK_STOCK_INDEX),
	GNOMEUIINFO_SEPARATOR,
	GNOMEUIINFO_MENU_QUIT_ITEM (G_CALLBACK (exit_cb), NULL),
	GNOMEUIINFO_END
};

static GnomeUIInfo actions_menu[] = {
	{ GNOME_APP_UI_ITEM, N_("_Update package list"),
		N_("Download the latest package info from the configured sources"),
		(gpointer) update_cb, NULL, NULL,
		GNOME_APP_PIXMAP_STOCK, GTK_STOCK_REFRESH, 'U',
		(GdkModifierType) GDK_CONTROL_MASK, NULL },

	{ GNOME_APP_UI_ITEM, N_("_Complete run"),
		N_("Install and remove packages as requested"),
		(gpointer) complete_run_cb, NULL, NULL,
		GNOME_APP_PIXMAP_STOCK, GTK_STOCK_EXECUTE, 'R',
		(GdkModifierType) GDK_CONTROL_MASK, NULL },
	{ GNOME_APP_UI_ITEM, N_("Mark up_grades"),
	      N_("Mark all out-of-date packages for upgrade, without removals or installs."),
   (gpointer)upgrade_cb, NULL, NULL,
   GNOME_APP_PIXMAP_NONE, NULL, '\0', 
	      (GdkModifierType) 0, NULL },
	{ GNOME_APP_UI_ITEM, N_("_Smart mark upgrades"),
	      N_("Mark upgrades, removing or installing packages if needed."),
	      (gpointer) smart_upgrade_cb, NULL, NULL,
	      GNOME_APP_PIXMAP_NONE, NULL, '\0',
   (GdkModifierType)0, NULL },
	{ GNOME_APP_UI_ITEM, N_("_Fix broken"),
	      N_("Fix broken packages, removing or installing packages if needed."),
   (gpointer)fix_broken_cb, NULL, NULL,
   GNOME_APP_PIXMAP_NONE, NULL, 'F', 
   (GdkModifierType)GDK_CONTROL_MASK, NULL },
  GNOMEUIINFO_END
};

static GnomeUIInfo package_menu[] = {
#define PACKAGE_REMOVE 0
	{ GNOME_APP_UI_ITEM, N_("_Delete"),
		N_("Uninstall package, keeping configuration."),
		(gpointer) remove_pkg_cb, NULL, NULL,
		GNOME_APP_PIXMAP_STOCK, GTK_STOCK_DELETE, '\0',
		(GdkModifierType) 0, NULL },
#define PACKAGE_KEEP 1
	{ GNOME_APP_UI_ITEM, N_("_Keep"),
		N_("Don't change this package."),
		(gpointer) keep_pkg_cb, NULL, NULL,
		GNOME_APP_PIXMAP_NONE, NULL, '\0',
		(GdkModifierType) 0, NULL },
#define PACKAGE_INSTALL 2
	{ GNOME_APP_UI_ITEM, N_("_Install/Upgrade"),
		N_("Install this package."),
		(gpointer) install_pkg_cb, NULL, NULL,
		GNOME_APP_PIXMAP_NONE, NULL, '\0',
		(GdkModifierType) 0, NULL },
	GNOMEUIINFO_END
};

static GnomeUIInfo advanced_menu[] = {
	{ GNOME_APP_UI_ITEM, N_("_Export packagelist..."),
		N_("Save the current state of the package list to disk for use on another system."),
		(gpointer)export_cb, NULL, NULL,
		GNOME_APP_PIXMAP_STOCK, GTK_STOCK_SAVE, '\0',
		(GdkModifierType) 0, NULL },
	{ GNOME_APP_UI_ITEM, N_("_Import packagelist..."),
		N_("Load a package list."),
		(gpointer) import_cb, NULL, NULL,
		GNOME_APP_PIXMAP_STOCK, GTK_STOCK_OPEN, '\0',
		(GdkModifierType) 0, NULL },
	{ GNOME_APP_UI_ITEM, N_("_Bug report..."),
   N_("File a bug against this package."),
   (gpointer)bug_cb, NULL, NULL,
   GNOME_APP_PIXMAP_NONE, NULL, '\0', 
   (GdkModifierType)0, NULL },
  GNOMEUIINFO_END
};

static GnomeUIInfo help_menu[] = {
  GNOMEUIINFO_HELP(const_cast<char*>(APPNAME)),
	{ GNOME_APP_UI_ITEM, N_("_About GNOME Apt"),
		N_("Tell about this application"),
		(gpointer) about_cb, NULL, NULL,
		GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_ABOUT, '\0',
		(GdkModifierType) 0, NULL },
	{ GNOME_APP_UI_ITEM, N_("_Icon help"),
	      N_("Explain what all the icons in the package list mean"),
	      (gpointer) icons_cb, NULL, NULL,
   GNOME_APP_PIXMAP_NONE, NULL, '\0',  
   (GdkModifierType)0, NULL },
  GNOMEUIINFO_END
};

static GnomeUIInfo main_menu[] = {
	GNOMEUIINFO_MENU_FILE_TREE (file_menu),
  GNOMEUIINFO_SUBTREE (N_("_Actions"), actions_menu),
  GNOMEUIINFO_SUBTREE (N_("_Package"), package_menu),
	GNOMEUIINFO_MENU_VIEW_TREE (view_menu),
  /* doesn't work yet */
  //  GNOMEUIINFO_SUBTREE (N_("A_dvanced"), advanced_menu),
	GNOMEUIINFO_MENU_HELP_TREE (help_menu),
	GNOMEUIINFO_END
};


///////////////////////////////// 
// Menu-handling code

struct MenuWidgets {
	GtkWidget* main_install;
	GtkWidget* main_remove;
	GtkWidget* main_keep;

	map<DrawTree::ColumnType,GtkWidget*> main_column;
	map<GAptPkgTree::CategoryType,GtkWidget*> main_group;
	map<GAptPkgTree::SortType,GtkWidget*> main_order;
};

static MenuWidgets widgets;

void 
gnome_apt_create_main_menu   (GnomeApp* app, GnomeAppBar* bar, GAptPkgList* pkglist)
{
	g_return_if_fail (widgets.main_column.empty());
	DrawTree* view = pkglist->getView();
	GAptPkgTree* tree = view->getModel();

  g_return_if_fail(tree != 0);

  gnome_app_create_menus_with_data(GNOME_APP(app), 
                                   main_menu,
                                   pkglist);

  // column visibility
	widgets.main_column[DrawTree::ColumnName] = columns_menu[COLUMNS_NAME].widget;
	widgets.main_column[DrawTree::ColumnCurrent] = columns_menu[COLUMNS_CURRENT].widget;
	widgets.main_column[DrawTree::ColumnAvailable] = columns_menu[COLUMNS_AVAILABLE].widget;
	widgets.main_column[DrawTree::ColumnSection] = columns_menu[COLUMNS_SECTION].widget;
	widgets.main_column[DrawTree::ColumnPriority] = columns_menu[COLUMNS_PRIORITY].widget;
	widgets.main_column[DrawTree::ColumnStatus] = columns_menu[COLUMNS_STATUS].widget;
	widgets.main_column[DrawTree::ColumnDescription] = columns_menu[COLUMNS_DESCRIPTION].widget;

	map<DrawTree::ColumnType,GtkWidget*>::iterator i = widgets.main_column.begin();
  while (i != widgets.main_column.end()) {
    
#ifdef GNOME_ENABLE_DEBUG
    if (i->second == 0) g_warning("widget == 0 in main creation");
#endif

		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (i->second), view->is_visible (i->first));
		++i;
  }

	/* Grouping */

	widgets.main_group[GAptPkgTree::CategoryNone] = group_items[GROUP_NONE].widget;
	widgets.main_group[GAptPkgTree::CategoryAlpha] = group_items[GROUP_ALPHA].widget;
	widgets.main_group[GAptPkgTree::CategoryStatus] = group_items[GROUP_STATUS].widget;
	widgets.main_group[GAptPkgTree::CategorySection] = group_items[GROUP_SECTION].widget;
	widgets.main_group[GAptPkgTree::CategoryPriority] = group_items[GROUP_PRIORITY].widget;

	map<GAptPkgTree::CategoryType, GtkWidget*>::iterator j = widgets.main_group.find (tree->get_category());

#ifdef GNOME_ENABLE_DEBUG
    if (j->second == 0) g_warning("widget == 0 in main creation");
#endif

	if (j == widgets.main_group.end()) {
		g_warning ("Category not found in main menu");
	} else {
		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (j->second), TRUE);
	}

	/* Sorting */

	widgets.main_order[GAptPkgTree::SortNone] = order_items[ORDERS_NONE].widget;
	widgets.main_order[GAptPkgTree::SortAlpha] = order_items[ORDERS_ALPHA].widget;
	widgets.main_order[GAptPkgTree::SortStatus] = order_items[ORDERS_STATUS].widget;
	widgets.main_order[GAptPkgTree::SortSection] = order_items[ORDERS_SECTION].widget;
	widgets.main_order[GAptPkgTree::SortPriority] = order_items[ORDERS_PRIORITY].widget;

	map<GAptPkgTree::SortType, GtkWidget*>::iterator k = widgets.main_order.find (tree->get_sort());

#ifdef GNOME_ENABLE_DEBUG
    if (k->second == 0) g_warning("widget == 0 in main creation");
#endif

	if (k == widgets.main_order.end()) {
		g_warning ("Sort order not found in main menu");
	} else {
		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (k->second), TRUE);
	}

	for (int j = 0; j < COLMARK_END; j++) {
		gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (marker_menu[j].widget), view->MarkRows[j]);
	}

  // package operations
  widgets.main_install = package_menu[PACKAGE_INSTALL].widget;
  widgets.main_keep    = package_menu[PACKAGE_KEEP].widget;
  widgets.main_remove  = package_menu[PACKAGE_REMOVE].widget;

  gnome_app_install_appbar_menu_hints(bar, main_menu);
}

void
gnome_apt_menus_selection_changed (DrawTree* view) {
	GAptPkgTree* tree = view->getModel();

	pkgCache::Package* p = 0;
	if (view->selected_node()) {
		p = view->selected_node()->package();
	}

  bool install = false;
  bool keep    = false;
  bool remove  = false;

  if (p != 0) {
		pkgCache::PkgIterator i(*(tree->cache()), p);
		install = Util::can_change_install (i, tree);
		keep = Util::can_change_keep (i, tree);
		remove = Util::can_change_remove (i, tree);
  }

  gtk_widget_set_sensitive(widgets.main_install,  install);
  gtk_widget_set_sensitive(widgets.main_keep,  keep);
  gtk_widget_set_sensitive(widgets.main_remove,  remove);
}

////////////////////////////////////
// Menu callbacks

static void
set_color_marker_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = (GAptPkgList*) (data);
	g_return_if_fail (pkglist);

	for (int j = 0; j < COLMARK_END; j++) {
		if (w == marker_menu[j].widget) {
			DrawTree* view = pkglist->getView();
			view->MarkRows[j] =
			      gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (marker_menu[j].widget));
			ga_debug ("setting color for %d to %d", j, view->MarkRows[j]);
			view->queue_display_update();
		}
	}
}

static void
showhide_column (GtkWidget* w, GAptPkgList* pkglist, DrawTree::ColumnType ct) {
  bool state = GTK_CHECK_MENU_ITEM(w)->active;

	pkglist->getView()->set_visible (ct, state);
}

static void
name_column_cb         (GtkWidget* w, gpointer data)
{
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);
	showhide_column (w, pkglist, DrawTree::ColumnName);
}

static void
status_column_cb       (GtkWidget* w, gpointer data)
{
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);
	showhide_column (w, pkglist, DrawTree::ColumnStatus);
}

static void
installed_column_cb    (GtkWidget* w, gpointer data)
{
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);
	showhide_column (w, pkglist, DrawTree::ColumnCurrent);
}

static void
available_column_cb    (GtkWidget* w, gpointer data)
{
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);
	showhide_column (w, pkglist, DrawTree::ColumnAvailable);
}

static void
section_column_cb      (GtkWidget* w, gpointer data)
{
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);
	showhide_column (w, pkglist, DrawTree::ColumnSection);
}

static void
priority_column_cb     (GtkWidget* w, gpointer data)
{
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);
	showhide_column (w, pkglist, DrawTree::ColumnPriority);
}


static void
description_column_cb     (GtkWidget* w, gpointer data)
{
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);
	showhide_column (w, pkglist, DrawTree::ColumnDescription);
}


// Ordering

static void
order_tree (GtkWidget* w, GAptPkgList* pkglist, GAptPkgTree::SortType st) {
	pkglist->getView()->getModel()->set_sort (st);
}

static void
set_order_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = (GAptPkgList*) data;
	g_return_if_fail (pkglist);

	/* account for GNOMEUIINFO_END */
	gint maxi = (sizeof (order_items) / sizeof (GnomeUIInfo)) - 1;

	int i = 0;
	while (i < maxi && w != order_items[i].widget) {
		++i;
	}

	if (i >= maxi) {
		g_warning ("Failed to find sort order method!");
		return;
	}

	order_tree (w, pkglist, (GAptPkgTree::SortType) i);
}

// Grouping

static void
group_tree (GtkWidget* w, GAptPkgList* pkglist, GAptPkgTree::CategoryType ct) {
	pkglist->getView()->getModel()->set_category (ct);
}

static void
set_grouping_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = (GAptPkgList*) data;
	g_return_if_fail (pkglist);

	/* account for GNOMEUIINFO_END */
	gint maxi = (sizeof (group_items) / sizeof (GnomeUIInfo)) - 1;

	int i = 0;
	while (i < maxi && w != group_items[i].widget) {
		++i;
	}

	if (i >= maxi) {
		g_warning ("Failed to find sort order method!");
		return;
	}

	group_tree (w, pkglist, (GAptPkgTree::CategoryType) i);
}

// Other stuff

static void
details_cb (GtkWidget* w, gpointer data) {
  GAptPkgList* pkglist = static_cast<GAptPkgList*>(data);

  g_return_if_fail(pkglist != 0);

	pkglist->details (true);
}

static void
pending_cb (GtkWidget* wdg, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

	GtkWidget* dialog = gtk_dialog_new_with_buttons (_("Pending Changes"), NULL,
	      GtkDialogFlags (GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR),
	      GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
	gnome_apt_setup_dialog (dialog);
	gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 360);

	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
	      gapt_cache_control_pending (GAPT_CACHE_CONTROL (gapt_cache_control_new (gnome_apt_cache_file()))),
	      TRUE, TRUE, GNOME_PAD_BIG / 2);

	gtk_widget_show_all (dialog);
	gtk_dialog_run (GTK_DIALOG (dialog));
	gtk_widget_destroy (dialog);
}

///////////////////////////////// was in app.cc

static void
update_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  GAptCacheFile* cf = gnome_apt_cache_file();
	if (cf) {
		GObject* cc = gapt_cache_control_new (cf);
		if (!gapt_cache_control_update (GAPT_CACHE_CONTROL (cc))) {
			if (!_error->empty()) {
				gnome_apt_error_dialog (_("Update failed"));
			}
		} else if (!_error->empty()) {
			/* Should be harmless (e.g. Release file misses) */
			_error->DumpErrors();
		}
  }
  else {
    g_warning(__FUNCTION__);
    g_warning("No cache file");
  }
}

static void
apt_prefs_cb (GtkWidget* w, gpointer data) {
	gnome_apt_preferences()->edit();
}

static void
sources_cb (GtkWidget* w, gpointer data) {
	gnome_apt_sources()->edit();
}

static void
exit_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  gnome_apt_quit();
}

static void
complete_run_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  GAptCacheFile* cf = gnome_apt_cache_file();
	if (cf) {
		GObject* cc = gapt_cache_control_new (cf);
		if (!gapt_cache_control_complete (GAPT_CACHE_CONTROL (cc))) {
			if (!_error->empty()) {
				gnome_apt_error_dialog (_("Run failed"));
			}
      }
  }
  else {
    g_warning(__FUNCTION__);
    g_warning("No cache file");
  }
}

static void
upgrade_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);
	g_return_if_fail (pkglist);

  GAptCacheFile* cf = gnome_apt_cache_file();
  if (cf) {
		cf->MarkUpgrades();
		pkglist->getView()->queue_recalc_rows (true);
		pkglist->getView()->getModel()->update_status();
	} else {
    g_warning(__FUNCTION__);
    g_warning("No cache file");
  }
}

static void
smart_upgrade_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);
	g_return_if_fail (pkglist);

	GAptCacheControl* cc = GAPT_CACHE_CONTROL (pkglist->getCacheControl());
	gapt_cache_control_smart_mark_upgrades (GAPT_CACHE_CONTROL (cc));
	pkglist->getView()->queue_recalc_rows (true);
	pkglist->getView()->getModel()->update_status();
}

static void
fix_broken_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);
	g_return_if_fail (pkglist);

  GAptCacheFile* cf = gnome_apt_cache_file();
  if (cf) {
		cf->Fix();
		if (_error->PendingError()) {
			string errmsg;
			_error->PopMessage (errmsg);
			gnome_apt_error_dialog (errmsg.c_str());
		}

		pkglist->getView()->queue_recalc_rows (true);
		pkglist->getView()->getModel()->update_status();
	} else {
    g_warning(__FUNCTION__);
    g_warning("No cache file");
  }
}

static void
install_pkg_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  pkglist->install();
}

static void
remove_pkg_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  pkglist->remove();
}

static void
keep_pkg_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);
  
  pkglist->keep();
}

static void
export_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  g_warning(__FUNCTION__ );
}

static void
import_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  g_warning(__FUNCTION__ );
}

static void
bug_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  g_warning(__FUNCTION__ );
}

static void
about_cb (GtkWidget* w, gpointer data) {
	GAptPkgList* pkglist = static_cast<GAptPkgList*> (data);

  g_return_if_fail(pkglist != 0);

  static GtkWidget* about = NULL;

  if (about != NULL)
    {
      gdk_window_show(about->window);
      gdk_window_raise(about->window);
      return;
    }
 
	const gchar* authors[] = { 
		"Jason Gunthorpe <jgg@debian.org> - Project leader",
		"Manoj Srivastava <srivasta@datasync.com> - Dependency Expert",
		"Ben Gertzfield <che@debian.org> - Packaging and Releases",
		"Adam Heath <doogie@debian.org> - FTP method author",
		"Filip Van Raemdonck <mechanix@debian.org> - GNOME frontend",
		"",
		"Past Contributors:",
		"Brian White <bcwhite@verisim.com> - Project originator",
		"Tom Lees <tom@lpsg.demon.co.uk> - DPKG documentation and ideas",
		"Behan Webster <behanw@verisim.com> - Original GUI design",
		"Scott Ellis <storm@gate.net> - Original packaging and beta releases",
		"Branden Robinson <branden@purdue.edu> - Man Page Documentation",
		"Havoc Pennington <hp@pobox.com> - GNOME frontend",
		"Diego Lages <dlages@dcc.ufrj.br> - GNOME frontend",
		"Olivier Gravel Aubin <ogaubin@ucalgary.ca> - GNOME frontend",
		"Mitch Blevins <mblevin@debian.org> - GNOME package maintainer",
		NULL 
	};

	GdkPixbuf* logo = gdk_pixbuf_new_from_file (GNOME_APT_LOGO, NULL);
	gchar* text = g_strconcat (
	      _("Gnome Apt is a tool for managing the software packages installed"
	      " on your Debian GNU/Linux system.\n"),
	      /* This legal text should not be translated */
	      " Gnome Apt 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 full text of the GPL for details.",
	      NULL);

	about = gnome_about_new (
	      "Apt: A Package Tool (GNOME Frontend)", VERSION,
	      "(c) 1998-2003 Individual contributors, GNU General Public License.",
	      text, authors, NULL, NULL, logo);
	g_object_unref (G_OBJECT (logo));
	g_free (text);

	gnome_apt_setup_dialog (about);

	g_signal_connect (G_OBJECT (about), "destroy", G_CALLBACK (gtk_widget_destroyed), &about);
	gtk_widget_show_all (about);
}

static void
make_icon_help (GAptPixbufType pbt, GtkWidget* vbox, const gchar* text) {
	GdkPixbuf* pixbuf;
  GtkWidget* hbox;
  GtkWidget* pix;
  GtkWidget* label;

	hbox = gtk_hbox_new (FALSE, 0);

	pixbuf = gapt_pixbuf_new (pbt);
	pix = gtk_image_new_from_pixbuf (pixbuf);
	g_object_unref (G_OBJECT (pixbuf));
	gtk_misc_set_alignment (GTK_MISC (pix), 0.5, 0.5);
	gtk_box_pack_start (GTK_BOX (hbox), pix, FALSE, FALSE, 0);

  label = gtk_label_new(text);
  gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);

	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, GNOME_PAD_SMALL);
}

static void 
icons_cb       (GtkWidget* w, gpointer data)
{
  static GtkWidget* icons = NULL;

  if (icons != NULL)
    {
      gdk_window_show(icons->window);
      gdk_window_raise(icons->window);
      return;
    }

	icons = gtk_dialog_new_with_buttons (_("GNOME Apt Icon Legend"), NULL,
	      GtkDialogFlags (GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR),
	      GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
  gnome_apt_setup_dialog(icons);
	g_signal_connect (G_OBJECT (icons), "destroy",
		G_CALLBACK (gtk_widget_destroyed), &icons);
	g_signal_connect_swapped (G_OBJECT (icons), "response",
		G_CALLBACK (gtk_widget_destroy), G_OBJECT (icons));

	GtkWidget* vbox = gtk_vbox_new (TRUE, 0);
	gtk_container_set_border_width (GTK_CONTAINER (vbox), GNOME_PAD_BIG / 2);
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (icons)->vbox), vbox, TRUE, TRUE, 0);

	make_icon_help (GAPT_PIXBUF_SECTION, vbox, _("Package section"));
	make_icon_help (GAPT_PIXBUF_PACKAGE, vbox, _("A package"));
	make_icon_help (GAPT_PIXBUF_DEPENDS, vbox, _("Dependency"));
	make_icon_help (GAPT_PIXBUF_RECOMMENDS, vbox, _("Recommends relationship"));
	make_icon_help (GAPT_PIXBUF_SUGGESTS, vbox, _("Suggests relationship"));
	make_icon_help (GAPT_PIXBUF_REPLACES, vbox, _("Replaces relationship"));
	make_icon_help (GAPT_PIXBUF_CONFLICTS, vbox, _("Conflicts relationship"));
 
	gtk_widget_show_all (icons);
}
