/** * @RDE_HEADER@ * ComboBox's popup, optimized for tablets (bigger dropdown/popup) * $Id$ * $HeadURL$ * $Author$ * * Created by Mike Wille, SLSE, 2016-03-09 */ #include "lts_selection_popup.h" #include "ui_lts_selection_popup.h" #include "lts_base.h" #include #include #include #include //#define NEVER #ifdef NEVER # include #endif // NEVER namespace LtsWidgets { class RadioButton : public QRadioButton { Q_OBJECT public: explicit RadioButton(int row, const QString &text) : QRadioButton(text) , m_row(row) {} int row() const { return m_row; } signals: void doubleClickEvent(); private: int m_row; void mouseDoubleClickEvent(QMouseEvent *) override { emit doubleClickEvent(); } }; LtsSelectionPopup::LtsSelectionPopup(QAbstractItemModel* model, int currentIndex, QWidget *parent) : LtsFramelessDialog(parent, Behaviour::Popup) , m_ui(new Ui::LtsSelectionPopup) // TODO: morph .ui to QDialog (is QWidget) , m_currentIndex(currentIndex) , m_firstIndex(currentIndex) , m_filter(new QSortFilterProxyModel(this)) , m_valid(false) { m_ui->setupUi(this); // i am sorry for this solution, but qlistview's are so unthankfully to work with m_filter->setSourceModel(model); m_filter->setFilterCaseSensitivity(Qt::CaseInsensitive); slotFilterChanged(); #ifdef TABLET_MODE m_ui->leSearch->setVisible(false); m_ui->label->setVisible(false); #endif connect(m_ui->pbCancel, &QPushButton::clicked, this, &LtsSelectionPopup::reject); connect(m_ui->pbSelect, &QPushButton::clicked, this, &LtsSelectionPopup::accept); connect(m_ui->leSearch, &QLineEdit::textEdited, this, &LtsSelectionPopup::slotFilterChanged); #ifdef NEVER // debugging : // // highlighted -> UserInteraction // connect(this, static_cast(&LtsSelectionPopup::highlighted), this, [](int idx){ // qCritical() << " called: highlighted(int)"; // }); // currentIndexChanged -> programmatically & UserInteraction connect(this, static_cast(&LtsSelectionPopup::currentIndexChanged), this, [](int idx){ qCritical() << " LtsSelectionPopup: called: currentIndexChanged(int), idx=" << idx; }); // activated -> UserInteraction connect(this, static_cast(&LtsSelectionPopup::activated), this, [](int idx){ qCritical() << " LtsSelectionPopup: called: activated(int), idx=" << idx; }); // : debugging #endif // NEVER } LtsSelectionPopup::~LtsSelectionPopup() { delete m_ui; } void LtsSelectionPopup::slotFilterChanged() { m_filter->setFilterWildcard(m_ui->leSearch->text().count() ? m_ui->leSearch->text() : QStringLiteral("*") /* show everything if nothing was entered */); refresh(); } void LtsSelectionPopup::refresh() { m_valid = false; // invalidate, none selected as all deleted qDeleteAll(m_ui->itemLayoutWidget->findChildren()); // delete all RBs QLayoutItem *tem = nullptr; if (m_ui->itemLayoutWidget->layout()->count() > 0) { tem = m_ui->itemLayoutWidget->layout()->takeAt(0); } int count = m_filter->rowCount(); for (int i = 0; i < count; i++) { int realRow = m_filter->mapToSource(m_filter->index(i, 0)).row(); RadioButton *rbItem = new RadioButton(realRow, m_filter->data(m_filter->index(i, 0)).toString()); int disable = m_filter->data(m_filter->index(i, 0), Qt::UserRole-1).toInt(); if (disable == 1) rbItem->setEnabled(false); m_ui->itemLayoutWidget->layout()->addWidget(rbItem); if (realRow == m_currentIndex) { rbItem->setChecked(true); m_valid = true; } connect(rbItem, &RadioButton::doubleClickEvent, this, &LtsSelectionPopup::accept); // is always selected then.. connect(rbItem, &RadioButton::toggled, this, [this](bool checked) { if (checked) m_ui->pbSelect->setEnabled(true); }); } if (tem) m_ui->itemLayoutWidget->layout()->addItem(tem); if (count == 1) // if there is only one item, then allow the user to click Select (or pressing enter) to select the only item available m_valid = true; m_ui->pbSelect->setEnabled(m_valid); } void LtsSelectionPopup::showEvent(QShowEvent *event) { LtsFramelessDialog::showEvent(event); m_ui->leSearch->setFocus(); resize(sizeHint().width() + m_ui->scrollArea->horizontalScrollBar()->height() , sizeHint().height()); } void LtsSelectionPopup::selectItem(int row, bool bCurrentIndexChanged, bool bActivated) { // order of signals (like Qt 5.9): 1st: currentIndexChanged 2nd: activated if (bCurrentIndexChanged) emit currentIndexChanged(row); if (bActivated) emit activated(row); m_ui->pbSelect->setEnabled(true); LtsFramelessDialog::accept(); // only accept if one item is selected } void LtsSelectionPopup::accept() { const QList items = m_ui->itemLayoutWidget->findChildren(); int count = items.count(); for (int i = 0; i < count; i++) { const RadioButton *rb = items.at(i); if (rb->isChecked()) { int realRow = m_filter->mapToSource(m_filter->index(i, 0)).row(); bool bCurrentIndexChanged = realRow != m_firstIndex; // currentIndex has changed? bool bActivated = true; selectItem(realRow, bCurrentIndexChanged, bActivated); // & closes dialog return; // no need to go further } } // okay, nothing was selected, is there only one item available? if yes, select it and accept if (count == 1) { const RadioButton *rb = items.at(0); selectItem(rb->row(), true, true); // item was not selected before, so it must also be emitted as "activated" // & closes dialog return; // no need to go further } // none selected and multiple choises? ignore.. } } // namespace LtsWidgets #include "lts_selection_popup.moc"