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