#ifndef KADU_USERBOX_H
#define KADU_USERBOX_H

#include <qlistbox.h>
#include <qpainter.h>
#include <qpopupmenu.h>
#include <qstringlist.h>
#include <qtooltip.h>

#include "misc.h"
#include "userlist.h"

class QFontMetrics;
class UserBoxSlots;
/**
	Klasa reprezentująca kontakt wizualnie na liście kontaktów. Opisuje ona ikonę kontaktu,
	jego wyświtlaną nazwę oraz ewentualny opis.
	\class KaduListBoxPixmap
	\brief Klasa reprezentująca kontakt wizualnie.
**/
class KaduListBoxPixmap : public QListBoxItem
{
	public:
		/**
			\fn KaduListBoxPixmap(const QPixmap &pix, const QString &text)
			Konstruktor dodający kontakt do listy z podaną ikoną oraz nazwą.
			\param pix ikona statusu.
			\param test wyświetlana nazwa kontaktu.
		**/
		KaduListBoxPixmap(const QPixmap &pix, const QString &text);

		/**
			\fn KaduListBoxPixmap(const QPixmap &pix, const QString &text, const QString &descr, bool bold)
			Konstruktor dodający kontakt do listy z podaną ikoną, nazwą, oraz opisem.
			\param pix ikona statusu.
			\param test wyświetlana nazwa kontaktu.
			\param descr wyświetlany opis pod nazwą kontaktu.
			\param bold wartość logiczna informująca o tym, czy nazwa kontaktu
				ma być wyświetlana pogrubioną czcionką.
		**/
		KaduListBoxPixmap(const QPixmap &pix, const QString &text, const QString &descr, bool bold);

		/**
			\fn const QString &description() const
			Zwraca wyświetlany opis kontaktu.
		**/
		const QString &description() const { return descr; }

		/**
			\fn bool isBold() const
			Zwraca informację, czy nazwa kontaktu jest wyświetlana pogrubioną czcionką, czy nie.
		**/
		bool isBold() const { return bold; }

		/**
			\fn int height(const QListBox *lb) const
			Zwraca wysokość elementu reprezentującego wyświetlany kontakt w pikselach.
			\param lb obiekt reprezentujący wyświetlany kontakt.
		**/
		int height(const QListBox *lb) const;

		/**
			\fn int width(const QListBox *lb) const
			Zwraca szerokość elementu reprezentującego wyświetlany kontakt w pikselach.
			\param lb obiekt reprezentujący wyświetlany kontakt.
		**/
		int width(const QListBox *lb) const;

	protected:
		/**
			\fn int lineHeight(const QListBox *lb) const
			Zwraca wysokość samej czcionki dla elementu reprezentującego wyświetlany kontakt w pikselach.
			\param lb obiekt reprezentujący wyświetlany kontakt.
		**/
		int lineHeight(const QListBox *lb) const;

		/**
			\fn void paint(QPainter *painter)
			Rysuje wyświetlany kontakt na liście.
			\param painter wskaźnik do obiektu rysującego.
		**/
		void paint(QPainter *painter);

		/**
			\fn void setDescription(const QString &d)
			Ustawia wywietlany opis na podany.
			\param d opis do wyświetlenia.
		**/
		void setDescription(const QString &d) { descr = d; }

		/**
			\fn void setBold(bool b)
			Ustawia stan pogrubienia czcionki wyświetlanego kontaktu.
			\param b wartość logiczna określająca, czy czcionka ma być pogrubiona czy nie.
		**/
		void setBold(bool b) { bold = b; }

		/**
			\fn void calculateSize(const QString &text, int width, QStringList &out, int &height) const
			Oblicza odpowiednią wysokość elementu listy kontaktów tak, aby pomieścić
			opis podzielony na niezbędną liczbę linii.
			\param[in] text wyświetlany opis.
			\param[in] width szerokość kolumny listy kontaktów.
			\param[out] out lista łańcuchów znaków, zawierająca kolejne linie opisu powstałe
				w wyniku podzielenia opisu tak, aby zmieścił się w danej szerokości kolumny.
			\param[out] height wysokość elementu listy kontaktów potrzebna aby pomieścić opis
				podzielony w liniach.
		**/
		void calculateSize(const QString &text, int width, QStringList &out, int &height) const;

		/**
			\fn void changeText(const QString &text)
			Zmienia nazwę wyświetlaną dla kontaktu na liście na podaną.
			\param text nowa nazwa do wyświetlenia.
		**/
		void changeText(const QString &text);
		friend class UserBox;
		friend class UserBoxSlots;

		/*funkcje wprowadzone żeby zaoszczędzić na odwołaniach do pliku konfiguracyjnego*/
		/**
			\fn static void setFont(const QFont &f)
			Ustawia czcionkę dla tego elementu.
			\param f czcionka
		**/
		static void setFont(const QFont &f);

		/**
			\fn static void setMyUIN(UinType u)
			Ustawia UIN lokalnego użytkownika Kadu dla tego elementu, aby było wiadomo,
			że ten element jego reprezentuje (ponieważ do pobierania informacji o statusie i opisie
			używane są różne metody dla kontaktu i lokalnego użytkownika).
			\param u numer UIN.
		**/
		static void setMyUIN(UinType u);

		/**
			\fn static void setShowDesc(bool sd)
			Ustawia stan wyświetlania opisów na liście kontaktów.
			\param sd wartość logiczna informująca o tym, czy opisy mają być wyświetlane na liście kontatów.
		**/
		static void setShowDesc(bool sd);

		/**
			\fn static void setAlignTop(bool at)
			Ustawia stan wyrównywania do górnego brzegu elementu.
			\param at wartość logiczna informująca o tym, czy wyświetlana nazwa kontaktu ma być wyrównywana
				do górnej krawędzi elementu.
		**/
		static void setAlignTop(bool at);

		/**
			\fn static void setShowMultilineDesc(bool m)
			Ustawia stan wyświetlania opisów wieloliniowych.
			\param m wartość logiczna informująca o tym, czy opis tego elementu może być wyświetlany
				w wielu liniach, jeśli zawiera znaki nowej linii.
		**/
		static void setShowMultilineDesc(bool m);

		/**
			\fn static void setMultiColumn(bool m)
			Ustawia stan wyświetlania listy kontaktów w wielu kolumnach.
			\param m wartość logiczna informująca o tym, czy lista ma być wyświetlana w wielu kolumnach.
		**/
		static void setMultiColumn(bool m);

		/**
			\fn static void setMultiColumnWidth(int w)
			Ustawia szerokość jednej kolumny dla wyświetlania listy w trybie wielu kolumn.
			\param w szerokość kolumny w pikselach.
		**/
		static void setMultiColumnWidth(int w);

		/**
			\fn static void setDescriptionColor(const QColor &col)
			Ustawia kolor wyświetlanego opisu.
			\param col kolor
		**/
		static void setDescriptionColor(const QColor &col);

	private:
		QPixmap pm;
		QString descr;
		bool bold;
		static QFontMetrics *descriptionFontMetrics;

		static UinType myUIN;
		static bool ShowDesc;
		static bool AlignUserboxIconsTop;
		static bool ShowMultilineDesc;
		static bool MultiColumn;
		static int  MultiColumnWidth;
		static QColor descColor;
		
		mutable QString buf_text;
		mutable int buf_width;
		mutable QStringList buf_out;
		mutable int buf_height;
};

/**
	Klasa reprezentująca menu podręczne listy kontaktów - czyli to, które dostajemy klikając
	na którymkolwiek kontakcie prawym przyciskiem myszy.
	\class UserBoxMenu
	\brief Menu podręczne listy kontaktów.
**/
class UserBoxMenu : public QPopupMenu
{
	Q_OBJECT

	private:
		QValueList<QPair<QString, QString> > iconNames;
	private slots:
		void restoreLook();

	public:
		/**
			\fn UserBoxMenu(QWidget *parent=0, const char* name=0)
			Standardowy konstruktor.
			\param parent wskaźnik na obiekt kontrolki-rodzica.
			\param name nazwa kontrolki.
		**/
		UserBoxMenu(QWidget *parent=0, const char* name=0);

		/**
			\fn int getItem(const QString &caption) const
			Zwraca unikalną liczbę identyfikującą element menu z podanym napisem.
			\param caption napis elementu.
		**/
		int getItem(const QString &caption) const;
	
	public slots:
		/**
			\fn void show(QListBoxItem *item)
			Pokazuje menu dla podanego kontaktu.
			\param item element wyświetlanej listy kontaktów reprezentujący rządany kontakt.
		**/
		void show(QListBoxItem *item);

		/**
			\fn int addItem(const QString &text, const QObject* receiver, const char* member, const QKeySequence accel= 0, int id= -1)
			Dodaje nowy element do menu.
			\param text napis dla nowego elementu.
			\param receiver obiekt odbierający sygnał wybrania elementu z menu.
			\param member SLOT obiektu \a receiver który zostanie wykonany po wybraniu elementu z menu.
			\param accel skrót klawiaturowy dla tego elementu. Domyślnie brak.
			\param id Unikatowa liczba identyfikująca nowy element. Domyślnie pierwsza wolna.
		**/
		int addItem(const QString &text, const QObject* receiver, const char* member, const QKeySequence accel= 0, int id= -1);

		/**
			\fn int addItem(const QString &iconname, const QString &text, const QObject* receiver, const char* member, const QKeySequence accel= 0, int id= -1)
			Dodaje nowy element do menu.
			\param iconname nazwa ikony z zestawu lub sciezka do pliku
			\param text napis dla nowego elementu.
			\param receiver obiekt odbierający sygnał wybrania elementu z menu.
			\param member SLOT obiektu \a receiver który zostanie wykonany po wybraniu elementu z menu.
			\param accel skrót klawiaturowy dla tego elementu. Domyślnie brak.
			\param id Unikatowa liczba identyfikująca nowy element. Domyślnie pierwsza wolna.
		**/
		int addItem(const QString &iconname, const QString &text, const QObject* receiver, const char* member, const QKeySequence accel= 0, int id= -1);

		/**
			\fn int addItemAtPos(int index,const QString &iconname, const QString &text, const QObject* receiver, const char* member, const QKeySequence accel= 0, int id= -1)
			Dodaje nowy element do menu.
			\param index pozycja (licząc od 0) na której znaleźć ma się nowy element.
			\param iconname nazwa ikony z zestawu lub sciezka do pliku
			\param text napis dla nowego elementu.
			\param receiver obiekt odbierający sygnał wybrania elementu z menu.
			\param member SLOT obiektu \a receiver który zostanie wykonany po wybraniu elementu z menu.
			\param accel skrót klawiaturowy dla tego elementu. Domyślnie brak.
			\param id Unikatowa liczba identyfikująca nowy element. Domyślnie pierwsza wolna.
		**/
		int addItemAtPos(int index,const QString &iconname, const QString &text, const QObject* receiver, const char* member, const QKeySequence accel= 0, int id= -1);
		
		/**
			\fn void refreshIcons()
			Przeładowuje wszystkie ikony w tym menu dodane przy pomocy powyższych funkcji 
		**/
		void refreshIcons();
	signals:
		/**
			\fn void popup()
			Sygnał emitowany, gdy menu jest wywoływane.
		**/
		void popup();
};


/**
	Klasa reprezentująca listę kontaktów wraz z ikonkami stanów.
	\class UserBox
	\brief Wyświetlana lista kontaktów.
**/
class UserBox : public QListBox , QToolTip
{
	Q_OBJECT

	private:
		static QValueList<UserBox*> UserBoxes;
		static UserBoxSlots *userboxslots;
		// Pixmaps
		static QPixmap* OnlineMobilePixmap;
		static QPixmap* OnlineDescMobilePixmap;
		static QPixmap* BusyMobilePixmap;
		static QPixmap* BusyDescMobilePixmap;
		static QPixmap* OfflineMobilePixmap;
		static QPixmap* OfflineDescMobilePixmap;		
		//
		QStringList Users;
		void sortUsersByAltNick(QStringList &);
			
	protected:
		/**
			\fn virtual void maybeTip(const QPoint& c)
			Wyświetla dymek w danym punkcie z informacją o kontakcie znajdującym się w tym punkcie
			względem lewego górnego rogu listy kontaktów.
			\param c współrzędne punktu
		**/
		virtual void maybeTip(const QPoint&);

		/**
			\fn virtual void mousePressEvent(QMouseEvent *e)
			Wciśnięto któryś z przycisków myszki na liście kontaktów.
			\param e wskaźnik obiektu opisującego to zdarzenie.
		**/
		virtual void mousePressEvent(QMouseEvent *e);

		/**
			\fn virtual void mouseMoveEvent(QMouseEvent* e)
			Poruszono myszką nad listą kontaktów.
			\param e wskaźnik obiektu opisującego to zdarzenie.
		**/
		virtual void mouseMoveEvent(QMouseEvent* e);

