diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..8a1cac4 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,28 @@ +kind: pipeline +name: default + +steps: + - name: build + image: einar/kde + pull: if-not-exists + commands: + - mkdir build + - cmake . -d build + - make -C build -j2 + when: + event: + - push + - name: pack + image: einar/kde + pull: if-not-exists + commands: + - mkdir build + - cmake . -d build + - make dist -C build + when: + event: + - tag + + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 77e94ea..985a773 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,20 @@ set(danbooru_client_VERSION_PATCH 0) set (danbooru_VERSION ${danbooru_client_VERSION_MAJOR}.${danbooru_client_VERSION_MINOR}.${danbooru_client_VERSION_PATCH}) +set(CPACK_PACKAGE_VERSION_MAJOR "${danbooru_client_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${danbooru_client_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${danbooru_client_VERSION_PATCH}") +set(CPACK_SOURCE_GENERATOR "TXZ") +set(CPACK_SOURCE_PACKAGE_FILE_NAME + "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") +set(CPACK_SOURCE_IGNORE_FILES + "/build/;/.bzr/;~$;/.git/;${CPACK_SOURCE_IGNORE_FILES}") +include(CPack) + +add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source) + find_package (ECM REQUIRED NO_MODULE) + set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) set(REQUIRED_QT_VERSION "5.4.0") @@ -29,6 +42,7 @@ find_package(Qt5Test ${REQUIRED_QT_VERSION}) find_package(KF5 ${KF5_VERSION} REQUIRED IconThemes # Handling of icons CoreAddons # Caches + TextWidgets # Spin boxes GuiAddons # Image cache Completion # KComboBox XmlGui # User interface @@ -37,23 +51,17 @@ find_package(KF5 ${KF5_VERSION} REQUIRED Wallet # Password handling Declarative # QML I18n # i18n + FileMetaData # Tagging # DocTools # Disabled until manual's ready ) -# Not a framework yet, hence separate -find_package(KF5 "5.6.0" COMPONENTS - FileMetaData) - - include(ECMInstallIcons) include(KDEInstallDirs) include(KDECompilerSettings) include(KDECMakeSettings) include(FeatureSummary) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") set(CMAKE_INCLUDE_CURRENT_DIR ON) -set_package_properties(KF5FileMetaData PROPERTIES TYPE OPTIONAL PURPOSE "Required for file tagging") set_package_properties(Qt5Test PROPERTIES TYPE OPTIONAL PURPOSE "Required to build tests") # add_subdirectory( doc ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6fb6e25..1a2d0e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ target_link_libraries(danbooru_client PUBLIC Qt5::Qml Qt5::QuickWidgets KF5::CoreAddons + KF5::TextWidgets KF5::IconThemes KF5::Completion KF5::I18n diff --git a/src/danbooru_client.cpp b/src/danbooru_client.cpp index 56a009f..14371b8 100644 --- a/src/danbooru_client.cpp +++ b/src/danbooru_client.cpp @@ -33,25 +33,25 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); - QCoreApplication::setApplicationName(QLatin1String("danbooru-client")); - QCoreApplication::setApplicationVersion(QLatin1String(DANBOORU_CLIENT_VERSION_STRING)); - QCoreApplication::setOrganizationDomain(QLatin1String("dennogumi.org")); + QCoreApplication::setApplicationName(QStringLiteral("danbooru-client")); + QCoreApplication::setApplicationVersion(QStringLiteral(DANBOORU_CLIENT_VERSION_STRING)); + QCoreApplication::setOrganizationDomain(QStringLiteral("dennogumi.org")); QApplication::setApplicationDisplayName(i18n("Danbooru Client")); KLocalizedString::setApplicationDomain("danbooru-client"); KAboutData aboutData(I18N_NOOP(QLatin1String("danbooru-client")), i18n("Danbooru Client"), - QLatin1String(DANBOORU_CLIENT_VERSION_STRING), + QStringLiteral(DANBOORU_CLIENT_VERSION_STRING), i18n("KF5 based Danbooru client"), KAboutLicense::GPL_V3, i18n("(C) 2015 Luca Beltrame"), QString("Using libdanbooru version %1").arg(LIBDANBOORU_VERSION_STRING), - QLatin1String("https://git.dennogumi.org/kde/danbooru-client"), - QLatin1String("https://git.dennogumi.org/kde/danbooru-client") + QStringLiteral("https://git.dennogumi.org/kde/danbooru-client"), + QStringLiteral("https://git.dennogumi.org/kde/danbooru-client") ); aboutData.addAuthor(i18n("Luca Beltrame"), i18n("Developer"), - QLatin1String("lbeltrame@kde.org") + QStringLiteral("lbeltrame@kde.org") ); KAboutData::setApplicationData(aboutData); diff --git a/src/danbooruconnectwidget.cpp b/src/danbooruconnectwidget.cpp index f428317..1859ca8 100644 --- a/src/danbooruconnectwidget.cpp +++ b/src/danbooruconnectwidget.cpp @@ -38,14 +38,14 @@ const QMap< QUrl, QString > initBoardSalts() QMap< QUrl, QString > boardSalts; - boardSalts.insert(QUrl("http://konachan.com"), - QString("So-I-Heard-You-Like-Mupkids-?--%1--")); - boardSalts.insert(QUrl("http://konachan.net"), - QString("So-I-Heard-You-Like-Mupkids-?--%1--")); - boardSalts.insert(QUrl("http://yande.re"), - QString("choujin-steiner--%1--")); - boardSalts.insert(QUrl("http://danbooru.donmai.us"), - QString("choujin-steiner--%1--")); + boardSalts.insert(QUrl(QStringLiteral("http://konachan.com")), + QStringLiteral("So-I-Heard-You-Like-Mupkids-?--%1--")); + boardSalts.insert(QUrl(QStringLiteral("http://konachan.net")), + QStringLiteral("So-I-Heard-You-Like-Mupkids-?--%1--")); + boardSalts.insert(QUrl(QStringLiteral("http://yande.re")), + QStringLiteral("choujin-steiner--%1--")); + boardSalts.insert(QUrl(QStringLiteral("http://danbooru.donmai.us")), + QStringLiteral("choujin-steiner--%1--")); return boardSalts; } @@ -61,7 +61,7 @@ DanbooruConnectWidget::DanbooruConnectWidget(QVector< QUrl > urlList, setupUi(this); danbooruUrlComboBox->setFocus(); - closeButton->setIcon(QIcon::fromTheme(QLatin1String("dialog-close"))); + closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); closeButton->setToolTip(i18n("Close dialog and discard changes")); userLineEdit->setClearButtonEnabled(true); passwdLineEdit->setClearButtonEnabled(true); @@ -74,7 +74,7 @@ DanbooruConnectWidget::DanbooruConnectWidget(QVector< QUrl > urlList, danbooruUrlComboBox->clear(); - for (auto item : urlList) { + Q_FOREACH(const auto& item, urlList) { danbooruUrlComboBox->insertUrl(urlList.indexOf(item), item); } @@ -128,20 +128,20 @@ void DanbooruConnectWidget::getWalletData() return; } - m_username = valueMap[QLatin1String("username")]; + m_username = valueMap[QStringLiteral("username")]; QString hashedPassword; // TODO: Handle the case where the "salt" is not known hashedPassword = boardSalts.value(key); - hashedPassword = hashedPassword.arg(valueMap[QLatin1String("password")]); + hashedPassword = hashedPassword.arg(valueMap[QStringLiteral("password")]); hashedPassword = QCryptographicHash::hash(hashedPassword.toUtf8(), QCryptographicHash::Sha1).toHex(); m_password = hashedPassword; userLineEdit->setText(m_username); - passwdLineEdit->setText(valueMap[QLatin1String("password")]); + passwdLineEdit->setText(valueMap[QStringLiteral("password")]); } } @@ -162,7 +162,7 @@ void DanbooruConnectWidget::setBoards(const QVector &urlList) danbooruUrlComboBox->clear(); - for (auto item : urlList) { + Q_FOREACH(const auto& item, urlList) { danbooruUrlComboBox->insertUrl(urlList.indexOf(item), item); } @@ -195,8 +195,8 @@ void DanbooruConnectWidget::accept() if (m_wallet && !m_wallet->hasEntry(currentBoard)) { QMap dataMap; - dataMap.insert(QLatin1String("username"), m_username); - dataMap.insert(QLatin1String("password"), passwdLineEdit->text()); + dataMap.insert(QStringLiteral("username"), m_username); + dataMap.insert(QStringLiteral("password"), passwdLineEdit->text()); m_wallet->writeMap(m_boardUrl.url(), dataMap); } diff --git a/src/danboorusearchwidget.cpp b/src/danboorusearchwidget.cpp index 124f66f..fbf384c 100644 --- a/src/danboorusearchwidget.cpp +++ b/src/danboorusearchwidget.cpp @@ -31,6 +31,12 @@ DanbooruSearchWidget::DanbooruSearchWidget(QWidget *parent): QWidget(parent) tagLineEdit->setPlaceholderText(i18n("Type search tags.")); tagLineEdit->setToolTip(i18n("Type search tags. An empty string searches all posts.")); + widthSpinBox->setSuffix(ki18np(" pixel", " pixels")); + heightSpinBox->setSuffix(ki18np(" pixel", " pixels")); + + widthSpinBox->setValue(0); + heightSpinBox->setValue(0); + connect(searchButton, &QPushButton::clicked, this, &DanbooruSearchWidget::accept); connect(tagLineEdit, &QLineEdit::returnPressed, this, &DanbooruSearchWidget::accept); @@ -49,11 +55,24 @@ QStringList DanbooruSearchWidget::selectedTags() const return m_tags; } +unsigned int DanbooruSearchWidget::selectedWidth() const +{ + return m_width; +} + +unsigned int DanbooruSearchWidget::selectedHeight() const +{ + return m_height; +} + + void DanbooruSearchWidget::accept() { - m_tags = tagLineEdit->text().split(","); + m_tags = tagLineEdit->text().split(QStringLiteral(",")); + m_width = widthSpinBox->value(); + m_height = heightSpinBox->value(); Q_EMIT(accepted()); } -} // namespace Danbooru \ No newline at end of file +} // namespace Danbooru diff --git a/src/danboorusearchwidget.h b/src/danboorusearchwidget.h index badf374..e83d0df 100644 --- a/src/danboorusearchwidget.h +++ b/src/danboorusearchwidget.h @@ -34,9 +34,13 @@ public: explicit DanbooruSearchWidget(QWidget *parent = 0); ~DanbooruSearchWidget(); QStringList selectedTags() const; + unsigned int selectedWidth() const; + unsigned int selectedHeight() const; private: QStringList m_tags; + unsigned int m_width; + unsigned int m_height; private Q_SLOTS: void accept(); @@ -49,4 +53,4 @@ Q_SIGNALS: } // namespace Danbooru -#endif \ No newline at end of file +#endif diff --git a/src/libdanbooru/danbooruservice.cpp b/src/libdanbooru/danbooruservice.cpp index db0c316..eb4bb7e 100644 --- a/src/libdanbooru/danbooruservice.cpp +++ b/src/libdanbooru/danbooruservice.cpp @@ -46,12 +46,12 @@ namespace Danbooru using KIO::StoredTransferJob; using KIO::MultiGetJob; -const QString DanbooruService::POST_URL = "post/index.json" ; -const QString DanbooruService::TAG_URL = "tag/index.xml"; -const QString DanbooruService::POOL_URL = "pool/index.json"; -const QString DanbooruService::ARTIST_URL = "artist/index.json"; -const QString DanbooruService::POOL_DATA_URL = "pool/show.xml"; -const QString DanbooruService::RELATED_TAG_URL = "tag/related.json"; +const QString DanbooruService::POST_URL = QStringLiteral("post/index.json"); +const QString DanbooruService::TAG_URL = QStringLiteral("tag/index.xml"); +const QString DanbooruService::POOL_URL = QStringLiteral("pool/index.json"); +const QString DanbooruService::ARTIST_URL = QStringLiteral("artist/index.json"); +const QString DanbooruService::POOL_DATA_URL = QStringLiteral("pool/show.xml"); +const QString DanbooruService::RELATED_TAG_URL = QStringLiteral("tag/related.json"); DanbooruService::DanbooruService(QUrl boardUrl, QString username, QString password, KImageCache *cache, @@ -81,8 +81,8 @@ void DanbooruService::getPostList() QMap parameters; - parameters.insert("limit", QString::number(m_maxPosts)); - parameters.insert("page", QString::number(m_currentPage)); + parameters.insert(QStringLiteral("limit"), QString::number(m_maxPosts)); + parameters.insert(QStringLiteral("page"), QString::number(m_currentPage)); QUrl danbooruUrl = requestUrl(m_url, POST_URL, m_username, m_password, parameters, m_tags); @@ -102,12 +102,12 @@ void DanbooruService::getPostList() void DanbooruService::getTagList(int limit, QString name) { QMap parameters; - parameters.insert("limit", QString::number(limit)); + parameters.insert(QStringLiteral("limit"), QString::number(limit)); if (!name.isEmpty()) { - parameters.insert("name", name); + parameters.insert(QStringLiteral("name"), name); } - parameters.insert("order", "date"); + parameters.insert(QStringLiteral("order"), QStringLiteral("date")); QUrl danbooruUrl = requestUrl(m_url, TAG_URL, m_username, m_password, parameters); @@ -124,10 +124,10 @@ void DanbooruService::getPool(int poolId, int page) QMap parameters; - parameters.insert("id", QString::number(poolId)); + parameters.insert(QStringLiteral("id"), QString::number(poolId)); if (page > 1) { - parameters.insert("page", QString::number(page)); + parameters.insert(QStringLiteral("page"), QString::number(page)); } QUrl danbooruUrl = requestUrl(m_url, POOL_DATA_URL, m_username, @@ -156,7 +156,7 @@ void DanbooruService::getPoolList() danbooruUrl = requestUrl(m_url, POOL_URL, m_username, m_password); } else { QMap map; - map.insert("page", QString::number(m_currentPage)); + map.insert(QStringLiteral("page"), QString::number(m_currentPage)); danbooruUrl = requestUrl(m_url, POOL_URL, m_username, m_password, map); @@ -185,13 +185,12 @@ void DanbooruService::getPoolList() QList poolList = parseDanbooruResult(data, &ok).toList(); if (!ok) { - Q_EMIT(downloadError(QString("Unable to decode data"))); + Q_EMIT(downloadError(QStringLiteral("Unable to decode data"))); return; } - for (auto element : poolList) { + Q_FOREACH(const auto & element, poolList) { QVariantMap map = element.toMap(); - DanbooruPool *pool = new DanbooruPool(map); Q_EMIT(poolDownloaded(pool)); } @@ -211,24 +210,24 @@ void DanbooruService::getRelatedTags(const QStringList &tags, QString type; switch (tagType) { case DanbooruTag::General: - type = "general"; + type = QStringLiteral("general"); break; case DanbooruTag::Artist: - type = "artist"; + type = QStringLiteral("artist"); break; case DanbooruTag::Copyright: - type = "copyright"; + type = QStringLiteral("copyright"); break; case DanbooruTag::Character: - type = "character"; + type = QStringLiteral("character"); break; case DanbooruTag::Unknown: - type = "unknown"; + type = QStringLiteral("unknown"); break; } QMap parameters; - parameters.insert("type", type); + parameters.insert(QStringLiteral("type"), type); QUrl danbooruUrl = requestUrl(m_url, RELATED_TAG_URL, m_username, m_password, parameters, tags); @@ -254,7 +253,7 @@ void DanbooruService::getRelatedTags(const QStringList &tags, QVariantMap tagList = parseDanbooruResult(data, &ok).toMap(); if (!ok) { - Q_EMIT(downloadError(QString("Unable to decode data"))); + Q_EMIT(downloadError(QStringLiteral("Unable to decode data"))); return; } @@ -273,7 +272,7 @@ void DanbooruService::getRelatedTags(const QStringList &tags, continue; } - for (auto tag : tags) { + Q_FOREACH(auto &tag, tags) { // We get the first element in the list, the second is // the ID which is useless (no API methods in Danbooru) QString tagName = tag.toList()[0].toString(); @@ -298,15 +297,15 @@ const QStringList DanbooruService::allowedRatings() const QStringList ratings; if (m_maxRating.testFlag(DanbooruPost::Safe)) { - ratings.append("Safe"); + ratings.append(QStringLiteral("Safe")); } if (m_maxRating.testFlag(DanbooruPost::Questionable)) { - ratings.append("Questionable"); + ratings.append(QStringLiteral("Questionable")); } if (m_maxRating.testFlag(DanbooruPost::Explicit)) { - ratings.append("Explicit"); + ratings.append(QStringLiteral("Explicit")); } return ratings; @@ -330,6 +329,16 @@ int DanbooruService::maxPosts() const return m_maxPosts; } +int DanbooruService::minimumWidth() const +{ + return m_minimumWidth > 0 ? m_minimumWidth: -1; +} + +int DanbooruService::minimumHeight() const +{ + return m_minimumHeight > 0 ? m_minimumHeight: -1; +} + void DanbooruService::nextPostPage() { m_currentPage++; @@ -371,14 +380,15 @@ void DanbooruService::processTagList(KJob *job) // Most Danbooru implementations return tags in wrong order when // using JSON, so we have to fall back to XML - QList tagList = parseDanbooruResult(data, "tag", &ok); + QList tagList = parseDanbooruResult(data, QStringLiteral("tag"), + &ok); if (!ok) { - Q_EMIT(downloadError(QString("Unable to decode data"))); + Q_EMIT(downloadError(QStringLiteral("Unable to decode data"))); return; } - for (auto element : tagList) { + Q_FOREACH(const auto& element, tagList) { QVariantMap map = element.toMap(); DanbooruTag *tag = new DanbooruTag(map); @@ -402,7 +412,7 @@ void DanbooruService::processPostList(KJob *job) StoredTransferJob *jobResult = qobject_cast(job); if (jobResult == 0) { - Q_EMIT(downloadError(QString("Internal error"))); + Q_EMIT(downloadError(QStringLiteral("Internal error"))); return; } @@ -416,13 +426,13 @@ void DanbooruService::processPostList(KJob *job) if (needsXML) { // Special cases for pools - postList = parseDanbooruResult(data, QString("post"), &ok); + postList = parseDanbooruResult(data, QStringLiteral("post"), &ok); } else { postList = parseDanbooruResult(data, &ok).toList(); } if (!ok) { - Q_EMIT(downloadError(QString("Unable to decode data"))); + Q_EMIT(downloadError(QStringLiteral("Unable to decode data"))); return; } @@ -436,7 +446,7 @@ void DanbooruService::processPostList(KJob *job) m_postsToFetch = postList.length(); - for (auto element : postList) { + Q_FOREACH(const auto& element, postList) { QVariantMap map = element.toMap(); DanbooruPost *post = new DanbooruPost(map); @@ -449,6 +459,18 @@ void DanbooruService::processPostList(KJob *job) continue; } + if (post->width() < minimumWidth()) { + m_postsToFetch--; + delete post; + continue; + } + + if (post->height() < minimumHeight()) { + m_postsToFetch--; + delete post; + continue; + } + QPixmap pix; // qCDebug(LIBDANBOORU) << "About to donwload images"; @@ -491,7 +513,7 @@ void DanbooruService::processPostList(KJob *job) if (!pix.loadFromData(jobResult->data())) { - Q_EMIT(downloadError(QString("Pixmap data could not be loaded"))); + Q_EMIT(downloadError(QStringLiteral("Pixmap data could not be loaded"))); return; } @@ -546,7 +568,7 @@ void DanbooruService::setBlacklist(const QStringList &blacklist) m_blacklist.clear(); - for (auto element : blacklist) { + for (const auto& element : blacklist) { m_blacklist.insert(element); } @@ -618,4 +640,16 @@ void DanbooruService::setCurrentPage(int page) m_currentPage = page; } +void Danbooru::DanbooruService::setResolution(unsigned int width, unsigned int height) +{ + if (width > 0) { + m_minimumWidth = width; + } + + if (height > 0) { + m_minimumHeight = height; + } +} + + } // namespace Danbooru diff --git a/src/libdanbooru/danbooruservice.h b/src/libdanbooru/danbooruservice.h index d9c7030..18c81e5 100644 --- a/src/libdanbooru/danbooruservice.h +++ b/src/libdanbooru/danbooruservice.h @@ -93,6 +93,8 @@ private: Danbooru::Ratings m_maxRating; int m_maxPosts; int m_currentPage; + unsigned int m_minimumHeight = 0; + unsigned int m_minimumWidth = 0; QStringList m_tags; unsigned int m_postsToFetch; // To tell when to quit @@ -162,7 +164,7 @@ public: * @param name The name of the tag to retrieve, or an empty string * **/ - void getTagList(int limit = 10, QString name = ""); + void getTagList(int limit = 10, QString name = QStringLiteral("")); /** * @brief Get tags related to a specific, user supplied list. @@ -207,6 +209,10 @@ public: **/ QStringList postTags() const; + int minimumWidth() const; + + int minimumHeight() const; + /** * @brief Resets the service to the default state, clearing the page counters. **/ @@ -282,6 +288,11 @@ public: void setPostTags(const QStringList &tags); + void setResolution(unsigned int width = 0, unsigned int height = 0); + + void setMinimumWidth(unsigned int width) { m_minimumWidth = width; }; + void setMinimumHeight(unsigned int height) { m_minimumHeight = height; }; + private Q_SLOTS: void processPostList(KJob *job); void processTagList(KJob *job); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 659ff02..9af1e2b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -119,16 +119,18 @@ DanbooruMainWindow::DanbooruMainWindow(QWidget *parent) KDeclarative::KDeclarative declarative; declarative.setDeclarativeEngine(m_view->engine()); declarative.setupBindings(); + m_view->setFocusPolicy(Qt::StrongFocus); + m_view->setFocus(); auto qmlViewPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, - qApp->applicationName() + QLatin1String("/danbooruimageview.qml")); + qApp->applicationName() + QStringLiteral("/danbooruimageview.qml")); QQmlContext *ctxt = m_view->rootContext(); - ctxt->setContextProperty("danbooruModel", m_model); - ctxt->setContextProperty("danbooruService", m_service); + ctxt->setContextProperty(QStringLiteral("danbooruModel"), m_model); + ctxt->setContextProperty(QStringLiteral("danbooruService"), m_service); m_view->setSource(QUrl::fromLocalFile(qmlViewPath)); m_view->rootObject()->setProperty("poolMode", QVariant(false)); - ctxt->setContextProperty("infiniteScroll", DanbooruSettings::self()->infiniteScrolling()); + ctxt->setContextProperty(QStringLiteral("infiniteScroll"), DanbooruSettings::self()->infiniteScrolling()); auto rootObj = m_view->rootObject(); connect(m_service, SIGNAL(postDownloadFinished()), rootObj, SIGNAL(downloadFinished())); @@ -140,7 +142,8 @@ DanbooruMainWindow::DanbooruMainWindow(QWidget *parent) // then, setup our actions setupActions(); - setupGUI(KXmlGuiWindow::ToolBar | Keys | Save | Create, "danbooru-clientui.rc"); + setupGUI(KXmlGuiWindow::ToolBar | Keys | Save | Create, + QStringLiteral("danbooru-clientui.rc")); // connections @@ -154,11 +157,11 @@ DanbooruMainWindow::DanbooruMainWindow(QWidget *parent) m_service->setPassword(m_connectWidget->password()); } - actionCollection()->action(QLatin1String("fetch"))->setEnabled(true); - actionCollection()->action(QLatin1String("find"))->setEnabled(true); - actionCollection()->action(QLatin1String("poolDownload"))->setEnabled(true); - actionCollection()->action(QLatin1String("tags"))->setEnabled(true); - actionCollection()->action(QLatin1String("morePosts"))->setEnabled(true); + actionCollection()->action(QStringLiteral("fetch"))->setEnabled(true); + actionCollection()->action(QStringLiteral("find"))->setEnabled(true); + actionCollection()->action(QStringLiteral("poolDownload"))->setEnabled(true); + actionCollection()->action(QStringLiteral("tags"))->setEnabled(true); + actionCollection()->action(QStringLiteral("morePosts"))->setEnabled(true); if (DanbooruSettings::self()->autoDownload()) { @@ -196,15 +199,19 @@ DanbooruMainWindow::DanbooruMainWindow(QWidget *parent) connect(m_searchWidget, &DanbooruSearchWidget::accepted, [this]() { - QDockWidget *searchDockWidget = findChild(QLatin1String("SearchView")); + QDockWidget *searchDockWidget = findChild(QStringLiteral("SearchView")); searchDockWidget->hide(); - handlePostDownload(m_searchWidget->selectedTags(), true /* relatedTags */); + handlePostDownload(m_searchWidget->selectedTags(), + true /* relatedTags */, + m_searchWidget->selectedWidth() /* minimumWidth */, + m_searchWidget->selectedHeight() /* minimumHeight */ + ); }); connect(m_searchWidget, &DanbooruSearchWidget::rejected, [this]() { - QDockWidget *searchDockWidget = findChild(QLatin1String("SearchView")); + QDockWidget *searchDockWidget = findChild(QStringLiteral("SearchView")); searchDockWidget->hide(); }); @@ -212,7 +219,7 @@ DanbooruMainWindow::DanbooruMainWindow(QWidget *parent) if (m_tagModel->rowCount() == 0) { // Only get tags if we don't have any already - for (auto tag : m_model->postTags()) { + Q_FOREACH(const auto& tag, m_model->postTags()) { m_service->getTagList(1, tag); } } @@ -243,10 +250,11 @@ void DanbooruMainWindow::loadSettings() QVector boardsList; QStringList::const_iterator it; + auto configList = DanbooruSettings::self()->boards(); - for (it = DanbooruSettings::self()->boards().constBegin(); - it != DanbooruSettings::self()->boards().constEnd(); - ++it) { + for (it = configList.constBegin(); + it != configList.constEnd(); + ++it) { boardsList.append(QUrl::fromUserInput(*it)); @@ -260,7 +268,7 @@ void DanbooruMainWindow::loadSettings() m_tagWidget->setBlackList(DanbooruSettings::self()->tagBlacklist()); - m_view->rootContext()->setContextProperty("infiniteScroll", + m_view->rootContext()->setContextProperty(QStringLiteral("infiniteScroll"), DanbooruSettings::self()->infiniteScrolling()); } @@ -269,23 +277,23 @@ void DanbooruMainWindow::setupActions() { QAction *connectAction = new QAction( - QIcon::fromTheme(QLatin1String("document-open-remote")), + QIcon::fromTheme(QStringLiteral("document-open-remote")), i18n("Connect..."), this); - QAction *fetchAction = new QAction(QIcon::fromTheme(QLatin1String("download")), + QAction *fetchAction = new QAction(QIcon::fromTheme(QStringLiteral("download")), i18n("Download"), this); - KToggleAction *findAction = new KToggleAction(QIcon::fromTheme(QLatin1String("edit-find")), + KToggleAction *findAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("edit-find")), i18n("Search"), this); - KToggleAction *poolAction = new KToggleAction(QIcon::fromTheme(QLatin1String("image-x-generic")), + KToggleAction *poolAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("image-x-generic")), i18n("Pools"), this); - QAction *nextPageAction = new QAction(QIcon::fromTheme(QLatin1String("go-next")), + QAction *nextPageAction = new QAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("More posts"), this); - QAction *nextPoolAction = new QAction(QIcon::fromTheme(QLatin1String("go-next")), + QAction *nextPoolAction = new QAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("More pools"), this); KDualAction *tagAction = new KDualAction(i18n("Show tags"), i18n("Hide tags"), this); - tagAction->setIconForStates(QIcon::fromTheme(QLatin1String("tag"))); + tagAction->setIconForStates(QIcon::fromTheme(QStringLiteral("tag"))); fetchAction->setEnabled(false); findAction->setEnabled(false); @@ -297,13 +305,13 @@ void DanbooruMainWindow::setupActions() findAction->setChecked(false); tagAction->setEnabled(false); - actionCollection()->addAction(QLatin1String("connect"), connectAction); - actionCollection()->addAction(QLatin1String("fetch"), fetchAction); - actionCollection()->addAction(QLatin1String("find"), findAction); - actionCollection()->addAction(QLatin1String("poolDownload"), poolAction); - actionCollection()->addAction(QLatin1String("tags"), tagAction); - actionCollection()->addAction(QLatin1String("morePosts"), nextPageAction); - actionCollection()->addAction(QLatin1String("morePools"), nextPoolAction); + actionCollection()->addAction(QStringLiteral("connect"), connectAction); + actionCollection()->addAction(QStringLiteral("fetch"), fetchAction); + actionCollection()->addAction(QStringLiteral("find"), findAction); + actionCollection()->addAction(QStringLiteral("poolDownload"), poolAction); + actionCollection()->addAction(QStringLiteral("tags"), tagAction); + actionCollection()->addAction(QStringLiteral("morePosts"), nextPageAction); + actionCollection()->addAction(QStringLiteral("morePools"), nextPoolAction); actionCollection()->setDefaultShortcut(connectAction, KStandardShortcut::Open); actionCollection()->setDefaultShortcut(findAction, KStandardShortcut::Find); @@ -319,7 +327,7 @@ void DanbooruMainWindow::setupActions() return; } - QDockWidget *poolDockWidget = findChild(QLatin1String("PoolView")); + QDockWidget *poolDockWidget = findChild(QStringLiteral("PoolView")); if (checked) { @@ -329,19 +337,19 @@ void DanbooruMainWindow::setupActions() } poolDockWidget->show(); - actionCollection()->action(QLatin1String("morePools"))->setEnabled(true); + actionCollection()->action(QStringLiteral("morePools"))->setEnabled(true); m_tableView->show(); } else { poolDockWidget->hide(); - actionCollection()->action(QLatin1String("morePools"))->setEnabled(false); + actionCollection()->action(QStringLiteral("morePools"))->setEnabled(false); m_tableView->hide(); } }); connect(findAction, &KToggleAction::toggled, [this](bool checked) { - QDockWidget *searchDockWidget = findChild(QLatin1String("SearchView")); + QDockWidget *searchDockWidget = findChild(QStringLiteral("SearchView")); if (checked) { searchDockWidget->show(); @@ -355,7 +363,7 @@ void DanbooruMainWindow::setupActions() connect(tagAction, &KDualAction::activeChanged, [this](bool checked) { - QDockWidget *tagDockWidget = findChild(QLatin1String("TagView")); + QDockWidget *tagDockWidget = findChild(QStringLiteral("TagView")); if (checked) { tagDockWidget->show(); @@ -392,7 +400,7 @@ void DanbooruMainWindow::setupDockWidgets() QDockWidget *poolDockWidget = new QDockWidget(i18n("Pools"), this); poolDockWidget->setAllowedAreas(Qt::BottomDockWidgetArea); poolDockWidget->setWidget(m_tableView); - poolDockWidget->setObjectName("PoolView"); + poolDockWidget->setObjectName(QStringLiteral("PoolView")); // Prevent the use of winId() when detached, leads to QQuickWidget bugs poolDockWidget->setFeatures(QDockWidget::DockWidgetClosable); @@ -404,7 +412,7 @@ void DanbooruMainWindow::setupDockWidgets() QDockWidget *searchDockWidget = new QDockWidget(QLatin1String(""), this); searchDockWidget->setAllowedAreas(Qt::TopDockWidgetArea); searchDockWidget->setWidget(m_searchWidget); - searchDockWidget->setObjectName("SearchView"); + searchDockWidget->setObjectName(QStringLiteral("SearchView")); searchDockWidget->setFeatures(QDockWidget::NoDockWidgetFeatures); addDockWidget(Qt::TopDockWidgetArea, searchDockWidget); @@ -414,10 +422,10 @@ void DanbooruMainWindow::setupDockWidgets() searchDockWidget->hide(); m_searchWidget->hide(); - QDockWidget *tagDockWidget = new QDockWidget(QLatin1String("Tags"), this); + QDockWidget *tagDockWidget = new QDockWidget(QStringLiteral("Tags"), this); tagDockWidget->setAllowedAreas(Qt::RightDockWidgetArea); tagDockWidget->setWidget(m_tagWidget); - tagDockWidget->setObjectName("TagView"); + tagDockWidget->setObjectName(QStringLiteral("TagView")); tagDockWidget->setFeatures(QDockWidget::DockWidgetClosable); addDockWidget(Qt::RightDockWidgetArea, tagDockWidget); @@ -427,15 +435,15 @@ void DanbooruMainWindow::setupDockWidgets() // Connections connect(poolDockWidget, &QDockWidget::visibilityChanged, [this](bool visible) { - actionCollection()->action(QLatin1String("poolDownload"))->setChecked(visible); + actionCollection()->action(QStringLiteral("poolDownload"))->setChecked(visible); }); connect(searchDockWidget, &QDockWidget::visibilityChanged, [this](bool visible) { - actionCollection()->action(QLatin1String("find"))->setChecked(visible); + actionCollection()->action(QStringLiteral("find"))->setChecked(visible); }); connect(tagDockWidget, &QDockWidget::visibilityChanged, [this](bool visible) { - qobject_cast(actionCollection()->action(QLatin1String("tags")))->setActive(visible); + qobject_cast(actionCollection()->action(QStringLiteral("tags")))->setActive(visible); }); } @@ -467,13 +475,13 @@ void DanbooruMainWindow::downloadPosts() void DanbooruMainWindow::optionsPreferences() { - KConfigDialog *dialog = new KConfigDialog(this, "danboorusettings", + KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("danboorusettings"), DanbooruSettings::self()); dialog->addPage(new GeneralPage(DanbooruSettings::self(), this), i18n("General"), - "table"); + QStringLiteral("table")); dialog->addPage(new BlacklistPage(DanbooruSettings::self(), this), i18n("Tag blacklist"), - "configure"); + QStringLiteral("configure")); connect(dialog, &KConfigDialog::settingsChanged, this, &DanbooruMainWindow::loadSettings); dialog->show(); } @@ -506,13 +514,15 @@ void DanbooruMainWindow::slotHandleDownload(const QUrl &url, const QVariant tags saveDialog->setMimeTypeFilters(filters); } else { filters.reserve(2); - filters << "Images (*.png *.gif *.jpg)" << "All files (*.*)"; + filters << QStringLiteral("Images (*.png *.gif *.jpg)") + << QStringLiteral("All files (*.*)"); saveDialog->setNameFilters(filters); } // Prevent invalid characters (":" can be a tag in Danbooru) - if (remoteFile.contains(":")) { - remoteFile.replace(":", "_"); + if (remoteFile.contains(QStringLiteral(":"))) { + remoteFile.replace(QStringLiteral(":"), + QStringLiteral("_")); } saveDialog->selectFile(remoteFile); @@ -578,12 +588,21 @@ void DanbooruMainWindow::clearModels() } -void DanbooruMainWindow::handlePostDownload(const QStringList &tags, bool relatedTags) +void DanbooruMainWindow::handlePostDownload(const QStringList &tags, bool relatedTags, + unsigned int minimumWidth, unsigned int minimumHeight) { clearModels(); m_view->rootObject()->setProperty("poolMode", QVariant(false)); m_service->setPostTags(tags); + if (minimumWidth > 0) { + m_service->setMinimumWidth(minimumWidth); + } + + if (minimumHeight > 0) { + m_service->setMinimumHeight(minimumHeight); + } + if (relatedTags) { m_service->getRelatedTags(tags); } diff --git a/src/mainwindow.h b/src/mainwindow.h index 90007f5..73f0bd6 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -90,7 +90,8 @@ private: void setupDockWidgets(); void setupConnections(); void clearModels(); - void handlePostDownload(const QStringList &tags = QStringList(), bool relatedTags = false); + void handlePostDownload(const QStringList &tags = QStringList(), bool relatedTags = false, + unsigned int minimumWidth = 0, unsigned int minimumHeight = 0); private Q_SLOTS: void connectToBoard(); diff --git a/src/qml/danbooruimageview.qml b/src/qml/danbooruimageview.qml index 527630f..77c0e5e 100644 --- a/src/qml/danbooruimageview.qml +++ b/src/qml/danbooruimageview.qml @@ -42,12 +42,16 @@ Rectangle { signal downloadRequested(url url, var tags) signal downloadStarted() signal fileInfo(url name, var tags) - + signal shareButtonClicked(url url) KRun { id: runner } + Clipboard { + id: clipboard + } + onDownloadFinished: { grid.opacity = 1 @@ -64,6 +68,10 @@ Rectangle { runningIndicator.running = true } + onShareButtonClicked: { + clipboard.content = url; + } + BusyIndicator { id: runningIndicator z: 1 @@ -121,8 +129,6 @@ Rectangle { height: parent.height width: parent.width -// - hoverEnabled: true onClicked: { @@ -137,11 +143,13 @@ Rectangle { onEntered: { viewButton.opacity = 1 downloadButton.opacity = 1 + shareButton.opacity = 1 } onExited: { viewButton.opacity = 0 downloadButton.opacity = 0 + shareButton.opacity = 0 } Button { @@ -198,19 +206,51 @@ Rectangle { } } } + + Button { + id: shareButton + iconName: "edit-copy" + tooltip: i18n("Copy link to clipboard") + visible: opacity > 0 + opacity: 0 + anchors.top: parent.top + anchors.right: parent.right + anchors.topMargin: (pixItem.height - pixItem.paintedHeight) / 2 + anchors.rightMargin: (pixItem.width - pixItem.paintedWidth) / 2 + + height: pixItem.height * 0.15 + width: pixItem.height * 0.15 + z: 1 + + onClicked: { + rootObj.shareButtonClicked(fileUrl) + } + + Behavior on opacity { + NumberAnimation { + duration: 200 + } + + } + + } + } } Text { id: sizeText + anchors.left: pixItem.left text: i18n("File size: %1", KCoreAddons.Format.formatByteSize(fileSize)) } Text { id: resolutionText + anchors.left: pixItem.left text: i18n("Resolution: %1 x %2", resolution.width, resolution.height) } Text { id: ratingText + anchors.left: pixItem.left text: { if (rating == DanbooruPost.Safe) { @@ -246,6 +286,7 @@ Rectangle { model: danbooruModel delegate: viewDelegate + interactive: true focus: true Component.onCompleted: { currentIndex = -1; forceActiveFocus()} diff --git a/src/ui/searchwidget.ui b/src/ui/searchwidget.ui index 9dcb5c9..38a9577 100644 --- a/src/ui/searchwidget.ui +++ b/src/ui/searchwidget.ui @@ -6,12 +6,12 @@ 0 0 - 387 - 45 + 371 + 160 - + 0 0 @@ -19,21 +19,76 @@ - - + + + + + Qt::Horizontal + + + + 37 + 29 + + + + + + + + Minimum height: + + + + + + + Minimum width: + + + + - + + .. true - + + + + Qt::Horizontal + + + + 37 + 29 + + + + + + + + 16834 + + + + + + + 16834 + + + + @@ -46,7 +101,20 @@ - + + + + + 0 + 0 + + + + Search + + + + @@ -62,16 +130,14 @@ - - - - Search - - - + + KPluralHandlingSpinBox + QSpinBox +
kpluralhandlingspinbox.h
+
KLineEdit QLineEdit