1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/config.h>
28 #include <com/sun/star/beans/NamedValue.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/configuration/theDefaultProvider.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/deployment/UpdateInformationProvider.hpp>
33 #include <com/sun/star/deployment/ExtensionManager.hpp>
34 #include <com/sun/star/deployment/XUpdateInformationProvider.hpp>
35 #include <com/sun/star/frame/Desktop.hpp>
36 #include <com/sun/star/frame/XDispatch.hpp>
37 #include <com/sun/star/frame/XDispatchProvider.hpp>
38 #include <com/sun/star/lang/IllegalArgumentException.hpp>
39 #include <com/sun/star/task/InteractionHandler.hpp>
40 #include <com/sun/star/ucb/CommandFailedException.hpp>
41 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
42 #include <com/sun/star/uno/Any.hxx>
43 #include <com/sun/star/uno/Exception.hpp>
44 #include <com/sun/star/uno/Reference.hxx>
45 #include <com/sun/star/uno/Sequence.hxx>
46 #include <com/sun/star/util/URL.hpp>
47 #include <com/sun/star/util/URLTransformer.hpp>
48 #include <com/sun/star/util/XURLTransformer.hpp>
49 #include <com/sun/star/xml/dom/XElement.hpp>
50 #include <osl/diagnose.h>
51 #include <rtl/ref.hxx>
52 #include <rtl/ustrbuf.hxx>
53 #include <rtl/ustring.hxx>
54 #include <sal/types.h>
55 #include <salhelper/thread.hxx>
56 #include <tools/gen.hxx>
57 #include <tools/link.hxx>
58 #include <unotools/configmgr.hxx>
59 #include <vcl/svapp.hxx>
61 #include <comphelper/processfactory.hxx>
62 #include <comphelper/propertyvalue.hxx>
64 #include <dp_dependencies.hxx>
65 #include <dp_descriptioninfoset.hxx>
66 #include <dp_identifier.hxx>
68 #include <dp_update.hxx>
70 #include <strings.hrc>
71 #include "dp_gui_updatedata.hxx"
72 #include "dp_gui_updatedialog.hxx"
73 #include <dp_shared.hxx>
77 namespace com::sun::star::uno
{
78 class XComponentContext
;
81 using namespace ::com::sun::star
;
82 using dp_gui::UpdateDialog
;
86 sal_Unicode
const LF
= 0x000A;
87 sal_Unicode
const CR
= 0x000D;
89 constexpr OUStringLiteral IGNORED_UPDATES
= u
"/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates";
90 constexpr OUStringLiteral PROPERTY_VERSION
= u
"Version";
92 enum Kind
{ ENABLED_UPDATE
, DISABLED_UPDATE
, SPECIFIC_ERROR
};
94 OUString
confineToParagraph(OUString
const & text
) {
95 // Confine arbitrary text to a single paragraph in a VclMultiLineEdit
96 // This assumes that U+000A and U+000D are the only paragraph separators in
97 // a VclMultiLineEdit, and that replacing them with a single space
98 // each is acceptable:
99 return text
.replace(LF
, ' ').replace(CR
, ' ');
103 struct UpdateDialog::DisabledUpdate
{
105 uno::Sequence
< OUString
> unsatisfiedDependencies
;
106 // We also want to show release notes and publisher for disabled updates
107 css::uno::Reference
< css::xml::dom::XNode
> aUpdateInfo
;
110 struct UpdateDialog::SpecificError
{
116 struct UpdateDialog::IgnoredUpdate
{
117 OUString sExtensionID
;
120 IgnoredUpdate( OUString aExtensionID
, OUString aVersion
);
124 UpdateDialog::IgnoredUpdate::IgnoredUpdate( OUString aExtensionID
, OUString aVersion
):
125 sExtensionID(std::move( aExtensionID
)),
126 sVersion(std::move( aVersion
))
130 struct UpdateDialog::Index
137 Index( Kind theKind
, sal_uInt16 nIndex
, OUString aName
) :
141 m_aName(std::move( aName
)) {}
145 class UpdateDialog::Thread
: public salhelper::Thread
{
148 uno::Reference
< uno::XComponentContext
> const & context
,
149 UpdateDialog
& dialog
,
150 std::vector
< uno::Reference
< deployment::XPackage
> > && vExtensionList
);
155 virtual ~Thread() override
;
157 virtual void execute() override
;
159 void handleSpecificError(
160 uno::Reference
< deployment::XPackage
> const & package
,
161 uno::Any
const & exception
) const;
163 OUString
getUpdateDisplayString(
164 dp_gui::UpdateData
const & data
, std::u16string_view version
= std::u16string_view()) const;
166 void prepareUpdateData(
167 css::uno::Reference
< css::xml::dom::XNode
> const & updateInfo
,
168 UpdateDialog::DisabledUpdate
& out_du
,
169 dp_gui::UpdateData
& out_data
) const;
172 UpdateDialog::DisabledUpdate
const & du
,
173 dp_gui::UpdateData
const & data
) const;
175 uno::Reference
< uno::XComponentContext
> m_context
;
176 UpdateDialog
& m_dialog
;
177 std::vector
< uno::Reference
< deployment::XPackage
> > m_vExtensionList
;
178 uno::Reference
< deployment::XUpdateInformationProvider
> m_updateInformation
;
179 uno::Reference
< task::XInteractionHandler
> m_xInteractionHdl
;
181 // guarded by Application::GetSolarMutex():
185 UpdateDialog::Thread::Thread(
186 uno::Reference
< uno::XComponentContext
> const & context
,
187 UpdateDialog
& dialog
,
188 std::vector
< uno::Reference
< deployment::XPackage
> >&& vExtensionList
):
189 salhelper::Thread("dp_gui_updatedialog"),
192 m_vExtensionList(std::move(vExtensionList
)),
194 deployment::UpdateInformationProvider::create(context
)),
200 task::InteractionHandler::createWithParent(m_context
, dialog
.getDialog()->GetXWindow());
201 m_updateInformation
->setInteractionHandler( m_xInteractionHdl
);
205 void UpdateDialog::Thread::stop() {
210 m_updateInformation
->cancel();
213 UpdateDialog::Thread::~Thread()
215 if ( m_xInteractionHdl
.is() )
216 m_updateInformation
->setInteractionHandler( uno::Reference
< task::XInteractionHandler
> () );
219 void UpdateDialog::Thread::execute()
227 uno::Reference
<deployment::XExtensionManager
> extMgr
=
228 deployment::ExtensionManager::get(m_context
);
230 std::vector
<std::pair
<uno::Reference
<deployment::XPackage
>, uno::Any
> > errors
;
232 dp_misc::UpdateInfoMap updateInfoMap
= dp_misc::getOnlineUpdateInfos(
233 m_context
, extMgr
, m_updateInformation
, &m_vExtensionList
, errors
);
235 for (auto const& elem
: errors
)
236 handleSpecificError(elem
.first
, elem
.second
);
238 for (auto const& updateInfo
: updateInfoMap
)
240 dp_misc::UpdateInfo
const & info
= updateInfo
.second
;
241 UpdateData
updateData(info
.extension
);
242 DisabledUpdate disableUpdate
;
243 //determine if online updates meet the requirements
244 prepareUpdateData(info
.info
, disableUpdate
, updateData
);
246 //determine if the update is installed in the user or shared repository
247 OUString sOnlineVersion
;
249 sOnlineVersion
= info
.version
;
250 OUString sVersionUser
;
251 OUString sVersionShared
;
252 OUString sVersionBundled
;
253 uno::Sequence
< uno::Reference
< deployment::XPackage
> > extensions
;
255 extensions
= extMgr
->getExtensionsWithSameIdentifier(
256 dp_misc::getIdentifier(info
.extension
), info
.extension
->getName(),
257 uno::Reference
<ucb::XCommandEnvironment
>());
258 } catch ( const lang::IllegalArgumentException
& ) {
261 } catch ( const css::ucb::CommandFailedException
& ) {
265 OSL_ASSERT(extensions
.getLength() == 3);
266 if (extensions
[0].is() )
267 sVersionUser
= extensions
[0]->getVersion();
268 if (extensions
[1].is() )
269 sVersionShared
= extensions
[1]->getVersion();
270 if (extensions
[2].is() )
271 sVersionBundled
= extensions
[2]->getVersion();
273 bool bSharedReadOnly
= extMgr
->isReadOnlyRepository(u
"shared"_ustr
);
275 dp_misc::UPDATE_SOURCE sourceUser
= dp_misc::isUpdateUserExtension(
276 bSharedReadOnly
, sVersionUser
, sVersionShared
, sVersionBundled
, sOnlineVersion
);
277 dp_misc::UPDATE_SOURCE sourceShared
= dp_misc::isUpdateSharedExtension(
278 bSharedReadOnly
, sVersionShared
, sVersionBundled
, sOnlineVersion
);
280 if (sourceUser
!= dp_misc::UPDATE_SOURCE_NONE
)
282 if (sourceUser
== dp_misc::UPDATE_SOURCE_SHARED
)
284 updateData
.aUpdateSource
= extensions
[1];
285 updateData
.updateVersion
= extensions
[1]->getVersion();
287 else if (sourceUser
== dp_misc::UPDATE_SOURCE_BUNDLED
)
289 updateData
.aUpdateSource
= extensions
[2];
290 updateData
.updateVersion
= extensions
[2]->getVersion();
292 if (!update(disableUpdate
, updateData
))
296 if (sourceShared
!= dp_misc::UPDATE_SOURCE_NONE
)
298 if (sourceShared
== dp_misc::UPDATE_SOURCE_BUNDLED
)
300 updateData
.aUpdateSource
= extensions
[2];
301 updateData
.updateVersion
= extensions
[2]->getVersion();
303 updateData
.bIsShared
= true;
304 if (!update(disableUpdate
, updateData
))
312 m_dialog
.checkingDone();
316 //Parameter package can be null
317 void UpdateDialog::Thread::handleSpecificError(
318 uno::Reference
< deployment::XPackage
> const & package
,
319 uno::Any
const & exception
) const
321 UpdateDialog::SpecificError data
;
323 data
.name
= package
->getDisplayName();
325 if (exception
>>= e
) {
326 data
.message
= e
.Message
;
330 m_dialog
.addSpecificError(data
);
334 OUString
UpdateDialog::Thread::getUpdateDisplayString(
335 dp_gui::UpdateData
const & data
, std::u16string_view version
) const
337 OSL_ASSERT(data
.aInstalledPackage
.is());
338 OUStringBuffer
b(data
.aInstalledPackage
->getDisplayName());
343 b
.append(m_dialog
.m_version
);
346 if (!version
.empty())
349 b
.append(data
.updateVersion
);
351 if (!data
.sWebsiteURL
.isEmpty())
357 b
.append(m_dialog
.m_browserbased
);
360 return b
.makeStringAndClear();
363 /** out_data will only be filled if all dependencies are ok.
365 void UpdateDialog::Thread::prepareUpdateData(
366 uno::Reference
< xml::dom::XNode
> const & updateInfo
,
367 UpdateDialog::DisabledUpdate
& out_du
,
368 dp_gui::UpdateData
& out_data
) const
370 if (!updateInfo
.is())
372 dp_misc::DescriptionInfoset
infoset(m_context
, updateInfo
);
373 OSL_ASSERT(!infoset
.getVersion().isEmpty());
374 uno::Sequence
< uno::Reference
< xml::dom::XElement
> > ds(
375 dp_misc::Dependencies::check(infoset
));
377 out_du
.aUpdateInfo
= updateInfo
;
378 out_du
.unsatisfiedDependencies
.realloc(ds
.getLength());
379 auto p_unsatisfiedDependencies
= out_du
.unsatisfiedDependencies
.getArray();
380 for (sal_Int32 i
= 0; i
< ds
.getLength(); ++i
) {
381 p_unsatisfiedDependencies
[i
] = dp_misc::Dependencies::getErrorText(ds
[i
]);
384 const ::std::optional
< OUString
> updateWebsiteURL(infoset
.getLocalizedUpdateWebsiteURL());
386 out_du
.name
= getUpdateDisplayString(out_data
, infoset
.getVersion());
388 if (!out_du
.unsatisfiedDependencies
.hasElements())
390 out_data
.aUpdateInfo
= updateInfo
;
391 out_data
.updateVersion
= infoset
.getVersion();
392 if (updateWebsiteURL
)
393 out_data
.sWebsiteURL
= *updateWebsiteURL
;
397 bool UpdateDialog::Thread::update(
398 UpdateDialog::DisabledUpdate
const & du
,
399 dp_gui::UpdateData
const & data
) const
402 if (!du
.unsatisfiedDependencies
.hasElements())
406 m_dialog
.addEnabledUpdate(getUpdateDisplayString(data
), data
);
412 m_dialog
.addDisabledUpdate(du
);
419 // UpdateDialog ----------------------------------------------------------
420 UpdateDialog::UpdateDialog(
421 uno::Reference
< uno::XComponentContext
> const & context
,
422 weld::Window
* parent
, std::vector
<uno::Reference
< deployment::XPackage
> > && vExtensionList
,
423 std::vector
< dp_gui::UpdateData
> * updateData
)
424 : GenericDialogController(parent
, u
"desktop/ui/updatedialog.ui"_ustr
, u
"UpdateDialog"_ustr
)
426 , m_none(DpResId(RID_DLG_UPDATE_NONE
))
427 , m_noInstallable(DpResId(RID_DLG_UPDATE_NOINSTALLABLE
))
428 , m_failure(DpResId(RID_DLG_UPDATE_FAILURE
))
429 , m_unknownError(DpResId(RID_DLG_UPDATE_UNKNOWNERROR
))
430 , m_noDescription(DpResId(RID_DLG_UPDATE_NODESCRIPTION
))
431 , m_noInstall(DpResId(RID_DLG_UPDATE_NOINSTALL
))
432 , m_noDependency(DpResId(RID_DLG_UPDATE_NODEPENDENCY
))
433 , m_noDependencyCurVer(DpResId(RID_DLG_UPDATE_NODEPENDENCY_CUR_VER
))
434 , m_browserbased(DpResId(RID_DLG_UPDATE_BROWSERBASED
))
435 , m_version(DpResId(RID_DLG_UPDATE_VERSION
))
436 , m_ignoredUpdate(DpResId(RID_DLG_UPDATE_IGNORED_UPDATE
))
437 , m_updateData(*updateData
)
438 , m_thread(new UpdateDialog::Thread(context
, *this, std::move(vExtensionList
)))
439 , m_xChecking(m_xBuilder
->weld_label(u
"UPDATE_CHECKING"_ustr
))
440 , m_xThrobber(m_xBuilder
->weld_spinner(u
"THROBBER"_ustr
))
441 , m_xUpdate(m_xBuilder
->weld_label(u
"UPDATE_LABEL"_ustr
))
442 , m_xUpdates(m_xBuilder
->weld_tree_view(u
"checklist"_ustr
))
443 , m_xAll(m_xBuilder
->weld_check_button(u
"UPDATE_ALL"_ustr
))
444 , m_xDescription(m_xBuilder
->weld_label(u
"DESCRIPTION_LABEL"_ustr
))
445 , m_xPublisherLabel(m_xBuilder
->weld_label(u
"PUBLISHER_LABEL"_ustr
))
446 , m_xPublisherLink(m_xBuilder
->weld_link_button(u
"PUBLISHER_LINK"_ustr
))
447 , m_xReleaseNotesLabel(m_xBuilder
->weld_label(u
"RELEASE_NOTES_LABEL"_ustr
))
448 , m_xReleaseNotesLink(m_xBuilder
->weld_link_button(u
"RELEASE_NOTES_LINK"_ustr
))
449 , m_xDescriptions(m_xBuilder
->weld_text_view(u
"DESCRIPTIONS"_ustr
))
450 , m_xOk(m_xBuilder
->weld_button(u
"ok"_ustr
))
451 , m_xClose(m_xBuilder
->weld_button(u
"close"_ustr
))
452 , m_xHelp(m_xBuilder
->weld_button(u
"help"_ustr
))
454 auto nWidth
= m_xDescriptions
->get_approximate_digit_width() * 62;
455 auto nHeight
= m_xDescriptions
->get_height_rows(8);
456 m_xDescriptions
->set_size_request(nWidth
, nHeight
);
457 m_xUpdates
->set_size_request(nWidth
, nHeight
);
459 m_xUpdates
->enable_toggle_buttons(weld::ColumnToggleType::Check
);
461 OSL_ASSERT(updateData
!= nullptr);
463 m_xExtensionManager
= deployment::ExtensionManager::get( context
);
465 m_xUpdates
->connect_selection_changed(LINK(this, UpdateDialog
, selectionHandler
));
466 m_xUpdates
->connect_toggled(LINK(this, UpdateDialog
, entryToggled
));
467 m_xAll
->connect_toggled(LINK(this, UpdateDialog
, allHandler
));
468 m_xOk
->connect_clicked(LINK(this, UpdateDialog
, okHandler
));
469 m_xClose
->connect_clicked(LINK(this, UpdateDialog
, closeHandler
));
470 if (!dp_misc::office_is_running())
471 m_xHelp
->set_sensitive(false);
477 UpdateDialog::~UpdateDialog()
481 short UpdateDialog::run() {
482 m_xThrobber
->start();
484 short nRet
= GenericDialogController::run();
489 IMPL_LINK(UpdateDialog
, entryToggled
, const weld::TreeView::iter_col
&, rRowCol
, void)
491 // error's can't be enabled
492 const UpdateDialog::Index
* p
= weld::fromId
<UpdateDialog::Index
const *>(m_xUpdates
->get_id(rRowCol
.first
));
493 if (p
->m_eKind
== SPECIFIC_ERROR
)
494 m_xUpdates
->set_toggle(rRowCol
.first
, TRISTATE_FALSE
);
499 void UpdateDialog::insertItem(const UpdateDialog::Index
*pEntry
, bool bEnabledCheckBox
)
501 int nEntry
= m_xUpdates
->n_children();
502 m_xUpdates
->append();
503 m_xUpdates
->set_toggle(nEntry
, bEnabledCheckBox
? TRISTATE_TRUE
: TRISTATE_FALSE
);
504 m_xUpdates
->set_text(nEntry
, pEntry
->m_aName
, 0);
505 m_xUpdates
->set_id(nEntry
, weld::toId(pEntry
));
508 void UpdateDialog::addAdditional(const UpdateDialog::Index
* index
, bool bEnabledCheckBox
)
510 m_xAll
->set_sensitive(true);
511 if (m_xAll
->get_active())
513 insertItem(index
, bEnabledCheckBox
);
514 m_xUpdate
->set_sensitive(true);
515 m_xUpdates
->set_sensitive(true);
516 m_xDescription
->set_sensitive(true);
517 m_xDescriptions
->set_sensitive(true);
521 void UpdateDialog::addEnabledUpdate( OUString
const & name
,
522 dp_gui::UpdateData
const & data
)
524 sal_uInt16 nIndex
= sal::static_int_cast
< sal_uInt16
>( m_enabledUpdates
.size() );
525 UpdateDialog::Index
*pEntry
= new UpdateDialog::Index( ENABLED_UPDATE
, nIndex
, name
);
527 m_enabledUpdates
.push_back( data
);
528 m_ListboxEntries
.emplace_back( pEntry
);
530 if (!isIgnoredUpdate(pEntry
))
532 insertItem(pEntry
, true);
535 addAdditional(pEntry
, false);
537 m_xUpdate
->set_sensitive(true);
538 m_xUpdates
->set_sensitive(true);
539 m_xDescription
->set_sensitive(true);
540 m_xDescriptions
->set_sensitive(true);
543 void UpdateDialog::addDisabledUpdate( UpdateDialog::DisabledUpdate
const & data
)
545 sal_uInt16 nIndex
= sal::static_int_cast
< sal_uInt16
>( m_disabledUpdates
.size() );
546 UpdateDialog::Index
*pEntry
= new UpdateDialog::Index( DISABLED_UPDATE
, nIndex
, data
.name
);
548 m_disabledUpdates
.push_back( data
);
549 m_ListboxEntries
.emplace_back( pEntry
);
551 isIgnoredUpdate( pEntry
);
552 addAdditional(pEntry
, false);
555 void UpdateDialog::addSpecificError( UpdateDialog::SpecificError
const & data
)
557 sal_uInt16 nIndex
= sal::static_int_cast
< sal_uInt16
>( m_specificErrors
.size() );
558 UpdateDialog::Index
*pEntry
= new UpdateDialog::Index( SPECIFIC_ERROR
, nIndex
, data
.name
);
560 m_specificErrors
.push_back( data
);
561 m_ListboxEntries
.emplace_back( pEntry
);
563 addAdditional(pEntry
, false);
566 void UpdateDialog::checkingDone() {
570 if (m_xUpdates
->n_children() == 0)
573 m_xDescription
->set_sensitive(true);
574 m_xDescriptions
->set_sensitive(true);
576 if ( m_disabledUpdates
.empty() && m_specificErrors
.empty() && m_ignoredUpdates
.empty() )
577 showDescription( m_none
);
579 showDescription( m_noInstallable
);
585 void UpdateDialog::enableOk() {
586 if (!m_xChecking
->get_visible()) {
588 for (int i
= 0, nCount
= m_xUpdates
->n_children(); i
< nCount
; ++i
) {
589 if (m_xUpdates
->get_toggle(i
) == TRISTATE_TRUE
)
592 m_xOk
->set_sensitive(nChecked
!= 0);
596 // *********************************************************************************
597 void UpdateDialog::createNotifyJob( bool bPrepareOnly
,
598 uno::Sequence
< uno::Sequence
< OUString
> > const &rItemList
)
600 if ( !dp_misc::office_is_running() )
603 // notify update check job
606 uno::Reference
< lang::XMultiServiceFactory
> xConfigProvider(
607 configuration::theDefaultProvider::get(
608 comphelper::getProcessComponentContext()));
610 uno::Sequence
< uno::Any
> aArgumentList
{ uno::Any(comphelper::makePropertyValue(
612 u
"org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob"_ustr
)) };
614 uno::Reference
< container::XNameAccess
> xNameAccess(
615 xConfigProvider
->createInstanceWithArguments(
616 u
"com.sun.star.configuration.ConfigurationAccess"_ustr
, aArgumentList
),
617 uno::UNO_QUERY_THROW
);
620 xNameAccess
->getByName(u
"URL"_ustr
) >>= aURL
.Complete
;
622 const uno::Reference
< uno::XComponentContext
>& xContext( ::comphelper::getProcessComponentContext() );
623 uno::Reference
< util::XURLTransformer
> xTransformer
= util::URLTransformer::create(xContext
);
625 xTransformer
->parseStrict(aURL
);
627 uno::Reference
< frame::XDesktop2
> xDesktop
= frame::Desktop::create( xContext
);
628 uno::Reference
< frame::XDispatchProvider
> xDispatchProvider( xDesktop
->getCurrentFrame(),
629 uno::UNO_QUERY_THROW
);
630 uno::Reference
< frame::XDispatch
> xDispatch
= xDispatchProvider
->queryDispatch(aURL
, OUString(), 0);
634 uno::Sequence aPropList
{ comphelper::makePropertyValue(u
"updateList"_ustr
, rItemList
),
635 comphelper::makePropertyValue(u
"prepareOnly"_ustr
, bPrepareOnly
) };
637 xDispatch
->dispatch(aURL
, aPropList
);
640 catch( const uno::Exception
& e
)
642 dp_misc::TRACE( "Caught exception: "
643 + e
.Message
+ "\n thread terminated.\n\n");
647 // *********************************************************************************
648 void UpdateDialog::notifyMenubar( bool bPrepareOnly
, bool bRecheckOnly
)
650 if ( !dp_misc::office_is_running() )
653 uno::Sequence
< uno::Sequence
< OUString
> > aItemList
;
655 if ( ! bRecheckOnly
)
657 sal_Int32 nCount
= 0;
658 for (sal_uInt16 i
= 0, nItemCount
= m_xUpdates
->n_children(); i
< nItemCount
; ++i
)
661 UpdateDialog::Index
const * p
= weld::fromId
<UpdateDialog::Index
const*>(m_xUpdates
->get_id(i
));
663 if ( p
->m_eKind
== ENABLED_UPDATE
)
665 dp_gui::UpdateData aUpdData
= m_enabledUpdates
[ p
->m_nIndex
];
667 dp_misc::DescriptionInfoset
aInfoset( m_context
, aUpdData
.aUpdateInfo
);
668 aItemList
.realloc(nCount
+ 1);
669 aItemList
.getArray()[nCount
] =
671 dp_misc::getIdentifier( aUpdData
.aInstalledPackage
),
672 aInfoset
.getVersion()
681 createNotifyJob( bPrepareOnly
, aItemList
);
684 // *********************************************************************************
686 void UpdateDialog::initDescription()
688 m_xPublisherLabel
->hide();
689 m_xPublisherLink
->hide();
690 m_xReleaseNotesLabel
->hide();
691 m_xReleaseNotesLink
->hide();
694 void UpdateDialog::clearDescription()
696 m_xPublisherLabel
->hide();
697 m_xPublisherLink
->hide();
698 m_xPublisherLink
->set_label(u
""_ustr
);
699 m_xPublisherLink
->set_uri(u
""_ustr
);
700 m_xReleaseNotesLabel
->hide();
701 m_xReleaseNotesLink
->hide();
702 m_xReleaseNotesLink
->set_uri( u
""_ustr
);
703 m_xDescriptions
->set_text(u
""_ustr
);
706 bool UpdateDialog::showDescription(uno::Reference
< xml::dom::XNode
> const & aUpdateInfo
)
708 dp_misc::DescriptionInfoset
infoset(m_context
, aUpdateInfo
);
709 return showDescription(infoset
.getLocalizedPublisherNameAndURL(),
710 infoset
.getLocalizedReleaseNotesURL());
713 bool UpdateDialog::showDescription(uno::Reference
< deployment::XPackage
> const & aExtension
)
715 OSL_ASSERT(aExtension
.is());
716 beans::StringPair pubInfo
= aExtension
->getPublisherInfo();
717 return showDescription(std::make_pair(pubInfo
.First
, pubInfo
.Second
),
721 bool UpdateDialog::showDescription(std::pair
< OUString
, OUString
> const & pairPublisher
,
722 OUString
const & sReleaseNotes
)
724 OUString sPub
= pairPublisher
.first
;
725 OUString sURL
= pairPublisher
.second
;
727 if ( sPub
.isEmpty() && sURL
.isEmpty() && sReleaseNotes
.isEmpty() )
731 if ( !sPub
.isEmpty() )
733 m_xPublisherLabel
->show();
734 m_xPublisherLink
->show();
735 m_xPublisherLink
->set_label(sPub
);
736 m_xPublisherLink
->set_uri(sURL
);
739 if ( !sReleaseNotes
.isEmpty() )
741 m_xReleaseNotesLabel
->show();
742 m_xReleaseNotesLink
->show();
743 m_xReleaseNotesLink
->set_uri( sReleaseNotes
);
748 bool UpdateDialog::showDescription( const OUString
& rDescription
)
750 if ( rDescription
.isEmpty() )
754 m_xDescriptions
->set_text(rDescription
);
758 void UpdateDialog::getIgnoredUpdates()
760 uno::Reference
< lang::XMultiServiceFactory
> xConfig(
761 configuration::theDefaultProvider::get(m_context
));
762 beans::NamedValue
aValue( u
"nodepath"_ustr
, uno::Any( OUString(IGNORED_UPDATES
) ) );
763 uno::Sequence
< uno::Any
> args
{ uno::Any(aValue
) };
765 uno::Reference
< container::XNameAccess
> xNameAccess( xConfig
->createInstanceWithArguments( u
"com.sun.star.configuration.ConfigurationAccess"_ustr
, args
), uno::UNO_QUERY_THROW
);
766 const uno::Sequence
< OUString
> aElementNames
= xNameAccess
->getElementNames();
768 for ( OUString
const & aIdentifier
: aElementNames
)
772 uno::Any
aPropValue( uno::Reference
< beans::XPropertySet
>( xNameAccess
->getByName( aIdentifier
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
773 aPropValue
>>= aVersion
;
774 IgnoredUpdate
*pData
= new IgnoredUpdate( aIdentifier
, aVersion
);
775 m_ignoredUpdates
.emplace_back( pData
);
780 bool UpdateDialog::isIgnoredUpdate( UpdateDialog::Index
* index
)
782 bool bIsIgnored
= false;
784 if (! m_ignoredUpdates
.empty() )
786 OUString aExtensionID
;
789 if ( index
->m_eKind
== ENABLED_UPDATE
)
791 dp_gui::UpdateData aUpdData
= m_enabledUpdates
[ index
->m_nIndex
];
792 aExtensionID
= dp_misc::getIdentifier( aUpdData
.aInstalledPackage
);
793 aVersion
= aUpdData
.updateVersion
;
795 else if ( index
->m_eKind
== DISABLED_UPDATE
)
797 DisabledUpdate
&rData
= m_disabledUpdates
[ index
->m_nIndex
];
798 dp_misc::DescriptionInfoset
aInfoset( m_context
, rData
.aUpdateInfo
);
799 ::std::optional
< OUString
> aID( aInfoset
.getIdentifier() );
802 aVersion
= aInfoset
.getVersion();
805 for (auto const& ignoredUpdate
: m_ignoredUpdates
)
807 if ( ignoredUpdate
->sExtensionID
== aExtensionID
)
809 if ( ( !ignoredUpdate
->sVersion
.isEmpty() ) || ( ignoredUpdate
->sVersion
== aVersion
) )
812 index
->m_bIgnored
= true;
823 IMPL_LINK_NOARG(UpdateDialog
, selectionHandler
, weld::TreeView
&, void)
826 int nSelectedPos
= m_xUpdates
->get_selected_index();
829 const UpdateDialog::Index
* p
= nullptr;
830 if (nSelectedPos
!= -1)
831 p
= weld::fromId
<UpdateDialog::Index
const*>(m_xUpdates
->get_id(nSelectedPos
));
834 sal_uInt16 pos
= p
->m_nIndex
;
840 if ( m_enabledUpdates
[ pos
].aUpdateSource
.is() )
841 showDescription( m_enabledUpdates
[ pos
].aUpdateSource
);
843 showDescription( m_enabledUpdates
[ pos
].aUpdateInfo
);
846 b
.append( m_ignoredUpdate
);
850 case DISABLED_UPDATE
:
852 if ( !m_disabledUpdates
.empty() )
853 showDescription( m_disabledUpdates
[pos
].aUpdateInfo
);
856 b
.append( m_ignoredUpdate
);
858 if ( m_disabledUpdates
.empty() )
861 UpdateDialog::DisabledUpdate
& data
= m_disabledUpdates
[ pos
];
862 if (data
.unsatisfiedDependencies
.hasElements())
864 // create error string for version mismatch
865 OUString
sVersion( u
"%VERSION"_ustr
);
866 OUString
sProductName( u
"%PRODUCTNAME"_ustr
);
867 sal_Int32 nPos
= m_noDependencyCurVer
.indexOf( sVersion
);
870 m_noDependencyCurVer
= m_noDependencyCurVer
.replaceAt( nPos
, sVersion
.getLength(), utl::ConfigManager::getAboutBoxProductVersion() );
872 nPos
= m_noDependencyCurVer
.indexOf( sProductName
);
875 m_noDependencyCurVer
= m_noDependencyCurVer
.replaceAt( nPos
, sProductName
.getLength(), utl::ConfigManager::getProductName() );
877 nPos
= m_noDependency
.indexOf( sProductName
);
880 m_noDependency
= m_noDependency
.replaceAt( nPos
, sProductName
.getLength(), utl::ConfigManager::getProductName() );
883 b
.append(m_noInstall
+ OUStringChar(LF
) + m_noDependency
);
884 for (sal_Int32 i
= 0;
885 i
< data
.unsatisfiedDependencies
.getLength(); ++i
)
887 b
.append(OUStringChar(LF
) + " ");
888 // U+2003 EM SPACE would be better than two spaces,
889 // but some fonts do not contain it
892 data
.unsatisfiedDependencies
[i
]));
894 b
.append(OUStringChar(LF
) + " " + m_noDependencyCurVer
);
900 UpdateDialog::SpecificError
& data
= m_specificErrors
[ pos
];
901 b
.append(m_failure
+ OUStringChar(LF
));
902 b
.append( data
.message
.isEmpty() ? m_unknownError
: data
.message
);
912 b
.append( m_noDescription
);
914 showDescription( b
.makeStringAndClear() );
917 IMPL_LINK_NOARG(UpdateDialog
, allHandler
, weld::Toggleable
&, void)
919 if (m_xAll
->get_active())
921 m_xUpdate
->set_sensitive(true);
922 m_xUpdates
->set_sensitive(true);
923 m_xDescription
->set_sensitive(true);
924 m_xDescriptions
->set_sensitive(true);
926 for (auto const& listboxEntry
: m_ListboxEntries
)
928 if ( listboxEntry
->m_bIgnored
|| ( listboxEntry
->m_eKind
!= ENABLED_UPDATE
) )
929 insertItem(listboxEntry
.get(), false);
934 for (sal_uInt16 i
= m_xUpdates
->n_children(); i
!= 0 ;)
937 UpdateDialog::Index
const * p
= weld::fromId
<UpdateDialog::Index
const*>(m_xUpdates
->get_id(i
));
938 if ( p
->m_bIgnored
|| ( p
->m_eKind
!= ENABLED_UPDATE
) )
940 m_xUpdates
->remove(i
);
944 if (m_xUpdates
->n_children() == 0)
947 m_xUpdate
->set_sensitive(false);
948 m_xUpdates
->set_sensitive(false);
949 if (m_xChecking
->get_visible())
950 m_xDescription
->set_sensitive(false);
952 showDescription(m_noInstallable
);
957 IMPL_LINK_NOARG(UpdateDialog
, okHandler
, weld::Button
&, void)
959 //If users are going to update a shared extension then we need
961 for (auto const& enableUpdate
: m_enabledUpdates
)
963 OSL_ASSERT(enableUpdate
.aInstalledPackage
.is());
964 //If the user has no write access to the shared folder then the update
965 //for a shared extension is disable, that is it cannot be in m_enabledUpdates
969 for (sal_uInt16 i
= 0, nCount
= m_xUpdates
->n_children(); i
< nCount
; ++i
)
971 UpdateDialog::Index
const * p
=
972 weld::fromId
<UpdateDialog::Index
const*>(m_xUpdates
->get_id(i
));
973 if (p
->m_eKind
== ENABLED_UPDATE
&& m_xUpdates
->get_toggle(i
) == TRISTATE_TRUE
) {
974 m_updateData
.push_back( m_enabledUpdates
[ p
->m_nIndex
] );
978 m_xDialog
->response(RET_OK
);
981 IMPL_LINK_NOARG(UpdateDialog
, closeHandler
, weld::Button
&, void)
984 m_xDialog
->response(RET_CANCEL
);
987 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */