diff options
Diffstat (limited to 'framework/source/dispatch/helpagentdispatcher.cxx')
-rw-r--r-- | framework/source/dispatch/helpagentdispatcher.cxx | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/framework/source/dispatch/helpagentdispatcher.cxx b/framework/source/dispatch/helpagentdispatcher.cxx new file mode 100644 index 000000000000..efc373338cf8 --- /dev/null +++ b/framework/source/dispatch/helpagentdispatcher.cxx @@ -0,0 +1,444 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <dispatch/helpagentdispatcher.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <svtools/helpopt.hxx> +#include <vcl/svapp.hxx> +#include <vcl/help.hxx> + +namespace css = ::com::sun::star; + +//........................................................................ +namespace framework +{ + +//----------------------------------------------- +DEFINE_XINTERFACE_4(HelpAgentDispatcher , + OWeakObject , + DIRECT_INTERFACE (css::lang::XTypeProvider ), + DIRECT_INTERFACE (css::frame::XDispatch ), + DIRECT_INTERFACE (css::awt::XWindowListener), + DIRECT_INTERFACE (css::lang::XEventListener)) + +//----------------------------------------------- +DEFINE_XTYPEPROVIDER_2(HelpAgentDispatcher , + css::lang::XTypeProvider, + css::frame::XDispatch ) + +//-------------------------------------------------------------------- +HelpAgentDispatcher::HelpAgentDispatcher( const css::uno::Reference< css::frame::XFrame >& xParentFrame) + : ThreadHelpBase (&Application::GetSolarMutex()) + , m_sCurrentURL ( ) + , m_xContainerWindow( ) + , m_xAgentWindow ( ) + , m_aTimer ( ) + , m_xSelfHold ( ) +{ + // It's required that this class has to be contructed with a valid frame. + // And "valid" means: the frame must already bound to a valid container window. + m_xContainerWindow = xParentFrame->getContainerWindow(); +} + +//-------------------------------------------------------------------- +HelpAgentDispatcher::~HelpAgentDispatcher() +{ + implts_stopTimer(); + implts_ignoreCurrentURL(); + + // Needed ... because it was create as "new VCLWindow()" ! Such windows must be disposed explicitly. + css::uno::Reference< css::lang::XComponent > xAgentWindow(m_xAgentWindow, css::uno::UNO_QUERY); + if (xAgentWindow.is()) + xAgentWindow->dispose(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::dispatch(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >&) + throw(css::uno::RuntimeException) +{ + // silently drop the request if the new URL was marked to be ignored next time. + sal_Int32 nAllowedToIgnore = SvtHelpOptions().getAgentIgnoreURLCounter(aURL.Complete); + if (nAllowedToIgnore < 1) + return; + + // stop the expiration timer for the old URL + // The timer will add the old URL to the list of ignorable URLs. + // So m_sCurrentURL must be set AFTER the timer was stopped !!! + implts_stopTimer(); + + // SAFE -> + WriteGuard aWriteLock(m_aLock); + m_sCurrentURL = aURL.Complete; + aWriteLock.unlock(); + // <- SAFE + + // start the expiration timer for the new URL + implts_startTimer(); + + // make sure the agent window is shown + implts_showAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >&, + const css::util::URL&) + throw(css::uno::RuntimeException) +{ + // no status available +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >&, + const css::util::URL&) + throw(css::uno::RuntimeException) +{ + // no status available +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowResized(const css::awt::WindowEvent&) + throw(css::uno::RuntimeException) +{ + implts_positionAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowMoved(const css::awt::WindowEvent&) + throw(css::uno::RuntimeException) +{ + implts_positionAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowShown(const css::lang::EventObject&) + throw(css::uno::RuntimeException) +{ + implts_showAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowHidden(const css::lang::EventObject&) + throw(css::uno::RuntimeException) +{ + implts_hideAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::disposing(const css::lang::EventObject& aEvent) + throw(css::uno::RuntimeException) +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + + // Already disposed ?! + if (! m_xContainerWindow.is()) + return; + // Wrong broadcaster ?! + if (aEvent.Source != m_xContainerWindow) + return; + + css::uno::Reference< css::uno::XInterface > xSelfHoldUntilMethodEnds(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); + m_xSelfHold.clear(); + + aWriteLock.unlock(); + // <- SAFE + + implts_stopTimer(); + implts_hideAgentWindow(); + implts_ignoreCurrentURL(); + + // SAFE -> + aWriteLock.lock(); + m_xContainerWindow.clear(); + css::uno::Reference< css::lang::XComponent > xAgentWindow(m_xAgentWindow, css::uno::UNO_QUERY); + m_xAgentWindow.clear(); + aWriteLock.unlock(); + // <- SAFE + + // Needed ... because it was create as "new VCLWindow()" ! Such windows must be disposed explicitly. + if (xAgentWindow.is()) + xAgentWindow->dispose(); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::helpRequested() +{ + implts_stopTimer(); + implts_hideAgentWindow(); + implts_acceptCurrentURL(); +} + +//----------------------------------------------- +void HelpAgentDispatcher::closeAgent() +{ + implts_stopTimer(); + implts_hideAgentWindow(); + implts_ignoreCurrentURL(); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_acceptCurrentURL() +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + + ::rtl::OUString sAcceptedURL = m_sCurrentURL; + m_sCurrentURL = ::rtl::OUString(); + + aWriteLock.unlock(); + // <- SAFE + + // We must make sure that this URL isnt marked as ignored by the user. + // Otherwhise the user wont see the corresponding help content in the future. + SvtHelpOptions().resetAgentIgnoreURLCounter(sAcceptedURL); + + // show the right help content + // SOLAR SAFE -> + { + ::vos::OGuard aSolarLock(Application::GetSolarMutex()); + Help* pHelp = Application::GetHelp(); + if (pHelp) + pHelp->Start(sAcceptedURL, NULL); + } + // <- SOLAR SAFE +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_ignoreCurrentURL() +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + + ::rtl::OUString sIgnoredURL = m_sCurrentURL; + m_sCurrentURL = ::rtl::OUString(); + + aWriteLock.unlock(); + // <- SAFE + + if (sIgnoredURL.getLength()) + SvtHelpOptions().decAgentIgnoreURLCounter(sIgnoredURL); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_stopTimer() +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + m_xSelfHold.clear(); + aWriteLock.unlock(); + // <- SAFE + + // SOLAR SAFE -> + // Timer access needs no "own lock" ! It lives if we live ... + // But it requires locking of the solar mutex ... because it's a vcl based timer. + { + ::vos::OGuard aSolarLock(Application::GetSolarMutex()); + if (! m_aTimer.IsActive()) + return; + m_aTimer.Stop(); + } + // <- SOLAR SAFE +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_startTimer() +{ + // SOLAR SAFE -> + // Timer access needs no "own lock" ! It lives if we live ... + // But it requires locking of the solar mutex ... because it's a vcl based timer. + { + ::vos::OGuard aSolarLock(Application::GetSolarMutex()); + if (m_aTimer.IsActive()) + return; + } + // <- SOLAR SAFE + + // SAFE -> + // Timer uses pointer to this help agent dispatcher ... + // But normaly we are ref counted. So we must make sure that this + // dispatcher isnt killed during the timer runs .-) + WriteGuard aWriteLock(m_aLock); + m_xSelfHold = css::uno::Reference< css::uno::XInterface >(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); + aWriteLock.unlock(); + // <- SAFE + + sal_Int32 nTime = SvtHelpOptions().GetHelpAgentTimeoutPeriod(); + + // SOLAR SAFE -> + // Timer access needs no "own lock" ! It lives if we live ... + // But it requires locking of the solar mutex ... because it's a vcl based timer. + { + ::vos::OGuard aSolarLock(Application::GetSolarMutex()); + m_aTimer.SetTimeout(nTime*1000); // sec => ms ! + m_aTimer.Start(); + } +} + +//----------------------------------------------- +IMPL_LINK(HelpAgentDispatcher, implts_timerExpired, void*,) +{ + // This method is called by using a pointer to us. + // But we must be aware that we can be destroyed hardly + // if our uno reference will be gone! + // => Hold this object alive till this method finish its work. + // SAFE -> + WriteGuard aWriteLock(m_aLock); + css::uno::Reference< css::uno::XInterface > xSelfHoldUntilMethodEnds(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); + m_xSelfHold.clear(); + aWriteLock.unlock(); + // <- SAFE + + implts_hideAgentWindow(); + implts_ignoreCurrentURL(); + + return 0; +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_showAgentWindow() +{ + // SAFE -> + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::awt::XWindow2 > xContainerWindow(m_xContainerWindow, css::uno::UNO_QUERY_THROW); + aReadLock.unlock(); + // <- SAFE + + css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); + + if ( + (xContainerWindow.is() ) && + (xAgentWindow.is() ) && + (xContainerWindow->isVisible()) + ) + { + // make sure that agent window resists at the right place .-) + implts_positionAgentWindow(); + xAgentWindow->setVisible(sal_True); + } +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_hideAgentWindow() +{ + css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); + if (xAgentWindow.is()) + xAgentWindow->setVisible(sal_False); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_positionAgentWindow() +{ + // SAFE -> + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::awt::XWindow > xContainerWindow = m_xContainerWindow; + aReadLock.unlock(); + // <- SAFE + + css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); + if ( + (! xContainerWindow.is()) || + (! xAgentWindow.is() ) + ) + return; + + ::svt::HelpAgentWindow* pAgentWindow = (::svt::HelpAgentWindow*)VCLUnoHelper::GetWindow(xAgentWindow); + const css::awt::Rectangle aContainerSize = xContainerWindow->getPosSize(); + const Size aAgentSize = pAgentWindow->getPreferredSizePixel(); + + sal_Int32 nW = aAgentSize.Width() ; + sal_Int32 nH = aAgentSize.Height(); + + if (nW < 1) + nW = 100; + if (nH < 1) + nH = 100; + + sal_Int32 nX = aContainerSize.Width - nW; + sal_Int32 nY = aContainerSize.Height - nH; + + // TODO: use a surrogate if the container window is too small to contain the full-sized agent window + xAgentWindow->setPosSize(nX, nY, nW, nH, css::awt::PosSize::POSSIZE); +} + +//-------------------------------------------------------------------- +css::uno::Reference< css::awt::XWindow > HelpAgentDispatcher::implts_ensureAgentWindow() +{ + // SAFE -> + ReadGuard aReadLock(m_aLock); + if (m_xAgentWindow.is()) + return m_xAgentWindow; + css::uno::Reference< css::awt::XWindow > xContainerWindow = m_xContainerWindow; + aReadLock.unlock(); + // <- SAFE + + if (!xContainerWindow.is()) + return css::uno::Reference< css::awt::XWindow >(); + + ::svt::HelpAgentWindow* pAgentWindow = 0; + // SOLAR SAFE -> + { + ::vos::OGuard aSolarLock(Application::GetSolarMutex()); + // create the agent window + Window* pContainerWindow = VCLUnoHelper::GetWindow(xContainerWindow); + pAgentWindow = new ::svt::HelpAgentWindow(pContainerWindow); + pAgentWindow->setCallback(this); + } + // <- SOLAR SAFE + + // SAFE -> + WriteGuard aWriteLock(m_aLock); + m_xAgentWindow = VCLUnoHelper::GetInterface(pAgentWindow); + css::uno::Reference< css::awt::XWindow > xAgentWindow = m_xAgentWindow; + aWriteLock.unlock(); + // <- SAFE + + // add as window listener to the container window so we can maintain the property position of the agent window + xContainerWindow->addWindowListener(this); + + // SOLAR SAFE -> + { + ::vos::OGuard aSolarLock(Application::GetSolarMutex()); + // establish callback for our internal used timer. + // Note: Its only active, if the timer will be started ... + m_aTimer.SetTimeoutHdl(LINK(this, HelpAgentDispatcher, implts_timerExpired)); + } + // <- SOLAR SAFE + + return xAgentWindow; +} + +} // namespace framework + |