Add a basic support for bookmarks.

This commit is contained in:
Matthieu Gautier 2018-12-02 16:10:35 +01:00
parent 67d56f1d03
commit b1b0c1d2c3
16 changed files with 298 additions and 18 deletions

View File

@ -57,7 +57,8 @@ SOURCES += \
src/contentmanager.cpp \
src/contentmanagerview.cpp \
src/tabbar.cpp \
src/contentmanagerside.cpp
src/contentmanagerside.cpp \
src/readinglistbar.cpp
HEADERS += \
src/mainwindow.h \
@ -76,13 +77,15 @@ HEADERS += \
src/contentmanager.h \
src/contentmanagerview.h \
src/tabbar.h \
src/contentmanagerside.h
src/contentmanagerside.h \
src/readinglistbar.h
FORMS += \
ui/mainwindow.ui \
ui/about.ui \
src/tocsidebar.ui \
src/contentmanagerside.ui
src/contentmanagerside.ui \
src/readinglistbar.ui
TRANSLATIONS = "resources/i18n/kiwix-desktop_fr.ts"
CODECFORSRC = UTF-8

View File

@ -193,7 +193,8 @@ QTabBar::close-button {
background-color: white;
}
#contentmanagerside QWidget{
#contentmanagerside QWidget,
#readinglistbar QWidget{
background-color: white;
outline: none;
}
@ -210,3 +211,12 @@ QTabBar::close-button {
#contentmanagerside QCheckBox::indicator {
image: none;
}
#readinglistbar QListWidget {
border: none;
}
#readinglistbar QListWidget::item {
font-size: 16px;
margin-bottom: 5px;
}

View File

@ -173,6 +173,7 @@ void KiwixApp::setSideBar(KiwixApp::SideBarType type)
switch(type) {
case SEARCH_BAR:
case CONTENTMANAGER_BAR:
case READINGLIST_BAR:
sideDockWidget->setCurrentIndex(type);
sideDockWidget->show();
break;
@ -208,6 +209,20 @@ QAction *KiwixApp::getAction(KiwixApp::Actions action)
return mpa_actions[action];
}
bool KiwixApp::isCurrentArticleBookmarked()
{
auto zimId = getTabWidget()->currentZimId().toStdString();
zimId.resize(zimId.length()-4);
auto url = getTabWidget()->currentArticleUrl().toStdString();
for (auto& bookmark: getLibrary()->getBookmarks()) {
if (bookmark.getBookId() == zimId && bookmark.getUrl() == url) {
return true;
}
}
return false;
}
#define CREATE_ACTION_ICON(ID, ICON, TEXT) \
mpa_actions[ID] = new QAction(QIcon(":/icons/" ICON ".svg"), TEXT)
#define CREATE_ACTION(ID, TEXT) \
@ -286,9 +301,17 @@ void KiwixApp::createAction()
SET_SHORTCUT(ToggleTOCAction, QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_1));
HIDE_ACTION(ToggleTOCAction);
CREATE_ACTION(ToggleReadingListAction, tr("Reading list"));
CREATE_ACTION_ICON(ToggleReadingListAction, "reading-list" ,tr("Reading list"));
SET_SHORTCUT(ToggleReadingListAction, QKeySequence(Qt::CTRL+Qt::SHIFT+Qt::Key_2));
HIDE_ACTION(ToggleReadingListAction);
connect(mpa_actions[ToggleReadingListAction], &QAction::toggled,
this, [=](bool checked) {
auto action = mpa_actions[ToggleReadingListAction];
action->setIcon(
QIcon(checked ? ":/icons/reading-list-active.svg" : ":/icons/reading-list.svg"));
setSideBar(checked ? READINGLIST_BAR : NONE);
});
mpa_actions[ToggleReadingListAction]->setCheckable(true);
CREATE_ACTION(ZoomInAction, tr("Zoom in"));
SET_SHORTCUT(ZoomInAction, QKeySequence::ZoomIn);

