/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_unotools.hxx" #include #include #include #include #include #include #include #include //........................................................................ namespace utl { //........................................................................ using namespace ::com::sun::star::uno; //==================================================================== //= local helpers //==================================================================== //-------------------------------------------------------------------- /** converts a string representation of a date into a integer representation

No semantic check is made, i.e. if the string describes the 40.12, this is not recognized. In opposite, the string must have a valid structure (DD.MM.YYYY).

@return the integer representation of the date which can be used with the Date class, or 0 if the given string was no valid date representation */ static sal_Int32 lcl_convertString2Date( const ::rtl::OUString& _rStringRep ) { sal_Int32 nDateIntRep = 0; if ( _rStringRep.getLength() == 2 + 1 + 2 + 1 + 4 ) // DD.MM.YYYY { // validate the string sal_Bool bValid = sal_True; const sal_Unicode* pStringRep = _rStringRep.getStr(); sal_Int32 nLen = _rStringRep.getLength(); for ( sal_Int32 nPos = 0; bValid && ( nPos < nLen ); ++nPos, ++pStringRep ) { if ( ( 2 == nPos ) || ( 5 == nPos ) ) bValid = '.' == *pStringRep; // the number separators else bValid = ( *pStringRep >= '0' ) && ( *pStringRep <= '9' ); } // passed the test? if ( bValid ) { Date aDate; aDate.SetDay ( (sal_uInt16)_rStringRep.copy( 0, 2 ).toInt32( ) ); aDate.SetMonth ( (sal_uInt16)_rStringRep.copy( 3, 2 ).toInt32( ) ); aDate.SetYear ( (sal_uInt16)_rStringRep.copy( 6, 4 ).toInt32( ) ); nDateIntRep = aDate.GetDate(); } } return nDateIntRep; } //-------------------------------------------------------------------- static const ::rtl::OUString& lcl_fillToken( const sal_Int32 /* [in] */ _nToken, const sal_Int16 /* [in] */ _nDigits, ::rtl::OUString& /* [out] */ _rToken ) { // convert into string ::rtl::OUString sLeanToken = ::rtl::OUString::valueOf( _nToken ); // check length if ( sLeanToken.getLength() < _nDigits ) { // fill OSL_ENSURE( _nDigits <= 4, "lcl_fillToken: invalid digit number!" ); _rToken = ::rtl::OUString( "0000", _nDigits - sLeanToken.getLength(), RTL_TEXTENCODING_ASCII_US ); _rToken += sLeanToken; } else _rToken = sLeanToken; return _rToken; } //-------------------------------------------------------------------- /** converts a integer representation of a date into a string representation */ static ::rtl::OUString lcl_ConvertDate2String( const Date& _rDate ) { OSL_ENSURE( _rDate.IsValid(), "lcl_ConvertDate2String: invalid integer representation!" ); sal_Unicode cSeparator( '.' ); ::rtl::OUString sSeparator( &cSeparator, 1 ); ::rtl::OUString sStringRep; ::rtl::OUString sToken; sStringRep += lcl_fillToken( (sal_Int32)_rDate.GetDay(), 2, sToken ); sStringRep += sSeparator; sStringRep += lcl_fillToken( (sal_Int32)_rDate.GetMonth(), 2, sToken ); sStringRep += sSeparator; sStringRep += lcl_fillToken( (sal_Int32)_rDate.GetYear(), 4, sToken ); return sStringRep; } //-------------------------------------------------------------------- /// checks whether a given trigger date is reached (i.e. is _before_ the current date) static sal_Bool lcl_reachedTriggerDate( const Date& _rTriggerDate ) { return _rTriggerDate <= Date(); } //-------------------------------------------------------------------- #define DECLARE_STATIC_LAZY_USTRING( name ) \ static const ::rtl::OUString& lcl_get##name##Name() \ { \ static const ::rtl::OUString sName(RTL_CONSTASCII_USTRINGPARAM( #name )); \ return sName; \ } DECLARE_STATIC_LAZY_USTRING( ReminderDate ); DECLARE_STATIC_LAZY_USTRING( RequestDialog ); DECLARE_STATIC_LAZY_USTRING( ShowMenuItem ); DECLARE_STATIC_LAZY_USTRING( Patch ); //==================================================================== //= RegOptionsImpl //==================================================================== class RegOptionsImpl { private: OConfigurationTreeRoot m_aRegistrationNode; // the configuration node we need to access our persistent data String m_sRegistrationURL; // the URL to use when doing an online registration Date m_aReminderDate; // the reminder date as found in the configuration sal_Int32 m_nDialogCounter; // the dialog counter - see getDialogPermission sal_Bool m_bShowMenuItem; // the flag indicating if the registration menu item is allowed static RegOptionsImpl* s_pSingleInstance; // the one and only instance of this class static sal_Int32 s_nInstanceCount; // reference counter for the instances static sal_Bool s_bThisSessionDone; // the flag indicating if for this session, everything beeing relevant has already been done private: RegOptionsImpl( ); static ::osl::Mutex& getStaticMutex(); // get the mutex used to protect the static members of this class void commit( ); sal_Int32 getBuildId() const; private: RegOptions::DialogPermission implGetDialogPermission( ) const; public: static RegOptionsImpl* registerClient( ); static void revokeClient( ); inline sal_Bool hasURL( ) const { return ( 0 != m_sRegistrationURL.Len() ); } inline sal_Bool allowMenu( ) const { return hasURL() && m_bShowMenuItem; } inline String getRegistrationURL( ) const { return m_sRegistrationURL; } RegOptions::DialogPermission getDialogPermission( ) const; void markSessionDone( ); void activateReminder( sal_Int32 _nDaysFromNow ); void removeReminder(); bool hasReminderDateCome() const; }; //-------------------------------------------------------------------- RegOptionsImpl* RegOptionsImpl::s_pSingleInstance = NULL; sal_Bool RegOptionsImpl::s_bThisSessionDone = sal_False; sal_Int32 RegOptionsImpl::s_nInstanceCount = 0; namespace { class theRegOptionsImplMutex : public rtl::Static{}; } //-------------------------------------------------------------------- ::osl::Mutex& RegOptionsImpl::getStaticMutex() { return theRegOptionsImplMutex::get(); } //-------------------------------------------------------------------- void RegOptionsImpl::commit( ) { m_aRegistrationNode.commit( ); } //-------------------------------------------------------------------- RegOptionsImpl* RegOptionsImpl::registerClient( ) { ::osl::MutexGuard aGuard( getStaticMutex() ); if ( !s_pSingleInstance ) s_pSingleInstance = new RegOptionsImpl; ++s_nInstanceCount; return s_pSingleInstance; } //-------------------------------------------------------------------- void RegOptionsImpl::revokeClient( ) { ::osl::MutexGuard aGuard( getStaticMutex() ); OSL_ENSURE( s_nInstanceCount, "RegOptionsImpl::revokeClient: there are no clients alive!" ); OSL_ENSURE( s_pSingleInstance || !s_nInstanceCount, "RegOptionsImpl::revokeClient: invalid instance pointer!" ); if ( s_nInstanceCount ) { if ( s_pSingleInstance ) // commit the changes done by this client s_pSingleInstance->commit(); if ( 0 == --s_nInstanceCount ) { delete s_pSingleInstance; s_pSingleInstance = NULL; } } } //-------------------------------------------------------------------- RegOptionsImpl::RegOptionsImpl( ) :m_nDialogCounter ( 0 ) ,m_bShowMenuItem ( sal_False ) { // create the config node for all our registration information m_aRegistrationNode = OConfigurationTreeRoot::createWithServiceFactory( ::comphelper::getProcessServiceFactory(), ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.Office.Common/Help/Registration")) ); // cache some data //the URL to use for online registration ::rtl::OUString sStringValue; m_aRegistrationNode.getNodeValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("URL")) ) >>= sStringValue; m_sRegistrationURL = sStringValue; // the state of the dialog m_aRegistrationNode.getNodeValue( lcl_getRequestDialogName() ) >>= m_nDialogCounter; // the flag for showing the menu item sal_Bool bBoolValue = sal_False; m_aRegistrationNode.getNodeValue( lcl_getShowMenuItemName() ) >>= bBoolValue; m_bShowMenuItem = bBoolValue; // the reminder date (if any) sal_Int32 nIntDate = 0; sStringValue = ::rtl::OUString(); m_aRegistrationNode.getNodeValue( lcl_getReminderDateName() ) >>= sStringValue; bool bIsPatchDate = ( sStringValue.equals( lcl_getPatchName() ) != sal_False ); if ( !bIsPatchDate && sStringValue.getLength() ) nIntDate = lcl_convertString2Date( sStringValue ); m_aReminderDate.SetDate( nIntDate ); } //-------------------------------------------------------------------- RegOptions::DialogPermission RegOptionsImpl::implGetDialogPermission( ) const { RegOptions::DialogPermission eResult = RegOptions::dpDisabled; // no URL or a counter already decreased to zero means the dialog is disabled if ( hasURL() && ( m_nDialogCounter > 0 ) ) { // during every session, the counter will be decreased // If it reaches zero, the dialog shall be executed if ( 1 == m_nDialogCounter ) { if ( m_aReminderDate.IsValid( ) ) { // valid reminder date // assume remind later eResult = RegOptions::dpRemindLater; // and check if we reached the reminder date if ( lcl_reachedTriggerDate( m_aReminderDate ) ) eResult = RegOptions::dpThisSession; } else eResult = RegOptions::dpThisSession; // execute in this session } else eResult = RegOptions::dpNotThisSession; // first trigger session not reached // a last check .... if ( ( s_bThisSessionDone ) // this session is already marked as "done" && ( RegOptions::dpThisSession == eResult )// but without this, the state would be "now" ) eResult = RegOptions::dpDisabled; // -> change state to "disabled" } return eResult; } //-------------------------------------------------------------------- RegOptions::DialogPermission RegOptionsImpl::getDialogPermission( ) const { OSL_ENSURE( !s_bThisSessionDone, "RegOptionsImpl::getDialogPermission: should never be asked in this session, again!" ); // Somebody already marked this session as "everything relevant happened". So why sombody (else?) asks // me again? return implGetDialogPermission( ); } //-------------------------------------------------------------------- void RegOptionsImpl::activateReminder( sal_Int32 _nDaysFromNow ) { OSL_ENSURE( s_bThisSessionDone || ( implGetDialogPermission( ) != RegOptions::dpDisabled ), "RegOptionsImpl::activateReminder: invalid call!" ); OSL_ENSURE( _nDaysFromNow > 0, "RegOptionsImpl::activateReminder: invalid argument!" ); // calc the reminder m_aReminderDate = Date() + _nDaysFromNow; // today (default ctor) + days // remember the date m_aRegistrationNode.setNodeValue( lcl_getReminderDateName(), makeAny( lcl_ConvertDate2String( m_aReminderDate ) ) ); // to be on the save side, write the counter m_aRegistrationNode.setNodeValue( lcl_getRequestDialogName(), makeAny( (sal_Int32)1 ) ); // mark this session as done if ( !s_bThisSessionDone ) markSessionDone( ); } //-------------------------------------------------------------------- void RegOptionsImpl::removeReminder() { ::rtl::OUString aDefault; ::rtl::OUString aReminderValue( lcl_getPatchName() ); aReminderValue += ::rtl::OUString::valueOf(getBuildId()); m_aRegistrationNode.setNodeValue( lcl_getReminderDateName(), Any( aReminderValue ) ); } //-------------------------------------------------------------------- sal_Int32 RegOptionsImpl::getBuildId() const { sal_Int32 nBuildId( 0 ); ::rtl::OUString aDefault; ::rtl::OUString aBuildIdData = utl::Bootstrap::getBuildIdData( aDefault ); sal_Int32 nIndex1 = aBuildIdData.indexOf(':'); sal_Int32 nIndex2 = aBuildIdData.indexOf(')'); if (( nIndex1 > 0 ) && ( nIndex2 > 0 ) && ( nIndex2-1 > nIndex1+1 )) { ::rtl::OUString aBuildId = aBuildIdData.copy( nIndex1+1, nIndex2-nIndex1-1 ); nBuildId = aBuildId.toInt32(); } return nBuildId; } //-------------------------------------------------------------------- bool RegOptionsImpl::hasReminderDateCome() const { bool bRet = false; sal_Int32 nDate = 0; ::rtl::OUString sDate; m_aRegistrationNode.getNodeValue( lcl_getReminderDateName() ) >>= sDate; if ( sDate.getLength() ) { if ( sDate.indexOf( lcl_getPatchName() ) == 0) { if (sDate.equals( lcl_getPatchName() )) bRet = true; else if (sDate.getLength() > lcl_getPatchName().getLength() ) { // Check the build ID to determine if the registration // dialog needs to be shown. sal_Int32 nBuildId = getBuildId(); ::rtl::OUString aStoredBuildId( sDate.copy(lcl_getPatchName().getLength())); // remind if the current build ID is not the same as the stored one if ( nBuildId != aStoredBuildId.toInt32() ) bRet = true; } } else { nDate = lcl_convertString2Date( sDate ); if ( nDate > 0 ) { Date aReminderDate; aReminderDate.SetDate( nDate ); bRet = aReminderDate <= Date(); } } } else bRet = true; return bRet; } //-------------------------------------------------------------------- void RegOptionsImpl::markSessionDone( ) { OSL_ENSURE( !s_bThisSessionDone, "RegOptionsImpl::markSessionDone: already marked!" ); OSL_ENSURE( implGetDialogPermission( ) != RegOptions::dpDisabled, "RegOptionsImpl::markSessionDone: invalid call!" ); if ( !s_bThisSessionDone ) { RegOptions::DialogPermission eOldPermission = implGetDialogPermission( ); s_bThisSessionDone = sal_True; if ( RegOptions::dpRemindLater == eOldPermission ) { // no action required. If we shall remind later, the counter is already at 1, we should not change this, // as the next smaller number (which is 0 :) means that the dialog would be disabled OSL_ENSURE( 1 == m_nDialogCounter, "RegOptionsImpl::markSessionDone: invalid session counter (1)!" ); } else { OSL_ENSURE( m_nDialogCounter > 0, "RegOptionsImpl::markSessionDone: invalid session counter (2)!" ); --m_nDialogCounter; // decrease the session counter m_aRegistrationNode.setNodeValue( lcl_getRequestDialogName(), makeAny( (sal_Int32)m_nDialogCounter ) ); // and clear the reminder date removeReminder(); } } } //==================================================================== //= RegOptions //==================================================================== //-------------------------------------------------------------------- RegOptions::RegOptions() :m_pImpl( NULL ) { } //-------------------------------------------------------------------- void RegOptions::ensureImpl( ) { if ( !m_pImpl ) m_pImpl = RegOptionsImpl::registerClient(); } //-------------------------------------------------------------------- RegOptions::~RegOptions() { if ( m_pImpl ) { RegOptionsImpl::revokeClient(); m_pImpl = NULL; } } //-------------------------------------------------------------------- String RegOptions::getRegistrationURL( ) const { const_cast< RegOptions* >( this )->ensureImpl( ); return m_pImpl->getRegistrationURL(); } //-------------------------------------------------------------------- RegOptions::DialogPermission RegOptions::getDialogPermission( ) const { const_cast< RegOptions* >( this )->ensureImpl( ); return m_pImpl->getDialogPermission(); } //-------------------------------------------------------------------- void RegOptions::markSessionDone( ) { const_cast< RegOptions* >( this )->ensureImpl( ); m_pImpl->markSessionDone(); } //-------------------------------------------------------------------- void RegOptions::activateReminder( sal_Int32 _nDaysFromNow ) { const_cast< RegOptions* >( this )->ensureImpl( ); m_pImpl->activateReminder( _nDaysFromNow ); } //-------------------------------------------------------------------- sal_Bool RegOptions::allowMenu( ) const { /// we cache this setting, 'cause it is needed very often static sal_Bool bKnowMenuPermission = sal_False; static sal_Bool bAllowMenu = sal_False; if ( !bKnowMenuPermission ) { const_cast< RegOptions* >( this )->ensureImpl( ); bAllowMenu = m_pImpl->allowMenu(); bKnowMenuPermission = sal_True; } return bAllowMenu; } //-------------------------------------------------------------------- void RegOptions::removeReminder() { const_cast< RegOptions* >( this )->ensureImpl( ); m_pImpl->removeReminder(); } //-------------------------------------------------------------------- bool RegOptions::hasReminderDateCome() const { const_cast< RegOptions* >( this )->ensureImpl( ); return m_pImpl->hasReminderDateCome(); } //........................................................................ } // namespace utl //........................................................................ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */