File indexing completed on 2024-05-12 05:29:34

0001 /*
0002  *   SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org>
0003  *   SPDX-FileCopyrightText: 2008 Marco Martin <notmart@gmail.com>
0004  *   SPDX-FileCopyrightText: 2008-2011 Matthias Fuchs <mat69@gmx.net>
0005  *   SPDX-FileCopyrightText: 2012 Reza Fatahilah Shah <rshah0385@kireihana.com>
0006  *   SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
0007  *   SPDX-FileCopyrightText: 2022 Alexander Lohnau <alexander.lohnau@gmx.de>
0008  *
0009  *   SPDX-License-Identifier: GPL-2.0-or-later
0010  */
0011 
0012 #include "comic.h"
0013 #include "checknewstrips.h"
0014 #include "comic_debug.h"
0015 #include "comicsaver.h"
0016 #include "stripselector.h"
0017 
0018 #include <QAction>
0019 #include <QDebug>
0020 #include <QNetworkInformation>
0021 #include <QScreen>
0022 #include <QSortFilterProxyModel>
0023 #include <QTimer>
0024 #include <QWindow>
0025 
0026 #include <KActionCollection>
0027 #include <KApplicationTrader>
0028 #include <KConfigDialog>
0029 #include <KIO/OpenUrlJob>
0030 #include <KLocalizedString>
0031 #include <KNotification>
0032 #include <KService>
0033 #include <KStandardShortcut>
0034 #include <kuiserverjobtracker.h>
0035 
0036 #include <Plasma/Containment>
0037 
0038 #include "comicmodel.h"
0039 
0040 ComicApplet::ComicApplet(QObject *parent, const KPluginMetaData &data, const QVariantList &args)
0041     : Plasma::Applet(parent, data, args)
0042     , mProxy(nullptr)
0043     , mActiveComicModel(new ActiveComicModel(parent))
0044     , mDifferentComic(true)
0045     , mShowComicUrl(false)
0046     , mShowComicAuthor(false)
0047     , mShowComicTitle(false)
0048     , mShowComicIdentifier(false)
0049     , mShowErrorPicture(true)
0050     , mArrowsOnHover(true)
0051     , mMiddleClick(true)
0052     , mCheckNewComicStripsInterval(0)
0053     , mMaxComicLimit(0)
0054     , mCheckNewStrips(nullptr)
0055     , mActionShop(nullptr)
0056     , mEngine(new ComicEngine(this))
0057     , mSavingDir(nullptr)
0058 {
0059     setHasConfigurationInterface(true);
0060 }
0061 
0062 void ComicApplet::init()
0063 {
0064     mSavingDir = new SavingDir(config());
0065 
0066     configChanged();
0067 
0068     mModel = new ComicModel(mEngine, mTabIdentifier, this);
0069     mProxy = new QSortFilterProxyModel(this);
0070     mProxy->setSourceModel(mModel);
0071     mProxy->setSortCaseSensitivity(Qt::CaseInsensitive);
0072     mProxy->sort(1, Qt::AscendingOrder);
0073 
0074     mCurrentDay = QDate::currentDate();
0075     mDateChangedTimer = new QTimer(this);
0076     connect(mDateChangedTimer, &QTimer::timeout, this, &ComicApplet::checkDayChanged);
0077     mDateChangedTimer->setInterval(5 * 60 * 1000); // every 5 minutes
0078     mDateChangedTimer->start();
0079 
0080     mActionNextNewStripTab = new QAction(QIcon::fromTheme(QStringLiteral("go-next-view")), i18nc("@action comic strip", "&Next Tab with a New Strip"), this);
0081     mActionNextNewStripTab->setShortcuts(KStandardShortcut::openNew());
0082     setInternalAction(QStringLiteral("next new strip"), mActionNextNewStripTab);
0083     mActions.append(mActionNextNewStripTab);
0084     connect(mActionNextNewStripTab, &QAction::triggered, this, &ComicApplet::showNextNewStrip);
0085 
0086     mActionGoFirst = new QAction(QIcon::fromTheme(QStringLiteral("go-first")), i18nc("@action", "Jump to &First Strip"), this);
0087     mActions.append(mActionGoFirst);
0088     connect(mActionGoFirst, &QAction::triggered, this, &ComicApplet::slotFirstDay);
0089 
0090     mActionGoLast = new QAction(QIcon::fromTheme(QStringLiteral("go-last")), i18nc("@action", "Jump to &Current Strip"), this);
0091     mActions.append(mActionGoLast);
0092     connect(mActionGoLast, &QAction::triggered, this, &ComicApplet::slotCurrentDay);
0093 
0094     mActionGoJump = new QAction(QIcon::fromTheme(QStringLiteral("go-jump")), i18nc("@action", "Jump to Strip…"), this);
0095     mActions.append(mActionGoJump);
0096     connect(mActionGoJump, &QAction::triggered, this, &ComicApplet::slotGoJump);
0097 
0098     mActionWebsite = new QAction(i18nc("@action", "Visit the Website"), this);
0099     KService::Ptr browser = KApplicationTrader::preferredService(QStringLiteral("x-scheme-handler/https"));
0100 
0101     if (browser) {
0102         mActionWebsite->setText(i18nc("@action:inmenu %1 is the name of a web browser", "View in %1", browser->name()));
0103         mActionWebsite->setIcon(QIcon::fromTheme(browser->icon()));
0104     }
0105 
0106     mActionWebsite->setEnabled(false);
0107     mActions.append(mActionWebsite);
0108     connect(mActionWebsite, &QAction::triggered, this, &ComicApplet::slotWebsite);
0109 
0110     mActionShop = new QAction(i18nc("@action", "Visit the Shop &Website"), this);
0111     mActionShop->setEnabled(false);
0112     mActions.append(mActionShop);
0113     connect(mActionShop, &QAction::triggered, this, &ComicApplet::slotShop);
0114 
0115     mActionSaveComicAs = new QAction(QIcon::fromTheme(QStringLiteral("document-save-as")), i18nc("@action", "&Save Comic As…"), this);
0116     mActions.append(mActionSaveComicAs);
0117     connect(mActionSaveComicAs, &QAction::triggered, this, &ComicApplet::slotSaveComicAs);
0118 
0119     mActionScaleContent = new QAction(QIcon::fromTheme(QStringLiteral("zoom-original")), //
0120                                       i18nc("@option:check Context menu of comic image", "&Actual Size"),
0121                                       this);
0122     mActionScaleContent->setCheckable(true);
0123     mActionScaleContent->setChecked(mCurrent.scaleComic());
0124     mActions.append(mActionScaleContent);
0125     connect(mActionScaleContent, &QAction::triggered, this, &ComicApplet::slotScaleToContent);
0126 
0127     mActionStorePosition =
0128         new QAction(QIcon::fromTheme(QStringLiteral("go-home")), i18nc("@option:check Context menu of comic image", "Store Current &Position"), this);
0129     mActionStorePosition->setCheckable(true);
0130     mActionStorePosition->setChecked(mCurrent.hasStored());
0131     mActions.append(mActionStorePosition);
0132     connect(mActionStorePosition, &QAction::triggered, this, &ComicApplet::slotStorePosition);
0133 
0134     // make sure that tabs etc. are displayed even if the comic strip in the first tab does not work
0135     updateView();
0136 
0137     updateUsedComics();
0138     changeComic(true);
0139 
0140     connect(mEngine, &ComicEngine::requestFinished, this, &ComicApplet::dataUpdated);
0141 
0142     QNetworkInformation::instance()->loadBackendByFeatures(QNetworkInformation::Feature::Reachability);
0143     connect(QNetworkInformation::instance(), &QNetworkInformation::reachabilityChanged, this, [this](auto reachability) {
0144         if (reachability != QNetworkInformation::Reachability::Online) {
0145             return;
0146         }
0147         qCDebug(PLASMA_COMIC) << "Online status changed to true, requesting comic" << mPreviousFailedIdentifier;
0148         mEngine->requestSource(mPreviousFailedIdentifier);
0149     });
0150 }
0151 
0152 ComicApplet::~ComicApplet()
0153 {
0154     delete mSavingDir;
0155 }
0156 
0157 void ComicApplet::dataUpdated(const ComicMetaData &data)
0158 {
0159     const QString source = data.identifier;
0160     setBusy(false);
0161 
0162     // disconnect prefetched comic strips
0163     if (source != mOldSource) {
0164         return;
0165     }
0166 
0167     setConfigurationRequired(mCurrent.id().isEmpty());
0168 
0169     // there was an error, display information as image
0170     if (data.error) {
0171         mPreviousFailedIdentifier = source;
0172         if (!mShowErrorPicture && !data.previousIdentifier.isEmpty()) {
0173             updateComic(data.previousIdentifier);
0174         }
0175         return;
0176     }
0177 
0178     mCurrent.setData(data);
0179 
0180     // looking at the last index, thus not mark it as new
0181     KConfigGroup cg = config();
0182     if (!mCurrent.hasNext() && mCheckNewComicStripsInterval) {
0183         setTabHighlighted(mCurrent.id(), false);
0184         mActionNextNewStripTab->setEnabled(isTabHighlighted(mCurrent.id()));
0185     }
0186 
0187     // call the slot to check if the position needs to be saved
0188     slotStorePosition();
0189 
0190     // prefetch the previous and following comic for faster navigation
0191     if (mCurrent.hasNext()) {
0192         const QString prefetch = mCurrent.id() + QLatin1Char(':') + mCurrent.next();
0193         mEngine->requestSource(prefetch);
0194     }
0195     if (mCurrent.hasPrev()) {
0196         const QString prefetch = mCurrent.id() + QLatin1Char(':') + mCurrent.prev();
0197         mEngine->requestSource(prefetch);
0198     }
0199 
0200     updateView();
0201 
0202     refreshComicData();
0203 }
0204 
0205 void ComicApplet::updateView()
0206 {
0207     updateContextMenu();
0208 }
0209 
0210 void ComicApplet::positionFullView(QWindow *window)
0211 {
0212     if (!window || !window->screen()) {
0213         return;
0214     }
0215 
0216     window->setPosition(window->screen()->availableGeometry().center() - QPoint(window->size().width() / 2, window->size().height() / 2));
0217 }
0218 
0219 void ComicApplet::changeComic(bool differentComic)
0220 {
0221     if (differentComic) {
0222         KConfigGroup cg = config();
0223         mActionStorePosition->setChecked(mCurrent.storePosition());
0224 
0225         // assign mScaleComic the moment the new strip has been loaded (dataUpdated) as up to this point
0226         // the old one should be still shown with its scaling settings
0227         mActionScaleContent->setChecked(mCurrent.scaleComic());
0228 
0229         updateComic(mCurrent.stored());
0230     } else {
0231         updateComic(mCurrent.current());
0232     }
0233 }
0234 
0235 void ComicApplet::updateUsedComics()
0236 {
0237     const QString oldIdentifier = mCurrent.id();
0238 
0239     mActiveComicModel->clear();
0240     mCurrent = ComicData();
0241 
0242     bool isFirst = true;
0243     QModelIndex data;
0244     KConfigGroup cg = config();
0245     int tab = 0;
0246     for (int i = 0; i < mProxy->rowCount(); ++i) {
0247         if (mTabIdentifier.contains(mProxy->index(i, 0).data(Qt::UserRole).toString())) {
0248             data = mProxy->index(i, 1);
0249 
0250             if (isFirst) {
0251                 isFirst = false;
0252                 const QString id = data.data(Qt::UserRole).toString();
0253                 mDifferentComic = (oldIdentifier != id);
0254                 const QString title = data.data().toString();
0255                 mCurrent.init(id, config());
0256                 mCurrent.setTitle(title);
0257             }
0258 
0259             const QString name = data.data().toString();
0260             const QString identifier = data.data(Qt::UserRole).toString();
0261             const QIcon icon = data.data(Qt::DecorationRole).value<QIcon>();
0262             // found a newer strip last time, which was not visited
0263 
0264             if (mCheckNewComicStripsInterval && !cg.readEntry(QLatin1String("lastStripVisited_") + identifier, true)) {
0265                 mActiveComicModel->addComic(identifier, name, icon, true);
0266             } else {
0267                 mActiveComicModel->addComic(identifier, name, icon);
0268             }
0269 
0270             ++tab;
0271         }
0272     }
0273 
0274     mActionNextNewStripTab->setVisible(mCheckNewComicStripsInterval);
0275     mActionNextNewStripTab->setEnabled(isTabHighlighted(mCurrent.id()));
0276 
0277     delete mCheckNewStrips;
0278     mCheckNewStrips = nullptr;
0279     if (mCheckNewComicStripsInterval) {
0280         mCheckNewStrips = new CheckNewStrips(mTabIdentifier, mEngine, mCheckNewComicStripsInterval, this);
0281         connect(mCheckNewStrips, &CheckNewStrips::lastStrip, this, &ComicApplet::slotFoundLastStrip);
0282     }
0283 
0284     Q_EMIT comicModelChanged();
0285 }
0286 
0287 void ComicApplet::slotTabChanged(const QString &identifier)
0288 {
0289     bool differentComic = (mCurrent.id() != identifier);
0290     mCurrent = ComicData();
0291     mCurrent.init(identifier, config());
0292     changeComic(differentComic);
0293 }
0294 
0295 void ComicApplet::checkDayChanged()
0296 {
0297     if (mCurrentDay != QDate::currentDate()) {
0298         updateComic(mCurrent.current());
0299         mCurrentDay = QDate::currentDate();
0300     } else if (!mCurrent.hasImage()) {
0301         updateComic(mCurrent.stored());
0302     }
0303 }
0304 
0305 void ComicApplet::configChanged()
0306 {
0307     KConfigGroup cg = config();
0308     mTabIdentifier = cg.readEntry("tabIdentifier", QStringList());
0309 
0310     if (mProxy) {
0311         updateUsedComics();
0312     }
0313 
0314     const QString id = mTabIdentifier.count() ? mTabIdentifier.at(0) : QString();
0315     mCurrent = ComicData();
0316     mCurrent.init(id, cg);
0317 
0318     mShowComicUrl = cg.readEntry("showComicUrl", false);
0319     mShowComicAuthor = cg.readEntry("showComicAuthor", false);
0320     mShowComicTitle = cg.readEntry("showComicTitle", false);
0321     mShowComicIdentifier = cg.readEntry("showComicIdentifier", false);
0322     mShowErrorPicture = cg.readEntry("showErrorPicture", true);
0323     mArrowsOnHover = cg.readEntry("arrowsOnHover", true);
0324     mMiddleClick = cg.readEntry("middleClick", true);
0325     mCheckNewComicStripsInterval = cg.readEntry("checkNewComicStripsIntervall", 30);
0326 
0327     auto oldMaxComicLimit = mMaxComicLimit;
0328     mMaxComicLimit = cg.readEntry("maxComicLimit", 29);
0329     if (oldMaxComicLimit != mMaxComicLimit) {
0330         mEngine->setMaxComicLimit(mMaxComicLimit);
0331     }
0332 }
0333 
0334 void ComicApplet::saveConfig()
0335 {
0336     KConfigGroup cg = config();
0337     cg.writeEntry("comic", mCurrent.id());
0338     cg.writeEntry("showComicUrl", mShowComicUrl);
0339     cg.writeEntry("showComicAuthor", mShowComicAuthor);
0340     cg.writeEntry("showComicTitle", mShowComicTitle);
0341     cg.writeEntry("showComicIdentifier", mShowComicIdentifier);
0342     cg.writeEntry("showErrorPicture", mShowErrorPicture);
0343     cg.writeEntry("arrowsOnHover", mArrowsOnHover);
0344     cg.writeEntry("middleClick", mMiddleClick);
0345     cg.writeEntry("tabIdentifier", mTabIdentifier);
0346     cg.writeEntry("checkNewComicStripsIntervall", mCheckNewComicStripsInterval);
0347     cg.writeEntry("maxComicLimit", mMaxComicLimit);
0348 }
0349 
0350 void ComicApplet::slotNextDay()
0351 {
0352     updateComic(mCurrent.next());
0353 }
0354 
0355 void ComicApplet::slotPreviousDay()
0356 {
0357     updateComic(mCurrent.prev());
0358 }
0359 
0360 void ComicApplet::slotFirstDay()
0361 {
0362     updateComic(mCurrent.first());
0363 }
0364 
0365 void ComicApplet::slotCurrentDay()
0366 {
0367     updateComic(QString());
0368 }
0369 
0370 void ComicApplet::slotFoundLastStrip(int index, const QString &identifier, const QString &suffix)
0371 {
0372     Q_UNUSED(index)
0373 
0374     if (mCurrent.id() != identifier) {
0375         return;
0376     }
0377 
0378     KConfigGroup cg = config();
0379     if (suffix != cg.readEntry(QLatin1String("lastStrip_") + identifier, QString())) {
0380         qDebug() << identifier << "has a newer strip.";
0381         cg.writeEntry(QLatin1String("lastStripVisited_") + identifier, false);
0382         updateComic(suffix);
0383     }
0384 }
0385 
0386 void ComicApplet::slotGoJump()
0387 {
0388     StripSelector *selector = StripSelectorFactory::create(mCurrent.type());
0389     connect(selector, &StripSelector::stripChosen, this, &ComicApplet::updateComic);
0390 
0391     selector->select(mCurrent);
0392 }
0393 
0394 void ComicApplet::slotStorePosition()
0395 {
0396     mCurrent.storePosition(mActionStorePosition->isChecked());
0397 }
0398 
0399 void ComicApplet::slotWebsite()
0400 {
0401     auto *job = new KIO::OpenUrlJob(mCurrent.websiteUrl());
0402     job->start();
0403 }
0404 
0405 void ComicApplet::slotShop()
0406 {
0407     auto *job = new KIO::OpenUrlJob(mCurrent.shopUrl());
0408     job->start();
0409 }
0410 
0411 QList<QAction *> ComicApplet::contextualActions()
0412 {
0413     return mActions;
0414 }
0415 
0416 void ComicApplet::updateComic(const QString &identifierSuffix)
0417 {
0418     const QString id = mCurrent.id();
0419     setConfigurationRequired(id.isEmpty());
0420 
0421     if (!id.isEmpty()) {
0422         setBusy(true);
0423 
0424         const QString identifier = id + QLatin1Char(':') + identifierSuffix;
0425 
0426         // disconnecting of the oldSource is needed, otherwise you could get data for comics you are not looking at if you use tabs
0427         // if there was an error only disconnect the oldSource if it had nothing to do with the error or if the comic changed, that way updates of the error can
0428         // come in
0429         if (!mIdentifierError.isEmpty() && !mIdentifierError.contains(id)) {
0430             mIdentifierError.clear();
0431         }
0432         mOldSource = identifier;
0433         mEngine->requestSource(identifier);
0434         slotScaleToContent();
0435     } else {
0436         setBusy(false);
0437         qWarning() << "Either no identifier was specified or the engine could not be created:"
0438                    << "id" << id;
0439     }
0440     updateContextMenu();
0441 }
0442 
0443 void ComicApplet::updateContextMenu()
0444 {
0445     if (mCurrent.id().isEmpty()) {
0446         mActiveComicModel->clear();
0447     }
0448 
0449     if (mCurrent.id().isEmpty() || !mCurrent.ready()) {
0450         mActionNextNewStripTab->setEnabled(false);
0451         mActionGoFirst->setEnabled(false);
0452         mActionGoLast->setEnabled(false);
0453         mActionScaleContent->setEnabled(false);
0454         mActionWebsite->setEnabled(false);
0455         mActionShop->setEnabled(false);
0456         mActionStorePosition->setEnabled(false);
0457         mActionGoJump->setEnabled(false);
0458         mActionSaveComicAs->setEnabled(false);
0459         mActionScaleContent->setChecked(false);
0460     } else {
0461         mActionGoFirst->setVisible(mCurrent.hasFirst());
0462         mActionGoFirst->setEnabled(mCurrent.hasPrev());
0463         mActionGoLast->setEnabled(true);
0464         mActionWebsite->setEnabled(true);
0465         mActionShop->setEnabled(mCurrent.shopUrl().isValid());
0466         mActionScaleContent->setEnabled(true);
0467         mActionStorePosition->setEnabled(true);
0468         mActionGoJump->setEnabled(true);
0469         mActionSaveComicAs->setEnabled(true);
0470     }
0471 }
0472 
0473 void ComicApplet::slotSaveComicAs()
0474 {
0475     ComicSaver saver(mSavingDir);
0476     saver.save(mCurrent);
0477 }
0478 
0479 void ComicApplet::slotScaleToContent()
0480 {
0481     setShowActualSize(mActionScaleContent->isChecked());
0482 }
0483 
0484 // QML
0485 QObject *ComicApplet::comicsModel() const
0486 {
0487     return mActiveComicModel;
0488 }
0489 
0490 QObject *ComicApplet::availableComicsModel() const
0491 {
0492     return mProxy;
0493 }
0494 
0495 bool ComicApplet::showComicUrl() const
0496 {
0497     return mShowComicUrl;
0498 }
0499 
0500 void ComicApplet::setShowComicUrl(bool show)
0501 {
0502     if (show == mShowComicUrl) {
0503         return;
0504     }
0505 
0506     mShowComicUrl = show;
0507 
0508     Q_EMIT showComicUrlChanged();
0509 }
0510 
0511 bool ComicApplet::showComicAuthor() const
0512 {
0513     return mShowComicAuthor;
0514 }
0515 
0516 void ComicApplet::setShowComicAuthor(bool show)
0517 {
0518     if (show == mShowComicAuthor) {
0519         return;
0520     }
0521 
0522     mShowComicAuthor = show;
0523 
0524     Q_EMIT showComicAuthorChanged();
0525 }
0526 
0527 bool ComicApplet::showComicTitle() const
0528 {
0529     return mShowComicTitle;
0530 }
0531 
0532 void ComicApplet::setShowComicTitle(bool show)
0533 {
0534     if (show == mShowComicTitle) {
0535         return;
0536     }
0537 
0538     mShowComicTitle = show;
0539 
0540     Q_EMIT showComicTitleChanged();
0541 }
0542 
0543 bool ComicApplet::showComicIdentifier() const
0544 {
0545     return mShowComicIdentifier;
0546 }
0547 
0548 void ComicApplet::setShowComicIdentifier(bool show)
0549 {
0550     if (show == mShowComicIdentifier) {
0551         return;
0552     }
0553 
0554     mShowComicIdentifier = show;
0555 
0556     Q_EMIT showComicIdentifierChanged();
0557 }
0558 
0559 bool ComicApplet::showErrorPicture() const
0560 {
0561     return mShowErrorPicture;
0562 }
0563 
0564 void ComicApplet::setShowErrorPicture(bool show)
0565 {
0566     if (show == mShowErrorPicture) {
0567         return;
0568     }
0569 
0570     mShowErrorPicture = show;
0571 
0572     Q_EMIT showErrorPictureChanged();
0573 }
0574 
0575 bool ComicApplet::arrowsOnHover() const
0576 {
0577     return mArrowsOnHover;
0578 }
0579 
0580 void ComicApplet::setArrowsOnHover(bool show)
0581 {
0582     if (show == mArrowsOnHover) {
0583         return;
0584     }
0585 
0586     mArrowsOnHover = show;
0587 
0588     Q_EMIT arrowsOnHoverChanged();
0589 }
0590 
0591 bool ComicApplet::middleClick() const
0592 {
0593     return mMiddleClick;
0594 }
0595 
0596 void ComicApplet::setMiddleClick(bool show)
0597 {
0598     if (show == mMiddleClick) {
0599         return;
0600     }
0601 
0602     mMiddleClick = show;
0603 
0604     Q_EMIT middleClickChanged();
0605     saveConfig();
0606 }
0607 
0608 QVariantMap ComicApplet::comicData() const
0609 {
0610     return mComicData;
0611 }
0612 
0613 QStringList ComicApplet::tabIdentifiers() const
0614 {
0615     return mTabIdentifier;
0616 }
0617 
0618 void ComicApplet::setTabIdentifiers(const QStringList &tabs)
0619 {
0620     if (mTabIdentifier == tabs) {
0621         return;
0622     }
0623 
0624     mTabIdentifier = tabs;
0625     Q_EMIT tabIdentifiersChanged();
0626     saveConfig();
0627     changeComic(mDifferentComic);
0628 }
0629 
0630 void ComicApplet::refreshComicData()
0631 {
0632     mComicData[QStringLiteral("image")] = mCurrent.image();
0633     mComicData[QStringLiteral("prev")] = mCurrent.prev();
0634     mComicData[QStringLiteral("next")] = mCurrent.next();
0635     mComicData[QStringLiteral("additionalText")] = mCurrent.additionalText();
0636 
0637     mComicData[QStringLiteral("websiteUrl")] = mCurrent.websiteUrl().toString();
0638     mComicData[QStringLiteral("websiteHost")] = mCurrent.websiteUrl().host();
0639     mComicData[QStringLiteral("imageUrl")] = mCurrent.websiteUrl().toString();
0640     mComicData[QStringLiteral("shopUrl")] = mCurrent.websiteUrl().toString();
0641     mComicData[QStringLiteral("first")] = mCurrent.first();
0642     mComicData[QStringLiteral("stripTitle")] = mCurrent.stripTitle();
0643     mComicData[QStringLiteral("author")] = mCurrent.author();
0644     mComicData[QStringLiteral("title")] = mCurrent.title();
0645 
0646     mComicData[QStringLiteral("suffixType")] = QStringLiteral("Date");
0647     mComicData[QStringLiteral("current")] = mCurrent.current();
0648     // mComicData[QStringLiteral("last")] = mCurrent.last();
0649     mComicData[QStringLiteral("currentReadable")] = mCurrent.currentReadable();
0650     mComicData[QStringLiteral("firstStripNum")] = mCurrent.firstStripNum();
0651     mComicData[QStringLiteral("maxStripNum")] = mCurrent.maxStripNum();
0652     mComicData[QStringLiteral("isLeftToRight")] = mCurrent.isLeftToRight();
0653     mComicData[QStringLiteral("isTopToBottom")] = mCurrent.isTopToBottom();
0654 
0655     Q_EMIT comicDataChanged();
0656 }
0657 
0658 bool ComicApplet::showActualSize() const
0659 {
0660     return mCurrent.scaleComic();
0661 }
0662 
0663 void ComicApplet::setShowActualSize(bool show)
0664 {
0665     if (show == mCurrent.scaleComic()) {
0666         return;
0667     }
0668 
0669     mCurrent.setScaleComic(show);
0670 
0671     Q_EMIT showActualSizeChanged();
0672 }
0673 
0674 int ComicApplet::checkNewComicStripsInterval() const
0675 {
0676     return mCheckNewComicStripsInterval;
0677 }
0678 
0679 void ComicApplet::setCheckNewComicStripsInterval(int interval)
0680 {
0681     if (mCheckNewComicStripsInterval == interval) {
0682         return;
0683     }
0684 
0685     mCheckNewComicStripsInterval = interval;
0686     Q_EMIT checkNewComicStripsIntervalChanged();
0687 }
0688 
0689 void ComicApplet::setMaxComicLimit(int limit)
0690 {
0691     if (mMaxComicLimit == limit) {
0692         return;
0693     }
0694 
0695     mMaxComicLimit = limit;
0696     Q_EMIT maxComicLimitChanged();
0697 }
0698 
0699 int ComicApplet::maxComicLimit() const
0700 {
0701     return mMaxComicLimit;
0702 }
0703 
0704 // Endof QML
0705 void ComicApplet::setTabHighlighted(const QString &id, bool highlight)
0706 {
0707     // Search for matching id
0708     for (int i = 0; i < mActiveComicModel->rowCount(); ++i) {
0709         QStandardItem *item = mActiveComicModel->item(i);
0710 
0711         QString currentId = item->data(ActiveComicModel::ComicKeyRole).toString();
0712         if (id == currentId) {
0713             if (highlight != item->data(ActiveComicModel::ComicHighlightRole).toBool()) {
0714                 item->setData(highlight, ActiveComicModel::ComicHighlightRole);
0715                 Q_EMIT tabHighlightRequest(id, highlight);
0716             }
0717         }
0718     }
0719 }
0720 
0721 bool ComicApplet::isTabHighlighted(const QString &id) const
0722 {
0723     for (int i = 0; i < mActiveComicModel->rowCount(); ++i) {
0724         QStandardItem *item = mActiveComicModel->item(i);
0725 
0726         QString currentId = item->data(ActiveComicModel::ComicKeyRole).toString();
0727         if (id == currentId) {
0728             return item->data(ActiveComicModel::ComicHighlightRole).toBool();
0729         }
0730     }
0731     return false;
0732 }
0733 
0734 void ComicApplet::loadProviders()
0735 {
0736     mModel->load();
0737 }
0738 
0739 K_PLUGIN_CLASS(ComicApplet)
0740 
0741 #include "comic.moc"