Skip to content

Commit 1e6a0f4

Browse files
committed
QRadioButton -> QCheckBox in MultiZimButton
Allow to search in multiple books Search in all books if none selected
1 parent 5c3392b commit 1e6a0f4

File tree

4 files changed

+179
-52
lines changed

4 files changed

+179
-52
lines changed

src/multizimbutton.cpp

Lines changed: 132 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#include <QListWidget>
22
#include <QMenu>
33
#include <QWidgetAction>
4-
#include <QButtonGroup>
5-
#include <QRadioButton>
4+
#include <QCheckBox>
65
#include "kiwixapp.h"
76
#include "multizimbutton.h"
87
#include "css_constants.h"
@@ -11,8 +10,7 @@ QString getElidedText(const QFont& font, int length, const QString& text);
1110

1211
MultiZimButton::MultiZimButton(QWidget *parent) :
1312
QToolButton(parent),
14-
mp_buttonList(new QListWidget),
15-
mp_radioButtonGroup(new QButtonGroup(this))
13+
mp_buttonList(new QListWidget)
1614
{
1715
setMenu(new QMenu(this));
1816
setPopupMode(QToolButton::InstantPopup);
@@ -23,17 +21,82 @@ MultiZimButton::MultiZimButton(QWidget *parent) :
2321
popupAction->setDefaultWidget(mp_buttonList);
2422
menu()->addAction(popupAction);
2523

26-
connect(mp_buttonList, &QListWidget::currentRowChanged, this, [=](int row){
27-
if (const auto widget = getZimWidget(row))
28-
widget->getRadioButton()->setChecked(true);
24+
connect(mp_buttonList, &QListWidget::itemActivated, this, [=](QListWidgetItem *item) {
25+
if (const auto widget = getZimWidget(item))
26+
widget->toggle();
27+
});
28+
connect(mp_buttonList, &QListWidget::itemClicked, this, [=](QListWidgetItem *item) {
29+
if (const auto widget = getZimWidget(item))
30+
widget->toggle();
2931
});
3032
}
3133

3234
void MultiZimButton::updateDisplay()
3335
{
36+
const auto library = KiwixApp::instance()->getLibrary();
37+
const auto view = KiwixApp::instance()->getTabWidget()->currentWebView();
38+
QListWidgetItem* currentItem = nullptr;
39+
QIcon currentIcon;
40+
const int paddingTopBot = CSS::MultiZimButton::QListWidget::paddingVertical * 2;
41+
const int itemHeight = paddingTopBot + CSS::ZimItemWidget::QLabel::lineHeight;
42+
43+
for (int row = 0; row < mp_buttonList->count(); row++)
44+
{
45+
const auto item = mp_buttonList->item(row);
46+
const auto bookId = item->data(Qt::UserRole).toString();
47+
const QString bookTitle = QString::fromStdString(library->getBookById(bookId).getTitle());
48+
const QIcon zimIcon = library->getBookIcon(bookId);
49+
item->setData(Qt::DisplayRole, bookTitle);
50+
item->setSizeHint(QSize(0, itemHeight));
51+
52+
if (view && view->zimId() == bookId)
53+
{
54+
currentItem = item;
55+
currentIcon = zimIcon;
56+
continue;
57+
}
58+
59+
setItemZimWidget(item, bookTitle, zimIcon);
60+
}
61+
62+
mp_buttonList->sortItems();
63+
if (currentItem)
64+
{
65+
const auto checked = getZimWidget(currentItem)->isChecked();
66+
const auto title = currentItem->data(Qt::DisplayRole).toString();
67+
const auto currentRow = mp_buttonList->row(currentItem);
68+
if (currentRow > 0) {
69+
currentItem = mp_buttonList->takeItem(currentRow);
70+
mp_buttonList->insertItem(0, currentItem);
71+
currentItem = mp_buttonList->item(0);
72+
setItemZimWidget(currentItem, "*" + title, currentIcon);
73+
if (checked)
74+
getZimWidget(currentItem)->setChecked(checked);
75+
}
76+
else {
77+
setItemZimWidget(currentItem, "*" + title, currentIcon);
78+
}
79+
}
80+
81+
/* Display should not be used other than for sorting. */
82+
for (int i = 0; i < mp_buttonList->count(); i++)
83+
mp_buttonList->item(i)->setData(Qt::DisplayRole, QVariant());
84+
85+
setDisabled(mp_buttonList->model()->rowCount() == 0);
86+
87+
mp_buttonList->scrollToTop();
88+
mp_buttonList->setCurrentRow(0);
89+
90+
/* We set a maximum display height for list. Respect padding. */
91+
const int listHeight = itemHeight * std::min(7, mp_buttonList->count());
92+
mp_buttonList->setFixedHeight(listHeight + paddingTopBot);
93+
mp_buttonList->setFixedWidth(menu()->width());
94+
}
95+
96+
void MultiZimButton::updateBooks()
97+
{
98+
auto checkedZimIds = getCheckedZimIds();
3499
mp_buttonList->clear();
35-
for (const auto& button : mp_radioButtonGroup->buttons())
36-
mp_radioButtonGroup->removeButton(button);
37100

38101
const auto library = KiwixApp::instance()->getLibrary();
39102
const auto view = KiwixApp::instance()->getTabWidget()->currentWebView();
@@ -65,6 +128,10 @@ void MultiZimButton::updateDisplay()
65128

66129
mp_buttonList->addItem(item);
67130
setItemZimWidget(item, bookTitle, zimIcon);
131+
if (checkedZimIds.contains(bookId)) {
132+
checkedZimIds.removeOne(bookId);
133+
getZimWidget(item)->setChecked(true);
134+
}
68135
}
69136

70137
mp_buttonList->sortItems();
@@ -77,6 +144,7 @@ void MultiZimButton::updateDisplay()
77144
}
78145

79146
/* Display should not be used other than for sorting. */
147+
80148
for (int i = 0; i < mp_buttonList->count(); i++)
81149
mp_buttonList->item(i)->setData(Qt::DisplayRole, QVariant());
82150

@@ -86,6 +154,7 @@ void MultiZimButton::updateDisplay()
86154
mp_buttonList->setCurrentRow(0);
87155

88156
/* We set a maximum display height for list. Respect padding. */
157+
89158
const int listHeight = itemHeight * std::min(7, mp_buttonList->count());
90159
mp_buttonList->setFixedHeight(listHeight + paddingTopBot);
91160
mp_buttonList->setFixedWidth(menu()->width());
@@ -94,10 +163,30 @@ void MultiZimButton::updateDisplay()
94163
QStringList MultiZimButton::getZimIds() const
95164
{
96165
QStringList idList;
166+
bool someChecked = false;
97167
for (int row = 0; row < mp_buttonList->count(); row++)
98168
{
99169
const auto widget = getZimWidget(row);
100-
if (widget && widget->getRadioButton()->isChecked())
170+
if (widget && widget->isChecked()) {
171+
if (!someChecked) {
172+
someChecked = true;
173+
idList.clear();
174+
}
175+
idList.append(mp_buttonList->item(row)->data(Qt::UserRole).toString());
176+
}
177+
else if (!someChecked)
178+
idList.append(mp_buttonList->item(row)->data(Qt::UserRole).toString());
179+
}
180+
return idList;
181+
}
182+
183+
QStringList MultiZimButton::getCheckedZimIds() const
184+
{
185+
QStringList idList;
186+
for (int row = 0; row < mp_buttonList->count(); row++)
187+
{
188+
const auto widget = getZimWidget(row);
189+
if (widget && widget->isChecked())
101190
idList.append(mp_buttonList->item(row)->data(Qt::UserRole).toString());
102191
}
103192
return idList;
@@ -109,19 +198,30 @@ ZimItemWidget *MultiZimButton::getZimWidget(int row) const
109198
return qobject_cast<ZimItemWidget *>(widget);
110199
}
111200

201+
ZimItemWidget *MultiZimButton::getZimWidget(QListWidgetItem *item) const
202+
{
203+
const auto widget = mp_buttonList->itemWidget(item);
204+
return qobject_cast<ZimItemWidget *>(widget);
205+
}
206+
112207
void MultiZimButton::setItemZimWidget(QListWidgetItem *item,
113208
const QString &title, const QIcon &icon)
114209
{
210+
const auto oldWidget = getZimWidget(item);
211+
const auto checked = oldWidget
212+
? oldWidget->isChecked()
213+
: false;
115214
const auto zimWidget = new ZimItemWidget(title, icon);
116-
mp_radioButtonGroup->addButton(zimWidget->getRadioButton());
117215
mp_buttonList->setItemWidget(item, zimWidget);
216+
if (checked)
217+
zimWidget->setChecked(true);
118218
}
119219

120220
ZimItemWidget::ZimItemWidget(QString text, QIcon icon, QWidget *parent) :
121221
QWidget(parent),
122222
textLabel(new QLabel(this)),
123223
iconLabel(new QLabel(this)),
124-
radioBt(new QRadioButton(this))
224+
checkBx(new QCheckBox(this))
125225
{
126226
setLayout(new QHBoxLayout);
127227

@@ -163,5 +263,24 @@ ZimItemWidget::ZimItemWidget(QString text, QIcon icon, QWidget *parent) :
163263

164264
layout()->addWidget(iconLabel);
165265
layout()->addWidget(textLabel);
166-
layout()->addWidget(radioBt);
266+
layout()->addWidget(checkBx);
267+
}
268+
269+
bool ZimItemWidget::isChecked() const {
270+
const auto cb = getCheckBox();
271+
if (cb)
272+
return cb->isChecked();
273+
return false;
274+
}
275+
276+
void ZimItemWidget::setChecked(bool checked) {
277+
const auto cb = getCheckBox();
278+
if (cb)
279+
cb->setChecked(checked);
280+
}
281+
282+
void ZimItemWidget::toggle() {
283+
const auto cb = getCheckBox();
284+
if (cb)
285+
cb->toggle();
167286
}

src/multizimbutton.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
class QListWidget;
77
class QButtonGroup;
88
class QListWidgetItem;
9-
class QRadioButton;
9+
class QCheckBox;
1010
class QLabel;
1111

1212
class ZimItemWidget : public QWidget {
@@ -15,12 +15,17 @@ class ZimItemWidget : public QWidget {
1515
public:
1616
ZimItemWidget(QString text, QIcon icon, QWidget *parent = nullptr);
1717

18-
QRadioButton* getRadioButton() const { return radioBt; }
18+
QCheckBox* getCheckBox() const { return checkBx; }
19+
bool isChecked() const;
20+
21+
public slots:
22+
void setChecked(bool checked);
23+
void toggle();
1924

2025
private:
2126
QLabel* textLabel;
2227
QLabel* iconLabel;
23-
QRadioButton* radioBt;
28+
QCheckBox* checkBx;
2429
};
2530

2631
class MultiZimButton : public QToolButton {
@@ -31,13 +36,15 @@ class MultiZimButton : public QToolButton {
3136

3237
public slots:
3338
void updateDisplay();
39+
void updateBooks();
3440
QStringList getZimIds() const;
41+
QStringList getCheckedZimIds() const;
3542

3643
private:
3744
QListWidget* mp_buttonList;
38-
QButtonGroup* mp_radioButtonGroup;
3945

4046
ZimItemWidget* getZimWidget(int row) const;
47+
ZimItemWidget* getZimWidget(QListWidgetItem *item) const;
4148
void setItemZimWidget(QListWidgetItem* item, const QString& title, const QIcon& icon);
4249
};
4350

src/searchbar.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ SearchBar::SearchBar(QWidget *parent) :
437437
&BookmarkButton::update_display);
438438
connect(KiwixApp::instance()->getContentManager(),
439439
&ContentManager::booksChanged, &m_multiZimButton,
440-
&MultiZimButton::updateDisplay);
440+
&MultiZimButton::updateBooks);
441441
connect(this, &SearchBar::currentTitleChanged, &m_multiZimButton,
442442
&MultiZimButton::updateDisplay);
443443
}

src/suggestionlistworker.cpp

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,43 @@ void SuggestionListWorker::run()
1818
const auto selectedIdList = app->getSearchBar().getMultiZimButton().getZimIds();
1919

2020
/* TODO: re-implement this after introducing the actual Multi-Zim. */
21-
const auto currentZimId = selectedIdList[0];
22-
try {
23-
const auto archive = app->getLibrary()->getArchive(currentZimId);
24-
QUrl url;
25-
url.setScheme("zim");
26-
url.setHost(currentZimId + ".zim");
27-
auto prefix = m_text.toStdString();
28-
auto suggestionSearcher = zim::SuggestionSearcher(*archive);
29-
auto suggestionSearch = suggestionSearcher.suggest(prefix);
30-
const auto suggestions = suggestionSearch.getResults(m_start, getFetchSize());
31-
for (auto current : suggestions) {
32-
QString path = QString("/") + QString::fromStdString(current.getPath());
33-
url.setPath(path);
34-
const auto text = QString::fromStdString(current.getTitle());
35-
suggestionList.append({text, url});
36-
}
21+
for (const auto &currentZimId : selectedIdList) {
22+
try {
23+
const auto archive = app->getLibrary()->getArchive(currentZimId);
24+
QUrl url;
25+
url.setScheme("zim");
26+
url.setHost(currentZimId + ".zim");
27+
auto prefix = m_text.toStdString();
28+
auto suggestionSearcher = zim::SuggestionSearcher(*archive);
29+
auto suggestionSearch = suggestionSearcher.suggest(prefix);
30+
const auto suggestions = suggestionSearch.getResults(m_start, getFetchSize());
31+
for (auto current : suggestions) {
32+
QString path = QString("/") + QString::fromStdString(current.getPath());
33+
url.setPath(path);
34+
const auto text = QString::fromStdString(current.getTitle());
35+
suggestionList.append({text, url});
36+
}
3737

38-
// Propose fulltext search
39-
url.setPath("");
40-
if (archive->hasFulltextIndex()) {
41-
// The host is used to determine the currentZimId
42-
// The content query item is used to know in which zim search (as for kiwix-serve)
43-
url.setHost(currentZimId + ".search");
44-
QUrlQuery query;
45-
query.addQueryItem("content", currentZimId);
46-
query.addQueryItem("pattern", m_text);
47-
url.setQuery(query);
48-
const auto text = m_text + " (" + gt("fulltext-search") + ")";
49-
suggestionList.append({text, url});
38+
// Propose fulltext search
39+
url.setPath("");
40+
if (archive->hasFulltextIndex()) {
41+
// The host is used to determine the currentZimId
42+
// The content query item is used to know in which zim search (as for kiwix-serve)
43+
url.setHost(currentZimId + ".search");
44+
QUrlQuery query;
45+
query.addQueryItem("content", currentZimId);
46+
query.addQueryItem("pattern", m_text);
47+
url.setQuery(query);
48+
const auto text = m_text + " (" + gt("fulltext-search") + ")";
49+
suggestionList.append({text, url});
50+
}
51+
} catch (std::out_of_range& e) {
52+
// Impossible to find the requested archive (bug ?)
53+
// We could propose a suggestion to do multi-zim search with:
54+
// url.setHost("library.search");
55+
// but we don't have a correct UI to select on which zim search, how to display results, ...
56+
// So do nothing for now
5057
}
51-
} catch (std::out_of_range& e) {
52-
// Impossible to find the requested archive (bug ?)
53-
// We could propose a suggestion to do multi-zim search with:
54-
// url.setHost("library.search");
55-
// but we don't have a correct UI to select on which zim search, how to display results, ...
56-
// So do nothing for now
5758
}
5859
emit(searchFinished(suggestionList, m_token));
5960
}

0 commit comments

Comments
 (0)