1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_desktop.hxx"
30 
31 #include "sal/config.h"
32 
33 #include <cstddef>
34 #include <limits>
35 #include <map>
36 #include <memory>
37 #include <utility>
38 #include <vector>
39 
40 
41 #include "boost/optional.hpp"
42 #include "com/sun/star/awt/Rectangle.hpp"
43 #include "com/sun/star/awt/WindowAttribute.hpp"
44 #include "com/sun/star/awt/WindowClass.hpp"
45 #include "com/sun/star/awt/WindowDescriptor.hpp"
46 #include "com/sun/star/awt/XToolkit.hpp"
47 #include "com/sun/star/awt/XWindow.hpp"
48 #include "com/sun/star/awt/XWindowPeer.hpp"
49 #include "com/sun/star/beans/NamedValue.hpp"
50 #include "com/sun/star/beans/Optional.hpp"
51 #include "com/sun/star/beans/PropertyValue.hpp"
52 #include "com/sun/star/beans/XPropertySet.hpp"
53 #include "com/sun/star/container/XNameAccess.hpp"
54 #include "com/sun/star/container/XNameContainer.hpp"
55 #include "com/sun/star/deployment/DeploymentException.hpp"
56 #include "com/sun/star/deployment/UpdateInformationProvider.hpp"
57 #include "com/sun/star/deployment/XPackage.hpp"
58 #include "com/sun/star/deployment/XExtensionManager.hpp"
59 #include "com/sun/star/deployment/ExtensionManager.hpp"
60 #include "com/sun/star/deployment/XUpdateInformationProvider.hpp"
61 #include "com/sun/star/frame/XDesktop.hpp"
62 #include "com/sun/star/frame/XDispatch.hpp"
63 #include "com/sun/star/frame/XDispatchProvider.hpp"
64 #include "com/sun/star/lang/IllegalArgumentException.hpp"
65 #include "com/sun/star/lang/XMultiComponentFactory.hpp"
66 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
67 #include "com/sun/star/system/SystemShellExecuteFlags.hpp"
68 #include "com/sun/star/system/XSystemShellExecute.hpp"
69 #include "com/sun/star/task/XAbortChannel.hpp"
70 #include "com/sun/star/task/XJob.hpp"
71 #include "com/sun/star/ucb/CommandAbortedException.hpp"
72 #include "com/sun/star/ucb/CommandFailedException.hpp"
73 #include "com/sun/star/ucb/XCommandEnvironment.hpp"
74 #include "com/sun/star/uno/Any.hxx"
75 #include "com/sun/star/uno/Exception.hpp"
76 #include "com/sun/star/uno/Reference.hxx"
77 #include "com/sun/star/uno/RuntimeException.hpp"
78 #include "com/sun/star/uno/Sequence.hxx"
79 #include "com/sun/star/uno/XInterface.hpp"
80 #include "com/sun/star/util/URL.hpp"
81 #include "com/sun/star/util/XChangesBatch.hpp"
82 #include "com/sun/star/util/XURLTransformer.hpp"
83 #include "com/sun/star/xml/dom/XElement.hpp"
84 #include "com/sun/star/xml/dom/XNode.hpp"
85 #include "osl/diagnose.h"
86 #include "rtl/bootstrap.hxx"
87 #include "rtl/ref.hxx"
88 #include "rtl/string.h"
89 #include "rtl/ustrbuf.hxx"
90 #include "rtl/ustring.h"
91 #include "rtl/ustring.hxx"
92 #include "sal/types.h"
93 #include "svtools/svlbitm.hxx"
94 #include "svtools/svlbox.hxx"
95 #include <svtools/controldims.hrc>
96 #include "svx/checklbx.hxx"
97 #include "tools/gen.hxx"
98 #include "tools/link.hxx"
99 #include "tools/resid.hxx"
100 #include "tools/resmgr.hxx"
101 #include "tools/solar.h"
102 #include "tools/string.hxx"
103 #include "vcl/button.hxx"
104 #include "vcl/dialog.hxx"
105 #include "vcl/fixed.hxx"
106 #include "vcl/image.hxx"
107 #include "vcl/msgbox.hxx"
108 #include "vcl/svapp.hxx"
109 #include "vos/mutex.hxx"
110 
111 #include "comphelper/processfactory.hxx"
112 
113 #include "dp_dependencies.hxx"
114 #include "dp_descriptioninfoset.hxx"
115 #include "dp_identifier.hxx"
116 #include "dp_version.hxx"
117 #include "dp_misc.h"
118 #include "dp_update.hxx"
119 
120 #include "dp_gui.h"
121 #include "dp_gui.hrc"
122 #include "dp_gui_thread.hxx"
123 #include "dp_gui_updatedata.hxx"
124 #include "dp_gui_updatedialog.hxx"
125 #include "dp_gui_shared.hxx"
126 #include "dp_gui_system.hxx"
127 
128 class KeyEvent;
129 class MouseEvent;
130 class Window;
131 namespace com { namespace sun { namespace star { namespace uno {
132     class XComponentContext;
133 } } } }
134 
135 using namespace ::com::sun::star;
136 using dp_gui::UpdateDialog;
137 
138 namespace {
139 
140 static sal_Unicode const LF = 0x000A;
141 static sal_Unicode const CR = 0x000D;
142 static const sal_uInt16 CMD_ENABLE_UPDATE = 1;
143 static const sal_uInt16 CMD_IGNORE_UPDATE = 2;
144 static const sal_uInt16 CMD_IGNORE_ALL_UPDATES = 3;
145 
146 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
147 
148 #define IGNORED_UPDATES     OUSTR("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates")
149 #define PROPERTY_VERSION    OUSTR("Version")
150 
151 enum Kind { ENABLED_UPDATE, DISABLED_UPDATE, SPECIFIC_ERROR };
152 
153 rtl::OUString confineToParagraph(rtl::OUString const & text) {
154     // Confine arbitrary text to a single paragraph in a dp_gui::AutoScrollEdit.
155     // This assumes that U+000A and U+000D are the only paragraph separators in
156     // a dp_gui::AutoScrollEdit, and that replacing them with a single space
157     // each is acceptable:
158     return text.replace(LF, ' ').replace(CR, ' ');
159 }
160 }
161 
162 struct UpdateDialog::DisabledUpdate {
163     rtl::OUString name;
164     uno::Sequence< rtl::OUString > unsatisfiedDependencies;
165     // We also want to show release notes and publisher for disabled updates
166     ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > aUpdateInfo;
167     sal_uInt16 m_nID;
168 };
169 
170 struct UpdateDialog::SpecificError {
171     rtl::OUString name;
172     rtl::OUString message;
173     sal_uInt16 m_nID;
174 };
175 
176 //------------------------------------------------------------------------------
177 struct UpdateDialog::IgnoredUpdate {
178     rtl::OUString sExtensionID;
179     rtl::OUString sVersion;
180     bool          bRemoved;
181 
182     IgnoredUpdate( const rtl::OUString &rExtensionID, const rtl::OUString &rVersion );
183 };
184 
185 //------------------------------------------------------------------------------
186 UpdateDialog::IgnoredUpdate::IgnoredUpdate( const rtl::OUString &rExtensionID, const rtl::OUString &rVersion ):
187     sExtensionID( rExtensionID ),
188     sVersion( rVersion ),
189     bRemoved( false )
190 {}
191 
192 //------------------------------------------------------------------------------
193 struct UpdateDialog::Index
194 {
195     Kind          m_eKind;
196     bool          m_bIgnored;
197     sal_uInt16        m_nID;
198     sal_uInt16        m_nIndex;
199     rtl::OUString m_aName;
200 
201     Index( Kind theKind, sal_uInt16 nID, sal_uInt16 nIndex, const rtl::OUString &rName );
202 };
203 
204 //------------------------------------------------------------------------------
205 UpdateDialog::Index::Index( Kind theKind, sal_uInt16 nID, sal_uInt16 nIndex, const rtl::OUString &rName ):
206     m_eKind( theKind ),
207     m_bIgnored( false ),
208     m_nID( nID ),
209     m_nIndex( nIndex ),
210     m_aName( rName )
211 {}
212 
213 //------------------------------------------------------------------------------
214 //------------------------------------------------------------------------------
215 //------------------------------------------------------------------------------
216 class UpdateDialog::Thread: public dp_gui::Thread {
217 public:
218     Thread(
219         uno::Reference< uno::XComponentContext > const & context,
220         UpdateDialog & dialog,
221         const std::vector< uno::Reference< deployment::XPackage >  > & vExtensionList);
222 
223     void stop();
224 
225 private:
226     Thread(UpdateDialog::Thread &); // not defined
227     void operator =(UpdateDialog::Thread &); // not defined
228 
229     struct Entry {
230         explicit Entry(
231             uno::Reference< deployment::XPackage > const & thePackage,
232             rtl::OUString const & theVersion);
233 
234         uno::Reference< deployment::XPackage > package;
235         rtl::OUString version;
236         //Indicates that the extension provides its own update URLs.
237         //If this is true, then we must not use the default update
238         //URL to find the update information.
239         bool bProvidesOwnUpdate;
240         uno::Reference< xml::dom::XNode > info;
241 	    UpdateDialog::DisabledUpdate disableUpdate;
242 	    dp_gui::UpdateData updateData;
243     };
244 
245     // A multimap in case an extension is installed in "user", "shared" or "bundled"
246     typedef std::map< rtl::OUString, Entry > Map;
247 
248     virtual ~Thread();
249 
250     virtual void execute();
251 #if 0
252     void handleGeneralError(uno::Any const & exception) const;
253 #endif
254     void handleSpecificError(
255         uno::Reference< deployment::XPackage > const & package,
256         uno::Any const & exception) const;
257 
258     uno::Sequence< uno::Reference< xml::dom::XElement > >
259     getUpdateInformation(
260         uno::Reference< deployment::XPackage > const & package,
261         uno::Sequence< rtl::OUString > const & urls,
262         rtl::OUString const & identifier) const;
263 
264     void getOwnUpdateInformation(
265         uno::Reference< deployment::XPackage > const & package,
266         Map * map);
267 
268     ::rtl::OUString getUpdateDisplayString(
269         dp_gui::UpdateData const & data, ::rtl::OUString const & version = ::rtl::OUString()) const;
270 
271     void prepareUpdateData(
272         ::com::sun::star::uno::Reference< ::com::sun::star::xml::dom::XNode > const & updateInfo,
273         UpdateDialog::DisabledUpdate & out_du,
274         dp_gui::UpdateData & out_data) const;
275 
276     bool update(
277         UpdateDialog::DisabledUpdate & du,
278         dp_gui::UpdateData & data) const;
279 
280     uno::Reference< uno::XComponentContext > m_context;
281     UpdateDialog & m_dialog;
282     std::vector< uno::Reference< deployment::XPackage > > m_vExtensionList;
283     uno::Reference< deployment::XUpdateInformationProvider > m_updateInformation;
284     uno::Reference< task::XInteractionHandler > m_xInteractionHdl;
285 
286     // guarded by Application::GetSolarMutex():
287     uno::Reference< task::XAbortChannel > m_abort;
288     bool m_stop;
289 };
290 
291 UpdateDialog::Thread::Thread(
292     uno::Reference< uno::XComponentContext > const & context,
293     UpdateDialog & dialog,
294     const std::vector< uno::Reference< deployment::XPackage > > &vExtensionList):
295     m_context(context),
296     m_dialog(dialog),
297     m_vExtensionList(vExtensionList),
298     m_updateInformation(
299         deployment::UpdateInformationProvider::create(context)),
300     m_stop(false)
301 {
302     if( m_context.is() )
303     {
304         uno::Reference< lang::XMultiComponentFactory > xServiceManager( m_context->getServiceManager() );
305 
306         if( xServiceManager.is() )
307         {
308             m_xInteractionHdl = uno::Reference< task::XInteractionHandler > (
309                                 xServiceManager->createInstanceWithContext( OUSTR( "com.sun.star.task.InteractionHandler" ), m_context),
310                                 uno::UNO_QUERY );
311             if ( m_xInteractionHdl.is() )
312                 m_updateInformation->setInteractionHandler( m_xInteractionHdl );
313         }
314     }
315 }
316 
317 void UpdateDialog::Thread::stop() {
318     uno::Reference< task::XAbortChannel > abort;
319     {
320         vos::OGuard g(Application::GetSolarMutex());
321         abort = m_abort;
322         m_stop = true;
323     }
324     if (abort.is()) {
325         abort->sendAbort();
326     }
327     m_updateInformation->cancel();
328 }
329 
330 UpdateDialog::Thread::Entry::Entry(
331     uno::Reference< deployment::XPackage > const & thePackage,
332     rtl::OUString const & theVersion):
333 
334     package(thePackage),
335     version(theVersion),
336     bProvidesOwnUpdate(false),
337     updateData(thePackage)
338 {
339 }
340 
341 UpdateDialog::Thread::~Thread()
342 {
343     if ( m_xInteractionHdl.is() )
344         m_updateInformation->setInteractionHandler( uno::Reference< task::XInteractionHandler > () );
345 }
346 
347 void UpdateDialog::Thread::execute()
348 {
349     {
350         vos::OGuard g( Application::GetSolarMutex() );
351         if ( m_stop ) {
352             return;
353         }
354     }
355     uno::Reference<deployment::XExtensionManager> extMgr =
356         deployment::ExtensionManager::get(m_context);
357 
358     std::vector<std::pair<uno::Reference<deployment::XPackage>, uno::Any > > errors;
359 
360     dp_misc::UpdateInfoMap updateInfoMap = dp_misc::getOnlineUpdateInfos(
361         m_context, extMgr, m_updateInformation, &m_vExtensionList, errors);
362 
363     typedef std::vector<std::pair<uno::Reference<deployment::XPackage>,
364         uno::Any> >::const_iterator ITERROR;
365     for (ITERROR ite = errors.begin(); ite != errors.end(); ite ++)
366         handleSpecificError(ite->first, ite->second);
367 
368     for (dp_misc::UpdateInfoMap::iterator i(updateInfoMap.begin()); i != updateInfoMap.end(); i++)
369     {
370         dp_misc::UpdateInfo const & info = i->second;
371         UpdateData updateData(info.extension);
372         DisabledUpdate disableUpdate;
373         //determine if online updates meet the requirements
374         prepareUpdateData(info.info, disableUpdate, updateData);
375 
376         //determine if the update is installed in the user or shared repository
377         rtl::OUString sOnlineVersion;
378         if (info.info.is())
379             sOnlineVersion = info.version;
380         rtl::OUString sVersionUser;
381         rtl::OUString sVersionShared;
382         rtl::OUString sVersionBundled;
383         uno::Sequence< uno::Reference< deployment::XPackage> > extensions;
384         try {
385             extensions = extMgr->getExtensionsWithSameIdentifier(
386                 dp_misc::getIdentifier(info.extension), info.extension->getName(),
387                 uno::Reference<ucb::XCommandEnvironment>());
388         } catch (lang::IllegalArgumentException& ) {
389             OSL_ASSERT(0);
390             continue;
391         } catch (css::ucb::CommandFailedException& ) {
392             OSL_ASSERT(0);
393             continue;
394         }
395         OSL_ASSERT(extensions.getLength() == 3);
396         if (extensions[0].is() )
397             sVersionUser = extensions[0]->getVersion();
398         if (extensions[1].is() )
399             sVersionShared = extensions[1]->getVersion();
400         if (extensions[2].is() )
401             sVersionBundled = extensions[2]->getVersion();
402 
403         bool bSharedReadOnly = extMgr->isReadOnlyRepository(OUSTR("shared"));
404 
405         dp_misc::UPDATE_SOURCE sourceUser = dp_misc::isUpdateUserExtension(
406             bSharedReadOnly, sVersionUser, sVersionShared, sVersionBundled, sOnlineVersion);
407         dp_misc::UPDATE_SOURCE sourceShared = dp_misc::isUpdateSharedExtension(
408             bSharedReadOnly, sVersionShared, sVersionBundled, sOnlineVersion);
409 
410         uno::Reference<deployment::XPackage> updateSource;
411         if (sourceUser != dp_misc::UPDATE_SOURCE_NONE)
412         {
413             if (sourceUser == dp_misc::UPDATE_SOURCE_SHARED)
414             {
415                 updateData.aUpdateSource = extensions[1];
416                 updateData.updateVersion = extensions[1]->getVersion();
417             }
418             else if (sourceUser == dp_misc::UPDATE_SOURCE_BUNDLED)
419             {
420                 updateData.aUpdateSource = extensions[2];
421                 updateData.updateVersion = extensions[2]->getVersion();
422             }
423             if (!update(disableUpdate, updateData))
424                 return;
425         }
426 
427         if (sourceShared != dp_misc::UPDATE_SOURCE_NONE)
428         {
429 			if (sourceShared == dp_misc::UPDATE_SOURCE_BUNDLED)
430 			{
431 				updateData.aUpdateSource = extensions[2];
432 				updateData.updateVersion = extensions[2]->getVersion();
433 			}
434             updateData.bIsShared = true;
435             if (!update(disableUpdate, updateData))
436                 return;
437         }
438     }
439 
440 
441     vos::OGuard g(Application::GetSolarMutex());
442     if (!m_stop) {
443         m_dialog.checkingDone();
444     }
445 }
446 #if 0
447 void UpdateDialog::Thread::handleGeneralError(uno::Any const & exception)
448     const
449 {
450     rtl::OUString message;
451     uno::Exception e;
452     if (exception >>= e) {
453         message = e.Message;
454     }
455     vos::OGuard g(Application::GetSolarMutex());
456     if (!m_stop) {
457         m_dialog.addGeneralError(message);
458     }
459 }
460 #endif
461 //Parameter package can be null
462 void UpdateDialog::Thread::handleSpecificError(
463     uno::Reference< deployment::XPackage > const & package,
464     uno::Any const & exception) const
465 {
466     UpdateDialog::SpecificError data;
467     if (package.is())
468         data.name = package->getDisplayName();
469     uno::Exception e;
470     if (exception >>= e) {
471         data.message = e.Message;
472     }
473     vos::OGuard g(Application::GetSolarMutex());
474     if (!m_stop) {
475         m_dialog.addSpecificError(data);
476     }
477 }
478 
479 ::rtl::OUString UpdateDialog::Thread::getUpdateDisplayString(
480     dp_gui::UpdateData const & data, ::rtl::OUString const & version) const
481 {
482     OSL_ASSERT(data.aInstalledPackage.is());
483     rtl::OUStringBuffer b(data.aInstalledPackage->getDisplayName());
484     b.append(static_cast< sal_Unicode >(' '));
485     {
486         vos::OGuard g( Application::GetSolarMutex() );
487 		if(!m_stop)
488 			b.append(m_dialog.m_version);
489     }
490     b.append(static_cast< sal_Unicode >(' '));
491     if (version.getLength())
492         b.append(version);
493     else
494         b.append(data.updateVersion);
495 
496     if (data.sWebsiteURL.getLength())
497     {
498         b.append(static_cast< sal_Unicode >(' '));
499         {
500             vos::OGuard g( Application::GetSolarMutex() );
501 			if(!m_stop)
502 				b.append(m_dialog.m_browserbased);
503         }
504     }
505     return  b.makeStringAndClear();
506 }
507 
508 /** out_data will only be filled if all dependencies are ok.
509  */
510 void UpdateDialog::Thread::prepareUpdateData(
511     uno::Reference< xml::dom::XNode > const & updateInfo,
512     UpdateDialog::DisabledUpdate & out_du,
513     dp_gui::UpdateData & out_data) const
514 {
515     if (!updateInfo.is())
516         return;
517     dp_misc::DescriptionInfoset infoset(m_context, updateInfo);
518     OSL_ASSERT(infoset.getVersion().getLength() != 0);
519     uno::Sequence< uno::Reference< xml::dom::XElement > > ds(
520         dp_misc::Dependencies::check(infoset));
521 
522     out_du.aUpdateInfo = updateInfo;
523     out_du.unsatisfiedDependencies.realloc(ds.getLength());
524     for (sal_Int32 i = 0; i < ds.getLength(); ++i) {
525         out_du.unsatisfiedDependencies[i] = dp_misc::Dependencies::getErrorText(ds[i]);
526     }
527 
528     const ::boost::optional< ::rtl::OUString> updateWebsiteURL(infoset.getLocalizedUpdateWebsiteURL());
529 
530     out_du.name = getUpdateDisplayString(out_data, infoset.getVersion());
531 
532     if (out_du.unsatisfiedDependencies.getLength() == 0)
533     {
534         out_data.aUpdateInfo = updateInfo;
535         out_data.updateVersion = infoset.getVersion();
536         if (updateWebsiteURL)
537             out_data.sWebsiteURL = *updateWebsiteURL;
538     }
539 }
540 
541 bool UpdateDialog::Thread::update(
542     UpdateDialog::DisabledUpdate & du,
543     dp_gui::UpdateData & data) const
544 {
545     bool ret = false;
546     if (du.unsatisfiedDependencies.getLength() == 0)
547     {
548         vos::OGuard g(Application::GetSolarMutex());
549         if (!m_stop) {
550             m_dialog.addEnabledUpdate(getUpdateDisplayString(data), data);
551         }
552         ret = !m_stop;
553     } else {
554         vos::OGuard g(Application::GetSolarMutex());
555         if (!m_stop) {
556                 m_dialog.addDisabledUpdate(du);
557         }
558         ret = !m_stop;
559     }
560     return ret;
561 }
562 
563 // UpdateDialog ----------------------------------------------------------
564 UpdateDialog::UpdateDialog(
565     uno::Reference< uno::XComponentContext > const & context,
566     Window * parent,
567     const std::vector<uno::Reference< deployment::XPackage > > &vExtensionList,
568     std::vector< dp_gui::UpdateData > * updateData):
569     ModalDialog(parent,DpGuiResId(RID_DLG_UPDATE)),
570     m_context(context),
571     m_checking(this, DpGuiResId(RID_DLG_UPDATE_CHECKING)),
572     m_throbber(this, DpGuiResId(RID_DLG_UPDATE_THROBBER)),
573     m_update(this, DpGuiResId(RID_DLG_UPDATE_UPDATE)),
574     m_updates(
575         *this, DpGuiResId(RID_DLG_UPDATE_UPDATES),
576         Image(DpGuiResId(RID_DLG_UPDATE_NORMALALERT)),
577         Image(DpGuiResId(RID_DLG_UPDATE_HIGHCONTRASTALERT))),
578     m_all(this, DpGuiResId(RID_DLG_UPDATE_ALL)),
579     m_description(this, DpGuiResId(RID_DLG_UPDATE_DESCRIPTION)),
580     m_PublisherLabel(this, DpGuiResId(RID_DLG_UPDATE_PUBLISHER_LABEL)),
581     m_PublisherLink(this, DpGuiResId(RID_DLG_UPDATE_PUBLISHER_LINK)),
582     m_ReleaseNotesLabel(this, DpGuiResId(RID_DLG_UPDATE_RELEASENOTES_LABEL)),
583     m_ReleaseNotesLink(this, DpGuiResId(RID_DLG_UPDATE_RELEASENOTES_LINK)),
584     m_descriptions(this, DpGuiResId(RID_DLG_UPDATE_DESCRIPTIONS)),
585     m_line(this, DpGuiResId(RID_DLG_UPDATE_LINE)),
586     m_help(this, DpGuiResId(RID_DLG_UPDATE_HELP)),
587     m_ok(this, DpGuiResId(RID_DLG_UPDATE_OK)),
588     m_close(this, DpGuiResId(RID_DLG_UPDATE_CLOSE)),
589     m_error(String(DpGuiResId(RID_DLG_UPDATE_ERROR))),
590     m_none(String(DpGuiResId(RID_DLG_UPDATE_NONE))),
591     m_noInstallable(String(DpGuiResId(RID_DLG_UPDATE_NOINSTALLABLE))),
592     m_failure(String(DpGuiResId(RID_DLG_UPDATE_FAILURE))),
593     m_unknownError(String(DpGuiResId(RID_DLG_UPDATE_UNKNOWNERROR))),
594     m_noDescription(String(DpGuiResId(RID_DLG_UPDATE_NODESCRIPTION))),
595     m_noInstall(String(DpGuiResId(RID_DLG_UPDATE_NOINSTALL))),
596     m_noDependency(String(DpGuiResId(RID_DLG_UPDATE_NODEPENDENCY))),
597     m_noDependencyCurVer(String(DpGuiResId(RID_DLG_UPDATE_NODEPENDENCY_CUR_VER))),
598     m_browserbased(String(DpGuiResId(RID_DLG_UPDATE_BROWSERBASED))),
599     m_version(String(DpGuiResId(RID_DLG_UPDATE_VERSION))),
600     m_ignoredUpdate(String(DpGuiResId(RID_DLG_UPDATE_IGNORED_UPDATE))),
601     m_updateData(*updateData),
602     m_thread(
603         new UpdateDialog::Thread(
604             context, *this, vExtensionList)),
605     m_nFirstLineDelta(0),
606     m_nOneLineMissing(0),
607     m_nLastID(1),
608     m_bModified( false )
609     // TODO: check!
610 //    ,
611 //    m_extensionManagerDialog(extensionManagerDialog)
612 {
613     OSL_ASSERT(updateData != NULL);
614 
615     m_xExtensionManager = deployment::ExtensionManager::get( context );
616 
617     uno::Reference< awt::XToolkit > toolkit;
618     try {
619         toolkit = uno::Reference< awt::XToolkit >(
620             (uno::Reference< lang::XMultiComponentFactory >(
621                 m_context->getServiceManager(),
622                 uno::UNO_QUERY_THROW)->
623              createInstanceWithContext(
624                  rtl::OUString(
625                      RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.Toolkit")),
626                  m_context)),
627             uno::UNO_QUERY_THROW);
628     } catch (uno::RuntimeException &) {
629         throw;
630     } catch (uno::Exception & e) {
631         throw uno::RuntimeException(e.Message, e.Context);
632     }
633     m_updates.SetSelectHdl(LINK(this, UpdateDialog, selectionHandler));
634     m_all.SetToggleHdl(LINK(this, UpdateDialog, allHandler));
635     m_ok.SetClickHdl(LINK(this, UpdateDialog, okHandler));
636     m_close.SetClickHdl(LINK(this, UpdateDialog, closeHandler));
637     if ( ! dp_misc::office_is_running())
638         m_help.Disable();
639     FreeResource();
640 
641     initDescription();
642     getIgnoredUpdates();
643 }
644 
645 //------------------------------------------------------------------------------
646 UpdateDialog::~UpdateDialog()
647 {
648     storeIgnoredUpdates();
649 
650     for ( std::vector< UpdateDialog::Index* >::iterator i( m_ListboxEntries.begin() ); i != m_ListboxEntries.end(); ++i )
651     {
652         delete (*i);
653     }
654     for ( std::vector< UpdateDialog::IgnoredUpdate* >::iterator i( m_ignoredUpdates.begin() ); i != m_ignoredUpdates.end(); ++i )
655     {
656         delete (*i);
657     }
658 }
659 
660 //------------------------------------------------------------------------------
661 sal_Bool UpdateDialog::Close() {
662     m_thread->stop();
663     return ModalDialog::Close();
664 }
665 
666 short UpdateDialog::Execute() {
667     m_throbber.start();
668     m_thread->launch();
669     return ModalDialog::Execute();
670 }
671 
672 //------------------------------------------------------------------------------
673 //------------------------------------------------------------------------------
674 //------------------------------------------------------------------------------
675 UpdateDialog::CheckListBox::CheckListBox( UpdateDialog & dialog, ResId const & resource,
676                                           Image const & normalStaticImage,
677                                           Image const & highContrastStaticImage ):
678     SvxCheckListBox( &dialog, resource, normalStaticImage, highContrastStaticImage ),
679     m_ignoreUpdate( String( DpGuiResId( RID_DLG_UPDATE_IGNORE ) ) ),
680     m_ignoreAllUpdates( String( DpGuiResId( RID_DLG_UPDATE_IGNORE_ALL ) ) ),
681     m_enableUpdate( String( DpGuiResId( RID_DLG_UPDATE_ENABLE ) ) ),
682     m_dialog(dialog)
683 {}
684 
685 //------------------------------------------------------------------------------
686 UpdateDialog::CheckListBox::~CheckListBox() {}
687 
688 //------------------------------------------------------------------------------
689 sal_uInt16 UpdateDialog::CheckListBox::getItemCount() const {
690     sal_uLong i = GetEntryCount();
691     OSL_ASSERT(i <= std::numeric_limits< sal_uInt16 >::max());
692     return sal::static_int_cast< sal_uInt16 >(i);
693 }
694 
695 //------------------------------------------------------------------------------
696 void UpdateDialog::CheckListBox::MouseButtonDown( MouseEvent const & event )
697 {
698     // When clicking on a selected entry in an SvxCheckListBox, the entry's
699     // checkbox is toggled on mouse button down:
700     SvxCheckListBox::MouseButtonDown( event );
701 
702     if ( event.IsRight() )
703     {
704         handlePopupMenu( event.GetPosPixel() );
705     }
706 
707     m_dialog.enableOk();
708 }
709 
710 //------------------------------------------------------------------------------
711 void UpdateDialog::CheckListBox::MouseButtonUp(MouseEvent const & event) {
712     // When clicking on an entry's checkbox in an SvxCheckListBox, the entry's
713     // checkbox is toggled on mouse button up:
714     SvxCheckListBox::MouseButtonUp(event);
715     m_dialog.enableOk();
716 }
717 
718 void UpdateDialog::CheckListBox::KeyInput(KeyEvent const & event) {
719     SvxCheckListBox::KeyInput(event);
720     m_dialog.enableOk();
721 }
722 
723 //------------------------------------------------------------------------------
724 void UpdateDialog::CheckListBox::handlePopupMenu( const Point &rPos )
725 {
726     SvListEntry *pData = GetEntry( rPos );
727 
728     if ( pData )
729     {
730         sal_uInt16 nEntryPos = GetSelectEntryPos();
731         UpdateDialog::Index * p = static_cast< UpdateDialog::Index * >( GetEntryData( nEntryPos ) );
732 
733         if ( ( p->m_eKind == ENABLED_UPDATE ) || ( p->m_eKind == DISABLED_UPDATE ) )
734         {
735             PopupMenu aPopup;
736 
737             if ( p->m_bIgnored )
738                 aPopup.InsertItem( CMD_ENABLE_UPDATE, m_enableUpdate );
739             else
740             {
741                 aPopup.InsertItem( CMD_IGNORE_UPDATE, m_ignoreUpdate );
742                 aPopup.InsertItem( CMD_IGNORE_ALL_UPDATES, m_ignoreAllUpdates );
743             }
744 
745             sal_uInt16 aCmd = aPopup.Execute( this, rPos );
746             if ( ( aCmd == CMD_IGNORE_UPDATE ) || ( aCmd == CMD_IGNORE_ALL_UPDATES ) )
747             {
748                 p->m_bIgnored = true;
749                 if ( p->m_eKind == ENABLED_UPDATE )
750                 {
751                     RemoveEntry( nEntryPos );
752                     m_dialog.addAdditional( p, SvLBoxButtonKind_disabledCheckbox );
753                 }
754                 if ( aCmd == CMD_IGNORE_UPDATE )
755                     m_dialog.setIgnoredUpdate( p, true, false );
756                 else
757                     m_dialog.setIgnoredUpdate( p, true, true );
758                 // TODO: reselect entry to display new description!
759             }
760             else if ( aCmd == CMD_ENABLE_UPDATE )
761             {
762                 p->m_bIgnored = false;
763                 if ( p->m_eKind == ENABLED_UPDATE )
764                 {
765                     RemoveEntry( nEntryPos );
766                     m_dialog.insertItem( p, SvLBoxButtonKind_enabledCheckbox );
767                 }
768                 m_dialog.setIgnoredUpdate( p, false, false );
769             }
770         }
771     }
772 }
773 
774 //------------------------------------------------------------------------------
775 //------------------------------------------------------------------------------
776 //------------------------------------------------------------------------------
777 sal_uInt16 UpdateDialog::insertItem( UpdateDialog::Index *pEntry, SvLBoxButtonKind kind )
778 {
779     m_updates.InsertEntry( pEntry->m_aName, LISTBOX_APPEND, static_cast< void * >( pEntry ), kind );
780 
781     for ( sal_uInt16 i = m_updates.getItemCount(); i != 0 ; )
782     {
783         i -= 1;
784         UpdateDialog::Index const * p = static_cast< UpdateDialog::Index const * >( m_updates.GetEntryData( i ) );
785         if ( p == pEntry )
786             return i;
787     }
788     OSL_ASSERT(0);
789     return 0;
790 }
791 
792 //------------------------------------------------------------------------------
793 void UpdateDialog::addAdditional( UpdateDialog::Index * index, SvLBoxButtonKind kind )
794 {
795     m_all.Enable();
796     if (m_all.IsChecked())
797     {
798         insertItem( index, kind );
799         m_update.Enable();
800         m_updates.Enable();
801         m_description.Enable();
802         m_descriptions.Enable();
803     }
804 }
805 
806 //------------------------------------------------------------------------------
807 void UpdateDialog::addEnabledUpdate( rtl::OUString const & name,
808                                      dp_gui::UpdateData & data )
809 {
810     sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_enabledUpdates.size() );
811     UpdateDialog::Index *pEntry = new UpdateDialog::Index( ENABLED_UPDATE, m_nLastID, nIndex, name );
812 
813     data.m_nID = m_nLastID;
814     m_nLastID += 1;
815 
816     m_enabledUpdates.push_back( data );
817     m_ListboxEntries.push_back( pEntry );
818 
819     if ( ! isIgnoredUpdate( pEntry ) )
820     {
821         sal_uInt16 nPos = insertItem( pEntry, SvLBoxButtonKind_enabledCheckbox );
822         m_updates.CheckEntryPos( nPos );
823     }
824     else
825         addAdditional( pEntry, SvLBoxButtonKind_disabledCheckbox );
826 
827     m_update.Enable();
828     m_updates.Enable();
829     m_description.Enable();
830     m_descriptions.Enable();
831 }
832 
833 //------------------------------------------------------------------------------
834 void UpdateDialog::addDisabledUpdate( UpdateDialog::DisabledUpdate & data )
835 {
836     sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_disabledUpdates.size() );
837     UpdateDialog::Index *pEntry = new UpdateDialog::Index( DISABLED_UPDATE, m_nLastID, nIndex, data.name );
838 
839     data.m_nID = m_nLastID;
840     m_nLastID += 1;
841 
842     m_disabledUpdates.push_back( data );
843     m_ListboxEntries.push_back( pEntry );
844 
845     isIgnoredUpdate( pEntry );
846     addAdditional( pEntry, SvLBoxButtonKind_disabledCheckbox );
847 }
848 
849 //------------------------------------------------------------------------------
850 void UpdateDialog::addSpecificError( UpdateDialog::SpecificError & data )
851 {
852     sal_uInt16 nIndex = sal::static_int_cast< sal_uInt16 >( m_specificErrors.size() );
853     UpdateDialog::Index *pEntry = new UpdateDialog::Index( DISABLED_UPDATE, m_nLastID, nIndex, data.name );
854 
855     data.m_nID = m_nLastID;
856     m_nLastID += 1;
857 
858     m_specificErrors.push_back( data );
859     m_ListboxEntries.push_back( pEntry );
860 
861     addAdditional( pEntry, SvLBoxButtonKind_staticImage);
862 }
863 
864 void UpdateDialog::checkingDone() {
865     m_checking.Hide();
866     m_throbber.stop();
867     m_throbber.Hide();
868     if (m_updates.getItemCount() == 0)
869     {
870         clearDescription();
871         m_description.Enable();
872         m_descriptions.Enable();
873 
874         if ( m_disabledUpdates.empty() && m_specificErrors.empty() && m_ignoredUpdates.empty() )
875             showDescription( m_none, false );
876         else
877             showDescription( m_noInstallable, false );
878     }
879 
880     enableOk();
881 }
882 
883 void UpdateDialog::enableOk() {
884     if (!m_checking.IsVisible()) {
885         m_ok.Enable(m_updates.GetCheckedEntryCount() != 0);
886     }
887 }
888 
889 // *********************************************************************************
890 void UpdateDialog::createNotifyJob( bool bPrepareOnly,
891     uno::Sequence< uno::Sequence< rtl::OUString > > &rItemList )
892 {
893     if ( !dp_misc::office_is_running() )
894         return;
895 
896     // notify update check job
897     try
898     {
899         uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
900         uno::Reference< lang::XMultiServiceFactory > xConfigProvider(
901             xFactory->createInstance( OUSTR( "com.sun.star.configuration.ConfigurationProvider" )),
902             uno::UNO_QUERY_THROW);
903 
904         beans::PropertyValue aProperty;
905         aProperty.Name  = OUSTR( "nodepath" );
906         aProperty.Value = uno::makeAny( OUSTR("org.openoffice.Office.Addons/AddonUI/OfficeHelp/UpdateCheckJob") );
907 
908         uno::Sequence< uno::Any > aArgumentList( 1 );
909         aArgumentList[0] = uno::makeAny( aProperty );
910 
911         uno::Reference< container::XNameAccess > xNameAccess(
912             xConfigProvider->createInstanceWithArguments(
913                 OUSTR("com.sun.star.configuration.ConfigurationAccess"), aArgumentList ),
914             uno::UNO_QUERY_THROW );
915 
916         util::URL aURL;
917         xNameAccess->getByName(OUSTR("URL")) >>= aURL.Complete;
918 
919         uno::Reference < util::XURLTransformer > xTransformer( xFactory->createInstance( OUSTR( "com.sun.star.util.URLTransformer" ) ),
920             uno::UNO_QUERY_THROW );
921 
922         xTransformer->parseStrict(aURL);
923 
924         uno::Reference < frame::XDesktop > xDesktop( xFactory->createInstance( OUSTR( "com.sun.star.frame.Desktop" ) ),
925             uno::UNO_QUERY_THROW );
926         uno::Reference< frame::XDispatchProvider > xDispatchProvider( xDesktop->getCurrentFrame(),
927             uno::UNO_QUERY_THROW );
928         uno::Reference< frame::XDispatch > xDispatch = xDispatchProvider->queryDispatch(aURL, rtl::OUString(), 0);
929 
930         if( xDispatch.is() )
931         {
932             uno::Sequence< beans::PropertyValue > aPropList(2);
933             aProperty.Name  = OUSTR( "updateList" );
934             aProperty.Value = uno::makeAny( rItemList );
935             aPropList[0] = aProperty;
936             aProperty.Name  = OUSTR( "prepareOnly" );
937             aProperty.Value = uno::makeAny( bPrepareOnly );
938             aPropList[1] = aProperty;
939 
940             xDispatch->dispatch(aURL, aPropList );
941         }
942     }
943     catch( const uno::Exception& e )
944     {
945         dp_misc::TRACE( OUSTR("Caught exception: ")
946             + e.Message + OUSTR("\n thread terminated.\n\n"));
947     }
948 }
949 
950 // *********************************************************************************
951 void UpdateDialog::notifyMenubar( bool bPrepareOnly, bool bRecheckOnly )
952 {
953     if ( !dp_misc::office_is_running() )
954         return;
955 
956     uno::Sequence< uno::Sequence< rtl::OUString > > aItemList;
957     sal_Int32 nCount = 0;
958 
959     if ( ! bRecheckOnly )
960     {
961         for ( sal_Int16 i = 0; i < m_updates.getItemCount(); ++i )
962         {
963             uno::Sequence< rtl::OUString > aItem(2);
964 
965             UpdateDialog::Index const * p = static_cast< UpdateDialog::Index const * >(m_updates.GetEntryData(i));
966 
967             if ( p->m_eKind == ENABLED_UPDATE )
968             {
969                 dp_gui::UpdateData aUpdData = m_enabledUpdates[ p->m_nIndex ];
970                 aItem[0] = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
971 
972                 dp_misc::DescriptionInfoset aInfoset( m_context, aUpdData.aUpdateInfo );
973                 aItem[1] = aInfoset.getVersion();
974             }
975             else if ( p->m_eKind == DISABLED_UPDATE )
976                 continue;
977             else
978                 continue;
979 
980             aItemList.realloc( nCount + 1 );
981             aItemList[ nCount ] = aItem;
982             nCount += 1;
983         }
984     }
985 
986     storeIgnoredUpdates();
987     createNotifyJob( bPrepareOnly, aItemList );
988 }
989 
990 // *********************************************************************************
991 
992 void UpdateDialog::initDescription()
993 {
994     m_PublisherLabel.Hide();
995     m_PublisherLink.Hide();
996     m_ReleaseNotesLabel.Hide();
997     m_ReleaseNotesLink.Hide();
998     m_descriptions.Hide();
999 
1000     Link aLink = LINK( this, UpdateDialog, hyperlink_clicked );
1001     m_PublisherLink.SetClickHdl( aLink );
1002     m_ReleaseNotesLink.SetClickHdl( aLink );
1003 
1004     long nTextWidth = m_PublisherLabel.GetCtrlTextWidth( m_PublisherLabel.GetText() );
1005     long nTemp = m_ReleaseNotesLabel.GetTextWidth( m_ReleaseNotesLabel.GetText() );
1006     if ( nTemp > nTextWidth )
1007         nTextWidth = nTemp;
1008     nTextWidth = nTextWidth * 110 / 100;
1009 
1010     Size aNewSize = m_PublisherLabel.GetSizePixel();
1011     if ( nTextWidth > aNewSize.Width() )
1012     {
1013         long nDelta = nTextWidth - aNewSize.Width();
1014         aNewSize.Width() = nTextWidth;
1015         m_PublisherLabel.SetSizePixel( aNewSize );
1016         m_ReleaseNotesLabel.SetSizePixel( aNewSize );
1017 
1018         aNewSize = m_PublisherLink.GetSizePixel();
1019         aNewSize.Width() = aNewSize.Width() - nDelta;
1020         Point aNewPos = m_PublisherLink.GetPosPixel();
1021         aNewPos.X() = aNewPos.X() + nDelta;
1022         m_PublisherLink.SetPosSizePixel( aNewPos, aNewSize );
1023         aNewPos.Y() = m_ReleaseNotesLink.GetPosPixel().Y();
1024         m_ReleaseNotesLink.SetPosSizePixel( aNewPos, aNewSize );
1025     }
1026 
1027     m_aFirstLinePos = m_descriptions.GetPosPixel();
1028     m_aFirstLineSize = m_descriptions.GetSizePixel();
1029     Size aMarginSize = LogicToPixel( Size( RSC_SP_CTRL_GROUP_X, RSC_SP_CTRL_GROUP_Y ), MAP_APPFONT );
1030     Point aThirdLinePos = m_ReleaseNotesLabel.GetPosPixel();
1031     aThirdLinePos.Y() = aThirdLinePos.Y() + m_ReleaseNotesLabel.GetSizePixel().Height() + aMarginSize.Height();
1032     m_nFirstLineDelta = aThirdLinePos.Y() - m_aFirstLinePos.Y();
1033     m_nOneLineMissing = m_ReleaseNotesLabel.GetPosPixel().Y() - m_PublisherLabel.GetPosPixel().Y();
1034 }
1035 
1036 void UpdateDialog::clearDescription()
1037 {
1038     String sEmpty;
1039     m_PublisherLabel.Hide();
1040     m_PublisherLink.Hide();
1041     m_PublisherLink.SetDescription( sEmpty );
1042     m_PublisherLink.SetURL( sEmpty );
1043     m_ReleaseNotesLabel.Hide();
1044     m_ReleaseNotesLink.Hide();
1045     m_ReleaseNotesLink.SetURL( sEmpty );
1046     if ( m_PublisherLabel.GetPosPixel().Y() == m_ReleaseNotesLabel.GetPosPixel().Y() )
1047     {
1048         Point aNewPos = m_ReleaseNotesLabel.GetPosPixel();
1049         aNewPos.Y() += m_nOneLineMissing;
1050         m_ReleaseNotesLabel.SetPosPixel( aNewPos );
1051         aNewPos = m_ReleaseNotesLink.GetPosPixel();
1052         aNewPos.Y() += m_nOneLineMissing;
1053         m_ReleaseNotesLink.SetPosPixel( aNewPos );
1054     }
1055     m_descriptions.Hide();
1056     m_descriptions.Clear();
1057     m_descriptions.SetPosSizePixel( m_aFirstLinePos, m_aFirstLineSize );
1058 }
1059 
1060 bool UpdateDialog::showDescription(uno::Reference< xml::dom::XNode > const & aUpdateInfo)
1061 {
1062     dp_misc::DescriptionInfoset infoset(m_context, aUpdateInfo);
1063     return showDescription(infoset.getLocalizedPublisherNameAndURL(),
1064                            infoset.getLocalizedReleaseNotesURL());
1065 }
1066 
1067 bool UpdateDialog::showDescription(uno::Reference< deployment::XPackage > const & aExtension)
1068 {
1069     OSL_ASSERT(aExtension.is());
1070     beans::StringPair pubInfo = aExtension->getPublisherInfo();
1071     return showDescription(std::make_pair(pubInfo.First, pubInfo.Second),
1072                            OUSTR(""));
1073 }
1074 
1075 bool UpdateDialog::showDescription(std::pair< rtl::OUString, rtl::OUString > const & pairPublisher,
1076                                    rtl::OUString const & sReleaseNotes)
1077 {
1078     rtl::OUString sPub = pairPublisher.first;
1079     rtl::OUString sURL = pairPublisher.second;
1080 
1081     if ( sPub.getLength() == 0 && sURL.getLength() == 0 && sReleaseNotes.getLength() == 0 )
1082         // nothing to show
1083         return false;
1084 
1085     bool bPublisher = false;
1086     if ( sPub.getLength() > 0 )
1087     {
1088         m_PublisherLabel.Show();
1089         m_PublisherLink.Show();
1090         m_PublisherLink.SetDescription( sPub );
1091         m_PublisherLink.SetURL( sURL );
1092         bPublisher = true;
1093     }
1094 
1095     if ( sReleaseNotes.getLength() > 0 )
1096     {
1097         if ( !bPublisher )
1098         {
1099             m_ReleaseNotesLabel.SetPosPixel( m_PublisherLabel.GetPosPixel() );
1100             m_ReleaseNotesLink.SetPosPixel( m_PublisherLink.GetPosPixel() );
1101         }
1102         m_ReleaseNotesLabel.Show();
1103         m_ReleaseNotesLink.Show();
1104         m_ReleaseNotesLink.SetURL( sReleaseNotes );
1105     }
1106     return true;
1107 }
1108 
1109 bool UpdateDialog::showDescription( const String& rDescription, bool bWithPublisher )
1110 {
1111     if ( rDescription.Len() == 0 )
1112         // nothing to show
1113         return false;
1114 
1115     if ( bWithPublisher )
1116     {
1117         bool bOneLineMissing = !m_ReleaseNotesLabel.IsVisible() || !m_PublisherLabel.IsVisible();
1118         Point aNewPos = m_aFirstLinePos;
1119         aNewPos.Y() += m_nFirstLineDelta;
1120         if ( bOneLineMissing )
1121             aNewPos.Y() -= m_nOneLineMissing;
1122         Size aNewSize = m_aFirstLineSize;
1123         aNewSize.Height() -= m_nFirstLineDelta;
1124         if ( bOneLineMissing )
1125             aNewSize.Height() += m_nOneLineMissing;
1126         m_descriptions.SetPosSizePixel( aNewPos, aNewSize );
1127     }
1128     m_descriptions.Show();
1129     m_descriptions.SetDescription( rDescription );
1130     return true;
1131 }
1132 
1133 bool UpdateDialog::isReadOnly( const uno::Reference< deployment::XPackage > &xPackage ) const
1134 {
1135     if ( m_xExtensionManager.is() && xPackage.is() )
1136     {
1137         return m_xExtensionManager->isReadOnlyRepository( xPackage->getRepositoryName() );
1138     }
1139     else
1140         return true;
1141 }
1142 
1143 //------------------------------------------------------------------------------
1144 void UpdateDialog::getIgnoredUpdates()
1145 {
1146     uno::Reference< lang::XMultiServiceFactory > xConfig( m_context->getServiceManager()->createInstanceWithContext(
1147         OUSTR("com.sun.star.configuration.ConfigurationProvider"), m_context ), uno::UNO_QUERY_THROW);
1148     beans::NamedValue aValue( OUSTR("nodepath"), uno::Any( IGNORED_UPDATES ) );
1149     uno::Sequence< uno::Any > args(1);
1150     args[0] <<= aValue;
1151 
1152     uno::Reference< container::XNameAccess > xNameAccess( xConfig->createInstanceWithArguments( OUSTR("com.sun.star.configuration.ConfigurationAccess"), args), uno::UNO_QUERY_THROW );
1153     uno::Sequence< rtl::OUString > aElementNames = xNameAccess->getElementNames();
1154 
1155     for ( sal_Int32 i = 0; i < aElementNames.getLength(); i++ )
1156     {
1157         ::rtl::OUString aIdentifier = aElementNames[i];
1158         ::rtl::OUString aVersion;
1159 
1160         uno::Any aPropValue( uno::Reference< beans::XPropertySet >( xNameAccess->getByName( aIdentifier ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) );
1161         aPropValue >>= aVersion;
1162         IgnoredUpdate *pData = new IgnoredUpdate( aIdentifier, aVersion );
1163         m_ignoredUpdates.push_back( pData );
1164     }
1165 }
1166 
1167 //------------------------------------------------------------------------------
1168 void UpdateDialog::storeIgnoredUpdates()
1169 {
1170     if ( m_bModified && ( m_ignoredUpdates.size() != 0 ) )
1171     {
1172         uno::Reference< lang::XMultiServiceFactory > xConfig( m_context->getServiceManager()->createInstanceWithContext(
1173             OUSTR("com.sun.star.configuration.ConfigurationProvider"), m_context ), uno::UNO_QUERY_THROW );
1174         beans::NamedValue aValue( OUSTR("nodepath"), uno::Any( IGNORED_UPDATES ) );
1175         uno::Sequence< uno::Any > args(1);
1176         args[0] <<= aValue;
1177 
1178         uno::Reference< container::XNameContainer > xNameContainer( xConfig->createInstanceWithArguments(
1179             OUSTR("com.sun.star.configuration.ConfigurationUpdateAccess"), args ), uno::UNO_QUERY_THROW );
1180 
1181         for ( std::vector< UpdateDialog::IgnoredUpdate* >::iterator i( m_ignoredUpdates.begin() ); i != m_ignoredUpdates.end(); ++i )
1182         {
1183             if ( xNameContainer->hasByName( (*i)->sExtensionID ) )
1184             {
1185                 if ( (*i)->bRemoved )
1186                     xNameContainer->removeByName( (*i)->sExtensionID );
1187                 else
1188                     uno::Reference< beans::XPropertySet >( xNameContainer->getByName( (*i)->sExtensionID ), uno::UNO_QUERY_THROW )->setPropertyValue( PROPERTY_VERSION, uno::Any( (*i)->sVersion ) );
1189             }
1190             else if ( ! (*i)->bRemoved )
1191             {
1192                 uno::Reference< beans::XPropertySet > elem( uno::Reference< lang::XSingleServiceFactory >( xNameContainer, uno::UNO_QUERY_THROW )->createInstance(), uno::UNO_QUERY_THROW );
1193                 elem->setPropertyValue( PROPERTY_VERSION, uno::Any( (*i)->sVersion ) );
1194                 xNameContainer->insertByName( (*i)->sExtensionID, uno::Any( elem ) );
1195             }
1196         }
1197 
1198         uno::Reference< util::XChangesBatch > xChangesBatch( xNameContainer, uno::UNO_QUERY );
1199         if ( xChangesBatch.is() && xChangesBatch->hasPendingChanges() )
1200             xChangesBatch->commitChanges();
1201     }
1202 
1203     m_bModified = false;
1204 }
1205 
1206 //------------------------------------------------------------------------------
1207 bool UpdateDialog::isIgnoredUpdate( UpdateDialog::Index * index )
1208 {
1209     bool bIsIgnored = false;
1210 
1211     if ( m_ignoredUpdates.size() != 0 )
1212     {
1213         rtl::OUString aExtensionID;
1214         rtl::OUString aVersion;
1215 
1216         if ( index->m_eKind == ENABLED_UPDATE )
1217         {
1218             dp_gui::UpdateData aUpdData = m_enabledUpdates[ index->m_nIndex ];
1219             aExtensionID = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
1220             aVersion = aUpdData.updateVersion;
1221         }
1222         else if ( index->m_eKind == DISABLED_UPDATE )
1223         {
1224             DisabledUpdate &rData = m_disabledUpdates[ index->m_nIndex ];
1225             dp_misc::DescriptionInfoset aInfoset( m_context, rData.aUpdateInfo );
1226             ::boost::optional< ::rtl::OUString > aID( aInfoset.getIdentifier() );
1227             if ( aID )
1228                 aExtensionID = *aID;
1229             aVersion = aInfoset.getVersion();
1230         }
1231 
1232         for ( std::vector< UpdateDialog::IgnoredUpdate* >::iterator i( m_ignoredUpdates.begin() ); i != m_ignoredUpdates.end(); ++i )
1233         {
1234             if ( (*i)->sExtensionID == aExtensionID )
1235             {
1236                 if ( ( (*i)->sVersion.getLength() == 0 ) || ( (*i)->sVersion == aVersion ) )
1237                 {
1238                     bIsIgnored = true;
1239                     index->m_bIgnored = true;
1240                 }
1241                 else // when we find another update of an ignored version, we will remove the old one to keep the ignored list small
1242                     (*i)->bRemoved = true;
1243                 break;
1244             }
1245         }
1246     }
1247 
1248     return bIsIgnored;
1249 }
1250 
1251 //------------------------------------------------------------------------------
1252 void UpdateDialog::setIgnoredUpdate( UpdateDialog::Index *pIndex, bool bIgnore, bool bIgnoreAll )
1253 {
1254     rtl::OUString aExtensionID;
1255     rtl::OUString aVersion;
1256 
1257     m_bModified = true;
1258 
1259     if ( pIndex->m_eKind == ENABLED_UPDATE )
1260     {
1261         dp_gui::UpdateData aUpdData = m_enabledUpdates[ pIndex->m_nIndex ];
1262         aExtensionID = dp_misc::getIdentifier( aUpdData.aInstalledPackage );
1263         if ( !bIgnoreAll )
1264             aVersion = aUpdData.updateVersion;
1265     }
1266     else if ( pIndex->m_eKind == DISABLED_UPDATE )
1267     {
1268         DisabledUpdate &rData = m_disabledUpdates[ pIndex->m_nIndex ];
1269         dp_misc::DescriptionInfoset aInfoset( m_context, rData.aUpdateInfo );
1270         ::boost::optional< ::rtl::OUString > aID( aInfoset.getIdentifier() );
1271         if ( aID )
1272             aExtensionID = *aID;
1273         if ( !bIgnoreAll )
1274             aVersion = aInfoset.getVersion();
1275     }
1276 
1277     if ( aExtensionID.getLength() )
1278     {
1279         bool bFound = false;
1280         for ( std::vector< UpdateDialog::IgnoredUpdate* >::iterator i( m_ignoredUpdates.begin() ); i != m_ignoredUpdates.end(); ++i )
1281         {
1282             if ( (*i)->sExtensionID == aExtensionID )
1283             {
1284                 (*i)->sVersion = aVersion;
1285                 (*i)->bRemoved = !bIgnore;
1286                 bFound = true;
1287                 break;
1288             }
1289         }
1290         if ( bIgnore && !bFound )
1291         {
1292             IgnoredUpdate *pData = new IgnoredUpdate( aExtensionID, aVersion );
1293             m_ignoredUpdates.push_back( pData );
1294         }
1295     }
1296 }
1297 
1298 //------------------------------------------------------------------------------
1299 IMPL_LINK(UpdateDialog, selectionHandler, void *, EMPTYARG)
1300 {
1301     rtl::OUStringBuffer b;
1302     bool bInserted = false;
1303     UpdateDialog::Index const * p = static_cast< UpdateDialog::Index const * >(
1304         m_updates.GetEntryData(m_updates.GetSelectEntryPos()));
1305     clearDescription();
1306 
1307     if ( p != NULL )
1308     {
1309         sal_uInt16 pos = p->m_nIndex;
1310 
1311         switch (p->m_eKind)
1312         {
1313             case ENABLED_UPDATE:
1314             {
1315                 if ( m_enabledUpdates[ pos ].aUpdateSource.is() )
1316                     bInserted = showDescription( m_enabledUpdates[ pos ].aUpdateSource );
1317                 else
1318                     bInserted = showDescription( m_enabledUpdates[ pos ].aUpdateInfo );
1319 
1320                 if ( p->m_bIgnored )
1321                     b.append( m_ignoredUpdate );
1322 
1323                 break;
1324             }
1325             case DISABLED_UPDATE:
1326             {
1327                 bInserted = showDescription( m_disabledUpdates[pos].aUpdateInfo );
1328 
1329                 if ( p->m_bIgnored )
1330                     b.append( m_ignoredUpdate );
1331 
1332                 UpdateDialog::DisabledUpdate & data = m_disabledUpdates[ pos ];
1333                 if (data.unsatisfiedDependencies.getLength() != 0)
1334                 {
1335                     // create error string for version mismatch
1336                     ::rtl::OUString sVersion( RTL_CONSTASCII_USTRINGPARAM("%VERSION") );
1337                     sal_Int32 nPos = m_noDependencyCurVer.indexOf( sVersion );
1338                     if ( nPos >= 0 )
1339                     {
1340                         ::rtl::OUString sCurVersion( RTL_CONSTASCII_USTRINGPARAM( "${$OOO_BASE_DIR/program/" SAL_CONFIGFILE("version") ":Version:OOOPackageVersion}"));
1341                         ::rtl::Bootstrap::expandMacros(sCurVersion);
1342                         m_noDependencyCurVer = m_noDependencyCurVer.replaceAt( nPos, sVersion.getLength(), sCurVersion );
1343                     }
1344 
1345                     b.append(m_noInstall);
1346                     b.append(LF);
1347                     b.append(m_noDependency);
1348                     for (sal_Int32 i = 0;
1349                          i < data.unsatisfiedDependencies.getLength(); ++i)
1350                     {
1351                         b.append(LF);
1352                         b.appendAscii(RTL_CONSTASCII_STRINGPARAM("  "));
1353                             // U+2003 EM SPACE would be better than two spaces,
1354                             // but some fonts do not contain it
1355                         b.append(
1356                             confineToParagraph(
1357                                 data.unsatisfiedDependencies[i]));
1358                     }
1359                     b.append(LF);
1360                     b.appendAscii(RTL_CONSTASCII_STRINGPARAM("  "));
1361                     b.append(m_noDependencyCurVer);
1362                 }
1363                 break;
1364             }
1365             case SPECIFIC_ERROR:
1366             {
1367                 UpdateDialog::SpecificError & data = m_specificErrors[ pos ];
1368                 b.append(m_failure);
1369                 b.append(LF);
1370                 b.append( data.message.getLength() == 0 ? m_unknownError : data.message );
1371                 break;
1372             }
1373             default:
1374                 OSL_ASSERT(false);
1375                 break;
1376         }
1377     }
1378 
1379     if ( b.getLength() == 0 )
1380         b.append( m_noDescription );
1381 
1382     showDescription( b.makeStringAndClear(), bInserted );
1383     return 0;
1384 }
1385 
1386 IMPL_LINK(UpdateDialog, allHandler, void *, EMPTYARG)
1387 {
1388     if (m_all.IsChecked())
1389     {
1390         m_update.Enable();
1391         m_updates.Enable();
1392         m_description.Enable();
1393         m_descriptions.Enable();
1394 
1395         for (std::vector< UpdateDialog::Index* >::iterator i( m_ListboxEntries.begin() );
1396              i != m_ListboxEntries.end(); ++i )
1397         {
1398             if ( (*i)->m_bIgnored || ( (*i)->m_eKind != ENABLED_UPDATE ) )
1399                 insertItem( (*i), SvLBoxButtonKind_disabledCheckbox );
1400         }
1401     }
1402     else
1403     {
1404         for ( sal_uInt16 i = 0; i < m_updates.getItemCount(); )
1405         {
1406             UpdateDialog::Index const * p = static_cast< UpdateDialog::Index const * >( m_updates.GetEntryData(i) );
1407             if ( p->m_bIgnored || ( p->m_eKind != ENABLED_UPDATE ) )
1408             {
1409                 m_updates.RemoveEntry(i);
1410             } else {
1411                 ++i;
1412             }
1413         }
1414 
1415         if (m_updates.getItemCount() == 0)
1416         {
1417             clearDescription();
1418             m_update.Disable();
1419             m_updates.Disable();
1420             if (m_checking.IsVisible())
1421                 m_description.Disable();
1422             else
1423                 showDescription(m_noInstallable,false);
1424         }
1425     }
1426     return 0;
1427 }
1428 
1429 IMPL_LINK(UpdateDialog, okHandler, void *, EMPTYARG)
1430 {
1431     //If users are going to update a shared extension then we need
1432     //to warn them
1433     typedef ::std::vector<UpdateData>::const_iterator CIT;
1434     for (CIT i = m_enabledUpdates.begin(); i < m_enabledUpdates.end(); i++)
1435     {
1436         OSL_ASSERT(i->aInstalledPackage.is());
1437         //If the user has no write access to the shared folder then the update
1438         //for a shared extension is disable, that is it cannot be in m_enabledUpdates
1439 //        OSL_ASSERT(isReadOnly(i->aInstalledPackage) == sal_False);
1440 #if 0
1441         // TODO: check!
1442         OSL_ASSERT(m_extensionManagerDialog.get());
1443         if (RET_CANCEL == m_extensionManagerDialog->continueUpdateForSharedExtension(
1444             this, i->aPackageManager))
1445         {
1446             EndDialog(RET_CANCEL);
1447         }
1448 #endif
1449     }
1450 
1451 
1452     for (sal_uInt16 i = 0; i < m_updates.getItemCount(); ++i) {
1453         UpdateDialog::Index const * p =
1454             static_cast< UpdateDialog::Index const * >(
1455                 m_updates.GetEntryData(i));
1456         if (p->m_eKind == ENABLED_UPDATE && m_updates.IsChecked(i)) {
1457             m_updateData.push_back( m_enabledUpdates[ p->m_nIndex ] );
1458         }
1459     }
1460 
1461     EndDialog(RET_OK);
1462     return 0;
1463 }
1464 
1465 IMPL_LINK(UpdateDialog, closeHandler, void *, EMPTYARG) {
1466     m_thread->stop();
1467     EndDialog(RET_CANCEL);
1468     return 0;
1469 }
1470 
1471 IMPL_LINK( UpdateDialog, hyperlink_clicked, svt::FixedHyperlink*, pHyperlink )
1472 {
1473     ::rtl::OUString sURL;
1474     if ( pHyperlink )
1475         sURL = ::rtl::OUString( pHyperlink->GetURL() );
1476     if ( sURL.getLength() == 0 )
1477         return 0;
1478 
1479     try
1480     {
1481         uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
1482             m_context->getServiceManager()->createInstanceWithContext(
1483                 OUSTR( "com.sun.star.system.SystemShellExecute" ),
1484                 m_context), uno::UNO_QUERY_THROW);
1485         //throws lang::IllegalArgumentException, system::SystemShellExecuteException
1486         xSystemShellExecute->execute(
1487                                      sURL, ::rtl::OUString(), com::sun::star::system::SystemShellExecuteFlags::DEFAULTS);
1488     }
1489     catch (uno::Exception& )
1490     {
1491     }
1492 
1493     return 1;
1494 }
1495