		/**
			\fn virtual void keyPressEvent(QKeyEvent *e)
			Wciśnięto któryś z klawiszów w aktywnej liście kontaktów.
			\param e wskaźnik obiektu opisującego to zdarzenie.
		**/
		virtual void keyPressEvent(QKeyEvent *e);

		/**
			\fn virtual void resizeEvent(QResizeEvent *)
			Lista kontaktów zmieniła swój rozmiar.
			\param e wskaźnik obiektu opisującego to zdarzenie.
		**/
		virtual void resizeEvent(QResizeEvent *);

	public:
		/**
			\fn UserBox(QWidget* parent=0, const char* name=0, WFlags f=0)
			Standardowy konstruktor tworzący listę kontaktów.
			\param parent rodzic kontrolki. Domyślnie 0.
			\param name nazwa kontrolki. Domyślnie 0.
			\param f flagi kontrolki. Domyślnie 0.
		**/
		UserBox(QWidget* parent=0,const char* name=0,WFlags f=0);
		~UserBox();

		/**
			\var static UserBoxMenu *userboxmenu
			Wskaźnik do menu kontekstowego listy kontaktów.
		**/
		static UserBoxMenu *userboxmenu;

		/**
			\fn bool containsAltNick(const QString &altnick) const
			Funkcja sprawdza czy dany altnick, znajduje się na liscie w UserBox.
		**/
		bool containsAltNick(const QString &altnick) const;

		/**
			\fn static void initModule()
			Inicjalizuje zmienne niezbędne do działania UserBox. Funkcja ta jest
			wywoływana przy starcie Kadu przez rdzeń Kadu.
		**/
		static void initModule();
		static void closeModule();
		/**
			\fn UinsList getSelectedUins() const
			Funkcja zwraca listę zaznaczonych użytkowników.
			\return UinsList z zaznaczonymi użytkownikami posiadającymi numer GG
		**/
		UinsList getSelectedUins() const;

		/**
			\fn UserList getSelectedUsers() const
			Funkcja zwraca listę zaznaczonych uzytkowników.
			\return UserList z zaznaczonymi użytkownikami.
		**/
		UserList getSelectedUsers() const;

		/**
			\fn QStringList getSelectedAltNicks() const
			Funkcja zwraca listę zaznaczonych uzytkowników.
			\return QStringList z pseudonimami wyświetlanymi (altNick'ami).
		**/
		QStringList getSelectedAltNicks() const;

		/**
			\fn static UserBox* getActiveUserBox()
			Funkcja znajdujaca aktywny UserBox.
			\return wskaźnik do aktywnego UserBox'a, jeśli taki nie istnieje zwracana jest wartość NULL.
		**/
		static UserBox* getActiveUserBox();

	public slots:
		/**
			\fn void refresh()
			Odświerza listę (rysuje od nowa).
		**/
		void refresh();

		/**
			\fn void showHideInactive()
			Przełącza tryb pokazywania kontaktów niedostępnych.
		**/
		void showHideInactive();

		/**
			\fn void showHideDescriptions()
			Przełącza tryb pokazywania opisów kontaktów.
		**/
		void showHideDescriptions();

		/**
			\fn virtual void clear()
			Czyśli listę.
		**/
		virtual void clear() { QListBox::clear(); };

		/**
			\fn void clearUsers()
			Funkcja czyści całą listę użytkowników w UserBox.
		**/
		void clearUsers() { Users.clear(); };

		/**
			\fn void addUser(const QString &altnick)
			Funkcja dodaje użytkownika o podanym pseudonimie wyświetlanym (altNicku) do listy w UserBox.
		**/
		void addUser(const QString &altnick);

		/**
			\fn void removeUser(const QString &altnick)
			Funkcja usuwa użytkownika o podanym pseudonimie wyświetlanym (altNick) z listy w UserBox.
		**/
		void removeUser(const QString &altnick);

		/**
			\fn void renameUser(const QString &oldaltnick, const QString &newaltnick)
			Funkcja zmienia pseudonim wyświetlany z podanego na inny w liście UserBox.
		**/
		void renameUser(const QString &oldaltnick, const QString &newaltnick);

		/**
			\fn void changeAllToInactive()
			Ustawia statusy dla wszystkich kontaktów na liście na niedostępny.
			\note Chodzi tu tylko o te widoczne statusy, rzeczywiste statusy kontaktów nadal
			będą znanie poprawnie w instancjach UserListElement.
		**/
		void changeAllToInactive();

