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 31 //_______________________________________________ 32 // include own header 33 #include <jobs/helponstartup.hxx> 34 #include <threadhelp/resetableguard.hxx> 35 #include <loadenv/targethelper.hxx> 36 #include <services.h> 37 38 //_______________________________________________ 39 // include others 40 #include <comphelper/configurationhelper.hxx> 41 #include <comphelper/sequenceashashmap.hxx> 42 #include <unotools/configmgr.hxx> 43 #include <vcl/svapp.hxx> 44 #include <vcl/help.hxx> 45 #include <rtl/ustrbuf.hxx> 46 47 //_______________________________________________ 48 // include interfaces 49 #include <com/sun/star/frame/FrameSearchFlag.hpp> 50 #include <com/sun/star/frame/XFramesSupplier.hpp> 51 #include <com/sun/star/frame/XDesktop.hpp> 52 53 //_______________________________________________ 54 // namespace 55 56 namespace framework{ 57 58 //_______________________________________________ 59 // definitions 60 61 // path to module config 62 static ::rtl::OUString CFG_PACKAGE_MODULES = ::rtl::OUString::createFromAscii("/org.openoffice.Setup/Office/Factories"); 63 static ::rtl::OUString CFG_PACKAGE_SETUP = ::rtl::OUString::createFromAscii("/org.openoffice.Setup" ); 64 static ::rtl::OUString CFG_PACKAGE_COMMON = ::rtl::OUString::createFromAscii("/org.openoffice.Office.Common" ); 65 static ::rtl::OUString CFG_PATH_L10N = ::rtl::OUString::createFromAscii("L10N" ); 66 static ::rtl::OUString CFG_PATH_HELP = ::rtl::OUString::createFromAscii("Help" ); 67 static ::rtl::OUString CFG_KEY_LOCALE = ::rtl::OUString::createFromAscii("ooLocale" ); 68 static ::rtl::OUString CFG_KEY_HELPSYSTEM = ::rtl::OUString::createFromAscii("System" ); 69 70 // props of job environment 71 static ::rtl::OUString PROP_ENVIRONMENT = ::rtl::OUString::createFromAscii("Environment" ); 72 static ::rtl::OUString PROP_JOBCONFIG = ::rtl::OUString::createFromAscii("JobConfig" ); 73 static ::rtl::OUString PROP_ENVTYPE = ::rtl::OUString::createFromAscii("EnvType" ); 74 static ::rtl::OUString PROP_MODEL = ::rtl::OUString::createFromAscii("Model" ); 75 76 // props of module config 77 static ::rtl::OUString PROP_HELP_BASEURL = ::rtl::OUString::createFromAscii("ooSetupFactoryHelpBaseURL" ); 78 static ::rtl::OUString PROP_AUTOMATIC_HELP = ::rtl::OUString::createFromAscii("ooSetupFactoryHelpOnOpen" ); 79 80 // special value of job environment 81 static ::rtl::OUString ENVTYPE_DOCUMENTEVENT = ::rtl::OUString::createFromAscii("DOCUMENTEVENT" ); 82 83 //----------------------------------------------- 84 85 DEFINE_XSERVICEINFO_MULTISERVICE(HelpOnStartup , 86 ::cppu::OWeakObject , 87 SERVICENAME_JOB , 88 IMPLEMENTATIONNAME_HELPONSTARTUP) 89 90 DEFINE_INIT_SERVICE(HelpOnStartup, 91 { 92 /* Attention 93 I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() 94 to create a new instance of this class by our own supported service factory. 95 see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! 96 */ 97 // create some needed uno services and cache it 98 m_xModuleManager = css::uno::Reference< css::frame::XModuleManager >( 99 m_xSMGR->createInstance(SERVICENAME_MODULEMANAGER), 100 css::uno::UNO_QUERY_THROW); 101 102 m_xDesktop = css::uno::Reference< css::frame::XFrame >( 103 m_xSMGR->createInstance(SERVICENAME_DESKTOP), 104 css::uno::UNO_QUERY_THROW); 105 106 m_xConfig = css::uno::Reference< css::container::XNameAccess >( 107 ::comphelper::ConfigurationHelper::openConfig( 108 m_xSMGR, 109 CFG_PACKAGE_MODULES, 110 ::comphelper::ConfigurationHelper::E_READONLY), 111 css::uno::UNO_QUERY_THROW); 112 113 // ask for office locale 114 ::comphelper::ConfigurationHelper::readDirectKey( 115 m_xSMGR, 116 CFG_PACKAGE_SETUP, 117 CFG_PATH_L10N, 118 CFG_KEY_LOCALE, 119 ::comphelper::ConfigurationHelper::E_READONLY) >>= m_sLocale; 120 121 // detect system 122 ::comphelper::ConfigurationHelper::readDirectKey( 123 m_xSMGR, 124 CFG_PACKAGE_COMMON, 125 CFG_PATH_HELP, 126 CFG_KEY_HELPSYSTEM, 127 ::comphelper::ConfigurationHelper::E_READONLY) >>= m_sSystem; 128 129 // Start listening for disposing events of these services, 130 // so we can react e.g. for an office shutdown 131 css::uno::Reference< css::lang::XComponent > xComponent; 132 xComponent = css::uno::Reference< css::lang::XComponent >(m_xModuleManager, css::uno::UNO_QUERY); 133 if (xComponent.is()) 134 xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this)); 135 xComponent = css::uno::Reference< css::lang::XComponent >(m_xDesktop, css::uno::UNO_QUERY); 136 if (xComponent.is()) 137 xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this)); 138 xComponent = css::uno::Reference< css::lang::XComponent >(m_xConfig, css::uno::UNO_QUERY); 139 if (xComponent.is()) 140 xComponent->addEventListener(static_cast< css::lang::XEventListener* >(this)); 141 } 142 ) 143 144 //----------------------------------------------- 145 HelpOnStartup::HelpOnStartup(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR) 146 : ThreadHelpBase( ) 147 , m_xSMGR (xSMGR) 148 { 149 } 150 151 //----------------------------------------------- 152 HelpOnStartup::~HelpOnStartup() 153 { 154 } 155 156 //----------------------------------------------- 157 // css.task.XJob 158 css::uno::Any SAL_CALL HelpOnStartup::execute(const css::uno::Sequence< css::beans::NamedValue >& lArguments) 159 throw(css::lang::IllegalArgumentException, 160 css::uno::Exception , 161 css::uno::RuntimeException ) 162 { 163 // Analyze the given arguments; try to locate a model there and 164 // classify it's used application module. 165 ::rtl::OUString sModule = its_getModuleIdFromEnv(lArguments); 166 167 // Attention: We are bound to events for openeing any document inside the office. 168 // That includes e.g. the help module itself. But we have to do nothing then! 169 if (!sModule.getLength()) 170 return css::uno::Any(); 171 172 // check current state of the help module 173 // a) help isnt open => show default page for the detected module 174 // b) help shows any other default page(!) => show default page for the detected module 175 // c) help shows any other content => do nothing (user travelled to any other content and leaved the set of default pages) 176 ::rtl::OUString sCurrentHelpURL = its_getCurrentHelpURL(); 177 sal_Bool bCurrentHelpURLIsAnyDefaultURL = its_isHelpUrlADefaultOne(sCurrentHelpURL); 178 sal_Bool bShowIt = sal_False; 179 180 // a) 181 if (!sCurrentHelpURL.getLength()) 182 bShowIt = sal_True; 183 else 184 // b) 185 if (bCurrentHelpURLIsAnyDefaultURL) 186 bShowIt = sal_True; 187 188 if (bShowIt) 189 { 190 // retrieve the help URL for the detected application module 191 ::rtl::OUString sModuleDependendHelpURL = its_checkIfHelpEnabledAndGetURL(sModule); 192 if (sModuleDependendHelpURL.getLength()) 193 { 194 // Show this help page. 195 // Note: The help window brings itself to front ... 196 Help* pHelp = Application::GetHelp(); 197 if (pHelp) 198 pHelp->Start(sModuleDependendHelpURL, 0); 199 } 200 } 201 202 return css::uno::Any(); 203 } 204 205 //----------------------------------------------- 206 void SAL_CALL HelpOnStartup::disposing(const css::lang::EventObject& aEvent) 207 throw(css::uno::RuntimeException) 208 { 209 // SAFE -> 210 ResetableGuard aLock(m_aLock); 211 212 if (aEvent.Source == m_xModuleManager) 213 m_xModuleManager.clear(); 214 else 215 if (aEvent.Source == m_xDesktop) 216 m_xDesktop.clear(); 217 else 218 if (aEvent.Source == m_xConfig) 219 m_xConfig.clear(); 220 221 aLock.unlock(); 222 // <- SAFE 223 } 224 225 //----------------------------------------------- 226 ::rtl::OUString HelpOnStartup::its_getModuleIdFromEnv(const css::uno::Sequence< css::beans::NamedValue >& lArguments) 227 { 228 ::comphelper::SequenceAsHashMap lArgs (lArguments); 229 ::comphelper::SequenceAsHashMap lEnvironment = lArgs.getUnpackedValueOrDefault(PROP_ENVIRONMENT, css::uno::Sequence< css::beans::NamedValue >()); 230 ::comphelper::SequenceAsHashMap lJobConfig = lArgs.getUnpackedValueOrDefault(PROP_JOBCONFIG , css::uno::Sequence< css::beans::NamedValue >()); 231 232 // check for right environment. 233 // If its not a DocumentEvent, which triggered this job, 234 // we cant work correctly! => return immediatly and do nothing 235 ::rtl::OUString sEnvType = lEnvironment.getUnpackedValueOrDefault(PROP_ENVTYPE, ::rtl::OUString()); 236 if (!sEnvType.equals(ENVTYPE_DOCUMENTEVENT)) 237 return ::rtl::OUString(); 238 239 css::uno::Reference< css::frame::XModel > xDoc = lEnvironment.getUnpackedValueOrDefault(PROP_MODEL, css::uno::Reference< css::frame::XModel >()); 240 if (!xDoc.is()) 241 return ::rtl::OUString(); 242 243 // be sure that we work on top level documents only, which are registered 244 // on the desktop instance. Ignore e.g. life previews, which are top frames too ... 245 // but not registered at this global desktop instance. 246 css::uno::Reference< css::frame::XDesktop > xDesktopCheck; 247 css::uno::Reference< css::frame::XFrame > xFrame ; 248 css::uno::Reference< css::frame::XController > xController = xDoc->getCurrentController(); 249 if (xController.is()) 250 xFrame = xController->getFrame(); 251 if (xFrame.is() && xFrame->isTop()) 252 xDesktopCheck = css::uno::Reference< css::frame::XDesktop >(xFrame->getCreator(), css::uno::UNO_QUERY); 253 if (!xDesktopCheck.is()) 254 return ::rtl::OUString(); 255 256 // OK - now we are sure this document is a top level document. 257 // Classify it. 258 // SAFE -> 259 ResetableGuard aLock(m_aLock); 260 css::uno::Reference< css::frame::XModuleManager > xModuleManager = m_xModuleManager; 261 aLock.unlock(); 262 // <- SAFE 263 264 if (!xModuleManager.is()) 265 return ::rtl::OUString(); 266 267 ::rtl::OUString sModuleId; 268 try 269 { 270 sModuleId = xModuleManager->identify(xDoc); 271 } 272 catch(const css::uno::RuntimeException& exRun) 273 { throw exRun; } 274 catch(const css::uno::Exception&) 275 { sModuleId = ::rtl::OUString(); } 276 277 return sModuleId; 278 } 279 280 //----------------------------------------------- 281 ::rtl::OUString HelpOnStartup::its_getCurrentHelpURL() 282 { 283 // SAFE -> 284 ResetableGuard aLock(m_aLock); 285 css::uno::Reference< css::frame::XFrame > xDesktop = m_xDesktop; 286 aLock.unlock(); 287 // <- SAFE 288 289 if (!xDesktop.is()) 290 return ::rtl::OUString(); 291 292 css::uno::Reference< css::frame::XFrame > xHelp = xDesktop->findFrame(SPECIALTARGET_HELPTASK, css::frame::FrameSearchFlag::CHILDREN); 293 if (!xHelp.is()) 294 return ::rtl::OUString(); 295 296 ::rtl::OUString sCurrentHelpURL; 297 try 298 { 299 css::uno::Reference< css::frame::XFramesSupplier > xHelpRoot (xHelp , css::uno::UNO_QUERY_THROW); 300 css::uno::Reference< css::container::XIndexAccess > xHelpChilds(xHelpRoot->getFrames(), css::uno::UNO_QUERY_THROW); 301 302 css::uno::Reference< css::frame::XFrame > xHelpChild ; 303 css::uno::Reference< css::frame::XController > xHelpView ; 304 css::uno::Reference< css::frame::XModel > xHelpContent; 305 306 xHelpChilds->getByIndex(0) >>= xHelpChild; 307 if (xHelpChild.is()) 308 xHelpView = xHelpChild->getController(); 309 if (xHelpView.is()) 310 xHelpContent = xHelpView->getModel(); 311 if (xHelpContent.is()) 312 sCurrentHelpURL = xHelpContent->getURL(); 313 } 314 catch(css::uno::RuntimeException& exRun) 315 { throw exRun; } 316 catch(css::uno::Exception&) 317 { sCurrentHelpURL = ::rtl::OUString(); } 318 319 return sCurrentHelpURL; 320 } 321 322 //----------------------------------------------- 323 ::sal_Bool HelpOnStartup::its_isHelpUrlADefaultOne(const ::rtl::OUString& sHelpURL) 324 { 325 if (!sHelpURL.getLength()) 326 return sal_False; 327 328 // SAFE -> 329 ResetableGuard aLock(m_aLock); 330 css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR (m_xSMGR, css::uno::UNO_QUERY_THROW); 331 css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig; 332 ::rtl::OUString sLocale = m_sLocale; 333 ::rtl::OUString sSystem = m_sSystem; 334 aLock.unlock(); 335 // <- SAFE 336 337 if (!xConfig.is()) 338 return sal_False; 339 340 // check given help url against all default ones 341 const css::uno::Sequence< ::rtl::OUString > lModules = xConfig->getElementNames(); 342 const ::rtl::OUString* pModules = lModules.getConstArray(); 343 ::sal_Int32 c = lModules.getLength(); 344 ::sal_Int32 i = 0; 345 346 for (i=0; i<c; ++i) 347 { 348 try 349 { 350 css::uno::Reference< css::container::XNameAccess > xModuleConfig; 351 xConfig->getByName(pModules[i]) >>= xModuleConfig; 352 if (!xModuleConfig.is()) 353 continue; 354 355 ::rtl::OUString sHelpBaseURL; 356 xModuleConfig->getByName(PROP_HELP_BASEURL) >>= sHelpBaseURL; 357 ::rtl::OUString sHelpURLForModule = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem); 358 if (sHelpURL.equals(sHelpURLForModule)) 359 return sal_True; 360 } 361 catch(const css::uno::RuntimeException& exRun) 362 { throw exRun; } 363 catch(const css::uno::Exception&) 364 {} 365 } 366 367 return sal_False; 368 } 369 370 //----------------------------------------------- 371 ::rtl::OUString HelpOnStartup::its_checkIfHelpEnabledAndGetURL(const ::rtl::OUString& sModule) 372 { 373 // SAFE -> 374 ResetableGuard aLock(m_aLock); 375 css::uno::Reference< css::container::XNameAccess > xConfig = m_xConfig; 376 ::rtl::OUString sLocale = m_sLocale; 377 ::rtl::OUString sSystem = m_sSystem; 378 aLock.unlock(); 379 // <- SAFE 380 381 ::rtl::OUString sHelpURL; 382 383 try 384 { 385 css::uno::Reference< css::container::XNameAccess > xModuleConfig; 386 if (xConfig.is()) 387 xConfig->getByName(sModule) >>= xModuleConfig; 388 389 sal_Bool bHelpEnabled = sal_False; 390 if (xModuleConfig.is()) 391 xModuleConfig->getByName(PROP_AUTOMATIC_HELP) >>= bHelpEnabled; 392 393 if (bHelpEnabled) 394 { 395 ::rtl::OUString sHelpBaseURL; 396 xModuleConfig->getByName(PROP_HELP_BASEURL) >>= sHelpBaseURL; 397 sHelpURL = HelpOnStartup::ist_createHelpURL(sHelpBaseURL, sLocale, sSystem); 398 } 399 } 400 catch(const css::uno::RuntimeException& exRun) 401 { throw exRun; } 402 catch(const css::uno::Exception&) 403 { sHelpURL = ::rtl::OUString(); } 404 405 return sHelpURL; 406 } 407 408 //----------------------------------------------- 409 ::rtl::OUString HelpOnStartup::ist_createHelpURL(const ::rtl::OUString& sBaseURL, 410 const ::rtl::OUString& sLocale , 411 const ::rtl::OUString& sSystem ) 412 { 413 ::rtl::OUStringBuffer sHelpURL(256); 414 sHelpURL.append (sBaseURL ); 415 sHelpURL.appendAscii("?Language="); 416 sHelpURL.append (sLocale ); 417 sHelpURL.appendAscii("&System=" ); 418 sHelpURL.append (sSystem ); 419 420 return sHelpURL.makeStringAndClear(); 421 } 422 423 } // namespace framework 424