//
// C++ Interface: packagedisplaywidget
//
// Description: 
//
//
// Author: Benjamin Mesing <bensmail@gmx.net>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//
//
#ifndef __NPACKAGESEARCH_PACKAGEDISPLAYWIDGET_H_2007_10_30
#define __NPACKAGESEARCH_PACKAGEDISPLAYWIDGET_H_2007_10_30

#include <QTableWidget>
#include <QList>
class QAction;

#include <set>
#include <vector>
#include <list>
#include <map>



// NXml
#include <ixmlstorable.h>

// NPlugin
#include "ipluginuser.h"
namespace NPlugin
{
	class ShortInformationPlugin;
	class ActionPlugin;
}


using namespace std;




namespace NPackageSearch {

/**
 * @brief This class is a widget which displays package information in a Table.
 *
 * The package information displayed is taken from all ShortInformationPlugins and
 * the action which can be performed are taken from the ActionPlugins. To get to know
 * about the plugins, this class implements the IPluginUser interface and needs to be
 * registered to all plugin providers.
 *
	@author Benjamin Mesing <bensmail@gmx.net>
*/
class PackageDisplayWidget : public QTableWidget, public NPlugin::IPluginUser, public NXml::IXmlStorable
{
	typedef NPlugin::ShortInformationPlugin ShortInformationPlugin;
	typedef NPlugin::ActionPlugin ActionPlugin;
	Q_OBJECT
	vector<ActionPlugin*> _actionPlugins;
	vector<ShortInformationPlugin*> _siPlugins;
	QAction* _pCustomizeColumnsAction;
	/** The state for one column. */
	struct Column
	{
		Column()	{}
		Column(QString caption, int width, int position, bool hidden ) :
			_caption(caption),
			_width(width),
			_position(position),
			_hidden(hidden)
		{
		}
		QString _caption;
		int _width;
		int _position;
		bool _hidden;
	};
	/** This contains the column settings that were loaded during loadSettings().
	  *
	  * It maps the column title to the stored settings.
	  * The appropriate data will be applied a column when it is added.
	  */
	map<QString, Column> _loadedColumnSettings;
	const static int CHAR_WIDTH;
	const static int MARGIN;

public:
	PackageDisplayWidget(QWidget * pParent = 0);
	~PackageDisplayWidget();


	/** @name IPluginUser interface
	  *
	  * These functions implement the IPluginUser interface.
	  */
	//@{	
	// documented in base class
	virtual void addPlugin(NPlugin::Plugin* pPlugin);
	/** @brief Finds every reference to plugin and remove it so that pPlugin can be safely deleted.
	  *
	  * @param pPlugin the plugin to be removed 
	  */
	void removePlugin(NPlugin::Plugin* pPlugin);
	//@}
public slots:
	/** @brief Sets the packages to be displayed. */
	void setPackages(const set<string>& packages);
	/** Shows a dialog to control the settings of the columns (which columns are shown). */
	void showColumnControlDialog();
protected:
	/** @brief Updates the columns displayed.
	  *
	  * This includes updating of the number of columns, the column caption and the ordering.
	  */
	void updateColumnDisplay();
protected slots:
	virtual void onItemSelectionChanged();
	void onHeaderContextMenuRequested(const QPoint& pos);
signals:
	/** Emitted whenever a package was selected.
	  *
	  * Emitted with an empty string, if no package was selected.
	  */
	void packageSelected(QString package);


//////////////////////////////////////////////////
// Column display control
//////////////////////////////////////////////////
public:
	virtual void saveSettings(NXml::XmlData& outData, QDomElement parent) const;
	virtual QDomElement loadSettings(QDomElement source);
	/** @brief To be called once all columns are added, so that the loaded settings can be applied. 
	  *
	  * Applies all non-column specfic settings.
	  */ 
	virtual void initialize();
	
//////////////////////////////////////////////////
// Query Methods
//////////////////////////////////////////////////

	/** @name Query Methods
	  *
	  * These methods query some information without changing the class.
	  */
	//@{	begin Query Methods
	/** @brief Returns the package that is currently selected. 
	  *
	  * @return the name of the package or a null string, if no package was selected.
	  */
	QString selectedPackage() const;
	/** @brief Returns if the score column is visible. 
	  *
	  * This is useful to determine if score calculation should be performed.
	  */
	bool scoreColumnVisible() const;
	/** @brief Returns the package referred to by the given row. 
	  */
	QString packageForRow(int row) const;
	
	/** Debug Method: Prints the name of the columns in order of their visible index using qDebug(). */
	void debugPrintOrder() const;
protected:
	/** Returns the logical index of the column where the header has the given name.
	  *
	  * @returns the index of the column or -1 if no such column was found.
	  */
	virtual int columnForName(const QString& name) const;
	
	/** Returns the plugin with the given caption.
	  *
	  * @returns the plugin or 0 if no such plugin exists.
	  */
	virtual ShortInformationPlugin* pluginForCaption(const QString& name) const;

	/** @brief Returns the position that the requested short information column shall have.
	  *
	  * The position will be determined as follows:
	  * <ul>
	  *	<li>if (position == -1) the position of the first column where the corresponding plugin has 
	  *		a priority larger than the request plugin </li>
	  *	<li>if (position != -1) the position of the first column where either the column has a larger 
	  *		position value in the stored setting or with a priority larger than the request plugin (the 
	  *		latter will only be considered if the added column has no saved settings</li>
	  * 	<li>the column itself will not be considered</li>
	  *	<li>-1 will be returned if the position should be at the end of the table</li>
	  * </ul>
	  *
	  * @param position the position of the requested column stored in the settings, -1 if the column has no
	  * settings
	  * @param logicalIndex the current logical index of the column for the plugin
	  * @param pPlugin the plugin for which the column shall be deterined
	  * @returns the visual index of that column or -1 if it shall be at the end.
	  */
	virtual int columnPosition(int position, int logicalIndex, const NPlugin::ShortInformationPlugin* pPlugin) const;
	/** @brief Returns the list of all actions provided by all action plugins. */
	virtual QList<QAction*> packageActions() const;
  	//@}	end Query Methods

	/** @brief Diplays a context menu showing the possible actions. 
	  *
	  * Reimplements QWidget::contextMenuEvent()
	  */
	virtual void contextMenuEvent(QContextMenuEvent * pEvent);

};

}

#endif	// __NPACKAGESEARCH_PACKAGEDISPLAYWIDGET_H_2007_10_30
