From 04f56b5fc29e082139ee77991f4780372edba34a Mon Sep 17 00:00:00 2001 From: Yusuf Keten Date: Thu, 23 Jul 2020 21:17:01 +0300 Subject: [PATCH] tdf#133026: Additions: Add Show More button and refactor After this patch, not all extensions that come with JSON will be shown. Instead, a certain number (currently 30) of extensions will be shown and the Show More button will appear after the last extension. If the user presses the button, a certain number of extensions will be added again. Change-Id: Icf8f549d585a5bca1d55b85acf9b72478b507444 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99338 Tested-by: Jenkins Reviewed-by: Muhammet Kara --- cui/source/dialogs/AdditionsDialog.cxx | 228 ++++++------ cui/source/inc/AdditionsDialog.hxx | 49 ++- cui/uiconfig/ui/additionsfragment.ui | 486 +++++++++++++------------ 3 files changed, 422 insertions(+), 341 deletions(-) diff --git a/cui/source/dialogs/AdditionsDialog.cxx b/cui/source/dialogs/AdditionsDialog.cxx index 37e90c4ecb66..555f0c74a64e 100644 --- a/cui/source/dialogs/AdditionsDialog.cxx +++ b/cui/source/dialogs/AdditionsDialog.cxx @@ -48,6 +48,8 @@ #include #include +#define PAGE_SIZE 30 + using namespace css; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::XComponentContext; @@ -71,25 +73,6 @@ const char kUserAgent[] = "LibreOffice AdditionsDownloader/1.0 (unknown platform namespace { -struct AdditionInfo -{ - OUString sExtensionID; - OUString sName; - OUString sAuthorName; - OUString sExtensionURL; - OUString sScreenshotURL; - OUString sIntroduction; - OUString sDescription; - OUString sCompatibleVersion; - OUString sReleaseVersion; - OUString sLicense; - OUString sCommentNumber; - OUString sCommentURL; - OUString sRating; - OUString sDownloadNumber; - OUString sDownloadURL; -}; - size_t WriteCallback(void* ptr, size_t size, size_t nmemb, void* userp) { if (!userp) @@ -293,13 +276,32 @@ bool getPreviewFile(const AdditionInfo& aAdditionInfo, OUString& sPreviewFile) return true; } +void LoadImage(const OUString& rPreviewFile, const AdditionsItem& rCurrentItem) +{ + SolarMutexGuard aGuard; + + GraphicFilter aFilter; + Graphic aGraphic; + + INetURLObject aURLObj(rPreviewFile); + + // for VCL to be able to create bitmaps / do visual changes in the thread + aFilter.ImportGraphic(aGraphic, aURLObj); + BitmapEx aBmp = aGraphic.GetBitmapEx(); + + ScopedVclPtr xVirDev = rCurrentItem.m_xImageScreenshot->create_virtual_device(); + xVirDev->SetOutputSizePixel(aBmp.GetSizePixel()); + xVirDev->DrawBitmapEx(Point(0, 0), aBmp); + + rCurrentItem.m_xImageScreenshot->set_image(xVirDev.get()); + xVirDev.disposeAndClear(); +} + } // End of the anonymous namespace -SearchAndParseThread::SearchAndParseThread(AdditionsDialog* pDialog, const OUString& rURL, - const bool& isFirstLoading) +SearchAndParseThread::SearchAndParseThread(AdditionsDialog* pDialog, const bool& isFirstLoading) : Thread("cuiAdditionsSearchThread") , m_pAdditionsDialog(pDialog) - , m_aURL(rURL) , m_bExecute(true) , m_bIsFirstLoading(isFirstLoading) { @@ -307,6 +309,78 @@ SearchAndParseThread::SearchAndParseThread(AdditionsDialog* pDialog, const OUStr SearchAndParseThread::~SearchAndParseThread() {} +std::vector SearchAndParseThread::CreateInfoVectorToLoading(const size_t startNumber) +{ + std::vector additionInfos; + for (size_t i = startNumber; i < m_pAdditionsDialog->m_nMaxItemCount; i++) + { + if (i == m_pAdditionsDialog->m_aAllExtensionsVector.size()) + break; + additionInfos.push_back(m_pAdditionsDialog->m_aAllExtensionsVector[i]); + } + + return additionInfos; +} + +void SearchAndParseThread::LoadInfo(const AdditionInfo& additionInfo, AdditionsItem& rCurrentItem, + const size_t nGridPositionY) +{ + SolarMutexGuard aGuard; + + rCurrentItem.m_xContainer->set_grid_left_attach(0); + rCurrentItem.m_xContainer->set_grid_top_attach(nGridPositionY); + + rCurrentItem.m_xLinkButtonName->set_label(additionInfo.sName); + rCurrentItem.m_xLinkButtonName->set_uri(additionInfo.sExtensionURL); + rCurrentItem.m_xLabelDescription->set_label(additionInfo.sIntroduction); + rCurrentItem.m_xLabelAuthor->set_label(additionInfo.sAuthorName); + rCurrentItem.m_xButtonInstall->set_label(CuiResId(RID_SVXSTR_ADDITIONS_INSTALLBUTTON)); + OUString sLicenseString = CuiResId(RID_SVXSTR_ADDITIONS_LICENCE) + additionInfo.sLicense; + rCurrentItem.m_xLabelLicense->set_label(sLicenseString); + OUString sVersionString + = CuiResId(RID_SVXSTR_ADDITIONS_REQUIREDVERSION) + additionInfo.sCompatibleVersion; + rCurrentItem.m_xLabelVersion->set_label(sVersionString); + rCurrentItem.m_xLinkButtonComments->set_label(additionInfo.sCommentNumber); + rCurrentItem.m_xLinkButtonComments->set_uri(additionInfo.sCommentURL); + rCurrentItem.m_xLabelDownloadNumber->set_label(additionInfo.sDownloadNumber); + rCurrentItem.m_pParentDialog = m_pAdditionsDialog; +} + +void SearchAndParseThread::UpdateUI(const std::vector& aAdditionInfos) +{ + //Get Preview Files + for (auto& additionInfo : aAdditionInfos) + { + if (!m_bExecute) + return; + OUString aPreviewFile; + bool bResult = getPreviewFile(additionInfo, aPreviewFile); // info vector json data + + if (!bResult) + { + SAL_INFO("cui.dialogs", "Couldn't get the preview file. Skipping: " << aPreviewFile); + continue; + } + + SolarMutexGuard aGuard; + AdditionsDialog* rDialog = m_pAdditionsDialog; + + rDialog->m_aAdditionsItems.emplace_back(rDialog->m_xContentGrid.get()); + AdditionsItem& aCurrentItem = rDialog->m_aAdditionsItems.back(); + + LoadInfo(additionInfo, aCurrentItem, rDialog->m_nCurrentListItemCount); + LoadImage(aPreviewFile, aCurrentItem); + + rDialog->m_nCurrentListItemCount++; + if (rDialog->m_nCurrentListItemCount == rDialog->m_nMaxItemCount) + { + if (rDialog->m_nCurrentListItemCount != rDialog->m_aAllExtensionsVector.size()) + aCurrentItem.m_xButtonShowMore->set_visible(true); + break; + } + } +} + void SearchAndParseThread::execute() { //m_pAdditionsDialog->ClearSearchResults(); @@ -316,18 +390,19 @@ void SearchAndParseThread::execute() else sProgress = CuiResId(RID_SVXSTR_ADDITIONS_SEARCHING); - m_pAdditionsDialog->SetProgress(sProgress); + m_pAdditionsDialog->SetProgress( + sProgress); // Loading or searching according to being first call or not - uno::Reference xFileAccess - = ucb::SimpleFileAccess::create(comphelper::getProcessComponentContext()); - OString rURL = OUStringToOString(m_aURL, RTL_TEXTENCODING_UTF8); - std::string sResponse = curlGet(rURL); + if (m_bIsFirstLoading) + { + std::string sResponse = curlGet(m_pAdditionsDialog->m_sURL); + parseResponse(sResponse, m_pAdditionsDialog->m_aAllExtensionsVector); + } - std::vector additionInfos; + std::vector currentVector + = CreateInfoVectorToLoading(m_pAdditionsDialog->m_nCurrentListItemCount); - parseResponse(sResponse, additionInfos); - - if (additionInfos.empty()) + if (currentVector.empty()) { sProgress = CuiResId(RID_SVXSTR_ADDITIONS_NORESULTS); m_pAdditionsDialog->SetProgress(sProgress); @@ -335,75 +410,7 @@ void SearchAndParseThread::execute() } else { - //Get Preview Files - sal_Int32 i = 0; - for (const auto& additionInfo : additionInfos) - { - if (!m_bExecute) - return; - - OUString aPreviewFile; - bool bResult = getPreviewFile(additionInfo, aPreviewFile); - - if (!bResult) - { - SAL_INFO("cui.dialogs", - "Couldn't get the preview file. Skipping: " << aPreviewFile); - continue; - } - - SolarMutexGuard aGuard; - m_pAdditionsDialog->m_aAdditionsItems.emplace_back( - m_pAdditionsDialog->m_xContentGrid.get()); - AdditionsItem& aCurrentItem = m_pAdditionsDialog->m_aAdditionsItems.back(); - - sal_Int32 nGridPositionY = i++; - aCurrentItem.m_xContainer->set_grid_left_attach(0); - aCurrentItem.m_xContainer->set_grid_top_attach(nGridPositionY); - - aCurrentItem.m_xLinkButtonName->set_label(additionInfo.sName); - aCurrentItem.m_xLinkButtonName->set_uri(additionInfo.sExtensionURL); - aCurrentItem.m_xLabelDescription->set_label(additionInfo.sIntroduction); - aCurrentItem.m_xLabelAuthor->set_label(additionInfo.sAuthorName); - aCurrentItem.m_xButtonInstall->set_label(CuiResId(RID_SVXSTR_ADDITIONS_INSTALLBUTTON)); - OUString sLicenseString - = CuiResId(RID_SVXSTR_ADDITIONS_LICENCE) + additionInfo.sLicense; - aCurrentItem.m_xLabelLicense->set_label(sLicenseString); - OUString sVersionString - = CuiResId(RID_SVXSTR_ADDITIONS_REQUIREDVERSION) + additionInfo.sCompatibleVersion; - aCurrentItem.m_xLabelVersion->set_label(sVersionString); - aCurrentItem.m_xLinkButtonComments->set_label(additionInfo.sCommentNumber); - aCurrentItem.m_xLinkButtonComments->set_uri(additionInfo.sCommentURL); - aCurrentItem.m_xLabelDownloadNumber->set_label(additionInfo.sDownloadNumber); - - GraphicFilter aFilter; - Graphic aGraphic; - - INetURLObject aURLObj(aPreviewFile); - - // This block may be added according to need - /*OUString aAdditionsSetting = additionInfo.sSlug - + ";" + additionInfo.sName - + ";" + additionInfo.sPreviewURL - + ";" + additionInfo.sHeaderURL - + ";" + additionInfo.sFooterURL - + ";" + additionInfo.sTextColor; - - m_pAdditionsDialog->AddPersonaSetting( aPersonaSetting ); - */ - - // for VCL to be able to create bitmaps / do visual changes in the thread - aFilter.ImportGraphic(aGraphic, aURLObj); - BitmapEx aBmp = aGraphic.GetBitmapEx(); - - ScopedVclPtr xVirDev - = aCurrentItem.m_xImageScreenshot->create_virtual_device(); - xVirDev->SetOutputSizePixel(aBmp.GetSizePixel()); - xVirDev->DrawBitmapEx(Point(0, 0), aBmp); - - aCurrentItem.m_xImageScreenshot->set_image(xVirDev.get()); - xVirDev.disposeAndClear(); - } + UpdateUI(currentVector); } if (!m_bExecute) @@ -430,10 +437,11 @@ AdditionsDialog::AdditionsDialog(weld::Window* pParent, const OUString& sAdditio m_xEntrySearch->connect_changed(LINK(this, AdditionsDialog, SearchUpdateHdl)); m_xEntrySearch->connect_focus_out(LINK(this, AdditionsDialog, FocusOut_Impl)); - m_xButtonClose->connect_clicked(LINK(this, AdditionsDialog, CloseButtonHdl)); m_sTag = OUStringToOString(sAdditionsTag, RTL_TEXTENCODING_UTF8); + m_nMaxItemCount = PAGE_SIZE; // Dialog initialization item count + m_nCurrentListItemCount = 0; // First, there is no item on the list. OUString titlePrefix = CuiResId(RID_SVXSTR_ADDITIONS_DIALOG_TITLE_PREFIX); if (!m_sTag.isEmpty()) @@ -449,11 +457,10 @@ AdditionsDialog::AdditionsDialog(weld::Window* pParent, const OUString& sAdditio OString sPrefixURL = "https://yusufketen.com/api/"; OString sSuffixURL = ".json"; OString rURL = sPrefixURL + m_sTag + sSuffixURL; + m_sURL = rURL; - m_pSearchThread - = new SearchAndParseThread(this, OStringToOUString(rURL, RTL_TEXTENCODING_UTF8), true); + m_pSearchThread = new SearchAndParseThread(this, true); m_pSearchThread->launch(); - // fillGrid(); } AdditionsDialog::~AdditionsDialog() @@ -515,8 +522,7 @@ IMPL_LINK_NOARG(AdditionsDialog, ImplUpdateDataHdl, Timer*, void) } this->SetProgress(finalURL); - m_pSearchThread - = new SearchAndParseThread(this, OStringToOUString(rURL, RTL_TEXTENCODING_UTF8), false); + m_pSearchThread = new SearchAndParseThread(this, false); m_pSearchThread->launch(); } @@ -541,4 +547,14 @@ IMPL_LINK_NOARG(AdditionsDialog, CloseButtonHdl, weld::Button&, void) this->response(RET_CLOSE); } +IMPL_LINK_NOARG(AdditionsItem, ShowMoreHdl, weld::Button&, void) +{ + this->m_xButtonShowMore->set_visible(false); + m_pParentDialog->m_nMaxItemCount += PAGE_SIZE; + if (m_pParentDialog->m_pSearchThread.is()) + m_pParentDialog->m_pSearchThread->StopExecution(); + m_pParentDialog->m_pSearchThread = new SearchAndParseThread(m_pParentDialog, false); + m_pParentDialog->m_pSearchThread->launch(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cui/source/inc/AdditionsDialog.hxx b/cui/source/inc/AdditionsDialog.hxx index 7f327b2a8c28..3b285d05629a 100644 --- a/cui/source/inc/AdditionsDialog.hxx +++ b/cui/source/inc/AdditionsDialog.hxx @@ -16,6 +16,9 @@ #include #include +class AdditionsDialog; +class SearchAndParseThread; + struct AdditionsItem { AdditionsItem(weld::Widget* pParent) @@ -34,9 +37,13 @@ struct AdditionsItem , m_xImageVoting(m_xBuilder->weld_image("imageVoting")) , m_xImageDownloadNumber(m_xBuilder->weld_image("imageDownloadNumber")) , m_xLabelDownloadNumber(m_xBuilder->weld_label("labelDownloadNumber")) + , m_xButtonShowMore(m_xBuilder->weld_button("buttonShowMore")) { + m_xButtonShowMore->connect_clicked(LINK(this, AdditionsItem, ShowMoreHdl)); } + DECL_LINK(ShowMoreHdl, weld::Button&, void); + std::unique_ptr m_xBuilder; std::unique_ptr m_xContainer; std::unique_ptr m_xImageScreenshot; @@ -52,8 +59,28 @@ struct AdditionsItem std::unique_ptr m_xImageVoting; std::unique_ptr m_xImageDownloadNumber; std::unique_ptr m_xLabelDownloadNumber; + std::unique_ptr m_xButtonShowMore; + AdditionsDialog* m_pParentDialog; +}; + +struct AdditionInfo +{ + OUString sExtensionID; + OUString sName; + OUString sAuthorName; + OUString sExtensionURL; + OUString sScreenshotURL; + OUString sIntroduction; + OUString sDescription; + OUString sCompatibleVersion; + OUString sReleaseVersion; + OUString sLicense; + OUString sCommentNumber; + OUString sCommentURL; + OUString sRating; + OUString sDownloadNumber; + OUString sDownloadURL; }; -class SearchAndParseThread; class AdditionsDialog : public weld::GenericDialogController { @@ -68,9 +95,9 @@ private: public: std::unique_ptr m_xEntrySearch; std::unique_ptr m_xButtonClose; - std::unique_ptr m_xMenuButtonSettings; - std::vector m_aAdditionsItems; + std::vector m_aAdditionsItems; // UI components + std::vector m_aAllExtensionsVector; // std::unique_ptr m_xContentWindow; std::unique_ptr m_xContentGrid; @@ -78,7 +105,12 @@ public: std::unique_ptr m_xLabelProgress; ::rtl::Reference m_pSearchThread; + OString m_sURL; OString m_sTag; + size_t + m_nMaxItemCount; // Max number of item which will appear on the list before the press to the show more button. + size_t m_nCurrentListItemCount; // Current number of item on the list + AdditionsDialog(weld::Window* pParent, const OUString& sAdditionsTag); ~AdditionsDialog() override; @@ -90,7 +122,6 @@ class SearchAndParseThread : public salhelper::Thread { private: AdditionsDialog* m_pAdditionsDialog; - OUString m_aURL; std::atomic m_bExecute; bool m_bIsFirstLoading; @@ -98,8 +129,14 @@ private: virtual void execute() override; public: - SearchAndParseThread(AdditionsDialog* pDialog, const OUString& rURL, - const bool& bIsFirstLoading); + SearchAndParseThread(AdditionsDialog* pDialog, const bool& bIsFirstLoading); + + std::vector CreateInfoVectorToLoading(const size_t startNumber); + + void LoadInfo(const AdditionInfo& additionInfo, AdditionsItem& rCurrentItem, + const size_t nGridPositionY); + + void UpdateUI(const std::vector& additionInfos); void StopExecution() { m_bExecute = false; } }; diff --git a/cui/uiconfig/ui/additionsfragment.ui b/cui/uiconfig/ui/additionsfragment.ui index 7ebf69f2a9fa..9b475e2fada4 100644 --- a/cui/uiconfig/ui/additionsfragment.ui +++ b/cui/uiconfig/ui/additionsfragment.ui @@ -8,52 +8,270 @@ start - 310 - 200 True False - start - start - 5 - False - False - vertical - - 60 - 60 + + 310 + 200 True False start start - 3 False False - gtk-missing-image - - - + vertical + + + 60 + 60 + True + False + start + start + 3 + False + False + gtk-missing-image + + + + + + False + False + 0 + + + + + button + 310 + True + True + True + center + center + 5 + True + + + True + True + 1 + + False - False + True 0 - - button - 310 + True - True - True - center - center - 5 - True + False + start + vertical + top + + + button + True + True + True + start + none + http://glade.gnome.org + + + False + True + 0 + + + + + 20 + True + False + start + label + + + False + True + 1 + + + + + True + False + start + 3 + Description: + + + False + True + 2 + + + + + True + False + start + start + label + True + word-char + 1 + 50 + + + + + + + False + False + 3 + + + + + True + False + start + 3 + label + + + False + True + 4 + + + + + True + False + start + 3 + label + + + False + True + 5 + + + + + True + False + start + + + True + False + Comments: + + + False + True + 0 + + + + + button + True + True + True + none + http://glade.gnome.org + + + False + True + 1 + + + + + False + True + 6 + + + + + True + False + start + gtk-about + + + + + + False + True + 7 + + + + + True + False + start + 3 + + + True + False + start + gtk-directory + + + + + + False + True + 0 + + + + + True + False + start + label + + + + + + False + True + 1 + + + + + False + True + 8 + + - True + False True 1 @@ -65,212 +283,22 @@ - - True - False - start - 5 - vertical - top - - - button - True - True - True - start - none - http://glade.gnome.org + + Show More Extensions + True + True + 7 + 7 + + + ButtonShowMore + This button shows more extensions. - - False - True - 0 - - - - - 20 - True - False - start - label - - - False - True - 1 - - - - - True - False - start - 3 - Description: - - - False - True - 2 - - - - - True - False - start - start - label - True - word-char - 1 - 50 - - - - - - - False - False - 3 - - - - - True - False - start - 3 - label - - - False - True - 4 - - - - - True - False - start - 3 - label - - - False - True - 5 - - - - - True - False - start - - - True - False - Comments: - - - False - True - 0 - - - - - button - True - True - True - none - http://glade.gnome.org - - - False - True - 1 - - - - - False - True - 6 - - - - - True - False - start - gtk-about - - - - - - False - True - 7 - - - - - True - False - start - 3 - - - True - False - start - gtk-directory - - - - - - False - True - 0 - - - - - True - False - start - 5 - label - - - - - - False - True - 1 - - - - - False - True - 8 - - 1 - 0 + 0 + 1