1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_framework.hxx" 30 #include <dispatch/helpagentdispatcher.hxx> 31 #include <threadhelp/readguard.hxx> 32 #include <threadhelp/writeguard.hxx> 33 #include <com/sun/star/awt/XWindow2.hpp> 34 #include <com/sun/star/awt/PosSize.hpp> 35 #include <com/sun/star/awt/Size.hpp> 36 #include <com/sun/star/awt/Rectangle.hpp> 37 #include <toolkit/helper/vclunohelper.hxx> 38 #include <svtools/helpopt.hxx> 39 #include <vcl/svapp.hxx> 40 #include <vcl/help.hxx> 41 42 namespace css = ::com::sun::star; 43 44 //........................................................................ 45 namespace framework 46 { 47 48 //----------------------------------------------- 49 DEFINE_XINTERFACE_4(HelpAgentDispatcher , 50 OWeakObject , 51 DIRECT_INTERFACE (css::lang::XTypeProvider ), 52 DIRECT_INTERFACE (css::frame::XDispatch ), 53 DIRECT_INTERFACE (css::awt::XWindowListener), 54 DIRECT_INTERFACE (css::lang::XEventListener)) 55 56 //----------------------------------------------- 57 DEFINE_XTYPEPROVIDER_2(HelpAgentDispatcher , 58 css::lang::XTypeProvider, 59 css::frame::XDispatch ) 60 61 //-------------------------------------------------------------------- 62 HelpAgentDispatcher::HelpAgentDispatcher( const css::uno::Reference< css::frame::XFrame >& xParentFrame) 63 : ThreadHelpBase (&Application::GetSolarMutex()) 64 , m_sCurrentURL ( ) 65 , m_xContainerWindow( ) 66 , m_xAgentWindow ( ) 67 , m_aTimer ( ) 68 , m_xSelfHold ( ) 69 { 70 // It's required that this class has to be contructed with a valid frame. 71 // And "valid" means: the frame must already bound to a valid container window. 72 m_xContainerWindow = xParentFrame->getContainerWindow(); 73 } 74 75 //-------------------------------------------------------------------- 76 HelpAgentDispatcher::~HelpAgentDispatcher() 77 { 78 implts_stopTimer(); 79 implts_ignoreCurrentURL(); 80 81 // Needed ... because it was create as "new VCLWindow()" ! Such windows must be disposed explicitly. 82 css::uno::Reference< css::lang::XComponent > xAgentWindow(m_xAgentWindow, css::uno::UNO_QUERY); 83 if (xAgentWindow.is()) 84 xAgentWindow->dispose(); 85 } 86 87 //-------------------------------------------------------------------- 88 void SAL_CALL HelpAgentDispatcher::dispatch(const css::util::URL& aURL , 89 const css::uno::Sequence< css::beans::PropertyValue >&) 90 throw(css::uno::RuntimeException) 91 { 92 // silently drop the request if the new URL was marked to be ignored next time. 93 sal_Int32 nAllowedToIgnore = SvtHelpOptions().getAgentIgnoreURLCounter(aURL.Complete); 94 if (nAllowedToIgnore < 1) 95 return; 96 97 // stop the expiration timer for the old URL 98 // The timer will add the old URL to the list of ignorable URLs. 99 // So m_sCurrentURL must be set AFTER the timer was stopped !!! 100 implts_stopTimer(); 101 102 // SAFE -> 103 WriteGuard aWriteLock(m_aLock); 104 m_sCurrentURL = aURL.Complete; 105 aWriteLock.unlock(); 106 // <- SAFE 107 108 // start the expiration timer for the new URL 109 implts_startTimer(); 110 111 // make sure the agent window is shown 112 implts_showAgentWindow(); 113 } 114 115 //-------------------------------------------------------------------- 116 void SAL_CALL HelpAgentDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >&, 117 const css::util::URL&) 118 throw(css::uno::RuntimeException) 119 { 120 // no status available 121 } 122 123 //-------------------------------------------------------------------- 124 void SAL_CALL HelpAgentDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >&, 125 const css::util::URL&) 126 throw(css::uno::RuntimeException) 127 { 128 // no status available 129 } 130 131 //-------------------------------------------------------------------- 132 void SAL_CALL HelpAgentDispatcher::windowResized(const css::awt::WindowEvent&) 133 throw(css::uno::RuntimeException) 134 { 135 implts_positionAgentWindow(); 136 } 137 138 //-------------------------------------------------------------------- 139 void SAL_CALL HelpAgentDispatcher::windowMoved(const css::awt::WindowEvent&) 140 throw(css::uno::RuntimeException) 141 { 142 implts_positionAgentWindow(); 143 } 144 145 //-------------------------------------------------------------------- 146 void SAL_CALL HelpAgentDispatcher::windowShown(const css::lang::EventObject&) 147 throw(css::uno::RuntimeException) 148 { 149 implts_showAgentWindow(); 150 } 151 152 //-------------------------------------------------------------------- 153 void SAL_CALL HelpAgentDispatcher::windowHidden(const css::lang::EventObject&) 154 throw(css::uno::RuntimeException) 155 { 156 implts_hideAgentWindow(); 157 } 158 159 //-------------------------------------------------------------------- 160 void SAL_CALL HelpAgentDispatcher::disposing(const css::lang::EventObject& aEvent) 161 throw(css::uno::RuntimeException) 162 { 163 // SAFE -> 164 WriteGuard aWriteLock(m_aLock); 165 166 // Already disposed ?! 167 if (! m_xContainerWindow.is()) 168 return; 169 // Wrong broadcaster ?! 170 if (aEvent.Source != m_xContainerWindow) 171 return; 172 173 css::uno::Reference< css::uno::XInterface > xSelfHoldUntilMethodEnds(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); 174 m_xSelfHold.clear(); 175 176 aWriteLock.unlock(); 177 // <- SAFE 178 179 implts_stopTimer(); 180 implts_hideAgentWindow(); 181 implts_ignoreCurrentURL(); 182 183 // SAFE -> 184 aWriteLock.lock(); 185 m_xContainerWindow.clear(); 186 css::uno::Reference< css::lang::XComponent > xAgentWindow(m_xAgentWindow, css::uno::UNO_QUERY); 187 m_xAgentWindow.clear(); 188 aWriteLock.unlock(); 189 // <- SAFE 190 191 // Needed ... because it was create as "new VCLWindow()" ! Such windows must be disposed explicitly. 192 if (xAgentWindow.is()) 193 xAgentWindow->dispose(); 194 } 195 196 //-------------------------------------------------------------------- 197 void HelpAgentDispatcher::helpRequested() 198 { 199 implts_stopTimer(); 200 implts_hideAgentWindow(); 201 implts_acceptCurrentURL(); 202 } 203 204 //----------------------------------------------- 205 void HelpAgentDispatcher::closeAgent() 206 { 207 implts_stopTimer(); 208 implts_hideAgentWindow(); 209 implts_ignoreCurrentURL(); 210 } 211 212 //-------------------------------------------------------------------- 213 void HelpAgentDispatcher::implts_acceptCurrentURL() 214 { 215 // SAFE -> 216 WriteGuard aWriteLock(m_aLock); 217 218 ::rtl::OUString sAcceptedURL = m_sCurrentURL; 219 m_sCurrentURL = ::rtl::OUString(); 220 221 aWriteLock.unlock(); 222 // <- SAFE 223 224 // We must make sure that this URL isnt marked as ignored by the user. 225 // Otherwhise the user wont see the corresponding help content in the future. 226 SvtHelpOptions().resetAgentIgnoreURLCounter(sAcceptedURL); 227 228 // show the right help content 229 // SOLAR SAFE -> 230 { 231 ::vos::OGuard aSolarLock(Application::GetSolarMutex()); 232 Help* pHelp = Application::GetHelp(); 233 if (pHelp) 234 pHelp->Start(sAcceptedURL, NULL); 235 } 236 // <- SOLAR SAFE 237 } 238 239 //-------------------------------------------------------------------- 240 void HelpAgentDispatcher::implts_ignoreCurrentURL() 241 { 242 // SAFE -> 243 WriteGuard aWriteLock(m_aLock); 244 245 ::rtl::OUString sIgnoredURL = m_sCurrentURL; 246 m_sCurrentURL = ::rtl::OUString(); 247 248 aWriteLock.unlock(); 249 // <- SAFE 250 251 if (sIgnoredURL.getLength()) 252 SvtHelpOptions().decAgentIgnoreURLCounter(sIgnoredURL); 253 } 254 255 //-------------------------------------------------------------------- 256 void HelpAgentDispatcher::implts_stopTimer() 257 { 258 // SAFE -> 259 WriteGuard aWriteLock(m_aLock); 260 m_xSelfHold.clear(); 261 aWriteLock.unlock(); 262 // <- SAFE 263 264 // SOLAR SAFE -> 265 // Timer access needs no "own lock" ! It lives if we live ... 266 // But it requires locking of the solar mutex ... because it's a vcl based timer. 267 { 268 ::vos::OGuard aSolarLock(Application::GetSolarMutex()); 269 if (! m_aTimer.IsActive()) 270 return; 271 m_aTimer.Stop(); 272 } 273 // <- SOLAR SAFE 274 } 275 276 //-------------------------------------------------------------------- 277 void HelpAgentDispatcher::implts_startTimer() 278 { 279 // SOLAR SAFE -> 280 // Timer access needs no "own lock" ! It lives if we live ... 281 // But it requires locking of the solar mutex ... because it's a vcl based timer. 282 { 283 ::vos::OGuard aSolarLock(Application::GetSolarMutex()); 284 if (m_aTimer.IsActive()) 285 return; 286 } 287 // <- SOLAR SAFE 288 289 // SAFE -> 290 // Timer uses pointer to this help agent dispatcher ... 291 // But normaly we are ref counted. So we must make sure that this 292 // dispatcher isnt killed during the timer runs .-) 293 WriteGuard aWriteLock(m_aLock); 294 m_xSelfHold = css::uno::Reference< css::uno::XInterface >(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); 295 aWriteLock.unlock(); 296 // <- SAFE 297 298 sal_Int32 nTime = SvtHelpOptions().GetHelpAgentTimeoutPeriod(); 299 300 // SOLAR SAFE -> 301 // Timer access needs no "own lock" ! It lives if we live ... 302 // But it requires locking of the solar mutex ... because it's a vcl based timer. 303 { 304 ::vos::OGuard aSolarLock(Application::GetSolarMutex()); 305 m_aTimer.SetTimeout(nTime*1000); // sec => ms ! 306 m_aTimer.Start(); 307 } 308 } 309 310 //----------------------------------------------- 311 IMPL_LINK(HelpAgentDispatcher, implts_timerExpired, void*,) 312 { 313 // This method is called by using a pointer to us. 314 // But we must be aware that we can be destroyed hardly 315 // if our uno reference will be gone! 316 // => Hold this object alive till this method finish its work. 317 // SAFE -> 318 WriteGuard aWriteLock(m_aLock); 319 css::uno::Reference< css::uno::XInterface > xSelfHoldUntilMethodEnds(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); 320 m_xSelfHold.clear(); 321 aWriteLock.unlock(); 322 // <- SAFE 323 324 implts_hideAgentWindow(); 325 implts_ignoreCurrentURL(); 326 327 return 0; 328 } 329 330 //-------------------------------------------------------------------- 331 void HelpAgentDispatcher::implts_showAgentWindow() 332 { 333 // SAFE -> 334 ReadGuard aReadLock(m_aLock); 335 css::uno::Reference< css::awt::XWindow2 > xContainerWindow(m_xContainerWindow, css::uno::UNO_QUERY_THROW); 336 aReadLock.unlock(); 337 // <- SAFE 338 339 css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); 340 341 if ( 342 (xContainerWindow.is() ) && 343 (xAgentWindow.is() ) && 344 (xContainerWindow->isVisible()) 345 ) 346 { 347 // make sure that agent window resists at the right place .-) 348 implts_positionAgentWindow(); 349 xAgentWindow->setVisible(sal_True); 350 } 351 } 352 353 //-------------------------------------------------------------------- 354 void HelpAgentDispatcher::implts_hideAgentWindow() 355 { 356 css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); 357 if (xAgentWindow.is()) 358 xAgentWindow->setVisible(sal_False); 359 } 360 361 //-------------------------------------------------------------------- 362 void HelpAgentDispatcher::implts_positionAgentWindow() 363 { 364 // SAFE -> 365 ReadGuard aReadLock(m_aLock); 366 css::uno::Reference< css::awt::XWindow > xContainerWindow = m_xContainerWindow; 367 aReadLock.unlock(); 368 // <- SAFE 369 370 css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); 371 if ( 372 (! xContainerWindow.is()) || 373 (! xAgentWindow.is() ) 374 ) 375 return; 376 377 ::svt::HelpAgentWindow* pAgentWindow = (::svt::HelpAgentWindow*)VCLUnoHelper::GetWindow(xAgentWindow); 378 const css::awt::Rectangle aContainerSize = xContainerWindow->getPosSize(); 379 const Size aAgentSize = pAgentWindow->getPreferredSizePixel(); 380 381 sal_Int32 nW = aAgentSize.Width() ; 382 sal_Int32 nH = aAgentSize.Height(); 383 384 if (nW < 1) 385 nW = 100; 386 if (nH < 1) 387 nH = 100; 388 389 sal_Int32 nX = aContainerSize.Width - nW; 390 sal_Int32 nY = aContainerSize.Height - nH; 391 392 // TODO: use a surrogate if the container window is too small to contain the full-sized agent window 393 xAgentWindow->setPosSize(nX, nY, nW, nH, css::awt::PosSize::POSSIZE); 394 } 395 396 //-------------------------------------------------------------------- 397 css::uno::Reference< css::awt::XWindow > HelpAgentDispatcher::implts_ensureAgentWindow() 398 { 399 // SAFE -> 400 ReadGuard aReadLock(m_aLock); 401 if (m_xAgentWindow.is()) 402 return m_xAgentWindow; 403 css::uno::Reference< css::awt::XWindow > xContainerWindow = m_xContainerWindow; 404 aReadLock.unlock(); 405 // <- SAFE 406 407 if (!xContainerWindow.is()) 408 return css::uno::Reference< css::awt::XWindow >(); 409 410 ::svt::HelpAgentWindow* pAgentWindow = 0; 411 // SOLAR SAFE -> 412 { 413 ::vos::OGuard aSolarLock(Application::GetSolarMutex()); 414 // create the agent window 415 Window* pContainerWindow = VCLUnoHelper::GetWindow(xContainerWindow); 416 pAgentWindow = new ::svt::HelpAgentWindow(pContainerWindow); 417 pAgentWindow->setCallback(this); 418 } 419 // <- SOLAR SAFE 420 421 // SAFE -> 422 WriteGuard aWriteLock(m_aLock); 423 m_xAgentWindow = VCLUnoHelper::GetInterface(pAgentWindow); 424 css::uno::Reference< css::awt::XWindow > xAgentWindow = m_xAgentWindow; 425 aWriteLock.unlock(); 426 // <- SAFE 427 428 // add as window listener to the container window so we can maintain the property position of the agent window 429 xContainerWindow->addWindowListener(this); 430 431 // SOLAR SAFE -> 432 { 433 ::vos::OGuard aSolarLock(Application::GetSolarMutex()); 434 // establish callback for our internal used timer. 435 // Note: Its only active, if the timer will be started ... 436 m_aTimer.SetTimeoutHdl(LINK(this, HelpAgentDispatcher, implts_timerExpired)); 437 } 438 // <- SOLAR SAFE 439 440 return xAgentWindow; 441 } 442 443 } // namespace framework 444 445