#include "multiselectcombobox.h" #include #include #include MultiSelectComboBox::MultiSelectComboBox(QWidget *parent) : QComboBox(parent) , suppressUpdate(false) { model = new QStandardItemModel(this); setModel(model); // Use list view for better checkbox display QListView *listView = new QListView(this); setView(listView); // Create a line edit to display the text (read-only) displayLabel = new QLineEdit(this); displayLabel->setReadOnly(true); setLineEdit(displayLabel); // Install event filter to keep popup open on click view()->viewport()->installEventFilter(this); connect(view(), &QAbstractItemView::pressed, this, &MultiSelectComboBox::onItemPressed); } void MultiSelectComboBox::addItem(const QString &text) { // First item is "Select All" if (model->rowCount() == 0) { QStandardItem *selectAllItem = new QStandardItem("Select All"); selectAllItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); selectAllItem->setData(Qt::Checked, Qt::CheckStateRole); selectAllItem->setData(true, Qt::UserRole); // Mark as "Select All" item model->appendRow(selectAllItem); } QStandardItem *item = new QStandardItem(text); item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); item->setData(Qt::Checked, Qt::CheckStateRole); item->setData(false, Qt::UserRole); // Regular item model->appendRow(item); } void MultiSelectComboBox::addItems(const QStringList &texts) { for (const QString &text : texts) { addItem(text); } updateText(); } QStringList MultiSelectComboBox::getSelectedItems() const { QStringList selected; for (int i = 1; i < model->rowCount(); ++i) { // Skip "Select All" at index 0 QStandardItem *item = model->item(i); if (item && item->checkState() == Qt::Checked) { selected.append(item->text()); } } return selected; } void MultiSelectComboBox::setSelectedItems(const QStringList &items) { suppressUpdate = true; for (int i = 1; i < model->rowCount(); ++i) { // Skip "Select All" at index 0 QStandardItem *item = model->item(i); if (item) { bool shouldCheck = items.contains(item->text()); item->setCheckState(shouldCheck ? Qt::Checked : Qt::Unchecked); } } // Update "Select All" checkbox if (model->rowCount() > 1) { QStandardItem *selectAllItem = model->item(0); if (selectAllItem) { selectAllItem->setCheckState(allSelected() ? Qt::Checked : Qt::Unchecked); } } suppressUpdate = false; updateText(); } bool MultiSelectComboBox::allSelected() const { for (int i = 1; i < model->rowCount(); ++i) { // Skip "Select All" at index 0 QStandardItem *item = model->item(i); if (item && item->checkState() == Qt::Unchecked) { return false; } } return model->rowCount() > 1; } void MultiSelectComboBox::clear() { model->clear(); QComboBox::clear(); } void MultiSelectComboBox::hidePopup() { // Don't hide on item click - only when clicking outside QComboBox::hidePopup(); updateText(); emit selectionChanged(); } bool MultiSelectComboBox::eventFilter(QObject *watched, QEvent *event) { if (watched == view()->viewport()) { if (event->type() == QEvent::MouseButtonRelease) { return true; // Prevent popup from closing } } return QComboBox::eventFilter(watched, event); } void MultiSelectComboBox::onItemPressed(const QModelIndex &index) { QStandardItem *item = model->itemFromIndex(index); if (item) { // Check if this is the "Select All" item bool isSelectAll = item->data(Qt::UserRole).toBool(); if (isSelectAll) { // Toggle all items Qt::CheckState newState = (item->checkState() == Qt::Checked) ? Qt::Unchecked : Qt::Checked; suppressUpdate = true; for (int i = 0; i < model->rowCount(); ++i) { QStandardItem *childItem = model->item(i); if (childItem) { childItem->setCheckState(newState); } } suppressUpdate = false; } else { // Toggle individual item Qt::CheckState newState = (item->checkState() == Qt::Checked) ? Qt::Unchecked : Qt::Checked; item->setCheckState(newState); // Update "Select All" state if (model->rowCount() > 1) { QStandardItem *selectAllItem = model->item(0); if (selectAllItem) { selectAllItem->setCheckState(allSelected() ? Qt::Checked : Qt::Unchecked); } } } updateText(); } } void MultiSelectComboBox::updateText() { if (suppressUpdate) return; QStringList selected = getSelectedItems(); if (selected.isEmpty()) { displayLabel->setText("No Accounts"); } else if (allSelected()) { displayLabel->setText("All Accounts"); } else if (selected.size() == 1) { displayLabel->setText(selected.first()); } else { displayLabel->setText(QString("%1 Accounts Selected").arg(selected.size())); } }