[qet] [1490] Refactoring: added the class GenericPanel, which provides most functions for ElementsPanel, ElementsCategoriesList, and any future panel-like widget.

[ Thread Index | Date Index | More lists.tuxfamily.org/qet Archives ]


Revision: 1490
Author:   xavier
Date:     2012-02-06 22:21:43 +0100 (Mon, 06 Feb 2012)
Log Message:
-----------
Refactoring: added the class GenericPanel, which provides most functions for ElementsPanel, ElementsCategoriesList, and any future panel-like widget.

Modified Paths:
--------------
    branches/0.3/sources/diagram.cpp
    branches/0.3/sources/diagram.h
    branches/0.3/sources/elementdialog.cpp
    branches/0.3/sources/elementscategorieslist.cpp
    branches/0.3/sources/elementscategorieslist.h
    branches/0.3/sources/elementspanel.cpp
    branches/0.3/sources/elementspanel.h
    branches/0.3/sources/elementspanelwidget.cpp
    branches/0.3/sources/elementspanelwidget.h
    branches/0.3/sources/qet.h
    branches/0.3/sources/qetdiagrameditor.cpp
    branches/0.3/sources/qetdiagrameditor.h
    branches/0.3/sources/qetproject.cpp
    branches/0.3/sources/qetproject.h

Added Paths:
-----------
    branches/0.3/sources/genericpanel.cpp
    branches/0.3/sources/genericpanel.h

Modified: branches/0.3/sources/diagram.cpp
===================================================================
--- branches/0.3/sources/diagram.cpp	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/diagram.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -69,6 +69,10 @@
 		&border_and_titleblock, SIGNAL(needTitleBlockTemplate(const QString &)),
 		this, SLOT(setTitleBlockTemplate(const QString &))
 	);
+	connect(
+		&border_and_titleblock, SIGNAL(diagramTitleChanged(const QString &)),
+		this, SLOT(titleChanged(const QString &))
+	);
 }
 
 /**
@@ -711,6 +715,10 @@
 	);
 }
 
+void Diagram::titleChanged(const QString &title) {
+	emit(diagramTitleChanged(this, title));
+}
+
 /**
 	Gere le fait qu'un texte du schema ait ete modifie
 	@param text_item Texte modifie

Modified: branches/0.3/sources/diagram.h
===================================================================
--- branches/0.3/sources/diagram.h	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/diagram.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -171,6 +171,7 @@
 	QGIManager &qgiManager();
 	
 	public slots:
+	void titleChanged(const QString &);
 	void diagramTextChanged(DiagramTextItem *, const QString &, const QString &);
 	void titleBlockTemplateChanged(const QString &);
 	void titleBlockTemplateRemoved(const QString &, const QString & = QString());
@@ -185,7 +186,9 @@
 	void written();
 	void readOnlyChanged(bool);
 	void usedTitleBlockTemplateChanged(const QString &);
+	void diagramTitleChanged(Diagram *, const QString &);
 };
+Q_DECLARE_METATYPE(Diagram *)
 
 /**
 	Permet d'ajouter ou enlever le "poseur de conducteur", c'est-a-dire la

Modified: branches/0.3/sources/elementdialog.cpp
===================================================================
--- branches/0.3/sources/elementdialog.cpp	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/elementdialog.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -51,9 +51,9 @@
 	int selectables = 0;
 	switch(mode_) {
 		case OpenElement:  selectables = QET::Element; break;
-		case SaveElement:  selectables = QET::All; break;
-		case OpenCategory: selectables = QET::Category | QET::Collection; break;
-		case SaveCategory: selectables = QET::Category | QET::Collection; break;
+		case SaveElement:  selectables = QET::ElementsCollectionItem; break;
+		case OpenCategory: selectables = QET::ElementsContainer; break;
+		case SaveCategory: selectables = QET::ElementsContainer; break;
 	}
 	list_    = new ElementsCategoriesList(display_elements, selectables);
 	connect(list_, SIGNAL(locationChanged(const ElementsLocation &)), this, SLOT(locationChanged(const ElementsLocation &)));

Modified: branches/0.3/sources/elementscategorieslist.cpp
===================================================================
--- branches/0.3/sources/elementscategorieslist.cpp	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/elementscategorieslist.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -31,7 +31,7 @@
 	@param parent QWidget parent de ce widget
 */
 ElementsCategoriesList::ElementsCategoriesList(bool display_elements, uint selectables, QWidget *parent) :
-	QTreeWidget(parent),
+	GenericPanel(parent),
 	display_elements_(display_elements),
 	selectables_(selectables),
 	first_load(true)
@@ -39,12 +39,15 @@
 	// selection unique
 	setSelectionMode(QAbstractItemView::SingleSelection);
 	setColumnCount(1);
-	header() -> hide();
 	
 	// charge les categories
+	setElementsCache(QETApp::collectionCache());
 	reload();
 	
-	connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(selectionChanged(QTreeWidgetItem *, QTreeWidgetItem *)));
+	connect(
+		this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
+		this, SLOT(selectionChanged(QTreeWidgetItem *, QTreeWidgetItem *))
+	);
 }
 
 /**
@@ -57,124 +60,61 @@
 	Recharge l'arbre des categories
 */
 void ElementsCategoriesList::reload() {
-	// vide l'arbre
-	clear();
+	GenericPanel::PanelOptions  options = display_elements_ ? GenericPanel::AddAllChildElements : GenericPanel::AddChildElementsContainers;
+	options |= GenericPanel::DisplayElementsPreview;
 	
 	foreach(ElementsCollection *collection, QETApp::availableCollections()) {
 		if (collection == QETApp::commonElementsCollection()) continue;
 		if (collection == QETApp::customElementsCollection()) continue;
-		addCollection(invisibleRootItem(), collection, tr("Collection projet"));
+		addElementsCollection(collection, invisibleRootItem(), options, tr("Collection projet")) -> setExpanded(true);
 	}
 	
 	// chargement des elements de la collection commune si droits d'ecriture
 	if (QETApp::commonElementsCollection() -> isWritable()) {
-		if (!first_load) QETApp::commonElementsCollection() -> reload();
-		addCollection(invisibleRootItem(), QETApp::commonElementsCollection(), tr("Collection QET"), QET::Icons::QETLogo);
+		addElementsCollection(
+			QETApp::commonElementsCollection(),
+			invisibleRootItem(),
+			options,
+			tr("Collection QET"),
+			QIcon(":/ico/16x16/qet.png")
+		) -> setExpanded(true);
 	}
 	
 	// chargement des elements de la collection utilisateur
-	if (!first_load) QETApp::customElementsCollection() -> reload();
-	addCollection(invisibleRootItem(), QETApp::customElementsCollection(), tr("Collection utilisateur"), QET::Icons::Home);
+	addElementsCollection(
+		QETApp::customElementsCollection(),
+		invisibleRootItem(),
+		options,
+		tr("Collection utilisateur"),
+		QIcon(":/ico/16x16/go-home.png")
+	) -> setExpanded(true);
 	
 	if (first_load) first_load = false;
 }
 
 /**
-	Methode privee permettant d'ajouter une collection d'elements
-	@param qtwi_parent QTreeWidgetItem parent sous lequel sera insere la collection d'elements
-	@param collection Collection a inserer dans le panel d'elements
-	@param coll_name Nom a utiliser pour la collection
-	@param icon Icone a utiliser pour l'affichage de la collection
-	@return Le QTreeWidgetItem insere le plus haut
+	Create a QTreeWidgetItem
+	@param type Item type (e.g QET::Diagram, QET::Project, ...)
+	@param parent Parent for the created item
+	@param label Label for the created item
+	@param icon Icon for the created item
+	@return the create QTreeWidgetItem
 */
