From 6a12a008e9d2968ed7e48a32a7f38dc2a4df2677 Mon Sep 17 00:00:00 2001 From: blacksun Date: Tue, 25 Sep 2018 16:05:24 +0000 Subject: [PATCH] Start the work on a new feature : search and replace. This commit let user find for : texts, conductors and elements. WIP. git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@5526 bfdf4180-ca20-0410-9c96-a3a8aa849046 --- qelectrotech.pro | 15 +- .../ui/searchandreplacewidget.cpp | 690 ++++++++++++++++++ .../ui/searchandreplacewidget.h | 92 +++ .../ui/searchandreplacewidget.ui | 236 ++++++ sources/diagramcontent.cpp | 59 +- sources/diagramcontent.h | 4 +- sources/diagramview.cpp | 2 +- sources/qetdiagrameditor.cpp | 63 +- sources/qetdiagrameditor.h | 8 +- sources/ui/masterpropertieswidget.cpp | 2 +- 10 files changed, 1123 insertions(+), 48 deletions(-) create mode 100644 sources/SearchAndReplace/ui/searchandreplacewidget.cpp create mode 100644 sources/SearchAndReplace/ui/searchandreplacewidget.h create mode 100644 sources/SearchAndReplace/ui/searchandreplacewidget.ui diff --git a/qelectrotech.pro b/qelectrotech.pro index f23b88b63..3b5342684 100644 --- a/qelectrotech.pro +++ b/qelectrotech.pro @@ -92,7 +92,9 @@ INCLUDEPATH += sources \ sources/ElementsCollection/ui \ sources/autoNum \ sources/autoNum/ui \ - sources/ui/configpage + sources/ui/configpage \ + sources/SearchAndReplace \ + sources/SearchAndReplace/ui # Fichiers sources @@ -113,7 +115,9 @@ HEADERS += $$files(sources/*.h) $$files(sources/ui/*.h) \ $$files(sources/ElementsCollection/ui/*.h) \ $$files(sources/autoNum/*.h) \ $$files(sources/autoNum/ui/*.h) \ - $$files(sources/ui/configpage/*.h) + $$files(sources/ui/configpage/*.h) \ + $$files(sources/SearchAndReplace/*.h) \ + $$files(sources/SearchAndReplace/ui/*.h) SOURCES += $$files(sources/*.cpp) \ $$files(sources/editor/*.cpp) \ @@ -133,7 +137,9 @@ SOURCES += $$files(sources/*.cpp) \ $$files(sources/ElementsCollection/ui/*.cpp) \ $$files(sources/autoNum/*.cpp) \ $$files(sources/autoNum/ui/*.cpp) \ - $$files(sources/ui/configpage/*.cpp) + $$files(sources/ui/configpage/*.cpp) \ + $$files(sources/SearchAndReplace/*.cpp) \ + $$files(sources/SearchAndReplace/ui/*.cpp) # Liste des fichiers qui seront incorpores au binaire en tant que ressources Qt RESOURCES += qelectrotech.qrc @@ -153,7 +159,8 @@ FORMS += $$files(sources/richtext/*.ui) \ $$files(sources/editor/ui/*.ui) \ $$files(sources/ElementsCollection/ui/*.ui) \ $$files(sources/autoNum/ui/*.ui) \ - $$files(sources/ui/configpage/*.ui) + $$files(sources/ui/configpage/*.ui) \ + $$files(sources/SearchAndReplace/ui/*.ui) UI_SOURCES_DIR = sources/ui/ UI_HEADERS_DIR = sources/ui/ diff --git a/sources/SearchAndReplace/ui/searchandreplacewidget.cpp b/sources/SearchAndReplace/ui/searchandreplacewidget.cpp new file mode 100644 index 000000000..424ed645c --- /dev/null +++ b/sources/SearchAndReplace/ui/searchandreplacewidget.cpp @@ -0,0 +1,690 @@ +/* + Copyright 2006-2018 The QElectroTech Team + 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 "searchandreplacewidget.h" +#include "ui_searchandreplacewidget.h" +#include "qetdiagrameditor.h" +#include "qetproject.h" +#include "diagram.h" +#include "qeticons.h" +#include "element.h" +#include "independenttextitem.h" +#include "conductor.h" + +/** + * @brief SearchAndReplaceWidget::SearchAndReplaceWidget + * Constructor + * @param parent + */ +SearchAndReplaceWidget::SearchAndReplaceWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::SearchAndReplaceWidget) +{ + ui->setupUi(this); + setHideAdvanced(true); + setUpTreeItems(); + + connect(ui->m_search_le, &QLineEdit::textEdited, this, &SearchAndReplaceWidget::search); +} + +/** + * @brief SearchAndReplaceWidget::~SearchAndReplaceWidget + * Destructor + */ +SearchAndReplaceWidget::~SearchAndReplaceWidget() { + delete ui; +} + +/** + * @brief SearchAndReplaceWidget::event + * Reimplemented to clear the the lines edit and hide + * the advanced widgets, when this widget become hidden + * @param event + * @return + */ +bool SearchAndReplaceWidget::event(QEvent *event) +{ + if (event->type() == QEvent::Hide) + { + clear(); + setHideAdvanced(true); + if (m_highlighted_element) + { + m_highlighted_element.data()->setHighlighted(false); + m_highlighted_element.clear(); + } + } + else if (event->type() == QEvent::Show) + { + ui->m_search_le->setFocus(); + fillItemsList(); + m_root_qtwi->setExpanded(true); + } + + return QWidget::event(event); +} + +/** + * @brief SearchAndReplaceWidget::clear + * Clear the content of the search and replace line edit + * Clear all tree items in the tree widget (except the category items). + */ +void SearchAndReplaceWidget::clear() +{ + disconnect(ui->m_tree_widget, &QTreeWidget::itemChanged, this, &SearchAndReplaceWidget::itemChanged); + + qDeleteAll(m_element_hash.keys()); + m_element_hash.clear(); + + qDeleteAll(m_text_hash.keys()); + m_text_hash.clear(); + + qDeleteAll(m_conductor_hash.keys()); + m_conductor_hash.clear(); + + for (QTreeWidgetItem *qtwi : m_category_qtwi) + qtwi->setHidden(false); + + ui->m_tree_widget->collapseAll(); + ui->m_tree_widget->clearSelection(); + + ui->m_search_le->clear(); + ui->m_replace_le->clear(); + updateNextPreviousButtons(); + ui->m_search_le->setPalette(QPalette()); +} + +/** + * @brief SearchAndReplaceWidget::setEditor + * Set the diagram editor of this widget + * @param editor + */ +void SearchAndReplaceWidget::setEditor(QETDiagramEditor *editor) { + m_editor = editor; +} + +/** + * @brief SearchAndReplaceWidget::setUpTreeItems + * Set up the main tree widget items + */ +void SearchAndReplaceWidget::setUpTreeItems() +{ + m_root_qtwi = new QTreeWidgetItem(ui->m_tree_widget); + m_root_qtwi->setIcon(0, QET::Icons::ProjectProperties); + m_root_qtwi->setText(0, tr("Correspondance :")); + m_root_qtwi->setCheckState(0, Qt::Checked); + m_category_qtwi.append(m_root_qtwi); + + m_folio_qtwi = new QTreeWidgetItem(m_root_qtwi); + m_folio_qtwi->setIcon(0, QET::Icons::Diagram); + m_folio_qtwi->setText(0, tr("Folios")); + m_folio_qtwi->setCheckState(0, Qt::Checked); + m_category_qtwi.append(m_folio_qtwi); + + m_indi_text_qtwi = new QTreeWidgetItem(m_root_qtwi); + m_indi_text_qtwi->setIcon(0, QET::Icons::PartText); + m_indi_text_qtwi->setText(0, tr("Champs texte")); + m_indi_text_qtwi->setCheckState(0, Qt::Checked); + m_category_qtwi.append(m_indi_text_qtwi); + + m_elements_qtwi = new QTreeWidgetItem(m_root_qtwi); + m_elements_qtwi->setIcon(0, QET::Icons::Element); + m_elements_qtwi->setText(0, tr("Elements")); + m_elements_qtwi->setCheckState(0, Qt::Checked); + m_category_qtwi.append(m_elements_qtwi); + + m_simple_elmt_qtwi = new QTreeWidgetItem(m_elements_qtwi); + m_simple_elmt_qtwi->setText(0, tr("Elements simple")); + m_simple_elmt_qtwi->setIcon(0, QET::Icons::Element); + m_simple_elmt_qtwi->setCheckState(0, Qt::Checked); + m_qtwi_elmts.append(m_simple_elmt_qtwi); + + m_master_elmt_qtwi= new QTreeWidgetItem(m_elements_qtwi); + m_master_elmt_qtwi->setText(0, tr("Elements maître")); + m_master_elmt_qtwi->setCheckState(0, Qt::Checked); + m_qtwi_elmts.append(m_master_elmt_qtwi); + + m_slave_elmt_qtwi = new QTreeWidgetItem(m_elements_qtwi); + m_slave_elmt_qtwi->setText(0, tr("Elements esclave")); + m_slave_elmt_qtwi->setCheckState(0, Qt::Checked); + m_qtwi_elmts.append(m_slave_elmt_qtwi); + + m_report_elmt_qtwi = new QTreeWidgetItem(m_elements_qtwi); + m_report_elmt_qtwi->setText(0, tr("Elements report de folio")); + m_report_elmt_qtwi->setCheckState(0, Qt::Checked); + m_qtwi_elmts.append(m_report_elmt_qtwi); + + m_terminal_elmt_qtwi = new QTreeWidgetItem(m_elements_qtwi); + m_terminal_elmt_qtwi->setText(0, tr("Elements bornier")); + m_terminal_elmt_qtwi->setCheckState(0, Qt::Checked); + m_qtwi_elmts.append(m_terminal_elmt_qtwi); + m_category_qtwi.append(m_qtwi_elmts); + + m_conductor_qtwi = new QTreeWidgetItem(m_root_qtwi); + m_conductor_qtwi->setIcon(0, QET::Icons::ConductorSettings); + m_conductor_qtwi->setText(0, tr("Conducteurs")); + m_conductor_qtwi->setCheckState(0, Qt::Checked); + m_category_qtwi.append(m_conductor_qtwi); + + updateNextPreviousButtons(); +} + +/** + * @brief SearchAndReplaceWidget::setHideAdvanced + * Hide advanced widgets + * @param hide + */ +void SearchAndReplaceWidget::setHideAdvanced(bool hide) const +{ + ui->m_advanced_pb ->setChecked(!hide); + ui->m_replace ->setHidden(hide); + ui->m_replace_le ->setHidden(hide); + ui->m_mode ->setHidden(hide); + ui->m_mode_cb ->setHidden(hide); + ui->m_tree_widget ->setHidden(hide); + ui->m_replace_pb ->setHidden(hide); + ui->m_replace_all_pb->setHidden(hide); + QSize size = ui->m_v_spacer->sizeHint(); + ui->m_v_spacer->changeSize(size.width(), size.height(), QSizePolicy::Minimum, hide ? QSizePolicy::Expanding : QSizePolicy::Ignored); +} + +/** + * @brief SearchAndReplaceWidget::fillItemsList + * Fill the tree + */ +void SearchAndReplaceWidget::fillItemsList() +{ + disconnect(ui->m_tree_widget, &QTreeWidget::itemChanged, this, &SearchAndReplaceWidget::itemChanged); + + qDeleteAll(m_element_hash.keys()); + m_element_hash.clear(); + + QETProject *project_ = m_editor->currentProject(); + if (!project_) { + return; + } + + + DiagramContent dc; + for (Diagram *diagram : project_->diagrams()) { + dc += DiagramContent(diagram, false); + } + + for (Element *elmt : dc.m_elements) + addElement(elmt); + + //Sort child of each "element type" tree item. + //we hide, "element type" tree item, if they do not have children + for(QTreeWidgetItem *qtwi : m_qtwi_elmts) + { + qtwi->sortChildren(0, Qt::AscendingOrder); + qtwi->setHidden(qtwi->childCount() ? false : true); + } + + for (IndependentTextItem *iti : dc.m_text_fields) + { + QTreeWidgetItem *qtwi = new QTreeWidgetItem(m_indi_text_qtwi); + qtwi->setText(0, iti->toPlainText()); + qtwi->setCheckState(0, Qt::Checked); + m_text_hash.insert(qtwi, QPointer(iti)); + } + m_indi_text_qtwi->sortChildren(0, Qt::AscendingOrder); + + for (Conductor *c : dc.m_potential_conductors) + { + QTreeWidgetItem *qtwi = new QTreeWidgetItem(m_conductor_qtwi); + qtwi->setText(0, c->properties().text); + qtwi->setCheckState(0, Qt::Checked); + m_conductor_hash.insert(qtwi, QPointer(c)); + } + m_conductor_qtwi->sortChildren(0, Qt::AscendingOrder); + + updateNextPreviousButtons(); + connect(ui->m_tree_widget, &QTreeWidget::itemChanged, this, &SearchAndReplaceWidget::itemChanged); +} + +/** + * @brief SearchAndReplaceWidget::addElement + * Add a tree widget item for @element + * @param element + */ +void SearchAndReplaceWidget::addElement(Element *element) +{ + QTreeWidgetItem *parent = m_elements_qtwi; + switch (element->linkType()) { + case Element::Simple: + parent = m_simple_elmt_qtwi; + break; + case Element::NextReport: + parent = m_report_elmt_qtwi; + break; + case Element::PreviousReport: + parent = m_report_elmt_qtwi; + break; + case Element::Master: + parent = m_master_elmt_qtwi; + break; + case Element::Slave: + parent = m_slave_elmt_qtwi; + break; + case Element::Terminale: + parent = m_terminal_elmt_qtwi; + break; + default: + break; + } + QTreeWidgetItem *qtwi = new QTreeWidgetItem(parent); + m_element_hash.insert(qtwi, QPointer(element)); + + QString str; + str += element->elementInformations().value("label").toString(); + if(!str.isEmpty()) + str += (" "); + str += element->elementInformations().value("comment").toString(); + if (str.isEmpty()) + str = tr("Inconnue"); + qtwi->setText(0, str); + qtwi->setCheckState(0, Qt::Checked); +} + +/** + * @brief SearchAndReplaceWidget::search + * Start the search + */ +void SearchAndReplaceWidget::search() +{ + QString str = ui->m_search_le->text(); + if(str.isEmpty()) + { + for (QTreeWidgetItemIterator it(m_root_qtwi) ; *it ; ++it) { + (*it)->setHidden(false); + } + + for (QTreeWidgetItem *item : m_category_qtwi) { + item->setExpanded(false); + } + m_root_qtwi->setExpanded(true); + + ui->m_tree_widget->setCurrentItem(m_root_qtwi); + ui->m_search_le->setPalette(QPalette()); + } + else + { + for (QTreeWidgetItemIterator it(m_root_qtwi) ; *it ; ++it) { + (*it)->setHidden(true); + } + + bool match = false; + for(QTreeWidgetItem *qtwi : ui->m_tree_widget->findItems(str, Qt::MatchContains | Qt::MatchRecursive)) + { + match = true; + qtwi->setHidden(false); + setVisibleAllParents(qtwi); + } + + QPalette background = ui->m_search_le->palette(); + background.setColor(QPalette::Base, match ? QColor("#E0FFF0") : QColor("#FFE0EF")); + ui->m_search_le->setPalette(background); + + //Go to the first occurence + ui->m_tree_widget->setCurrentItem(m_root_qtwi); + on_m_next_pb_clicked(); + } +} + +/** + * @brief SearchAndReplaceWidget::setVisibleAllParents + * Set visible all parents of @item until the invisible root item + * @param item + * @param expend_parent + */ +void SearchAndReplaceWidget::setVisibleAllParents(QTreeWidgetItem *item, bool expend_parent) +{ + if (item->parent()) + { + QTreeWidgetItem *parent = item->parent(); + parent->setHidden(false); + setVisibleAllParents(parent); + parent->setExpanded(expend_parent); + } +} + +/** + * @brief SearchAndReplaceWidget::nextItem + * @param item : find the next item from @item, if @item is nullptr, start the search for the root of the tree + * @param flags + * @return the next item according to flag or nullptr if there is not a next item + */ +QTreeWidgetItem *SearchAndReplaceWidget::nextItem(QTreeWidgetItem *item, QTreeWidgetItemIterator::IteratorFlag flags) const +{ + QTreeWidgetItem *qtwi = item; + if (!item) { + qtwi = ui->m_tree_widget->currentItem(); + } + + if (!qtwi) { + qtwi = m_root_qtwi; + } + + QTreeWidgetItemIterator it(qtwi, flags); + + ++it; + QTreeWidgetItem *next_ = *it; + if (next_) { + return next_; + } + else { + return nullptr; + } +} + +/** + * @brief SearchAndReplaceWidget::previousItem + * @param item : find the previous item from @item, if @item is nullptr, start the search for the root of the tree + * @param flags + * @return the previous item according to flag or nullptr if there is not a previous item + */ +QTreeWidgetItem *SearchAndReplaceWidget::previousItem(QTreeWidgetItem *item, QTreeWidgetItemIterator::IteratorFlag flags) const +{ + QTreeWidgetItem *qtwi = item; + if (!item) { + qtwi = ui->m_tree_widget->currentItem(); + } + + if (!qtwi) { + qtwi = m_root_qtwi; + } + + QTreeWidgetItemIterator it(qtwi, flags); + + --it; + QTreeWidgetItem *previous_ = *it; + if (previous_) { + return previous_; + } + else { + return nullptr; + } +} + +/** + * @brief SearchAndReplaceWidget::updateNextPreviousButtons + * According to the current item, if there is a next or a previous item, + * we enable/disable the buttons next/previous item. + */ +void SearchAndReplaceWidget::updateNextPreviousButtons() +{ + QTreeWidgetItem *item_ = ui->m_tree_widget->currentItem(); + if (!item_) + { + ui->m_next_pb->setEnabled(true); + ui->m_previous_pb->setDisabled(true); + return; + } + + QTreeWidgetItem *next_ = item_; + do + { + next_ = nextItem(next_, QTreeWidgetItemIterator::NotHidden); + if (!next_) + { + ui->m_next_pb->setDisabled(true); + break; + } + else if (!m_category_qtwi.contains(next_)) + { + ui->m_next_pb->setEnabled(true); + break; + } + } while (m_category_qtwi.contains(next_)); + + QTreeWidgetItem *previous_ = item_; + do + { + previous_ = previousItem(previous_, QTreeWidgetItemIterator::NotHidden); + if (!previous_) + { + ui->m_previous_pb->setDisabled(true); + break; + } + else if (!m_category_qtwi.contains(previous_)) + { + ui->m_previous_pb->setEnabled(true); + break; + } + } while (m_category_qtwi.contains(previous_)); +} + +/** + * @brief SearchAndReplaceWidget::itemChanged + * Reimplemented from QTreeWidget. + * Use to update the check state of items. + * @param item + * @param column + */ +void SearchAndReplaceWidget::itemChanged(QTreeWidgetItem *item, int column) +{ + Q_UNUSED(column); + ui->m_tree_widget->blockSignals(true); + + setChildCheckState(item, item->checkState(0)); + updateParentCheckState(item); + + ui->m_tree_widget->blockSignals(false); +} + +/** + * @brief SearchAndReplaceWidget::setChildCheckState + * @param item : Parent of the items to be evaluated + * @param check : check state + * @param deep : if true, we evaluate every subchilds. + */ +void SearchAndReplaceWidget::setChildCheckState(QTreeWidgetItem *item, Qt::CheckState check, bool deep) +{ + for (int i=0 ; ichildCount() ; ++i) + { + item->child(i)->setCheckState(0, check); + if (deep && item->child(i)->childCount()) { + setChildCheckState(item->child(i), check, deep); + } + } +} + +/** + * @brief SearchAndReplaceWidget::updateParentCheckState + * @param item : a child item of the parent to be evaluated. + * @param all_parents : if true, we evaluate every parents, until the root item. + */ +void SearchAndReplaceWidget::updateParentCheckState(QTreeWidgetItem *item, bool all_parents) +{ + QTreeWidgetItem *parent = item->parent(); + + if (!parent) { + parent = item; + } + + int check=0, + partially=0; + + for (int i=0 ; ichildCount() ; ++i) + { + switch (parent->child(i)->checkState(0)) { + case Qt::Checked: + ++check; + break; + case Qt::PartiallyChecked: + ++partially; + break; + default: + break; + } + } + + if (check == parent->childCount()) { + parent->setCheckState(0, Qt::Checked); + } + else if (partially || check) { + parent->setCheckState(0, Qt::PartiallyChecked); + } + else { + parent->setCheckState(0, Qt::Unchecked); + } + + if (all_parents && item->parent()) { + updateParentCheckState(parent, all_parents); + } +} + +void SearchAndReplaceWidget::on_m_quit_button_clicked() { + this->setHidden(true); +} + +void SearchAndReplaceWidget::on_m_advanced_pb_toggled(bool checked) { + setHideAdvanced(!checked); +} + +void SearchAndReplaceWidget::on_m_tree_widget_itemDoubleClicked(QTreeWidgetItem *item, int column) +{ + Q_UNUSED(column); + + if (m_element_hash.keys().contains(item)) + { + QPointer elmt = m_element_hash.value(item); + if (elmt) { + elmt.data()->diagram()->showMe(); + } + } + else if (m_text_hash.keys().contains(item)) + { + QPointer text = m_text_hash.value(item); + if (text) { + text.data()->diagram()->showMe(); + } + } + else if (m_conductor_hash.keys().contains(item)) + { + QPointer cond = m_conductor_hash.value(item); + if (cond) { + cond.data()->diagram()->showMe(); + } + } +} + +void SearchAndReplaceWidget::on_m_reload_pb_clicked() +{ + clear(); + if (m_highlighted_element) + { + m_highlighted_element.data()->setHighlighted(false); + m_highlighted_element.clear(); + } + if (m_last_selected) + { + m_last_selected.data()->setSelected(false); + m_last_selected.clear(); + } + + ui->m_search_le->setFocus(); + fillItemsList(); + m_root_qtwi->setExpanded(true); +} + +void SearchAndReplaceWidget::on_m_tree_widget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) +{ + Q_UNUSED(previous); + + if(m_highlighted_element) { + m_highlighted_element.data()->setHighlighted(false); + } + if (m_last_selected) { + m_last_selected.data()->setSelected(false); + } + + if (m_element_hash.keys().contains(current)) + { + QPointer elmt = m_element_hash.value(current); + if (elmt) + { + m_highlighted_element = elmt; + elmt.data()->setHighlighted(true); + } + } + else if (m_text_hash.keys().contains(current)) + { + QPointer text = m_text_hash.value(current); + if (text) + { + text.data()->setSelected(true); + m_last_selected = text; + } + } + else if (m_conductor_hash.keys().contains(current)) + { + QPointer cond = m_conductor_hash.value(current); + if (cond) + { + cond.data()->setSelected(true); + m_last_selected = cond; + } + } + + updateNextPreviousButtons(); +} + +void SearchAndReplaceWidget::on_m_next_pb_clicked() +{ + QTreeWidgetItem *item = nullptr; + + do + { + item = nextItem(nullptr, QTreeWidgetItemIterator::NotHidden); + if (item) { + ui->m_tree_widget->setCurrentItem(item); + } else { + return; + } + } while (m_category_qtwi.contains(item)); + + ui->m_tree_widget->setCurrentItem(item); + ui->m_tree_widget->scrollToItem(item); + on_m_tree_widget_itemDoubleClicked(item, 0); +} + +void SearchAndReplaceWidget::on_m_previous_pb_clicked() +{ + QTreeWidgetItem *item = nullptr; + + do + { + item = previousItem(nullptr, QTreeWidgetItemIterator::NotHidden); + if (item) { + ui->m_tree_widget->setCurrentItem(item); + } + else + { + //There is not a previous selected item, so the current item is m_root_qtwi but we know he must not be selected + //we user click on the button 'next item'. + //So we select the first selectable item by calling on_m_next_pb_clicked + on_m_next_pb_clicked(); + return; + } + } while (m_category_qtwi.contains(item)); + + ui->m_tree_widget->setCurrentItem(item); + ui->m_tree_widget->scrollToItem(item); + on_m_tree_widget_itemDoubleClicked(item, 0); +} diff --git a/sources/SearchAndReplace/ui/searchandreplacewidget.h b/sources/SearchAndReplace/ui/searchandreplacewidget.h new file mode 100644 index 000000000..4de4b9574 --- /dev/null +++ b/sources/SearchAndReplace/ui/searchandreplacewidget.h @@ -0,0 +1,92 @@ +/* + Copyright 2006-2018 The QElectroTech Team + 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 . +*/ +#ifndef SEARCHANDREPLACEWIDGET_H +#define SEARCHANDREPLACEWIDGET_H + +#include +#include +#include "element.h" +#include "independenttextitem.h" + +class QTreeWidgetItem; + +namespace Ui { + class SearchAndReplaceWidget; +} + +class QETDiagramEditor; + +class SearchAndReplaceWidget : public QWidget +{ + Q_OBJECT + + public: + explicit SearchAndReplaceWidget(QWidget *parent = nullptr); + ~SearchAndReplaceWidget(); + + bool event(QEvent *event) override; + void clear(); + void setEditor(QETDiagramEditor *editor); + + private: + void setUpTreeItems(); + void setHideAdvanced(bool hide) const; + void fillItemsList(); + void addElement(Element *element); + void search(); + + void setVisibleAllParents(QTreeWidgetItem *item, bool expend_parent = true); + QTreeWidgetItem *nextItem(QTreeWidgetItem *item=nullptr, QTreeWidgetItemIterator::IteratorFlag flags = QTreeWidgetItemIterator::All) const; + QTreeWidgetItem *previousItem(QTreeWidgetItem *item=nullptr, QTreeWidgetItemIterator::IteratorFlag flags = QTreeWidgetItemIterator::All) const; + void updateNextPreviousButtons(); + void itemChanged(QTreeWidgetItem *item, int column); + void setChildCheckState(QTreeWidgetItem *item, Qt::CheckState check, bool deep = true); + void updateParentCheckState(QTreeWidgetItem *item, bool all_parents = true); + + private slots: + void on_m_quit_button_clicked(); + void on_m_advanced_pb_toggled(bool checked); + void on_m_tree_widget_itemDoubleClicked(QTreeWidgetItem *item, int column); + void on_m_reload_pb_clicked(); + void on_m_tree_widget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); + void on_m_next_pb_clicked(); + void on_m_previous_pb_clicked(); + + private: + Ui::SearchAndReplaceWidget *ui; + QETDiagramEditor *m_editor; + QTreeWidgetItem *m_root_qtwi = nullptr, + *m_folio_qtwi = nullptr, + *m_indi_text_qtwi = nullptr, + *m_elements_qtwi = nullptr, + *m_simple_elmt_qtwi = nullptr, + *m_master_elmt_qtwi = nullptr, + *m_slave_elmt_qtwi = nullptr, + *m_report_elmt_qtwi = nullptr, + *m_terminal_elmt_qtwi = nullptr, + *m_conductor_qtwi = nullptr; + QList m_qtwi_elmts; + QList m_category_qtwi; + QHash> m_element_hash; + QHash> m_text_hash; + QHash> m_conductor_hash; + QPointer m_highlighted_element; + QPointer m_last_selected; +}; + +#endif // SEARCHANDREPLACEWIDGET_H diff --git a/sources/SearchAndReplace/ui/searchandreplacewidget.ui b/sources/SearchAndReplace/ui/searchandreplacewidget.ui new file mode 100644 index 000000000..d5e5f81d3 --- /dev/null +++ b/sources/SearchAndReplace/ui/searchandreplacewidget.ui @@ -0,0 +1,236 @@ + + + SearchAndReplaceWidget + + + + 0 + 0 + 897 + 596 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Aller à la correspondance suivante + + + + + + + .. + + + false + + + + + + + true + + + true + + + false + + + + 1 + + + + + + + + Aller à la correspondance précédente + + + + + + + .. + + + false + + + + + + + Quitter + + + + + + + .. + + + false + + + + + + + + + true + + + + + + + Remplacer : + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Remplacer la correspondance séléctionner + + + Remplacer + + + + + + + Remplacer les correspondances coché + + + Tout remplacer + + + + + + + Mode : + + + + + + + + Texte brut + + + + + Mots entiers + + + + + + + + true + + + + + + + Chercher : + + + + + + + + + Avancé + + + + + + + :/ico/16x16/configure-toolbars.png:/ico/16x16/configure-toolbars.png + + + true + + + false + + + false + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/diagramcontent.cpp b/sources/diagramcontent.cpp index f05469659..c21488121 100644 --- a/sources/diagramcontent.cpp +++ b/sources/diagramcontent.cpp @@ -37,12 +37,20 @@ DiagramContent::DiagramContent() {} * @brief DiagramContent::DiagramContent * Constructor * @param diagram : Construct a diagramContent and fill it with the selected item of @diagram + * @param selected : this diagramcontent get only selected items if true. */ -DiagramContent::DiagramContent(Diagram *diagram) : +DiagramContent::DiagramContent(Diagram *diagram, bool selected) : m_selected_items(diagram->selectedItems()) { - //Get the selected items - for (QGraphicsItem *item : m_selected_items) + QList item_list; + if (selected) { + item_list = m_selected_items; + } else { + item_list = diagram->items(); + } + + + for (QGraphicsItem *item : item_list) { if (Element *elmt = qgraphicsitem_cast(item)) m_elements << elmt; @@ -55,6 +63,15 @@ DiagramContent::DiagramContent(Diagram *diagram) : !c->terminal2->parentItem()->isSelected()) { m_other_conductors << c; } + + if (m_potential_conductors.isEmpty()) { + m_potential_conductors << c; + } + else + { + if (!potentialIsManaged(c->relatedPotentialConductors(true).toList())) + m_potential_conductors << c; + } } else if (DiagramImageItem *dii = qgraphicsitem_cast(item)) m_images << dii; @@ -66,6 +83,7 @@ DiagramContent::DiagramContent(Diagram *diagram) : if(ElementTextItemGroup *etig = dynamic_cast(group)) m_texts_groups << etig; } + //For each selected element, we determine if conductors must be moved or updated. for(Element *elmt : m_elements) @@ -103,16 +121,14 @@ DiagramContent::DiagramContent(const DiagramContent &other) : m_conductors_to_update(other.m_conductors_to_update), m_conductors_to_move(other.m_conductors_to_move), m_other_conductors(other.m_other_conductors), + m_potential_conductors(other.m_potential_conductors), m_element_texts(other.m_element_texts), m_texts_groups(other.m_texts_groups), m_selected_items(other.m_selected_items) {} -/** - * @brief DiagramContent::~DiagramContent - */ -DiagramContent::~DiagramContent() {} - +DiagramContent::~DiagramContent() +{} /** * @brief DiagramContent::selectedTexts @@ -309,9 +325,36 @@ DiagramContent &DiagramContent::operator+=(const DiagramContent &other) if(!m_selected_items.contains(qgi)) m_selected_items << qgi; + for (Conductor *c : other.m_potential_conductors) + { + QList c_list = c->relatedPotentialConductors(true).toList(); + c_list << c; + if (!potentialIsManaged(c_list)) { + m_potential_conductors << c; + } + } + return *this; } +/** + * @brief DiagramContent::potentialIsManaged + * @param conductors a list of conductors at the same potential. + * @return true, if m_potential_conductors already have a conductor of this potential. + */ +bool DiagramContent::potentialIsManaged(QList conductors) +{ + bool b = false; + + for (Conductor *c : conductors) + { + if (m_potential_conductors.contains(c)) + b = true; + } + + return b; +} + /** * @brief DiagramContent::items * @param filter diff --git a/sources/diagramcontent.h b/sources/diagramcontent.h index feb6cefe0..2d1190b50 100644 --- a/sources/diagramcontent.h +++ b/sources/diagramcontent.h @@ -44,7 +44,7 @@ class DiagramContent { public: DiagramContent(); - DiagramContent(Diagram *diagram); + DiagramContent(Diagram *diagram, bool selected = true); DiagramContent(const DiagramContent &); ~DiagramContent(); @@ -71,6 +71,7 @@ class DiagramContent QList m_conductors_to_update; QList m_conductors_to_move; QList m_other_conductors; + QList m_potential_conductors; QSet m_element_texts; QSet m_texts_groups; QList m_selected_items; @@ -87,6 +88,7 @@ class DiagramContent int removeNonMovableItems(); DiagramContent& operator+=(const DiagramContent& other); + bool potentialIsManaged(QListconductors); }; QDebug &operator<<(QDebug, DiagramContent &); #endif diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 94b31fea5..8a52bbbf6 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -539,7 +539,7 @@ void DiagramView::keyPressEvent(QKeyEvent *e) if (m_event_interface && m_event_interface->keyPressEvent(e)) return; - ProjectView *current_project = this->diagramEditor()->acessCurrentProject(); + ProjectView *current_project = this->diagramEditor()->currentProjectView(); DiagramContent dc(m_diagram); switch(e -> key()) { diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 8a46b54a4..1fc052c33 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -72,8 +72,15 @@ QETDiagramEditor::QETDiagramEditor(const QStringList &files, QWidget *parent) : open_dialog_dir (QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)) { activeSubWindowIndex = 0; - //Setup the mdi area at center of application - setCentralWidget(&m_workspace); + + QSplitter *splitter_ = new QSplitter(this); + splitter_->setChildrenCollapsible(false); + splitter_->setOrientation(Qt::Vertical); + splitter_->addWidget(&m_workspace); + splitter_->addWidget(&m_search_and_replace_widget); + m_search_and_replace_widget.setHidden(true); + m_search_and_replace_widget.setEditor(this); + setCentralWidget(splitter_); //Set object name to be retrieved by the stylesheets m_workspace.setBackground(QBrush(Qt::NoBrush)); @@ -606,6 +613,12 @@ void QETDiagramEditor::setUpActions() connect(m_depth_action_group, &QActionGroup::triggered, [this](QAction *action) { this->currentDiagramView()->diagram()->changeZValue(action->data().value()); }); + + m_find = new QAction(tr("Chercher"), this); + m_find->setShortcut(QKeySequence::Find); + connect(m_find, &QAction::triggered, [this]() { + this->m_search_and_replace_widget.setHidden(!m_search_and_replace_widget.isHidden()); + }); } /** @@ -712,6 +725,8 @@ void QETDiagramEditor::setUpMenu() { menu_edition -> addActions(m_row_column_actions_group.actions()); menu_edition -> addSeparator(); menu_edition -> addActions(m_depth_action_group->actions()); + menu_edition -> addSeparator(); + menu_edition -> addAction(m_find); // menu Projet menu_project -> addAction(m_project_edit_properties); @@ -1095,6 +1110,22 @@ ProjectView *QETDiagramEditor::currentProjectView() const { return(nullptr); } +/** + * @brief QETDiagramEditor::currentProject + * @return the current edited project. + * This function can return nullptr. + */ +QETProject *QETDiagramEditor::currentProject() const +{ + ProjectView *view = currentProjectView(); + if (view) { + return view->project(); + } + else { + return nullptr; + } +} + /** @return Le schema actuellement edite (= l'onglet ouvert dans le projet courant) ou 0 s'il n'y en a pas @@ -1675,23 +1706,6 @@ ProjectView *QETDiagramEditor::viewForFile(const QString &filepath) const { return(nullptr); } -/** - * @brief QETDiagramEditor::acessCurrentProject - * Retrieve current Project open in diagram editor - */ -ProjectView *QETDiagramEditor::acessCurrentProject (){ - QMdiSubWindow *current_window = m_workspace.activeSubWindow(); - if (!current_window) return(nullptr); - - QWidget *current_widget = current_window -> widget(); - if (!current_widget) return(nullptr); - - if (ProjectView *project_view = qobject_cast(current_widget)) { - return(project_view); - } - return(nullptr); -} - /** * @brief QETDiagramEditor::drawGrid * @return true if the grid of folio must be displayed @@ -1700,17 +1714,6 @@ bool QETDiagramEditor::drawGrid() const { return m_draw_grid->isChecked(); } -/** - * @brief QETDiagramEditor::acessCurrentDiagramView - * Retrieve current DiagramView used in diagram editor - */ -DiagramView *QETDiagramEditor::acessCurrentDiagramView () { - if (ProjectView *project_view = currentProjectView()) { - return(project_view -> currentDiagram()); - } - return(nullptr); -} - /** met a jour le menu "Fenetres" */ diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 2a5755f35..3dc46e145 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -25,6 +25,7 @@ #include #include "qetmainwindow.h" +#include "searchandreplacewidget.h" class QMdiSubWindow; class QETProject; @@ -63,8 +64,8 @@ class QETDiagramEditor : public QETMainWindow bool openAndAddProject (const QString &, bool = true); QList editedFiles () const; ProjectView *viewForFile (const QString &) const; - ProjectView *acessCurrentProject (); - DiagramView *acessCurrentDiagramView (); + ProjectView *currentProjectView() const; + QETProject *currentProject() const; bool drawGrid() const; protected: @@ -81,7 +82,6 @@ class QETDiagramEditor : public QETMainWindow void setUpMenu (); bool addProject(QETProject *, bool = true); - ProjectView *currentProjectView() const; DiagramView *currentDiagramView() const; Element *currentElement() const; ProjectView *findProject(DiagramView *) const; @@ -197,6 +197,7 @@ class QETDiagramEditor : public QETMainWindow QAction *m_close_file; ///< Close current project file QAction *m_save_file; ///< Save current project QAction *m_save_file_as; ///< Save current project as a specific file + QAction *m_find = nullptr; QMdiArea m_workspace; QSignalMapper windowMapper; @@ -221,5 +222,6 @@ class QETDiagramEditor : public QETMainWindow AutoNumberingDockWidget *m_autonumbering_dock; int activeSubWindowIndex; bool m_first_show = true; + SearchAndReplaceWidget m_search_and_replace_widget; }; #endif diff --git a/sources/ui/masterpropertieswidget.cpp b/sources/ui/masterpropertieswidget.cpp index 3746e8e70..f57f17370 100644 --- a/sources/ui/masterpropertieswidget.cpp +++ b/sources/ui/masterpropertieswidget.cpp @@ -79,7 +79,7 @@ MasterPropertiesWidget::MasterPropertiesWidget(Element *elmt, QWidget *parent) : QHeaderView *qhv = ui->m_free_tree_widget->header(); qhv->setContextMenuPolicy(Qt::CustomContextMenu); connect(qhv, &QHeaderView::customContextMenuRequested, this, &MasterPropertiesWidget::headerCustomContextMenuRequested); - connect(m_save_header_state, &QAction::triggered, [this, qhv]() + connect(m_save_header_state, &QAction::triggered, [qhv]() { QByteArray qba = qhv->saveState(); QSettings settings;