/** * @RDE_HEADER@ * GUI Plugin for ParticipantManagement - Participant Edit * $Id$ * $HeadURL$ * $Author$ * Created by Patric Karwat, SLSE, 2016-10-17 */ #include "participant_selection.h" //#include "participant_selection_model.h" #include "ui_participant_selection.h" #include #include #include #include #include #include #include #include //#include #include #include #include #include #include #include #include #include #include namespace ParticipantManagement { int ParticipantSelection::s_preselectedParty = 2; ParticipantSelection::ParticipantSelection(LtsSession::LtsSession *session, QWidget *parent) : LtsWidgets::LtsFramelessDialog(parent, LtsWidgets::Behaviour::Modal) , m_dtc(nullptr) , m_ppmGuiCbxIfc(nullptr) , m_session(session) , m_ui(new Ui::ParticipantSelection) , m_logger(getLogger("ParticipantSelection")) { m_ui->setupUi(this); // this will make the tree view look like a table m_ui->tableViewSelection->treeView()->setIndentation(0); m_ui->tableViewSelection->treeView()->setItemsExpandable(false); // add buttons to switch between a tree view and a table view connect(m_ui->pbTreeView, &QPushButton::clicked, this, &ParticipantSelection::onSwitchToTreeView); connect(m_ui->pbTableView, &QPushButton::clicked, this, &ParticipantSelection::onSwitchToTableView); m_ui->treeViewSelection->treeView()->setContextMenuPolicy(Qt::CustomContextMenu); m_ui->tableViewSelection->treeView()->setContextMenuPolicy(Qt::CustomContextMenu); setStyleSheet(QStringLiteral("QToolTip { background-color: #ffffff; }")); } ParticipantSelection::~ParticipantSelection() { delete m_ui; } bool ParticipantSelection::init() { if (!m_session->getDtc(m_dtc)) return false; if (!m_session->getForeignGuiInterface(m_ppmGuiCbxIfc)) return false; m_session->getForeignDataInterface(m_asb); connect(m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Ok), &QPushButton::clicked, this, &ParticipantSelection::accept); connect(m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Close), &QPushButton::clicked, this, &ParticipantSelection::reject); // interfaces ............................................................................................................... if (!m_dtc || !m_ppmGuiCbxIfc) return false; // tree model ............................................................................................................... m_model = new ParticipantEditModel(this, m_dtc, m_asb); // connect(m_model, &ParticipantSelectionModel::internalDataChanged, this, &ParticipantSelection::slotChangesMade); // proxy model for the tree view ............................................................................................ m_proxyTree = new ParticipantTreeFilterProxyModel(this); m_proxyTree->setSourceModel(m_model); m_ui->treeViewSelection->setModel(m_proxyTree); m_ui->treeViewSelection->setContextMenuPolicy(Qt::CustomContextMenu); #ifndef LTS_DEBUG m_ui->treeViewSelection->setColumnHidden(ParticipantEditModel::ColParticipantId, true); #endif // proxy model for the table view ........................................................................................... m_proxyTable = new ParticipantTableFilterProxyModel(this); m_proxyTable->setSourceModel(m_model); connect(m_ui->tableViewSelection, &LtsDataView::LtsDataView::filterChanged, m_proxyTable, &ParticipantTableFilterProxyModel::onFilter); connect(m_ui->tableViewSelection, &LtsDataView::LtsDataView::sortOrderChanged, this, &ParticipantSelection::onSortTableView); connect(m_model, &ParticipantEditModel::internalDataChanged, m_proxyTable, &ParticipantTableFilterProxyModel::init); connect(m_ui->tableViewSelection, &LtsDataView::LtsDataView::doubleClicked, this, &ParticipantSelection::accept); connect(m_ui->treeViewSelection, &LtsDataView::LtsDataView::doubleClicked, this, &ParticipantSelection::accept); m_ui->tableViewSelection->setModel(m_proxyTable); m_ui->tableViewSelection->setContextMenuPolicy(Qt::CustomContextMenu); #ifndef LTS_DEBUG m_ui->tableViewSelection->setColumnHidden(ParticipantEditModel::ColParticipantId, true); #endif // party combo box .......................................................................................................... connect(m_ui->cbParty, static_cast(&LtsWidgets::LtsComboBox::currentIndexChanged), this, &ParticipantSelection::onPartyChanged); // This is a direct connection as the receiver lives in this same thread. m_ppmGuiCbxIfc->fillPartyComboBox(m_ui->cbParty, ForeignGuiComboboxInterface::CbxPartyFilter::NormalPool); // // tree handler ............................................................................................................. // m_pTreehandler = new ParticipantTreeEditHandler(m_ui->treeViewSelection, m_dtc, nullptr, false, this); // connect(m_pTreehandler, &ParticipantTreeEditHandler::signalSelectionChanged, this, &ParticipantSelection::onEnaDisa); // connect(m_ui->tableViewSelection->treeView(), &QTreeView::customContextMenuRequested, // m_pTreehandler, &ParticipantTreeEditHandler::showContextMenu); // .......................................................................................................................... const int idx = m_ui->cbParty->findData(s_preselectedParty); if (idx >= 0) m_ui->cbParty->setCurrentIndex(idx); // synchronize tree view and table view ..................................................................................... // filtering connect(m_ui->treeViewSelection, &LtsDataView::LtsDataView::filterChanged, this, [this](){ onFilterChanged(m_ui->treeViewSelection->searchModel(), m_ui->tableViewSelection->searchModel()); }); connect(m_ui->tableViewSelection, &LtsDataView::LtsDataView::filterChanged, this, [this](){ onFilterChanged(m_ui->tableViewSelection->searchModel(), m_ui->treeViewSelection->searchModel()); }); // selection connect(m_ui->treeViewSelection, &LtsDataView::LtsDataView::selectionChanged, this, &ParticipantSelection::onSelectionChangedInTree); connect(m_ui->tableViewSelection, &LtsDataView::LtsDataView::selectionChanged, this, &ParticipantSelection::onSelectionChangedInTable); // column width connect(m_ui->treeViewSelection->searchView()->header(), &QHeaderView::sectionResized, this, [this](int column, int oldWidth, int newWidth) { Q_UNUSED(oldWidth); onColumnWidthChanged(m_ui->tableViewSelection->searchView(), column, newWidth); }); connect(m_ui->tableViewSelection->searchView()->header(), &QHeaderView::sectionResized, this, [this](int column, int oldWidth, int newWidth) { Q_UNUSED(oldWidth); onColumnWidthChanged(m_ui->treeViewSelection->searchView(), column, newWidth); }); // .......................................................................................................................... m_model->setUnitsSelectable(false); onSwitchToTreeView(); onPartyChanged(); onEnaDisa(); return true; } void ParticipantSelection::setMultiSelectionEnabled(bool enabled) { if (enabled) { m_ui->treeViewSelection->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection); m_ui->tableViewSelection->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection); } else { m_ui->treeViewSelection->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); m_ui->tableViewSelection->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection); } } void ParticipantSelection::setParticipantSelected(int partyId, int participantId) { if (participantId <= 0) return; m_ui->cbParty->setCurrentIndex(m_ui->cbParty->findData(partyId)); // As the slot that update the table/tree is a DirectConnection, we can go on here and will find the index. const QModelIndex index = m_model->indexFromParticipantId(participantId); onSelectionChangedInTable(QItemSelection(index, index),{}); onSelectionChangedInTree(QItemSelection(index, index),{}); } //void ParticipantSelection::retranslate() //{ // translate(m_ui, tr("Select Participants")); //} void ParticipantSelection::accept() { QModelIndexList indexList = m_ui->tableViewSelection->selectionModel()->selectedIndexes(); if (indexList.isEmpty()) return; LtsWidgets::LtsFramelessDialog::accept(); m_proxyTable->resetMapping(); m_proxyTable->init(); QVector participantIds; participantIds.reserve(indexList.size()); for (const auto &index : qAsConst(indexList)) { QModelIndex sourceIndex = m_proxyTable->mapToSource(index); if (index.column() != 0) continue; participantIds << m_model->privateData(sourceIndex)->participant.id(); } emit selectedParticipants(participantIds); } void ParticipantSelection::onPartyChanged() { const int newPartyId = m_ui->cbParty->currentData().toInt(); s_preselectedParty = newPartyId; m_proxyTable->resetMapping(); m_proxyTable->disableSorting(); if (m_model->onReinitModel(newPartyId)) { m_ui->treeViewSelection->expandAll(); m_ui->treeViewSelection->resizeHeadersByContent(); } m_proxyTable->init(); // Some icons in the table view won't update automatically after initialization (maybe a timing issue?). // Workaround: emit dataChanged on the first items (up to 50 rows, since more will not be visible after reinit) // with a slight delay of 100 msecs to force an update. QTimer *timer = new QTimer(this); timer->singleShot(100, this, [this, timer]() { m_ui->tableViewSelection->treeView()->dataChanged ( m_proxyTable->index(0, 0), m_proxyTable->index(std::min(50, m_proxyTable->rowCount()), 0), { Qt::DecorationRole } ); timer->deleteLater(); }); } void ParticipantSelection::onChangesMade() { onEnaDisa(); if (m_model->onReinitModel(s_preselectedParty)) beautifyTreeView(m_ui->treeViewSelection->treeView(), m_model, true); } void ParticipantSelection::onBeautifyTreeView() { beautifyTreeView(m_ui->treeViewSelection->treeView(), m_model, true); } void ParticipantSelection::onEnaDisa() { // OK only enabled if there's at least one item selected. } void ParticipantSelection::onSwitchToTreeView() { m_ui->pbTreeView->setEnabled(false); m_ui->pbTableView->setEnabled(true); m_ui->tableViewSelection->hide(); m_ui->treeViewSelection->show(); m_ui->treeViewSelection->expandAll(); if (!m_ui->treeViewSelection->selectionModel()->selectedIndexes().isEmpty()) // scroll to selection { const QModelIndex &proxyIndex = m_ui->treeViewSelection->selectionModel()->selectedIndexes().first(); m_ui->treeViewSelection->scrollTo(proxyIndex); } // if onEnaDisa(); } void ParticipantSelection::onSwitchToTableView() { m_ui->pbTreeView->setEnabled(true); m_ui->pbTableView->setEnabled(false); m_ui->treeViewSelection->hide(); m_ui->tableViewSelection->show(); if (!m_ui->tableViewSelection->selectionModel()->selectedIndexes().isEmpty()) // scroll to selection { const QModelIndex &proxyIndex = m_ui->tableViewSelection->selectionModel()->selectedIndexes().first(); m_ui->tableViewSelection->scrollTo(proxyIndex); } // if onEnaDisa(); } void ParticipantSelection::onSelectionChangedInTree(const QItemSelection &selected, const QItemSelection &deselected) { m_ui->tableViewSelection->blockSignals(true); QModelIndexList indexes = deselected.indexes(); for (const QModelIndex &sourceIndex : qAsConst(indexes)) { QModelIndex proxyIndex = m_proxyTable->mapFromSource(sourceIndex); if (m_ui->tableViewSelection->selectionModel()->selectedIndexes().contains(proxyIndex)) m_ui->tableViewSelection->selectionModel()->select(proxyIndex, { QItemSelectionModel::Deselect, QItemSelectionModel::Rows }); } // for indexes = selected.indexes(); for (const QModelIndex &sourceIndex : qAsConst(indexes)) { QModelIndex proxyIndex = m_proxyTable->mapFromSource(sourceIndex); if (!m_ui->tableViewSelection->selectionModel()->selectedIndexes().contains(proxyIndex)) m_ui->tableViewSelection->selectionModel()->select(proxyIndex, { QItemSelectionModel::Select, QItemSelectionModel::Rows }); } // for m_ui->tableViewSelection->blockSignals(false); m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(m_ui->treeViewSelection->selectedRows().count() > 0); } void ParticipantSelection::onSelectionChangedInTable(const QItemSelection &selected, const QItemSelection &deselected) { m_ui->treeViewSelection->blockSignals(true); QModelIndexList indexes = deselected.indexes(); for (const QModelIndex &sourceIndex : qAsConst(indexes)) { QModelIndex proxyIndex = m_proxyTree->mapFromSource(sourceIndex); if (m_ui->treeViewSelection->selectionModel()->selectedIndexes().contains(proxyIndex)) m_ui->treeViewSelection->selectionModel()->select(proxyIndex, { QItemSelectionModel::Deselect, QItemSelectionModel::Rows }); } // for indexes = selected.indexes(); for (const QModelIndex &sourceIndex : qAsConst(indexes)) { QModelIndex proxyIndex = m_proxyTree->mapFromSource(sourceIndex); if (!m_ui->treeViewSelection->selectionModel()->selectedIndexes().contains(proxyIndex)) m_ui->treeViewSelection->selectionModel()->select(proxyIndex, { QItemSelectionModel::Select, QItemSelectionModel::Rows }); } // for m_ui->treeViewSelection->blockSignals(false); m_ui->ltsDialogButtonBox->getButton(LtsWidgets::DialogButton::Ok)->setEnabled(m_ui->tableViewSelection->selectedRows().count() > 0); } void ParticipantSelection::onFilterChanged(LtsDataView::SearchModel *from, LtsDataView::SearchModel *to) { for (int column = 0; column < to->columnCount(); ++column) { QModelIndex fromIndex = from->index(0, column, QModelIndex()); QModelIndex toIndex = to->index(0, column, QModelIndex()); QVariant columnFilter = from->data(fromIndex, Qt::EditRole); QVariant comboBoxData = from->data(fromIndex, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole); if (columnFilter != to->data(toIndex, Qt::EditRole)) { to->setData(toIndex, columnFilter, Qt::EditRole); to->setData(toIndex, from->data(fromIndex, Qt::DisplayRole).toString(), Qt::DisplayRole); } // if else if (comboBoxData != to->data(toIndex, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole)) { to->setData(toIndex, comboBoxData, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole); LtsWidgets::ComboboxFilterContent comboFilterContent = LtsWidgets::ComboboxFilterContent::fromVariant( m_model->headerData(column, Qt::Horizontal, LtsWidgets::LtsColumnFilterProxyModel::ComboboxFilterRole) ); if (comboBoxData.toInt() == 0) { to->setData(toIndex, tr(""), Qt::DisplayRole); } // if else { for (const LtsWidgets::ComboboxFilterData &data : qAsConst(comboFilterContent.data)) if (data.data == comboBoxData) { to->setData(toIndex, data.text, Qt::DisplayRole); break; } // if } // else } // else if } // for // undo selection m_ui->tableViewSelection->blockSignals(true); m_ui->tableViewSelection->selectionModel()->clearSelection(); m_ui->tableViewSelection->blockSignals(false); m_ui->treeViewSelection->blockSignals(true); m_ui->treeViewSelection->selectionModel()->clearSelection(); m_ui->treeViewSelection->blockSignals(false); } void ParticipantSelection::onSortTableView(int column, Qt::SortOrder order) { QModelIndex sourceIndex; if (!m_ui->treeViewSelection->selectionModel()->selectedIndexes().isEmpty()) // store selected item { QModelIndex proxyIndex = m_ui->tableViewSelection->selectionModel()->selectedIndexes().first(); sourceIndex = m_proxyTable->mapToSource(proxyIndex); m_ui->tableViewSelection->blockSignals(true); m_ui->tableViewSelection->selectionModel()->select(proxyIndex, { QItemSelectionModel::Deselect, QItemSelectionModel::Rows }); m_ui->tableViewSelection->blockSignals(false); } // if m_proxyTable->onSort(column, order); if (sourceIndex != QModelIndex()) // reselect item with new index { QModelIndex proxyIndex = m_proxyTable->mapFromSource(sourceIndex); m_ui->tableViewSelection->blockSignals(true); m_ui->tableViewSelection->selectionModel()->select(proxyIndex, { QItemSelectionModel::Select, QItemSelectionModel::Rows }); m_ui->tableViewSelection->blockSignals(false); m_ui->tableViewSelection->scrollTo(proxyIndex); } // if } void ParticipantSelection::onColumnWidthChanged(QTreeView *to, const int &column, const int &width) { if (to->columnWidth(column) != width) to->setColumnWidth(column, width); } } //namespace ParticipantManagement