mirror of
https://github.com/kiwix/kiwix-desktop.git
synced 2025-09-24 04:32:15 -04:00
Merge pull request #1098 from kiwix/united_states_of_books
Declaration of USB (Unified States of Books)
This commit is contained in:
commit
18456eb9c4
@ -218,26 +218,40 @@ void ContentManager::onCustomContextMenu(const QPoint &point)
|
|||||||
QAction menuCancelBook(gt("cancel-download"), this);
|
QAction menuCancelBook(gt("cancel-download"), this);
|
||||||
QAction menuOpenFolder(gt("open-folder"), this);
|
QAction menuOpenFolder(gt("open-folder"), this);
|
||||||
|
|
||||||
if (const auto download = bookNode->getDownloadState()) {
|
const auto bookState = getBookState(id);
|
||||||
if (download->paused) {
|
switch ( bookState ) {
|
||||||
|
case BookState::DOWNLOAD_PAUSED:
|
||||||
contextMenu.addAction(&menuResumeBook);
|
contextMenu.addAction(&menuResumeBook);
|
||||||
} else {
|
|
||||||
contextMenu.addAction(&menuPauseBook);
|
|
||||||
}
|
|
||||||
contextMenu.addAction(&menuCancelBook);
|
contextMenu.addAction(&menuCancelBook);
|
||||||
} else {
|
break;
|
||||||
try {
|
|
||||||
|
case BookState::DOWNLOADING:
|
||||||
|
contextMenu.addAction(&menuPauseBook);
|
||||||
|
contextMenu.addAction(&menuCancelBook);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BookState::AVAILABLE_LOCALLY_AND_HEALTHY:
|
||||||
|
case BookState::ERROR_MISSING_ZIM_FILE:
|
||||||
|
case BookState::ERROR_CORRUPTED_ZIM_FILE:
|
||||||
|
{
|
||||||
const auto book = mp_library->getBookById(id);
|
const auto book = mp_library->getBookById(id);
|
||||||
auto bookPath = QString::fromStdString(book.getPath());
|
auto bookPath = QString::fromStdString(book.getPath());
|
||||||
|
if ( bookState == BookState::AVAILABLE_LOCALLY_AND_HEALTHY ) {
|
||||||
contextMenu.addAction(&menuOpenBook);
|
contextMenu.addAction(&menuOpenBook);
|
||||||
|
}
|
||||||
contextMenu.addAction(&menuDeleteBook);
|
contextMenu.addAction(&menuDeleteBook);
|
||||||
contextMenu.addAction(&menuOpenFolder);
|
contextMenu.addAction(&menuOpenFolder);
|
||||||
connect(&menuOpenFolder, &QAction::triggered, [=]() {
|
connect(&menuOpenFolder, &QAction::triggered, [=]() {
|
||||||
openFileLocation(bookPath, mp_view);
|
openFileLocation(bookPath, mp_view);
|
||||||
});
|
});
|
||||||
} catch (...) {
|
break;
|
||||||
contextMenu.addAction(&menuDownloadBook);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BookState::AVAILABLE_ONLINE:
|
||||||
|
contextMenu.addAction(&menuDownloadBook);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(&menuDeleteBook, &QAction::triggered, [=]() {
|
connect(&menuDeleteBook, &QAction::triggered, [=]() {
|
||||||
@ -390,6 +404,19 @@ QVariant getBookAttribute(const kiwix::Book& b, const QString& a)
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentManager::BookState getStateOfLocalBook(const kiwix::Book& book)
|
||||||
|
{
|
||||||
|
if ( !book.isPathValid() ) {
|
||||||
|
return ContentManager::BookState::ERROR_MISSING_ZIM_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX: When a book is detected to be corrupted, information about that
|
||||||
|
// XXX: has to be recorded somewhere so that we can return
|
||||||
|
// XXX: ERROR_CORRUPTED_ZIM_FILE here
|
||||||
|
|
||||||
|
return ContentManager::BookState::AVAILABLE_LOCALLY_AND_HEALTHY;
|
||||||
|
}
|
||||||
|
|
||||||
} // unnamed namespace
|
} // unnamed namespace
|
||||||
|
|
||||||
ContentManager::BookInfo ContentManager::getBookInfos(QString id, const QStringList &keys)
|
ContentManager::BookInfo ContentManager::getBookInfos(QString id, const QStringList &keys)
|
||||||
@ -420,17 +447,40 @@ ContentManager::BookInfo ContentManager::getBookInfos(QString id, const QStringL
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentManager::BookState ContentManager::getBookState(QString bookId)
|
||||||
|
{
|
||||||
|
if ( const auto downloadState = m_downloads.value(bookId) ) {
|
||||||
|
return downloadState->paused
|
||||||
|
? BookState::DOWNLOAD_PAUSED
|
||||||
|
: BookState::DOWNLOADING;
|
||||||
|
// TODO: a download may be in error state
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const kiwix::Book& b = mp_library->getBookById(bookId);
|
||||||
|
return b.getDownloadId().empty()
|
||||||
|
? getStateOfLocalBook(b)
|
||||||
|
: BookState::DOWNLOADING;
|
||||||
|
} catch (...) {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
QMutexLocker locker(&remoteLibraryLocker);
|
||||||
|
const kiwix::Book& b = mp_remoteLibrary->getBookById(bookId.toStdString());
|
||||||
|
return !b.getUrl().empty()
|
||||||
|
? BookState::AVAILABLE_ONLINE
|
||||||
|
: BookState::METADATA_ONLY;
|
||||||
|
} catch (...) {}
|
||||||
|
|
||||||
|
return BookState::INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
void ContentManager::openBookWithIndex(const QModelIndex &index)
|
void ContentManager::openBookWithIndex(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
try {
|
|
||||||
auto bookNode = static_cast<Node*>(index.internalPointer());
|
auto bookNode = static_cast<Node*>(index.internalPointer());
|
||||||
const QString bookId = bookNode->getBookId();
|
const QString bookId = bookNode->getBookId();
|
||||||
// throws std::out_of_range if the book isn't available in local library
|
if ( getBookState(bookId) == BookState::AVAILABLE_LOCALLY_AND_HEALTHY ) {
|
||||||
const kiwix::Book& book = mp_library->getBookById(bookId);
|
|
||||||
if ( !book.getDownloadId().empty() )
|
|
||||||
return;
|
|
||||||
openBook(bookId);
|
openBook(bookId);
|
||||||
} catch (std::out_of_range &e) {}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentManager::openBook(const QString &id)
|
void ContentManager::openBook(const QString &id)
|
||||||
|
@ -20,6 +20,43 @@ public: // types
|
|||||||
typedef ContentManagerModel::BookInfo BookInfo;
|
typedef ContentManagerModel::BookInfo BookInfo;
|
||||||
typedef ContentManagerModel::BookInfoList BookInfoList;
|
typedef ContentManagerModel::BookInfoList BookInfoList;
|
||||||
|
|
||||||
|
enum class BookState
|
||||||
|
{
|
||||||
|
// Nothing known about a book with that id
|
||||||
|
INVALID,
|
||||||
|
|
||||||
|
// Only (some) metadata is available for the book, however neither a
|
||||||
|
// ZIM-file nor a URL is associated with it.
|
||||||
|
METADATA_ONLY,
|
||||||
|
|
||||||
|
// No ZIM file is associated with the book but a URL is provided.
|
||||||
|
AVAILABLE_ONLINE,
|
||||||
|
|
||||||
|
// The book is being downloaded.
|
||||||
|
DOWNLOADING,
|
||||||
|
|
||||||
|
// The book started downloading, but the download is currently paused.
|
||||||
|
DOWNLOAD_PAUSED,
|
||||||
|
|
||||||
|
// The book started downloading but the download was stopped due to
|
||||||
|
// errors.
|
||||||
|
DOWNLOAD_ERROR,
|
||||||
|
|
||||||
|
// A valid ZIM file path is associated with the book and no evidence
|
||||||
|
// about any issues with that ZIM file has so far been obtained.
|
||||||
|
AVAILABLE_LOCALLY_AND_HEALTHY,
|
||||||
|
|
||||||
|
// A ZIM file path is associated with the book but no such file seems
|
||||||
|
// to exist (may be caused by missing read permissions for the directory
|
||||||
|
// containing the ZIM file).
|
||||||
|
ERROR_MISSING_ZIM_FILE,
|
||||||
|
|
||||||
|
// A ZIM file is associated with the book but it cannot be opened
|
||||||
|
// due to issues with its content.
|
||||||
|
ERROR_CORRUPTED_ZIM_FILE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
public: // functions
|
public: // functions
|
||||||
explicit ContentManager(Library* library, kiwix::Downloader *downloader, QObject *parent = nullptr);
|
explicit ContentManager(Library* library, kiwix::Downloader *downloader, QObject *parent = nullptr);
|
||||||
virtual ~ContentManager();
|
virtual ~ContentManager();
|
||||||
@ -49,6 +86,7 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
QStringList getTranslations(const QStringList &keys);
|
QStringList getTranslations(const QStringList &keys);
|
||||||
BookInfo getBookInfos(QString id, const QStringList &keys);
|
BookInfo getBookInfos(QString id, const QStringList &keys);
|
||||||
|
BookState getBookState(QString id);
|
||||||
void openBook(const QString& id);
|
void openBook(const QString& id);
|
||||||
void downloadBook(const QString& id);
|
void downloadBook(const QString& id);
|
||||||
void downloadBook(const QString& id, QModelIndex index);
|
void downloadBook(const QString& id, QModelIndex index);
|
||||||
|
@ -146,17 +146,39 @@ void showDownloadProgress(QPainter *painter, QRect box, const DownloadState& dow
|
|||||||
createArc(painter, startAngle, spanAngle, rectangle, pen);
|
createArc(painter, startAngle, spanAngle, rectangle, pen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentManagerDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
void ContentManagerDelegate::paintButton(QPainter *p, const QRect &r, QString t) const
|
||||||
{
|
{
|
||||||
QStyleOptionButton button;
|
QStyleOptionButton button;
|
||||||
QRect r = option.rect;
|
button.rect = r;
|
||||||
int x,y,w,h;
|
|
||||||
x = r.left();
|
|
||||||
y = r.top();
|
|
||||||
w = r.width();
|
|
||||||
h = r.height();
|
|
||||||
button.rect = QRect(x,y,w,h);
|
|
||||||
button.state = QStyle::State_Enabled;
|
button.state = QStyle::State_Enabled;
|
||||||
|
button.text = t;
|
||||||
|
baseButton->style()->drawControl( QStyle::CE_PushButton, &button, p, baseButton.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentManagerDelegate::paintBookState(QPainter *p, QRect r, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
const auto node = static_cast<RowNode*>(index.internalPointer());
|
||||||
|
const auto id = node->getBookId();
|
||||||
|
switch ( KiwixApp::instance()->getContentManager()->getBookState(id) ) {
|
||||||
|
case ContentManager::BookState::AVAILABLE_LOCALLY_AND_HEALTHY:
|
||||||
|
return paintButton(p, r, gt("open"));
|
||||||
|
|
||||||
|
case ContentManager::BookState::AVAILABLE_ONLINE:
|
||||||
|
return paintButton(p, r, gt("download"));
|
||||||
|
|
||||||
|
case ContentManager::BookState::DOWNLOADING:
|
||||||
|
case ContentManager::BookState::DOWNLOAD_PAUSED:
|
||||||
|
case ContentManager::BookState::DOWNLOAD_ERROR:
|
||||||
|
return showDownloadProgress(p, r, *node->getDownloadState());
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentManagerDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QRect r = option.rect;
|
||||||
if (index.parent().isValid()) {
|
if (index.parent().isValid()) {
|
||||||
// additional info
|
// additional info
|
||||||
QRect nRect = r;
|
QRect nRect = r;
|
||||||
@ -165,24 +187,9 @@ void ContentManagerDelegate::paint(QPainter *painter, const QStyleOptionViewItem
|
|||||||
painter->drawText(nRect, Qt::AlignLeft | Qt::AlignVCenter, index.data(Qt::UserRole+1).toString());
|
painter->drawText(nRect, Qt::AlignLeft | Qt::AlignVCenter, index.data(Qt::UserRole+1).toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto node = static_cast<RowNode*>(index.internalPointer());
|
|
||||||
try {
|
|
||||||
const auto id = node->getBookId();
|
|
||||||
const auto book = KiwixApp::instance()->getLibrary()->getBookById(id);
|
|
||||||
if ( book.getDownloadId().empty() ) {
|
|
||||||
button.text = gt("open");
|
|
||||||
}
|
|
||||||
} catch (std::out_of_range& e) {
|
|
||||||
button.text = gt("download");
|
|
||||||
}
|
|
||||||
QStyleOptionViewItem eOpt = option;
|
QStyleOptionViewItem eOpt = option;
|
||||||
if (index.column() == 5) {
|
if (index.column() == 5) {
|
||||||
if (const auto downloadState = node->getDownloadState()) {
|
paintBookState(painter, option.rect, index);
|
||||||
showDownloadProgress(painter, r, *downloadState);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
baseButton->style()->drawControl( QStyle::CE_PushButton, &button, painter, baseButton.data());
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (index.column() == 0) {
|
if (index.column() == 0) {
|
||||||
@ -192,7 +199,7 @@ void ContentManagerDelegate::paint(QPainter *painter, const QStyleOptionViewItem
|
|||||||
QPixmap pix;
|
QPixmap pix;
|
||||||
pix.loadFromData(iconData);
|
pix.loadFromData(iconData);
|
||||||
QIcon icon(pix);
|
QIcon icon(pix);
|
||||||
icon.paint(painter, QRect(x+10, y+10, 30, 50));
|
icon.paint(painter, QRect(r.left()+10, r.top()+10, 30, 50));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (index.column() == 1) {
|
if (index.column() == 1) {
|
||||||
@ -249,23 +256,24 @@ void ContentManagerDelegate::handleLastColumnClicked(const QModelIndex& index, Q
|
|||||||
int x = r.left();
|
int x = r.left();
|
||||||
int w = r.width();
|
int w = r.width();
|
||||||
|
|
||||||
if (const auto downloadState = node->getDownloadState()) {
|
ContentManager& contentMgr = *KiwixApp::instance()->getContentManager();
|
||||||
if (downloadState->paused) {
|
switch ( contentMgr.getBookState(id) ) {
|
||||||
if (clickX < (x + w/2)) {
|
case ContentManager::BookState::AVAILABLE_LOCALLY_AND_HEALTHY:
|
||||||
KiwixApp::instance()->getContentManager()->cancelBook(id);
|
return contentMgr.openBook(id);
|
||||||
} else {
|
|
||||||
KiwixApp::instance()->getContentManager()->resumeBook(id, index);
|
case ContentManager::BookState::AVAILABLE_ONLINE:
|
||||||
}
|
return contentMgr.downloadBook(id, index);
|
||||||
} else {
|
|
||||||
KiwixApp::instance()->getContentManager()->pauseBook(id, index);
|
case ContentManager::BookState::DOWNLOADING:
|
||||||
}
|
return contentMgr.pauseBook(id, index);
|
||||||
} else {
|
|
||||||
try {
|
case ContentManager::BookState::DOWNLOAD_PAUSED:
|
||||||
const auto book = KiwixApp::instance()->getLibrary()->getBookById(id);
|
return clickX < (x + w/2)
|
||||||
KiwixApp::instance()->getContentManager()->openBook(id);
|
? contentMgr.cancelBook(id)
|
||||||
} catch (std::out_of_range& e) {
|
: contentMgr.resumeBook(id, index);
|
||||||
KiwixApp::instance()->getContentManager()->downloadBook(id, index);
|
|
||||||
}
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,10 @@ public:
|
|||||||
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
|
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
|
||||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
private: // functions
|
||||||
|
void paintBookState(QPainter *p, QRect r, const QModelIndex &index) const;
|
||||||
|
void paintButton(QPainter *p, const QRect &r, QString t) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<QPushButton> baseButton;
|
QScopedPointer<QPushButton> baseButton;
|
||||||
QByteArray placeholderIcon;
|
QByteArray placeholderIcon;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user