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 // my own includes 29 //_________________________________________________________________________________________________________________ 30 #include <services/license.hxx> 31 #include <threadhelp/resetableguard.hxx> 32 #include <macros/debug.hxx> 33 #include <services.h> 34 35 // local header for UI implementation 36 #include "services/licensedlg.hxx" 37 #include "classes/resource.hrc" 38 39 //_________________________________________________________________________________________________________________ 40 // interface includes 41 //_________________________________________________________________________________________________________________ 42 43 #include <com/sun/star/frame/XDesktop.hpp> 44 #include <com/sun/star/lang/XInitialization.hpp> 45 #include <com/sun/star/beans/XPropertySet.hpp> 46 #include <com/sun/star/uno/Any.hxx> 47 #include <com/sun/star/util/XChangesBatch.hpp> 48 #include <com/sun/star/beans/NamedValue.hpp> 49 #include <com/sun/star/lang/XComponent.hpp> 50 51 52 //_________________________________________________________________________________________________________________ 53 // includes of other projects 54 //_________________________________________________________________________________________________________________ 55 56 #include <rtl/ustrbuf.hxx> 57 #include <rtl/strbuf.hxx> 58 #include <rtl/ustring.hxx> 59 #include <rtl/string.hxx> 60 #include <unotools/bootstrap.hxx> 61 #include <osl/file.hxx> 62 #include <svtools/xtextedt.hxx> 63 #include <vcl/svapp.hxx> 64 #include <comphelper/processfactory.hxx> 65 #include <tools/date.hxx> 66 #include <tools/time.hxx> 67 #include <tools/datetime.hxx> 68 #include <osl/file.hxx> 69 #include <osl/time.h> 70 71 //_________________________________________________________________________________________________________________ 72 // namespace 73 //_________________________________________________________________________________________________________________ 74 75 namespace framework{ 76 using namespace utl; 77 using namespace ::osl ; 78 using namespace ::cppu ; 79 using namespace ::com::sun::star::uno ; 80 using namespace ::com::sun::star::beans ; 81 using namespace ::com::sun::star::lang ; 82 using namespace ::com::sun::star::util ; 83 using namespace ::com::sun::star::frame ; 84 85 //_________________________________________________________________________________________________________________ 86 // non exported const 87 //_________________________________________________________________________________________________________________ 88 89 // license file name 90 static const char *szLicensePath = "/share/readme"; 91 #ifdef UNX 92 static const char *szUNXLicenseName = "/LICENSE"; 93 static const char *szUNXLicenseExt = ""; 94 #elif defined(WNT) || defined(OS2) 95 static const char *szWNTLicenseName = "/license"; 96 static const char *szWNTLicenseExt = ".txt"; 97 #endif 98 99 //_________________________________________________________________________________________________________________ 100 // non exported definitions 101 //_________________________________________________________________________________________________________________ 102 103 //_________________________________________________________________________________________________________________ 104 // declarations 105 //_________________________________________________________________________________________________________________ 106 107 //***************************************************************************************************************** 108 // constructor 109 //***************************************************************************************************************** 110 License::License( const Reference< XMultiServiceFactory >& xFactory ) 111 // Init baseclasses first 112 // Attention: 113 // Don't change order of initialization! 114 // ThreadHelpBase is a struct with a mutex as member. We can't use a mutex as member, while 115 // we must garant right initialization and a valid value of this! First initialize 116 // baseclasses and then members. And we need the mutex for other baseclasses !!! 117 : ThreadHelpBase ( &Application::GetSolarMutex() ) 118 , OWeakObject ( ) 119 // Init member 120 , m_xFactory ( xFactory ) 121 , m_bTerminate ( sal_False ) 122 { 123 } 124 125 //***************************************************************************************************************** 126 // destructor 127 //***************************************************************************************************************** 128 License::~License() 129 { 130 } 131 132 //***************************************************************************************************************** 133 // XInterface, XTypeProvider, XServiceInfo 134 //***************************************************************************************************************** 135 136 DEFINE_XINTERFACE_4 ( License , 137 OWeakObject , 138 DIRECT_INTERFACE(XTypeProvider ), 139 DIRECT_INTERFACE(XServiceInfo ), 140 DIRECT_INTERFACE(XJob ), 141 DIRECT_INTERFACE(XCloseable ) 142 ) 143 144 DEFINE_XTYPEPROVIDER_4 ( License , 145 XTypeProvider , 146 XServiceInfo , 147 XJob , 148 XCloseable 149 ) 150 151 DEFINE_XSERVICEINFO_MULTISERVICE ( License, 152 OWeakObject , 153 SERVICENAME_LICENSE , 154 IMPLEMENTATIONNAME_LICENSE 155 ) 156 157 DEFINE_INIT_SERVICE ( License, 158 { 159 } 160 ) 161 162 163 #if 0 164 IMPL_STATIC_LINK_NOINSTANCE( License, Terminate, void*, EMPTYARG ) 165 { 166 /* 167 Reference< XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); 168 Reference< XDesktop > xDesktop(xFactory->createInstance( 169 ::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop")), UNO_QUERY); 170 if (xDesktop.is()) 171 xDesktop->terminate(); 172 */ 173 /* 174 _exit(0); 175 */ 176 return 0; 177 } 178 #endif 179 180 static DateTime _oslDateTimeToDateTime(const oslDateTime& aDateTime) 181 { 182 return DateTime( 183 Date(aDateTime.Day, aDateTime.Month, aDateTime.Year), 184 Time(aDateTime.Hours, aDateTime.Minutes, aDateTime.Seconds)); 185 } 186 187 static ::rtl::OUString _makeDateTimeString (const DateTime& aDateTime, sal_Bool bUTC = sal_False) 188 { 189 ::rtl::OStringBuffer aDateTimeString; 190 aDateTimeString.append((sal_Int32)aDateTime.GetYear()); 191 aDateTimeString.append("-"); 192 if (aDateTime.GetMonth()<10) aDateTimeString.append("0"); 193 aDateTimeString.append((sal_Int32)aDateTime.GetMonth()); 194 aDateTimeString.append("-"); 195 if (aDateTime.GetDay()<10) aDateTimeString.append("0"); 196 aDateTimeString.append((sal_Int32)aDateTime.GetDay()); 197 aDateTimeString.append("T"); 198 if (aDateTime.GetHour()<10) aDateTimeString.append("0"); 199 aDateTimeString.append((sal_Int32)aDateTime.GetHour()); 200 aDateTimeString.append(":"); 201 if (aDateTime.GetMin()<10) aDateTimeString.append("0"); 202 aDateTimeString.append((sal_Int32)aDateTime.GetMin()); 203 aDateTimeString.append(":"); 204 if (aDateTime.GetSec()<10) aDateTimeString.append("0"); 205 aDateTimeString.append((sal_Int32)aDateTime.GetSec()); 206 if (bUTC) aDateTimeString.append("Z"); 207 208 return OStringToOUString(aDateTimeString.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US); 209 } 210 211 static sal_Bool _parseDateTime(const ::rtl::OUString& aString, DateTime& aDateTime) 212 { 213 // take apart a canonical literal xsd:dateTime string 214 //CCYY-MM-DDThh:mm:ss(Z) 215 216 ::rtl::OUString aDateTimeString = aString.trim(); 217 218 // check length 219 if (aDateTimeString.getLength() < 19 || aDateTimeString.getLength() > 20) 220 return sal_False; 221 222 sal_Int32 nDateLength = 10; 223 sal_Int32 nTimeLength = 8; 224 225 ::rtl::OUString aDateTimeSep = ::rtl::OUString::createFromAscii("T"); 226 ::rtl::OUString aDateSep = ::rtl::OUString::createFromAscii("-"); 227 ::rtl::OUString aTimeSep = ::rtl::OUString::createFromAscii(":"); 228 ::rtl::OUString aUTCString = ::rtl::OUString::createFromAscii("Z"); 229 230 ::rtl::OUString aDateString = aDateTimeString.copy(0, nDateLength); 231 ::rtl::OUString aTimeString = aDateTimeString.copy(nDateLength+1, nTimeLength); 232 233 sal_Int32 nIndex = 0; 234 sal_Int32 nYear = aDateString.getToken(0, '-', nIndex).toInt32(); 235 sal_Int32 nMonth = aDateString.getToken(0, '-', nIndex).toInt32(); 236 sal_Int32 nDay = aDateString.getToken(0, '-', nIndex).toInt32(); 237 nIndex = 0; 238 sal_Int32 nHour = aTimeString.getToken(0, ':', nIndex).toInt32(); 239 sal_Int32 nMinute = aTimeString.getToken(0, ':', nIndex).toInt32(); 240 sal_Int32 nSecond = aTimeString.getToken(0, ':', nIndex).toInt32(); 241 242 Date tmpDate((sal_uInt16)nDay, (sal_uInt16)nMonth, (sal_uInt16)nYear); 243 Time tmpTime(nHour, nMinute, nSecond); 244 DateTime tmpDateTime(tmpDate, tmpTime); 245 if (aString.indexOf(aUTCString) < 0) 246 tmpDateTime.ConvertToUTC(); 247 248 aDateTime = tmpDateTime; 249 return sal_True; 250 } 251 252 static ::rtl::OUString _getCurrentDateString() 253 { 254 ::rtl::OUString aString; 255 return _makeDateTimeString(DateTime()); 256 } 257 258 // execution of license check... 259 css::uno::Any SAL_CALL License::execute(const css::uno::Sequence< css::beans::NamedValue >& ) 260 throw( css::lang::IllegalArgumentException, css::uno::Exception) 261 { 262 // return value 263 Any aRet; aRet <<= sal_False; 264 265 try 266 { 267 ::rtl::OUString aBaseInstallPath; 268 Bootstrap::PathStatus aBaseLocateResult = 269 Bootstrap::locateBaseInstallation(aBaseInstallPath); 270 if (aBaseLocateResult != Bootstrap::PATH_EXISTS) 271 { 272 // base install noit found 273 // prepare termination 274 // m_bTerminate = sal_True; 275 // Application::PostUserEvent( STATIC_LINK( 0, License, Terminate ) ); 276 aRet <<= sal_False; 277 return aRet; 278 } 279 // determine the filename of the license to show 280 ::rtl::OUString aLangString; 281 ::com::sun::star::lang::Locale aLocale; 282 ::rtl::OString aMgrName = ::rtl::OString("fwe"); 283 AllSettings aSettings(Application::GetSettings()); 284 aLocale = aSettings.GetUILocale(); 285 ResMgr* pResMgr = ResMgr::SearchCreateResMgr(aMgrName, aLocale); 286 287 aLangString = aLocale.Language; 288 if ( aLocale.Country.getLength() != 0 ) 289 { 290 aLangString += ::rtl::OUString::createFromAscii("-"); 291 aLangString += aLocale.Country; 292 if ( aLocale.Variant.getLength() != 0 ) 293 { 294 aLangString += ::rtl::OUString::createFromAscii("-"); 295 aLangString += aLocale.Variant; 296 } 297 } 298 #if defined(WNT) || defined(OS2) 299 ::rtl::OUString aLicensePath = 300 aBaseInstallPath + ::rtl::OUString::createFromAscii(szLicensePath) 301 + ::rtl::OUString::createFromAscii(szWNTLicenseName) 302 + ::rtl::OUString::createFromAscii("_") 303 + aLangString 304 + ::rtl::OUString::createFromAscii(szWNTLicenseExt); 305 #else 306 ::rtl::OUString aLicensePath = 307 aBaseInstallPath + ::rtl::OUString::createFromAscii(szLicensePath) 308 + ::rtl::OUString::createFromAscii(szUNXLicenseName) 309 + ::rtl::OUString::createFromAscii("_") 310 + aLangString 311 + ::rtl::OUString::createFromAscii(szUNXLicenseExt); 312 #endif 313 // check if we need to show the license at all 314 // open org.openoffice.Setup/Office/ooLicenseAcceptDate 315 ::rtl::OUString sConfigSrvc = SERVICENAME_CFGPROVIDER; 316 ::rtl::OUString sAccessSrvc = ::rtl::OUString::createFromAscii("com.sun.star.configuration.ConfigurationUpdateAccess"); 317 ::rtl::OUString sReadSrvc = SERVICENAME_CFGREADACCESS; 318 319 // get configuration provider 320 Reference< XMultiServiceFactory > theConfigProvider = Reference< XMultiServiceFactory >( 321 m_xFactory->createInstance(sConfigSrvc), UNO_QUERY_THROW); 322 Sequence< Any > theArgs(1); 323 NamedValue v; 324 v.Name = ::rtl::OUString::createFromAscii("NodePath"); 325 v.Value <<= ::rtl::OUString::createFromAscii("org.openoffice.Setup/Office"); 326 theArgs[0] <<= v; 327 Reference< XPropertySet > pset = Reference< XPropertySet >( 328 theConfigProvider->createInstanceWithArguments(sAccessSrvc, theArgs), UNO_QUERY_THROW); 329 330 // if we find a date there, compare it to baseinstall license date 331 ::rtl::OUString aAcceptDate; 332 if (pset->getPropertyValue(::rtl::OUString::createFromAscii("ooLicenseAcceptDate")) >>= aAcceptDate) 333 { 334 // get LicenseFileDate from base install 335 ::rtl::OUString aLicenseURL = aLicensePath; 336 /* 337 if (FileBase::getFileURLFromSystemPath(aLicensePath, aLicenseURL) != FileBase::E_None) 338 return makeAny(sal_False); 339 */ 340 DirectoryItem aDirItem; 341 if (DirectoryItem::get(aLicenseURL, aDirItem) != FileBase::E_None) 342 return makeAny(sal_False); 343 FileStatus aStatus(FileStatusMask_All); 344 if (aDirItem.getFileStatus(aStatus) != FileBase::E_None) 345 return makeAny(sal_False); 346 TimeValue aTimeVal = aStatus.getModifyTime(); 347 oslDateTime aDateTimeVal; 348 if (!osl_getDateTimeFromTimeValue(&aTimeVal, &aDateTimeVal)) 349 return makeAny(sal_False); 350 351 // compare dates 352 DateTime aLicenseDateTime = _oslDateTimeToDateTime(aDateTimeVal); 353 DateTime aAcceptDateTime; 354 if (!_parseDateTime(aAcceptDate, aAcceptDateTime)) 355 return makeAny(sal_False); 356 357 if ( aAcceptDateTime > aLicenseDateTime ) 358 return makeAny(sal_True); 359 } 360 // prepare to show 361 // display license dialog 362 LicenseDialog* pDialog = new LicenseDialog(aLicensePath, pResMgr); 363 sal_Bool bAgreed = (pDialog->Execute() == 1); 364 delete pDialog; 365 366 if (bAgreed) { 367 368 // write org.openoffice.Setup/ooLicenseAcceptDate 369 aAcceptDate = _getCurrentDateString(); 370 pset->setPropertyValue(::rtl::OUString::createFromAscii("ooLicenseAcceptDate"), makeAny(aAcceptDate)); 371 Reference< XChangesBatch >(pset, UNO_QUERY_THROW)->commitChanges(); 372 373 // enable quickstarter 374 sal_Bool bQuickstart( sal_True ); 375 sal_Bool bAutostart( sal_True ); 376 Sequence< Any > aSeq( 2 ); 377 aSeq[0] <<= bQuickstart; 378 aSeq[1] <<= bAutostart; 379 380 Reference < XInitialization > xQuickstart( ::comphelper::getProcessServiceFactory()->createInstance( 381 ::rtl::OUString::createFromAscii( "com.sun.star.office.Quickstart" )),UNO_QUERY ); 382 if ( xQuickstart.is() ) 383 xQuickstart->initialize( aSeq ); 384 385 aRet <<= sal_True; 386 } 387 else 388 { 389 // license was not accepted 390 // prepare termination 391 // m_bTerminate = sal_True; 392 // Application::PostUserEvent( STATIC_LINK( 0, License, Terminate ) ); 393 aRet <<= sal_False; 394 } 395 } 396 catch (RuntimeException&) 397 { 398 // license could not be verified 399 aRet <<= sal_False; 400 } 401 return aRet; 402 } 403 404 void SAL_CALL License::close(sal_Bool /*bDeliverOwnership*/) throw (css::util::CloseVetoException) 405 { 406 if (!m_bTerminate) 407 throw CloseVetoException(); 408 } 409 void SAL_CALL License::addCloseListener(const css::uno::Reference< css::util::XCloseListener >&) 410 throw (css::uno::RuntimeException) 411 { 412 } 413 void SAL_CALL License::removeCloseListener(const css::uno::Reference< css::util::XCloseListener >&) 414 throw (css::uno::RuntimeException) 415 { 416 } 417 418 419 //************************************************************************ 420 // License Dialog 421 //************************************************************************ 422 423 LicenseDialog::LicenseDialog(const ::rtl::OUString & aLicensePath, ResMgr *pResMgr) : 424 ModalDialog(NULL, ResId(DLG_LICENSE, *pResMgr)), 425 aLicenseML(this, ResId(ML_LICENSE, *pResMgr)), 426 aInfo1FT(this, ResId(FT_INFO1, *pResMgr)), 427 aInfo2FT(this, ResId(FT_INFO2, *pResMgr)), 428 aInfo3FT(this, ResId(FT_INFO3, *pResMgr)), 429 aInfo2_1FT(this, ResId(FT_INFO2_1, *pResMgr)), 430 aInfo3_1FT(this, ResId(FT_INFO3_1, *pResMgr)), 431 aFixedLine(this, ResId(FL_DIVIDE, *pResMgr)), 432 aPBPageDown(this, ResId(PB_PAGEDOWN, *pResMgr)), 433 aPBDecline( this, ResId(PB_DECLINE, *pResMgr) ), 434 aPBAccept( this, ResId(PB_ACCEPT, *pResMgr) ), 435 aArrow(this, ResId(IMG_ARROW, *pResMgr)), 436 aStrAccept( ResId(LICENSE_ACCEPT, *pResMgr) ), 437 aStrNotAccept( ResId(LICENSE_NOTACCEPT, *pResMgr) ), 438 bEndReached(sal_False) 439 { 440 FreeResource(); 441 442 aLicenseML.SetEndReachedHdl( LINK(this, LicenseDialog, EndReachedHdl) ); 443 aLicenseML.SetScrolledHdl( LINK(this, LicenseDialog, ScrolledHdl) ); 444 445 aPBPageDown.SetClickHdl( LINK(this, LicenseDialog, PageDownHdl) ); 446 aPBDecline.SetClickHdl( LINK(this, LicenseDialog, DeclineBtnHdl) ); 447 aPBAccept.SetClickHdl( LINK(this, LicenseDialog, AcceptBtnHdl) ); 448 449 // We want a automatic repeating page down button 450 WinBits aStyle = aPBPageDown.GetStyle(); 451 aStyle |= WB_REPEAT; 452 aPBPageDown.SetStyle( aStyle ); 453 454 String aText = aInfo2FT.GetText(); 455 aText.SearchAndReplaceAll( UniString::CreateFromAscii("%PAGEDOWN"), aPBPageDown.GetText() ); 456 aInfo2FT.SetText( aText ); 457 458 aPBDecline.SetText( aStrNotAccept ); 459 aPBAccept.SetText( aStrAccept ); 460 461 aPBAccept.Disable(); 462 463 // load license text 464 File aLicenseFile(aLicensePath); 465 if ( aLicenseFile.open(OpenFlag_Read) == FileBase::E_None) 466 { 467 DirectoryItem d; 468 DirectoryItem::get(aLicensePath, d); 469 FileStatus fs(FileStatusMask_FileSize); 470 d.getFileStatus(fs); 471 sal_uInt64 nBytesRead = 0; 472 sal_uInt64 nPosition = 0; 473 sal_uInt32 nBytes = (sal_uInt32)fs.getFileSize(); 474 sal_Char *pBuffer = new sal_Char[nBytes]; 475 // FileBase RC r = FileBase::E_None; 476 while (aLicenseFile.read(pBuffer+nPosition, nBytes-nPosition, nBytesRead) == FileBase::E_None 477 && nPosition + nBytesRead < nBytes) 478 { 479 nPosition += nBytesRead; 480 } 481 ::rtl::OUString aLicenseString(pBuffer, nBytes, RTL_TEXTENCODING_UTF8, 482 OSTRING_TO_OUSTRING_CVTFLAGS | RTL_TEXTTOUNICODE_FLAGS_GLOBAL_SIGNATURE); 483 delete[] pBuffer; 484 aLicenseML.SetText(aLicenseString); 485 } 486 487 } 488 489 LicenseDialog::~LicenseDialog() 490 { 491 } 492 493 IMPL_LINK( LicenseDialog, PageDownHdl, PushButton *, EMPTYARG ) 494 { 495 aLicenseML.ScrollDown( SCROLL_PAGEDOWN ); 496 return 0; 497 } 498 499 IMPL_LINK( LicenseDialog, EndReachedHdl, LicenseView *, EMPTYARG ) 500 { 501 bEndReached = sal_True; 502 503 EnableControls(); 504 505 return 0; 506 } 507 508 IMPL_LINK( LicenseDialog, ScrolledHdl, LicenseView *, EMPTYARG ) 509 { 510 EnableControls(); 511 512 return 0; 513 } 514 515 IMPL_LINK( LicenseDialog, DeclineBtnHdl, PushButton *, EMPTYARG ) 516 { 517 EndDialog(0); 518 return 0; 519 } 520 IMPL_LINK( LicenseDialog, AcceptBtnHdl, PushButton *, EMPTYARG ) 521 { 522 EndDialog(1); 523 return 0; 524 } 525 526 527 void LicenseDialog::EnableControls() 528 { 529 if( !bEndReached && 530 ( aLicenseML.IsEndReached() || !aLicenseML.GetText().Len() ) ) 531 bEndReached = sal_True; 532 533 if ( bEndReached ) 534 { 535 Point aPos( aInfo1FT.GetPosPixel().X(), 536 aInfo3_1FT.GetPosPixel().Y() ); 537 aArrow.SetPosPixel( aPos ); 538 aPBAccept.Enable(); 539 } 540 else 541 { 542 Point aPos( aInfo1FT.GetPosPixel().X(), 543 aInfo2_1FT.GetPosPixel().Y() ); 544 aArrow.SetPosPixel( aPos ); 545 aPBAccept.Disable(); 546 } 547 548 if ( aLicenseML.IsEndReached() ) 549 aPBPageDown.Disable(); 550 else 551 aPBPageDown.Enable(); 552 553 } 554 555 556 LicenseView::LicenseView( Window* pParent, const ResId& rResId ) 557 : MultiLineEdit( pParent, rResId ) 558 { 559 SetLeftMargin( 5 ); 560 561 mbEndReached = IsEndReached(); 562 563 StartListening( *GetTextEngine() ); 564 } 565 566 LicenseView::~LicenseView() 567 { 568 maEndReachedHdl = Link(); 569 maScrolledHdl = Link(); 570 571 EndListeningAll(); 572 } 573 574 void LicenseView::ScrollDown( ScrollType eScroll ) 575 { 576 ScrollBar* pScroll = GetVScrollBar(); 577 578 if ( pScroll ) 579 pScroll->DoScrollAction( eScroll ); 580 } 581 582 sal_Bool LicenseView::IsEndReached() const 583 { 584 sal_Bool bEndReached; 585 586 ExtTextView* pView = GetTextView(); 587 ExtTextEngine* pEdit = GetTextEngine(); 588 sal_uLong nHeight = pEdit->GetTextHeight(); 589 Size aOutSize = pView->GetWindow()->GetOutputSizePixel(); 590 Point aBottom( 0, aOutSize.Height() ); 591 592 if ( (sal_uLong) pView->GetDocPos( aBottom ).Y() >= nHeight - 1 ) 593 bEndReached = sal_True; 594 else 595 bEndReached = sal_False; 596 597 return bEndReached; 598 } 599 600 void LicenseView::Notify( SfxBroadcaster&, const SfxHint& rHint ) 601 { 602 if ( rHint.IsA( TYPE(TextHint) ) ) 603 { 604 sal_Bool bLastVal = EndReached(); 605 sal_uLong nId = ((const TextHint&)rHint).GetId(); 606 607 if ( nId == TEXT_HINT_PARAINSERTED ) 608 { 609 if ( bLastVal ) 610 mbEndReached = IsEndReached(); 611 } 612 else if ( nId == TEXT_HINT_VIEWSCROLLED ) 613 { 614 if ( ! mbEndReached ) 615 mbEndReached = IsEndReached(); 616 maScrolledHdl.Call( this ); 617 } 618 619 if ( EndReached() && !bLastVal ) 620 { 621 maEndReachedHdl.Call( this ); 622 } 623 } 624 } 625 626 } // namespace framework 627 628