Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / desktop / source / deployment / gui / dp_gui_dialog2.cxx
blobe48bb2d0912dee950ee406e313e73cc21a968226
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <strings.hrc>
21 #include <helpids.h>
22 #include <svtools/controldims.hxx>
24 #include "dp_gui.h"
25 #include "dp_gui_dialog2.hxx"
26 #include "dp_gui_extlistbox.hxx"
27 #include <dp_shared.hxx>
28 #include "dp_gui_theextmgr.hxx"
29 #include "dp_gui_extensioncmdqueue.hxx"
30 #include <dp_misc.h>
31 #include <dp_ucb.h>
32 #include <dp_update.hxx>
33 #include <dp_identifier.hxx>
34 #include <dp_descriptioninfoset.hxx>
36 #include <fpicker/strings.hrc>
38 #include <vcl/commandevent.hxx>
39 #include <vcl/svapp.hxx>
41 #include <osl/mutex.hxx>
42 #include <sal/log.hxx>
44 #include <svtools/restartdialog.hxx>
46 #include <sfx2/filedlghelper.hxx>
47 #include <sfx2/sfxdlg.hxx>
49 #include <comphelper/anytostring.hxx>
50 #include <cppuhelper/exc_hlp.hxx>
51 #include <cppuhelper/bootstrap.hxx>
53 #include <comphelper/processfactory.hxx>
54 #include <tools/diagnose_ex.h>
55 #include <ucbhelper/content.hxx>
56 #include <unotools/collatorwrapper.hxx>
57 #include <unotools/configmgr.hxx>
59 #include <com/sun/star/beans/StringPair.hpp>
60 #include <com/sun/star/deployment/DeploymentException.hpp>
61 #include <com/sun/star/i18n/CollatorOptions.hpp>
62 #include <com/sun/star/lang/IllegalArgumentException.hpp>
63 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
64 #include <com/sun/star/system/SystemShellExecute.hpp>
66 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
67 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
68 #include <com/sun/star/ui/dialogs/FilePicker.hpp>
69 #include <com/sun/star/ui/dialogs/XFilterManager.hpp>
71 #include <com/sun/star/uno/Any.hxx>
72 #include <com/sun/star/uno/XComponentContext.hpp>
74 #include <officecfg/Office/ExtensionManager.hxx>
76 #include <map>
77 #include <memory>
78 #include <vector>
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::system;
84 namespace dp_gui {
86 #define USER_PACKAGE_MANAGER "user"
87 #define SHARED_PACKAGE_MANAGER "shared"
88 #define BUNDLED_PACKAGE_MANAGER "bundled"
91 struct StrAllFiles : public rtl::StaticWithInit< OUString, StrAllFiles >
93 OUString operator () () {
94 const SolarMutexGuard guard;
95 std::locale loc = Translate::Create("fps");
96 return Translate::get(STR_FILTERNAME_ALL, loc);
100 // ExtBoxWithBtns_Impl
101 class ExtBoxWithBtns_Impl : public ExtensionBox_Impl
103 bool m_bInterfaceLocked;
105 ExtMgrDialog* m_pParent;
107 void SetButtonStatus( const TEntry_Impl& rEntry );
108 OString ShowPopupMenu( const Point &rPos, const long nPos );
110 public:
111 explicit ExtBoxWithBtns_Impl(std::unique_ptr<weld::ScrolledWindow> xScroll);
113 void InitFromDialog(ExtMgrDialog *pParentDialog);
115 virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override;
116 virtual bool Command( const CommandEvent& rCEvt ) override;
118 virtual void RecalcAll() override;
119 virtual void selectEntry( const long nPos ) override;
121 void enableButtons( bool bEnable );
124 ExtBoxWithBtns_Impl::ExtBoxWithBtns_Impl(std::unique_ptr<weld::ScrolledWindow> xScroll)
125 : ExtensionBox_Impl(std::move(xScroll))
126 , m_bInterfaceLocked(false)
127 , m_pParent(nullptr)
131 void ExtBoxWithBtns_Impl::InitFromDialog(ExtMgrDialog *pParentDialog)
133 setExtensionManager(pParentDialog->getExtensionManager());
135 m_pParent = pParentDialog;
138 void ExtBoxWithBtns_Impl::RecalcAll()
140 const sal_Int32 nActive = getSelIndex();
142 if ( nActive != ExtensionBox_Impl::ENTRY_NOTFOUND )
144 SetButtonStatus( GetEntryData( nActive) );
146 else
148 m_pParent->enableOptionsButton( false );
149 m_pParent->enableRemoveButton( false );
150 m_pParent->enableEnableButton( false );
153 ExtensionBox_Impl::RecalcAll();
157 //This function may be called with nPos < 0
158 void ExtBoxWithBtns_Impl::selectEntry( const long nPos )
160 if ( HasActive() && ( nPos == getSelIndex() ) )
161 return;
163 ExtensionBox_Impl::selectEntry( nPos );
166 void ExtBoxWithBtns_Impl::SetButtonStatus(const TEntry_Impl& rEntry)
168 bool bShowOptionBtn = true;
170 rEntry->m_bHasButtons = false;
171 if ( ( rEntry->m_eState == REGISTERED ) || ( rEntry->m_eState == NOT_AVAILABLE ) )
173 m_pParent->enableButtontoEnable( false );
175 else
177 m_pParent->enableButtontoEnable( true );
178 bShowOptionBtn = false;
181 if ( ( !rEntry->m_bUser || ( rEntry->m_eState == NOT_AVAILABLE ) || rEntry->m_bMissingDeps )
182 && !rEntry->m_bMissingLic )
184 m_pParent->enableEnableButton( false );
186 else
188 m_pParent->enableEnableButton( !rEntry->m_bLocked );
189 rEntry->m_bHasButtons = true;
192 if ( rEntry->m_bHasOptions && bShowOptionBtn )
194 m_pParent->enableOptionsButton( true );
195 rEntry->m_bHasButtons = true;
197 else
199 m_pParent->enableOptionsButton( false );
202 if ( rEntry->m_bUser || rEntry->m_bShared )
204 m_pParent->enableRemoveButton( !rEntry->m_bLocked );
205 rEntry->m_bHasButtons = true;
207 else
209 m_pParent->enableRemoveButton( false );
213 bool ExtBoxWithBtns_Impl::Command(const CommandEvent& rCEvt)
215 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
216 return ExtensionBox_Impl::Command(rCEvt);
218 const Point aMousePos(rCEvt.GetMousePosPixel());
219 const auto nPos = PointToPos(aMousePos);
220 OString sCommand = ShowPopupMenu(aMousePos, nPos);
222 if (sCommand == "CMD_ENABLE")
223 m_pParent->enablePackage( GetEntryData( nPos )->m_xPackage, true );
224 else if (sCommand == "CMD_DISABLE")
225 m_pParent->enablePackage( GetEntryData( nPos )->m_xPackage, false );
226 else if (sCommand == "CMD_UPDATE")
227 m_pParent->updatePackage( GetEntryData( nPos )->m_xPackage );
228 else if (sCommand == "CMD_REMOVE")
229 m_pParent->removePackage( GetEntryData( nPos )->m_xPackage );
230 else if (sCommand == "CMD_SHOW_LICENSE")
232 m_pParent->incBusy();
233 ShowLicenseDialog aLicenseDlg(m_pParent->getDialog(), GetEntryData(nPos)->m_xPackage);
234 aLicenseDlg.run();
235 m_pParent->decBusy();
238 return true;
241 OString ExtBoxWithBtns_Impl::ShowPopupMenu( const Point & rPos, const long nPos )
243 if ( nPos >= static_cast<long>(getItemCount()) )
244 return "CMD_NONE";
246 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(nullptr, "desktop/ui/extensionmenu.ui"));
247 std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
249 #if ENABLE_EXTENSION_UPDATE
250 xPopup->append("CMD_UPDATE", DpResId( RID_CTX_ITEM_CHECK_UPDATE ) );
251 #endif
253 if ( ! GetEntryData( nPos )->m_bLocked )
255 if ( GetEntryData( nPos )->m_bUser )
257 if ( GetEntryData( nPos )->m_eState == REGISTERED )
258 xPopup->append("CMD_DISABLE", DpResId(RID_CTX_ITEM_DISABLE));
259 else if ( GetEntryData( nPos )->m_eState != NOT_AVAILABLE )
260 xPopup->append("CMD_ENABLE", DpResId(RID_CTX_ITEM_ENABLE));
262 if (!officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionRemoval::get())
264 xPopup->append("CMD_REMOVE", DpResId(RID_CTX_ITEM_REMOVE));
268 if ( !GetEntryData( nPos )->m_sLicenseText.isEmpty() )
269 xPopup->append("CMD_SHOW_LICENSE", DpResId(RID_STR_SHOW_LICENSE_CMD));
271 return xPopup->popup_at_rect(GetDrawingArea(), tools::Rectangle(rPos, Size(1, 1)));
274 bool ExtBoxWithBtns_Impl::MouseButtonDown( const MouseEvent& rMEvt )
276 if (m_bInterfaceLocked)
277 return false;
278 return ExtensionBox_Impl::MouseButtonDown(rMEvt);
281 void ExtBoxWithBtns_Impl::enableButtons( bool bEnable )
283 m_bInterfaceLocked = ! bEnable;
285 if ( bEnable )
287 sal_Int32 nIndex = getSelIndex();
288 if ( nIndex != ExtensionBox_Impl::ENTRY_NOTFOUND )
289 SetButtonStatus( GetEntryData( nIndex ) );
291 else
293 m_pParent->enableEnableButton( false );
294 m_pParent->enableOptionsButton( false );
295 m_pParent->enableRemoveButton( false );
299 // DialogHelper
301 DialogHelper::DialogHelper(const uno::Reference< uno::XComponentContext > &xContext,
302 weld::Window* pWindow)
303 : m_pWindow(pWindow)
304 , m_nEventID(nullptr)
306 m_xContext = xContext;
309 DialogHelper::~DialogHelper()
311 if ( m_nEventID )
312 Application::RemoveUserEvent( m_nEventID );
316 bool DialogHelper::IsSharedPkgMgr( const uno::Reference< deployment::XPackage > &xPackage )
318 return xPackage->getRepositoryName() == SHARED_PACKAGE_MANAGER;
321 bool DialogHelper::continueOnSharedExtension( const uno::Reference< deployment::XPackage > &xPackage,
322 weld::Widget* pParent,
323 const char* pResID,
324 bool &bHadWarning )
326 if ( !bHadWarning && IsSharedPkgMgr( xPackage ) )
328 const SolarMutexGuard guard;
329 incBusy();
330 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
331 VclMessageType::Warning, VclButtonsType::OkCancel, DpResId(pResID)));
332 bHadWarning = true;
334 bool bRet = RET_OK == xBox->run();
335 xBox.reset();
336 decBusy();
337 return bRet;
339 else
340 return true;
343 void DialogHelper::openWebBrowser(const OUString& sURL, const OUString& sTitle)
345 if ( sURL.isEmpty() ) // Nothing to do, when the URL is empty
346 return;
350 uno::Reference< XSystemShellExecute > xSystemShellExecute(
351 SystemShellExecute::create(m_xContext));
352 //throws css::lang::IllegalArgumentException, css::system::SystemShellExecuteException
353 xSystemShellExecute->execute( sURL, OUString(), SystemShellExecuteFlags::URIS_ONLY );
355 catch ( const uno::Exception& )
357 uno::Any exc( ::cppu::getCaughtException() );
358 OUString msg( ::comphelper::anyToString( exc ) );
359 const SolarMutexGuard guard;
360 incBusy();
361 std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(getFrameWeld(),
362 VclMessageType::Warning, VclButtonsType::Ok, msg));
363 xErrorBox->set_title(sTitle);
364 xErrorBox->run();
365 xErrorBox.reset();
366 decBusy();
370 bool DialogHelper::installExtensionWarn(const OUString &rExtensionName)
372 const SolarMutexGuard guard;
374 // Check if extension installation is disabled in the expert configurations
375 if (officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionInstallation::get())
377 incBusy();
378 std::unique_ptr<weld::MessageDialog> xWarnBox(Application::CreateMessageDialog(getFrameWeld(),
379 VclMessageType::Warning, VclButtonsType::Ok,
380 DpResId(RID_STR_WARNING_INSTALL_EXTENSION_DISABLED)));
381 xWarnBox->run();
382 xWarnBox.reset();
383 decBusy();
385 return false;
388 incBusy();
389 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(getFrameWeld(),
390 VclMessageType::Warning, VclButtonsType::OkCancel,
391 DpResId(RID_STR_WARNING_INSTALL_EXTENSION)));
392 OUString sText(xInfoBox->get_primary_text());
393 sText = sText.replaceAll("%NAME", rExtensionName);
394 xInfoBox->set_primary_text(sText);
396 bool bRet = RET_OK == xInfoBox->run();
397 xInfoBox.reset();
398 decBusy();
399 return bRet;
402 bool DialogHelper::installForAllUsers(bool &bInstallForAll)
404 const SolarMutexGuard guard;
405 incBusy();
406 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(getFrameWeld(), "desktop/ui/installforalldialog.ui"));
407 std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("InstallForAllDialog"));
408 short nRet = xQuery->run();
409 xQuery.reset();
410 decBusy();
411 if (nRet == RET_CANCEL)
412 return false;
414 bInstallForAll = ( nRet == RET_NO );
415 return true;
418 void DialogHelper::PostUserEvent( const Link<void*,void>& rLink, void* pCaller )
420 if ( m_nEventID )
421 Application::RemoveUserEvent( m_nEventID );
423 m_nEventID = Application::PostUserEvent(rLink, pCaller);
426 // ExtMgrDialog
427 ExtMgrDialog::ExtMgrDialog(weld::Window *pParent, TheExtensionManager *pManager)
428 : GenericDialogController(pParent, "desktop/ui/extensionmanager.ui", "ExtensionManagerDialog")
429 , DialogHelper(pManager->getContext(), m_xDialog.get())
430 , m_sAddPackages(DpResId(RID_STR_ADD_PACKAGES))
431 , m_bHasProgress(false)
432 , m_bProgressChanged(false)
433 , m_bStartProgress(false)
434 , m_bStopProgress(false)
435 , m_bEnableWarning(false)
436 , m_bDisableWarning(false)
437 , m_bDeleteWarning(false)
438 , m_bClosed(false)
439 , m_nProgress(0)
440 , m_pManager(pManager)
441 , m_xExtensionBox(new ExtBoxWithBtns_Impl(m_xBuilder->weld_scrolled_window("scroll")))
442 , m_xExtensionBoxWnd(new weld::CustomWeld(*m_xBuilder, "extensions", *m_xExtensionBox))
443 , m_xOptionsBtn(m_xBuilder->weld_button("optionsbtn"))
444 , m_xAddBtn(m_xBuilder->weld_button("addbtn"))
445 , m_xRemoveBtn(m_xBuilder->weld_button("removebtn"))
446 , m_xEnableBtn(m_xBuilder->weld_button("enablebtn"))
447 , m_xUpdateBtn(m_xBuilder->weld_button("updatebtn"))
448 , m_xCloseBtn(m_xBuilder->weld_button("close"))
449 , m_xBundledCbx(m_xBuilder->weld_check_button("bundled"))
450 , m_xSharedCbx(m_xBuilder->weld_check_button("shared"))
451 , m_xUserCbx(m_xBuilder->weld_check_button("user"))
452 , m_xGetExtensions(m_xBuilder->weld_link_button("getextensions"))
453 , m_xProgressText(m_xBuilder->weld_label("progressft"))
454 , m_xProgressBar(m_xBuilder->weld_progress_bar("progressbar"))
455 , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
457 m_xExtensionBox->InitFromDialog(this);
459 m_xEnableBtn->set_help_id(HID_EXTENSION_MANAGER_LISTBOX_ENABLE);
461 m_xOptionsBtn->connect_clicked( LINK( this, ExtMgrDialog, HandleOptionsBtn ) );
462 m_xAddBtn->connect_clicked( LINK( this, ExtMgrDialog, HandleAddBtn ) );
463 m_xRemoveBtn->connect_clicked( LINK( this, ExtMgrDialog, HandleRemoveBtn ) );
464 m_xEnableBtn->connect_clicked( LINK( this, ExtMgrDialog, HandleEnableBtn ) );
465 m_xCloseBtn->connect_clicked( LINK( this, ExtMgrDialog, HandleCloseBtn ) );
467 m_xCancelBtn->connect_clicked( LINK( this, ExtMgrDialog, HandleCancelBtn ) );
469 m_xBundledCbx->connect_clicked( LINK( this, ExtMgrDialog, HandleExtTypeCbx ) );
470 m_xSharedCbx->connect_clicked( LINK( this, ExtMgrDialog, HandleExtTypeCbx ) );
471 m_xUserCbx->connect_clicked( LINK( this, ExtMgrDialog, HandleExtTypeCbx ) );
473 m_xBundledCbx->set_active(true);
474 m_xSharedCbx->set_active(true);
475 m_xUserCbx->set_active(true);
477 m_xProgressBar->hide();
479 #if ENABLE_EXTENSION_UPDATE
480 m_xUpdateBtn->connect_clicked( LINK( this, ExtMgrDialog, HandleUpdateBtn ) );
481 m_xUpdateBtn->set_sensitive(false);
482 #else
483 m_xUpdateBtn->hide();
484 #endif
486 if (officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionInstallation::get())
488 m_xAddBtn->set_sensitive(false);
489 m_xAddBtn->set_tooltip_text(DpResId(RID_STR_WARNING_INSTALL_EXTENSION_DISABLED));
491 if (officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionRemoval::get())
493 m_xRemoveBtn->set_sensitive(false);
494 m_xRemoveBtn->set_tooltip_text(DpResId(RID_STR_WARNING_REMOVE_EXTENSION_DISABLED));
497 m_aIdle.SetPriority(TaskPriority::LOWEST);
498 m_aIdle.SetDebugName( "ExtMgrDialog m_aIdle TimeOutHdl" );
499 m_aIdle.SetInvokeHandler( LINK( this, ExtMgrDialog, TimeOutHdl ) );
502 ExtMgrDialog::~ExtMgrDialog()
504 m_aIdle.Stop();
507 void ExtMgrDialog::setGetExtensionsURL( const OUString &rURL )
509 m_xGetExtensions->set_uri( rURL );
512 void ExtMgrDialog::addPackageToList( const uno::Reference< deployment::XPackage > &xPackage,
513 bool bLicenseMissing )
515 const SolarMutexGuard aGuard;
516 m_xUpdateBtn->set_sensitive(true);
518 if (m_xBundledCbx->get_active() && (xPackage->getRepositoryName() == BUNDLED_PACKAGE_MANAGER) )
520 m_xExtensionBox->addEntry( xPackage, bLicenseMissing );
522 else if (m_xSharedCbx->get_active() && (xPackage->getRepositoryName() == SHARED_PACKAGE_MANAGER) )
524 m_xExtensionBox->addEntry( xPackage, bLicenseMissing );
526 else if (m_xUserCbx->get_active() && (xPackage->getRepositoryName() == USER_PACKAGE_MANAGER ))
528 m_xExtensionBox->addEntry( xPackage, bLicenseMissing );
532 void ExtMgrDialog::prepareChecking()
534 m_xExtensionBox->prepareChecking();
537 void ExtMgrDialog::checkEntries()
539 const SolarMutexGuard guard;
540 m_xExtensionBox->checkEntries();
543 bool ExtMgrDialog::removeExtensionWarn(const OUString &rExtensionName)
545 const SolarMutexGuard guard;
546 incBusy();
547 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
548 VclMessageType::Warning, VclButtonsType::OkCancel,
549 DpResId(RID_STR_WARNING_REMOVE_EXTENSION)));
551 OUString sText(xInfoBox->get_primary_text());
552 sText = sText.replaceAll("%NAME", rExtensionName);
553 xInfoBox->set_primary_text(sText);
555 bool bRet = RET_OK == xInfoBox->run();
556 xInfoBox.reset();
557 decBusy();
559 return bRet;
562 void ExtMgrDialog::enablePackage( const uno::Reference< deployment::XPackage > &xPackage,
563 bool bEnable )
565 if ( !xPackage.is() )
566 return;
568 if ( bEnable )
570 if (!continueOnSharedExtension(xPackage, m_xDialog.get(), RID_STR_WARNING_ENABLE_SHARED_EXTENSION, m_bEnableWarning))
571 return;
573 else
575 if (!continueOnSharedExtension(xPackage, m_xDialog.get(), RID_STR_WARNING_DISABLE_SHARED_EXTENSION, m_bDisableWarning))
576 return;
579 m_pManager->getCmdQueue()->enableExtension( xPackage, bEnable );
583 void ExtMgrDialog::removePackage( const uno::Reference< deployment::XPackage > &xPackage )
585 if ( !xPackage.is() )
586 return;
588 if ( !IsSharedPkgMgr( xPackage ) || m_bDeleteWarning )
590 if ( ! removeExtensionWarn( xPackage->getDisplayName() ) )
591 return;
594 if (!continueOnSharedExtension(xPackage, m_xDialog.get(), RID_STR_WARNING_REMOVE_SHARED_EXTENSION, m_bDeleteWarning))
595 return;
597 m_pManager->getCmdQueue()->removeExtension( xPackage );
601 void ExtMgrDialog::updatePackage( const uno::Reference< deployment::XPackage > &xPackage )
603 if ( !xPackage.is() )
604 return;
606 // get the extension with highest version
607 uno::Sequence<uno::Reference<deployment::XPackage> > seqExtensions =
608 m_pManager->getExtensionManager()->getExtensionsWithSameIdentifier(
609 dp_misc::getIdentifier(xPackage), xPackage->getName(), uno::Reference<ucb::XCommandEnvironment>());
610 uno::Reference<deployment::XPackage> extension =
611 dp_misc::getExtensionWithHighestVersion(seqExtensions);
612 OSL_ASSERT(extension.is());
613 std::vector< css::uno::Reference< css::deployment::XPackage > > vEntries;
614 vEntries.push_back(extension);
616 m_pManager->getCmdQueue()->checkForUpdates( vEntries );
620 bool ExtMgrDialog::acceptLicense( const uno::Reference< deployment::XPackage > &xPackage )
622 if ( !xPackage.is() )
623 return false;
625 m_pManager->getCmdQueue()->acceptLicense( xPackage );
627 return true;
631 uno::Sequence< OUString > ExtMgrDialog::raiseAddPicker()
633 sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, m_xDialog.get());
634 const uno::Reference<ui::dialogs::XFilePicker3>& xFilePicker = aDlgHelper.GetFilePicker();
635 xFilePicker->setTitle( m_sAddPackages );
637 if ( !m_sLastFolderURL.isEmpty() )
638 xFilePicker->setDisplayDirectory( m_sLastFolderURL );
640 // collect and set filter list:
641 typedef std::map< OUString, OUString > t_string2string;
642 t_string2string title2filter;
643 OUString sDefaultFilter( StrAllFiles::get() );
645 const uno::Sequence< uno::Reference< deployment::XPackageTypeInfo > > packageTypes(
646 m_pManager->getExtensionManager()->getSupportedPackageTypes() );
648 for ( sal_Int32 pos = 0; pos < packageTypes.getLength(); ++pos )
650 uno::Reference< deployment::XPackageTypeInfo > const & xPackageType = packageTypes[ pos ];
651 const OUString filter( xPackageType->getFileFilter() );
652 if (!filter.isEmpty())
654 const OUString title( xPackageType->getShortDescription() );
655 const std::pair< t_string2string::iterator, bool > insertion(
656 title2filter.emplace( title, filter ) );
657 if ( ! insertion.second )
658 { // already existing, append extensions:
659 OUStringBuffer buf;
660 buf.append( insertion.first->second );
661 buf.append( ';' );
662 buf.append( filter );
663 insertion.first->second = buf.makeStringAndClear();
665 if ( xPackageType->getMediaType() == "application/vnd.sun.star.package-bundle" )
666 sDefaultFilter = title;
670 // All files at top:
671 xFilePicker->appendFilter( StrAllFiles::get(), "*.*" );
672 // then supported ones:
673 for (auto const& elem : title2filter)
677 xFilePicker->appendFilter( elem.first, elem.second );
679 catch (const lang::IllegalArgumentException &)
681 TOOLS_WARN_EXCEPTION( "desktop", "" );
684 xFilePicker->setCurrentFilter( sDefaultFilter );
686 if ( xFilePicker->execute() != ui::dialogs::ExecutableDialogResults::OK )
687 return uno::Sequence<OUString>(); // cancelled
689 m_sLastFolderURL = xFilePicker->getDisplayDirectory();
690 uno::Sequence< OUString > files( xFilePicker->getSelectedFiles() );
691 OSL_ASSERT( files.hasElements() );
692 return files;
695 void ExtMgrDialog::enableOptionsButton( bool bEnable )
697 m_xOptionsBtn->set_sensitive( bEnable );
700 void ExtMgrDialog::enableRemoveButton( bool bEnable )
702 m_xRemoveBtn->set_sensitive( bEnable && !officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionRemoval::get());
704 if (officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionRemoval::get())
706 m_xRemoveBtn->set_tooltip_text(DpResId(RID_STR_WARNING_REMOVE_EXTENSION_DISABLED));
708 else
710 m_xRemoveBtn->set_tooltip_text("");
714 void ExtMgrDialog::enableEnableButton( bool bEnable )
716 m_xEnableBtn->set_sensitive( bEnable );
719 void ExtMgrDialog::enableButtontoEnable( bool bEnable )
721 if (bEnable)
723 m_xEnableBtn->set_label( DpResId( RID_CTX_ITEM_ENABLE ) );
724 m_xEnableBtn->set_help_id( HID_EXTENSION_MANAGER_LISTBOX_ENABLE );
726 else
728 m_xEnableBtn->set_label( DpResId( RID_CTX_ITEM_DISABLE ) );
729 m_xEnableBtn->set_help_id( HID_EXTENSION_MANAGER_LISTBOX_DISABLE );
733 IMPL_LINK_NOARG(ExtMgrDialog, HandleCancelBtn, weld::Button&, void)
735 if ( m_xAbortChannel.is() )
739 m_xAbortChannel->sendAbort();
741 catch ( const uno::RuntimeException & )
743 OSL_FAIL( "### unexpected RuntimeException!" );
748 IMPL_LINK_NOARG(ExtMgrDialog, HandleCloseBtn, weld::Button&, void)
750 bool bCallClose = true;
752 //only suggest restart if modified and this is the first close attempt
753 if (!m_bClosed && m_pManager->isModified())
755 m_pManager->clearModified();
757 //only suggest restart if we're actually running, e.g. not from standalone unopkg gui
758 if (dp_misc::office_is_running())
760 SolarMutexGuard aGuard;
761 bCallClose = !::svtools::executeRestartDialog(comphelper::getProcessComponentContext(),
762 m_xDialog.get(),
763 svtools::RESTART_REASON_EXTENSION_INSTALL);
767 if (bCallClose)
768 m_xDialog->response(RET_CANCEL);
771 IMPL_LINK( ExtMgrDialog, startProgress, void*, _bLockInterface, void )
773 ::osl::MutexGuard aGuard( m_aMutex );
774 bool bLockInterface = static_cast<bool>(_bLockInterface);
776 if ( m_bStartProgress && !m_bHasProgress )
777 m_aIdle.Start();
779 if ( m_bStopProgress )
781 if ( m_xProgressBar->get_visible() )
782 m_xProgressBar->set_percentage( 100 );
783 m_xAbortChannel.clear();
785 SAL_INFO( "desktop.deployment", " startProgress handler: stop" );
787 else
789 SAL_INFO( "desktop.deployment", " startProgress handler: start" );
792 m_xCancelBtn->set_sensitive( bLockInterface );
793 m_xAddBtn->set_sensitive( !bLockInterface && !officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionInstallation::get());
794 if (officecfg::Office::ExtensionManager::ExtensionSecurity::DisableExtensionInstallation::get())
796 m_xAddBtn->set_tooltip_text(DpResId(RID_STR_WARNING_INSTALL_EXTENSION_DISABLED));
798 else
800 m_xAddBtn->set_tooltip_text("");
803 m_xUpdateBtn->set_sensitive( !bLockInterface && m_xExtensionBox->getItemCount() );
804 m_xExtensionBox->enableButtons( !bLockInterface );
806 clearEventID();
810 void ExtMgrDialog::showProgress( bool _bStart )
812 ::osl::MutexGuard aGuard( m_aMutex );
814 bool bStart = _bStart;
816 if ( bStart )
818 m_nProgress = 0;
819 m_bStartProgress = true;
820 SAL_INFO( "desktop.deployment", "showProgress start" );
822 else
824 m_nProgress = 100;
825 m_bStopProgress = true;
826 SAL_INFO( "desktop.deployment", "showProgress stop!" );
829 DialogHelper::PostUserEvent( LINK( this, ExtMgrDialog, startProgress ), reinterpret_cast<void*>(bStart) );
830 m_aIdle.Start();
834 void ExtMgrDialog::updateProgress( const long nProgress )
836 if ( m_nProgress != nProgress )
838 ::osl::MutexGuard aGuard( m_aMutex );
839 m_nProgress = nProgress;
840 m_aIdle.Start();
845 void ExtMgrDialog::updateProgress( const OUString &rText,
846 const uno::Reference< task::XAbortChannel > &xAbortChannel)
848 ::osl::MutexGuard aGuard( m_aMutex );
850 m_xAbortChannel = xAbortChannel;
851 m_sProgressText = rText;
852 m_bProgressChanged = true;
853 m_aIdle.Start();
857 void ExtMgrDialog::updatePackageInfo( const uno::Reference< deployment::XPackage > &xPackage )
859 const SolarMutexGuard aGuard;
860 m_xExtensionBox->updateEntry( xPackage );
863 IMPL_LINK_NOARG(ExtMgrDialog, HandleOptionsBtn, weld::Button&, void)
865 const sal_Int32 nActive = m_xExtensionBox->getSelIndex();
867 if ( nActive != ExtensionBox_Impl::ENTRY_NOTFOUND )
869 SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
871 OUString sExtensionId = m_xExtensionBox->GetEntryData( nActive )->m_xPackage->getIdentifier().Value;
872 ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateOptionsDialog(m_xDialog.get(), sExtensionId));
874 pDlg->Execute();
878 IMPL_LINK_NOARG(ExtMgrDialog, HandleAddBtn, weld::Button&, void)
880 incBusy();
882 uno::Sequence< OUString > aFileList = raiseAddPicker();
884 if ( aFileList.hasElements() )
886 m_pManager->installPackage( aFileList[0] );
889 decBusy();
892 IMPL_LINK_NOARG(ExtMgrDialog, HandleRemoveBtn, weld::Button&, void)
894 const sal_Int32 nActive = m_xExtensionBox->getSelIndex();
896 if ( nActive != ExtensionBox_Impl::ENTRY_NOTFOUND )
898 TEntry_Impl pEntry = m_xExtensionBox->GetEntryData( nActive );
899 removePackage( pEntry->m_xPackage );
903 IMPL_LINK_NOARG(ExtMgrDialog, HandleEnableBtn, weld::Button&, void)
905 const sal_Int32 nActive = m_xExtensionBox->getSelIndex();
907 if ( nActive != ExtensionBox_Impl::ENTRY_NOTFOUND )
909 TEntry_Impl pEntry = m_xExtensionBox->GetEntryData( nActive );
911 if ( pEntry->m_bMissingLic )
912 acceptLicense( pEntry->m_xPackage );
913 else
915 const bool bEnable( pEntry->m_eState != REGISTERED );
916 enablePackage( pEntry->m_xPackage, bEnable );
921 IMPL_LINK_NOARG(ExtMgrDialog, HandleExtTypeCbx, weld::Button&, void)
923 // re-creates the list of packages with addEntry selecting the packages
924 prepareChecking();
925 m_pManager->createPackageList();
926 checkEntries();
929 IMPL_LINK_NOARG(ExtMgrDialog, HandleUpdateBtn, weld::Button&, void)
931 #if ENABLE_EXTENSION_UPDATE
932 m_pManager->checkUpdates();
933 #else
934 (void) this;
935 #endif
938 IMPL_LINK_NOARG(ExtMgrDialog, TimeOutHdl, Timer *, void)
940 if ( m_bStopProgress )
942 m_bHasProgress = false;
943 m_bStopProgress = false;
944 m_xProgressText->hide();
945 m_xProgressBar->hide();
946 m_xCancelBtn->hide();
948 else
950 if ( m_bProgressChanged )
952 m_bProgressChanged = false;
953 m_xProgressText->set_label(m_sProgressText);
956 if ( m_bStartProgress )
958 m_bStartProgress = false;
959 m_bHasProgress = true;
960 m_xProgressBar->show();
961 m_xProgressText->show();
962 m_xCancelBtn->set_sensitive(true);
963 m_xCancelBtn->show();
966 if ( m_xProgressBar->get_visible() )
967 m_xProgressBar->set_percentage( static_cast<sal_uInt16>(m_nProgress) );
971 void ExtMgrDialog::Close()
973 m_pManager->terminateDialog();
974 m_bClosed = true;
977 //UpdateRequiredDialog
978 UpdateRequiredDialog::UpdateRequiredDialog(weld::Window *pParent, TheExtensionManager *pManager)
979 : GenericDialogController(pParent, "desktop/ui/updaterequireddialog.ui", "UpdateRequiredDialog")
980 , DialogHelper(pManager->getContext(), m_xDialog.get())
981 , m_sCloseText(DpResId(RID_STR_CLOSE_BTN))
982 , m_bHasProgress(false)
983 , m_bProgressChanged(false)
984 , m_bStartProgress(false)
985 , m_bStopProgress(false)
986 , m_bHasLockedEntries(false)
987 , m_nProgress(0)
988 , m_pManager(pManager)
989 , m_xExtensionBox(new ExtensionBox_Impl(m_xBuilder->weld_scrolled_window("scroll")))
990 , m_xExtensionBoxWnd(new weld::CustomWeld(*m_xBuilder, "extensions", *m_xExtensionBox))
991 , m_xUpdateNeeded(m_xBuilder->weld_label("updatelabel"))
992 , m_xUpdateBtn(m_xBuilder->weld_button("ok"))
993 , m_xCloseBtn(m_xBuilder->weld_button("disable"))
994 , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
995 , m_xProgressText(m_xBuilder->weld_label("progresslabel"))
996 , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
998 m_xExtensionBox->setExtensionManager(pManager);
1000 m_xUpdateBtn->connect_clicked( LINK( this, UpdateRequiredDialog, HandleUpdateBtn ) );
1001 m_xCloseBtn->connect_clicked( LINK( this, UpdateRequiredDialog, HandleCloseBtn ) );
1002 m_xCancelBtn->connect_clicked( LINK( this, UpdateRequiredDialog, HandleCancelBtn ) );
1004 OUString aText = m_xUpdateNeeded->get_label();
1005 aText = aText.replaceAll(
1006 "%PRODUCTNAME", utl::ConfigManager::getProductName());
1007 m_xUpdateNeeded->set_label(aText);
1009 m_xProgressBar->hide();
1010 m_xUpdateBtn->set_sensitive( false );
1011 m_xCloseBtn->grab_focus();
1013 m_aIdle.SetPriority( TaskPriority::LOWEST );
1014 m_aIdle.SetDebugName( "UpdateRequiredDialog m_aIdle TimeOutHdl" );
1015 m_aIdle.SetInvokeHandler( LINK( this, UpdateRequiredDialog, TimeOutHdl ) );
1018 UpdateRequiredDialog::~UpdateRequiredDialog()
1020 m_aIdle.Stop();
1023 void UpdateRequiredDialog::addPackageToList( const uno::Reference< deployment::XPackage > &xPackage,
1024 bool bLicenseMissing )
1026 // We will only add entries to the list with unsatisfied dependencies
1027 if ( !bLicenseMissing && !checkDependencies( xPackage ) )
1029 m_bHasLockedEntries |= m_pManager->isReadOnly( xPackage );
1030 const SolarMutexGuard aGuard;
1031 m_xUpdateBtn->set_sensitive(true);
1032 m_xExtensionBox->addEntry( xPackage );
1037 void UpdateRequiredDialog::prepareChecking()
1039 m_xExtensionBox->prepareChecking();
1043 void UpdateRequiredDialog::checkEntries()
1045 const SolarMutexGuard guard;
1046 m_xExtensionBox->checkEntries();
1048 if ( ! hasActiveEntries() )
1050 m_xCloseBtn->set_label( m_sCloseText );
1051 m_xCloseBtn->grab_focus();
1056 IMPL_LINK_NOARG(UpdateRequiredDialog, HandleCancelBtn, weld::Button&, void)
1058 if ( m_xAbortChannel.is() )
1062 m_xAbortChannel->sendAbort();
1064 catch ( const uno::RuntimeException & )
1066 OSL_FAIL( "### unexpected RuntimeException!" );
1072 IMPL_LINK( UpdateRequiredDialog, startProgress, void*, _bLockInterface, void )
1074 ::osl::MutexGuard aGuard( m_aMutex );
1075 bool bLockInterface = static_cast<bool>(_bLockInterface);
1077 if ( m_bStartProgress && !m_bHasProgress )
1078 m_aIdle.Start();
1080 if ( m_bStopProgress )
1082 if ( m_xProgressBar->get_visible() )
1083 m_xProgressBar->set_percentage( 100 );
1084 m_xAbortChannel.clear();
1085 SAL_INFO( "desktop.deployment", " startProgress handler: stop" );
1087 else
1089 SAL_INFO( "desktop.deployment", " startProgress handler: start" );
1092 m_xCancelBtn->set_sensitive( bLockInterface );
1093 m_xUpdateBtn->set_sensitive( false );
1094 clearEventID();
1098 void UpdateRequiredDialog::showProgress( bool _bStart )
1100 ::osl::MutexGuard aGuard( m_aMutex );
1102 bool bStart = _bStart;
1104 if ( bStart )
1106 m_nProgress = 0;
1107 m_bStartProgress = true;
1108 SAL_INFO( "desktop.deployment", "showProgress start" );
1110 else
1112 m_nProgress = 100;
1113 m_bStopProgress = true;
1114 SAL_INFO( "desktop.deployment", "showProgress stop!" );
1117 DialogHelper::PostUserEvent( LINK( this, UpdateRequiredDialog, startProgress ), reinterpret_cast<void*>(bStart) );
1118 m_aIdle.Start();
1122 void UpdateRequiredDialog::updateProgress( const long nProgress )
1124 if ( m_nProgress != nProgress )
1126 ::osl::MutexGuard aGuard( m_aMutex );
1127 m_nProgress = nProgress;
1128 m_aIdle.Start();
1133 void UpdateRequiredDialog::updateProgress( const OUString &rText,
1134 const uno::Reference< task::XAbortChannel > &xAbortChannel)
1136 ::osl::MutexGuard aGuard( m_aMutex );
1138 m_xAbortChannel = xAbortChannel;
1139 m_sProgressText = rText;
1140 m_bProgressChanged = true;
1141 m_aIdle.Start();
1145 void UpdateRequiredDialog::updatePackageInfo( const uno::Reference< deployment::XPackage > &xPackage )
1147 // We will remove all updated packages with satisfied dependencies, but
1148 // we will show all disabled entries so the user sees the result
1149 // of the 'disable all' button
1150 const SolarMutexGuard aGuard;
1151 if ( isEnabled( xPackage ) && checkDependencies( xPackage ) )
1152 m_xExtensionBox->removeEntry( xPackage );
1153 else
1154 m_xExtensionBox->updateEntry( xPackage );
1156 if ( ! hasActiveEntries() )
1158 m_xCloseBtn->set_label( m_sCloseText );
1159 m_xCloseBtn->grab_focus();
1164 IMPL_LINK_NOARG(UpdateRequiredDialog, HandleUpdateBtn, weld::Button&, void)
1166 ::osl::ClearableMutexGuard aGuard( m_aMutex );
1168 std::vector< uno::Reference< deployment::XPackage > > vUpdateEntries;
1169 sal_Int32 nCount = m_xExtensionBox->GetEntryCount();
1171 for ( sal_Int32 i = 0; i < nCount; ++i )
1173 TEntry_Impl pEntry = m_xExtensionBox->GetEntryData( i );
1174 vUpdateEntries.push_back( pEntry->m_xPackage );
1177 aGuard.clear();
1179 m_pManager->getCmdQueue()->checkForUpdates( vUpdateEntries );
1183 IMPL_LINK_NOARG(UpdateRequiredDialog, HandleCloseBtn, weld::Button&, void)
1185 ::osl::MutexGuard aGuard( m_aMutex );
1187 if ( !isBusy() )
1189 if ( m_bHasLockedEntries )
1190 m_xDialog->response(-1);
1191 else if ( hasActiveEntries() )
1192 disableAllEntries();
1193 else
1194 m_xDialog->response(RET_CANCEL);
1199 IMPL_LINK_NOARG(UpdateRequiredDialog, TimeOutHdl, Timer *, void)
1201 if ( m_bStopProgress )
1203 m_bHasProgress = false;
1204 m_bStopProgress = false;
1205 m_xProgressText->hide();
1206 m_xProgressBar->hide();
1207 m_xCancelBtn->hide();
1209 else
1211 if ( m_bProgressChanged )
1213 m_bProgressChanged = false;
1214 m_xProgressText->set_label( m_sProgressText );
1217 if ( m_bStartProgress )
1219 m_bStartProgress = false;
1220 m_bHasProgress = true;
1221 m_xProgressBar->show();
1222 m_xProgressText->show();
1223 m_xCancelBtn->set_sensitive(true);
1224 m_xCancelBtn->show();
1227 if (m_xProgressBar->get_visible())
1228 m_xProgressBar->set_percentage(m_nProgress);
1232 // VCL::Dialog
1233 short UpdateRequiredDialog::run()
1235 //ToDo
1236 //I believe m_bHasLockedEntries was used to prevent showing extensions which cannot
1237 //be disabled because they are in a read only repository. However, disabling extensions
1238 //is now always possible because the registration data of all repositories
1239 //are in the user installation.
1240 //Therefore all extensions could be displayed and all the handling around m_bHasLockedEntries
1241 //could be removed.
1242 if ( m_bHasLockedEntries )
1244 // Set other text, disable update btn, remove not shared entries from list;
1245 m_xUpdateNeeded->set_label( DpResId( RID_STR_NO_ADMIN_PRIVILEGE ) );
1246 m_xCloseBtn->set_label( DpResId( RID_STR_EXIT_BTN ) );
1247 m_xUpdateBtn->set_sensitive( false );
1248 m_xExtensionBox->RemoveUnlocked();
1251 return GenericDialogController::run();
1254 // Check dependencies of all packages
1256 bool UpdateRequiredDialog::isEnabled( const uno::Reference< deployment::XPackage > &xPackage )
1258 bool bRegistered = false;
1259 try {
1260 beans::Optional< beans::Ambiguous< sal_Bool > > option( xPackage->isRegistered( uno::Reference< task::XAbortChannel >(),
1261 uno::Reference< ucb::XCommandEnvironment >() ) );
1262 if ( option.IsPresent )
1264 ::beans::Ambiguous< sal_Bool > const & reg = option.Value;
1265 if ( reg.IsAmbiguous )
1266 bRegistered = false;
1267 else
1268 bRegistered = reg.Value;
1270 else
1271 bRegistered = false;
1273 catch ( const uno::RuntimeException & ) { throw; }
1274 catch (const uno::Exception & ) {
1275 TOOLS_WARN_EXCEPTION( "desktop", "" );
1276 bRegistered = false;
1279 return bRegistered;
1282 // Checks the dependencies no matter if the extension is enabled or disabled!
1283 bool UpdateRequiredDialog::checkDependencies( const uno::Reference< deployment::XPackage > &xPackage )
1285 bool bDependenciesValid = false;
1286 try {
1287 bDependenciesValid = xPackage->checkDependencies( uno::Reference< ucb::XCommandEnvironment >() );
1289 catch ( const deployment::DeploymentException & ) {}
1290 return bDependenciesValid;
1294 bool UpdateRequiredDialog::hasActiveEntries()
1296 ::osl::MutexGuard aGuard( m_aMutex );
1298 bool bRet = false;
1299 long nCount = m_xExtensionBox->GetEntryCount();
1300 for ( long nIndex = 0; nIndex < nCount; nIndex++ )
1302 TEntry_Impl pEntry = m_xExtensionBox->GetEntryData( nIndex );
1304 if ( isEnabled(pEntry->m_xPackage) && !checkDependencies( pEntry->m_xPackage ) )
1306 bRet = true;
1307 break;
1311 return bRet;
1315 void UpdateRequiredDialog::disableAllEntries()
1317 ::osl::MutexGuard aGuard( m_aMutex );
1319 incBusy();
1321 long nCount = m_xExtensionBox->GetEntryCount();
1322 for ( long nIndex = 0; nIndex < nCount; nIndex++ )
1324 TEntry_Impl pEntry = m_xExtensionBox->GetEntryData( nIndex );
1325 m_pManager->getCmdQueue()->enableExtension( pEntry->m_xPackage, false );
1328 decBusy();
1330 if ( ! hasActiveEntries() )
1331 m_xCloseBtn->set_label( m_sCloseText );
1334 // ShowLicenseDialog
1335 ShowLicenseDialog::ShowLicenseDialog(weld::Window* pParent,
1336 const uno::Reference< deployment::XPackage> &xPackage)
1337 : GenericDialogController(pParent, "desktop/ui/showlicensedialog.ui", "ShowLicenseDialog")
1338 , m_xLicenseText(m_xBuilder->weld_text_view("textview"))
1340 m_xLicenseText->set_size_request(m_xLicenseText->get_approximate_digit_width() * 72,
1341 m_xLicenseText->get_height_rows(21));
1342 m_xLicenseText->set_text(xPackage->getLicenseText());
1345 ShowLicenseDialog::~ShowLicenseDialog()
1349 // UpdateRequiredDialogService
1351 UpdateRequiredDialogService::UpdateRequiredDialogService( SAL_UNUSED_PARAMETER uno::Sequence< uno::Any > const&,
1352 uno::Reference< uno::XComponentContext > const& xComponentContext )
1353 : m_xComponentContext( xComponentContext )
1358 // XExecutableDialog
1360 void UpdateRequiredDialogService::setTitle( OUString const & )
1365 sal_Int16 UpdateRequiredDialogService::execute()
1367 ::rtl::Reference< ::dp_gui::TheExtensionManager > xManager( TheExtensionManager::get(
1368 m_xComponentContext) );
1369 xManager->createDialog( true );
1370 sal_Int16 nRet = xManager->execute();
1372 return nRet;
1376 } //namespace dp_gui
1378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */