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