File indexing completed on 2022-09-27 16:29:12

0001 /**
0002  * SPDX-FileCopyrightText: (C) 2003 by Sébastien Laoût <slaout@linux62.org>
0003  * SPDX-License-Identifier: GPL-2.0-or-later
0004  */
0005 
0006 #include "filter.h"
0007 
0008 #include <QDialog>
0009 #include <QHBoxLayout>
0010 #include <QLabel>
0011 #include <QLineEdit>
0012 #include <QLocale>
0013 #include <QToolButton>
0014 #include <QtGui/QPixmap>
0015 
0016 #include <KComboBox>
0017 #include <KIconLoader>
0018 #include <KLocalizedString>
0019 
0020 #include "bnpview.h"
0021 #include "focusedwidgets.h"
0022 #include "global.h"
0023 #include "tag.h"
0024 #include "tools.h"
0025 
0026 /** FilterBar */
0027 
0028 FilterBar::FilterBar(QWidget *parent)
0029     : QWidget(parent) /*, m_blinkTimer(this), m_blinkedTimes(0)*/
0030 {
0031     QHBoxLayout *hBox = new QHBoxLayout(this);
0032 
0033     // Create every widgets:
0034     // (Aaron Seigo says we don't need to worry about the
0035     //  "Toolbar group" stuff anymore.)
0036 
0037     QIcon resetIcon = QIcon::fromTheme("dialog-close");
0038     QIcon inAllIcon = QIcon::fromTheme("edit-find");
0039 
0040     m_resetButton = new QToolButton(this);
0041     m_resetButton->setIcon(resetIcon);
0042     m_resetButton->setText(i18n("Reset Filter")); //, /*groupText=*/QString(), this, SLOT(reset()), 0);
0043     m_resetButton->setAutoRaise(true);
0044     // new KToolBarButton("locationbar_erase", /*id=*/1230, this, /*name=*/0, i18n("Reset Filter"));
0045     m_lineEdit = new QLineEdit(this);
0046     QLabel *label = new QLabel(this);
0047     label->setText(i18n("&Filter: "));
0048     label->setBuddy(m_lineEdit);
0049     m_tagsBox = new KComboBox(this);
0050     QLabel *label2 = new QLabel(this);
0051     label2->setText(i18n("T&ag: "));
0052     label2->setBuddy(m_tagsBox);
0053     m_inAllBasketsButton = new QToolButton(this);
0054     m_inAllBasketsButton->setIcon(inAllIcon);
0055     m_inAllBasketsButton->setText(i18n("Filter All Baskets")); //, /*groupText=*/QString(), this, SLOT(inAllBaskets()), 0);
0056     m_inAllBasketsButton->setAutoRaise(true);
0057 
0058     // Configure the Tags combobox:
0059     repopulateTagsCombo();
0060 
0061     // Configure the Search in all Baskets button:
0062     m_inAllBasketsButton->setCheckable(true);
0063     //  m_inAllBasketsButton->setChecked(true);
0064     //  Global::bnpView->toggleFilterAllBaskets(true);
0065 
0066     //  m_lineEdit->setMaximumWidth(150);
0067     m_lineEdit->setClearButtonEnabled(true);
0068 
0069     // Layout all those widgets:
0070     hBox->addWidget(m_resetButton);
0071     hBox->addWidget(label);
0072     hBox->addWidget(m_lineEdit);
0073     hBox->addWidget(label2);
0074     hBox->addWidget(m_tagsBox);
0075     hBox->addWidget(m_inAllBasketsButton);
0076 
0077     //connect(&m_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkBar()));
0078     connect(m_resetButton, &QToolButton::clicked, this, &FilterBar::reset);
0079     connect(m_lineEdit, &QLineEdit::textChanged, this, &FilterBar::changeFilter);
0080     connect(m_tagsBox, SIGNAL(activated(int)), this, SLOT(tagChanged(int)));
0081 
0082     //connect(m_inAllBasketsButton, SIGNAL(clicked()), this, SLOT(inAllBaskets()));
0083     m_inAllBasketsButton->setDefaultAction(Global::bnpView->m_actFilterAllBaskets);
0084 
0085     FocusWidgetFilter *lineEditF = new FocusWidgetFilter(m_lineEdit);
0086     m_tagsBox->installEventFilter(lineEditF);
0087     connect(lineEditF, &FocusWidgetFilter::escapePressed, this, &FilterBar::reset);
0088     connect(lineEditF, &FocusWidgetFilter::returnPressed, this, &FilterBar::changeFilter);
0089 }
0090 
0091 FilterBar::~FilterBar()
0092 {
0093 }
0094 
0095 void FilterBar::setFilterData(const FilterData &data)
0096 {
0097     m_lineEdit->setText(data.string);
0098 
0099     int index = 0;
0100     switch (data.tagFilterType) {
0101     default:
0102     case FilterData::DontCareTagsFilter:
0103         index = 0;
0104         break;
0105     case FilterData::NotTaggedFilter:
0106         index = 1;
0107         break;
0108     case FilterData::TaggedFilter:
0109         index = 2;
0110         break;
0111     case FilterData::TagFilter:
0112         filterTag(data.tag);
0113         return;
0114     case FilterData::StateFilter:
0115         filterState(data.state);
0116         return;
0117     }
0118 
0119     if (m_tagsBox->currentIndex() != index) {
0120         m_tagsBox->setCurrentIndex(index);
0121         tagChanged(index);
0122     }
0123 }
0124 
0125 void FilterBar::repopulateTagsCombo()
0126 {
0127     static const int ICON_SIZE = 16;
0128 
0129     m_tagsBox->clear();
0130     m_tagsMap.clear();
0131     m_statesMap.clear();
0132 
0133     m_tagsBox->addItem(QString());
0134     m_tagsBox->addItem(i18n("(Not tagged)"));
0135     m_tagsBox->addItem(i18n("(Tagged)"));
0136 
0137     int index = 3;
0138     Tag *tag;
0139     State *state;
0140     QString icon;
0141     QString text;
0142     QPixmap emblem;
0143     for (Tag::List::iterator it = Tag::all.begin(); it != Tag::all.end(); ++it) {
0144         tag = *it;
0145         state = tag->states().first();
0146         // Insert the tag in the combo-box:
0147         if (tag->countStates() > 1) {
0148             text = tag->name();
0149             icon = QString();
0150         } else {
0151             text = state->name();
0152             icon = state->emblem();
0153         }
0154         emblem = KIconLoader::global()->loadIcon(icon, KIconLoader::Desktop, ICON_SIZE, KIconLoader::DefaultState, QStringList(), nullptr, /*canReturnNull=*/true);
0155         m_tagsBox->insertItem(index, emblem, text);
0156         // Update the mapping:
0157         m_tagsMap.insert(index, tag);
0158         ++index;
0159         // Insert sub-states, if needed:
0160         if (tag->countStates() > 1) {
0161             for (State::List::iterator it2 = tag->states().begin(); it2 != tag->states().end(); ++it2) {
0162                 state = *it2;
0163                 // Insert the state:
0164                 text = state->name();
0165                 icon = state->emblem();
0166                 emblem = KIconLoader::global()->loadIcon(icon,
0167                                                          KIconLoader::Desktop,
0168                                                          ICON_SIZE,
0169                                                          KIconLoader::DefaultState,
0170                                                          QStringList(),
0171                                                          nullptr,
0172                                                          /*canReturnNull=*/true);
0173                 // Indent the emblem to show the hierarchy relation:
0174                 if (!emblem.isNull())
0175                     emblem = Tools::indentPixmap(emblem, /*depth=*/1, /*deltaX=*/2 * ICON_SIZE / 3);
0176                 m_tagsBox->insertItem(index, emblem, text);
0177                 // Update the mapping:
0178                 m_statesMap.insert(index, state);
0179                 ++index;
0180             }
0181         }
0182     }
0183 }
0184 
0185 void FilterBar::reset()
0186 {
0187     m_lineEdit->setText(QString()); // m_data->isFiltering will be set to false;
0188     m_lineEdit->clearFocus();
0189     changeFilter();
0190     if (m_tagsBox->currentIndex() != 0) {
0191         m_tagsBox->setCurrentIndex(0);
0192         tagChanged(0);
0193     }
0194     hide();
0195     Q_EMIT newFilter(m_data);
0196 }
0197 
0198 void FilterBar::filterTag(Tag *tag)
0199 {
0200     int index = 0;
0201 
0202     for (QMap<int, Tag *>::Iterator it = m_tagsMap.begin(); it != m_tagsMap.end(); ++it)
0203         if (it.value() == tag) {
0204             index = it.key();
0205             break;
0206         }
0207     if (index <= 0)
0208         return;
0209 
0210     if (m_tagsBox->currentIndex() != index) {
0211         m_tagsBox->setCurrentIndex(index);
0212         tagChanged(index);
0213     }
0214 }
0215 
0216 void FilterBar::filterState(State *state)
0217 {
0218     int index = 0;
0219 
0220     for (QMap<int, State *>::Iterator it = m_statesMap.begin(); it != m_statesMap.end(); ++it)
0221         if (it.value() == state) {
0222             index = it.key();
0223             break;
0224         }
0225     if (index <= 0)
0226         return;
0227 
0228     if (m_tagsBox->currentIndex() != index) {
0229         m_tagsBox->setCurrentIndex(index);
0230         tagChanged(index);
0231     }
0232 }
0233 
0234 void FilterBar::inAllBaskets()
0235 {
0236     // TODO!
0237 }
0238 
0239 void FilterBar::setEditFocus()
0240 {
0241     m_lineEdit->setFocus();
0242 }
0243 
0244 bool FilterBar::hasEditFocus()
0245 {
0246     return m_lineEdit->hasFocus() || m_tagsBox->hasFocus();
0247 }
0248 
0249 const FilterData &FilterBar::filterData()
0250 {
0251     return m_data;
0252 }
0253 
0254 void FilterBar::changeFilter()
0255 {
0256     m_data.string = m_lineEdit->text();
0257     m_data.isFiltering = (!m_data.string.isEmpty() || m_data.tagFilterType != FilterData::DontCareTagsFilter);
0258     if (hasEditFocus())
0259         m_data.isFiltering = true;
0260     Q_EMIT newFilter(m_data);
0261 }
0262 
0263 void FilterBar::tagChanged(int index)
0264 {
0265     m_data.tag = nullptr;
0266     m_data.state = nullptr;
0267     switch (index) {
0268     case 0:
0269         m_data.tagFilterType = FilterData::DontCareTagsFilter;
0270         break;
0271     case 1:
0272         m_data.tagFilterType = FilterData::NotTaggedFilter;
0273         break;
0274     case 2:
0275         m_data.tagFilterType = FilterData::TaggedFilter;
0276         break;
0277     default:
0278         // Try to find if we are filtering a tag:
0279         QMap<int, Tag *>::iterator it = m_tagsMap.find(index);
0280         if (it != m_tagsMap.end()) {
0281             m_data.tagFilterType = FilterData::TagFilter;
0282             m_data.tag = *it;
0283         } else {
0284             // If not, try to find if we are filtering a state:
0285             QMap<int, State *>::iterator it2 = m_statesMap.find(index);
0286             if (it2 != m_statesMap.end()) {
0287                 m_data.tagFilterType = FilterData::StateFilter;
0288                 m_data.state = *it2;
0289             } else {
0290                 // If not (should never happens), do as if the tags filter was reset:
0291                 m_data.tagFilterType = FilterData::DontCareTagsFilter;
0292             }
0293         }
0294         break;
0295     }
0296     m_data.isFiltering = (!m_data.string.isEmpty() || m_data.tagFilterType != FilterData::DontCareTagsFilter);
0297     if (hasEditFocus())
0298         m_data.isFiltering = true;
0299     Q_EMIT newFilter(m_data);
0300 }