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("shared");
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
, "desktop/ui/updatedialog.ui", "UpdateDialog")
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("UPDATE_CHECKING"))
440 , m_xThrobber(m_xBuilder
->weld_spinner("THROBBER"))
441 , m_xUpdate(m_xBuilder
->weld_label("UPDATE_LABEL"))
442 , m_xUpdates(m_xBuilder
->weld_tree_view("checklist"))
443 , m_xAll(m_xBuilder
->weld_check_button("UPDATE_ALL"))
444 , m_xDescription(m_xBuilder
->weld_label("DESCRIPTION_LABEL"))
445 , m_xPublisherLabel(m_xBuilder
->weld_label("PUBLISHER_LABEL"))
446 , m_xPublisherLink(m_xBuilder
->weld_link_button("PUBLISHER_LINK"))
447 , m_xReleaseNotesLabel(m_xBuilder
->weld_label("RELEASE_NOTES_LABEL"))
448 , m_xReleaseNotesLink(m_xBuilder
->weld_link_button("RELEASE_NOTES_LINK"))
449 , m_xDescriptions(m_xBuilder
->weld_text_view("DESCRIPTIONS"))
450 , m_xOk(m_xBuilder
->weld_button("ok"))
451 , m_xClose(m_xBuilder
->weld_button("close"))
452 , m_xHelp(m_xBuilder
->weld_button("help"))
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_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 OUString("org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob"))) };
614 uno::Reference
< container::XNameAccess
> xNameAccess(
615 xConfigProvider
->createInstanceWithArguments(
616 "com.sun.star.configuration.ConfigurationAccess", aArgumentList
),
617 uno::UNO_QUERY_THROW
);
620 xNameAccess
->getByName("URL") >>= aURL
.Complete
;
622 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("updateList", rItemList
),
635 comphelper::makePropertyValue("prepareOnly", 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 uno::Sequence
< OUString
> aItem
670 dp_misc::getIdentifier( aUpdData
.aInstalledPackage
),
671 aInfoset
.getVersion()
673 aItemList
.realloc( nCount
+ 1 );
674 aItemList
.getArray()[ nCount
] = aItem
;
682 createNotifyJob( bPrepareOnly
, aItemList
);
685 // *********************************************************************************
687 void UpdateDialog::initDescription()
689 m_xPublisherLabel
->hide();
690 m_xPublisherLink
->hide();
691 m_xReleaseNotesLabel
->hide();
692 m_xReleaseNotesLink
->hide();
695 void UpdateDialog::clearDescription()
697 m_xPublisherLabel
->hide();
698 m_xPublisherLink
->hide();
699 m_xPublisherLink
->set_label("");
700 m_xPublisherLink
->set_uri("");
701 m_xReleaseNotesLabel
->hide();
702 m_xReleaseNotesLink
->hide();
703 m_xReleaseNotesLink
->set_uri( "" );
704 m_xDescriptions
->set_text("");
707 bool UpdateDialog::showDescription(uno::Reference
< xml::dom::XNode
> const & aUpdateInfo
)
709 dp_misc::DescriptionInfoset
infoset(m_context
, aUpdateInfo
);
710 return showDescription(infoset
.getLocalizedPublisherNameAndURL(),
711 infoset
.getLocalizedReleaseNotesURL());
714 bool UpdateDialog::showDescription(uno::Reference
< deployment::XPackage
> const & aExtension
)
716 OSL_ASSERT(aExtension
.is());
717 beans::StringPair pubInfo
= aExtension
->getPublisherInfo();
718 return showDescription(std::make_pair(pubInfo
.First
, pubInfo
.Second
),
722 bool UpdateDialog::showDescription(std::pair
< OUString
, OUString
> const & pairPublisher
,
723 OUString
const & sReleaseNotes
)
725 OUString sPub
= pairPublisher
.first
;
726 OUString sURL
= pairPublisher
.second
;
728 if ( sPub
.isEmpty() && sURL
.isEmpty() && sReleaseNotes
.isEmpty() )
732 if ( !sPub
.isEmpty() )
734 m_xPublisherLabel
->show();
735 m_xPublisherLink
->show();
736 m_xPublisherLink
->set_label(sPub
);
737 m_xPublisherLink
->set_uri(sURL
);
740 if ( !sReleaseNotes
.isEmpty() )
742 m_xReleaseNotesLabel
->show();
743 m_xReleaseNotesLink
->show();
744 m_xReleaseNotesLink
->set_uri( sReleaseNotes
);
749 bool UpdateDialog::showDescription( const OUString
& rDescription
)
751 if ( rDescription
.isEmpty() )
755 m_xDescriptions
->set_text(rDescription
);
759 void UpdateDialog::getIgnoredUpdates()
761 uno::Reference
< lang::XMultiServiceFactory
> xConfig(
762 configuration::theDefaultProvider::get(m_context
));
763 beans::NamedValue
aValue( "nodepath", uno::Any( OUString(IGNORED_UPDATES
) ) );
764 uno::Sequence
< uno::Any
> args
{ uno::Any(aValue
) };
766 uno::Reference
< container::XNameAccess
> xNameAccess( xConfig
->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", args
), uno::UNO_QUERY_THROW
);
767 const uno::Sequence
< OUString
> aElementNames
= xNameAccess
->getElementNames();
769 for ( OUString
const & aIdentifier
: aElementNames
)
773 uno::Any
aPropValue( uno::Reference
< beans::XPropertySet
>( xNameAccess
->getByName( aIdentifier
), uno::UNO_QUERY_THROW
)->getPropertyValue( PROPERTY_VERSION
) );
774 aPropValue
>>= aVersion
;
775 IgnoredUpdate
*pData
= new IgnoredUpdate( aIdentifier
, aVersion
);
776 m_ignoredUpdates
.emplace_back( pData
);
781 bool UpdateDialog::isIgnoredUpdate( UpdateDialog::Index
* index
)
783 bool bIsIgnored
= false;
785 if (! m_ignoredUpdates
.empty() )
787 OUString aExtensionID
;
790 if ( index
->m_eKind
== ENABLED_UPDATE
)
792 dp_gui::UpdateData aUpdData
= m_enabledUpdates
[ index
->m_nIndex
];
793 aExtensionID
= dp_misc::getIdentifier( aUpdData
.aInstalledPackage
);
794 aVersion
= aUpdData
.updateVersion
;
796 else if ( index
->m_eKind
== DISABLED_UPDATE
)
798 DisabledUpdate
&rData
= m_disabledUpdates
[ index
->m_nIndex
];
799 dp_misc::DescriptionInfoset
aInfoset( m_context
, rData
.aUpdateInfo
);
800 ::std::optional
< OUString
> aID( aInfoset
.getIdentifier() );
803 aVersion
= aInfoset
.getVersion();
806 for (auto const& ignoredUpdate
: m_ignoredUpdates
)
808 if ( ignoredUpdate
->sExtensionID
== aExtensionID
)
810 if ( ( !ignoredUpdate
->sVersion
.isEmpty() ) || ( ignoredUpdate
->sVersion
== aVersion
) )
813 index
->m_bIgnored
= true;
824 IMPL_LINK_NOARG(UpdateDialog
, selectionHandler
, weld::TreeView
&, void)
827 int nSelectedPos
= m_xUpdates
->get_selected_index();
830 const UpdateDialog::Index
* p
= nullptr;
831 if (nSelectedPos
!= -1)
832 p
= weld::fromId
<UpdateDialog::Index
const*>(m_xUpdates
->get_id(nSelectedPos
));
835 sal_uInt16 pos
= p
->m_nIndex
;
841 if ( m_enabledUpdates
[ pos
].aUpdateSource
.is() )
842 showDescription( m_enabledUpdates
[ pos
].aUpdateSource
);
844 showDescription( m_enabledUpdates
[ pos
].aUpdateInfo
);
847 b
.append( m_ignoredUpdate
);
851 case DISABLED_UPDATE
:
853 if ( !m_disabledUpdates
.empty() )
854 showDescription( m_disabledUpdates
[pos
].aUpdateInfo
);
857 b
.append( m_ignoredUpdate
);
859 if ( m_disabledUpdates
.empty() )
862 UpdateDialog::DisabledUpdate
& data
= m_disabledUpdates
[ pos
];
863 if (data
.unsatisfiedDependencies
.hasElements())
865 // create error string for version mismatch
866 OUString
sVersion( "%VERSION" );
867 OUString
sProductName( "%PRODUCTNAME" );
868 sal_Int32 nPos
= m_noDependencyCurVer
.indexOf( sVersion
);
871 m_noDependencyCurVer
= m_noDependencyCurVer
.replaceAt( nPos
, sVersion
.getLength(), utl::ConfigManager::getAboutBoxProductVersion() );
873 nPos
= m_noDependencyCurVer
.indexOf( sProductName
);
876 m_noDependencyCurVer
= m_noDependencyCurVer
.replaceAt( nPos
, sProductName
.getLength(), utl::ConfigManager::getProductName() );
878 nPos
= m_noDependency
.indexOf( sProductName
);
881 m_noDependency
= m_noDependency
.replaceAt( nPos
, sProductName
.getLength(), utl::ConfigManager::getProductName() );
884 b
.append(m_noInstall
+ OUStringChar(LF
) + m_noDependency
);
885 for (sal_Int32 i
= 0;
886 i
< data
.unsatisfiedDependencies
.getLength(); ++i
)
888 b
.append(OUStringChar(LF
) + " ");
889 // U+2003 EM SPACE would be better than two spaces,
890 // but some fonts do not contain it
893 data
.unsatisfiedDependencies
[i
]));
895 b
.append(OUStringChar(LF
) + " " + m_noDependencyCurVer
);
901 UpdateDialog::SpecificError
& data
= m_specificErrors
[ pos
];
902 b
.append(m_failure
+ OUStringChar(LF
));
903 b
.append( data
.message
.isEmpty() ? m_unknownError
: data
.message
);
913 b
.append( m_noDescription
);
915 showDescription( b
.makeStringAndClear() );
918 IMPL_LINK_NOARG(UpdateDialog
, allHandler
, weld::Toggleable
&, void)
920 if (m_xAll
->get_active())
922 m_xUpdate
->set_sensitive(true);
923 m_xUpdates
->set_sensitive(true);
924 m_xDescription
->set_sensitive(true);
925 m_xDescriptions
->set_sensitive(true);
927 for (auto const& listboxEntry
: m_ListboxEntries
)
929 if ( listboxEntry
->m_bIgnored
|| ( listboxEntry
->m_eKind
!= ENABLED_UPDATE
) )
930 insertItem(listboxEntry
.get(), false);
935 for (sal_uInt16 i
= m_xUpdates
->n_children(); i
!= 0 ;)
938 UpdateDialog::Index
const * p
= weld::fromId
<UpdateDialog::Index
const*>(m_xUpdates
->get_id(i
));
939 if ( p
->m_bIgnored
|| ( p
->m_eKind
!= ENABLED_UPDATE
) )
941 m_xUpdates
->remove(i
);
945 if (m_xUpdates
->n_children() == 0)
948 m_xUpdate
->set_sensitive(false);
949 m_xUpdates
->set_sensitive(false);
950 if (m_xChecking
->get_visible())
951 m_xDescription
->set_sensitive(false);
953 showDescription(m_noInstallable
);
958 IMPL_LINK_NOARG(UpdateDialog
, okHandler
, weld::Button
&, void)
960 //If users are going to update a shared extension then we need
962 for (auto const& enableUpdate
: m_enabledUpdates
)
964 OSL_ASSERT(enableUpdate
.aInstalledPackage
.is());
965 //If the user has no write access to the shared folder then the update
966 //for a shared extension is disable, that is it cannot be in m_enabledUpdates
970 for (sal_uInt16 i
= 0, nCount
= m_xUpdates
->n_children(); i
< nCount
; ++i
)
972 UpdateDialog::Index
const * p
=
973 weld::fromId
<UpdateDialog::Index
const*>(m_xUpdates
->get_id(i
));
974 if (p
->m_eKind
== ENABLED_UPDATE
&& m_xUpdates
->get_toggle(i
) == TRISTATE_TRUE
) {
975 m_updateData
.push_back( m_enabledUpdates
[ p
->m_nIndex
] );
979 m_xDialog
->response(RET_OK
);
982 IMPL_LINK_NOARG(UpdateDialog
, closeHandler
, weld::Button
&, void)
985 m_xDialog
->response(RET_CANCEL
);
988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */