diff options
Diffstat (limited to 'fpicker/source/office/commonpicker.cxx')
-rw-r--r-- | fpicker/source/office/commonpicker.cxx | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/fpicker/source/office/commonpicker.cxx b/fpicker/source/office/commonpicker.cxx new file mode 100644 index 000000000..29ae5d08b --- /dev/null +++ b/fpicker/source/office/commonpicker.cxx @@ -0,0 +1,476 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "commonpicker.hxx" +#include "fpdialogbase.hxx" +#include "OfficeControlAccess.hxx" +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <osl/mutex.hxx> +#include <sal/log.hxx> +#include <tools/debug.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <comphelper/weakeventlistener.hxx> +#include <comphelper/types.hxx> + + +namespace svt +{ + + +#define PROPERTY_ID_HELPURL 1 +#define PROPERTY_ID_WINDOW 2 + + // using -------------------------------------------------------------- + + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::comphelper; + + + OCommonPicker::OCommonPicker() + :OCommonPicker_Base( m_aMutex ) + ,OPropertyContainer( GetBroadcastHelper() ) + ,m_nCancelEvent( nullptr ) + ,m_bExecuting( false ) + { + // the two properties we have + registerProperty( + "HelpURL", PROPERTY_ID_HELPURL, + PropertyAttribute::TRANSIENT, + &m_sHelpURL, cppu::UnoType<decltype(m_sHelpURL)>::get() + ); + + registerProperty( + "Window", PROPERTY_ID_WINDOW, + PropertyAttribute::TRANSIENT | PropertyAttribute::READONLY, + &m_xWindow, cppu::UnoType<decltype(m_xWindow)>::get() + ); + } + + + OCommonPicker::~OCommonPicker() + { + if ( !GetBroadcastHelper().bDisposed ) + { + acquire(); + dispose(); + } + } + + + // disambiguate XInterface + + IMPLEMENT_FORWARD_XINTERFACE2( OCommonPicker, OCommonPicker_Base, OPropertyContainer ) + + + // disambiguate XTypeProvider + + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCommonPicker, OCommonPicker_Base, OPropertyContainer ) + + + // XComponent related methods + + void OCommonPicker::checkAlive() const + { + if ( GetBroadcastHelper().bInDispose || GetBroadcastHelper().bDisposed ) + throw DisposedException(); + } + + void OCommonPicker::prepareDialog() + { + if(createPicker()) + { + // set the title + if ( !m_aTitle.isEmpty() ) + m_xDlg->set_title(m_aTitle); + } + } + + + void SAL_CALL OCommonPicker::disposing() + { + SolarMutexGuard aGuard; + + stopWindowListening(); + + if ( m_nCancelEvent ) + Application::RemoveUserEvent( m_nCancelEvent ); + + { + ::osl::MutexGuard aOwnGuard( m_aMutex ); + if ( m_bExecuting && m_xDlg ) + m_xDlg->response(RET_CANCEL); + } + + m_xDlg.reset(); + m_xWindow = nullptr; + m_xDialogParent = nullptr; + } + + + void OCommonPicker::stopWindowListening() + { + disposeComponent( m_xWindowListenerAdapter ); + disposeComponent( m_xParentListenerAdapter ); + } + + // XEventListener + void SAL_CALL OCommonPicker::disposing( const EventObject& _rSource ) + { + SolarMutexGuard aGuard; + bool bDialogDying = _rSource.Source == m_xWindow; + bool bParentDying = _rSource.Source == m_xDialogParent; + + if ( bDialogDying || bParentDying ) + { + stopWindowListening(); + + SAL_WARN_IF(bDialogDying && m_bExecuting, "fpicker.office", "unexpected disposing before response" ); + + // it's the parent which is dying -> delete the dialog + { + ::osl::MutexGuard aOwnGuard(m_aMutex); + if (m_bExecuting && m_xDlg) + m_xDlg->response(RET_CANCEL); + } + + m_xDlg.reset(); + m_xWindow = nullptr; + m_xDialogParent = nullptr; + } + else + { + OSL_FAIL( "OCommonPicker::disposing: where did this come from?" ); + } + } + + // property set related methods + ::cppu::IPropertyArrayHelper* OCommonPicker::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties( aProps ); + return new cppu::OPropertyArrayHelper( aProps ); + } + + ::cppu::IPropertyArrayHelper& SAL_CALL OCommonPicker::getInfoHelper() + { + return *getArrayHelper(); + } + + Reference< XPropertySetInfo > SAL_CALL OCommonPicker::getPropertySetInfo( ) + { + return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ); + } + + void SAL_CALL OCommonPicker::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) + { + OPropertyContainer::setFastPropertyValue_NoBroadcast(nHandle, rValue); + + // if the HelpURL changed, forward this to the dialog + if (PROPERTY_ID_HELPURL == nHandle && m_xDlg) + { + ::svt::OControlAccess aAccess(m_xDlg.get(), m_xDlg->GetView()); + aAccess.setHelpURL(m_xDlg->getDialog(), m_sHelpURL); + } + } + + bool OCommonPicker::createPicker() + { + if ( !m_xDlg ) + { + m_xDlg = implCreateDialog(Application::GetFrameWeld(m_xDialogParent)); + SAL_WARN_IF( !m_xDlg, "fpicker.office", "OCommonPicker::createPicker: invalid dialog returned!" ); + + if ( m_xDlg ) + { + weld::Dialog* pDlg = m_xDlg->getDialog(); + + ::svt::OControlAccess aAccess(m_xDlg.get(), m_xDlg->GetView()); + // synchronize the help id of the dialog without help URL property + if ( !m_sHelpURL.isEmpty() ) + { // somebody already set the help URL while we had no dialog yet + aAccess.setHelpURL(pDlg, m_sHelpURL); + } + else + { + m_sHelpURL = aAccess.getHelpURL(pDlg); + } + + m_xWindow = pDlg->GetXWindow(); + + // add as event listener to the window + OSL_ENSURE( m_xWindow.is(), "OCommonPicker::createFileDialog: invalid window component!" ); + if ( m_xWindow.is() ) + { + m_xWindowListenerAdapter = new OWeakEventListenerAdapter( this, m_xWindow ); + // the adapter will add itself as listener, and forward notifications + } + + VclPtr<vcl::Window> xVclDialog(VCLUnoHelper::GetWindow(m_xWindow)); + if (xVclDialog) // this block is quite possibly unnecessary by now + { + // _and_ add as event listener to the parent - in case the parent is destroyed + // before we are disposed, our disposal would access dead VCL windows then... + m_xDialogParent = VCLUnoHelper::GetInterface(xVclDialog->GetParent()); + OSL_ENSURE(m_xDialogParent.is() || !xVclDialog->GetParent(), "OCommonPicker::createFileDialog: invalid window component (the parent this time)!"); + } + if ( m_xDialogParent.is() ) + { + m_xParentListenerAdapter = new OWeakEventListenerAdapter( this, m_xDialogParent ); + // the adapter will add itself as listener, and forward notifications + } + } + } + + return nullptr != m_xDlg; + } + + // XControlAccess functions + void SAL_CALL OCommonPicker::setControlProperty( const OUString& aControlName, const OUString& aControlProperty, const Any& aValue ) + { + checkAlive(); + + SolarMutexGuard aGuard; + if ( createPicker() ) + { + ::svt::OControlAccess aAccess( m_xDlg.get(), m_xDlg->GetView() ); + aAccess.setControlProperty( aControlName, aControlProperty, aValue ); + } + } + + Any SAL_CALL OCommonPicker::getControlProperty( const OUString& aControlName, const OUString& aControlProperty ) + { + checkAlive(); + + SolarMutexGuard aGuard; + if ( createPicker() ) + { + ::svt::OControlAccess aAccess( m_xDlg.get(), m_xDlg->GetView() ); + return aAccess.getControlProperty( aControlName, aControlProperty ); + } + + return Any(); + } + + // XControlInformation functions + Sequence< OUString > SAL_CALL OCommonPicker::getSupportedControls( ) + { + checkAlive(); + + SolarMutexGuard aGuard; + if ( createPicker() ) + { + ::svt::OControlAccess aAccess( m_xDlg.get(), m_xDlg->GetView() ); + return aAccess.getSupportedControls( ); + } + + return Sequence< OUString >(); + } + + sal_Bool SAL_CALL OCommonPicker::isControlSupported( const OUString& aControlName ) + { + checkAlive(); + + SolarMutexGuard aGuard; + if ( createPicker() ) + { + return svt::OControlAccess::isControlSupported( aControlName ); + } + + return false; + } + + Sequence< OUString > SAL_CALL OCommonPicker::getSupportedControlProperties( const OUString& aControlName ) + { + checkAlive(); + + SolarMutexGuard aGuard; + if ( createPicker() ) + { + ::svt::OControlAccess aAccess( m_xDlg.get(), m_xDlg->GetView() ); + return aAccess.getSupportedControlProperties( aControlName ); + } + + return Sequence< OUString >(); + } + + sal_Bool SAL_CALL OCommonPicker::isControlPropertySupported( const OUString& aControlName, const OUString& aControlProperty ) + { + checkAlive(); + + SolarMutexGuard aGuard; + if ( createPicker() ) + { + ::svt::OControlAccess aAccess( m_xDlg.get(), m_xDlg->GetView() ); + return aAccess.isControlPropertySupported( aControlName, aControlProperty ); + } + + return false; + } + + + // XExecutableDialog functions + + void OCommonPicker::setTitle( const OUString& _rTitle ) + { + SolarMutexGuard aGuard; + m_aTitle = _rTitle; + } + + + sal_Int16 OCommonPicker::execute() + { + SolarMutexGuard aGuard; + + prepareDialog(); + + { + ::osl::MutexGuard aOwnGuard( m_aMutex ); + m_bExecuting = true; + } + sal_Int16 nResult = implExecutePicker(); + { + ::osl::MutexGuard aOwnGuard( m_aMutex ); + m_bExecuting = false; + } + + return nResult; + } + + + // XCancellable functions + + void SAL_CALL OCommonPicker::cancel( ) + { + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_nCancelEvent ) + // nothing to do - the event for cancelling the dialog is already on the way + return; + } + + // The thread which executes our dialog has locked the solar mutex for + // sure. Cancelling the dialog should be done with a locked solar mutex, too. + // Thus we post ourself a message for cancelling the dialog. This way, the message + // is either handled in the thread which opened the dialog (which may even be + // this thread here), or, if no dialog is open, in the thread doing scheduling + // currently. Both is okay for us... + + // Note that we could do check if we are really executing the dialog currently. + // but the information would be potentially obsolete at the moment our event + // arrives, so we need to check it there, anyway... + m_nCancelEvent = Application::PostUserEvent( LINK( this, OCommonPicker, OnCancelPicker ) ); + } + + IMPL_LINK_NOARG(OCommonPicker, OnCancelPicker, void*, void) + { + // By definition, the solar mutex is locked when we arrive here. Note that this + // is important, as for instance the consistency of m_xDlg depends on this mutex. + ::osl::MutexGuard aGuard( m_aMutex ); + m_nCancelEvent = nullptr; + + if ( !m_bExecuting ) + // nothing to do. This may be because the dialog was canceled after our cancel method + // posted this async event, or because somebody called cancel without the dialog + // being executed at this time. + return; + + OSL_ENSURE( m_xDlg, "OCommonPicker::OnCancelPicker: executing, but no dialog!" ); + if (m_xDlg) + m_xDlg->response(RET_CANCEL); + } + + // XInitialization functions + void SAL_CALL OCommonPicker::initialize( const Sequence< Any >& _rArguments ) + { + checkAlive(); + + OUString sSettingName; + Any aSettingValue; + + PropertyValue aPropArg; + NamedValue aPairArg; + + + const Any* pArguments = _rArguments.getConstArray(); + const Any* pArgumentsEnd = _rArguments.getConstArray() + _rArguments.getLength(); + for ( const Any* pArgument = pArguments; + pArgument != pArgumentsEnd; + ++pArgument + ) + { + if ( *pArgument >>= aPropArg ) + { + if ( aPropArg.Name.isEmpty()) + continue; + + sSettingName = aPropArg.Name; + aSettingValue = aPropArg.Value; + } + else if ( *pArgument >>= aPairArg ) + { + if ( aPairArg.Name.isEmpty()) + continue; + + sSettingName = aPairArg.Name; + aSettingValue = aPairArg.Value; + + + } + else + { + SAL_WARN( "fpicker", "OCommonPicker::initialize: unknown argument type at position " + << (pArguments - _rArguments.getConstArray())); + continue; + } + + bool bKnownSetting = + implHandleInitializationArgument( sSettingName, aSettingValue ); + DBG_ASSERT( bKnownSetting, + OString( + "OCommonPicker::initialize: unknown argument \"" + + OString(sSettingName.getStr(), sSettingName.getLength(), osl_getThreadTextEncoding()) + + "\"!").getStr() ); + } + } + + bool OCommonPicker::implHandleInitializationArgument( const OUString& _rName, const Any& _rValue ) + { + bool bKnown = true; + if ( _rName == "ParentWindow" ) + { + m_xDialogParent.clear(); + OSL_VERIFY( _rValue >>= m_xDialogParent ); + OSL_ENSURE( m_xDialogParent.is(), "OCommonPicker::implHandleInitializationArgument: invalid parent window given!" ); + } + else + bKnown = false; + return bKnown; + } + +} // namespace svt + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |