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 <muhammet.kara@collabora.com>
This commit is contained in:
Yusuf Keten
2020-07-23 23:54:26 +02:00
committed by Muhammet Kara
parent 92f4a031cc
commit 04f56b5fc2
3 changed files with 422 additions and 341 deletions
+122 -106
View File
@@ -48,6 +48,8 @@
#include <orcus/config.hpp>
#include <orcus/pstring.hpp>
#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<VirtualDevice> 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<AdditionInfo> SearchAndParseThread::CreateInfoVectorToLoading(const size_t startNumber)
{
std::vector<AdditionInfo> 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<AdditionInfo>& 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<ucb::XSimpleFileAccess3> 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<AdditionInfo> additionInfos;
std::vector<AdditionInfo> 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<VirtualDevice> 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: */
+43 -6
View File
@@ -16,6 +16,9 @@
#include <vcl/timer.hxx>
#include <vcl/weld.hxx>
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<weld::Builder> m_xBuilder;
std::unique_ptr<weld::Widget> m_xContainer;
std::unique_ptr<weld::Image> m_xImageScreenshot;
@@ -52,8 +59,28 @@ struct AdditionsItem
std::unique_ptr<weld::Image> m_xImageVoting;
std::unique_ptr<weld::Image> m_xImageDownloadNumber;
std::unique_ptr<weld::Label> m_xLabelDownloadNumber;
std::unique_ptr<weld::Button> 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<weld::Entry> m_xEntrySearch;
std::unique_ptr<weld::Button> m_xButtonClose;
std::unique_ptr<weld::MenuButton> m_xMenuButtonSettings;
std::vector<AdditionsItem> m_aAdditionsItems;
std::vector<AdditionsItem> m_aAdditionsItems; // UI components
std::vector<AdditionInfo> m_aAllExtensionsVector; //
std::unique_ptr<weld::ScrolledWindow> m_xContentWindow;
std::unique_ptr<weld::Container> m_xContentGrid;
@@ -78,7 +105,12 @@ public:
std::unique_ptr<weld::Label> m_xLabelProgress;
::rtl::Reference<SearchAndParseThread> 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<bool> 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<AdditionInfo> CreateInfoVectorToLoading(const size_t startNumber);
void LoadInfo(const AdditionInfo& additionInfo, AdditionsItem& rCurrentItem,
const size_t nGridPositionY);
void UpdateUI(const std::vector<AdditionInfo>& additionInfos);
void StopExecution() { m_bExecute = false; }
};
+257 -229
View File
@@ -8,52 +8,270 @@
<property name="valign">start</property>
<child>
<object class="GtkBox">
<property name="width_request">310</property>
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="margin_left">5</property>
<property name="hexpand">False</property>
<property name="vexpand">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage" id="imageScreenshot">
<property name="width_request">60</property>
<property name="height_request">60</property>
<object class="GtkBox">
<property name="width_request">310</property>
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="margin_top">3</property>
<property name="hexpand">False</property>
<property name="vexpand">False</property>
<property name="stock">gtk-missing-image</property>
<accessibility>
<relation type="labelled-by" target="labelDescription"/>
</accessibility>
<property name="orientation">vertical</property>
<child>
<object class="GtkImage" id="imageScreenshot">
<property name="width_request">60</property>
<property name="height_request">60</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="margin_top">3</property>
<property name="hexpand">False</property>
<property name="vexpand">False</property>
<property name="stock">gtk-missing-image</property>
<accessibility>
<relation type="labelled-by" target="labelDescription"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonInstall">
<property name="label" translatable="yes" context="additionsEntry|buttonInstall">button</property>
<property name="width_request">310</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_top">5</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonInstall">
<property name="label" translatable="yes" context="additionsEntry|buttonInstall">button</property>
<property name="width_request">310</property>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="margin_top">5</property>
<property name="hexpand">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="orientation">vertical</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkLinkButton" id="linkButtonName">
<property name="label" translatable="yes" context="additionsEntry|linkButtonName">button</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">start</property>
<property name="relief">none</property>
<property name="uri">http://glade.gnome.org</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelAuthor">
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" context="additionsEntry|labelAuthor">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelDesc">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<property name="label" translatable="yes" context="additionsEntry|labelDesc">Description:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelDescription">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes" context="additionsEntry|labelDescription">label</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<property name="width_chars">1</property>
<property name="max_width_chars">50</property>
<accessibility>
<relation type="label-for" target="imageScreenshot"/>
<relation type="label-for" target="imageVoting"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelLicense">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<property name="label" translatable="yes" context="additionsEntry|labelLicense">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelVersion">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<property name="label" translatable="yes" context="additionsEntry|labelVersion">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<child>
<object class="GtkLabel" id="labelComments">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes" context="additionsEntry|labelComments">Comments:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLinkButton" id="linkButtonComments">
<property name="label" translatable="yes" context="additionsEntry|linkButtonComments">button</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<property name="uri">http://glade.gnome.org</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkImage" id="imageVoting">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="stock">gtk-about</property>
<accessibility>
<relation type="labelled-by" target="labelDescription"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<child>
<object class="GtkImage" id="imageDownloadNumber">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="stock">gtk-directory</property>
<accessibility>
<relation type="labelled-by" target="labelDownloadNumber"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelDownloadNumber">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" context="additionsEntry|labelDownloader">label</property>
<accessibility>
<relation type="label-for" target="imageDownloadNumber"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
@@ -65,212 +283,22 @@
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_left">5</property>
<property name="orientation">vertical</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkLinkButton" id="linkButtonName">
<property name="label" translatable="yes" context="additionsEntry|linkButtonName">button</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="halign">start</property>
<property name="relief">none</property>
<property name="uri">http://glade.gnome.org</property>
<object class="GtkButton" id="buttonShowMore">
<property name="label" translatable="yes" context="additionsDialog|buttonShowMore">Show More Extensions</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_left">7</property>
<property name="margin_right">7</property>
<child internal-child="accessible">
<object class="AtkObject" id="buttonShowMore-atkobject">
<property name="AtkObject::accessible-name" translatable="yes" context="additionsDialog|buttonShowMore">ButtonShowMore</property>
<property name="AtkObject::accessible-description" translatable="yes" context="additionsDialog|buttonShowMore">This button shows more extensions.</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelAuthor">
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes" context="additionsEntry|labelAuthor">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelDesc">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<property name="label" translatable="yes" context="additionsEntry|labelDesc">Description:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelDescription">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes" context="additionsEntry|labelDescription">label</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<property name="width_chars">1</property>
<property name="max_width_chars">50</property>
<accessibility>
<relation type="label-for" target="imageScreenshot"/>
<relation type="label-for" target="imageVoting"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelLicense">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<property name="label" translatable="yes" context="additionsEntry|labelLicense">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelVersion">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<property name="label" translatable="yes" context="additionsEntry|labelVersion">label</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<child>
<object class="GtkLabel" id="labelComments">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes" context="additionsEntry|labelComments">Comments:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLinkButton" id="linkButtonComments">
<property name="label" translatable="yes" context="additionsEntry|linkButtonComments">button</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<property name="uri">http://glade.gnome.org</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkImage" id="imageVoting">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="stock">gtk-about</property>
<accessibility>
<relation type="labelled-by" target="labelDescription"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_top">3</property>
<child>
<object class="GtkImage" id="imageDownloadNumber">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="stock">gtk-directory</property>
<accessibility>
<relation type="labelled-by" target="labelDownloadNumber"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="labelDownloadNumber">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_left">5</property>
<property name="label" translatable="yes" context="additionsEntry|labelDownloader">label</property>
<accessibility>
<relation type="label-for" target="imageDownloadNumber"/>
</accessibility>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>