		// Functions below works on all created userboxes
		/**
			\fn static void all_refresh()
			Wykonuje metodę UserBox::refresh() na wszystkich istniejących instancjach UserBox.
		**/
		static void all_refresh();

		/**
			\fn static void all_removeUser(const QString &altnick)
			Funkcja usuwa użytkownika o podanym pseudonimie wyświetlanym (altNick) z wszystkich
			instancji UserBox.
		**/
		static void all_removeUser(const QString &altnick);

		/**
			\fn static void all_changeAllToInactive()
			Wykonuje metodę UserBox::changeAllToInactive() na wszystkich istniejących instancjach
			UserBox.
		**/
		static void all_changeAllToInactive();

		/**
			\fn static void all_renameUser(const QString &oldaltnick, const QString &newaltnick)
			Funkcja zmienia pseudonim wyświetlany z podanego na inny we wszystkich instancjach UserBox.
		**/
		static void all_renameUser(const QString &oldaltnick, const QString &newaltnick);

	signals:
		/**
			\fn void doubleClicked(const QString &text)
			Sygnał jest emitowany, gdy na którymś z kontaktów kliknięto dwukrotnie.
			\param text pseudonim wyświetlany (altNick) kontaktu na którym dwu-kilknięto.
			\warning Używaj tego sygnału zamiast QListBox::doubleClicked(QListBoxItem *) !!!
			Tamten ze względu na odświeżanie listy w jednym ze slotów podłączonych
			do tego sygnału czasami przekazuje wskaźnik do elementu, który już NIE ISTNIEJE.
		**/
		void doubleClicked(const QString &text);

		/**
			\fn void returnPressed(const QString &text)
			Sygnał jest emitowany, gdy wciśnięto klawisz enter na wybranym kontakcie.
			\param text pseudonim wyświetlany (altNick) kontaktu na którym wciśnięto enter.
			\warning Używaj tego sygnału zamiast QListBox::returnPressed(QListBoxItem *) !!!
			Tamten ze względu na odświeżanie listy w jednym ze slotów podłączonych
			do tego sygnału czasami przekazuje wskaźnik do elementu, który już NIE ISTNIEJE.
		**/
		void returnPressed(const QString &text);
	private slots:
		void doubleClickedSlot(QListBoxItem *item);
		void returnPressedSlot(QListBoxItem *item);
};

/**
	Klasa ta pozwala na podgląd wprowadzanych zmian konfiguracyjnych wobec UserBox
	w oknie konfiguracji, zanim zaaplikuje się je do Kadu.
	\class UserBoxSlots
	\brief Obsługa UserBox w konfiguracji.
**/
class UserBoxSlots : public QObject
{
	Q_OBJECT
	public slots:
		/**
			\fn void onCreateConfigDialog()
			Obsługuje sekcję UserBox podczas otwierania okna konfiguracji.
		**/
		void onCreateConfigDialog();

		/**
			\fn void onDestroyConfigDialog()
			Obsługuje sekcję UserBox podczas zamykania okna konfiguracji.
		**/
		void onDestroyConfigDialog();

		/**
			\fn void chooseColor(const char *name, const QColor& color)
			Odświerza podgląd wybranego koloru.
			\param name nazwa elementu, dla którego wybrano kolor.
				\arg \c userbox_bg_color oznacza kolor tła.
				\arg \c userbox_font_color oznacz kolor czcionki.
			\param color wybrany kolor.
		**/
		void chooseColor(const char *name, const QColor& color);

		/**
			\fn void chooseFont(const char *name, const QFont& font)
			Odświerza podgląd wybranej czcionki.
			\param name nazwa elementu, dla którego wybrano czcionkę.
				\arg \c userbox_font_box oznacza ogólną czcionkę listy kontaktów.
			\param font wybrana czcionka.
		**/
		void chooseFont(const char *name, const QFont& font);

		/**
			\fn void onMultiColumnUserbox(bool toggled)
			Włącza bądź wyłącza kontrolkę szerokości kolumny listy kontaktów, w zależności od podanego argumentu.
			\param togglet wartość logiczna informująca, czy kontrolka ma być włączona czy wyłączona.
		**/
		void onMultiColumnUserbox(bool toggled);

		/**
			\fn void updatePreview()
			Odświerza podgląd wszystkich elementów UserBox'a.
		**/
		void updatePreview();
};

#endif