View File

@ -51,6 +51,7 @@ public:
enum SideBarType {
SEARCH_BAR,
CONTENTMANAGER_BAR,
READINGLIST_BAR,
NONE
};
@ -69,6 +70,8 @@ public:
TabBar* getTabWidget() { return mp_tabWidget; }
QAction* getAction(Actions action);
bool isCurrentArticleBookmarked();
signals:
void currentTitleChanged(const QString& title);

View File

@ -9,11 +9,15 @@ class LibraryManipulator: public kiwix::LibraryManipulator {
public:
LibraryManipulator(Library* p_library)
: mp_library(p_library) {}
virtual ~LibraryManipulator() {}
bool addBookToLibrary(kiwix::Book book) {
auto ret = mp_library->m_library.addBook(book);
emit(mp_library->booksChanged());
return ret;
}
void addBookmarkToLibrary(kiwix::Bookmark bookmark) {
mp_library->m_library.addBookmark(bookmark);
}
Library* mp_library;
};
@ -23,6 +27,7 @@ Library::Library()
auto manager = kiwix::Manager(&manipulator);
qInfo() << QString::fromStdString(getDataDirectory());
manager.readFile(appendToDirectory(getDataDirectory(),"library.xml"), false);
manager.readBookmarkFile(appendToDirectory(getDataDirectory(),"library.bookmarks.xml"));
qInfo() << getBookIds().length();
emit(booksChanged());
}
@ -93,9 +98,22 @@ void Library::addBookToLibrary(kiwix::Book &book)
m_library.addBook(book);
}
void Library::addBookmark(kiwix::Bookmark &bookmark)
{
m_library.addBookmark(bookmark);
emit bookmarksChanged();
}
void Library::removeBookmark(const QString &zimId, const QString &url)
{
m_library.removeBookmark(zimId.toStdString(), url.toStdString());
emit bookmarksChanged();
}
void Library::save()
{
m_library.writeToFile(appendToDirectory(getDataDirectory(),"library.xml"));
m_library.writeBookmarksToFile(appendToDirectory(getDataDirectory(), "library.bookmarks.xml"));
}
kiwix::Book &Library::getBookById(QString id)

View File

@ -29,7 +29,10 @@ public:
QString openBookFromPath(const QString& zimPath);
std::shared_ptr<kiwix::Reader> getReader(const QString& zimId);
QStringList getBookIds();
const std::vector<kiwix::Bookmark>& getBookmarks() { return m_library.getBookmarks(); }
void addBookToLibrary(kiwix::Book& book);
void addBookmark(kiwix::Bookmark& bookmark);
void removeBookmark(const QString& zimId, const QString& url);
void save();
public slots:
QString openBookById(const QString& _id);
@ -37,6 +40,7 @@ public slots:
signals:
void booksChanged();
void bookmarksChanged();
private:
kiwix::Library m_library;

59
src/readinglistbar.cpp Normal file
View File

@ -0,0 +1,59 @@
#include "readinglistbar.h"
#include "ui_readinglistbar.h"
#include "kiwixapp.h"
#include <QListWidgetItem>
ReadingListBar::ReadingListBar(QWidget *parent) :
QWidget(parent),
ui(new Ui::readinglistbar)
{
ui->setupUi(this);
connect(KiwixApp::instance()->getLibrary(), &Library::bookmarksChanged,
this, &ReadingListBar::setupList);
connect(ui->listWidget, &QListWidget::itemActivated,
this, &ReadingListBar::on_itemActivated);
setupList();
}
ReadingListBar::~ReadingListBar()
{
delete ui;
}
void ReadingListBar::setupList()
{
auto library = KiwixApp::instance()->getLibrary();
auto bookmarks = library->getBookmarks();
auto listWidget = ui->listWidget;
listWidget->clear();
for(auto& bookmark:bookmarks) {
auto reader = library->getReader(QString::fromStdString(bookmark.getBookId()) + ".zim");
if (reader == nullptr)
continue;
std::string content;
std::string mimeType;
reader->getFavicon(content, mimeType);
QPixmap pixmap;
pixmap.loadFromData(reinterpret_cast<const uchar*>(content.data()), content.size());
auto icon = QIcon(pixmap);
auto item = new QListWidgetItem(
icon,
QString::fromStdString(bookmark.getTitle()),
listWidget);
item->setTextAlignment(Qt::TextWordWrap);
}
}
void ReadingListBar::on_itemActivated(QListWidgetItem* item)
{
int index = ui->listWidget->row(item);
auto bookmark = KiwixApp::instance()->getLibrary()->getBookmarks().at(index);
QUrl url;
url.setScheme("zim");
url.setHost(QString::fromStdString(bookmark.getBookId())+".zim");
url.setPath(QString::fromStdString(bookmark.getUrl()));
KiwixApp::instance()->openUrl(url);
}

26
src/readinglistbar.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef READINGLISTBAR_H
#define READINGLISTBAR_H
#include <QWidget>
#include <QListWidgetItem>
namespace Ui {
class readinglistbar;
}
class ReadingListBar : public QWidget
{
Q_OBJECT
public:
explicit ReadingListBar(QWidget *parent = nullptr);
~ReadingListBar();
public slots:
void setupList();
void on_itemActivated(QListWidgetItem *item);
private:
Ui::readinglistbar *ui;
};
#endif // READINGLISTBAR_H

73
src/readinglistbar.ui Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>readinglistbar</class>
<widget class="QWidget" name="readinglistbar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>Reading List</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listWidget">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="isWrapping" stdset="0">
<bool>true</bool>
</property>
<property name="uniformItemSizes">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -11,21 +11,51 @@ SearchButton::SearchButton(QWidget *parent) :
{
setFlat(true);
setIcon(QIcon(":/icons/search.svg"));
connect(this, &QPushButton::clicked, this, &SearchButton::on_buttonClicked);
}
void SearchButton::set_searchMode(bool searchMode)
{
if (searchMode == m_searchMode)
return;
m_searchMode = searchMode;
if (m_searchMode) {
setIcon(QIcon(":/icons/search.svg"));
} else {
setIcon(QIcon(":/icons/reading-list.svg"));
auto kiwixApp = KiwixApp::instance();
if (kiwixApp->isCurrentArticleBookmarked()) {
setIcon(QIcon(":/icons/reading-list-active.svg"));
} else {
setIcon(QIcon(":/icons/reading-list.svg"));
}
}
}
void SearchButton::on_buttonClicked()
{
if (m_searchMode)
return;
auto kiwixApp = KiwixApp::instance();
auto library = kiwixApp->getLibrary();
auto tabWidget = kiwixApp->getTabWidget();
if (kiwixApp->isCurrentArticleBookmarked()) {
auto zimid = tabWidget->currentZimId();
zimid.resize(zimid.length()-4);
library->removeBookmark(
zimid, tabWidget->currentArticleUrl()
);
} else {
kiwix::Bookmark bookmark;
auto zimid = tabWidget->currentZimId().toStdString();
zimid.resize(zimid.length()-4);
bookmark.setBookId(zimid);
bookmark.setUrl(tabWidget->currentArticleUrl().toStdString());
bookmark.setTitle(tabWidget->currentArticleTitle().toStdString());
library->addBookmark(bookmark);
}
set_searchMode(false);
library->save();
}
SearchBar::SearchBar(QWidget *parent) :
QLineEdit(parent),
m_completer(&m_completionModel, this),
@ -42,13 +72,15 @@ SearchBar::SearchBar(QWidget *parent) :
#else
connect(this, &QLineEdit::returnPressed, this, &SearchBar::openTitle);
#endif
connect(KiwixApp::instance(), &KiwixApp::currentTitleChanged, this,
[=](const QString& title) {
setText(title);
m_button.set_searchMode(false);
});
connect(KiwixApp::instance(), &KiwixApp::currentTitleChanged,
this, &SearchBar::on_currentTitleChanged);
}
void SearchBar::on_currentTitleChanged(const QString& title)
{
setText(title);
m_button.set_searchMode(false);
}
void SearchBar::focusInEvent( QFocusEvent* event)
{

View File

@ -14,6 +14,8 @@ public:
public slots:
void set_searchMode(bool searchMode);
void on_buttonClicked();
protected:
bool m_searchMode;
};
@ -24,6 +26,8 @@ class SearchBar : public QLineEdit
public:
SearchBar(QWidget *parent = nullptr);
public slots:
void on_currentTitleChanged(const QString &title);
protected:
virtual void focusInEvent(QFocusEvent *);
private:

