| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 |
| |