/* Copyright 2006-2008 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 . */ #include "elementspanel.h" #include "qetapp.h" #include "elementscategory.h" #include "elementscategoryeditor.h" #include "elementscategorydeleter.h" #include "elementdeleter.h" #include "customelement.h" #include "qetelementeditor.h" /** Constructeur @param parent Le QWidget parent du panel d'appareils */ ElementsPanel::ElementsPanel(QWidget *parent) : QTreeWidget(parent) { // selection unique setSelectionMode(QAbstractItemView::SingleSelection); setColumnCount(1); header() -> hide(); // drag'n drop autorise setDragEnabled(true); setAcceptDrops(false); setDropIndicatorShown(false); // taille des elements setIconSize(QSize(50, 50)); // charge les collections reload(); // la premiere fois, etend le premier niveau des collections QList items = findItems("*", Qt::MatchWildcard); if (items.count() == 2) { items[0] -> setExpanded(true); items[1] -> setExpanded(true); } // 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(); qp.setColor(QPalette::Text, Qt::black); qp.setColor(QPalette::Base, Qt::white); qp.setColor(QPalette::AlternateBase, QColor("#e8e8e8")); qp.setColor(QPalette::Highlight, QColor("#678db2")); 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))); // emet un signal au lieu de gerer son menu contextuel setContextMenuPolicy(Qt::CustomContextMenu); } /** Destructeur */ ElementsPanel::~ElementsPanel() { } /// @return true si un element est selectionne, false sinon bool ElementsPanel::selectedItemIsAnElement() const { QFileInfo infos_file = selectedFile(); if (!infos_file.exists()) return(false); return(infos_file.isFile()); } /// @return true si une categorie est selectionnee, false sinon bool ElementsPanel::selectedItemIsACategory() const { QFileInfo infos_file = selectedFile(); if (!infos_file.exists()) return(false); return(infos_file.isDir()); } /** Gere le mouvement lors d'un drag'n drop */ void ElementsPanel::dragMoveEvent(QDragMoveEvent */*e*/) { } /** Gere le depot lors d'un drag'n drop */ void ElementsPanel::dropEvent(QDropEvent */*e*/) { } /** Gere le debut des drag'n drop @param supportedActions Les actions supportees */ void ElementsPanel::startDrag(Qt::DropActions) { // recupere le nom du fichier decrivant l'element QString nom_fichier = currentItem() -> data(0, 42).toString(); if (nom_fichier.isEmpty()) return; // objet QDrag pour realiser le drag'n drop QDrag *drag = new QDrag(this); // donnees qui seront transmises par le drag'n drop QMimeData *mimeData = new QMimeData(); // appareil temporaire pour fournir un apercu int etat; Element *appar = new CustomElement(nom_fichier, 0, 0, &etat); if (etat != 0) { delete appar; return; } mimeData -> setText(nom_fichier); drag -> setMimeData(mimeData); // accrochage d'une pixmap representant l'appareil au pointeur drag -> setPixmap(appar -> pixmap()); drag -> setHotSpot(appar -> hotspot()); // realisation du drag'n drop drag -> start(Qt::CopyAction); // suppression de l'appareil temporaire delete appar; } /** Methode privee permettant d'ajouter un dossier au panel d'appareils @param qtwi_parent QTreeWidgetItem parent sous lequel sera insere l'element @param dossier Chemin absolu du dossier a inserer @param nom Parametre facultatif permettant de forcer le nom du dossier. S'il n'est pas precise, la fonction ouvre le fichier qet_directory situe dans le dossier et y lit le nom du dossier ; si ce fichier n'existe pas ou est invalide, la fonction utilise le nom du dossier. */ void ElementsPanel::addDir(QTreeWidgetItem *qtwi_parent, QString adr_dossier, QString nom) { ElementsCategory category(adr_dossier); if (!category.exists()) return; // recupere le nom de la categorie QString nom_categorie = (nom != QString()) ? nom : category.name(); // creation du QTreeWidgetItem representant le dossier QTreeWidgetItem *qtwi_dossier = new QTreeWidgetItem(qtwi_parent, QStringList(nom_categorie)); qtwi_dossier -> setIcon(0, QIcon(":/ico/folder.png")); QLinearGradient t(0, 0, 200, 0); t.setColorAt(0, QColor("#e8e8e8")); t.setColorAt(1, QColor("#ffffff")); qtwi_dossier -> setBackground(0, QBrush(t)); qtwi_dossier -> setData(0, 42, adr_dossier); // reduit le dossier si besoin qtwi_dossier -> setExpanded(expanded_directories.contains(adr_dossier)); // ajout des sous-categories / sous-dossiers QStringList dossiers = category.entryList(QStringList(), QDir::AllDirs | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDir::Name); foreach(QString dossier, dossiers) addDir(qtwi_dossier, adr_dossier + dossier + "/"); // ajout des elements / fichiers QStringList fichiers = category.entryList(QStringList("*.elmt"), QDir::Files, QDir::Name); foreach(QString fichier, fichiers) addFile(qtwi_dossier, adr_dossier + fichier); } /** Methode privee permettant d'ajouter un element au panel d'appareils @param qtwi_parent QTreeWidgetItem parent sous lequel sera insere l'element @param fichier Chemin absolu du fichier XML decrivant l'element a inserer */ void ElementsPanel::addFile(QTreeWidgetItem *qtwi_parent, QString fichier) { QString whats_this = tr("Ceci est un \351l\351ment que vous pouvez ins\351rer dans votre sch\351ma par cliquer-d\351placer"); QString tool_tip = tr("Cliquer-d\351posez cet \351l\351ment sur le sch\351ma pour ins\351rer un \351l\351ment "); int etat; CustomElement elmt_perso(fichier, 0, 0, &etat); if (etat != 0) { qDebug() << "Le chargement du composant" << fichier << "a echoue avec le code d'erreur" << etat; return; } QTreeWidgetItem *qtwi = new QTreeWidgetItem(qtwi_parent, QStringList(elmt_perso.nom())); qtwi -> setStatusTip(0, tool_tip + "\253 " + elmt_perso.nom() + " \273"); qtwi -> setToolTip(0, elmt_perso.nom()); qtwi -> setWhatsThis(0, whats_this); qtwi -> setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled); qtwi -> setIcon(0, QIcon(elmt_perso.pixmap())); qtwi -> setData(0, 42, fichier); } /** Recharge l'arbre des elements */ void ElementsPanel::reload() { // sauvegarde la liste des repertoires reduits saveExpandedCategories(); // vide l'arbre clear(); // chargement des elements de la collection QET addDir(invisibleRootItem(), QETApp::commonElementsDir(), tr("Collection QET")); // chargement des elements de la collection utilisateur addDir(invisibleRootItem(), QETApp::customElementsDir(), tr("Collection utilisateur")); // icones QList items = findItems("*", Qt::MatchWildcard); if (items.count() == 2) { items[0] -> setIcon(0, QIcon(":/ico/qet-16.png")); items[1] -> setIcon(0, QIcon(":/ico/folder_home.png")); } // reselectionne le dernier element selectionne if (!last_selected_item.isNull()) { QTreeWidgetItem *qtwi = findFile(last_selected_item); if (qtwi) setCurrentItem(qtwi); } } /** Edite la categorie selectionnee */ void ElementsPanel::editCategory() { QFileInfo infos_file = selectedFile(); if (!infos_file.exists() || !infos_file.isDir()) return; launchCategoryEditor(infos_file.absoluteFilePath()); } /** Edite l'element selectionne */ void ElementsPanel::editElement() { QFileInfo infos_file = selectedFile(); if (!infos_file.exists() || !infos_file.isFile()) return; launchElementEditor(infos_file.absoluteFilePath()); } /** Supprime la categorie selectionnee */ void ElementsPanel::deleteCategory() { QFileInfo infos_file = selectedFile(); if (!infos_file.exists() || !infos_file.isDir()) return; // supprime la categorie ElementsCategoryDeleter cat_deleter(infos_file.absoluteFilePath(), this); cat_deleter.exec(); // recharge la liste des categories reload(); } /** Supprime l'element selectionne */ void ElementsPanel::deleteElement() { QFileInfo infos_file = selectedFile(); if (!infos_file.exists() || !infos_file.isFile()) return; // supprime l'element ElementDeleter elmt_deleter(infos_file.absoluteFilePath(), this); elmt_deleter.exec(); // recharge la liste des categories reload(); } /** Gere le double-clic sur un element. Permet de lancer l'editeur de categorie ou d'element. */ void ElementsPanel::slot_doubleClick(QTreeWidgetItem *, int) { // le fichier doit exister QFileInfo infos_file = selectedFile(); if (!infos_file.exists()) return; if (infos_file.isFile()) { // il s'agit d'un element launchElementEditor(infos_file.absoluteFilePath()); } else if (infos_file.isDir()) { // il s'agit d'une categorie launchCategoryEditor(infos_file.absoluteFilePath()); } } /// @return un QFileInfo decrivant le fichier ou le dossier correspondant au QTreeWidgetItem selectionne QFileInfo ElementsPanel::selectedFile() const { QTreeWidgetItem *current_qtwi = currentItem(); if(!current_qtwi) return(QFileInfo()); return(QFileInfo(currentItem() -> data(0, 42).toString())); } /** Lance l'editeur d'element pour l'element filename @param filename Chemin du fichier representant l'element */ void ElementsPanel::launchElementEditor(const QString &filename) { QETElementEditor *editor = new QETElementEditor(); editor -> fromFile(filename); editor -> show(); } /** Lance l'editeur de categorie pour la categorie filename @param filename Chemin du dossier representant la categorie */ void ElementsPanel::launchCategoryEditor(const QString &filename) { ElementsCategoryEditor ece(filename, true); if (ece.exec() == QDialog::Accepted) reload(); } /** Enregistre la liste des categories repliees ainsi que le dernier element selectionne */ void ElementsPanel::saveExpandedCategories() { expanded_directories.clear(); QList items = findItems("*", Qt::MatchRecursive|Qt::MatchWildcard); foreach(QTreeWidgetItem *item, items) { QString file = item -> data(0, 42).toString(); if (!file.endsWith(".elmt") && item -> isExpanded()) { expanded_directories << file; } } // sauvegarde egalement le dernier element selectionne QTreeWidgetItem *current_item = currentItem(); if (current_item) last_selected_item = current_item -> data(0, 42).toString(); } /** @param file fichier ou dossier a retrouver dans l'arborescence @return le QTreeWidgetItem correspondant au fichier file ou 0 si celui-ci n'est pas trouve */ QTreeWidgetItem *ElementsPanel::findFile(const QString &file) const { QList items = findItems("*", Qt::MatchRecursive|Qt::MatchWildcard); foreach(QTreeWidgetItem *item, items) { if (item -> data(0, 42).toString() == file) return(item); } return(0); } /** N'affiche que les elements contenant une chaine donnee @param m Chaine a filtrer */ void ElementsPanel::filter(const QString &m) { QList items = findItems("*", Qt::MatchRecursive | Qt::MatchWildcard); if (m.isEmpty()) { foreach(QTreeWidgetItem *item, items) item -> setHidden(false); } else { foreach(QTreeWidgetItem *item, items) { QString file = item -> data(0, 42).toString(); bool item_matches = item -> text(0).contains(m, Qt::CaseInsensitive); item -> setHidden(!item_matches); if (item_matches) { // remonte l'arborescence pour afficher les categories contenant l'element QTreeWidgetItem *parent_qtwi = item -> parent(); while(parent_qtwi && (parent_qtwi -> isHidden() || !parent_qtwi -> isExpanded())) { parent_qtwi -> setHidden(false); parent_qtwi -> setExpanded(true); parent_qtwi = parent_qtwi -> parent(); } } } } }