-QTreeWidgetItem *ElementsCategoriesList::addCollection(QTreeWidgetItem *qtwi_parent, ElementsCollection *collection, const QString &coll_name, const QIcon &icon) {
-	QTreeWidgetItem *qtwi_coll = addCategory(qtwi_parent, collection -> rootCategory(), coll_name, icon);
-	qtwi_coll -> setExpanded(true);
-	Qt::ItemFlags flags_coll = Qt::ItemIsEnabled;
-	if (selectables_ & QET::Collection) flags_coll |= Qt::ItemIsSelectable;
-	qtwi_coll -> setFlags(flags_coll);
-	return(qtwi_coll);
+QTreeWidgetItem *ElementsCategoriesList::makeItem(QET::ItemType type, QTreeWidgetItem *parent, const QString &label, const QIcon &icon) {
+	QTreeWidgetItem *item = GenericPanel::makeItem(type, parent, label, icon);
+	Qt::ItemFlags flags = Qt::ItemIsEnabled;
+	if (selectables_ & item -> type()) flags |= Qt::ItemIsSelectable;
+	item -> setFlags(flags);
+	return(item);
 }
 
 /**
-	Methode privee permettant d'ajouter une categorie
-	@param qtwi_parent QTreeWidgetItem parent sous lequel sera insere la categorie
-	@param category Categorie d'elements a inserer
-	@param cat_name Parametre facultatif permettant de forcer le nom affiche
-	S'il n'est pas precise, la methode utilise le nom declare par la categorie.
-	@param icon Icone a utiliser pour l'affichage de la categorie
-	Si elle n'est pas precisee, une icone par defaut est utilisee
-	@return Le QTreeWidgetItem insere le plus haut
-*/
-QTreeWidgetItem *ElementsCategoriesList::addCategory(QTreeWidgetItem *qtwi_parent, ElementsCategory *category, const QString &cat_name, const QIcon &icon) {
-	// recupere le nom de la categorie
-	QString final_name(cat_name.isEmpty() ? category -> name() : cat_name);
-	QIcon final_icon(icon.isNull() ? QET::Icons::Folder : icon);
-	
-	// creation du QTreeWidgetItem representant le dossier
-	QTreeWidgetItem *qtwi_category = new QTreeWidgetItem(qtwi_parent, QStringList(final_name));
-	qtwi_category -> setIcon(0, final_icon);
-	locations_.insert(qtwi_category, category -> location());
-	Qt::ItemFlags flags_category = Qt::ItemIsEnabled;
-	if (selectables_ & QET::Category) flags_category |= Qt::ItemIsSelectable;
-	qtwi_category -> setFlags(flags_category);
-	
-	// ajout des sous-categories
-	foreach(ElementsCategory *sub_cat, category -> categories()) addCategory(qtwi_category, sub_cat);
-	
-	if (display_elements_) {
-		foreach(ElementDefinition *elmt, category -> elements()) addElement(qtwi_category, elmt);
-	}
-	
-	return(qtwi_category);
-}
-
-/**
-	Methode privee permettant d'ajouter un element
-	@param qtwi_parent QTreeWidgetItem parent sous lequel sera insere l'element
-	@param element Element a inserer
-	@param elmt_name Parametre facultatif permettant de forcer le nom affiche
-	S'il n'est pas precise, la methode utilise le nom declare par la categorie.
-	@param icon Icone a utiliser pour l'affichage de l'element
-	@return Le QTreeWidgetItem insere
-*/
-QTreeWidgetItem *ElementsCategoriesList::addElement(QTreeWidgetItem *qtwi_parent, ElementDefinition *element, const QString &elmt_name, const QIcon &icon) {
-	int state;
-	CustomElement custom_elmt(element -> xml(), 0, 0, &state);
-	if (state) {
-		qDebug() << "ElementsCategoriesList::addElement() : Le chargement du composant" << qPrintable(element -> location().toString()) << "a echoue avec le code d'erreur" << state;
-		return(0);
-	}
-	QString final_name(elmt_name.isEmpty() ? custom_elmt.name() : elmt_name);
-	QTreeWidgetItem *qtwi = new QTreeWidgetItem(qtwi_parent, QStringList(final_name));
-	qtwi -> setToolTip(0, custom_elmt.name());
-	Qt::ItemFlags flags_element = Qt::ItemIsEnabled;
-	if (selectables_ & QET::Element) flags_element |= Qt::ItemIsSelectable;
-	qtwi -> setFlags(flags_element);
-	qtwi -> setIcon(0, icon);
-	locations_.insert(qtwi, element -> location());
-	
-	return(qtwi);
-}
-
-/**
-	@return Le nom de la categorie selectionnee
-*/
-QString ElementsCategoriesList::selectedCategoryName() const {
-	QTreeWidgetItem *qtwi = currentItem();
-	if (qtwi) return(qtwi -> data(0, Qt::DisplayRole).toString());
-	else return(QString());
-}
-
-/**
 	@return l'emplacement correspondant au QTreeWidgetItem selectionne
 */
 ElementsLocation ElementsCategoriesList::selectedLocation() const {
-	if (QTreeWidgetItem *current_qtwi = currentItem()) {
-		return(locations_[current_qtwi]);
-	} else {
-		return(ElementsLocation());
-	}
+	QTreeWidgetItem *current_qtwi = currentItem();
+	if (!current_qtwi) return(ElementsLocation());
+	return(valueForItem<ElementsLocation>(current_qtwi));
 }
 
 /**
@@ -184,11 +124,9 @@
 	@return true si la selection a pu etre effectuee, false sinon
 */
 bool ElementsCategoriesList::selectLocation(const ElementsLocation &location) {
-	if (QTreeWidgetItem *qtwi = locations_.key(location)) {
-		setCurrentItem(qtwi);
-		return(true);
-	}
-	return(false);
+	QTreeWidgetItem *qtwi = itemForElementsLocation(location);
+	if (qtwi) setCurrentItem(qtwi);
+	return(qtwi);
 }
 
 /**
@@ -201,7 +139,7 @@
 	Q_UNUSED(previous);
 	ElementsLocation emited_location;
 	if (current) {
-		emited_location = locations_[current];
+		emited_location = valueForItem<ElementsLocation>(current);
 	}
 	emit(locationChanged(emited_location));
 }

Modified: branches/0.3/sources/elementscategorieslist.h
===================================================================
--- branches/0.3/sources/elementscategorieslist.h	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/elementscategorieslist.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -20,6 +20,7 @@
 #include <QtGui>
 #include "qet.h"
 #include "elementslocation.h"
+#include "genericpanel.h"
 class ElementsCollection;
 class ElementsCategory;
 class ElementDefinition;
@@ -27,7 +28,7 @@
 	Cette classe fournit une liste graphique des categories d'elements de
 	l'utilisateur.
 */
-class ElementsCategoriesList : public QTreeWidget {
+class ElementsCategoriesList : public GenericPanel {
 	Q_OBJECT
 	
 	// Constructeurs, destructeur
@@ -40,15 +41,12 @@
 	
 	// methodes
 	public:
-	QString selectedCategoryName() const;
 	ElementsLocation selectedLocation() const;
 	bool selectLocation(const ElementsLocation &);
 	
 	private:
-	QTreeWidgetItem *addCollection(QTreeWidgetItem *, ElementsCollection *, const QString & = QString(), const QIcon & = QIcon());
-	QTreeWidgetItem *addCategory  (QTreeWidgetItem *, ElementsCategory   *, const QString & = QString(), const QIcon & = QIcon());
-	QTreeWidgetItem *addElement   (QTreeWidgetItem *, ElementDefinition  *, const QString & = QString(), const QIcon & = QIcon());
 	QString categoryName(QDir &);
+	QTreeWidgetItem *makeItem(QET::ItemType, QTreeWidgetItem *, const QString &, const QIcon &);
 	
 	public slots:
 	void reload();
@@ -64,6 +62,5 @@
 	bool display_elements_;
 	int selectables_;
 	bool first_load;
-	QHash<QTreeWidgetItem *, ElementsLocation> locations_;
 };
 #endif

Modified: branches/0.3/sources/elementspanel.cpp
===================================================================
--- branches/0.3/sources/elementspanel.cpp	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/elementspanel.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -85,17 +85,15 @@
 	@param parent Le QWidget parent du panel d'appareils
 */
 ElementsPanel::ElementsPanel(QWidget *parent) :
-	QTreeWidget(parent),
+	GenericPanel(parent),
 	common_collection_item_(0),
 	custom_collection_item_(0),
-	first_activation_(true),
 	first_reload_(true)
 {
 	// selection unique
 	setSelectionMode(QAbstractItemView::SingleSelection);
 	setColumnCount(1);
 	setExpandsOnDoubleClick(true);
-	header() -> hide();
 	
 	// drag'n drop autorise
 	setDragEnabled(true);
@@ -103,9 +101,6 @@
 	setDropIndicatorShown(true);
 	setAutoExpandDelay(1000);
 	
-	// taille des elements
-	setIconSize(QSize(50, 50));
-	
 	// force du noir sur une alternance de blanc (comme le schema) et de gris
 	// clair, avec du blanc sur bleu pas trop fonce pour la selection
 	QPalette qp = palette();
@@ -116,15 +111,20 @@
 	qp.setColor(QPalette::HighlightedText, Qt::white);
 	setPalette(qp);
 	
-	// double-cliquer sur un element permet de l'editer
-	connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(slot_doubleClick(QTreeWidgetItem *, int)));
+	// we handle double click on items ourselves
+	connect(
+		this,
+		SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
+		this,
+		SLOT(slot_doubleClick(QTreeWidgetItem *, int))
+	);
 	
+	connect(this, SIGNAL(firstActivated()), this, SLOT(firstActivation()));
+	
 	// emet un signal au lieu de gerer son menu contextuel
 	setContextMenuPolicy(Qt::CustomContextMenu);
 	
-	QString cache_path = QETApp::configDir() + "/elements_cache.sqlite";
-	cache_ = new ElementsCollectionCache(cache_path, this);
-	cache_ -> setLocale(QLocale::system().name().left(2)); // @todo we need a unique function to get the good language
+	setElementsCache(QETApp::collectionCache());
 }
 
 /**
@@ -135,65 +135,8 @@
 
 /**
 	@param qtwi Un QTreeWidgetItem
-	@return true si qtwi represente une collection, false sinon
-*/
-bool ElementsPanel::itemIsACollection(QTreeWidgetItem *qtwi) const {
-	if (ElementsCollectionItem *qtwi_item = collectionItemForItem(qtwi)) {
-		return(qtwi_item -> isCollection());
-	}
-	return(false);
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return true si qtwi represente une categorie, false sinon
-*/
-bool ElementsPanel::itemIsACategory(QTreeWidgetItem *qtwi) const {
-	if (ElementsCollectionItem *qtwi_item = collectionItemForItem(qtwi)) {
-		return(qtwi_item -> isCategory());
-	}
-	return(false);
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
 	@return true si qtwi represente un element, false sinon
 */
-bool ElementsPanel::itemIsAnElement(QTreeWidgetItem *qtwi) const {
-	if (ElementsCollectionItem *qtwi_item = collectionItemForItem(qtwi)) {
-		return(qtwi_item -> isElement());
-	}
-	return(false);
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return true si qtwi represente un projet, false sinon
-*/
-bool ElementsPanel::itemIsAProject(QTreeWidgetItem *qtwi) const {
-	return(projects_.contains(qtwi));
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return true si ce que represente qtwi est accessible en ecriture
-*/
-bool ElementsPanel::itemIsADiagram(QTreeWidgetItem *qtwi) const {
-	return(diagrams_.contains(qtwi));
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return true si le qtwi est associe a une ElementsLocation
-*/
-bool ElementsPanel::itemHasLocation(QTreeWidgetItem *qtwi) const {
-	return(locations_.contains(qtwi));
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return true si qtwi represente un element, false sinon
-*/
 bool ElementsPanel::itemIsWritable(QTreeWidgetItem *qtwi) const {
 	if (ElementsCollectionItem *qtwi_item = collectionItemForItem(qtwi)) {
 		return(qtwi_item -> isWritable());
@@ -201,127 +144,8 @@
 	return(false);
 }
 
-/**
-	@param qtwi A QTreeWidgetItem 
-	@return true if the given QTreeWidgetItem represents a block templates directory
-*/
-bool ElementsPanel::itemIsATitleBlockTemplatesCollection(QTreeWidgetItem *qtwi) const {
-	return(
-		qtwi == custom_tbt_collection_item_ ||
-		qtwi == common_tbt_collection_item_ ||
-		title_blocks_collections_.contains(qtwi)
-	);
-}
 
 /**
-	@param qtwi A QTreeWidgetItem 
-	@return true if the given QTreeWidgetItem represents a block template
-*/
-bool ElementsPanel::itemIsATitleBlockTemplate(QTreeWidgetItem *qtwi) const {
-	return(title_blocks_.contains(qtwi));
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return L'ElementsCollectionItem represente par qtwi, ou 0 si qtwi ne
-	represente pas un ElementsCollectionItem
-*/
-ElementsCollectionItem *ElementsPanel::collectionItemForItem(QTreeWidgetItem *qtwi) const {
-	if (locations_.contains(qtwi)) {
-		return(QETApp::collectionItem(locations_[qtwi]));
-	}
-	return(0);
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return Le projet represente par qtwi, ou 0 si qtwi ne represente pas un
-	projet
-*/
-QETProject *ElementsPanel::projectForItem(QTreeWidgetItem *qtwi) const {
-	if (projects_.contains(qtwi)) {
-		return(projects_[qtwi]);
-	}
-	return(0);
-}
-
-/**
-	@param qtwi Un QTreeWidgetItem
-	@return Le schema represente par qtwi, ou 0 si qtwi ne represente pas un
-	schema
-*/
-Diagram *ElementsPanel::diagramForItem(QTreeWidgetItem *qtwi) const {
-	if (diagrams_.contains(qtwi)) {
-		return(diagrams_[qtwi]);
-	}
-	return(0);
-}
-
-/**
-	@param qtwi QTreeWidgetItem dont on veut connaitre l'emplacement
-	@return L'emplacement associe a qtwi, ou un emplacement nul s'il n'y a pas
-	d'emplacement associe a qtwi
-*/
-ElementsLocation ElementsPanel::locationForItem(QTreeWidgetItem *qtwi) const {
-	if (locations_.contains(qtwi)) {
-		return(locations_[qtwi]);
-	}
-	return(ElementsLocation());
-}
-
-/**
-	@return true si une collection est selectionnee, false sinon
-*/
-bool ElementsPanel::selectedItemIsACollection() const {
-	if (ElementsCollectionItem *selected_item = selectedItem()) {
-		return(selected_item -> isCollection());
-	}
-	return(false);
-}
-
-/**
-	@return true si une categorie est selectionnee, false sinon
-*/
-bool ElementsPanel::selectedItemIsACategory() const {
-	if (ElementsCollectionItem *selected_item = selectedItem()) {
-		return(selected_item -> isCategory());
-	}
-	return(false);
-}
-
-/**
-	@return true si un element est selectionne, false sinon
-*/
-bool ElementsPanel::selectedItemIsAnElement() const {
-	if (ElementsCollectionItem *selected_item = selectedItem()) {
-		return(selected_item -> isElement());
-	}
-	return(false);
-}
-
-/**
-	@return true si un projet est selectionne, false sinon
-*/
-bool ElementsPanel::selectedItemIsAProject() const {
-	return(projects_.contains(currentItem()));
-}
-
-/**
-	@return true si un schema est selectionne, false sinon
-*/
-bool ElementsPanel::selectedItemIsADiagram() const {
-	QTreeWidgetItem *current = currentItem();
-	return(diagrams_.contains(current));
-}
-
-/**
-	@return true si l'element selectionne est associe a une ElementsLocation
-*/
-bool ElementsPanel::selectedItemHasLocation() const {
-	return(locations_.contains(currentItem()));
-}
-
-/**
 	@return true si l'item selectionne est accessible en ecriture, false sinon
 */
 bool ElementsPanel::selectedItemIsWritable() const {
@@ -332,27 +156,10 @@
 }
 
 /**
-	@return true if the currently selected item represents a title block
-	templates directory
-*/
-bool ElementsPanel::selectedItemIsATitleBlockTemplatesDirectory() const {
-	return(itemIsATitleBlockTemplatesCollection(currentItem()));
-}
-
-/**
-	@return true if the currently selected item represents a title block
-	template
-*/
-bool ElementsPanel::selectedItemIsATitleBlockTemplate() const {
-	if (!currentItem()) return(false);
-	return(itemIsATitleBlockTemplate(currentItem()));
-}
-
-/**
 	@return la collection, la categorie ou l'element selectionne(e)
 */
 ElementsCollectionItem *ElementsPanel::selectedItem() const {
-	ElementsLocation selected_location(selectedLocation());
+	ElementsLocation selected_location(selectedElementLocation());
 	if (!selected_location.isNull()) {
 		return(QETApp::collectionItem(selected_location));
 	}
@@ -360,27 +167,6 @@
 }
 
 /**
-	@return Le projet selectionne, ou 0 s'il n'y en a pas
-*/
-QETProject *ElementsPanel::selectedProject() const {
-	return(projectForItem(currentItem()));
-}
-
-/**
-	@return Le schema selectionne, ou 0 s'il n'y en a pas
-*/
-Diagram *ElementsPanel::selectedDiagram() const {
-	return(diagramForItem(currentItem()));
-}
-
-/**
-	@return L'emplacement selectionne, ou un emplacement nul s'il n'y en a pas
-*/
-ElementsLocation ElementsPanel::selectedLocation() const {
-	return(locationForItem(currentItem()));
-}
-
-/**
 	Gere l'entree d'un drag'n drop. L'evenement est accepte si les donnees
 	fournies contiennent un type MIME representant une categorie ou un element
 	QET.
@@ -493,13 +279,13 @@
 void ElementsPanel::startDrag(Qt::DropActions supportedActions) {
 	Q_UNUSED(supportedActions);
 	// recupere l'emplacement selectionne
-	ElementsLocation element_location = selectedLocation();
+	ElementsLocation element_location = selectedElementLocation();
 	if (!element_location.isNull()) {
 		startElementDrag(element_location);
 		return;
 	}
 	
-	TitleBlockTemplateLocation tbt_location = locationForTitleBlockTemplate(currentItem());
+	TitleBlockTemplateLocation tbt_location = selectedTemplateLocation();
 	if (tbt_location.isValid()) {
 		startTitleBlockTemplateDrag(tbt_location);
 		return;
@@ -580,15 +366,8 @@
 	drag -> start(Qt::CopyAction);
 }
 
-/**
-	@param event Object describing the received event 
-*/
-bool ElementsPanel::event(QEvent *event) {
-	if (first_activation_ && event -> type() == QEvent::WindowActivate) {
-		QTimer::singleShot(250, this, SLOT(reload()));
-		first_activation_ = false;
-	}
-	return(QTreeWidget::event(event));
+void ElementsPanel::firstActivation() {
+	QTimer::singleShot(250, this, SLOT(reload()));
 }
 
 /**
@@ -597,73 +376,21 @@
 	@param project Projet a inserer dans le panel d'elements
 	@return Le QTreeWidgetItem insere le plus haut
 */
-QTreeWidgetItem *ElementsPanel::addProject(QTreeWidgetItem *qtwi_parent, QETProject *project) {
+QTreeWidgetItem *ElementsPanel::addProject(QETProject *project) {
+	// create the QTreeWidgetItem representing the project
+	QTreeWidgetItem *qtwi_project = GenericPanel::addProject(project, 0, GenericPanel::All);
 	// the project will be inserted right before the common tb templates collection
-	QTreeWidgetItem *last_project = 0;
-	if (int common_collection_item_idx = indexOfTopLevelItem(common_tbt_collection_item_)) {
-		last_project = topLevelItem(common_collection_item_idx - 1);
-	}
-	
-	// creation du QTreeWidgetItem representant le projet
-	QTreeWidgetItem *qtwi_project = new QTreeWidgetItem(qtwi_parent, last_project);
-	qtwi_project -> setExpanded(true);
-	projects_.insert(qtwi_project, project);
-	updateProjectItemInformations(project);
-	connect(
-		project, SIGNAL(projectInformationsChanged(QETProject *)),
-		this,    SLOT  (projectInformationsChanged(QETProject *))
+	invisibleRootItem() -> insertChild(
+		indexOfTopLevelItem(common_tbt_collection_item_),
+		qtwi_project
 	);
+	qtwi_project -> setExpanded(true);
+	itemForTemplatesCollection(project -> embeddedTitleBlockTemplatesCollection()) -> setExpanded(true);
 	
-	// ajoute les schemas du projet
-	foreach (Diagram *diagram, project -> diagrams()) {
-		addDiagram(qtwi_project, diagram);
-	}
-	
-	// add the embedded title block templates collection
-	addTitleBlockTemplatesCollection(qtwi_project, project -> embeddedTitleBlockTemplatesCollection());
-	
-	// add the embedded elements collection
-	addCollection(qtwi_project, project -> embeddedCollection(), tr("Collection projet"));
-	
 	return(qtwi_project);
 }
 
 /**
-	Methode permettant d'ajouter un schema au panel d'elements.
-	@param qtwi_parent QTreeWidgetItem parent sous lequel sera insere le schema
-	@param diagram Schema a inserer dans le panel d'elements
-	@return Le QTreeWidgetItem insere le plus haut
-*/
-QTreeWidgetItem *ElementsPanel::addDiagram(QTreeWidgetItem *qtwi_parent, Diagram *diagram) {
-	// determine le nom du schema
-	QString final_name = diagramTitleToDisplay(diagram);
-	
-	// repere le dernier element correspondant a un schema, s'il existe
-	QTreeWidgetItem *previous_diagram_item = 0;
-	if (QETProject *project = diagram -> project()) {
-		int added_diagram_index = project -> diagrams().indexOf(diagram);
-		if (added_diagram_index > 0) {
-			Diagram *previous_diagram = project -> diagrams().at(added_diagram_index - 1);
-			previous_diagram_item = diagrams_.key(previous_diagram, 0);
-		}
-	}
-	
-	// creation du QTreeWidgetItem representant le schema
-	QTreeWidgetItem *qtwi_diagram;
-	if (previous_diagram_item) {
-		qtwi_diagram = new QTreeWidgetItem(qtwi_parent, previous_diagram_item);
-	} else {
-		qtwi_diagram = new QTreeWidgetItem();
-		qtwi_parent -> insertChild(0, qtwi_diagram);
-	}
-	qtwi_diagram -> setText(0, final_name);
-	qtwi_diagram -> setIcon(0, QET::Icons::Diagram);
-	diagrams_.insert(qtwi_diagram, diagram);
-	
-	return(qtwi_diagram);
-}
-
-/**
 	Methode privee permettant d'ajouter une collection d'elements au panel d'elements
 	@param qtwi_parent QTreeWidgetItem parent sous lequel sera insere la collection d'elements
 	@param collection Collection a inserer dans le panel d'elements - si
@@ -672,212 +399,56 @@
 	@param icon Icone a utiliser pour l'affichage de la collection
 	@return Le QTreeWidgetItem insere le plus haut
 */
-QTreeWidgetItem *ElementsPanel::addCollection(QTreeWidgetItem *qtwi_parent, ElementsCollection *collection, const QString &coll_name, const QIcon &icon) {
-	if (!collection) return(0);
-	
-	cache_ -> beginCollection(collection);
-	QTreeWidgetItem *qtwi_coll = addCategory(qtwi_parent, collection -> rootCategory(), coll_name, icon);
-	cache_ -> endCollection(collection);
-	return(qtwi_coll);
+QTreeWidgetItem *ElementsPanel::addCollection(ElementsCollection *collection, const QString &coll_name, const QIcon &icon) {
+	PanelOptions options = GenericPanel::AddAllChild;
+	options |= GenericPanel::DisplayElementsPreview;
+	return(addElementsCollection(collection, invisibleRootItem(), options, coll_name, icon));
 }
 
-/**
-	Methode privee permettant d'ajouter une categorie au panel d'elements
-	@param qtwi_parent QTreeWidgetItem parent sous lequel sera insere la categorie
-	@param category Categorie d'elements a inserer - si category vaut 0, cette
-	methode retourne 0.
-	@param cat_name Parametre facultatif permettant de forcer le nom affiche
-	S'il n'est pas precise, la methode utilise le nom declare par la categorie.
-	@param icon Icone a utiliser pour l'affichage de la categorie
-	Si elle n'est pas precisee, une icone par defaut est utilisee
-	@return Le QTreeWidgetItem insere le plus haut
-*/
-QTreeWidgetItem *ElementsPanel::addCategory(QTreeWidgetItem *qtwi_parent, ElementsCategory *category, const QString &cat_name, const QIcon &icon) {
-	if (!category) return(0);
-	
-	// recupere le nom de la categorie
-	QString final_name(cat_name.isEmpty() ? category -> name() : cat_name);
-	QIcon final_icon(icon.isNull() ? QET::Icons::Folder : icon);
-	
-	// creation du QTreeWidgetItem representant le dossier
-	QTreeWidgetItem *qtwi_category = new QTreeWidgetItem(qtwi_parent, QStringList(final_name));
-	qtwi_category -> setToolTip(0, category -> location().toString());
-	qtwi_category -> setIcon(0, final_icon);
-	QLinearGradient t(0, 0, 200, 0);
-	t.setColorAt(0, QColor("#e8e8e8"));
-	t.setColorAt(1, QColor("#ffffff"));
-	qtwi_category -> setBackground(0, QBrush(t));
-	locations_.insert(qtwi_category, category -> location());
+QTreeWidgetItem *ElementsPanel::updateTemplateItem(QTreeWidgetItem *tb_template_qtwi, const TitleBlockTemplateLocation &tb_template, PanelOptions options, bool freshly_created) {
+	QTreeWidgetItem *item = GenericPanel::updateTemplateItem(tb_template_qtwi, tb_template, options, freshly_created);
+	item -> setStatusTip(
+		0,
+		tr(
+			"Cliquer-d\351posez ce mod\350le de cartouche sur un sch\351ma pour l'y appliquer.",
+			"Tip displayed when selecting a title block template"
+		)
+	);
+	item -> setWhatsThis(
+		0,
+		tr(
+			"Ceci est un mod\350le de cartouche, qui peut \320tre appliqu\351 a un sch\351ma.",
+			"\"What's this\" tip"
+		)
+	);
+	return(item);
+}
+
+QTreeWidgetItem *ElementsPanel::updateElementsCategoryItem(QTreeWidgetItem *category_qtwi, ElementsCategory *category, PanelOptions options, bool freshly_created) {
+	QTreeWidgetItem *item = GenericPanel::updateElementsCategoryItem(category_qtwi, category, options, freshly_created);
 	emit(loadingProgressed(++ loading_progress_, -1));
-	
-	// reduit le dossier si besoin
-	qtwi_category -> setExpanded(expanded_directories.contains(category -> location().toString()));
-	
-	// ajout des sous-categories
-	foreach(ElementsCategory *sub_cat, category -> categories()) addCategory(qtwi_category, sub_cat);
-	
-	// ajout des elements
-	foreach(ElementDefinition *elmt, category -> elements()) {
-		addElement(qtwi_category, elmt);
-		emit(loadingProgressed(++ loading_progress_, -1));
-	}
-	
-	return(qtwi_category);
+	return(item);
 }
 
-/**
-	Methode privee permettant d'ajouter un element au panel d'elements
-	@param qtwi_parent QTreeWidgetItem parent sous lequel sera insere l'element
-	@param element Element a inserer
-	@param elmt_name Parametre facultatif permettant de forcer le nom affiche
-	S'il n'est pas precise, la methode utilise le nom declare par l'element.
-	Une icone sera generee a partir de l'element.
-	@return Le QTreeWidgetItem insere
-*/
-QTreeWidgetItem *ElementsPanel::addElement(QTreeWidgetItem *qtwi_parent, ElementDefinition *element, const QString &elmt_name) {
-	if (!element) return(0);
+QTreeWidgetItem *ElementsPanel::updateElementItem(QTreeWidgetItem *element_qtwi, ElementDefinition *element, PanelOptions options, bool freshly_created) {
+	QTreeWidgetItem *item = GenericPanel::updateElementItem(element_qtwi, element, options, freshly_created);
 	
-	if (!cache_ -> fetchElement(element)) {
-		return(0);
-	}
-	QString custom_element_name   = cache_ -> name();
-	QPixmap custom_element_pixmap = cache_ -> pixmap();
-	
 	QString whats_this = tr("Ceci est un \351l\351ment que vous pouvez ins\351rer dans votre sch\351ma par cliquer-d\351placer");
+	item -> setWhatsThis(0, whats_this);
+	
 	QString status_tip = tr(
 		"Cliquer-d\351posez cet \351l\351ment sur le sch\351ma pour ins\351rer un \351l\351ment \253 %1 \273",
 		"Tip displayed in the status bar when selecting an element"
 	);
-	QString final_name(elmt_name.isEmpty() ? custom_element_name : elmt_name);
-	QTreeWidgetItem *qtwi = new QTreeWidgetItem(qtwi_parent, QStringList(final_name));
-	qtwi -> setStatusTip(0, status_tip.arg(custom_element_name));
-	qtwi -> setToolTip(0, element -> location().toString());
-	qtwi -> setWhatsThis(0, whats_this);
-	qtwi -> setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled);
-	qtwi -> setIcon(0, QIcon(custom_element_pixmap));
+	item -> setStatusTip(0, status_tip.arg(item -> text(0)));
 	
-	// actions speciales pour les elements appartenant a un projet
-	if (QETProject *element_project = element -> location().project()) {
-		// affiche en rouge les elements inutilises dans un projet
-		if (!element_project -> usesElement(element -> location())) {
-			markItemAsUnused(qtwi);
-		}
-	}
-	locations_.insert(qtwi, element -> location());
+	item -> setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled);
 	
-	return(qtwi);
+	emit(loadingProgressed(++ loading_progress_, -1));
+	return(item);
 }
 
 /**
-	Adds \a collection under \a qtwi_parent with the given \a label and \a icon.
-	@param qtwi_parent Parent QTreeWidgetItem
-	@param collection Title block templates collection to be added to the panel
-	@param label Label for the returned QTreeWidgetItem
-	@param icon  Label for the returned QTreeWidgetItem
-	@return the QTreeWidgetItem representing the collection
-*/
-QTreeWidgetItem *ElementsPanel::addTitleBlockTemplatesCollection(
-	QTreeWidgetItem *qtwi_parent,
-	TitleBlockTemplatesCollection *collection,
-	const QString &label,
-	const QIcon &icon
-) {
-	if (!collection) return(0);
-	
-	QString selected_template;
-	
-	// check whether we have an item for the given collection
-	QTreeWidgetItem *qtwi_tbt_collection = title_blocks_collections_.key(collection);
-	if (!qtwi_tbt_collection) {
-		// the collection has not been added yet
-		QString final_label(label.isEmpty() ? tr("Mod\350les de cartouche") : label);
-		QIcon final_icon(icon.isNull() ? QET::Icons::TitleBlock : icon);
-		
-		// create the QTreeWidgetItem representing the collection itself
-		qtwi_tbt_collection = new QTreeWidgetItem(qtwi_parent, QStringList(final_label));
-		qtwi_tbt_collection -> setIcon(0, final_icon);
-		qtwi_tbt_collection -> setToolTip(0, collection -> location().toString());
-		qtwi_tbt_collection -> setExpanded(true);
-		title_blocks_collections_.insert(qtwi_tbt_collection, collection);
-		
-		// ensure the added collection will inform us about its changes
-		connect(
-			collection,
-			SIGNAL(changed(TitleBlockTemplatesCollection*, const QString &)),
-			this,
-			SLOT(titleBlockTemplatesCollectionChanged(TitleBlockTemplatesCollection*, const QString &))
-		);
-		// if the added collection is rattached to a project, we're interested in
-		// knowing how many times each template is used.
-		if (QETProject *project = collection -> parentProject()) {
-			connect(
-				project, SIGNAL(diagramUsedTemplate(TitleBlockTemplatesCollection *, const QString &)),
-				this, SLOT(titleBlockTemplatesCollectionChanged(TitleBlockTemplatesCollection *, const QString &))
-			);
-		}
-	} else {
-		// save the currently selected template, if any
-		if (QTreeWidgetItem *current_qtwi = currentItem()) {
-			for (int i = 0 ; i < qtwi_tbt_collection -> childCount() ; ++ i) {
-				if (qtwi_tbt_collection -> child(i) == current_qtwi) {
-					selected_template = nameOfTitleBlockTemplate(qtwi_tbt_collection -> child(i));
-				}
-			}
-		}
-		
-		// the collection has already been added
-		// remove the child title block templates
-		foreach(QTreeWidgetItem *qtwi_tbt, qtwi_tbt_collection -> takeChildren()) {
-			deleteItem(qtwi_tbt);
-		}
-	}
-	
-	// add the templates
-	foreach (QString template_name, collection -> templates()) {
-		QString final_name = titleBlockTemplateNameToDisplay(template_name);
-		TitleBlockTemplateLocation template_location = collection -> location(template_name);
-		
-		QTreeWidgetItem *qtwi_tbt = new QTreeWidgetItem(qtwi_tbt_collection, QStringList(final_name));
-		qtwi_tbt -> setStatusTip(
-			0,
-			tr(
-				"Cliquer-d\351posez ce mod\350le de cartouche sur un sch\351ma pour l'y appliquer.",
-				"Tip displayed when selecting a title block template"
-			)
-		);
-		qtwi_tbt -> setWhatsThis(
-			0,
-			tr(
-				"Ceci est un mod\350le de cartouche, qui peut \320tre appliqu\351 a un sch\351ma.",
-				"\"What's this\" tip"
-			)
-		);
-		qtwi_tbt -> setToolTip(0, template_location.toString());
-		qtwi_tbt -> setIcon(0, QET::Icons::TitleBlock);
-		
-		// special action for templates that belong to a project
-		if (QETProject *tbt_project = template_location.parentProject()) {
-			// display unused templates using a red background
-			if (!tbt_project -> usesTitleBlockTemplate(template_location)) {
-				markItemAsUnused(qtwi_tbt);
-			}
-		}
-		
-		title_blocks_.insert(qtwi_tbt, template_location);
-	}
-	
-	// restore the previously selected template, if any
-	if (!selected_template.isEmpty()) {
-		TitleBlockTemplateLocation location = collection -> location(selected_template);
-		QTreeWidgetItem *previously_selected_item = title_blocks_.key(location, 0);
-		if (previously_selected_item) {
-			setCurrentItem(previously_selected_item);
-		}
-	}
-	return(qtwi_tbt_collection);
-}
-
-/**
 	Reloads the following collections:
 	  * common collection
 	  * custom collection
@@ -887,7 +458,7 @@
 	ReloadCollectionThread thread;
 	thread.projects_ = projects_to_display_.values();
 	thread.start();
-	while(!thread.wait(100)) {
+	while(!thread.wait(50)) {
 		QApplication::processEvents();
 	}
 }
@@ -915,73 +486,50 @@
 	@param reload_collections true pour relire les collections depuis leurs sources (fichiers, projets...)
 */
 void ElementsPanel::reload(bool reload_collections) {
-	// sauvegarde la liste des repertoires reduits
-	saveExpandedCategories();
-	
 	if (reload_collections) {
 		emit(readingAboutToBegin());
 		reloadCollections();
 		emit(readingFinished());
 	}
 	
-	// vide l'arbre et le hash
-	foreach (TitleBlockTemplatesCollection *tbt_collection, title_blocks_collections_) {
-		if (QETProject *project = tbt_collection -> parentProject()) {
-			disconnect(project, 0, this, 0);
-		}
-	}
-	clear();
-	locations_.clear();
-	projects_.clear();
-	diagrams_.clear();
-	title_blocks_collections_.clear();
-	title_blocks_.clear();
-	common_collection_item_ = 0;
-	custom_collection_item_ = 0;
-	
 	QIcon system_icon(":/ico/16x16/qet.png");
 	QIcon user_icon(":/ico/16x16/go-home.png");
 	
-	
 	// estimates the number of categories and elements to load
 	int items_count = elementsCollectionItemsCount();
 	emit(loadingProgressed(loading_progress_ = 0, items_count));
 	
 	// load the common title block templates collection
 	TitleBlockTemplatesCollection *common_tbt_collection = QETApp::commonTitleBlockTemplatesCollection();
-	common_tbt_collection_item_ = addTitleBlockTemplatesCollection(invisibleRootItem(), common_tbt_collection, common_tbt_collection -> title(), system_icon);
+	common_tbt_collection_item_ = addTemplatesCollection(common_tbt_collection, invisibleRootItem());
+	common_tbt_collection_item_ -> setIcon(0, system_icon);
 	if (first_reload_) common_tbt_collection_item_ -> setExpanded(true);
 	
-	// chargement des elements de la collection QET
+	// load the common elements collection
 	if (QETApp::commonElementsCollection()->rootCategory()) {
-		common_collection_item_ = addCollection(invisibleRootItem(), QETApp::commonElementsCollection(), tr("Collection QET"), system_icon);
+		common_collection_item_ = addCollection(QETApp::commonElementsCollection(), tr("Collection QET"), system_icon);
 		if (first_reload_) common_collection_item_ -> setExpanded(true);
 	}
 	
 	// load the custom title block templates collection
 	TitleBlockTemplatesCollection *custom_tbt_collection = QETApp::customTitleBlockTemplatesCollection();
-	custom_tbt_collection_item_ = addTitleBlockTemplatesCollection(invisibleRootItem(), custom_tbt_collection, custom_tbt_collection -> title(), user_icon);
+	custom_tbt_collection_item_ = addTemplatesCollection(custom_tbt_collection, invisibleRootItem());
+	custom_tbt_collection_item_ -> setIcon(0, user_icon);
 	if (first_reload_) custom_tbt_collection_item_ -> setExpanded(true);
 	
-	// chargement des elements de la collection utilisateur
+	// load the custom elements collection
 	if (QETApp::customElementsCollection()->rootCategory()) {
-		custom_collection_item_ = addCollection(invisibleRootItem(), QETApp::customElementsCollection(), tr("Collection utilisateur"), user_icon);
+		custom_collection_item_ = addCollection(QETApp::customElementsCollection(), tr("Collection utilisateur"), user_icon);
 		if (first_reload_) custom_collection_item_ -> setExpanded(true);
 	}
 	
-	// chargement des projets
+	// add projects
 	foreach(QETProject *project, projects_to_display_.values()) {
-		addProject(invisibleRootItem(), project);
+		addProject(project);
 	}
 	
 	// the first time, expand the first level of collections
 	if (first_reload_) first_reload_ = false;
-	
-	// reselectionne le dernier element selectionne
-	if (!last_selected_item.isNull()) {
-		QTreeWidgetItem *qtwi = findLocation(last_selected_item);
-		if (qtwi) setCurrentItem(qtwi);
-	}
 }
 
 /**
@@ -995,79 +543,53 @@
 	@param qtwi
 */
 void ElementsPanel::slot_doubleClick(QTreeWidgetItem *qtwi, int) {
-	if (QETProject *project = projectForItem(qtwi)) {
+	int qtwi_type = qtwi -> type();
+	if (qtwi_type == QET::Project) {
+		QETProject *project = valueForItem<QETProject *>(qtwi);
 		emit(requestForProject(project));
-	} else if (Diagram *diagram = diagramForItem(qtwi)) {
+	} else if (qtwi_type == QET::Diagram) {
+		Diagram *diagram = valueForItem<Diagram *>(qtwi);
 		emit(requestForDiagram(diagram));
-	} else if (ElementsCollectionItem *item = collectionItemForItem(qtwi)) {
-		emit(requestForCollectionItem(item));
-	} else if (itemIsATitleBlockTemplate(qtwi)) {
-		emit(requestForTitleBlockTemplate(title_blocks_[qtwi]));
+	} else if (qtwi_type & QET::ElementsCollectionItem) {
+		ElementsLocation element = valueForItem<ElementsLocation>(qtwi);
+		emit(requestForCollectionItem(element));
+	} else if (qtwi_type == QET::TitleBlockTemplate) {
+		TitleBlockTemplateLocation tbt = valueForItem<TitleBlockTemplateLocation>(qtwi);
+		emit(requestForTitleBlockTemplate(tbt));
 	}
 }
 
 /**
-	Enregistre la liste des categories repliees ainsi que le dernier element
-	selectionne
+	@param qtwi Un QTreeWidgetItem
+	@return L'ElementsCollectionItem represente par qtwi, ou 0 si qtwi ne
+	represente pas un ElementsCollectionItem
 */
-void ElementsPanel::saveExpandedCategories() {
-	expanded_directories.clear();
-	QList<QTreeWidgetItem *> items = findItems("*", Qt::MatchRecursive|Qt::MatchWildcard);
-	foreach(QTreeWidgetItem *item, items) {
-		QString file = locations_[item].toString();
-		if (!file.endsWith(".elmt") && item -> isExpanded()) {
-			expanded_directories << file;
-		}
+ElementsCollectionItem *ElementsPanel::collectionItemForItem(QTreeWidgetItem *qtwi) const {
+	if (qtwi && qtwi -> type() & QET::ElementsCollectionItem) {
+		ElementsLocation item_location = elementLocationForItem(qtwi);
+		return(QETApp::collectionItem(item_location));
 	}
-	
-	// sauvegarde egalement le dernier element selectionne
-	QTreeWidgetItem *current_item = currentItem();
-	if (current_item) last_selected_item = locations_[current_item].toString();
+	return(0);
 }
 
 /**
-	@param location emplacement a retrouver dans l'arborescence
-	@return le QTreeWidgetItem correspondant a l'emplacaement location ou 0 si celui-ci n'est pas trouve
+	Cette methode permet d'acceder a la categorie correspondant a un item donne.
+	Si cet item represente une collection, c'est sa categorie racine qui est renvoyee.
+	Si cet item represente une categorie, c'est cette categorie qui est renvoyee.
+	Si cet item represente un element, c'est sa categorie parente qui est renvoyee.
+	@param qtwi un QTreeWidgetItem
+	@return la categorie correspondant au QTreeWidgetItem qtwi, ou 0 s'il n'y a
+	aucune categorie correspondante.
 */
-QTreeWidgetItem *ElementsPanel::findLocation(const ElementsLocation &location) const {
-	if (location.isNull()) return(0);
-	return(locations_.key(location, 0));
-}
-
-/**
-	@param location emplacement a retrouver dans l'arborescence
-	@return le QTreeWidgetItem correspondant a l'emplacaement location ou 0 si celui-ci n'est pas trouve
-*/
-QTreeWidgetItem *ElementsPanel::findLocation(const QString &location) const {
-	return(findLocation(ElementsLocation(location)));
-}
-
-/**
-	Enleve et supprime un item du panel en nettoyant les structures le referencant.
-	Note : Ce nettoyage est recursif
-	@param removed_item Item a enlever et supprimer
-*/
-void ElementsPanel::deleteItem(QTreeWidgetItem *removed_item) {
-	if (!removed_item) return;
+ElementsCategory *ElementsPanel::categoryForItem(QTreeWidgetItem *qtwi) {
+	if (!qtwi) return(0);
 	
-	if (locations_.contains(removed_item)) {
-		locations_.remove(removed_item);
-	} else if (diagrams_.contains(removed_item)) {
-		diagrams_.remove(removed_item);
-	} else if (projects_.contains(removed_item)) {
-		projects_.remove(removed_item);
-	} else if (title_blocks_collections_.contains(removed_item)) {
-		title_blocks_collections_.remove(removed_item);
-	} else if (title_blocks_.contains(removed_item)) {
-		title_blocks_.remove(removed_item);
-	}
+	// Recupere le CollectionItem associe a cet item
+	ElementsCollectionItem *collection_item = collectionItemForItem(qtwi);
+	if (!collection_item) return(0);
 	
-	// supprime les eventuels enfants de l'item
-	foreach(QTreeWidgetItem *child_item, removed_item -> takeChildren()) {
-		deleteItem(child_item);
-	}
-	
-	delete removed_item;
+	// recupere la categorie cible pour le deplacement
+	return(collection_item -> toCategory());
 }
 
 /**
@@ -1087,70 +609,47 @@
 }
 
 /**
-	@param qtwi A QTreeWidgetItem, supposed to represent either a title block
-	@template or a title block templates collection. return the adequate title
-	@block template location
+	Hide items that do not match the provided string, ensure others are visible
+	along with their parent hierarchy. When ending the filtering, restore the tree
+	as it was before the filtering (except the current item) and scroll to the
+	currently selected item.
+	@param m String to be matched
+	@param filtering whether to begin/apply/end the filtering
+	@see QET::Filtering
 */
-TitleBlockTemplateLocation ElementsPanel::locationForTitleBlockTemplate(QTreeWidgetItem *qtwi) {
-	if (title_blocks_.contains(qtwi)) {
-		// the QTreeWidgetItem is a title block template
-		return(title_blocks_[qtwi]);
-	} else if (title_blocks_collections_.contains(qtwi)) {
-		return(title_blocks_collections_[qtwi] -> location());
+void ElementsPanel::filter(const QString &m, QET::Filtering filtering) {
+	QList<QTreeWidgetItem *> items = findItems("*", Qt::MatchRecursive | Qt::MatchWildcard);
+	const int expanded_role = 42; // magic number? So you consider Douglas Adams wrote about magic?
+	
+	if (filtering == QET::BeginFilter) {
+		foreach (QTreeWidgetItem *item, items) {
+			item -> setData(0, expanded_role, item -> isExpanded());
+		}
 	}
-	return(TitleBlockTemplateLocation());
-}
-
-/**
-	@param qtwi A QTreeWidgetItem, supposed to represent a title block template
-	@return the name of the given template, if applicable, 0 otherwise
-*/
-QString ElementsPanel::nameOfTitleBlockTemplate(QTreeWidgetItem *qtwi) {
-	if (title_blocks_.contains(qtwi)) {
-		return(title_blocks_[qtwi].name());
-	}
-	return(QString());
-}
-
-/**
-	Cette methode permet d'acceder a la categorie correspondant a un item donne.
-	Si cet item represente une collection, c'est sa categorie racine qui est renvoyee.
-	Si cet item represente une categorie, c'est cette categorie qui est renvoyee.
-	Si cet item represente un element, c'est sa categorie parente qui est renvoyee.
-	@param qtwi un QTreeWidgetItem
-	@return la categorie correspondant au QTreeWidgetItem qtwi, ou 0 s'il n'y a
-	aucune categorie correspondante.
-*/
-ElementsCategory *ElementsPanel::categoryForItem(QTreeWidgetItem *qtwi) {
-	if (!qtwi) return(0);
 	
-	// Recupere le CollectionItem associe a cet item
-	ElementsCollectionItem *collection_item = collectionItemForItem(qtwi);
-	if (!collection_item) return(0);
-	
-	// recupere la categorie cible pour le deplacement
-	return(collection_item -> toCategory());
-}
-
-/**
-	N'affiche que les elements contenant une chaine donnee
-	@param m Chaine a filtrer
-*/
-void ElementsPanel::filter(const QString &m) {
-	QList<QTreeWidgetItem *> items = findItems("*", Qt::MatchRecursive | Qt::MatchWildcard);
-	if (m.isEmpty()) {
-		// la chaine est vide : affiche tout
-		foreach(QTreeWidgetItem *item, items) item -> setHidden(false);
-	} else {
+	if (filtering != QET::EndFilter) {
 		// repere les items correspondant au filtre
 		QList<QTreeWidgetItem *> matching_items;
-		foreach(QTreeWidgetItem *item, items) {
+		foreach (QTreeWidgetItem *item, items) {
 			bool item_matches = item -> text(0).contains(m, Qt::CaseInsensitive);
 			if (item_matches) matching_items << item;
 			item -> setHidden(!item_matches);
 		}
-		
 		ensureHierarchyIsVisible(matching_items);
+	} else { // filtering == QET::EndFilter
+		QTreeWidgetItem *current_item = currentItem();
+		
+		// restore the tree as it was before the filtering
+		foreach (QTreeWidgetItem *qtwi, items) {
+			qtwi -> setHidden(false);
+			qtwi -> setExpanded(qtwi -> data(0, expanded_role).toBool());
+		}
+		
+		// avoid hiding the currently selected item
+		if (current_item) {
+			ensureHierarchyIsVisible(QList<QTreeWidgetItem *>() << current_item);
+			scrollToItem(current_item);
+		}
 	}
 }
 
@@ -1160,7 +659,7 @@
 */
 void ElementsPanel::projectWasOpened(QETProject *project) {
 	projects_to_display_ << project;
-	addProject(invisibleRootItem(), project);
+	addProject(project);
 }
 
 /**
@@ -1168,128 +667,19 @@
 	@param project Projet a enlever du panel
 */
 void ElementsPanel::projectWasClosed(QETProject *project) {
-	if (QTreeWidgetItem *item_to_remove = projects_.key(project, 0)) {
-		deleteItem(item_to_remove);
+	if (QTreeWidgetItem *item_to_remove = itemForProject(project)) {
+		GenericPanel::deleteItem(item_to_remove);
 		projects_to_display_.remove(project);
 	}
 }
 
 /**
-	Gere le fait que les proprietes d'un projet change (exemple : fichier,
-	titre, ...).
-	@param project Projet modifie
-*/
-void ElementsPanel::projectInformationsChanged(QETProject *project) {
-	updateProjectItemInformations(project);
-}
-
-/**
-	@param collection Title block templates collection that changed and should be updated
-	@param template_name Name of the changed template (unused)
-*/
-void ElementsPanel::titleBlockTemplatesCollectionChanged(TitleBlockTemplatesCollection*collection, const QString &template_name) {
-	Q_UNUSED(template_name)
-	
-	QTreeWidgetItem *qtwi_parent = title_blocks_collections_.key(collection);
-	if (!qtwi_parent) qtwi_parent = invisibleRootItem();
-	
-	addTitleBlockTemplatesCollection(qtwi_parent, collection);
-}
-
-/**
-	Gere l'ajout d'un schema dans un projet
-	@param project Projet auquel a ete ajouter le schema
-	@param diagram Schema ajoute
-*/
-void ElementsPanel::diagramWasAdded(QETProject *project, Diagram *diagram) {
-	// repere le QTWI du projet
-	if (QTreeWidgetItem *qtwi_project = projects_.key(project)) {
-		addDiagram(qtwi_project, diagram);
-	}
-}
-
-/**
-	Gere la suppression d'un schema dans un projet
-	@param project Projet duquel a ete supprime le schema
-	@param diagram Schema supprime
-*/
-void ElementsPanel::diagramWasRemoved(QETProject *project, Diagram *diagram) {
-	// on verifie que le projet apparait dans le panel
-	if (projects_.key(project, 0)) {
-		// on verifie que le schema apparait dans le panel
-		if (QTreeWidgetItem *item_to_remove = diagrams_.key(diagram, 0)) {
-			QTreeWidgetItem *parent_qtwi = item_to_remove -> parent();
-			
-			// we keep the index of the deleted item
-			int deleted_index = -1;
-			if (parent_qtwi) {
-				deleted_index = parent_qtwi -> indexOfChild(item_to_remove);
-			}
-			
-			// deletion itself
-			deleteItem(item_to_remove);
-			
-			// we also need to update the labels of following diagrams
-			// because they may display the folio index
-			if (deleted_index != -1) {
-				// -2 avoids the title blocks directory and the common collection
-				for (int i = deleted_index ; i < parent_qtwi -> childCount() - 2; ++i) {
-					updateDiagramLabel(parent_qtwi, i);
-				}
-			}
-		}
-	}
-}
-
-/**
-	@param project Projet auquel appartient le schema concerne
-	@param diagram schema dont le titre a change
-*/
-void ElementsPanel::diagramTitleChanged(QETProject *project, Diagram *diagram) {
-	// on verifie que le projet apparait dans le panel
-	if (projects_.key(project, 0)) {
-		// on verifie que le schema apparait dans le panel
-		if (QTreeWidgetItem *qtwi_diagram = diagrams_.key(diagram)) {
-			qtwi_diagram -> setText(0, diagramTitleToDisplay(diagram));
-		}
-	}
-}
-
-/**
-	@param project Projet auquel appartiennent les schemas concernes
-	@param from Index de l'onglet avant le deplacement
-	@param to   Index de l'onglet apres le deplacement
-*/
-void ElementsPanel::diagramOrderChanged(QETProject *project, int from, int to) {
-	// repere le QTWI correspondant au projet
-	QTreeWidgetItem *qtwi_project = projects_.key(project);
-	if (!qtwi_project) return;
-	
-	// repere le QTWI representant le schema deplace
-	QTreeWidgetItem *moved_qtwi_diagram = qtwi_project -> child(from);
-	if (!moved_qtwi_diagram) return;
-	
-	// enleve le QTWI et le reinsere au bon endroit
-	bool was_selected = moved_qtwi_diagram -> isSelected();
-	qtwi_project -> removeChild(moved_qtwi_diagram);
-	qtwi_project -> insertChild(to, moved_qtwi_diagram);
-	
-	// update the QTWI labels because they may display the folio index
-	updateDiagramLabel(qtwi_project, from);
-	updateDiagramLabel(qtwi_project, to);
-	
-	if (was_selected) {
-		setCurrentItem(moved_qtwi_diagram);
-	}
-}
-
-/**
 	Affiche un element etant donne son emplacement
 	@param location Emplacement de l'element a afficher
 */
 bool ElementsPanel::scrollToElement(const ElementsLocation &location) {
 	// recherche l'element dans le panel
-	QTreeWidgetItem *item = findLocation(location);
+	QTreeWidgetItem *item = itemForElementsLocation(location);
 	if (!item) return(false);
 	
 	// s'assure que l'item ne soit pas filtre
@@ -1301,119 +691,6 @@
 }
 
 /**
-	Met a jour le nom, l'info-bulle et l'icone de l'item representant un projet.
-	@param project le projet dont il faut mettre a jour l'affichage
-*/
-void ElementsPanel::updateProjectItemInformations(QETProject *project) {
-	// determine le QTWI correspondant au projet
-	QTreeWidgetItem *qtwi_project = projects_.key(project);
-	if (!qtwi_project) return;
-	
-	// determine le nom et l'icone du projet
-	QString final_name(project -> pathNameTitle());
-	QString final_tooltip = QDir::toNativeSeparators(project -> filePath());
-	if (final_tooltip.isEmpty()) {
-		final_tooltip = tr(
-			"Pas de fichier",
-			"tooltip for a file-less project in the element panel"
-		);
-	}
-	
-	qtwi_project -> setText(0, final_name);
-	qtwi_project -> setToolTip(0, final_tooltip);
-	qtwi_project -> setIcon(0, QET::Icons::Project);
-}
-
-/**
-	(Re)generates the templates list of a given project.
-	@param project the project we want to update the templates
-*/
-/*void ElementsPanel::updateProjectTemplates(QETProject *project) {
-	// determine the QTWI for the templates directory of the given project
-	QTreeWidgetItem *qtwi_project = projects_.key(project);
-	if (!qtwi_project) return;
-	
-	// determine the templates directory for the given project, if any
-	QTreeWidgetItem *titleblock_templates_qtwi = title_blocks_directories_.key(project);
-	if (!titleblock_templates_qtwi) {
-		// the poor thing does not exist... let's create it.
-		titleblock_templates_qtwi = new QTreeWidgetItem(qtwi_project, QStringList() << tr("Mod\350les de cartouche"));
-		titleblock_templates_qtwi -> setIcon(0, QET::Icons::Folder);
-		titleblock_templates_qtwi -> setExpanded(true);
-		title_blocks_directories_.insert(titleblock_templates_qtwi, project);
-	} else {
-		// oh, what a shiny templates directory... let's clear it.
-		foreach(QTreeWidgetItem *titleblock_template_qtwi, titleblock_templates_qtwi -> takeChildren()) {
-			deleteItem(titleblock_template_qtwi);
-		}
-	}
-	
-	// we can now populate the templates directory
-	TitleBlockTemplatesCollection *collection = project -> embeddedTitleBlockTemplatesCollection();
-	if (!collection) {
-		// this stinks...
-		return;
-	}
-	foreach (QString titleblock_name, collection -> templates()) {
-		QString final_name = titleBlockTemplateNameToDisplay(titleblock_name);
-		QTreeWidgetItem *titleblock_template_qtwi = new QTreeWidgetItem(titleblock_templates_qtwi, QStringList(final_name));
-		titleblock_template_qtwi -> setIcon(0, QET::Icons::TitleBlock);
-		titleblocks_.insert(titleblock_template_qtwi, collection -> location(titleblock_name));
-	}
-}*/
-
-/**
-	Updates the label of a diagram displayed by the elements panel
-	@param qtwi_project QTreeWidgetItem representing the diagram's parent project
-	@param diagram_index Index of the diagram within the parent project
-*/
-void ElementsPanel::updateDiagramLabel(QTreeWidgetItem *qtwi_project, int diagram_index) {
-	if (!qtwi_project) return;
-	
-	QTreeWidgetItem *qtwi_diagram = qtwi_project -> child(diagram_index);
-	if (!qtwi_diagram) return;
-	
-	Diagram *diagram = diagrams_[qtwi_diagram];
-	if (diagram) {
-		qtwi_diagram -> setText(0, diagramTitleToDisplay(diagram));
-	}
-}
-
-/**
-	@param diagram Schema dont on souhaite affiche le titre
-	@return Un titre affichable, tenant compte du fait que le titre du schema
-	peut etre vide.
-*/
-QString ElementsPanel::diagramTitleToDisplay(Diagram *diagram) const {
-	QString displayed_title = diagram -> title();
-	if (displayed_title.isEmpty()) {
-		displayed_title = tr("Sch\351ma sans titre", "Fallback label when a diagram has no title");
-	}
-	
-	QString displayed_label;
-	int diagram_folio_idx = diagram -> folioIndex();
-	if (diagram_folio_idx != -1) {
-		displayed_label = QString(
-			tr(
-				"%1 - %2",
-				"label displayed for a diagram in the panel ; %1 is the folio index, %2 is the diagram title"
-			)
-		).arg(diagram_folio_idx + 1).arg(displayed_title);
-	} else {
-		displayed_label = displayed_title;
-	}
-	return(displayed_label);
-}
-
-/**
-	@param template_name Name of a title block template
-	@return a displayable title
-*/
-QString ElementsPanel::titleBlockTemplateNameToDisplay(const QString &template_name) const {
-	return(tr("Mod\350le \"%1\"", "used to display a title block template").arg(template_name));
-}
-
-/**
 	@param items une liste de QTreeWidgetItem pour lesquels il faut s'assurer
 	que eux et leurs parents sont visibles
 */
@@ -1436,16 +713,3 @@
 		if (parent_qtwi -> isHidden()) parent_qtwi -> setHidden(false);
 	}
 }
-
-/**
-	Mark the provided QTreeWidgetItem as unused in its parent project.
-	@param qtwi A QTreeWidgetItem
-*/
-void ElementsPanel::markItemAsUnused(QTreeWidgetItem *qtwi) {
-	QLinearGradient t(0, 0, 200, 0);
-	t.setColorAt(0, QColor("#ffc0c0"));
-	t.setColorAt(1, QColor("#ffffff"));
-	qtwi -> setBackground(0, QBrush(t));
-	qtwi -> setToolTip(0, QString(tr("%1 [non utilis\351 dans le projet]")).arg(qtwi -> toolTip(0)));
-}
-

Modified: branches/0.3/sources/elementspanel.h
===================================================================
--- branches/0.3/sources/elementspanel.h	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/elementspanel.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -18,6 +18,7 @@
 #ifndef PANELAPPAREILS_H
 #define PANELAPPAREILS_H
 #include <QtGui>
+#include "genericpanel.h"
 #include "elementslocation.h"
 #include "templatelocation.h"
 class QETProject;
@@ -34,7 +35,7 @@
 	graphique) dans lequel l'utilisateur choisit les composants de
 	son choix et les depose sur le schema par drag'n drop.
 */
-class ElementsPanel : public QTreeWidget {
+class ElementsPanel : public GenericPanel {
 	Q_OBJECT
 	
 	// constructeurs, destructeur
@@ -45,53 +46,25 @@
 	private:
 	ElementsPanel(const ElementsPanel &);
 	
-	// methodes
+	// methods
 	public:
 	// methodes pour determiner ce que represente un item donne
-	bool itemIsACollection(QTreeWidgetItem *) const;
-	bool itemIsACategory(QTreeWidgetItem *) const;
-	bool itemIsAnElement(QTreeWidgetItem *) const;
-	bool itemIsAProject(QTreeWidgetItem *) const;
-	bool itemIsADiagram(QTreeWidgetItem *) const;
-	bool itemHasLocation(QTreeWidgetItem *) const;
 	bool itemIsWritable(QTreeWidgetItem *) const;
-	bool itemIsATitleBlockTemplatesCollection(QTreeWidgetItem *) const;
-	bool itemIsATitleBlockTemplate(QTreeWidgetItem *) const;
+	bool selectedItemIsWritable() const;
 	
 	// methodes pour obtenir ce que represente un item donne
 	ElementsCollectionItem *collectionItemForItem(QTreeWidgetItem *) const;
-	QETProject *projectForItem(QTreeWidgetItem *) const;
-	Diagram *diagramForItem(QTreeWidgetItem *) const;
-	ElementsLocation locationForItem(QTreeWidgetItem *) const;
+	ElementsCollectionItem *selectedItem() const;
 	ElementsCategory *categoryForItem(QTreeWidgetItem *);
 	ElementsCategory *categoryForPos(const QPoint &);
-	TitleBlockTemplateLocation locationForTitleBlockTemplate(QTreeWidgetItem *);
-	QString nameOfTitleBlockTemplate(QTreeWidgetItem *);
 	
-	// methodes pour determiner ce que represente l'item selectionne
-	bool selectedItemIsACollection() const;
-	bool selectedItemIsACategory() const;
-	bool selectedItemIsAnElement() const;
-	bool selectedItemIsAProject() const;
-	bool selectedItemIsADiagram() const;
-	bool selectedItemHasLocation() const;
-	bool selectedItemIsWritable() const;
-	bool selectedItemIsATitleBlockTemplatesDirectory() const;
-	bool selectedItemIsATitleBlockTemplate() const;
-	
-	// methodes pour obtenir ce que represente l'item selectionne
-	ElementsCollectionItem *selectedItem() const;
-	QETProject *selectedProject() const;
-	Diagram *selectedDiagram() const;
-	ElementsLocation selectedLocation() const;
-	
 	void reloadCollections();
 	int elementsCollectionItemsCount();
 	
 	signals:
 	void requestForProject(QETProject *);
 	void requestForDiagram(Diagram *);
-	void requestForCollectionItem(ElementsCollectionItem *);
+	void requestForCollectionItem(const ElementsLocation &);
 	void requestForMoveElements(ElementsCollectionItem *, ElementsCollectionItem *, QPoint);
 	void requestForTitleBlockTemplate(const TitleBlockTemplateLocation &);
 	void readingAboutToBegin();
@@ -101,15 +74,9 @@
 	public slots:
 	void slot_doubleClick(QTreeWidgetItem *, int);
 	void reload(bool = false);
-	void filter(const QString &);
+	void filter(const QString &, QET::Filtering = QET::RegularFilter);
 	void projectWasOpened(QETProject *);
 	void projectWasClosed(QETProject *);
-	void projectInformationsChanged(QETProject *);
-	void titleBlockTemplatesCollectionChanged(TitleBlockTemplatesCollection*, const QString & = QString());
-	void diagramWasAdded(QETProject *, Diagram *);
-	void diagramWasRemoved(QETProject *, Diagram *);
-	void diagramTitleChanged(QETProject *, Diagram *);
-	void diagramOrderChanged(QETProject *, int, int);
 	bool scrollToElement(const ElementsLocation &);
 	
 	protected:
@@ -119,43 +86,27 @@
 	void startDrag(Qt::DropActions);
 	void startElementDrag(const ElementsLocation &);
 	void startTitleBlockTemplateDrag(const TitleBlockTemplateLocation &);
-	bool event(QEvent *);
 	
+	protected slots:
+	void firstActivation();
+	
 	private:
-	QTreeWidgetItem *addProject   (QTreeWidgetItem *, QETProject         *);
-	QTreeWidgetItem *addDiagram   (QTreeWidgetItem *, Diagram            *);
-	QTreeWidgetItem *addCollection(QTreeWidgetItem *, ElementsCollection *, const QString & = QString(), const QIcon & = QIcon());
-	QTreeWidgetItem *addCategory  (QTreeWidgetItem *, ElementsCategory   *, const QString & = QString(), const QIcon & = QIcon());
-	QTreeWidgetItem *addElement   (QTreeWidgetItem *, ElementDefinition  *, const QString & = QString());
-	QTreeWidgetItem *addTitleBlockTemplatesCollection(QTreeWidgetItem *, TitleBlockTemplatesCollection *, const QString & = QString(), const QIcon & = QIcon());
-	void saveExpandedCategories();
-	QTreeWidgetItem *findLocation(const ElementsLocation &) const;
-	QTreeWidgetItem *findLocation(const QString &) const;
-	void deleteItem(QTreeWidgetItem *);
-	void updateProjectItemInformations(QETProject *);
-	void updateDiagramLabel(QTreeWidgetItem *, int);
-	QString diagramTitleToDisplay(Diagram *) const;
-	QString titleBlockTemplateNameToDisplay(const QString &) const;
+	QTreeWidgetItem *addProject   (QETProject *);
+	QTreeWidgetItem *addCollection(ElementsCollection *, const QString & = QString(), const QIcon & = QIcon());
+	QTreeWidgetItem *updateTemplateItem        (QTreeWidgetItem *, const TitleBlockTemplateLocation &,  PanelOptions, bool = false);
+	QTreeWidgetItem *updateElementsCategoryItem(QTreeWidgetItem *, ElementsCategory *,  PanelOptions, bool = false);
+	QTreeWidgetItem *updateElementItem         (QTreeWidgetItem *, ElementDefinition *, PanelOptions, bool = false);
+	
 	void ensureHierarchyIsVisible(QList<QTreeWidgetItem *>);
-	void markItemAsUnused(QTreeWidgetItem *);
 	
-	// attributs
+	// attributes
 	private:
-	QStringList expanded_directories;
-	QString last_selected_item;
-	QHash<QTreeWidgetItem *, ElementsLocation> locations_;
-	QHash<QTreeWidgetItem *, TitleBlockTemplateLocation> title_blocks_;
-	QSet<QETProject *> projects_to_display_;
-	QHash<QTreeWidgetItem *, QETProject *> projects_;
-	QHash<QTreeWidgetItem *, Diagram *> diagrams_;
-	QHash<QTreeWidgetItem *, TitleBlockTemplatesCollection *> title_blocks_collections_;
-	QTreeWidgetItem *common_collection_item_;
-	QTreeWidgetItem *common_tbt_collection_item_;
-	QTreeWidgetItem *custom_collection_item_;
-	QTreeWidgetItem *custom_tbt_collection_item_;
-	int loading_progress_;
-	bool first_activation_;
-	bool first_reload_;
-	ElementsCollectionCache *cache_;
+	QSet<QETProject *> projects_to_display_;       ///< list of projects that have been added to this panel
+	QTreeWidgetItem *common_collection_item_;      ///< pointer to the item representing the common elements collection
+	QTreeWidgetItem *common_tbt_collection_item_;  ///< pointer to the item representing the common templates collection
+	QTreeWidgetItem *custom_collection_item_;      ///< pointer to the item representing the user elements collection
+	QTreeWidgetItem *custom_tbt_collection_item_;  ///< pointer to the item representing the user templates collection
+	int loading_progress_;                         ///< used to track the loading progress of elements collections
+	bool first_reload_;                            ///< used to distinguish the first time this panel is reloaded
 };
 #endif

Modified: branches/0.3/sources/elementspanelwidget.cpp
===================================================================
--- branches/0.3/sources/elementspanelwidget.cpp	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/elementspanelwidget.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -117,11 +117,11 @@
 	connect(copy_elements_,        SIGNAL(triggered()), this,           SLOT(copyElements()));
 	
 	connect(erase_textfield,       SIGNAL(triggered()),                 this,             SLOT(clearFilterTextField()));
-	connect(filter_textfield,      SIGNAL(textEdited(const QString &)), elements_panel,   SLOT(filter(const QString &)));
+	connect(filter_textfield,      SIGNAL(textEdited(const QString &)), this,             SLOT(filterEdited(const QString &)));
 	
 	connect(elements_panel,        SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), this, SLOT(updateButtons()));
 	connect(elements_panel,        SIGNAL(customContextMenuRequested(const QPoint &)),               this, SLOT(handleContextMenu(const QPoint &)));
-	connect(elements_panel,        SIGNAL(requestForCollectionItem(ElementsCollectionItem *)),       this, SLOT(handleCollectionRequest(ElementsCollectionItem *)));
+	connect(elements_panel,        SIGNAL(requestForCollectionItem(const ElementsLocation &)),       this, SLOT(handleCollectionRequest(const ElementsLocation &)));
 	connect(
 		elements_panel,
 		SIGNAL(requestForMoveElements(ElementsCollectionItem *, ElementsCollectionItem *, QPoint)),
@@ -179,7 +179,7 @@
 void ElementsPanelWidget::clearFilterTextField() {
 	filter_textfield -> clear();
 	filter_textfield -> setFocus();
-	elements_panel -> filter(QString());
+	filterEdited(QString());
 }
 
 /**
@@ -263,9 +263,10 @@
 	QTreeWidgetItem *current_item = elements_panel -> currentItem();
 	if (!current_item) return;
 	
-	if (elements_panel -> itemIsATitleBlockTemplatesCollection(current_item)) {
-		TitleBlockTemplateLocation location = elements_panel -> locationForTitleBlockTemplate(current_item);
-		QETApp::instance() -> openTitleBlockTemplate(location);
+	if (current_item -> type() == QET::TitleBlockTemplatesCollection) {
+		QETApp::instance() -> openTitleBlockTemplate(
+			elements_panel -> templateLocationForItem(current_item)
+		);
 	}
 }
 
@@ -274,8 +275,10 @@
 */
 void ElementsPanelWidget::editTitleBlockTemplate() {
 	QTreeWidgetItem *current_item = elements_panel -> currentItem();
-	if (current_item && elements_panel -> itemIsATitleBlockTemplate(current_item)) {
-		QETApp::instance() -> openTitleBlockTemplate(elements_panel -> locationForTitleBlockTemplate(current_item));
+	if (current_item && current_item -> type() == QET::TitleBlockTemplate) {
+		QETApp::instance() -> openTitleBlockTemplate(
+			elements_panel -> templateLocationForItem(current_item)
+		);
 	}
 }
 
@@ -284,9 +287,9 @@
 */
 void ElementsPanelWidget::removeTitleBlockTemplate() {
 	QTreeWidgetItem *current_item = elements_panel -> currentItem();
-	if (current_item && elements_panel -> itemIsATitleBlockTemplate(current_item)) {
+	if (current_item && current_item -> type() == QET::TitleBlockTemplate) {
 		TitleBlockTemplateDeleter(
-			elements_panel -> locationForTitleBlockTemplate(current_item),
+			elements_panel -> templateLocationForItem(current_item),
 			this
 		).exec();
 	}
@@ -342,10 +345,13 @@
 	Met a jour les boutons afin d'assurer la coherence de l'interface
 */
 void ElementsPanelWidget::updateButtons() {
-	bool collection_selected = elements_panel -> selectedItemIsACollection();
-	bool category_selected = collection_selected || elements_panel -> selectedItemIsACategory();
-	bool element_selected = elements_panel -> selectedItemIsAnElement();
+	QTreeWidgetItem *current_item = elements_panel -> currentItem();
+	int current_type = elements_panel -> currentItemType();
 	
+	bool collection_selected = current_type == QET::ElementsCollection;
+	bool category_selected   = current_type & QET::ElementsContainer;
+	bool element_selected    = current_type == QET::Element;
+	
 	if (collection_selected || category_selected || element_selected) {
 		bool element_writable = elements_panel -> selectedItemIsWritable();
 		delete_collection -> setEnabled(collection_selected && element_writable);
@@ -355,11 +361,11 @@
 		new_element       -> setEnabled(category_selected && element_writable);
 		edit_element      -> setEnabled(element_selected);
 		delete_element    -> setEnabled(element_selected && element_writable);
-	} else if (elements_panel -> selectedItemIsAProject()) {
+	} else if (current_type == QET::Project) {
 		bool is_writable = !(elements_panel -> selectedProject() -> isReadOnly());
 		prj_add_diagram -> setEnabled(is_writable);
 		setElementsActionEnabled(false);
-	} else if (elements_panel -> selectedItemIsADiagram()) {
+	} else if (current_type == QET::Diagram) {
 		Diagram    *selected_diagram         = elements_panel -> selectedDiagram();
 		QETProject *selected_diagram_project = selected_diagram -> project();
 		
@@ -371,16 +377,15 @@
 		prj_move_diagram_up   -> setEnabled(is_writable && diagram_position > 0);
 		prj_move_diagram_down -> setEnabled(is_writable && diagram_position < project_diagrams_count - 1);
 		setElementsActionEnabled(false);
-	} else if (elements_panel -> selectedItemIsATitleBlockTemplatesDirectory()) {
-		QTreeWidgetItem *item = elements_panel -> currentItem();
-		TitleBlockTemplateLocation location = elements_panel -> locationForTitleBlockTemplate(item);
+	} else if (current_type == QET::TitleBlockTemplatesCollection) {
+		TitleBlockTemplateLocation location = elements_panel -> templateLocationForItem(current_item);
 		tbt_add    -> setEnabled(!location.isReadOnly());
 		tbt_edit   -> setEnabled(false); // would not make sense
 		tbt_remove -> setEnabled(false); // would not make sense
 		setElementsActionEnabled(false);
-	} else if (elements_panel -> selectedItemIsATitleBlockTemplate()) {
+	} else if (current_type == QET::TitleBlockTemplate) {
 		QTreeWidgetItem *item = elements_panel -> currentItem();
-		TitleBlockTemplateLocation location = elements_panel -> locationForTitleBlockTemplate(item);
+		TitleBlockTemplateLocation location = elements_panel -> templateLocationForItem(item);
 		tbt_add    -> setEnabled(false); // would not make sense
 		tbt_edit   -> setEnabled(true); // the tbt editor has a read-only mode
 		// deleting a tbt requires its parent collection to be writable
@@ -441,42 +446,40 @@
 	updateButtons();
 	context_menu -> clear();
 	
-	if (elements_panel -> itemHasLocation(item)) {
-		// recupere l'emplacement associe a l'item
-		ElementsCollectionItem *selected_item = elements_panel -> collectionItemForItem(item);
-		
-		if (selected_item) {
-			if (selected_item -> isCategory()) {
-				context_menu -> addAction(new_category);
-				context_menu -> addAction(edit_category);
-				context_menu -> addAction(delete_category);
-				context_menu -> addAction(new_element);
-			} else if (selected_item -> isElement()) {
-				context_menu -> addAction(edit_element);
-				context_menu -> addAction(delete_element);
-			} else if (selected_item -> isCollection()) {
-				// categorie racine / collection
-				context_menu -> addAction(new_category);
-				context_menu -> addAction(delete_collection);
-				context_menu -> addAction(new_element);
-			}
-		}
-	} else {
-		if (elements_panel -> itemIsAProject(item)) {
+	switch(item -> type()) {
+		case QET::ElementsCategory:
+			context_menu -> addAction(new_category);
+			context_menu -> addAction(edit_category);
+			context_menu -> addAction(delete_category);
+			context_menu -> addAction(new_element);
+			break;
+		case QET::Element:
+			context_menu -> addAction(edit_element);
+			context_menu -> addAction(delete_element);
+			break;
+		case QET::ElementsCollection:
+			context_menu -> addAction(new_category);
+			context_menu -> addAction(delete_collection);
+			context_menu -> addAction(new_element);
+			break;
+		case QET::Project:
 			context_menu -> addAction(prj_edit_prop);
 			context_menu -> addAction(prj_add_diagram);
 			context_menu -> addAction(prj_close);
-		} else if (elements_panel -> itemIsADiagram(item)) {
+			break;
+		case QET::Diagram:
 			context_menu -> addAction(prj_prop_diagram);
 			context_menu -> addAction(prj_del_diagram);
 			context_menu -> addAction(prj_move_diagram_up);
 			context_menu -> addAction(prj_move_diagram_down);
-		} else if (elements_panel -> itemIsATitleBlockTemplatesCollection(item)) {
+			break;
+		case QET::TitleBlockTemplatesCollection:
 			context_menu -> addAction(tbt_add);
-		} else if (elements_panel -> itemIsATitleBlockTemplate(item)) {
+			break;
+		case QET::TitleBlockTemplate:
 			context_menu -> addAction(tbt_edit);
 			context_menu -> addAction(tbt_remove);
-		}
+			break;
 	}
 	
 	// affiche le menu
@@ -489,7 +492,9 @@
 	Gere les demandes d'edition de categories ou d'elements
 	@param item Item de la collection a editer
 */
-void ElementsPanelWidget::handleCollectionRequest(ElementsCollectionItem *item) {
+void ElementsPanelWidget::handleCollectionRequest(const ElementsLocation &item_location) {
+	if (item_location.isNull()) return;
+	ElementsCollectionItem *item = QETApp::collectionItem(item_location);
 	if (!item) return;
 	if (item -> isElement()) {
 		// il s'agit d'un element
@@ -601,6 +606,20 @@
 	progress_bar_ -> setValue(current);
 }
 
+void ElementsPanelWidget::filterEdited(const QString &next_text) {
+	if (previous_filter_.isEmpty() && next_text.length() == 1) {
+		// the field is not empty anymore: begin filtering
+		elements_panel -> filter(next_text, QET::BeginFilter);
+	} else if (!previous_filter_.isEmpty() && next_text.isEmpty()) {
+		// the field is now empty again: end of filtering
+		elements_panel -> filter(QString(), QET::EndFilter);
+	} else {
+		// regular filtering
+		elements_panel -> filter(next_text, QET::RegularFilter);
+	}
+	previous_filter_ = next_text;
+}
+
 /**
 	Copie l'item src dans l'item dst
 */
@@ -686,7 +705,10 @@
 	if (!selected_qtwi) return(0);
 	
 	// l'element selectionne doit pouvoir correspondre a une categorie
-	ElementsCategory *selected_category = elements_panel -> categoryForItem(selected_qtwi);
+	if (!(selected_qtwi -> type() & QET::ElementsContainer)) return(0);
+	ElementsLocation category_location = elements_panel -> elementLocationForItem(selected_qtwi);
+	ElementsCollectionItem *category = QETApp::collectionItem(category_location, false);
+	ElementsCategory *selected_category = category -> toCategory();
 	if (!selected_category) return(0);
 	
 	// la categorie doit etre accessible en ecriture

Modified: branches/0.3/sources/elementspanelwidget.h
===================================================================
--- branches/0.3/sources/elementspanelwidget.h	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/elementspanelwidget.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -88,7 +88,7 @@
 	void setElementsActionEnabled(bool);
 	int  launchCategoriesManager();
 	void handleContextMenu(const QPoint &);
-	void handleCollectionRequest(ElementsCollectionItem *);
+	void handleCollectionRequest(const ElementsLocation &);
 	void handleMoveElementsRequest(ElementsCollectionItem *, ElementsCollectionItem *, const QPoint & = QPoint());
 	void moveElements();
 	void moveElements(ElementsCollectionItem *, ElementsCollectionItem *);
@@ -97,11 +97,13 @@
 	void collectionsRead();
 	void collectionsReadFinished();
 	void updateProgressBar(int, int);
+	void filterEdited(const QString &);
 	
 	private:
 	void launchElementEditor(const ElementsLocation &);
 	void launchCategoryEditor(const ElementsLocation &);
 	ElementsCategory *writableSelectedCategory();
+	QString previous_filter_;
 };
 
 /**

Added: branches/0.3/sources/genericpanel.cpp
===================================================================
--- branches/0.3/sources/genericpanel.cpp	                        (rev 0)
+++ branches/0.3/sources/genericpanel.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -0,0 +1,1045 @@
+#include "genericpanel.h"
+#include <QTreeWidgetItem>
+#include "qetproject.h"
+#include "diagram.h"
+#include "elementscollection.h"
+#include "elementscategory.h"
+#include "elementdefinition.h"
+#include "titleblock/templatescollection.h"
+#include "titleblock/templatelocation.h"
+#include "elementslocation.h"
+#include "qeticons.h"
+#include "elementscollectioncache.h"
+
+/**
+	Constructor
+	@param parent Parent QWidget
+*/
+GenericPanel::GenericPanel(QWidget *parent) :
+	QTreeWidget(parent),
+	cache_(0),
+	first_activation_(true)
+{
+	header() -> hide();
+	setIconSize(QSize(50, 50));
+}
+
+/**
+	Destructor
+*/
+GenericPanel::~GenericPanel() {
+}
+
+/**
+	@return the elements cache currently used, or 0 if none has been set.
+*/
+ElementsCollectionCache *GenericPanel::elementsCache() {
+	return(cache_);
+}
+
+/**
+	@return the elements cache to be used to render elements collection. If no
+	cache has been explicitly set using setElementsCache(), this method builds
+	a basic cache named "genericpanel.sqlite" in the current working directory.
+*/
+ElementsCollectionCache *GenericPanel::getElementsCache() {
+	if (!cache_) {
+		// build a default cache
+		QString cache_path = "./genericpanel.sqlite";
+		cache_ = new ElementsCollectionCache(cache_path, this);
+		/// @todo we need a unique function to get the good language
+		cache_ -> setLocale(QLocale::system().name().left(2));
+	}
+	return(cache_);
+}
+
+/**
+	@return the type of the current item
+*/
+int GenericPanel::currentItemType() {
+	QTreeWidgetItem *current_qtwi = currentItem();
+	if (!current_qtwi) return(0);
+	return(current_qtwi -> type());
+}
+
+QETProject *GenericPanel::projectForItem(QTreeWidgetItem *item) const {
+	if (item && item -> type() == QET::Project) {
+		return(valueForItem<QETProject *>(item));
+	}
+	return(0);
+	
+}
+
+/**
+	
+*/
+Diagram *GenericPanel::diagramForItem(QTreeWidgetItem *item) const {
+	if (item && item -> type() == QET::Diagram) {
+		return(valueForItem<Diagram *>(item));
+	}
+	return(0);
+}
+
+/**
+	
+*/
+TitleBlockTemplateLocation GenericPanel::templateLocationForItem(QTreeWidgetItem *item) const {
+	if (item && item -> type() & QET::TitleBlockTemplatesCollectionItem) {
+		return(valueForItem<TitleBlockTemplateLocation>(item));
+	}
+	return(TitleBlockTemplateLocation());
+}
+
+/**
+	
+*/
+ElementsLocation GenericPanel::elementLocationForItem(QTreeWidgetItem *item) const {
+	if (item && item -> type() & QET::ElementsCollectionItem) {
+		return(valueForItem<ElementsLocation>(item));
+	}
+	return(ElementsLocation());
+}
+
+/**
+	
+*/
+QETProject *GenericPanel::selectedProject() const {
+	return(projectForItem(currentItem()));
+}
+
+/**
+	
+*/
+Diagram *GenericPanel::selectedDiagram() const {
+	return(diagramForItem(currentItem()));
+}
+
+/**
+	
+*/
+TitleBlockTemplateLocation GenericPanel::selectedTemplateLocation() const {
+	return(templateLocationForItem(currentItem()));
+}
+
+/**
+	
+*/
+ElementsLocation GenericPanel::selectedElementLocation() const {
+	return(elementLocationForItem(currentItem()));
+}
+
+/**
+	@param cache New cache to be used to render elements.
+	@param previous if non-zero, this pointer will be set to the previously used cache
+	@return true if the cache was changed, false otherwise (it may happen if the
+	provided cache is already the one being used).
+*/
+bool GenericPanel::setElementsCache(ElementsCollectionCache *cache, ElementsCollectionCache **previous) {
+	if (cache == cache_) return(false);
+	if (previous) {
+		*previous = cache_;
+	}
+	cache_ = cache;
+	return(true);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::addProject(QETProject *project, QTreeWidgetItem *parent_item, PanelOptions options) {
+	if (!project) return(0);
+	bool creation_required;
+	
+	QTreeWidgetItem *project_qtwi = getItemForProject(project, &creation_required);
+	updateProjectItem(project_qtwi, project, options, creation_required);
+	reparent(project_qtwi, parent_item);
+	fillProjectItem(project_qtwi, project, options, creation_required);
+	
+	return(project_qtwi);
+}
+
+/**
+	@param project A standard project.
+	@return the tree item representing the provided project or 0 if this
+	project does not appear within this panel.
+*/
+QTreeWidgetItem *GenericPanel::itemForProject(QETProject *project) {
+	if (!project) return(0);
+	return(projects_.value(project, 0));
+}
+
+/**
+	@param project A standard project.
+	@param created if provided with a pointer to a boolean, this method will
+	update it to reflect whether the returned item has been freshly created or
+	not.
+	@return the tree item representing the provided project. If it does not
+	appear within this panel, it is created.
+*/
+QTreeWidgetItem *GenericPanel::getItemForProject(QETProject *project, bool *created) {
+	if (!project) return(0);
+	
+	QTreeWidgetItem *project_qtwi = projects_.value(project, 0);
+	if (project_qtwi) {
+		if (created) *created = false;
+		return(project_qtwi);
+	}
+	
+	project_qtwi = makeItem(QET::Project);
+	if (created) *created = true;
+	return(project_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::updateProjectItem(QTreeWidgetItem *project_qtwi, QETProject *project, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(options)
+	if (!project_qtwi || !project) return(0);
+	
+	if (freshly_created) {
+		project_qtwi -> setData(0, GenericPanel::Item, qVariantFromValue(project));
+		projects_.insert(project, project_qtwi);
+		
+		connect(
+			project, SIGNAL(projectInformationsChanged(QETProject *)),
+			this,    SLOT  (projectInformationsChanged(QETProject *))
+		);
+		connect(
+			project, SIGNAL(readOnlyChanged(QETProject *, bool)),
+			this,    SLOT  (projectInformationsChanged(QETProject *))
+		);
+	}
+	
+	// text
+	project_qtwi -> setText(0, project -> pathNameTitle());
+	// tooltip
+	QString final_tooltip = QDir::toNativeSeparators(project -> filePath());
+	if (final_tooltip.isEmpty()) {
+		final_tooltip = tr(
+			"Pas de fichier",
+			"tooltip for a file-less project in the element panel"
+		);
+	}
+	project_qtwi -> setToolTip(0, final_tooltip);
+	return(project_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::fillProjectItem(QTreeWidgetItem *project_qtwi, QETProject *project, PanelOptions options, bool freshly_created) {
+	if (!project_qtwi || !project) return(0);
+	
+	
+	if (options & AddChildDiagrams) {
+		if (freshly_created) {
+			connect(
+				project, SIGNAL(diagramAdded(QETProject *, Diagram *)),
+				this,    SLOT  (diagramAdded(QETProject *, Diagram *))
+			);
+			connect(
+				project, SIGNAL(diagramRemoved(QETProject *, Diagram *)),
+				this,    SLOT  (diagramRemoved(QETProject *, Diagram *))
+			);
+			connect(
+				project, SIGNAL(projectDiagramsOrderChanged(QETProject *, int, int)),
+				this,    SLOT  (projectDiagramsOrderChanged(QETProject *, int, int))
+			);
+		} else {
+			// remove diagrams unknown to the project (presumably removed)
+			removeObsoleteItems(project -> diagrams(), project_qtwi, QET::Diagram, false);
+		}
+		int index = 0;
+		foreach (Diagram *diagram, project -> diagrams()) {
+			QTreeWidgetItem *diagram_qtwi = addDiagram(diagram, 0, options);
+			project_qtwi -> insertChild(index, diagram_qtwi);
+			++ index;
+		}
+	}
+	
+	if (options & AddChildTemplatesCollection) {
+		if (freshly_created) {
+			connect(
+				project, SIGNAL(diagramUsedTemplate(TitleBlockTemplatesCollection *, const QString &)),
+				this,    SLOT  (diagramUsedTemplate(TitleBlockTemplatesCollection *, const QString &))
+			);
+		}
+		addTemplatesCollection(
+			project -> embeddedTitleBlockTemplatesCollection(),
+			project_qtwi,
+			options
+		);
+	}
+	
+	if (options & AddChildElementsCollections) {
+		addElementsCollection(
+			project -> embeddedCollection(),
+			project_qtwi,
+			options,
+			tr("Collection projet")
+		);
+	}
+	return(project_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::addDiagram(Diagram *diagram, QTreeWidgetItem *parent_item, PanelOptions options) {
+	Q_UNUSED(options)
+	if (!diagram) return(0);
+	
+	bool creation_required;
+	
+	QTreeWidgetItem *diagram_qtwi = getItemForDiagram(diagram, &creation_required);
+	updateDiagramItem(diagram_qtwi, diagram, options, creation_required);
+	reparent(diagram_qtwi, parent_item);
+	fillDiagramItem(diagram_qtwi, diagram, options, creation_required);
+	
+	return(diagram_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::itemForDiagram(Diagram *diagram) {
+	if (!diagram) return(0);
+	return(diagrams_.value(diagram, 0));
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::getItemForDiagram(Diagram *diagram, bool *created) {
+	if (!diagram) return(0);
+	
+	QTreeWidgetItem *diagram_qtwi = diagrams_.value(diagram, 0);
+	if (diagram_qtwi) {
+		if (created) *created = false;
+		return(diagram_qtwi);
+	}
+	
+	diagram_qtwi = makeItem(QET::Diagram);
+	if (created) *created = true;
+	return(diagram_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::updateDiagramItem(QTreeWidgetItem *diagram_qtwi, Diagram *diagram, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(options)
+	if (!diagram || !diagram_qtwi) return(0);
+	
+	QString displayed_title = diagram -> title();
+	if (displayed_title.isEmpty()) {
+		displayed_title = tr("Sch\351ma sans titre", "Fallback label when a diagram has no title");
+	}
+	
+	QString displayed_label;
+	int diagram_folio_idx = diagram -> folioIndex();
+	if (diagram_folio_idx != -1) {
+		displayed_label = QString(
+			tr(
+				"%1 - %2",
+				"label displayed for a diagram in the panel ; %1 is the folio index, %2 is the diagram title"
+			)
+		).arg(diagram_folio_idx + 1).arg(displayed_title);
+	} else {
+		displayed_label = displayed_title;
+	}
+	
+	
+	diagram_qtwi -> setText(0, displayed_label);
+	if (freshly_created) {
+		diagram_qtwi -> setData(0, GenericPanel::Item, qVariantFromValue(diagram));
+		diagrams_.insert(diagram, diagram_qtwi);
+		
+		connect(
+			diagram, SIGNAL(diagramTitleChanged(Diagram *, const QString &)),
+			this,    SLOT  (diagramTitleChanged(Diagram *, const QString &))
+		);
+	}
+	
+	return(diagram_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::fillDiagramItem(QTreeWidgetItem *diagram_qtwi, Diagram *diagram, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(diagram)
+	Q_UNUSED(options)
+	Q_UNUSED(freshly_created)
+	return(diagram_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::addTemplatesCollection(TitleBlockTemplatesCollection *tbt_collection, QTreeWidgetItem *parent_item, PanelOptions options) {
+	if (!tbt_collection) return(0);
+	bool creation_required;
+	
+	QTreeWidgetItem *tbt_collection_qtwi = getItemForTemplatesCollection(tbt_collection, &creation_required);
+	updateTemplatesCollectionItem(tbt_collection_qtwi, tbt_collection, options, creation_required);
+	reparent(tbt_collection_qtwi, parent_item);
+	fillTemplatesCollectionItem(tbt_collection_qtwi, tbt_collection, options, creation_required);
+	
+	return(tbt_collection_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::itemForTemplatesCollection(TitleBlockTemplatesCollection *tbt_collection) {
+	if (!tbt_collection) return(0);
+	return(tb_templates_.value(tbt_collection -> location(), 0));
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::getItemForTemplatesCollection(TitleBlockTemplatesCollection *tbt_collection, bool *created) {
+	if (!tbt_collection) return(0);
+	QTreeWidgetItem *tbt_collection_item = tb_templates_.value(tbt_collection -> location(), 0);
+	if (tbt_collection_item) {
+		if (created) *created = false;
+		return(tbt_collection_item);
+	}
+	
+	tbt_collection_item = makeItem(QET::TitleBlockTemplatesCollection);
+	if (created) *created = true;
+	return(tbt_collection_item);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::updateTemplatesCollectionItem(QTreeWidgetItem *tbt_collection_qtwi, TitleBlockTemplatesCollection *tbt_collection, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(options)
+	QString label = tbt_collection -> title();
+	if (label.isEmpty()) label = tr("Mod\350les de cartouche");
+	
+	tbt_collection_qtwi -> setText(0, label);
+	tbt_collection_qtwi -> setToolTip(0, tbt_collection -> location().toString());
+	
+	if (freshly_created) {
+		tbt_collection_qtwi -> setData(0, GenericPanel::Item, qVariantFromValue(tbt_collection -> location()));
+		tb_templates_.insert(tbt_collection -> location(), tbt_collection_qtwi);
+	}
+	
+	return(tbt_collection_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::fillTemplatesCollectionItem(QTreeWidgetItem *tbt_collection_qtwi, TitleBlockTemplatesCollection *tbt_collection, PanelOptions options, bool freshly_created) {
+	if (!tbt_collection_qtwi || !tbt_collection) return(tbt_collection_qtwi);
+	
+	if (options & AddChildTemplates) {
+		if (freshly_created) {
+			connect(
+				tbt_collection, SIGNAL(changed(TitleBlockTemplatesCollection*,QString)),
+				this, SLOT(templatesCollectionChanged(TitleBlockTemplatesCollection*, const QString &))
+			);
+			if (QETProject *project = tbt_collection -> parentProject()) {
+				connect(
+					project, SIGNAL(diagramUsedTemplate(TitleBlockTemplatesCollection *, const QString &)),
+					this,    SLOT  (templatesCollectionChanged(TitleBlockTemplatesCollection *, const QString &))
+				);
+			}
+		} else {
+			// remove templates unknown to the collection (presumably removed)
+			removeObsoleteItems(tbt_collection -> templatesLocations(), tbt_collection_qtwi, QET::TitleBlockTemplate, false);
+		}
+		
+		int index = 0;
+		foreach (QString template_name, tbt_collection -> templates()) {
+			QTreeWidgetItem *template_item = addTemplate(tbt_collection -> location(template_name), 0, options);
+			tbt_collection_qtwi -> insertChild(index ++, template_item);
+		}
+	}
+	
+	return(tbt_collection_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::addTemplate(const TitleBlockTemplateLocation &tb_template, QTreeWidgetItem *parent_item, PanelOptions options) {
+	if (!tb_template.isValid()) return(0);
+	bool creation_required;
+	
+	QTreeWidgetItem *tb_template_qtwi = getItemForTemplate(tb_template, &creation_required);
+	updateTemplateItem(tb_template_qtwi, tb_template, options, creation_required);
+	reparent(tb_template_qtwi, parent_item);
+	fillTemplateItem(tb_template_qtwi, tb_template, options, creation_required);
+	
+	return(tb_template_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::itemForTemplate(const TitleBlockTemplateLocation &tb_template) {
+	return(tb_templates_.value(tb_template, 0));
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::getItemForTemplate(const TitleBlockTemplateLocation &tb_template, bool *created) {
+	if (!tb_template.isValid()) return(0);
+	
+	QTreeWidgetItem *tb_template_qtwi = tb_templates_.value(tb_template, 0);
+	if (tb_template_qtwi) {
+		if (created) *created = false;
+		return(tb_template_qtwi);
+	}
+	
+	tb_template_qtwi = makeItem(QET::TitleBlockTemplate);
+	if (created) *created = true;
+	return(tb_template_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::updateTemplateItem(QTreeWidgetItem *tb_template_qtwi, const TitleBlockTemplateLocation &tb_template, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(options)
+	tb_template_qtwi -> setText(0, tr("Mod\350le \"%1\"", "used to display a title block template").arg(tb_template.name()));
+	// note the following lines are technically marking the template as used
+	tb_template_qtwi -> setToolTip(0, tb_template.toString());
+	tb_template_qtwi -> setBackground(0, QBrush());
+	
+	// special action for templates that belong to a project
+	if (QETProject *tbt_project = tb_template.parentProject()) {
+		// display unused templates using a red background
+		if (!tbt_project -> usesTitleBlockTemplate(tb_template)) {
+			markItemAsUnused(tb_template_qtwi);
+		}
+	}
+	
+	if (freshly_created) {
+		tb_template_qtwi -> setData(0, GenericPanel::Item, qVariantFromValue(tb_template));
+		tb_templates_.insert(tb_template, tb_template_qtwi);
+	}
+	return(tb_template_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::fillTemplateItem(QTreeWidgetItem *tb_template_qtwi, const TitleBlockTemplateLocation &tb_template, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(tb_template)
+	Q_UNUSED(options)
+	Q_UNUSED(freshly_created)
+	return(tb_template_qtwi);
+}
+
+/**
+	Add an elements category to the panel.
+	@param parent_item Parent for the created QTreeWidgetItem
+	@param collection Collection to be added to the panel
+	@param label Name displayed by the created QTreeWidgetItem
+	@param icon Icon displayed by the created QTreeWidgetItem
+	@param options Control the creation of child items
+	@return the created QTreeWidgetItem
+*/
+QTreeWidgetItem *GenericPanel::addElementsCollection(ElementsCollection *collection, QTreeWidgetItem *parent_item, PanelOptions options, const QString &label, const QIcon &icon) {
+	if (!collection) return(0);
+	
+	// use the cache from the provided collection, if any
+	bool restore_previous_cache = false;
+	ElementsCollectionCache *previous_cache = 0;
+	ElementsCollectionCache *collection_cache = collection -> cache();
+	if (collection_cache) {
+		restore_previous_cache = setElementsCache(collection_cache, &previous_cache);
+	}
+	
+	ElementsCollectionCache *cache = getElementsCache();
+	cache -> beginCollection(collection);
+	QTreeWidgetItem *collection_qtwi = addElementsCategory(collection -> rootCategory(), parent_item, options);
+	cache -> endCollection(collection);
+	if (!label.isEmpty()) collection_qtwi -> setText(0, label);
+	if (!icon.isNull()) collection_qtwi -> setIcon(0, icon);
+	
+	// restore the former cache
+	if (restore_previous_cache) {
+		setElementsCache(previous_cache);
+	}
+	
+	return(collection_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::itemForElementsLocation(const ElementsLocation &location) {
+	return(elements_.value(location, 0));
+}
+
+/**
+	Add an elements category to the panel.
+	@param category Category to be added to the panel
+	@param parent_item Parent for the created QTreeWidgetItem
+	@param options Control the creation of child items
+	@return the created QTreeWidgetItem
+*/
+QTreeWidgetItem *GenericPanel::addElementsCategory(ElementsCategory *category, QTreeWidgetItem *parent_item, PanelOptions options) {
+	if (!category) return(0);
+	bool creation_required;
+	
+	QTreeWidgetItem *category_qtwi = getItemForElementsCategory(category, &creation_required);
+	updateElementsCategoryItem(category_qtwi, category, options, creation_required);
+	reparent(category_qtwi, parent_item);
+	fillElementsCategoryItem(category_qtwi, category, options, creation_required);
+	
+	return(category_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::itemForElementsCategory(ElementsCategory *category) {
+	if (!category) return(0);
+	return(elements_.value(category -> location()));
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::getItemForElementsCategory(ElementsCategory *category, bool *created) {
+	if (!category) return(0);
+	
+	QTreeWidgetItem *category_item = elements_.value(category -> location(), 0);
+	if (category_item) {
+		if (created) *created = false;
+		return(category_item);
+	}
+	
+	QET::ItemType type = category -> isRootCategory() ? QET::ElementsCollection : QET::ElementsCategory;
+	category_item = makeItem(type);
+	if (created) *created = true;
+	return(category_item);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::updateElementsCategoryItem(QTreeWidgetItem *category_qtwi, ElementsCategory *category, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(options)
+	if (!category || !category_qtwi) return(0);
+	
+	category_qtwi -> setText(0, category -> name());
+	markItemAsContainer(category_qtwi);
+	
+	if (freshly_created) {
+		category_qtwi -> setData(0, GenericPanel::Item, qVariantFromValue(category -> location()));
+		elements_.insert(category -> location(), category_qtwi);
+	}
+	return(category_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::fillElementsCategoryItem(QTreeWidgetItem *category_qtwi, ElementsCategory *category, PanelOptions options, bool freshly_created) {
+	if (!category || !category_qtwi) return(0);
+	
+	int index = 0;
+	
+	if (options & AddChildElementsCategories) {
+		if (!freshly_created) {
+			QList<ElementsLocation> sub_categories;
+			foreach(ElementsCategory *sub_category, category -> categories()) {
+				sub_categories << sub_category -> location();
+			}
+			removeObsoleteItems(sub_categories, category_qtwi, QET::ElementsCategory, false);
+		}
+		
+		foreach (ElementsCategory *sub_category, category -> categories()) {
+			QTreeWidgetItem *sub_category_qtwi = addElementsCategory(sub_category, 0, options);
+			category_qtwi -> insertChild(index ++, sub_category_qtwi);
+		}
+	}
+	
+	if (options & AddChildElements) {
+		if (!freshly_created) {
+			QList<ElementsLocation> sub_elements;
+			foreach(ElementDefinition *sub_element, category -> elements()) {
+				sub_elements << sub_element -> location();
+			}
+			removeObsoleteItems(sub_elements, category_qtwi, QET::Element, false);
+		}
+		foreach (ElementDefinition *sub_element, category -> elements()) {
+			QTreeWidgetItem *sub_element_qtwi = addElement(sub_element, 0, options);
+			category_qtwi -> insertChild(index ++, sub_element_qtwi);
+		}
+	}
+	
+	return(category_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::addElement(ElementDefinition *element, QTreeWidgetItem *parent_item, PanelOptions options) {
+	if (!element) return(0);
+	bool creation_required;
+	
+	QTreeWidgetItem *element_qtwi = getItemForElement(element, &creation_required);
+	updateElementItem(element_qtwi, element, options, creation_required);
+	reparent(element_qtwi, parent_item);
+	fillElementItem(element_qtwi, element, options, creation_required);
+	
+	return(element_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::itemForElement(ElementDefinition *element) {
+	if (!element) return(0);
+	return(elements_.value(element -> location(), 0));
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::getItemForElement(ElementDefinition *element, bool *created) {
+	if (!element) return(0);
+	
+	QTreeWidgetItem *element_qtwi = elements_.value(element -> location(), 0);
+	if (element_qtwi) {
+		if (created) *created = false;
+		return(element_qtwi);
+	}
+	
+	element_qtwi = makeItem(QET::Element);
+	if (created) *created = true;
+	return(element_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::updateElementItem(QTreeWidgetItem *element_qtwi, ElementDefinition *element, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(options)
+	Q_UNUSED(freshly_created)
+	if (!element_qtwi || !element) return(element_qtwi);
+	
+	ElementsCollectionCache *cache = getElementsCache();
+	if (!cache -> fetchElement(element)) {
+		return(element_qtwi);
+	}
+	
+	ElementsLocation element_location = element -> location();
+	element_qtwi -> setText(0, cache -> name());
+	if (options & DisplayElementsPreview) {
+		element_qtwi -> setIcon(0, QIcon(cache -> pixmap()));
+	}
+	
+	element_qtwi -> setToolTip(0, element_location.toString());
+	// actions speciales pour les elements appartenant a un projet
+	if (QETProject *element_project = element_location.project()) {
+		// affiche en rouge les elements inutilises dans un projet
+		if (!element_project -> usesElement(element -> location())) {
+			markItemAsUnused(element_qtwi);
+		}
+	}
+	
+	if (freshly_created) {
+		element_qtwi -> setData(0, GenericPanel::Item, qVariantFromValue(element_location));
+		elements_.insert(element_location, element_qtwi);
+	}
+	
+	return(element_qtwi);
+}
+
+/**
+	
+*/
+QTreeWidgetItem *GenericPanel::fillElementItem (QTreeWidgetItem *element_qtwi, ElementDefinition *element, PanelOptions options, bool freshly_created) {
+	Q_UNUSED(element_qtwi)
+	Q_UNUSED(element)
+	Q_UNUSED(options)
+	Q_UNUSED(freshly_created)
+	return(element_qtwi);
+}
+
+/**
+	
+*/
+void GenericPanel::projectInformationsChanged(QETProject *project) {
+	addProject(project, 0, 0);
+}
+
+/**
+	
+*/
+void GenericPanel::diagramAdded(QETProject *project, Diagram *diagram) {
+	Q_UNUSED(diagram)
+	addProject(project, 0, GenericPanel::AddChildDiagrams);
+}
+
+/**
+	
+*/
+void GenericPanel::diagramRemoved(QETProject *project, Diagram *diagram) {
+	Q_UNUSED(diagram)
+	addProject(project, 0, GenericPanel::AddChildDiagrams);
+}
+
+/**
+	@param project Projet auquel appartiennent les schemas concernes
+	@param from Index de l'onglet avant le deplacement
+	@param to   Index de l'onglet apres le deplacement
+*/
+void GenericPanel::projectDiagramsOrderChanged(QETProject *project, int from, int to) {
+	// get the item representing the provided project
+	QTreeWidgetItem *qtwi_project = itemForProject(project);
+	if (!qtwi_project) return;
+	
+	// get the item representing the moved diagram
+	QTreeWidgetItem *moved_qtwi_diagram = qtwi_project -> child(from);
+	if (!moved_qtwi_diagram) return;
+	
+	// remove the QTWI then insert it back at the adequate location
+	bool was_selected = moved_qtwi_diagram -> isSelected();
+	qtwi_project -> removeChild(moved_qtwi_diagram);
+	qtwi_project -> insertChild(to, moved_qtwi_diagram);
+	
+	// update the QTWI labels because they may display the folio index
+	foreach (int diagram_index, QList<int>() << from << to) {
+		QTreeWidgetItem *qtwi_diagram = qtwi_project -> child(diagram_index);
+		if (!qtwi_diagram) continue;
+		
+		Diagram *diagram = valueForItem<Diagram *>(qtwi_diagram);
+		if (diagram) {
+			updateDiagramItem(qtwi_diagram, diagram);
+		}
+	}
+	
+	if (was_selected) {
+		setCurrentItem(moved_qtwi_diagram);
+	}
+}
+
+/**
+	Inform this panel the diagram \a diagram has changed its title to \a title.
+*/
+void GenericPanel::diagramTitleChanged(Diagram *diagram, const QString &title) {
+	Q_UNUSED(title)
+	GenericPanel::addDiagram(diagram);
+}
+
+/**
+	@param collection Title block templates collection that changed and should be updated
+	@param template_name Name of the changed template (unused)
+*/
+void GenericPanel::templatesCollectionChanged(TitleBlockTemplatesCollection*collection, const QString &template_name) {
+	Q_UNUSED(template_name)
+	addTemplatesCollection(collection);
+}
+
+/**
+	
+*/
+void GenericPanel::diagramUsedTemplate(TitleBlockTemplatesCollection *collection, const QString &name) {
+	Q_UNUSED(collection)
+	Q_UNUSED(name)
+	qDebug() << Q_FUNC_INFO << name;
+	addTemplatesCollection(collection);
+}
+
+/**
+	
+*/
+QString GenericPanel::defaultText(QET::ItemType type) {
+	switch(type) {
+		case QET::ElementsCollectionItem:
+		case QET::Element: return("element");
+		case QET::ElementsContainer:
+		case QET::ElementsCategory: return("elements category");
+		case QET::ElementsCollection: return("elements collection");
+		case QET::TitleBlockTemplatesCollectionItem:
+		case QET::TitleBlockTemplate: return("title block template");
+		case QET::TitleBlockTemplatesCollection: return("title block templates collection");
+		case QET::Diagram: return("diagram");
+		case QET::Project: return("project");
+		default: return(QString());
+	}
+	return(QString());
+}
+
+/**
+	@param type Item type we want the default icon for
+	@return the default icon for \a type
+*/
+QIcon GenericPanel::defaultIcon(QET::ItemType type) {
+	if (type & QET::ElementsContainer) {
+		return(QET::Icons::Folder);
+	} else if (type & QET::TitleBlockTemplatesCollectionItem) {
+		return(QET::Icons::TitleBlock);
+	} else if (type == QET::Diagram) {
+		return(QET::Icons::Diagram);
+	} else if (type == QET::Project) {
+		return(QET::Icons::Project);
+	}
+	return(QIcon());
+}
+
+/**
+	Create a QTreeWidgetItem
+	@param parent Parent for the created item
+	@param type Item type (e.g QET::Diagram, QET::Project, ...)
+	@param label Label for the created item
+	@param icon Icon for the created item
+	@return the create QTreeWidgetItem
+*/
+QTreeWidgetItem *GenericPanel::makeItem(QET::ItemType type, QTreeWidgetItem *parent, const QString &label, const QIcon &icon) {
+	QTreeWidgetItem *qtwi = new QTreeWidgetItem(parent, type);
+	qtwi -> setText(0, label.isEmpty() ? defaultText(type) : label);
+	qtwi -> setIcon(0, icon.isNull() ? defaultIcon(type) : icon);
+	return(qtwi);
+}
+
+/**
+	
+*/
+void GenericPanel::deleteItem(QTreeWidgetItem *item) {
+	// recursively delete child items first
+	for (int i = 0 ; i < item -> childCount() ; ++ i) {
+		deleteItem(item -> child(i));
+	}
+	
+	// delete the item itself
+	unregisterItem(item);
+	delete item;
+}
+
+/**
+	Mark an item as being a container (collection, category, ...)
+*/
+void GenericPanel::markItemAsContainer(QTreeWidgetItem *qtwi) {
+	if (!qtwi) return;
+	QLinearGradient t(0, 0, 200, 0);
+	t.setColorAt(0, QColor("#e8e8e8"));
+	t.setColorAt(1, QColor("#ffffff"));
+	qtwi -> setBackground(0, QBrush(t));
+}
+
+/**
+	Mark the provided QTreeWidgetItem as unused in its parent project.
+	@param qtwi A QTreeWidgetItem
+*/
+void GenericPanel::markItemAsUnused(QTreeWidgetItem *qtwi) {
+	QLinearGradient t(0, 0, 200, 0);
+	t.setColorAt(0, QColor("#ffc0c0"));
+	t.setColorAt(1, QColor("#ffffff"));
+	qtwi -> setBackground(0, QBrush(t));
+	qtwi -> setToolTip(0, QString(tr("%1 [non utilis\351 dans le projet]")).arg(qtwi -> toolTip(0)));
+}
+
+/**
+	
+*/
+void GenericPanel::reparent(QTreeWidgetItem *item, QTreeWidgetItem *parent) {
+	if (parent && item -> parent() != parent) {
+		parent -> addChild(item);
+	}
+}
+
+/**
+	@return the child items of \a item of type \a type
+*/
+QList<QTreeWidgetItem *> GenericPanel::childItems(QTreeWidgetItem *item, QET::ItemType type, bool recursive) const {
+	QList<QTreeWidgetItem *> items;
+	if (!item) return(items);
+	for (int i = 0 ; i < item -> childCount() ; ++ i) {
+		QTreeWidgetItem *current_item = item -> child(i);
+		if (!current_item) continue;
+		if (current_item -> type() == type) {
+			items << current_item;
+		}
+		if (recursive) {
+			items << childItems(current_item, type, true);
+		}
+	}
+	return(items);
+}
+
+/**
+	
+*/
+template<typename T>
+void GenericPanel::removeObsoleteItems(const QList<T> &expected_items, QTreeWidgetItem *item, QET::ItemType type, bool recursive) {
+	// remove items unknown to the project (presumably removed)
+	
+	foreach (QTreeWidgetItem *child_item, childItems(item, type, recursive)) {
+		T child_value = valueForItem<T>(child_item);
+		if (!expected_items.contains(child_value)) {
+			deleteItem(child_item);
+		}
+	}
+}
+
+/**
+	
+*/
+template<typename T>
+T GenericPanel::valueForItem(QTreeWidgetItem *item) const {
+	return(qVariantValue<T>(item -> data(0, GenericPanel::Item)));
+}
+
+/**
+	
+*/
+void GenericPanel::unregisterItem(QTreeWidgetItem *item) {
+	if (!item) return;
+	
+	int type = item ->type();
+	if (type & QET::ElementsCollectionItem) {
+		elements_.remove(valueForItem<ElementsLocation>(item));
+	} else if (type & QET::TitleBlockTemplatesCollectionItem) {
+		tb_templates_.remove(valueForItem<TitleBlockTemplateLocation>(item));
+	} else if (type == QET::Diagram) {
+		diagrams_.remove(valueForItem<Diagram *>(item));
+	} else if (type == QET::Project) {
+		projects_.remove(valueForItem<QETProject *>(item));
+	}
+}
+
+/**
+	
+*/
+void GenericPanel::clearPanel() {
+	clear();
+	projects_.clear();
+	diagrams_.clear();
+	tb_templates_.clear();
+	elements_.clear();
+}
+
+/**
+	Handle various events; reimplemented here to emit the signal
+	firstActivated().
+*/
+bool GenericPanel::event(QEvent *event) {
+	if (first_activation_ && event -> type() == QEvent::WindowActivate) {
+		QTimer::singleShot(250, this, SLOT(emitFirstActivated()));
+		first_activation_ = false;
+	}
+	return(QTreeWidget::event(event));
+}
+
+/**
+	Emit the signal firstActivated().
+*/
+void GenericPanel::emitFirstActivated() {
+	emit(firstActivated());
+}

Added: branches/0.3/sources/genericpanel.h
===================================================================
--- branches/0.3/sources/genericpanel.h	                        (rev 0)
+++ branches/0.3/sources/genericpanel.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -0,0 +1,194 @@
+/*
+	Copyright 2006-2012 Xavier Guerrin
+	This file is part of QElectroTech.
+	
+	QElectroTech 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.
+	
+	QElectroTech 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 QElectroTech.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef GENERIC_PANEL_H
+#define GENERIC_PANEL_H
+#include "qet.h"
+#include <QTreeWidget>
+#include "elementslocation.h"
+class QTreeWidgetItem;
+class QETProject;
+class Diagram;
+class ElementsCollection;
+class ElementsCategory;
+class ElementDefinition;
+class TitleBlockTemplatesCollection;
+class TitleBlockTemplateLocation;
+class ElementsCollectionCache;
+
+/**
+	The generic panel is a QTreeWidget subclass providing extra methods
+	allowing developers to easily add objects (projects, diagrams, title block
+	templates, elements, ...) to it; it also ensures the displayed information
+	remains up to date.
+*/
+class GenericPanel : public QTreeWidget {
+	Q_OBJECT
+	
+	public:
+	enum PanelOption {
+		AddChildDiagrams              =   1,
+		AddChildTemplatesCollection   =   2,
+		AddChildTemplates             =   4,
+		AddAllChildTemplates          =   6,
+		AddChildElementsCollections   =   8,
+		AddChildElementsCategories    =  16,
+		AddChildElementsContainers    =  24,
+		AddChildElements              =  32,
+		AddAllChildElements           =  56,
+		AddAllChild                   =  63,
+		DisplayElementsPreview        =  64,
+		All                           = 127
+	};
+	Q_DECLARE_FLAGS(PanelOptions, PanelOption)
+	
+	enum MetaData {
+		Item = Qt::UserRole + 1,
+		AliasItem,
+		Parent
+	};
+	
+	// Constructors, destructor
+	public:
+	GenericPanel(QWidget * = 0);
+	virtual ~GenericPanel();
+	
+	// cache-related methods
+	public:
+	virtual ElementsCollectionCache *elementsCache();
+	virtual bool setElementsCache(ElementsCollectionCache *, ElementsCollectionCache ** = 0);
+	
+	protected:
+	virtual ElementsCollectionCache *getElementsCache();
+	
+	public:
+	// convenience methods to obtain what an item represents
+	virtual int currentItemType();
+	virtual QETProject *projectForItem(QTreeWidgetItem *) const;
+	virtual Diagram *diagramForItem(QTreeWidgetItem *) const;
+	virtual TitleBlockTemplateLocation templateLocationForItem(QTreeWidgetItem *) const;
+	virtual ElementsLocation elementLocationForItem(QTreeWidgetItem *) const;
+	
+	// convenience methods to obtain what the selected item represents
+	virtual QETProject *selectedProject() const;
+	virtual Diagram *selectedDiagram() const;
+	virtual TitleBlockTemplateLocation selectedTemplateLocation() const;
+	virtual ElementsLocation selectedElementLocation() const;
+	
+	// project-related methods
+	public:
+	virtual QTreeWidgetItem *addProject(QETProject *, QTreeWidgetItem * = 0, PanelOptions = AddAllChild);
+	virtual QTreeWidgetItem *itemForProject(QETProject *);
+	protected:
+	virtual QTreeWidgetItem *getItemForProject(QETProject *, bool * = 0);
+	virtual QTreeWidgetItem *updateProjectItem(QTreeWidgetItem *, QETProject *, PanelOptions = AddAllChild, bool = false);
+	virtual QTreeWidgetItem *fillProjectItem  (QTreeWidgetItem *, QETProject *, PanelOptions = AddAllChild, bool = false);
+	
+	// diagram-related methods
+	public:
+	virtual QTreeWidgetItem *addDiagram(Diagram *, QTreeWidgetItem * = 0, PanelOptions = AddAllChild);
+	virtual QTreeWidgetItem *itemForDiagram(Diagram *);
+	protected:
+	virtual QTreeWidgetItem *getItemForDiagram(Diagram *, bool * = 0);
+	virtual QTreeWidgetItem *updateDiagramItem(QTreeWidgetItem *, Diagram *, PanelOptions = AddAllChild, bool = false);
+	virtual QTreeWidgetItem *fillDiagramItem  (QTreeWidgetItem *, Diagram *, PanelOptions = AddAllChild, bool = false);
+	
+	// title block templates collections methods
+	public:
+	virtual QTreeWidgetItem *addTemplatesCollection(TitleBlockTemplatesCollection *, QTreeWidgetItem * = 0, PanelOptions = AddAllChild);
+	virtual QTreeWidgetItem *itemForTemplatesCollection(TitleBlockTemplatesCollection *);
+	protected:
+	virtual QTreeWidgetItem *getItemForTemplatesCollection(TitleBlockTemplatesCollection *, bool * = 0);
+	virtual QTreeWidgetItem *updateTemplatesCollectionItem(QTreeWidgetItem *, TitleBlockTemplatesCollection *, PanelOptions = AddAllChild, bool = false);
+	virtual QTreeWidgetItem *fillTemplatesCollectionItem  (QTreeWidgetItem *, TitleBlockTemplatesCollection *, PanelOptions = AddAllChild, bool = false);
+	
+	// title block templates methods
+	public:
+	virtual QTreeWidgetItem *addTemplate(const TitleBlockTemplateLocation &, QTreeWidgetItem * = 0, PanelOptions = AddAllChild);
+	virtual QTreeWidgetItem *itemForTemplate(const TitleBlockTemplateLocation &);
+	protected:
+	virtual QTreeWidgetItem *getItemForTemplate(const TitleBlockTemplateLocation &, bool * = 0);
+	virtual QTreeWidgetItem *updateTemplateItem(QTreeWidgetItem *, const TitleBlockTemplateLocation &, PanelOptions = AddAllChild, bool = false);
+	virtual QTreeWidgetItem *fillTemplateItem  (QTreeWidgetItem *, const TitleBlockTemplateLocation &, PanelOptions = AddAllChild, bool = false);
+	
+	// elements collections methods
+	public:
+	virtual QTreeWidgetItem *addElementsCollection(ElementsCollection *, QTreeWidgetItem *, PanelOptions = AddAllChild, const QString & = QString(), const QIcon & = QIcon());
+	virtual QTreeWidgetItem *itemForElementsLocation(const ElementsLocation &);
+	
+	// elements categories methods
+	public:
+	virtual QTreeWidgetItem *addElementsCategory(ElementsCategory *, QTreeWidgetItem * = 0, PanelOptions = AddAllChild);
+	virtual QTreeWidgetItem *itemForElementsCategory(ElementsCategory *);
+	protected:
+	virtual QTreeWidgetItem *getItemForElementsCategory(ElementsCategory *, bool * = 0);
+	virtual QTreeWidgetItem *updateElementsCategoryItem(QTreeWidgetItem *, ElementsCategory *, PanelOptions = AddAllChild, bool = false);
+	virtual QTreeWidgetItem *fillElementsCategoryItem  (QTreeWidgetItem *, ElementsCategory *, PanelOptions = AddAllChild, bool = false);
+	
+	// elements methods
+	public:
+	virtual QTreeWidgetItem *addElement(ElementDefinition *, QTreeWidgetItem * = 0, PanelOptions = AddAllChild);
+	virtual QTreeWidgetItem *itemForElement(ElementDefinition *);
+	protected:
+	virtual QTreeWidgetItem *getItemForElement(ElementDefinition *, bool * = 0);
+	virtual QTreeWidgetItem *updateElementItem(QTreeWidgetItem *, ElementDefinition *, PanelOptions = AddAllChild, bool = false);
+	virtual QTreeWidgetItem *fillElementItem  (QTreeWidgetItem *, ElementDefinition *, PanelOptions = AddAllChild, bool = false);
+	
+	// slots used to receive change notifications from added objects
+	protected slots:
+	void projectInformationsChanged(QETProject *);
+	void diagramAdded(QETProject *, Diagram *);
+	void diagramRemoved(QETProject *, Diagram *);
+	void projectDiagramsOrderChanged(QETProject *, int, int);
+	void diagramTitleChanged(Diagram *, const QString &);
+	void templatesCollectionChanged(TitleBlockTemplatesCollection*, const QString &);
+	void diagramUsedTemplate(TitleBlockTemplatesCollection *, const QString &);
+	
+	// various other methods
+	protected:
+	virtual QString defaultText(QET::ItemType);
+	virtual QIcon   defaultIcon(QET::ItemType);
+	virtual QTreeWidgetItem *makeItem(QET::ItemType, QTreeWidgetItem * = 0, const QString & = QString(), const QIcon & = QIcon());
+	virtual void deleteItem(QTreeWidgetItem *);
+	virtual void markItemAsContainer(QTreeWidgetItem *);
+	virtual void markItemAsUnused(QTreeWidgetItem *);
+	virtual void reparent(QTreeWidgetItem *, QTreeWidgetItem *);
+	QList<QTreeWidgetItem *> childItems(QTreeWidgetItem *, QET::ItemType, bool = false) const;
+	template<typename T> void removeObsoleteItems(const QList<T> &, QTreeWidgetItem *, QET::ItemType, bool);
+	template<typename T> T valueForItem(QTreeWidgetItem *) const;
+	void unregisterItem(QTreeWidgetItem *);
+	void clearPanel();
+	
+	bool event(QEvent *);
+	
+	signals:
+	bool firstActivated();
+	
+	private slots:
+	void emitFirstActivated();
+	
+	protected:
+	ElementsCollectionCache *cache_; ///< Cache used to render elements
+	
+	private:
+	bool first_activation_; ///< boolean used to track the first time this widget is activated/shown
+	QHash<QETProject *, QTreeWidgetItem *>               projects_;     ///< Allow quick retrieval of the item representing a given project
+	QHash<Diagram *, QTreeWidgetItem *>                  diagrams_;     ///< Allow quick retrieval of the item representing a given diagram
+	QHash<TitleBlockTemplateLocation, QTreeWidgetItem *> tb_templates_; ///< Allow quick retrieval of the item representing a title block template
+	QHash<ElementsLocation, QTreeWidgetItem *>           elements_;     ///< Allow quick retrieval of the item representing an element
+};
+#endif

Modified: branches/0.3/sources/qet.h
===================================================================
--- branches/0.3/sources/qet.h	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/qet.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -68,12 +68,27 @@
 		collection d'elements.
 	*/
 	enum ItemType {
-		Element    = 1, ///< Element
-		Category   = 2, ///< Categorie
-		Collection = 4, ///< Collection
-		All        = 7  ///< Tous
+		Element                           =    1,
+		ElementsCategory                  =    2,
+		ElementsCollection                =    4,
+		ElementsContainer                 =    6,
+		ElementsCollectionItem            =    7,
+		TitleBlockTemplate                =    8,
+		TitleBlockTemplatesCollection     =   16,
+		TitleBlockTemplatesCollectionItem =   24,
+		Diagram                           =   32,
+		Project                           =   64,
+		All                               =  127
 	};
 	
+	/**
+		This enum represents the various steps when applying a filter.
+	*/
+	enum Filtering {
+		BeginFilter,
+		RegularFilter,
+		EndFilter
+	};
 	
 	/**
 		Cet enum represente les differentes facons de gerer un probleme lors de

Modified: branches/0.3/sources/qetdiagrameditor.cpp
===================================================================
--- branches/0.3/sources/qetdiagrameditor.cpp	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/qetdiagrameditor.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -27,6 +27,7 @@
 #include "qeticons.h"
 #include "qetelementeditor.h"
 #include "qetmessagebox.h"
+#include "genericpanel.h"
 
 /**
 	constructeur
@@ -968,20 +969,6 @@
 }
 
 /**
-	@param project_view Projet concerne
-	@param from Index de l'onglet avant le deplacement
-	@param to   Index de l'onglet apres le deplacement
-*/
-void QETDiagramEditor::diagramOrderChanged(ProjectView *project_view, int from, int to) {
-	if (!project_view) return;
-	
-	QETProject *project = project_view -> project();
-	if (!project) return;
-	
-	pa -> elementsPanel().diagramOrderChanged(project, from, to);
-}
-
-/**
 	Effectue l'action "couper" sur le schema en cours
 */
 void QETDiagramEditor::slot_cut() {
@@ -1252,16 +1239,10 @@
 	connect(project_view, SIGNAL(diagramRemoved(DiagramView *)), this, SLOT(diagramWasRemoved(DiagramView *)));
 	connect(project_view, SIGNAL(diagramRemoved(DiagramView *)), this, SLOT(slot_updateActions()));
 	if (QETProject *project = project_view -> project()) {
-		connect(project, SIGNAL(diagramAdded  (QETProject *, Diagram*)), &(pa -> elementsPanel()), SLOT(diagramWasAdded  (QETProject *, Diagram*)));
-		connect(project, SIGNAL(diagramRemoved(QETProject *, Diagram*)), &(pa -> elementsPanel()), SLOT(diagramWasRemoved(QETProject *, Diagram*)));
-		
 		// on met aussi les menus a jour quand un projet passe en lecture seule ou non
 		connect(project, SIGNAL(readOnlyChanged(QETProject *, bool)), this, SLOT(slot_updateActions()));
 	}
 	
-	// gere les changements de l'ordre des schemas dans le projet
-	connect(project_view, SIGNAL(diagramOrderChanged(ProjectView *, int, int)), this, SLOT(diagramOrderChanged(ProjectView *, int, int)));
-	
 	// gere les demandes consistant a retrouver un element dans le panel
 	connect(project_view, SIGNAL(findElementRequired(const ElementsLocation &)), this, SLOT(findElementInPanel(const ElementsLocation &)));
 	
@@ -1694,7 +1675,6 @@
 	connect(dv,              SIGNAL(selectionChanged()),         this,     SLOT(slot_updateComplexActions()));
 	connect(dv,              SIGNAL(modeChanged()),              this,     SLOT(slot_updateModeActions()));
 	connect(dv,              SIGNAL(textAdded(bool)),            add_text, SLOT(setChecked(bool)));
-	connect(dv, SIGNAL(titleChanged(DiagramView *, const QString &)), this, SLOT(diagramTitleChanged(DiagramView *)));
 }
 
 /**
@@ -1716,18 +1696,6 @@
 }
 
 /**
-	Gere le changement de titre d'un schema dans un projet
-	@param dv DiagramView concerne
-*/
-void QETDiagramEditor::diagramTitleChanged(DiagramView *dv) {
-	if (Diagram *diagram = dv -> diagram()) {
-		if (QETProject *project = diagram -> project()) {
-			pa -> elementsPanel().diagramTitleChanged(project, diagram);
-		}
-	}
-}
-
-/**
 	@param location Emplacement de l'element a retrouver dans le panel
 	d'elements.
 */

Modified: branches/0.3/sources/qetdiagrameditor.h
===================================================================
--- branches/0.3/sources/qetdiagrameditor.h	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/qetdiagrameditor.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -129,7 +129,6 @@
 	void activateProject(QETProject *);
 	void activateProject(ProjectView *);
 	void activateWidget(QWidget *);
-	void diagramOrderChanged(ProjectView *, int, int);
 	void projectWasClosed(ProjectView *);
 	void editCurrentProjectProperties();
 	void editProjectProperties(ProjectView *);
@@ -147,7 +146,6 @@
 	void diagramWasAdded(DiagramView *);
 	void diagramIsAboutToBeRemoved(DiagramView *);
 	void diagramWasRemoved(DiagramView *);
-	void diagramTitleChanged(DiagramView *);
 	void findElementInPanel(const ElementsLocation &);
 	void editElementInEditor(const ElementsLocation &);
 	

Modified: branches/0.3/sources/qetproject.cpp
===================================================================
--- branches/0.3/sources/qetproject.cpp	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/qetproject.cpp	2012-02-06 21:21:43 UTC (rev 1490)
@@ -832,6 +832,7 @@
 	
 	diagrams_.move(old_index, new_index);
 	updateDiagramsFolioData();
+	emit(projectDiagramsOrderChanged(this, old_index, new_index));
 }
 
 /**

Modified: branches/0.3/sources/qetproject.h
===================================================================
--- branches/0.3/sources/qetproject.h	2012-02-06 21:19:58 UTC (rev 1489)
+++ branches/0.3/sources/qetproject.h	2012-02-06 21:21:43 UTC (rev 1490)
@@ -128,6 +128,7 @@
 	void projectInformationsChanged(QETProject *);
 	void diagramAdded(QETProject *, Diagram *);
 	void diagramRemoved(QETProject *, Diagram *);
+	void projectDiagramsOrderChanged(QETProject *, int, int);
 	void diagramUsedTemplate(TitleBlockTemplatesCollection *, const QString &);
 	void readOnlyChanged(QETProject *, bool);
 	
@@ -181,4 +182,5 @@
 	/// Embedded title block templates collection
 	TitleBlockTemplatesProjectCollection titleblocks_;
 };
+Q_DECLARE_METATYPE(QETProject *)
 #endif


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/