1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_desktop.hxx"
26 
27 
28 
29 #include <dp_gui_handleversionexception.hxx>
30 
31 #include "sal/config.h"
32 
33 #include <cstddef>
34 
35 #include "com/sun/star/beans/PropertyValue.hpp"
36 #include "com/sun/star/beans/NamedValue.hpp"
37 
38 #include "com/sun/star/deployment/DependencyException.hpp"
39 #include "com/sun/star/deployment/LicenseException.hpp"
40 #include "com/sun/star/deployment/VersionException.hpp"
41 #include "com/sun/star/deployment/InstallException.hpp"
42 #include "com/sun/star/deployment/PlatformException.hpp"
43 
44 #include "com/sun/star/deployment/ui/LicenseDialog.hpp"
45 #include "com/sun/star/deployment/DeploymentException.hpp"
46 #include "com/sun/star/deployment/UpdateInformationProvider.hpp"
47 #include "com/sun/star/deployment/XPackage.hpp"
48 
49 #include "com/sun/star/task/XAbortChannel.hpp"
50 #include "com/sun/star/task/XInteractionAbort.hpp"
51 #include "com/sun/star/task/XInteractionApprove.hpp"
52 
53 #include "com/sun/star/ucb/CommandAbortedException.hpp"
54 #include "com/sun/star/ucb/CommandFailedException.hpp"
55 #include "com/sun/star/ucb/XCommandEnvironment.hpp"
56 
57 #include "com/sun/star/ui/dialogs/ExecutableDialogResults.hpp"
58 
59 #include "com/sun/star/uno/Reference.hxx"
60 #include "com/sun/star/uno/RuntimeException.hpp"
61 #include "com/sun/star/uno/Sequence.hxx"
62 #include "com/sun/star/uno/XInterface.hpp"
63 #include "com/sun/star/uno/TypeClass.hpp"
64 #include "osl/diagnose.h"
65 #include "osl/mutex.hxx"
66 #include "rtl/ref.hxx"
67 #include "rtl/ustring.h"
68 #include "rtl/ustring.hxx"
69 #include "sal/types.h"
70 #include "ucbhelper/content.hxx"
71 #include "cppuhelper/exc_hlp.hxx"
72 #include "cppuhelper/implbase3.hxx"
73 #include "comphelper/anytostring.hxx"
74 #include "vcl/msgbox.hxx"
75 #include "toolkit/helper/vclunohelper.hxx"
76 #include "comphelper/processfactory.hxx"
77 
78 #include "dp_gui.h"
79 #include "dp_gui_thread.hxx"
80 #include "dp_gui_extensioncmdqueue.hxx"
81 #include "dp_gui_dependencydialog.hxx"
82 #include "dp_gui_dialog2.hxx"
83 #include "dp_gui_shared.hxx"
84 #include "dp_gui_theextmgr.hxx"
85 #include "dp_gui_updatedialog.hxx"
86 #include "dp_gui_updateinstalldialog.hxx"
87 #include "dp_dependencies.hxx"
88 #include "dp_identifier.hxx"
89 #include "dp_version.hxx"
90 #include <dp_gui_handleversionexception.hxx>
91 
92 #include <queue>
93 #include <boost/shared_ptr.hpp>
94 
95 #if (defined(_MSC_VER) && (_MSC_VER < 1400))
96 #define _WIN32_WINNT 0x0400
97 #endif
98 
99 #ifdef WNT
100 #include "tools/prewin.h"
101 #include <objbase.h>
102 #include "tools/postwin.h"
103 #endif
104 
105 
106 using namespace ::com::sun::star;
107 using ::rtl::OUString;
108 
109 namespace dp_gui {
110 
111 //==============================================================================
112 
113 class ProgressCmdEnv
114     : public ::cppu::WeakImplHelper3< ucb::XCommandEnvironment,
115                                       task::XInteractionHandler,
116                                       ucb::XProgressHandler >
117 {
118     uno::Reference< task::XInteractionHandler> m_xHandler;
119     uno::Reference< uno::XComponentContext > m_xContext;
120     uno::Reference< task::XAbortChannel> m_xAbortChannel;
121 
122     DialogHelper   *m_pDialogHelper;
123     OUString        m_sTitle;
124     bool            m_bAborted;
125     bool            m_bWarnUser;
126     sal_Int32       m_nCurrentProgress;
127 
128     void updateProgress();
129 
130     void update_( uno::Any const & Status ) throw ( uno::RuntimeException );
131 
132 public:
133     virtual ~ProgressCmdEnv();
134 
135     /** When param bAskWhenInstalling = true, then the user is asked if he
136     agrees to install this extension. In case this extension is already installed
137     then the user is also notified and asked if he wants to replace that existing
138     extension. In first case an interaction request with an InstallException
139     will be handled and in the second case a VersionException will be handled.
140     */
141 
ProgressCmdEnv(const uno::Reference<uno::XComponentContext> rContext,DialogHelper * pDialogHelper,const OUString & rTitle)142     ProgressCmdEnv( const uno::Reference< uno::XComponentContext > rContext,
143                     DialogHelper *pDialogHelper,
144                     const OUString &rTitle )
145         :   m_xContext( rContext ),
146             m_pDialogHelper( pDialogHelper ),
147             m_sTitle( rTitle ),
148             m_bAborted( false ),
149             m_bWarnUser( false )
150     {}
151 
activeDialog()152     Dialog * activeDialog() { return m_pDialogHelper ? m_pDialogHelper->getWindow() : NULL; }
153 
setTitle(const OUString & rNewTitle)154     void setTitle( const OUString& rNewTitle ) { m_sTitle = rNewTitle; }
155     void startProgress();
156     void stopProgress();
157     void progressSection( const OUString &rText,
158                           const uno::Reference< task::XAbortChannel > &xAbortChannel = 0 );
isAborted() const159     inline bool isAborted() const { return m_bAborted; }
setWarnUser(bool bNewVal)160     inline void setWarnUser( bool bNewVal ) { m_bWarnUser = bNewVal; }
161 
162     // XCommandEnvironment
163     virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler()
164         throw ( uno::RuntimeException );
165     virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler()
166         throw ( uno::RuntimeException );
167 
168     // XInteractionHandler
169     virtual void SAL_CALL handle( uno::Reference< task::XInteractionRequest > const & xRequest )
170         throw ( uno::RuntimeException );
171 
172     // XProgressHandler
173     virtual void SAL_CALL push( uno::Any const & Status )
174         throw ( uno::RuntimeException );
175     virtual void SAL_CALL update( uno::Any const & Status )
176         throw ( uno::RuntimeException );
177     virtual void SAL_CALL pop() throw ( uno::RuntimeException );
178 };
179 
180 //------------------------------------------------------------------------------
181 struct ExtensionCmd
182 {
183     enum E_CMD_TYPE { ADD, ENABLE, DISABLE, REMOVE, CHECK_FOR_UPDATES, ACCEPT_LICENSE };
184 
185     E_CMD_TYPE  m_eCmdType;
186     bool        m_bWarnUser;
187     OUString    m_sExtensionURL;
188     OUString    m_sRepository;
189     uno::Reference< deployment::XPackage > m_xPackage;
190     std::vector< uno::Reference< deployment::XPackage > >        m_vExtensionList;
191 
ExtensionCmddp_gui::ExtensionCmd192     ExtensionCmd( const E_CMD_TYPE eCommand,
193                   const OUString &rExtensionURL,
194                   const OUString &rRepository,
195                   const bool bWarnUser )
196         : m_eCmdType( eCommand ),
197           m_bWarnUser( bWarnUser ),
198           m_sExtensionURL( rExtensionURL ),
199           m_sRepository( rRepository ) {};
ExtensionCmddp_gui::ExtensionCmd200     ExtensionCmd( const E_CMD_TYPE eCommand,
201                   const uno::Reference< deployment::XPackage > &rPackage )
202         : m_eCmdType( eCommand ),
203           m_bWarnUser( false ),
204           m_xPackage( rPackage ) {};
ExtensionCmddp_gui::ExtensionCmd205     ExtensionCmd( const E_CMD_TYPE eCommand,
206                   const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
207         : m_eCmdType( eCommand ),
208           m_bWarnUser( false ),
209           m_vExtensionList( vExtensionList ) {};
210 };
211 
212 typedef ::boost::shared_ptr< ExtensionCmd > TExtensionCmd;
213 
214 //------------------------------------------------------------------------------
215 class ExtensionCmdQueue::Thread: public dp_gui::Thread
216 {
217 public:
218     Thread( DialogHelper *pDialogHelper,
219             TheExtensionManager *pManager,
220             const uno::Reference< uno::XComponentContext > & rContext );
221 
222     void addExtension( const OUString &rExtensionURL,
223                        const OUString &rRepository,
224                        const bool bWarnUser );
225     void removeExtension( const uno::Reference< deployment::XPackage > &rPackage );
226     void enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
227                           const bool bEnable );
228     void checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
229     void acceptLicense( const uno::Reference< deployment::XPackage > &rPackage );
230     void stop();
231     bool isBusy();
232 
233     static OUString searchAndReplaceAll( const OUString &rSource,
234                                          const OUString &rWhat,
235                                          const OUString &rWith );
236 private:
237     Thread( Thread & ); // not defined
238     void operator =( Thread & ); // not defined
239 
240     virtual ~Thread();
241 
242     virtual void execute();
243     virtual void SAL_CALL onTerminated();
244 
245     void _addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
246                         const OUString &rPackageURL,
247                         const OUString &rRepository,
248                         const bool bWarnUser );
249     void _removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
250                            const uno::Reference< deployment::XPackage > &xPackage );
251     void _enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
252                            const uno::Reference< deployment::XPackage > &xPackage );
253     void _disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
254                             const uno::Reference< deployment::XPackage > &xPackage );
255     void _checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList );
256     void _acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
257                            const uno::Reference< deployment::XPackage > &xPackage );
258 
259     enum Input { NONE, START, STOP };
260 
261     uno::Reference< uno::XComponentContext > m_xContext;
262     std::queue< TExtensionCmd >              m_queue;
263 
264     DialogHelper *m_pDialogHelper;
265     TheExtensionManager *m_pManager;
266 
267     const OUString   m_sEnablingPackages;
268     const OUString   m_sDisablingPackages;
269     const OUString   m_sAddingPackages;
270     const OUString   m_sRemovingPackages;
271     const OUString   m_sDefaultCmd;
272     const OUString   m_sAcceptLicense;
273     osl::Condition   m_wakeup;
274     osl::Mutex       m_mutex;
275     Input            m_eInput;
276     bool             m_bTerminated;
277     bool             m_bStopped;
278     bool             m_bWorking;
279 };
280 
281 //------------------------------------------------------------------------------
startProgress()282 void ProgressCmdEnv::startProgress()
283 {
284     m_nCurrentProgress = 0;
285 
286     if ( m_pDialogHelper )
287         m_pDialogHelper->showProgress( true );
288 }
289 
290 //------------------------------------------------------------------------------
stopProgress()291 void ProgressCmdEnv::stopProgress()
292 {
293     if ( m_pDialogHelper )
294         m_pDialogHelper->showProgress( false );
295 }
296 
297 //------------------------------------------------------------------------------
progressSection(const OUString & rText,const uno::Reference<task::XAbortChannel> & xAbortChannel)298 void ProgressCmdEnv::progressSection( const OUString &rText,
299                                       const uno::Reference< task::XAbortChannel > &xAbortChannel )
300 {
301     m_xAbortChannel = xAbortChannel;
302     if (! m_bAborted)
303     {
304         m_nCurrentProgress = 0;
305         if ( m_pDialogHelper )
306         {
307             m_pDialogHelper->updateProgress( rText, xAbortChannel );
308             m_pDialogHelper->updateProgress( 5 );
309         }
310     }
311 }
312 
313 //------------------------------------------------------------------------------
updateProgress()314 void ProgressCmdEnv::updateProgress()
315 {
316     if ( ! m_bAborted )
317     {
318         long nProgress = ((m_nCurrentProgress*5) % 100) + 5;
319         if ( m_pDialogHelper )
320             m_pDialogHelper->updateProgress( nProgress );
321     }
322 }
323 
324 //------------------------------------------------------------------------------
~ProgressCmdEnv()325 ProgressCmdEnv::~ProgressCmdEnv()
326 {
327     // TODO: stop all threads and wait
328 }
329 
330 
331 //------------------------------------------------------------------------------
332 // XCommandEnvironment
333 //------------------------------------------------------------------------------
getInteractionHandler()334 uno::Reference< task::XInteractionHandler > ProgressCmdEnv::getInteractionHandler()
335     throw ( uno::RuntimeException )
336 {
337     return this;
338 }
339 
340 //------------------------------------------------------------------------------
getProgressHandler()341 uno::Reference< ucb::XProgressHandler > ProgressCmdEnv::getProgressHandler()
342     throw ( uno::RuntimeException )
343 {
344     return this;
345 }
346 
347 //------------------------------------------------------------------------------
348 // XInteractionHandler
349 //------------------------------------------------------------------------------
350 
handle(uno::Reference<task::XInteractionRequest> const & xRequest)351 void ProgressCmdEnv::handle( uno::Reference< task::XInteractionRequest > const & xRequest )
352     throw ( uno::RuntimeException )
353 {
354     uno::Any request( xRequest->getRequest() );
355     OSL_ASSERT( request.getValueTypeClass() == uno::TypeClass_EXCEPTION );
356     dp_misc::TRACE( OUSTR("[dp_gui_cmdenv.cxx] incoming request:\n")
357         + ::comphelper::anyToString(request) + OUSTR("\n"));
358 
359     lang::WrappedTargetException wtExc;
360     deployment::DependencyException depExc;
361 	deployment::LicenseException licExc;
362     deployment::VersionException verExc;
363 	deployment::InstallException instExc;
364     deployment::PlatformException platExc;
365 
366     // selections:
367     bool approve = false;
368     bool abort = false;
369 
370     if (request >>= wtExc) {
371         // handable deployment error signalled, e.g.
372         // bundle item registration failed, notify cause only:
373         uno::Any cause;
374         deployment::DeploymentException dpExc;
375         if (wtExc.TargetException >>= dpExc)
376             cause = dpExc.Cause;
377         else {
378             ucb::CommandFailedException cfExc;
379             if (wtExc.TargetException >>= cfExc)
380                 cause = cfExc.Reason;
381             else
382                 cause = wtExc.TargetException;
383         }
384         update_( cause );
385 
386         // ignore intermediate errors of legacy packages, i.e.
387         // former pkgchk behaviour:
388         const uno::Reference< deployment::XPackage > xPackage( wtExc.Context, uno::UNO_QUERY );
389         OSL_ASSERT( xPackage.is() );
390         if ( xPackage.is() )
391         {
392             const uno::Reference< deployment::XPackageTypeInfo > xPackageType( xPackage->getPackageType() );
393             OSL_ASSERT( xPackageType.is() );
394             if (xPackageType.is())
395             {
396                 approve = ( xPackage->isBundle() &&
397                             xPackageType->getMediaType().matchAsciiL(
398                                 RTL_CONSTASCII_STRINGPARAM(
399                                     "application/"
400                                     "vnd.sun.star.legacy-package-bundle") ));
401             }
402         }
403         abort = !approve;
404     }
405     else if (request >>= depExc)
406     {
407         std::vector< rtl::OUString > deps;
408         for (sal_Int32 i = 0; i < depExc.UnsatisfiedDependencies.getLength();
409              ++i)
410         {
411             deps.push_back(
412                 dp_misc::Dependencies::getErrorText( depExc.UnsatisfiedDependencies[i]) );
413         }
414         {
415             vos::OGuard guard(Application::GetSolarMutex());
416             short n = DependencyDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, deps ).Execute();
417             // Distinguish between closing the dialog and programatically
418             // canceling the dialog (headless VCL):
419             approve = n == RET_OK
420                 || (n == RET_CANCEL && !Application::IsDialogCancelEnabled());
421         }
422     }
423 	else if (request >>= licExc)
424     {
425         uno::Reference< ui::dialogs::XExecutableDialog > xDialog(
426             deployment::ui::LicenseDialog::create(
427             m_xContext, VCLUnoHelper::GetInterface( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL ),
428             licExc.ExtensionName, licExc.Text ) );
429         sal_Int16 res = xDialog->execute();
430         if ( res == ui::dialogs::ExecutableDialogResults::CANCEL )
431             abort = true;
432         else if ( res == ui::dialogs::ExecutableDialogResults::OK )
433             approve = true;
434         else
435         {
436             OSL_ASSERT(0);
437         }
438 	}
439     else if (request >>= verExc)
440     {
441         approve = handleVersionException( verExc, m_pDialogHelper );
442         abort = !approve;
443     }
444 	else if (request >>= instExc)
445 	{
446         if ( ! m_bWarnUser )
447         {
448             approve = true;
449         }
450         else
451         {
452             if ( m_pDialogHelper )
453             {
454                 vos::OGuard guard(Application::GetSolarMutex());
455 
456                 approve = m_pDialogHelper->installExtensionWarn( instExc.displayName );
457             }
458             else
459                 approve = false;
460             abort = !approve;
461         }
462 	}
463     else if (request >>= platExc)
464     {
465         vos::OGuard guard( Application::GetSolarMutex() );
466         String sMsg( ResId( RID_STR_UNSUPPORTED_PLATFORM, *DeploymentGuiResMgr::get() ) );
467         sMsg.SearchAndReplaceAllAscii( "%Name", platExc.package->getDisplayName() );
468         ErrorBox box( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, sMsg );
469         box.Execute();
470         approve = true;
471     }
472 
473 	if (approve == false && abort == false)
474     {
475         // forward to UUI handler:
476         if (! m_xHandler.is()) {
477             // late init:
478             uno::Sequence< uno::Any > handlerArgs( 1 );
479             handlerArgs[ 0 ] <<= beans::PropertyValue(
480                 OUSTR("Context"), -1, uno::Any( m_sTitle ),
481                 beans::PropertyState_DIRECT_VALUE );
482              m_xHandler.set( m_xContext->getServiceManager()
483                             ->createInstanceWithArgumentsAndContext(
484                                 OUSTR("com.sun.star.uui.InteractionHandler"),
485                                 handlerArgs, m_xContext ), uno::UNO_QUERY_THROW );
486         }
487         m_xHandler->handle( xRequest );
488     }
489 	else
490 	{
491         // select:
492         uno::Sequence< uno::Reference< task::XInteractionContinuation > > conts(
493             xRequest->getContinuations() );
494         uno::Reference< task::XInteractionContinuation > const * pConts = conts.getConstArray();
495         sal_Int32 len = conts.getLength();
496         for ( sal_Int32 pos = 0; pos < len; ++pos )
497         {
498             if (approve) {
499                 uno::Reference< task::XInteractionApprove > xInteractionApprove( pConts[ pos ], uno::UNO_QUERY );
500                 if (xInteractionApprove.is()) {
501                     xInteractionApprove->select();
502                     // don't query again for ongoing continuations:
503                     approve = false;
504                 }
505             }
506             else if (abort) {
507                 uno::Reference< task::XInteractionAbort > xInteractionAbort( pConts[ pos ], uno::UNO_QUERY );
508                 if (xInteractionAbort.is()) {
509                     xInteractionAbort->select();
510                     // don't query again for ongoing continuations:
511                     abort = false;
512                 }
513             }
514         }
515 	}
516 }
517 
518 //------------------------------------------------------------------------------
519 // XProgressHandler
520 //------------------------------------------------------------------------------
push(uno::Any const & rStatus)521 void ProgressCmdEnv::push( uno::Any const & rStatus )
522     throw( uno::RuntimeException )
523 {
524     update_( rStatus );
525 }
526 
527 //------------------------------------------------------------------------------
update_(uno::Any const & rStatus)528 void ProgressCmdEnv::update_( uno::Any const & rStatus )
529     throw( uno::RuntimeException )
530 {
531     OUString text;
532     if ( rStatus.hasValue() && !( rStatus >>= text) )
533     {
534         if ( rStatus.getValueTypeClass() == uno::TypeClass_EXCEPTION )
535             text = static_cast< uno::Exception const *>( rStatus.getValue() )->Message;
536         if ( text.getLength() == 0 )
537             text = ::comphelper::anyToString( rStatus ); // fallback
538 
539         const ::vos::OGuard aGuard( Application::GetSolarMutex() );
540         const ::std::auto_ptr< ErrorBox > aBox( new ErrorBox( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, WB_OK, text ) );
541         aBox->Execute();
542     }
543     ++m_nCurrentProgress;
544     updateProgress();
545 }
546 
547 //------------------------------------------------------------------------------
update(uno::Any const & rStatus)548 void ProgressCmdEnv::update( uno::Any const & rStatus )
549     throw( uno::RuntimeException )
550 {
551     update_( rStatus );
552 }
553 
554 //------------------------------------------------------------------------------
pop()555 void ProgressCmdEnv::pop()
556     throw( uno::RuntimeException )
557 {
558     update_( uno::Any() ); // no message
559 }
560 
561 //------------------------------------------------------------------------------
Thread(DialogHelper * pDialogHelper,TheExtensionManager * pManager,const uno::Reference<uno::XComponentContext> & rContext)562 ExtensionCmdQueue::Thread::Thread( DialogHelper *pDialogHelper,
563                                    TheExtensionManager *pManager,
564                                    const uno::Reference< uno::XComponentContext > & rContext ) :
565     m_xContext( rContext ),
566     m_pDialogHelper( pDialogHelper ),
567     m_pManager( pManager ),
568     m_sEnablingPackages( DialogHelper::getResourceString( RID_STR_ENABLING_PACKAGES ) ),
569     m_sDisablingPackages( DialogHelper::getResourceString( RID_STR_DISABLING_PACKAGES ) ),
570     m_sAddingPackages( DialogHelper::getResourceString( RID_STR_ADDING_PACKAGES ) ),
571     m_sRemovingPackages( DialogHelper::getResourceString( RID_STR_REMOVING_PACKAGES ) ),
572     m_sDefaultCmd( DialogHelper::getResourceString( RID_STR_ADD_PACKAGES ) ),
573     m_sAcceptLicense( DialogHelper::getResourceString( RID_STR_ACCEPT_LICENSE ) ),
574     m_eInput( NONE ),
575     m_bTerminated( false ),
576     m_bStopped( false ),
577     m_bWorking( false )
578 {
579     OSL_ASSERT( pDialogHelper );
580 }
581 
582 //------------------------------------------------------------------------------
addExtension(const::rtl::OUString & rExtensionURL,const::rtl::OUString & rRepository,const bool bWarnUser)583 void ExtensionCmdQueue::Thread::addExtension( const ::rtl::OUString &rExtensionURL,
584                                               const ::rtl::OUString &rRepository,
585                                               const bool bWarnUser )
586 {
587     ::osl::MutexGuard aGuard( m_mutex );
588 
589     //If someone called stop then we do not add the extension -> game over!
590     if ( m_bStopped )
591         return;
592 
593     if ( rExtensionURL.getLength() )
594     {
595         TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ADD, rExtensionURL, rRepository, bWarnUser ) );
596 
597         m_queue.push( pEntry );
598         m_eInput = START;
599         m_wakeup.set();
600     }
601 }
602 
603 //------------------------------------------------------------------------------
removeExtension(const uno::Reference<deployment::XPackage> & rPackage)604 void ExtensionCmdQueue::Thread::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
605 {
606     ::osl::MutexGuard aGuard( m_mutex );
607 
608     //If someone called stop then we do not remove the extension -> game over!
609     if ( m_bStopped )
610         return;
611 
612     if ( rPackage.is() )
613     {
614         TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::REMOVE, rPackage ) );
615 
616         m_queue.push( pEntry );
617         m_eInput = START;
618         m_wakeup.set();
619     }
620 }
621 
622 //------------------------------------------------------------------------------
acceptLicense(const uno::Reference<deployment::XPackage> & rPackage)623 void ExtensionCmdQueue::Thread::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
624 {
625     ::osl::MutexGuard aGuard( m_mutex );
626 
627     //If someone called stop then we do not remove the extension -> game over!
628     if ( m_bStopped )
629         return;
630 
631     if ( rPackage.is() )
632     {
633         TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::ACCEPT_LICENSE, rPackage ) );
634 
635         m_queue.push( pEntry );
636         m_eInput = START;
637         m_wakeup.set();
638     }
639 }
640 
641 //------------------------------------------------------------------------------
enableExtension(const uno::Reference<deployment::XPackage> & rPackage,const bool bEnable)642 void ExtensionCmdQueue::Thread::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
643                                                  const bool bEnable )
644 {
645     ::osl::MutexGuard aGuard( m_mutex );
646 
647     //If someone called stop then we do not remove the extension -> game over!
648     if ( m_bStopped )
649         return;
650 
651     if ( rPackage.is() )
652     {
653         TExtensionCmd pEntry( new ExtensionCmd( bEnable ? ExtensionCmd::ENABLE :
654                                                           ExtensionCmd::DISABLE,
655                                                 rPackage ) );
656         m_queue.push( pEntry );
657         m_eInput = START;
658         m_wakeup.set();
659     }
660 }
661 
662 //------------------------------------------------------------------------------
checkForUpdates(const std::vector<uno::Reference<deployment::XPackage>> & vExtensionList)663 void ExtensionCmdQueue::Thread::checkForUpdates(
664     const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
665 {
666     ::osl::MutexGuard aGuard( m_mutex );
667 
668     //If someone called stop then we do not update the extension -> game over!
669     if ( m_bStopped )
670         return;
671 
672     TExtensionCmd pEntry( new ExtensionCmd( ExtensionCmd::CHECK_FOR_UPDATES, vExtensionList ) );
673     m_queue.push( pEntry );
674     m_eInput = START;
675     m_wakeup.set();
676 }
677 
678 //------------------------------------------------------------------------------
679 //Stopping this thread will not abort the installation of extensions.
stop()680 void ExtensionCmdQueue::Thread::stop()
681 {
682     osl::MutexGuard aGuard( m_mutex );
683     m_bStopped = true;
684     m_eInput = STOP;
685     m_wakeup.set();
686 }
687 
688 //------------------------------------------------------------------------------
isBusy()689 bool ExtensionCmdQueue::Thread::isBusy()
690 {
691     osl::MutexGuard aGuard( m_mutex );
692     return m_bWorking;
693 }
694 
695 //------------------------------------------------------------------------------
~Thread()696 ExtensionCmdQueue::Thread::~Thread() {}
697 
698 //------------------------------------------------------------------------------
execute()699 void ExtensionCmdQueue::Thread::execute()
700 {
701 #ifdef WNT
702     //Needed for use of the service "com.sun.star.system.SystemShellExecute" in
703     //DialogHelper::openWebBrowser
704     CoUninitialize();
705     HRESULT r = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
706 #endif
707     for (;;)
708     {
709         if ( m_wakeup.wait() != osl::Condition::result_ok )
710         {
711             dp_misc::TRACE( "dp_gui::ExtensionCmdQueue::Thread::run: ignored "
712                        "osl::Condition::wait failure\n" );
713         }
714         m_wakeup.reset();
715 
716         int nSize;
717         Input eInput;
718         {
719             osl::MutexGuard aGuard( m_mutex );
720             eInput = m_eInput;
721             m_eInput = NONE;
722             nSize = m_queue.size();
723             m_bWorking = false;
724         }
725 
726         // If this thread has been woken up by anything else except start, stop
727         // then input is NONE and we wait again.
728         // We only install the extension which are currently in the queue.
729         // The progressbar will be set to show the progress of the current number
730         // of extensions. If we allowed to add extensions now then the progressbar may
731         // have reached the end while we still install newly added extensions.
732         if ( ( eInput == NONE ) || ( nSize == 0 ) )
733             continue;
734         if ( eInput == STOP )
735             break;
736 
737         ::rtl::Reference< ProgressCmdEnv > currentCmdEnv( new ProgressCmdEnv( m_xContext, m_pDialogHelper, m_sDefaultCmd ) );
738 
739         // Do not lock the following part with addExtension. addExtension may be called in the main thread.
740         // If the message box "Do you want to install the extension (or similar)" is shown and then
741         // addExtension is called, which then blocks the main thread, then we deadlock.
742         bool bStartProgress = true;
743 
744         while ( !currentCmdEnv->isAborted() && --nSize >= 0 )
745         {
746             {
747                 osl::MutexGuard aGuard( m_mutex );
748                 m_bWorking = true;
749             }
750 
751             try
752             {
753                 TExtensionCmd pEntry;
754                 {
755                     ::osl::MutexGuard queueGuard( m_mutex );
756                     pEntry = m_queue.front();
757                     m_queue.pop();
758                 }
759 
760                 if ( bStartProgress && ( pEntry->m_eCmdType != ExtensionCmd::CHECK_FOR_UPDATES ) )
761                 {
762                     currentCmdEnv->startProgress();
763                     bStartProgress = false;
764                 }
765 
766                 switch ( pEntry->m_eCmdType ) {
767                 case ExtensionCmd::ADD :
768                     _addExtension( currentCmdEnv, pEntry->m_sExtensionURL, pEntry->m_sRepository, pEntry->m_bWarnUser );
769                     break;
770                 case ExtensionCmd::REMOVE :
771                     _removeExtension( currentCmdEnv, pEntry->m_xPackage );
772                     break;
773                 case ExtensionCmd::ENABLE :
774                     _enableExtension( currentCmdEnv, pEntry->m_xPackage );
775                     break;
776                 case ExtensionCmd::DISABLE :
777                     _disableExtension( currentCmdEnv, pEntry->m_xPackage );
778                     break;
779                 case ExtensionCmd::CHECK_FOR_UPDATES :
780                     _checkForUpdates( pEntry->m_vExtensionList );
781                     break;
782                 case ExtensionCmd::ACCEPT_LICENSE :
783                     _acceptLicense( currentCmdEnv, pEntry->m_xPackage );
784                     break;
785                 }
786             }
787             //catch ( deployment::DeploymentException &)
788             //{
789             //}
790             //catch ( lang::IllegalArgumentException &)
791             //{
792             //}
793             catch ( ucb::CommandAbortedException & )
794             {
795                 //This exception is thrown when the user clicks cancel on the progressbar.
796                 //Then we cancel the installation of all extensions and remove them from
797                 //the queue.
798                 {
799                     ::osl::MutexGuard queueGuard2(m_mutex);
800                     while ( --nSize >= 0 )
801                         m_queue.pop();
802                 }
803                 break;
804             }
805             catch ( ucb::CommandFailedException & )
806             {
807                 //This exception is thrown when a user clicked cancel in the messagebox which was
808                 //startet by the interaction handler. For example the user will be asked if he/she
809                 //really wants to install the extension.
810                 //These interaction are run for exectly one extension at a time. Therefore we continue
811                 //with installing the remaining extensions.
812                 continue;
813             }
814             catch ( uno::Exception & )
815             {
816                 //Todo display the user an error
817                 //see also DialogImpl::SyncPushButton::Click()
818                 uno::Any exc( ::cppu::getCaughtException() );
819                 OUString msg;
820                 deployment::DeploymentException dpExc;
821                 if ((exc >>= dpExc) &&
822                     dpExc.Cause.getValueTypeClass() == uno::TypeClass_EXCEPTION)
823                 {
824                     // notify error cause only:
825                     msg = reinterpret_cast< uno::Exception const * >( dpExc.Cause.getValue() )->Message;
826                 }
827                 if (msg.getLength() == 0) // fallback for debugging purposes
828                     msg = ::comphelper::anyToString(exc);
829 
830                 const ::vos::OGuard guard( Application::GetSolarMutex() );
831                 ::std::auto_ptr<ErrorBox> box(
832                     new ErrorBox( currentCmdEnv->activeDialog(), WB_OK, msg ) );
833                 if ( m_pDialogHelper )
834                     box->SetText( m_pDialogHelper->getWindow()->GetText() );
835                 box->Execute();
836                     //Continue with installation of the remaining extensions
837             }
838             {
839                 osl::MutexGuard aGuard( m_mutex );
840                 m_bWorking = false;
841             }
842         }
843 
844         {
845             // when leaving the while loop with break, we should set working to false, too
846 			osl::MutexGuard aGuard( m_mutex );
847             m_bWorking = false;
848         }
849 
850 		if ( !bStartProgress )
851             currentCmdEnv->stopProgress();
852     }
853     //end for
854     //enable all buttons
855 //     m_pDialog->m_bAddingExtensions = false;
856 //     m_pDialog->updateButtonStates();
857 #ifdef WNT
858     CoUninitialize();
859 #endif
860 }
861 
862 //------------------------------------------------------------------------------
_addExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const OUString & rPackageURL,const OUString & rRepository,const bool bWarnUser)863 void ExtensionCmdQueue::Thread::_addExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
864                                                const OUString &rPackageURL,
865                                                const OUString &rRepository,
866                                                const bool bWarnUser )
867 {
868     //check if we have a string in anyTitle. For example "unopkg gui \" caused anyTitle to be void
869     //and anyTitle.get<OUString> throws as RuntimeException.
870     uno::Any anyTitle;
871 	try
872 	{
873 		anyTitle = ::ucbhelper::Content( rPackageURL, rCmdEnv.get() ).getPropertyValue( OUSTR("Title") );
874 	}
875 	catch ( uno::Exception & )
876 	{
877 		return;
878 	}
879 
880     OUString sName;
881     if ( ! (anyTitle >>= sName) )
882     {
883         OSL_ENSURE(0, "Could not get file name for extension.");
884         return;
885     }
886 
887     rCmdEnv->setWarnUser( bWarnUser );
888     uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
889     uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
890     OUString sTitle = searchAndReplaceAll( m_sAddingPackages, OUSTR("%EXTENSION_NAME"), sName );
891     rCmdEnv->progressSection( sTitle, xAbortChannel );
892 
893     try
894     {
895 		xExtMgr->addExtension(rPackageURL, uno::Sequence<beans::NamedValue>(),
896                               rRepository, xAbortChannel, rCmdEnv.get() );
897     }
898     catch ( ucb::CommandFailedException & )
899     {
900         // When the extension is already installed we'll get a dialog asking if we want to overwrite. If we then press
901         // cancel this exception is thrown.
902     }
903     catch ( ucb::CommandAbortedException & )
904     {
905         // User clicked the cancel button
906         // TODO: handle cancel
907     }
908     rCmdEnv->setWarnUser( false );
909 }
910 
911 //------------------------------------------------------------------------------
_removeExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)912 void ExtensionCmdQueue::Thread::_removeExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
913                                                   const uno::Reference< deployment::XPackage > &xPackage )
914 {
915     uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
916     uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
917     OUString sTitle = searchAndReplaceAll( m_sRemovingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
918     rCmdEnv->progressSection( sTitle, xAbortChannel );
919 
920     OUString id( dp_misc::getIdentifier( xPackage ) );
921     try
922     {
923         xExtMgr->removeExtension( id, xPackage->getName(), xPackage->getRepositoryName(), xAbortChannel, rCmdEnv.get() );
924     }
925     catch ( deployment::DeploymentException & )
926     {}
927     catch ( ucb::CommandFailedException & )
928     {}
929     catch ( ucb::CommandAbortedException & )
930     {}
931 
932     // Check, if there are still updates to be notified via menu bar icon
933     uno::Sequence< uno::Sequence< rtl::OUString > > aItemList;
934     UpdateDialog::createNotifyJob( false, aItemList );
935 }
936 
937 //------------------------------------------------------------------------------
_checkForUpdates(const std::vector<uno::Reference<deployment::XPackage>> & vExtensionList)938 void ExtensionCmdQueue::Thread::_checkForUpdates(
939     const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
940 {
941     UpdateDialog* pUpdateDialog;
942     std::vector< UpdateData > vData;
943 
944     const ::vos::OGuard guard( Application::GetSolarMutex() );
945 
946     pUpdateDialog = new UpdateDialog( m_xContext, m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, vExtensionList, &vData );
947 
948     pUpdateDialog->notifyMenubar( true, false ); // prepare the checking, if there updates to be notified via menu bar icon
949 
950     if ( ( pUpdateDialog->Execute() == RET_OK ) && !vData.empty() )
951     {
952         // If there is at least one directly downloadable dialog then we
953         // open the install dialog.
954         ::std::vector< UpdateData > dataDownload;
955         int countWebsiteDownload = 0;
956         typedef std::vector< dp_gui::UpdateData >::const_iterator cit;
957 
958         for ( cit i = vData.begin(); i < vData.end(); i++ )
959         {
960             if ( i->sWebsiteURL.getLength() > 0 )
961                 countWebsiteDownload ++;
962             else
963                 dataDownload.push_back( *i );
964         }
965 
966         short nDialogResult = RET_OK;
967         if ( !dataDownload.empty() )
968         {
969             nDialogResult = UpdateInstallDialog( m_pDialogHelper? m_pDialogHelper->getWindow() : NULL, dataDownload, m_xContext ).Execute();
970             pUpdateDialog->notifyMenubar( false, true ); // Check, if there are still pending updates to be notified via menu bar icon
971         }
972         else
973             pUpdateDialog->notifyMenubar( false, false ); // Check, if there are pending updates to be notified via menu bar icon
974 
975         //Now start the webbrowser and navigate to the websites where we get the updates
976         if ( RET_OK == nDialogResult )
977         {
978             for ( cit i = vData.begin(); i < vData.end(); i++ )
979             {
980                 if ( m_pDialogHelper && ( i->sWebsiteURL.getLength() > 0 ) )
981                     m_pDialogHelper->openWebBrowser( i->sWebsiteURL, m_pDialogHelper->getWindow()->GetText() );
982             }
983         }
984     }
985     else
986         pUpdateDialog->notifyMenubar( false, false ); // check if there updates to be notified via menu bar icon
987 
988     delete pUpdateDialog;
989 }
990 
991 //------------------------------------------------------------------------------
_enableExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)992 void ExtensionCmdQueue::Thread::_enableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
993                                                   const uno::Reference< deployment::XPackage > &xPackage )
994 {
995     if ( !xPackage.is() )
996         return;
997 
998     uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
999     uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1000     OUString sTitle = searchAndReplaceAll( m_sEnablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1001     rCmdEnv->progressSection( sTitle, xAbortChannel );
1002 
1003     try
1004     {
1005         xExtMgr->enableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
1006         if ( m_pDialogHelper )
1007             m_pDialogHelper->updatePackageInfo( xPackage );
1008     }
1009     catch ( ::ucb::CommandAbortedException & )
1010     {}
1011 }
1012 
1013 //------------------------------------------------------------------------------
_disableExtension(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)1014 void ExtensionCmdQueue::Thread::_disableExtension( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1015                                                    const uno::Reference< deployment::XPackage > &xPackage )
1016 {
1017     if ( !xPackage.is() )
1018         return;
1019 
1020     uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1021     uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1022     OUString sTitle = searchAndReplaceAll( m_sDisablingPackages, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1023     rCmdEnv->progressSection( sTitle, xAbortChannel );
1024 
1025     try
1026     {
1027         xExtMgr->disableExtension( xPackage, xAbortChannel, rCmdEnv.get() );
1028         if ( m_pDialogHelper )
1029             m_pDialogHelper->updatePackageInfo( xPackage );
1030     }
1031     catch ( ::ucb::CommandAbortedException & )
1032     {}
1033 }
1034 
1035 //------------------------------------------------------------------------------
_acceptLicense(::rtl::Reference<ProgressCmdEnv> & rCmdEnv,const uno::Reference<deployment::XPackage> & xPackage)1036 void ExtensionCmdQueue::Thread::_acceptLicense( ::rtl::Reference< ProgressCmdEnv > &rCmdEnv,
1037                                                 const uno::Reference< deployment::XPackage > &xPackage )
1038 {
1039     if ( !xPackage.is() )
1040         return;
1041 
1042     uno::Reference< deployment::XExtensionManager > xExtMgr = m_pManager->getExtensionManager();
1043     uno::Reference< task::XAbortChannel > xAbortChannel( xExtMgr->createAbortChannel() );
1044     OUString sTitle = searchAndReplaceAll( m_sAcceptLicense, OUSTR("%EXTENSION_NAME"), xPackage->getDisplayName() );
1045     rCmdEnv->progressSection( sTitle, xAbortChannel );
1046 
1047     try
1048     {
1049         xExtMgr->checkPrerequisitesAndEnable( xPackage, xAbortChannel, rCmdEnv.get() );
1050         if ( m_pDialogHelper )
1051             m_pDialogHelper->updatePackageInfo( xPackage );
1052     }
1053     catch ( ::ucb::CommandAbortedException & )
1054     {}
1055 }
1056 
1057 //------------------------------------------------------------------------------
onTerminated()1058 void ExtensionCmdQueue::Thread::onTerminated()
1059 {
1060     ::osl::MutexGuard g(m_mutex);
1061     m_bTerminated = true;
1062 }
1063 
1064 //------------------------------------------------------------------------------
searchAndReplaceAll(const OUString & rSource,const OUString & rWhat,const OUString & rWith)1065 OUString ExtensionCmdQueue::Thread::searchAndReplaceAll( const OUString &rSource,
1066                                                          const OUString &rWhat,
1067                                                          const OUString &rWith )
1068 {
1069     OUString aRet( rSource );
1070     sal_Int32 nLen = rWhat.getLength();
1071 
1072     if ( !nLen )
1073         return aRet;
1074 
1075     sal_Int32 nIndex = rSource.indexOf( rWhat );
1076     while ( nIndex != -1 )
1077     {
1078         aRet = aRet.replaceAt( nIndex, nLen, rWith );
1079         nIndex = aRet.indexOf( rWhat, nIndex + rWith.getLength() );
1080     }
1081     return aRet;
1082 }
1083 
1084 
1085 //------------------------------------------------------------------------------
1086 //------------------------------------------------------------------------------
1087 //------------------------------------------------------------------------------
ExtensionCmdQueue(DialogHelper * pDialogHelper,TheExtensionManager * pManager,const uno::Reference<uno::XComponentContext> & rContext)1088 ExtensionCmdQueue::ExtensionCmdQueue( DialogHelper * pDialogHelper,
1089                                       TheExtensionManager *pManager,
1090                                       const uno::Reference< uno::XComponentContext > &rContext )
1091   : m_thread( new Thread( pDialogHelper, pManager, rContext ) )
1092 {
1093     m_thread->launch();
1094 }
1095 
~ExtensionCmdQueue()1096 ExtensionCmdQueue::~ExtensionCmdQueue() {
1097     stop();
1098 }
1099 
addExtension(const::rtl::OUString & extensionURL,const::rtl::OUString & repository,const bool bWarnUser)1100 void ExtensionCmdQueue::addExtension( const ::rtl::OUString & extensionURL,
1101                                       const ::rtl::OUString & repository,
1102                                       const bool bWarnUser )
1103 {
1104     m_thread->addExtension( extensionURL, repository, bWarnUser );
1105 }
1106 
removeExtension(const uno::Reference<deployment::XPackage> & rPackage)1107 void ExtensionCmdQueue::removeExtension( const uno::Reference< deployment::XPackage > &rPackage )
1108 {
1109     m_thread->removeExtension( rPackage );
1110 }
1111 
enableExtension(const uno::Reference<deployment::XPackage> & rPackage,const bool bEnable)1112 void ExtensionCmdQueue::enableExtension( const uno::Reference< deployment::XPackage > &rPackage,
1113                                          const bool bEnable )
1114 {
1115     m_thread->enableExtension( rPackage, bEnable );
1116 }
1117 
checkForUpdates(const std::vector<uno::Reference<deployment::XPackage>> & vExtensionList)1118 void ExtensionCmdQueue::checkForUpdates( const std::vector<uno::Reference<deployment::XPackage > > &vExtensionList )
1119 {
1120     m_thread->checkForUpdates( vExtensionList );
1121 }
1122 
acceptLicense(const uno::Reference<deployment::XPackage> & rPackage)1123 void ExtensionCmdQueue::acceptLicense( const uno::Reference< deployment::XPackage > &rPackage )
1124 {
1125     m_thread->acceptLicense( rPackage );
1126 }
1127 
syncRepositories(const uno::Reference<uno::XComponentContext> & xContext)1128 void ExtensionCmdQueue::syncRepositories( const uno::Reference< uno::XComponentContext > &xContext )
1129 {
1130     dp_misc::syncRepositories( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) );
1131 }
1132 
stop()1133 void ExtensionCmdQueue::stop()
1134 {
1135     m_thread->stop();
1136 }
1137 
isBusy()1138 bool ExtensionCmdQueue::isBusy()
1139 {
1140     return m_thread->isBusy();
1141 }
1142 
handleInteractionRequest(const uno::Reference<uno::XComponentContext> & xContext,const uno::Reference<task::XInteractionRequest> & xRequest)1143 void handleInteractionRequest( const uno::Reference< uno::XComponentContext > & xContext,
1144                                const uno::Reference< task::XInteractionRequest > & xRequest )
1145 {
1146     ::rtl::Reference< ProgressCmdEnv > xCmdEnv( new ProgressCmdEnv( xContext, NULL, OUSTR("Extension Manager") ) );
1147     xCmdEnv->handle( xRequest );
1148 }
1149 
1150 } //namespace dp_gui
1151 
1152