View File

@ -137,6 +137,20 @@ QString TabBar::currentZimId()
return currentWidget()->zimId();
}
QString TabBar::currentArticleUrl()
{
if(!currentWidget())
return "";
return currentWidget()->url().path();
}
QString TabBar::currentArticleTitle()
{
if(!currentWidget())
return "";
return currentWidget()->title();
}
void TabBar::triggerWebPageAction(QWebEnginePage::WebAction action, WebView *webView)
{
CURRENTIFNULL(webView);

View File

@ -11,6 +11,7 @@ class TabBar : public QTabBar
{
Q_OBJECT
Q_PROPERTY(QString currentZimId READ currentZimId NOTIFY currentZimIdChanged)
public:
TabBar(QWidget* parent=nullptr);
void setStackedWidget(QStackedWidget* widget);
@ -30,6 +31,8 @@ public:
QString currentZimId();
void triggerWebPageAction(QWebEnginePage::WebAction action, WebView* webView=nullptr);
QString currentArticleUrl();
QString currentArticleTitle();
signals:
void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
void currentZimIdChanged(const QString& zimId);

View File

@ -14,7 +14,7 @@ TopWidget::TopWidget(QWidget *parent) :
mp_historyBackAction->setIcon(QIcon(":/icons/back.svg"));
mp_historyBackAction->setText(tr("back"));
mp_historyBackAction->setToolTip(tr("back"));
connect(mp_historyBackAction, &QAction::triggered, [this](){
connect(mp_historyBackAction, &QAction::triggered, [](){
KiwixApp::instance()->getTabWidget()->triggerWebPageAction(QWebEnginePage::Back);
});
addAction(mp_historyBackAction);
@ -22,13 +22,14 @@ TopWidget::TopWidget(QWidget *parent) :
mp_historyForwardAction->setIcon(QIcon(":/icons/forward.svg"));
mp_historyForwardAction->setText(tr("forward"));
mp_historyForwardAction->setToolTip(tr("forward"));
connect(mp_historyForwardAction, &QAction::triggered, [this](){
connect(mp_historyForwardAction, &QAction::triggered, [](){
KiwixApp::instance()->getTabWidget()->triggerWebPageAction(QWebEnginePage::Forward);
});
addAction(mp_historyForwardAction);
addSeparator();
addWidget(&m_searchEntry);
addAction(KiwixApp::instance()->getAction(KiwixApp::ToggleReadingListAction));
addSeparator();

View File

@ -9,7 +9,7 @@
class WebView : public QWebEngineView
{
Q_OBJECT
Q_PROPERTY(const QIcon icon READ icon NOTIFY iconChanged);
Q_PROPERTY(const QIcon icon READ icon NOTIFY iconChanged)
Q_PROPERTY(QString zimId READ zimId NOTIFY zimIdChanged)
public:

View File

@ -76,6 +76,7 @@
</sizepolicy>
</property>
</widget>
<widget class="ReadingListBar" name="readinglistbar"/>
</widget>
</item>
<item>
@ -126,6 +127,12 @@
<header>src/contentmanagerside.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ReadingListBar</class>
<extends>QWidget</extends>
<header>src/readinglistbar.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>